Vim Tips Wiki
No edit summary
 
m (Reverted edits by 122.169.117.83 (talk | block) to last version by JohnBeckett)
(20 intermediate revisions by 7 users not shown)
Line 1: Line 1:
  +
{{TipImported
{{review}}
 
{{Tip
 
 
|id=671
 
|id=671
  +
|previous=670
|title=Add a newline after given pattern(s)
 
  +
|next=672
|created=March 5, 2004 23:58
+
|created=2004
 
|complexity=intermediate
 
|complexity=intermediate
|author=parv
+
|author=
|version=6.0
+
|version=7.0
 
|rating=4/1
 
|rating=4/1
  +
|category1=Searching
|text=
 
  +
|category2=
After having gone numb when trying to de parse HTML source code w/
 
 
}}
  +
You may need to insert a line break (newline) before or after each occurrence of a search pattern. That is useful if the newlines are needed, or as a temporary change to help understand some text. This tip shows how to insert newlines before or after specified strings, both manually and using a script to define a command so, for example, {{code|:%LineBreakAt <p> </p>}} would add a newline after {{code|<p>}} and {{code|</p>}} tags in an HTML file.
   
  +
==Using search and replace==
very long lines, i created the following function, thus macro and
 
  +
Suppose you want to insert a line break before each parenthesis and comma ('<code>(</code>', '<code>,</code>', '<code>)</code>') in a line. To do that, enter these commands:
  +
<pre>
  +
/[(,)]
  +
:s//\r&/g
  +
</pre>
   
  +
The first command searches for any occurrence of each of the three characters. You can refine this search (that is, [[Using command-line history|search again]] after correcting any problems with the [[Search patterns|search pattern]]). When the search correctly [[Highlight all search pattern matches|highlights]] the wanted hits, enter the second command to insert a newline before each hit in the current line. In the substitute command, the ''find'' pattern is empty, so the last search is used; in the ''replacement'', <code>\r</code> inserts a newline and <code>&</code> inserts the search hit (see [[search and replace]]).
command. It takes a list of one or more patterns/strings, and adds a
 
   
  +
Use <code>:%s//\r&/g</code> if you want to replace all occurrences in all lines.
newline after each. (Wrapping/Indentation is controlled by your own
 
 
settings.)
 
 
 
 
&lt;code&gt;
 
 
" Intentionally left incomplete to be complete as needed
 
 
nnoremap ,nl :NewLine
 
 
 
 
" Add line breaks in after given strings/regex
 
 
com! -nargs=+ -range -bar NewLine &lt;line1&gt;,&lt;line2&gt;call AddNewLine(&lt;f-args&gt;)
 
 
 
 
function! AddNewLine(...) range
 
 
let str_no = 1
 
 
 
 
while str_no &lt;= a:0
 
 
exec 'let var = a:' . str_no
 
 
 
 
" ` (backquote) is used as delimiters for s///, which is hard
 
 
" to distinguish but also is much rarer than delimiters.
 
 
"
 
 
" And, "No Match found" messages are suppressed (s///e)
 
 
"
 
 
" (The "exec..." is one long line.)
 
 
exec a:firstline . "," . a:lastline . 's`\(' . var . '\)\($\)\@!`\1\r`ge'
 
 
 
 
let str_no = str_no +1
 
 
endwhile
 
 
 
 
unlet! var
 
 
unlet str_no
 
 
endfunction
 
 
&lt;/code&gt;
 
 
 
 
 
}}
 
   
== Comments ==
+
==Using a script==
  +
The following script defines a user command to automate the insertion of line breaks. Save the script in a file called <code>linebreakat.vim</code>.
I forgot to mention that default range is limited to current line;
 
  +
<pre>
specify other range just like any other Vim command. And, that "com"
 
  +
" Insert a newline after each specified string (or before if use '!').
line is also one long line.
 
  +
" If no arguments, use previous search.
  +
command! -bang -nargs=* -range LineBreakAt <line1>,<line2>call LineBreakAt('<bang>', <f-args>)
 
function! LineBreakAt(bang, ...) range
  +
let save_search = @/
  +
