How to create the strings sequence into specified line in edited text? - vim

Here is the initial text.
test1
test2
Only two lines in the text.
I want to insert strings sequence into from 5th line into 16th line.
I have tried it with below codes.
for i in range(1,12)
echo ".item".i.","
endfor
1.the initial text.
2.to enter into command mode and input the codes
Two problems to be solved.
1.echo command output the first string .item1 before endfor.
for i in range(1,12)
echo ".item".i.","
2.How create the strings sequence into specified line:from 5th till 16th in edited text with vimscript?
The desired result is as below.
Almost done!
What i get is as below with the command :pu! =map(range(1,12), 'printf(''item%1d'', v:val)').
Both of them can't work.
:5pu! =map(range(1,12), 'printf(''item%1d'', v:val)')
:5,16pu! =map(range(1,12), 'printf(''item%1d'', v:val)')
The last issue for my desired format is when the cursor is on the 3th line ,how to create the desired output?

In order to insert the missing lines, without inserting unrequired empty lines (-> append() + repeat([''], nb) + possible negative nb)
:let lin = 5 - 1
:call append('$', repeat([''], lin-line('$')))
Then, in order to insert what you're looking for (no need for printf() if you don't want to format the numbers)
:call append(lin, map(range(1,12), '"item".v:val'))
PS: I'd rather avoid :put when I can as it's kind of difficult to use with complex expressions.

Assuming you are in a Unix based operating system, you have a seq command.
So you can do:
$ seq -f 'Item %.0f' 20
Item 1
Item 2
...
Item 20
Inside vim you can try the reading from external command approach:
:r! seq -f 'Item \%.0f' 20

Related

Write output from command line into file in vim

I would like to insert at the end of each line the number of alphabetic characters on that line. To do this on one line is easy. I search using :s/\a//gn and get the occurrence of alphabetic characters in the command line and then A and space and enter the number.
My problem arises when I have so many lines that it becomes extremely tedious to do this. I am trying to create a macro but am having difficulty getting command line output into it. Is there a way to do this without resorting to *nix commands? I have access to a *nix box but not all the time.
So if my file had the following content:
abc2d4s
jd4a5ag
jdf7fjf
abdd5ff
I would like the output to look like this:
abc2d4s 5
jd4a5ag 5
jdf7fjf 6
abdd5ff 6
I was thinking if there was a way to get the replace output piped into the register somehow but cannot figure out how to do it, but maybe there is a better way.
You can capture the output of the :s///gn command with :redir, but in this case, I would rather implement the counting via substitute() and :help sub-replace-expression:
:%s/.*/\=submatch(0) . ' ' . len(substitute(submatch(0), '\A', '', 'g'))/
This matches the entire line (.*), then removes all non-alphabetic characters (\A), and appends the length of the result. Note: Works only for ASCII characters (but \a covers only those, anyway)!
this cmd should give you that output:
%s/.*/\=submatch(0).' '.(len(submatch(0))-len(substitute(submatch(0),'\a','','g')))
One way to do that would be to use a simple macro:
:%norm A <C-v><C-r>=col('.')-2<C-v><CR>
which should look like:
:%norm A ^R=col('.')-2^M
where we enter insert mode at the end of each line and insert a space followed by the column number of the last character.
A variant:
:%norm A^R=" ".len(getline('.'))^M

Writing whole alphabet in Vim

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.

How to let Vim process my command backforward?

