-1

I've found substantial use for commands that will find differences in two lists of words, and the best (and really only) solution to this I've found is this command:

g/^/kl |if search('^'.escape(getline('.'),'\.*[]^$/').'$','bW') |'ld

I want to make a mapping in my _vimrc file that will execute this line whenever I hit F2 for example, but I haven't been able to make it work. If someone could explain character by character what this line actually does, I think it would make all the difference in the world. I've seen a dozen or so articles on vim mapping and none of them explain what things like / or ^ or \.*{}^$/' do in contexts like this one.

When are : needed in mappings? I've seen some examples with and most without.

When is <CR> needed?

Thanks in advance

Amit
  • 19,780
  • 6
  • 46
  • 54
Doxa
  • 3
  • 1

1 Answers1

3

This sounds like a job for Awk

:%!awk '!a[$0]{a[$0]=1;print}'

However you asking a two questions:

  1. What does :g/^/kl |if search('^'.escape(getline('.'),'\.*[]^$/').'$','bW') |'ld do?
  2. How can I make a mapping to this?

The Mapping

Let's start with "How can I make a mapping to this?":

:nnoremap <f2> :g/^/kl<bar>if search('^'.escape(getline('.'),'\.*[]^$/').'$','bW')<bar>'ld<cr>

The trick is to use <bar> instead of | and to actually execute the command with <cr>. See :h keycodes.

What does this do?

It goes over every line of the buffer with :g/^/ and deletes lines that are the same as a line from above, if search('^'.escape(getline('.'),'\.*[]^$/').'$','bW') and d. The confusing parts to me are the following:

  • Using marks needlessly i.e. :k and range with the :d command.
  • A complicated building of the regex for the search() function. By using the \V (very nomagic) we can reduce the line noise in the regex: '\V\^'.escape(getline('.'),'\').'\$'
  • Why are you doing an O(N^2) operation when you can do an O(N)?

Simplify the command

g/^/if search('\V\^'.escape(getline('.'),'\').'\$','bWn') | d | endif

We remove the needless marks and simplify the escaping. I also added the endif to show the end of the if statement (this can be optionally left off because it will be assumed).

  • :g/{pat}/{cmd} The :global command runs {cmd} on ever line matching {pat}
  • :g/^/ is a common idiom to run a command on every line, since all lins have a beginning, ^.
  • if {expr} | {cmds} | endif. Execute {cmds} if the expression, {expr}, evaluates to true
  • search({pat}, {flags}) search for {pat} in the buffer. {flag} alter the search behavior
  • search() returns the line number of a match or 0 for no match found
  • b flag for search() means search backwards
  • W flag means do not wrap around the buffer when searching
  • n do not move the cursor
  • escape({str}, {chars}) escape {chars} with \
  • \V pattern uses very no magic meaning all regex meta characters need to be escaped
  • \^ and \$ are escaped for start and end of line because of \V option
  • :delete or :d for short delete the current line

I suggest you use the awk solution at the start of this answer.

:nnoremap <f2> :%!awk '!a[$0]{a[$0]=1;print}'<cr>

For more help see the following:

:h :range!
:h :g
:h :d
:h :l
:h :if
:h search(
:h escape(
:h /\V
Peter Rincker
  • 43,539
  • 9
  • 74
  • 101
  • Good use of `\V`. If you want an `O(N)` solution that does not rely on awk (for example, you want it to work even if vim is running on a crippled OS) then it would be easy to modify the function I gave here: http://stackoverflow.com/a/22202004/3130080 – benjifisher Mar 06 '14 at 21:10
  • Thanks for the answer. I added both mappings to $MYVIMRC (under and ) and the second one doesn't work for me. It says no previous command. I'm not new to programming, but I am new to vim and linux so I'm still confused about many of the operators and I haven't found anywhere that lists much of what I want to know, which led to my confusion above. For example, I know that g addresses the entire file, and ^ goes to the first nonblank character in the line, but I don't know what / does and I'm never sure if ' is being used as a single quote or as an operator. Could you help me with this? – Doxa Mar 10 '14 at 18:56