if empty(a:bang)
  +
let before = ''
  +
let after = '\ze.'
  +
let repl = '&\r'
  +
else
  +
let before = '.\zs'
  +
let after = ''
  +
let repl = '\r&'
  +
endif
  +
let pat_list = map(deepcopy(a:000), "escape(v:val, '/\\.*$^~[')")
  +
let find = empty(pat_list) ? @/ : join(pat_list, '\|')
  +
let find = before . '\%(' . find . '\)' . after
  +
" Example: 10,20s/\%(arg1\|arg2\|arg3\)\ze./&\r/ge
 
execute a:firstline . ',' . a:lastline . 's/'. find . '/' . repl . '/ge'
  +
let @/ = save_search
 
endfunction
  +
</pre>
   
  +
In Vim, enter the command <code>:so linebreakat.vim</code> to source the script. If you want the script sourced automatically whenever Vim starts, place the file in directory <code>~/.vim/plugin</code> (Unix) or <code>$HOME/vimfiles/plugin</code> (Windows). On Windows, enter the following command to see the name of the required directory (which you may need to create):
(Argh! Missed that "to be complete"...)
 
  +
<pre>
  +
:echo expand('$HOME/vimfiles/plugin')
  +
</pre>
   
  +
;Usage examples
  +
{| class="cleartable"
  +
| <code>:LineBreakAt ( )</code> || Insert newline after each '(' and ')' in current line.
  +
|-
  +
| <code>:10,20LineBreakAt ( )</code> || Same, in lines 10 to 20 inclusive.
  +
|-
  +
| <code>:%LineBreakAt ( )</code> || Same, whole buffer.
  +
|-
  +
| <code>:LineBreakAt! ( )</code> || Insert newline before each '(' and ')' in current line.
  +
|-
  +
| <code>:%LineBreakAt</code> || Insert newline after each occurrence of last-used search pattern.
  +
|-
  +
| <code>:%LineBreakAt!</code> || Insert newline before each occurrence of last-used search pattern.
  +
|}
   
  +
You do not need to type the entire command; depending on your system, you may find that typing <code>:L</code> is sufficient (press the Tab key to expand <code>L</code> to see other commands that start with that text {{help|'wildchar'}}).
'''Anonymous'''
 
, March 6, 2004 0:09
 
----
 
Why not just use the 's'ubstitution command and ^V^M (ctrl-v, ctrl-m) (or ^Q^M)?
 
   
  +
The arguments to <code>LineBreakAt</code> are the strings that you want to find; they are not search patterns. For example, <code>:%LineBreakAt! *</code> will insert a newline before each asterisk in the whole buffer (the command escapes the <code>*</code> by preceding it with a backslash, so the asterisk has no special meaning).
To put a new line after each &lt;br /&gt; tag in your html try something like
 
   
  +
If you want to include a space in the text, type a backslash before the space. For example, <code>:%LineBreakAt! The\ rain</code> will insert a newline before each occurrence of "The rain" in the whole buffer.
:%s/&lt;br \/&gt;/&lt;br \/&gt;^V^M/g
 
   
  +
After searching for a pattern (for example <code>\<t\w*e\></code> to find all words starting with '<code>t</code>' and ending with '<code>e</code>'), using <code>:%LineBreakAt!</code> (with no arguments) will insert a newline before each of the search hits, and using <code>:%LineBreakAt</code> will insert a newline after each of the search hits.
andy47--AT--halfcooked.com
 
, March 6, 2004 2:51
 
----
 
( In OP i forgot to explicitly mention that the the substitution is done
 
on a pattern which is NOT ALREADY AT THE END of the line. In
 
addition, it should have been labeled Basic ... Only if i could
 
rewind time ... )
 
   
  +
===Explanation===
To Andy47,
 
  +
The <code>:command</code> line defines a user command (<code>LineBreakAt</code>) that calls a function with the same name. The first argument to the function (<code>bang</code>) will be '<code>!</code>' if an exclamation mark was typed after the command, and will be an empty string otherwise. The arguments typed after the command (one or more strings separated by whitespace) are passed as the <code>...</code> in the function. {{help|<f-args>|&lt;f-args&gt;}}
   
  +