Suppose I have 5 lines of text, if I input some commands to let vim process each line, Vim will process the text one by one, first line, second line, ... the last line. what I want is to let Vim process my text in reverse order. that is the last line first, then the 4th line, and at last the first line.
Why I need this?
I have the following text
1234567890
abc
123
def
1234567890
123456789
I want to remove the newline symbol(\n) from lines which contains 3 characters. so after processing,I will get the following text
1234567890
abc123def1234567890
123456789
It seems a piece of cake, I use the following command
:%s/\v(^\w{3})\n/\1/
But what i got is
1234567890
abc123
def1234567890
1234567890
Why? I guess vim first remove \n from the second line, then this line has text abc123, now vim will not remove \n after 123, since it's not 3 characters now, so vim process the next line def, and remove \n from it, that's the result i got.
If vim can process from back to front, this will not happen and I can got the result I want.
BTW, I can get the expected result in other ways, I just want to know whether this is possible.
Explicitly loop over the range of lines (e.g. the visually selected ones) backwards, then execute the command on each line. I've used :join here instead of the :substitute with a newline:
:for i in range(line("'>"), line("'<"), -1)| silent execute i . 'g/^\w\{3}$/join!' | endfor
Can be achieved using perl:
while (<>) {
chomp if (/^...$/);
print;
}
In this case it is easier to use the :global command to join the lines.
:g/^\w\{3}$/normal! gJ
The command gJ joins the current line with the following line without inserting any spaces. The global command above calls gJ on each line containing only three characters. It works by marking all the matches first, before performing the operation, so the problem of looping is avoided.
this line should do what you want:
:%s/\v(\_^\w{3}\n)+/\=substitute(submatch(0),"\n","","g")/
if you want to do it simpler with external command, e.g. awk, you could:
%!awk '{printf "\%s", length($0)==3? $0:$0"\n"}'

Add Padded Incremental Number to End of Each Line in VIM

I have a text file with a list in it:
dateformatfile.ext
dateformatfile.ext
dateformatfile.ext
...
I need to add a padded number to the end of each, like so:
dateformatfile.ext 00001
dateformatfile.ext 00002
dateformatfile.ext 00003
...
There are a lot, so I need to have a command to do this somehow.
Thanks in advance.
Assuming you want to do this for every line in your file, you can use the line number like this:
:execute "% normal A \<C-R>=printf(\"%05d\", line(\".\"))\<CR>"
where
execute(...) runs the string as a command
% normal runs a normal command on every line of the file
A appends to the line
<C-R>= inserts the result of a command
printf("%05d", ...) formats the second parameters as a five-digit number
line(".") gets the number of the current line
<CR> completes the <C-R>= insertion
if your text block is sitting at the beginning of the file. which means the line you want to append "00001" is the first line of your file, try this command, I just simply check the line ending with ext, you could change it to right regex if it is needed:
:%s/ext$/\="ext ".printf("%05d", line("."))/g
if the text block is not at the beginning of the file. You just check the first line (the line you want to append 00001) of the block and get the line number, for example, line number 5:
:let b=5|%s/ext$/\="ext ".printf("%05d", line(".")-b+1)/g
Here is my take.
Position cursor on first line where you want to add the first number.
:let i=0 Define a variable to hold the count.
qm Start to record a macro into register m.
A <C-R>=printf("%05d", i)<CR><ESC> Add a space and the ouput from printf.
:let i+=1 Increment the count for the next macro execution.
q End the recording of the macro.
jVG Visual select the rest of the document where we want to add numbers.
:normal #m Execute the macro to add the numbers to the selected lines.
I think this approach has some advantages:
No ugly escaping necessary.
The count is not tied to the line number. Allowing for offsets.
Using a macro can be easily combined with the :global command. For example:
:g/ext$/ normal #m Execute macro stored in register m on lines ending in ext.
One could very easily do this using awk. The NR variable gives you the record number, and records map to lines unless the RS variable is redefined. So the following:
awk -e '{ print $0 NR }' filename should do the trick. Padding them is an exercise left up to the reader.
I would do this using macros (I like macros :D).
First, let's take care of the numbers (we'll pad them later).
Add manually the number 1 at the end of the first line.
Then record this macro on the first line :
qq - record the macro q
$ - go at the end of the line
F<space> - go backward to the last space
"ay$ - copy till the end of the line in the buffer a
j$ - go at the end of the line below
"ap - copy the buffer content
<ctrl+A> - increment the number
q - stop recording the macro
Now you can apply it a bunch of times with 1000#q (it will stop at the end of the file).
This is not really pretty but it does the job.
For the padding, I would use another ugly trick. First, use a regex to match 3 digits numbers and add a 0 before, then do the same with 2 digits numbers (add two 0 this time) and so on...
vim macros are pretty ugly but they are useful to me when I am too tired to write a oneliner (I should learn awk though). Also, they can help you remember some obscure, yet useful vim shortcuts.
If you have PERL in your environment, you can run a PERL one-liner inside your VIM session.
:%! perl -pe " $count++ ; s/$/$count/"
The caveat is that you might have to use double quotes around your perl script. On my PC, PERL will run if I use single quotes. But I cannot address variables with the dollar sign.

