22

Lets say I want to produce the following text in my document:

%
%            Not Important
%    O ------------------------->
%    |
%  S |
%  o |
%  m |
%  e |
%    |
%  M |
%  s |
%  g |
%    |
%    V

Is there any easy way of writing the "Some Msg" vertically as above without having to manually insert each character in each line?

  • 5
    You could write your text as normal, and then do :s/./% \0\r/ to add the % and newlines ... Not a great solution, though... – Martin Tournoij Feb 28 '15 at 0:26
  • Nice solution, it kinda works. Will be using it for now, thank you. – Allan Hasegawa Feb 28 '15 at 0:47
16

Really good solution would probably require some more work, but "not bad" is not very hard to achieve.

Idea

All we need is to move one line down after each character, so let's do just that via InsertCharPre auto-command!

Code

Put it into .vimrc or better yet to some file under plugin/ directory.

" enters insert mode to write vertically
function! VertStart()
    augroup Vert
        autocmd!
        " handles each entered character and moves cursor down
        autocmd InsertCharPre * call feedkeys("\<left>\<down>", 'n')
        autocmd InsertLeave * call VertEnd()
    augroup END

    inoremap <BS> <Up><Del>
    startinsert
endfunction

" cleans up on leaving insert mode
function! VertEnd()
    iunmap <BS>
    augroup Vert
        autocmd!
    augroup END
endfunction

" command to start writing vertically
command! Vert call VertStart()

Usage

Enter :Vert command to start writing vertically. Leaving insert mode automatically disables this "mode". Of course, you can map it to a shortcut if you need to use this command often.

Known Issues

  1. Vertical writing won't be disabled if you leave insert mode via Ctrl-C (this is a result of Ctrl-C being implemented in a slightly strange way with regard to InsertLeave event, which is not fired; thus using the key requires one to be careful).
  • 1
    A rebuttal to Known Issue #1: You shouldn't leave Insert mode with <C-C>. – tommcdo Mar 1 '15 at 12:49
  • @tommcdo, I don't, but if it's there, someone uses it. It's actually useful to avoid abbreviation expansion, I'm wondering why InsertLeave is not triggered for this key. – xaizek Mar 1 '15 at 12:56
  • 1
    I suppose I mean to promote a trend of rejecting <C-C> as a good way to exit Insert mode. The way you've mentioned it could imply that it's sometimes a good method. It's kind of like saying "Caveat: your document won't be saved if you close Microsoft Word by unplugging your computer." – tommcdo Mar 1 '15 at 13:04
  • @tommcdo Didn't think it might sound this way. Added a note about <C-C> being the reason of the issue. I'm not aware of another method to leave insert mode suppressing abbreviation expansion as <C-C> does, if there is no, it's useful at least as part of a mapping like inoremap <silent> <c-c> <c-c>:doautocmd InsertLeave<cr>. – xaizek Mar 1 '15 at 13:37
  • I hadn't considered abbreviations, that's a good point. I even found some places in the help that describe <C-C> as leaving Insert mode without expanding abbreviations, and there's no mention of how it doesn't trigger InsertLeave events. I'm now curious if there is a built-in way to do that, but for now your mapping is a great idea. – tommcdo Mar 1 '15 at 13:51
4

You can type as usual and then convert the current horizontal text into vertical by using substitution in Vim as follow (applies to the current line):

:s/\(.\)/\1\r/g

Or much easier to remember method is to execute one of the following commands (for all lines):

:%!fold -w1
:%!grep -o .

To apply only for the current line or more lines, precede with V, expand the area for more lines if needed, and execute above (but without %).

For PowerShell on Windows, check the substitution for fold.

To define simple key mapping (e.g. F2), try the following:

:nnoremap <F2> V:!fold -w1<CR>

Then type something and press F2 to make the text vertical, simple as that.


Other alternative is to set automatic word wrapping, e.g.

:set tw=1 " textwidth
:set formatoptions+=t

That will automatically wrap text as close to 1 character as white space allows. The disadvantage is that each letter needs to be followed by space (so it's almost the same as you would be pressing Enter

  • 1
    Rather than :s/\(.\)/\1\r/g, you could just use :s/./\0\r/g which is functionally identical. – Wildcard Oct 13 '15 at 18:13
1

I find that macros are an awesome way to do unusual stuff if you are interested in doing that no more than once in a blue moon. Let's say you have the following table:

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  S |
%  o | So you can't just write your
%  m |
%  e | text and transform it into
%    |
%  M | the shape that you want
%  s |
%  g | Macros help here
%    |
%    V

And let's say you want to replace Some Msg with Other Message. First off, let's extend the table for the extra character (line before last yy5p:

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  S |
%  o | So you can't just write your
%  m |
%  e | text and transform it into
%    |
%  M | the shape that you want
%  s |
%  g | Macros help here
%    |
%    |
%    |
%    |
%    |
%    |
%    V

The macro I'm going to come up with is going to take care of converting the text from horizontal to vertical while replacing the old text. Start by typing the text in the first location (cursor is at the end of Other Message):

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  SOther Message |
%  o | So you can't just write your
%  m |
%  e | text and transform it into
%    |
%  M | the shape that you want
%  s |
%  g | Macros help here
%    |
%    |
%    |
%    |
%    |
%    |
%    V

Record the following macro:

  • qq: start recording macro named q
  • ^: go to beginning of line
  • 3l: move to the column where the text is going to be placed
  • x: delete the old character
  • l: move right, leaving one character from the message in place of the old character:
  • v: go to visual mode
  • f|: jump to |
  • 2h: move back two characters
  • d: cut selection
  • j: move down
  • P: paste before cursor
  • q: terminate recording the macro

At this point you have:

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  O |
%  other Message | So you can't just write your
%  m |
%  e | text and transform it into
%    |
%  M | the shape that you want
%  s |
%  g | Macros help here
%    |
%    |
%    |
%    |
%    |
%    |
%    V

Repeat the macro enough number of times (i.e, the number of characters, but you don't need to know it in advance. Just underestimate, and continue once you see how close your estimate was). So let's go with 10@q. You get:

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  O |
%  t | So you can't just write your
%  h |
%  e | text and transform it into
%  r |
%    | the shape that you want
%  M |
%  e | Macros help here
%  s |
%  s |
%  a |
%   ge |
%    |
%    |
%    V

Ok, one more (@q):

%
%            Not Important
%    O ------------------------->
%    | Stuff in side the table
%  O |
%  t | So you can't just write your
%  h |
%  e | text and transform it into
%  r |
%    | the shape that you want
%  M |
%  e | Macros help here
%  s |
%  s |
%  a |
%  g |
%   e |
%    |
%    V

Your cursor is now on the last e. The macro doesn't work well with the last letter (you can try with @q and then u (undo) for unsatisfactory results). Simply adjust it yourself (X for backspace).

  • Very nice. Macros are the way to go in vim. My quick attempt was essentially the same as yours; qq03lxldt|i ^[jPxq@q – Wildcard Oct 13 '15 at 18:23
  • @Wildcard, i can haz upvote? – Shahbaz Oct 14 '15 at 4:21
  • 1
    Ha! Slipped my mind; I thought I had. :) – Wildcard Oct 14 '15 at 4:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.