The function converts the <code>...</code> arguments (accessed as the list <code>a:000</code>) by escaping the characters that have a special meaning when searching, for example, <code>/</code> is replaced with <code>\/</code> because the substitute command uses slash as a delimiter. The list of arguments is copied with <code>deepcopy()</code> (because arguments to a Vim function cannot be changed), then <code>map()</code> processes each argument (<code>v:val</code>) with the <code>escape()</code> function; the result is copied into <code>pat_list</code> (a list of the individual escaped search patterns).
I wrote the function mainly because to get the effect of giving OR'd
 
pattern, in LHS of s///, simply separated by spaces w/o having to
 
escape the darned "|"; also, to not having to remember to put
 
"\($\)\--AT--!" -- zero width negative look ahead assertion for end-of-line
 
-- on each invocation of s///. \--AT--! is used to limit the number of
 
useless blank lines.
 
   
  +
A search pattern is then formed in the <code>find</code> variable. If <code>bang</code> is empty and there are three arguments, <code>arg1 arg2 arg3</code>, the pattern will be <code>\%(arg1\|arg2\|arg3\)\ze.</code>. Each argument is separated with <code>\|</code> (''or''), and the result is grouped (<code>\%(...\)</code>) so that what follows applies to the whole group, rather than to <code>arg3</code>. The <code>.</code> at the end requires that a character that is not a newline follows the pattern (so another newline will not be inserted). The <code>\ze</code> marks the end of the search hit, so the newline will be inserted before the character that follows the pattern.
As to using ^V^M, instead of \r i suppose, ... I tried using \&lt;CR&gt; ,
 
&lt;CR&gt; , ^V^M and ^M in a normal macro, which was not including a new
 
line. (I had not tried ^Q^M.) Instead, search for 'g' was being
 
initiated, given macro's RHS was ":%s/\(&gt;\)\($\)\--AT--!/\1^M/g" (where ^M
 
is one of \&lt;CR&gt; , &lt;CR&gt; , ^V^M, ^M).
 
   
  +
If <code>bang</code> is empty, the replacement text (<code>repl</code>) is <code>&\r</code> (the search hit then newline), or is <code>\r&</code> (a newline then the search hit), otherwise.
The same excat macro works as desired when manually executed. After
 
wasting time w/ above four character sequences, i used \r.
 
   
  +
