I had a large file I was trying to reformat which involved removing the 2nd to nth repeating sets on 2 to 100 lines per duplicate.
The data looked like
element1.element2.element...field.comment
I wanted to remove the repetition in elements after the first instance so of course I went complicated :) and did a macro something like
In a macro Yanked first element on current line to register p and then processed lines yanking the first element into register o and then doing, still in the macro
:if (#p=!#o)|:.s/paste register p//g|else|:norm! j|endif
Now this worked OK except when it got to a line where #p<>#o the :norm! j part stayed in : mode until I manually escaped once or twice then executed the :norm! j command.
I solved the problem an easier way but would like to know why it was only on the else portion that it wouldn't leave :ex mode.
From :help norm
:norm[al][!] {commands} *:norm* *:normal*
...
This command cannot be followed by another command,
since any '|' is considered part of the command.
...
An alternative is to use |:execute|, which uses an
expression as argument. This allows the use of
printable characters to represent special characters.
Example: >
:exe "normal \<c-w>\<c-w>"
So this would do the trick:
:if (#p=!#o)|:.s/paste register p//g|else|:exe "norm j"|endif
Related
In Vim I need to convert all lowercase to uppercase and all uppercase to lowercase with a single command. So if my text file looks like this..
Hello World
.. it needs to be toggled to look like this..
hELLO wORLD
I know :%s/[a-z]/\U&/g will change all lowercase to uppercase and that :%s/[A-Z]/\L&/g will change all uppercase to lowercase. But how would I write that to do both at the same time?
In addition I know if my cursor is at the top of the file VG~ will toggle case everything but that's not the answer I need. Thank you.
<Esc>1GVG~
Explanation:
<Esc> — return to Normal mode; just in case we're in Insert mode or Command line
1G — jump to the 1st line
V — start Visual mode
G — jump to the last line extending selection
~ — toggle case in the selection
Or
<Esc>1Gg~G
g~<motion> — change case during motion; the motion is G (jump to last line)
Docs: http://vimdoc.sourceforge.net/htmldoc/change.html#~
Looks like you already know everything you need. ggVG~ marks all your code and toggles the case. If you want a single command you can either use:
:nnoremap <keybinding> ggVG~
or use this function, which does the same, but keeps your current position in the file:
function ToggleCase()
exec "normal! mqHmw"
exec "normal! ggVG~"
exec "normal! 'wzt`q"
endfunction
command ToggleCase silent call ToggleCase()
the first and last exec mark your position in the file and restore them, after the case toggling. See: :h marks
type :ToggleCase to use the function. Of cause you can bind this to a keybinding as well.
:nnoremap <keybinding> :ToggleCase<cr>
Since you mentioned using a single command and you mentioned some :%s/.../ substitutions, I'll offer this one:
:%normal! g~~
This will run the g~~ command to switch case of a single line, for each line of the buffer.
One more way to accomplish this, if you're ok adopting a plug-in, is to use the kana/vim-textobj-entire plug-in for a text object for the entire buffer.
As the plug-in README.md file says:
Though these are trivial operations (e.g. ggVG), text object versions are more handy, because you do not have to be conscious of the cursor position (e.g. vae).
With this plug-in installed and enabled, you can switch case of the whole buffer with:
g~ae
I sometimes need to write the whole alphabet abcd…z and I hate typing it letter by letter in Vim's insert mode. Does there exist any method to do this more efficiently?
I know about the ga command which gives me the ascii code of the character where the cursor is … but don't know anything about how to mix it with my standard solution to type numbers from 1 to (for example) 5000: a1ESCqqyyp^Aq4998#q …
Using set nrformats+=alpha:
ia<Esc>qqylp<C-a>q24#q
Step by step:
ia<Esc> " Start with 'a'
qqylp<C-a>q " #q will duplicate the last character and increment it
24#q " Append c..z
If your shell does brace expansion this is a pretty elegant solution:
:r !printf '\%s' {a..z}
:read! reads the output of an external command into the current buffer. In this case, it reads the output of the shell's printf applied to {a..z} after it's been expanded by the shell.
How about this command:
:put =join(map(range(char2nr('a'),char2nr('z')),'nr2char(v:val)'),'')
Collect the ASCII values of the characters in the range from a to z, then map them over the nr2char() function and insert the result into the current buffer with :put =.
When you leave out the enclosing join( … ,'') you get the characters on a separate line each.
See
:h nr2char(),
:h char2nr(),
:h :put,
and look up range(), map(), join() and friends in the list-functions table.
First, set nrformats+=alpha.
Then:
ia<ESC>Y25p<CTRL-V>}g<CTRL-A>k26gJ
Which means:
ia insert the initial a
Y25p yank the a and duplicate it on 25 lines
<CTRL-V> go into visual block mode
} go to the last character at the end of the current paragraph
g<CTRL-A> incrementally increase each alphabetic character (see help v_g_CTRL-A)
k go up one line
26gJ join 26 lines without inserting or removing any spaces
Which leads to:
abcdefghijklmnopqrstuvwxyz
I have found a shorter solution (you don't need to change nrformats beforehand) while solving http://www.vimgolf.com/challenges/5ebe8a63d8085e000c2f5bd5
iabcdefghijklm<Esc>yiwg??P
which means:
iabcdefghijklm<Esc> insert first half of the alphabet
yiw copy it
g?? ROT13 encode (shift by 13 letters) to get the second half
P paste the first half
You might try using Vim abbreviations or a full-fledged snippet manager plugin like UltiSnips. It might take a few moments to set up, and you'd have to type that alphabet one more time to define it as an abbreviation or snippet, but after that you'd be able to insert the alphabet or any other common chunk of text much more easily.
Suppose I'm editing the following document (* = cursor):
Lions
Tigers
Kittens
Puppies
*
Humans
What sequence can I use to delete the surrounding white space so that I'm left with:
Lions
Tigers
Kittens
Puppies
*
Humans
Note: I'm looking for an answer that handles any number of empty lines, not just this exact case.
EDIT 1: Line numbers are unknown and I only want to effect the span my cursor is in.
EDIT 2: Edited example to show I need to preserve leading whitespace on edges
Thanks
Easy. In normal mode, dipO<Esc> should do it.
Explanation:
dip on a blank line deletes it and all adjacent blank lines.
O<Esc> opens a new empty line, then goes back to normal mode.
Even more concise, cip<Esc> would roll these two steps into one, as suggested by #Lorkenpeist.
A possible solution is to use the :join command with a range:
:?.?+1,/./-1join!
Explanation:
[range]join! will join together a [range] of lines. The ! means with out inserting any extra space.
The starting point is to search backwards to the first character then down 1 line, ?.?+1
As the 1 in +1 can be assumed this can be abbreviated ?.?+
The ending point is to search forwards to the next character then up 1 line, /./-1
Same as before the 1 can be assumed so, /./-
As we are using the same pattern only searching forward the pattern can be omitted. //-
The command :join can be shorted to just :j
Final shortened command:
:?.?+,//-j!
Here are some related commands that might be handy:
1) to delete all empty lines:
:g/^$/d
:v/./d
2) Squeeze all empty lines into just 1 empty line:
:v/./,//-j
For more help see:
:h :j
:h [range]
:h :g
:h :v
Short Answer: ()V)kc<esc>
In normal mode, if you type () your cursor will move to the first blank line. ( moves the cursor to the beginning of the previous block of non-blank lines, and ) moves the cursor to the end (specifically, to the first blank line after said block). Then a simple d) will delete all text until the beginning of the next non-blank line. So the complete sequence is ()d).
EDIT: You're right, that deletes the whitespace at the beginning of the next non-blank line. Instead of d) try V)kd. V puts you in visual line mode, ) jumps to the first non-blank line (skipping the whitespace at the beginning of the line), k moves the cursor up one line. At this point you've selected all the blank lines, so d deletes the selection.
Finally, type O (capital O) followed by escape to crate a new blank line to replace the ones you deleted. Alternatively, replacing dO<Escape> with c<Escape> does the same thing with one less keystroke, so the entire sequence would be ()V)kc<Esc>.
These answers are irrelevant after the updated question:
This may not be the answer you want to hear, but I would make use of ranges. Take a look at the line number for the first empty line (let's say 55 for example) and the second to last empty line (perhaps 67). Then just do :55,67d.
Or, perhaps you only want there to ever be one empty line in your whole file. In that case you can match any occurrence of one or more empty lines and replace them with one empty line.
:%s/\(^$\n\)\+/\r/
This answer works:
If you just want to use normal mode you could search for the last line with something on it. For instance,
/.<Enter>kkVNjd
I didn't test so much, but it should work for your examples. There maybe more elegant solutions.
function! DelWrapLines()
while match(getline('.'),'^\s*$')>=0
exe 'normal kJ'
endwhile
exe 'silent +|+,/./-1d|noh'
exe 'normal k'
endfunction
source it and try :call DelWrapLines()
I know this question has already been resolved, but I just found a great solution in "sed & awk, 2nd Ed." (O'Reilly) that I thought was worth sharing. It does not use vim at all, but instead uses sed. This script will replace all instances of one or more blank lines (assuming there is no whitespace in those lines) with a single blank line. On the command line:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile
Keep in mind that sed does not actually edit the file, but instead prints the edited lines to standard output. You can redirect this input to a file:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile
Be careful though, if you try to write it directly to myfile, it will just delete the entire contents of the file, which is clearly not what you want! After you write the output to tempfile, you can just mv tempfile myfile and tada! All instances of multiple blank lines are replaced by a single blank line.
Even better:
cat -s myfile > temp
mv temp myfile
cat is awesome, yes?
Bestest:
If you want to do it inside vim, you can replace all instances of multiple blank lines with a single blank line by using vim's handy feature of executing shell commands on a range of lines within vim.
:%!cat -s
That's all it takes, and your entire file is reformatted all nice!
I'm hand-editing CNC Gcode text files and need a way to reference locations in the file and on the toolpath.
I want to modify every line in the text file so that it begins with the the upper case letter N followed by the line number, incremented in tens for each successive line, then a whitespace followed by the original text on that line. How can I do this in Vim?
I'm not sure about vi, but (since you're using the vim tag) Vim allows you to accomplish your task as follows:
Adjust the first line by hand (insert a N10 at the beginning of the line), then put the cursor at the beginning of the next line.
Press qb to start recording a macro (the b names the register used to store the macro; feel free to use a different letter -- and definitely do use a different letter if you've got something useful stashed away in b).
Move the cursor upward to the beginning of the previous line (which you have adjusted by hand). Press v to start visual selection mode, then f to move the cursor to the next space on the line (if you use a single space as your whitespace separator, that is; adjust this step if you're using a tab or multiple spaces).
Press y to yank the selected text. This will also remove the visual selection.
Move the cursor to the beginning of the next line. Press P to insert the previously yanked text before the cursor, that is, on the very beginning of the line.
Move the cursor to the numeric part of the line header. Press 10 C-a (1, 0, control + A) to increment that number by 10.
Move the cursor to the beginning of the next line. Press q to stop recording the macro.
Press 10000000 #b to execute the macro 10000000 times or until it hits the end of the file. This should be enough to take care of all the lines in your file, unless it is really huge, in which case use a bigger number.
...or use Vim to write a simple script to do the job in whichever language you like best, then run it from a terminal (or from withing Vim with something like :!./your-script-name). ;-)
The following command will prepend ‘N<line number * 10>’ to every line:
:g/^/exe 'normal! 0iN' . (line('.')*10) . ' '
You can do it easily in Vim with this:
:%s/^/\=line(".")*10 . " "/
This replaces the start of every line with the result of an expression that gives the line number times ten, followed by a space.
I have not timed it, but I suspect it might be noticeably faster than the other Vim solutions.
Cheating answer:
:%!awk '{print "N" NR "0", $0}'
There are two ways to implement that without resorting to external
tools: via a macro or by using Vimscript. In my opinion, the first way
is a little cumbersome (and probably not as effective as the solution
listed below).
The second way can be implemented like this (put the code into your
.vimrc or source it some other way):
function! NumberLines(format) range
let lfmt = (empty(a:format) ? 'N%04d' : a:format[0]) . ' %s'
for lnum in range(a:firstline, a:lastline)
call setline(lnum, printf(lfmt, lnum, getline(lnum)))
endfor
endfunction
The NumberLines function enumerates all lines of the file in a given
range and prepends to each line its number according to the provided
printf-format (N%04d, by default).
To simplify the usage of this function, it is convenient to create
a command that accepting a range of lines to process (the whole file,
by default) and a optional argument for the line number format:
command! -range=% -nargs=? NumberLines <line1>,<line2>call NumberLines([<f-args>])
I frequently use Shift+J in visual mode to join several selected lines into a single line with the original lines separated by spaces. But I am wondering if there is an opposite shortcut such that it will split selected words into separate lines (one word per line).
Of course I can do:
:'<,'>s/ /^M/g
But something more succinct in terms of keystrokes would be very useful. Has anyone else found a way to do this?
Thanks in advance,
-aj
Map it if you are using it often in your ~/.vimrc file or similar
vnoremap \ll :'<,'>s/ /^M/g<cr>
nnoremap \ll :s/ /^M/g<cr>
if you are only wanting to to it multiple times now you can use & command to repeat last search also
Theres also gqq but thats for textwidth eg 80 chars
Recently I stumbled across the same problem. My solution is the following vim function (put in my .vimrc):
function SplitToLines() range
for lnum in range(a:lastline, a:firstline, -1)
let words = split(getline(lnum))
execute lnum . "delete"
call append(lnum-1, words)
endfor
endfunction
This can be used with line ranges, e.g., as follows
:26call SplitToLines()
which would split line number 26. But the code also handles ranges of lines gracefully (that's why the range in the for loop is built in reverse order).
1,10call SplitToLines()
will split lines 1 to 10 into several lines. However, I mostly use this in visual mode, like
'<,'>call SplitToLines()
which splits all lines that are visually marked. Of course you may define some single letter abbreviation for this function call (with auto completion by Tab I do not find it necessary). Also note that by adding an additional argument which would also be used by 'split' you can have a function that does split lines at specific patterns (instead of just white space).
I use this in my config to Un-Join/split the last word on current line:
nnoremap <C-J> g_F<Space><Space>i<CR><Esc>k
It maps CTRL-j to do the opposite of Join, I think of it as Counter-Join :) I mostly use it to convert between K&R style vs ...the other kind of curly brace placement.
g_ : search for the last non-whitespace on current line
F<Space> : reverse-find first space
<Space> : go one character forward
i : enter insert mode
<CR> : insert a line break
<Esc> : return to normal mode
k : go up one line to where we begun