How to add line numbers to range of lines in Vim?

How can I add line numbers to a range of lines in a file opened in Vim? Not as in :set nu—this just displays line numbers—but actually have them be prepended to each line in the file?
With
:%s/^/\=line('.')/
EDIT: to sum up the comments.
This command can be tweaked as much as you want.
Let's say you want to add numbers in front of lines from a visual selection (V + move), and you want the numbering to start at 42.
:'<,'>s/^/\=(line('.')-line("'<")+42)/
If you want to add a string between the number and the old text from the line, just concatenate (with . in VimL) it to the number-expression:
:'<,'>s/^/\=(line('.')-line("'<")+42).' --> '/
If you need this to sort as text, you may want to zero pad the results, which can be done using printf for 0001, 0002 ... instead of 1, 2... eg:
:%s/^/\=printf('%04d', line('.'))/
Anyway, if you want more information, just open vim help: :h :s and follow the links (|subreplace-special|, ..., |submatch()|)
cat -n adds line numbers to its input. You can pipe the current file to cat -n and replace the current buffer with what it prints to stdout. Fortunately this convoluted solution is less than 10 characters in vim:
:%!cat -n
Or, if you want just a subselection, visually select the area, and type this:
:!cat -n
That will automatically put the visual selection markers in, and will look like this after you've typed it:
:'<,'>!cat -n
In order to erase the line numbers, I recommend using control-v, which will allow you to visually select a rectangle, you can then delete that rectangle with x.
On a GNU system: with the external nl binary:
:%!nl
With Unix-like environment, you can use cat or awk to generate a line number easily, because vim has a friendly interface with shell, so everything work in vim as well as it does in shell.
From Vim Tip28:
:%!cat -n
or
:%!awk '{print NR,$0}'
But, if you use vim in MS-DOS, of win9x, win2000, you loss these toolkit.
here is a very simple way to archive this only by vim:
fu! LineIt()
exe ":s/^/".line(".")."/"
endf
Or, a sequence composed with alphabet is as easy as above:
exe "s/^/".nr2char(line("."))."/"
You can also use a subst:
:g/^/exe ":s/^/".line(".")."^I/"
You can also only want to print the lines without adding them to the file:
"Sometimes it could be useful especially be editing large source files to print the line numbers out on paper.
To do so you can use the option :set printoptions=number:y to activate and :set printoptions=number:n to deactivate this feature.
If the line number should be printed always, place the line set printoptions=number:y in the vimrc."
First, you can remove the existing line numbers if you need to:
:%s/^[0-9]*//
Then, you can add line numbers. NR refers to the current line number starting at one, so you can do some math on it to get the numbering you want. The following command gives you four digit line numbers:
:%!awk '{print 1000+NR*10,$0}'
The "VisIncr" plugin is good for inserting columns of incrementing numbers in general (or letters, dates, roman numerals etc.). You can control the number format, padding, and so on. So insert a "1" in front of every line (via :s or :g or visual-block insert), highlight that column in visual-block mode, and run one of the commands from the plugin.
If someone wants to put a tab (or some spaces) after inserting the line numbers using the this excellent answer, here's a way. After going into the escape mode, do:
:%s/^/\=line('.').' '/
^ means beginning of a line and %s is the directive for substitution. So, we say that put a line number at the beginning of each line and add 4 spaces to it and then put whatever was the contents of the line before the substitution, and do this for all lines in the file.
This will automatically substitute it. Alternatively, if you want the command to ask for confirmation from you, then do:
:%s/^/\=line('.').' '/igc
P.S: power of vim :)
The best reply is done in a duplicate question.
In summary:
with CTRL-V then G I 0 You can insert a column of zero.
Then select the whole column and increment:
CTRL-V g CTRL-A
See also: https://vim.fandom.com/wiki/Making_a_list_of_numbers#Incrementing_selected_numbers

Resources