The <code>:execute</code> command performs a substitute (<code>:s///ge</code>) on the given range of lines (by default, the current line; otherwise, as specified). The <code>g</code> flag (global) replaces all occurrences on each specified line, and the <code>e</code> flag prevents an error message being displayed if no matches are found.
   
  +
==References==
- Parv
 
  +
*{{help|:command}}
  +
*{{help|:substitute}}
  +
*{{help|:function}}
  +
*{{help|map()}}
   
  +
==Comments==
parv
 
, March 6, 2004 12:33
 
----
 
<!-- parsed by vimtips.py in 0.756181 seconds-->
 

Revision as of 09:54, 10 September 2012

Tip 671 Printable Monobook Previous Next

created 2004 · complexity intermediate · version 7.0


You may need to insert a line break (newline) before or after each occurrence of a search pattern. That is useful if the newlines are needed, or as a temporary change to help understand some text. This tip shows how to insert newlines before or after specified strings, both manually and using a script to define a command so, for example, :%LineBreakAt <p> </p> would add a newline after <p> and </p> tags in an HTML file.

Using search and replace

Suppose you want to insert a line break before each parenthesis and comma ('(', ',', ')') in a line. To do that, enter these commands:

/[(,)]
:s//\r&/g

The first command searches for any occurrence of each of the three characters. You can refine this search (that is, search again after correcting any problems with the search pattern). When the search correctly highlights the wanted hits, enter the second command to insert a newline before each hit in the current line. In the substitute command, the find pattern is empty, so the last search is used; in the replacement, \r inserts a newline and & inserts the search hit (see search and replace).

Use :%s//\r&/g if you want to replace all occurrences in all lines.

Using a script

The following script defines a user command to automate the insertion of line breaks. Save the script in a file called linebreakat.vim.

" Insert a newline after each specified string (or before if use '!').
" If no arguments, use previous search.
command! -bang -nargs=* -range LineBreakAt <line1>,<line2>call LineBreakAt('<bang>', <f-args>)
function! LineBreakAt(bang, ...) range
  let save_search = @/
  if empty(a:bang)
    let before = ''
    let after = '\ze.'
    let repl = '&\r'
  else
    let before = '.\zs'
    let after = ''
    let repl = '\r&'
  endif
  let pat_list = map(deepcopy(a:000), "escape(v:val, '/\\.*$^~[')")
  let find = empty(pat_list) ? @/ : join(pat_list, '\|')
  let find = before . '\%(' . find . '\)' . after
  " Example: 10,20s/\%(arg1\|arg2\|arg3\)\ze./&\r/ge
  execute a:firstline . ',' . a:lastline . 's/'. find . '/' . repl . '/ge'
  let @/ = save_search
endfunction

In Vim, enter the command :so linebreakat.vim to source the script. If you want the script sourced automatically whenever Vim starts, place the file in directory ~/.vim/plugin (Unix) or $HOME/vimfiles/plugin (Windows). On Windows, enter the following command to see the name of the required directory (which you may need to create):

:echo expand('$HOME/vimfiles/plugin')
Usage examples
:LineBreakAt ( ) Insert newline after each '(' and ')' in current line.
:10,20LineBreakAt ( ) Same, in lines 10 to 20 inclusive.
:%LineBreakAt ( ) Same, whole buffer.
:LineBreakAt! ( ) Insert newline before each '(' and ')' in current line.
:%LineBreakAt Insert newline after each occurrence of last-used search pattern.
:%LineBreakAt! Insert newline before each occurrence of last-used search pattern.

You do not need to type the entire command; depending on your system, you may find that typing :L is sufficient (press the Tab key to expand L to see other commands that start with that text :help 'wildchar').

The arguments to LineBreakAt are the strings that you want to find; they are not search patterns. For example, :%LineBreakAt! * will insert a newline before each asterisk in the whole buffer (the command escapes the * by preceding it with a backslash, so the asterisk has no special meaning).

If you want to include a space in the text, type a backslash before the space. For example, :%LineBreakAt! The\ rain will insert a newline before each occurrence of "The rain" in the whole buffer.

After searching for a pattern (for example \<t\w*e\> to find all words starting with 't' and ending with 'e'), using :%LineBreakAt! (with no arguments) will insert a newline before each of the search hits, and using :%LineBreakAt will insert a newline after each of the search hits.

Explanation

The :command line defines a user command (LineBreakAt) that calls a function with the same name. The first argument to the function (bang) will be '!' if an exclamation mark was typed after the command, and will be an empty string otherwise. The arguments typed after the command (one or more strings separated by whitespace) are passed as the ... in the function. :help <f-args>

The function converts the ... arguments (accessed as the list a:000) by escaping the characters that have a special meaning when searching, for example, / is replaced with \/ because the substitute command uses slash as a delimiter. The list of arguments is copied with deepcopy() (because arguments to a Vim function cannot be changed), then map() processes each argument (v:val) with the escape() function; the result is copied into pat_list (a list of the individual escaped search patterns).

A search pattern is then formed in the find variable. If bang is empty and there are three arguments, arg1 arg2 arg3, the pattern will be \%(arg1\|arg2\|arg3\)\ze.. Each argument is separated with \| (or), and the result is grouped (\%(...\)) so that what follows applies to the whole group, rather than to arg3. The . at the end requires that a character that is not a newline follows the pattern (so another newline will not be inserted). The \ze marks the end of the search hit, so the newline will be inserted before the character that follows the pattern.

If bang is empty, the replacement text (repl) is &\r (the search hit then newline), or is \r& (a newline then the search hit), otherwise.

The :execute command performs a substitute (:s///ge) on the given range of lines (by default, the current line; otherwise, as specified). The g flag (global) replaces all occurrences on each specified line, and the e flag prevents an error message being displayed if no matches are found.

References

Comments