Can VIM do this Sublime trick? - vim

I want to edit this text:
Aenean vel sem bibendum, eleifend odio a, dictum nibh.
The third word in the above line is
Morbi eget est vitae quam ultricies porta vitae quis nunc.
The third word in the above line is
Praesent accumsan ex a laoreet cursus.
The third word in the above line is
Quisque efficitur lectus at dolor mollis, sit amet tristique libero lobortis.
The third word in the above line is
to this text:
Aenean vel sem bibendum, eleifend odio a, dictum nibh.
The third word in the above line is sem
Morbi eget est vitae quam ultricies porta vitae quis nunc.
The third word in the above line is est
Praesent accumsan ex a laoreet cursus.
The third word in the above line is ex
Quisque efficitur lectus at dolor mollis, sit amet tristique libero lobortis.
The third word in the above line is lectus
To do this with Sublime
Select repeated part
ALT+F3
UpArrow
HOME
3 x CTRL+RightArrow
CTRL+Shift+LeftArrow
CTRL+C
DownArrow
END
CTRL+V
this trick is very useful in many cases.
can VIM do it?

It should work easily with a macro. If you have your cursor on the first character of the first line then:
qq: start recording macro named q
2w: advance two words
yw: yank (copy) word
j$: jump to next line and go to end of line
p: paste what you've yanked
+: go to start of next line
q: stop recording macro.
3#q: execute macro named q 3 times

As an alternative to a macro solution, you could also use a substitute command
:%s/\vis $\zs/\=split(getline(line('.')-1), ' ')[2]
breakdown
:%s/ start a substitute command
\vis $\zs/ select lines ending with "is "
use \zs to start replacing after the match
\=split(getline(line('.')-1), ' ')[2] split previous line on spaces and use the 3th item from the list
Note that to use this as a general template following has to hold
You need a search criteria to only match the lines you like to change. For your example, this is is $
You need to be able to split the previous line on something meaningfull returning the item you need in the same array position for each substituion. For you example this is by splitting on space and returning the 3th item.

Another vim solution:
:g/^/if line('.') % 2 | normal! wwyiwj$p | endif
g .................. globally
/^/ ................ on every start of line
if
line('.') % 2 ...... Mod of the integer division of line number by 2
normal! ............ normal mode
ww ................. jump to the third word
yiw ................ yank inner word (word under cursor)
j .................. go to the line below
$ .................. jump to othe end of the line
p .................. paste

Related

How to remove all empty lines from beginning and end of file

I have a file that looks like
Blank Line
Blank Line
Blank Line
Blank Line
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Morbi a justo egestas, malesuada lacus ut, euismod purus.
Etiam faucibus felis ac orci varius cursus.
Praesent tincidunt nibh condimentum, finibus odio non, euismod tortor.
Quisque eget ligula eu turpis consequat rutrum.
Cras non ipsum vel ipsum sodales ullamcorper non vitae dui.
Blank Line
Blank Line
Blank Line
Blank Line
The Blank Line is literally blank line. I could not put blank lines in the beginning and end in the code block so using the text Blank Line.
I need to remove all the blank lines from the beginning and end of this file. Please notice that there are blank lines in between lines. I do not want to remove those.
I have come up with the following code that remove all blank lines from the beginning of the file. But I could not manage to remove all the blank lines at the end of the file.
#!/usr/bin/env python3
import sys
import argparse
import logging
parser = argparse.ArgumentParser()
parser.add_argument("infile", nargs="?", type=argparse.FileType("r"), default=sys.stdin)
parser.add_argument(
'-d',
'--debug',
help="Print lots of debugging statements",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.WARNING,
)
parser.add_argument(
'-v',
'--verbose',
help="Be verbose",
action="store_const",
dest="loglevel",
const=logging.INFO,
)
args = parser.parse_args()
if sys.stdin.isatty() and args.infile.name == "<stdin>":
sys.exit("Please give some input")
logging.basicConfig(level=args.loglevel)
# Business Logic Here
do_not_print_all_lines = True
for line in args.infile:
if not line.strip() and do_not_print_all_lines:
pass
else:
do_not_print_all_lines = False
if not do_not_print_all_lines:
print(line)
How can I do that?
Can you just first read the file into a list?
Then, you can address empty lines from the beginning and the end of the list
Something like this:
my_file = open("sample-file.txt", "r")
lines = my_file.readlines()
# inspection starting from beginning of list
for n in range(len(lines)):
line = lines[n].strip()
if line == "":
frm= n
else:
break
# inspection starting from end of list
for n in range(len(lines)-1,-1,-1):
line = lines[n].strip()
if line == "":
to= n
else:
break
newlines = lines[frm+1:to]
print(newlines)

