简体   繁体   中英

Vim: Convert map to command

I'd like to convert this map to a command . I've tried the "obvious," copying the command part of the map line to a command line:

command SortWords d:execute 'normal i' . join(sort(split(getreg('"'))), ' ')<CR>

However, when using this with selected text it just fails with " E481: No range allowed ". My Google-fu is not strong enough, and the manual is ... computer parseable, let's say.

command! -nargs=0 -range SortWords exe 'norm! gvd'|call setreg('"', join(sort(split(@")), ' '), visualmode()[0])|norm! P

This command is dirty as it clobbers the unnamed register.

To avoid this you must save the register and restore it when you are done. The best way to do this is by using a function.

command! -nargs=0 -range SortWords call VisualSortWords()

function! VisualSortWords()
  let rv = @"
  let rt = getregtype('"')
  try
    norm! gvy
    call setreg('"', join(sort(split(@")), ' '), visualmode()[0])
    norm! `>pgvd
  finally
    call setreg('"', rv, rt)
  endtry
endfunction

Here's a different approach that makes use of only 2 commands ( :call and :delete ). The process is explained below.

command! -range -nargs=0 Sort
  \ call append(<line2>,join(sort(split(join(getline(<line1>,<line2>)))), ' ')) |
  \ <line1>,<line2>d _

Notice that I used 3 lines with the correspondent continuation characters for the sake of readability, but you could have used only one.

The command itself

The command is defined as "Sort" and has two special characteristics:

  • -range makes it able to receive a range, obviously. Also, it sets the default range to the current line (see help for :command-range ).
  • -nargs=0 could be omitted, as it will only guarantee that you or future users of your command won't pass any arguments to it.

Before the command is processed, the text marked as <line1> will be replaced by the line number of the range start. Similarly, <line2> will be replaced by the line number of the range end. Check help on <line1> and subsequent lines to know more about replacement text in commands.

What it does

The command will execute its task in two takes. The first is a chain of functions that can be read from inside out. Let's consider the command was called with a visual selection range ( '< , '> ) that translates as (1,3). The functions will be executed as:

append(3, join(sort(split(join(getline(1,3)))), ' '))

From a different point of view:

#1 getline(1,3)  " the result is a list with text from lines 1 to 3
#2 join(#1)      " joins that list into a string
#3 split(#2)     " splits the string on whitespace, resulting in a list
#4 sort(#3)      " sorts that list
#5 join(#4, ' ') " joins the elements into a string separated by single space
#6 append(3, #5) " insert that string after line 3

If you started with this text:

f e
d c
b a

Now you should have this:

f e
d c
b a
a b c d e f

It's just a matter of deleting those lines. This is exactly that the next part of the command does:

1,3d _

d is a short for the ex command :delete , and _ is the register to put the deleted text in. In this case, it's the black hole register.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM