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.
Related
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
I have a huge file containing a unique long string. I need to search for a specific word in that file. Of course I cannot use gedit or similar software because they chock. So, a solution could be grep. The problem is that it returns the full string into the shell if the word matches, so I cannot find where the word is located and I cannot observe the other near words.
Is there any particular option to pass in order to stop/pause the grep shell stream (e.g., a certain number of chars after the match) as soon as it finds my word?
Use the -o option to "Show only the part of a matching line that matches PATTERN."
Example:
% cat lorem
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
% grep -oE '.{20}fugiat.{20}' lorem
se cillum dolore eu fugiat nulla pariatur. Exc
Edit: #tripleee suggested the E part, to give padding on either side of the match.
Use the -m NUM, --max-count=NUM option:
$ grep -m 1 [pattern] [/path/to/file]
Stop reading a file after NUM matching lines. If the input is standard input from a regular file, and NUM matching lines are output, grep ensures that the standard input is positioned to just after the last matching line before exiting, regardless of the presence of trailing context lines. This enables a calling process to resume a search. When grep stops after NUM matching lines, it outputs any trailing context lines. When the -c or --count option is also used, grep does not output a count greater than NUM. When the -v or --invert-match option is also used, grep stops after outputting NUM non-matching lines.
Am a long time kate user switching to vim.
Wonder whether vim has an easily activable option (or for it has been coded a plugin) to 'smartly' apply static word wrap to large strings when coding major languages: C/C++, Java, Python, PHP, (more follow).
Not only while writing but also while applying an indentation modification to a visual text block, or (un)?commenting it. Let us have a pseudo-Java situation like:
1 String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipi" +
2 "sicing elit, sed do eiusmod tempor incididunt ut " +
3 "labore et dolore magna aliqua. Ut enim ad minim v" +
4 "eniam, quis nostrud exercitation ullamco laboris " +
5 "nisi ut aliquip ex ea commodo consequat. Duis aut" +
6 "e irure dolor in reprehenderit in voluptate velit" +
7 " esse cillum dolore eu fugiat nulla pariatur. Exc" +
8 "epteur sint occaecat cupidatat non proident, sunt" +
9 " in culpa qui officia deserunt mollit anim id est" +
10 " laborum.";
~
At some point would want to add or remove some indentation levels, but relying in the editor to rebuild the whole language provisioned string with our static word wrap rules. Suppose now by some reason it is desirable to remove two spaces of indentation, the desired output would be:
1 String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipisi" +
2 "cing elit, sed do eiusmod tempor incididunt ut labo" +
3 "re et dolore magna aliqua. Ut enim ad minim veniam," +
4 " quis nostrud exercitation ullamco laboris nisi ut " +
5 "aliquip ex ea commodo consequat. Duis aute irure do" +
6 "lor in reprehenderit in voluptate velit esse cillum" +
7 " dolore eu fugiat nulla pariatur. Excepteur sint oc" +
8 "caeact cupidatat non proident, sunt in culpa qui of" +
9 "ficia deserunt mollit anim id est laborum.";
~
Which is the tool for this to be constructed by vim?
With Vim, the gq command reformats lines; this can even be done as-you-type with :set formatoptions+=a.
Unfortunately, Vim's built-in capabilities are limited to basic stuff (see :help fo-table); elaborate and language-specific formatters are meant to be provided by external programs ('formatprg'), or Vimscript ('formatexpr'), the latter one I haven't actually seen used yet.
So, if you're lucky you'll find an external code formatter program that can be integrated, or you'll have to write such a thing yourself.
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();
Just watched this http://www.derekwyatt.org/vim/vim-tutorial-videos/vim-advanced-tutorial-videos/#expression-register, and I can't see any benefit to using <c-r>= vs <c-o>normal or something like that (although I'm sure that is just because I am not understanding something)
It has many interesting uses, many many. In Derek's video, it was used to call
an external script. The point is that you can do that without leaving insert
mode. You said you don't see benefits over <c-o>, but how would you to that?
The expression register inserts the result from an expression. You don't need to
:call a function for example, as demonstrated in the video. I'll try to show
you another two uses that I find interesting, and use frequently.
1.Evaluating Math
The expression 2 evaluates to 2, right (like in VimScript)? So you can use the
expression register to insert some numbers as result from a calculation. For
example, considering you're in insert mode in this file:
... the total sum is $
Now hit <c-r>= and type
5*6+3.2*8+5.52<enter>
And the result is:
... the total sum is $61.12
Practical, eh?
2.Using Variable Values
Let's say you need to number headings in a text. Headings start with a # like
in:
# Heading
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
# Another Heading
Consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
Considering it's a long list, you'd need to find a way to do it quickly. Here is
one approach:
Create a variable to hold the current value
Find the next heading
Insert the contents of that variable (using the expression register)
Increment the variable
This can be done with by first creating the variable:
:let i=1
And then with a macro:
qa ; start recording
/^#<CR> ; find next heading
0w ; move to the first word
i ; switch to insert mode
<c-r>=i<CR> ; insert the number
.<esc> ; insert a dot and back to normal mode
:let i+=1<CR> ; increment the variable
q ; stop recording
And now you can press #a and use ## to subsequently insert the numbers in
your headings.
I use the expression register like this: <C-r>=618+27<CR>. It's very useful when doing CSS.