Strange looping behavior with Preserve function call in Vim

I am using a function that I got from Vimcasts to preserve the cursor position when executing a command in Vim:
" A command to preserve last search and cursor position after running another
" command. See: http://vimcasts.org/episodes/tidying-whitespace/
function! Preserve(command)
" Preparation: save last search, and cursor position.
let _s=#/
let l = line(".")
let c = col(".")
" Do the business:
execute a:command
" Clean up: restore previous search history, and cursor position
let #/=_s
call cursor(l, c)
endfunction
" Strip trailing whitespace
nmap <Leader>$ :call Preserve("%s/\\s\\+$//e")<CR>
It works pretty well for the strip trailing whitespace mapping I've shown here, but not when I'm calling an external command like this:
" Reformat a plain text document to use hard wrapping and uniform spacing
" Note: This uses the BSD `fmt` program. The GNU coreutils version takes
" different options.
nmap <Leader>f :call Preserve("%!fmt -s -78")<CR>
vnoremap <Leader>f :call Preserve("'<,'>!fmt -s -78")<CR>
The first mapping works fine, but the second one exhibits a strange looping behavior. For example, if I have a text file like this:
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut laboret dolore magna aliqua. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Sed ut perspiciatis unde omnis iste natus error sit. Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Itaque reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
When I select those lines in visual mode to filter them, the command appears to run five times. Here's what I'm seeing in the output:
5 lines filtered
5 lines filtered
5 lines filtered
5 lines filtered
5 lines filtered
Press ENTER or type command to continue
If the file has 10 lines, then they are filtered 10 times. It still filters the area correctly, but I'm confused as to why it's looping. I think it has something to do with the Preserve function because running the command outside of preserve doesn't exhibit the looping.
Note: I think this is the appropriate place for this question, but the closing of the Vi/Vim proposal leaves me wondering where I should really be posting a question like this. Please let me know if there's a more appropriate forum for it.
When you call a function on a multi-line visual selection, that function is called for each line in the selection. Since your visual selection covers 5 lines the Preserve() function and the command you passed to it are called 5 times.
The solution is simple, add the range argument to the function definition:
function! Preserve() range
With that argument, the function is called only once and you can let it or the underlying command deal with the visual range itself.
See :help func-range.
Another – slightly dirtier – solution could be to modify your mappings to remove the range before calling the function so that it is called only once:
map <key> :<C-u>call Function(args)<CR>
See :help c_ctrl-u.

Lua string operation

