This sounds like a job for Awk
:%!awk '!a[$0]{a[$0]=1;print}'
However you asking a two questions:
- What does
:g/^/kl |if search('^'.escape(getline('.'),'\.*[]^$/').'$','bW') |'ld do?
- 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