I'm trying to figure out a way, so far unsuccessfully, to add a new line ("\n") to a very long string.
Is there a function that will insert a new line every x amount of characters? Basically, I need to add a newline every 95 characters. Here's the text I'm working with:
MEMORANDUM FOR RECORD
SUBJECT: Subject
1) Nam fabulas mnesarchum comprehensam ne, cu ullum euismod consulatu usu. Eam alii lobortis
voluptatum id, denique eligendi pertinax quo ne. Vis congue eirmod ut. Duo probo soleat ex. Elit pertinax
abhorreant eu his, ipsum dicam dissentiunt pri id. Kasd erant dolorum id sed, ei vim partem deseruisse,
ne mea dico tantas alienum.
2) Has cu facilisis mediocritatem. Fabellas lucilius vim ex. Mei simul omnium et, wisi vidit ut ius.
Ad has erat honestatis. Malis animal aliquid id usu.
3) Nulla utinam appellantur cu qui, scripta sententiae disputando eu nam, ut pri unum labore.
Odio wisi torquatos sea cu. Ut detracto torquatos repudiandae pri. Vim puto solum epicurei at.
Per nonummy perpetua similique te, odio platonem ut pri. Mei indoctum prodesset in, eam nisl quaerendum at.
4) At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium
voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est
laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam
libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id
quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus.
I'm interpreting the question as: I want to divide the text into lines of at most, but as close as possible to 95 characters, breaking on whitespace.
I'm ignoring the file IO in the other answers. Here goes:
-- Second parameter governs where to break; defaults to 80.
-- Call me like: breakAt(longstring, 95)
local function breakAt(str, lineLength)
local lineLength = lineLength or 80
-- Arrays are more efficient for large text operations.
local out = {}
-- Match line without newlines; save original newlines.
for line, breaks in str:gmatch('([^\n]+)(\n+)') do
local count = 0
-- Match whitespace with '*' to allow for the last word on the line having no adjacent whitespace.
for word, whitespace in line:gmatch('(%S+)(%s*)') do
count = count + #word
if count > lineLength then
-- If this word crosses the lineLength boundary, replace the last words' whitespace with a newline.
out[#out] = '\n'
-- The current word is the first on the new line.
count = #word
end
count = count + #whitespace
table.insert(out, word)
table.insert(out, whitespace)
end
table.insert(out, breaks)
end
return table.concat(out)
end
This'll break the string on the whitespace, maximizing the number of words on a line.
It's easy!
local text = io.open'memorandum.txt':read'*a' -- Load text from file
local n0, width = 0, 80
text = text:gsub('()(%s)',
function(n, c)
c = (n-n0 > width) and '\n' or c
n0 = (c == '\n') and n or n0
return c
end)
io.open('memorandum2.txt','w'):write(text) -- Save corrected text to file
Try print(s:gsub("("..string.rep(".",95)..")","%1\n")).
But I suspect you want to do this for each line, not for the whole text.
This will directly output any lines shorter than 95 characters, and split lines 95+ characters into 94 character chunks with a newline appended. it doesn't split on white-space, that is left as an exercise to you.
local fout = io.output(os.getenv('userprofile').. '\\desktop\\temp.txt', 'w+');
for str in string.gmatch(text, '(.-\n)') do
if str:len() > 95 then
while str:len() > 95 do
local s = str:sub(1, 94)
fout:write(s.. '\n')
str = str:sub(94)
end
else
fout:write(str)
end
end
fout:flush(); fout:close();

VIM: Insert a line number, with a space after

I need to insert the line number before each line of text using Vim, and there has to be a space after the line number. For example, if this was TestFile:
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Morbi nunc enim, vehicula eget, ultricies vel, nonummy in, turpis.
It should look like this
1 Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
2 Morbi nunc enim, vehicula eget, ultricies vel, nonummy in, turpis.
I have been using the command :%s/^/\line('.')/ with a number of variations, but I cannot figure out how to get the space at the end.
Any ideas?
You were very close!
This substitution will do the job by concatenating the string ' ' to the line number:
%s!^!\=line('.').' '!
This is probably easiest with an external tool:
:%!nl -ba -w1 -s' '
You can use a macro. First make sure you have a 0 before the first line and have your cursor placed on it:
0 Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Morbi nunc enim, vehicula eget, ultricies vel, nonummy in, turpis.
foo
bar
etc...
Then perform this key sequence to store the right macro in register a: qaywjP0<C-A>q.
Now press #a to execute the macro. Use a quantifier to execute it multiple times.
Type :help q to find out more about recording macro's.

How to get a custom sentence format in VIM?

I use vim to write a lot of text (mostly for research papers), and I recently start to format paragraphs and sentences like this:
Lorem ipsum dolor sit amet, consectetur adipiscing
elit sed diam et arcu scelerisque rutrum eget
vitae sed diam et arcu scelerisque rutrum eget
vitae sed diam et arcu scelerisque rutrum eget
vitae.
Aenean euismod tristique sollicitudin.
Vestibulum sed diam et arcu scelerisque rutrum eget
vitae sapien.
Quisque dui ligula, semper eget iaculis at, eleifend
at ligula.
Sed vestibulum tellus ac libero iaculis sit amet commodo
sapien pellentesque.
Cras quis dignissim neque.
Donec neque mauris, dictum tempus tincidunt in,
pellentesque sit amet dui.
I hope you can guess the pattern.
Now I do this mostly manual what is some kind of akward, especially if you add text in the middle of the sentence. My question would be, how can i do this automagically?
I know that I can use "gq100" to force a linebreak on the next 100 lines, but this does not do exactly what I want. It would be great if this is not really a hard linebreak but only a virtual one, which means when I put the cursor in the line starting with "Lorem ipsum" I can copy and past the whole sentence with y and p as if there wouldn't be any linebreak at all.
Does someone have an idea on this one?
Cheers,
T
Do you mean: If a line starts with 3 spaces, it belong to previous sentence?
You can do this:
:set textwidth=0
:set wrap
:set showbreak=\ \ \
Note: there's a space after every \.
Try to type a very lone line. It'll auto wrap. And the next line starts with 3 spaces.
I guess this is what you are looking for, the breakindent patch for vim:
http://sqizit.bartletts.id.au/2011/01/31/vim-and-breakindent/

Resources