I'm using vim to maintain a weblog of what I do through the day (what commands I used to generate output, etc..), and sometimes I need to copy-paste strings that have special html characters in them. Is there a way to make an "html-paste" mode that will (for instance) convert < to <?
There are a few small functions here if someone feels like modifying them to accept a range, then provide a mapping which passes the [ and ] marks to act on the last pasted text.
Actually, after looking a bit, you don't need to modify the functions from the vim tip at all. If a function doesn't explicitly pass the range option, the function is called once for each line of the given range. This means that all you need to do is call the function with a range.
A couple useful examples are below. The first calls HtmlEscape() for each line in the last pasted text, the second does the same but for each line in a visually selected block. Add this to your .vimrc:
nnoremap <Leader>h :'[,']call HtmlEscape()<CR>
vnoremap <Leader>h :call HtmlEscape()<CR>
function HtmlEscape()
silent s/&/\&/eg
silent s/</\</eg
silent s/>/\>/eg
endfunction
Obviously if you want more things replaced you'd have to add them; there are many on the linked wiki page.
For simple XML encoding I use Tim Pope's unimpaired.vim.
[x followed by a motion
visually select the text then [x
[xx to encode the current line
To encode the just pasted text:
`[[x`]
Explanation:
`[ and `] are marks set by the boundaries of a change or a yank. `[ at the beginning and `] at the end.
First move to the start of the just pasted text with `[
Next execute [x to encode the following motion
By using `] the motion will be all the text between the current cursor location to the end of the pasted text.
Optionally you can wrap this up into a mapping
nmap <leader>x `[[x`]
More information:
:h mark-motion
:h `[
You can use a mapping that will convert register value and then paste it:
python import xmlrpclib, vim
function! EscapeHTML(str)
try " Force any error to be an exception "
let d={}
python vim.eval("extend(d, {'xml': '"+xmlrpclib.escape(vim.eval("a:str")).replace("'", "''")+"'})")
return d.xml
endtry
endfunction
function! s:PasteHTML()
return "\"=EscapeHTML(getreg(".string(v:register)."))\np"
endfunction
nnoremap <expr> ,p <SID>PasteHTML()
Requires vim with python support and python installed. xmlrpclib packages comes with python. If you don't want python, replace EscapeHTML function. With this script ,p will work just as p except for converting its input.
Related
During the implementation process of a program I generally insert many append code lines, mainly with print command, to help me understand and debug the implemented program. Unfortunately, it is common to me to forget which lines are from the code and with were appended and should be deleted some time after. This problem gets worst with large programs.
Well, I found this article that teaches how to keep one arbitrary user selected line highlighted (see section: Highlighting that stays after cursor moves). The solution given by the article is to include in .vimrc the following code:
:nnoremap <silent> <Leader>l ml:execute 'match Search /\%'.line('.').'l/'<CR>
So, every time when I press \l the current line is highlighted and kept so, and the previous highlighted line, if there are one, is unhighlighted.
This isn't the behavior that I would like. Instead, I would like to be able to highlight as many arbitrary lines as I want without unhighlighting the previous highlighted lines. And if it is possible, with a unique command like \l.
Someone knows a solution for this?
Thanks in advance.
EDITED:
The command proposed by yolenoyer solved the initial problem. But, now other problem raised. The following command:
:call clearmatches()
proposed to clean the highlighted lines cleans all lines and I would like to be able to clean specific highlighted lines, instead off all of them at once. Is it possible?
I program in C quite alot, and when debugging tend to pepper the code with debug prints.
I use the vim command
:syntax match Error /\<debug_printf\>/
to ensure the word 'debug_printf' is highlighted in the default 'Error' colors for the particular colorscheme.
This doesn't help you bookmarking a series of lines, but for that you should check out the 'bookmark' plugin which allows you to create and remove bookmarks throughout the file.
VIM Bookmarks Plugin
:match accepts only one match.
Use the matchadd({highlight-group}, {pattern}) function instead, for example:
nnoremap <silent> <leader>l :call matchadd('Search', '\%'.line('.').'l')<cr>
To clear the matches you added, run :call clearmatches().
I used the answers here to come up with this combo, which I think is nice:
" \l to highlight a line
nnoremap <silent> <leader>l :call matchadd('Search', '\%'.line('.').'l')<CR>
" \L to remove highlighted line
nnoremap <silent> <leader>L :
\for m in filter(getmatches(), { i, v -> has_key(l:v, 'pattern') && l:v.pattern is? '\%'.line('.').'l'} )
\<BAR> :call matchdelete(m.id)
\<BAR> :endfor<CR>
I think your first paragraph, which explains your problem, has nothing to do with vim, so maybe you don't need to use vim to solve your problem.
What about not debugging with regular print statements, but with a function that wraps print? That would be really easy to search for program wide and also file wide (just search with * or # for all occurrences of your debug printing function).
In VIM, text block yanking in Visual Mode, and pasting the block afterwards, paste it after the desired column given by the cursor, but pastes in-place, overwriting contents of the current and following lines.
Sometimes I don't want this, what I want is to paste a block with the indentation given by the cursor position, but pasting inside new empty lines, without overwriting text.
Is there a way to do that?
Currently, to achieve this, I create a good amount of empty lines, and then paste the block, eliminating the remaining empty lines after (not very clever... ).
Note: I use set virtualedit=all to be able to paste at any column in the said empty lines.
You can try something like the following. Block-wise yank something, position the cursor and hit <Leader>p, whatever your leader key is.
function! FancyPaste()
let paste = split(#", '\n')
let spaces = repeat(' ', col('.')-1)
call map(paste, 'spaces . v:val')
call append(line('.'), paste)
endfunction
nnoremap <Leader>p :call FancyPaste()<CR>
You can of course change the mapping to be anything you want; it's just a suggestion.
Update: Here's a version that accepts an argument. This let's you e.g. paste from the system clipboard instead. It also uses virtcol() instead of col() to take account for the possible use of 'virtualedit':
function! FancyPaste(reg)
let paste = split(getreg(a:reg), '\n')
let spaces = repeat(' ', virtcol('.')-1)
call map(paste, 'spaces . v:val')
call append(line('.'), paste)
endfunction
nnoremap <Leader>p :call FancyPaste('"')<CR>
nnoremap <Leader>cp :call FancyPaste('+')<CR>
Keep in mind it will only indent with spaces, not tabs. Indenting with the appropriate amount of tabs (and spaces if needed) would require some extra lines of code, but is quite doable.
If I understand correctly what you want, you could try this based on an ex command and the = operator:
nmap <leader>p :put "<cr>'[=']
Another possibility:
nmap <leader>p :let #"=#"<cr>]p
The #"=#" seems to make Vim forget about the lines being copied, character-wise and ]p pastes reindented.
The UnconditionalPaste plugin can also help you paste like that.
I have log file of multi threaded application. Each line has a well know format (e.g. 3rd field is thread id). while one of fields is thread id. I hope that I'm not trying to reinvent the wheel :)
Any way, to easy reading of the file, I thought of two options that could help:
Highlight all lines with the same thread id as current line.
If some keystroke is pressed, all lines with other thread id are folded, pressing again the keystroke unfold the lines.
A skeleton for both items is welcomed.
Highlighting by pattern
Here is a function to highlight (and another to clear) all lines that contain a given pattern, with an accent highlight on the pattern itself. The "last search" register #/ is also set to the requested pattern so n/N, in normal mode, jumps forwards/backwards through matching lines. <Leader>l (equivalent to \l on most installs) is a shortcut to highlight lines that contain the WORD under your cursor.
highlight def link xHiLine Special
highlight def link xHiPatt String
function! ClearHighlight()
syn clear xHiLine
syn clear xHiPatt
let #/ = ''
endfunction
function! HighlightPattern(patt)
call ClearHighlight()
if a:patt != ''
echo "Highlighting pattern: ".a:patt
exec "syn match xHiPatt \"".a:patt."\" contained"
exec "syn match xHiLine \".*".a:patt.".*\" contains=xHiPatt"
let #/ = a:patt
endif
endfunction
map <Leader>l :call HighlightPattern(expand("<cWORD>"))<CR>
map <Leader>c :call ClearHighlight()<CR>
Folding by pattern
For an example of folding based on patterns, check out the Show-Hide Vim plug-in. It provides two commands, SHOW and HIDE, and a few shortcut maps. For example, :SHOW thread=1234 will fold all lines except those that contain thread=1234, while zs in normal mode will show lines containing the word under your cursor. [You may want to create an alternate map, such as zS, to use <cWORD> instead of <cword>.]
Building patterns
If neither <cword> nor <cWORD> extract a sufficiently unique filter pattern (or to avoid moving the cursor to the proper field), create another function like the one below and call it from a map.
function! GetField(num)
let toks = split(getline('.'))
if len(toks) >= a:num
return toks[a:num-1]
endif
return ''
endfunction
map <Leader>hl :call HighlightPattern(GetField(3))<CR>
map <Leader>fl :exec "SHOW ".GetField(3)<CR>
What you are basically looking for is an external mechanisem to be built on top of your log file.
Chainsaw is doing exactly that for log4j based logs:
http://logging.apache.org/chainsaw/index.html
Not sure what is your logging application, but you should probbaly look at that direction.
I find myself often repeating the following pattern of operations.
I usually go into visual mode, select some lines or block. Then I yank them using y, and paste them using p or P. The next step is to select the pasted text, to replace a variable or function name or change indentation.
I know that I can use gvto reselect the "origin" but what I would like is a similar command to select the "destination".
:help gv mentions :
After using "p" or "P" in Visual mode the text that was put will be selected.
but it is only useful when you are replacing a selection by the content of register, not when you are inserting a whole new block.
You are looking for
`[v`]
'[ and '] are marks automatically set by vim to the start and the end of the "previously changed or yanked text". v switches to visual mode in between.
I prefer the following simple mapping to Benoit's function
nnoremap <expr> g<c-v> '`[' . strpart(getregtype(), 0, 1) . '`]'
Learn more about expression maps:
:h :map-expression
As #ZyX pointed out the strpart is not needed and can be rewritten as:
nnoremap <expr> g<c-v> '`[' . getregtype()[0] . '`]'
One of your use cases is to change indentation after pasting.
I use the following maps to achieve this:
nnoremap <leader>[ `[V`]<
nnoremap <leader>] `[V`]>
They do the following:
de-indent the recently pasted block
indent the recently pasted block
I find these very useful and well used maps.
I often have to paste some stuff on a new line in vim. What I usually do is:
o<Esc>p
Which inserts a new line and puts me in insertion mode, than quits insertion mode, and finally pastes.
Three keystrokes. Not very efficient. Any better ideas?
Shortly after :help p it says:
:[line]pu[t] [x] Put the text [from register x] after [line] (default
current line). This always works |linewise|, thus
this command can be used to put a yanked block as
new lines.
:[line]pu[t]! [x] Put the text [from register x] before [line]
(default current line).
Unfortunately itβs not shorter than your current solution unless you combined it with some keyboard map as suggested in a different answer. For instance, you can map it to any key (even p):
:nmap p :pu<CR>
Options:
1) Use yy to yank the whole line (including the end of line character). p will then paste the line on a new line after the current one and P (Shift-P) will paste above the current line.
2) Make a mapping: then it's only one or two keys:
:nmap ,p o<ESC>p
:nmap <F4> o<ESC>p
3) The function version of the mapping (unnecessary really, but just for completeness):
:nmap <F4> :call append(line('.'), #")<CR>
" This one may be a little better (strip the ending new-line before pasting)
:nmap <F4> :call append(line('.'), substitute(#", '\n$', '', ''))<CR>
:help let-register
:help :call
:help append()
:help line()
:help nmap
You can paste a buffer in insert mode using <C-R> followed by the name of the buffer to paste. The default buffer is ", so you would do
o<C-R>"
I found that I use <C-R>" very often and bound that to <C-F> in my vimrc:
inoremap <C-F> <C-R>"
This still uses three keystrokes, but I find it easier than Esc:
o<Alt-p>
Since you're in insert mode after hitting o, the Alt modifier will allow you to use a command as if you weren't.
Using this plugin: https://github.com/tpope/vim-unimpaired
]p pastes on the line below
[p pastes on the line above
advantages:
works on all yanked text (word, line, character, etc)
indents the pasted text to match the indentation of the text
around it
2 keystrokes instead of 3 and much "easier" strokes
fast
Personally I've nmapped Enter (CR) like this:
nmap <CR> o<Esc>k
...based on this Vim Wikia article.
This way I can make newlines directly from normal mode, and combining this with wanting to paste to a newline below I'd do:
<CR>jp
You could also skip k in the nmap above, depending on what functionality you prefer from Enter, so it would just be <CR>p.
I've also imapped jj to Esc, which would also assist in this case. Esc is way too far away from the home row for how significant it is in vim.
Not shorter than the other solutions, but I do think it feels less clunky than some of them, and it has other uses too.
If you wanted to stay in the insert mode, you can do o ctrl+o p
o β insert mode and go to the new line
ctrl+o β run a single command
like in normal mode
p β paste
It's three keystrokes but you stay in insert mode and also o ctrl+o is quite fast so I personally treat it as 2.5 keystrokes.
If you're copying a whole line then pasting a whole line, use Y to yank the line or lines, including line break, in the first place, and p to paste. You can also use V, which is visual line mode, in contrast with plain v for visual mode.
I have mapping inoremap jj <ESC>. So it is easy to insert new line with ojj and Ojj and then p.
so ojjp paste new a newline. it have one more stroke then o<esc>p but ojjp is easy for me.
I found an elegant solution to this. If you are putting the yank register in your OS's clipboard (which is great anyway), with
set clipboard+=unnamed
than you can do o<Ctl-v>.
Besides being fewer strokes, this improves on both o<Esc>p and :pu because it preserves indenting: both of the other options start you at character zero on the new line.
Caveat is that this may or may not be OS dependent. All I know is that it works on recent version of OS X, but clipboard is just one of many ways to get yank in the OS clipboard.
If you want to paste in a new line and still keep indentation, create this mapping:
nnoremap <leader>p oq<BS><Esc>p
Prerequisite: you have leader mapped and you have set autoindent in your .vimrc.
Explanation: a new line is created with 'o', 'q' is typed and then back-spaced on (to keep indentation), and 'esc' brings you back to normal mode where you finally paste.
If you also want to end in insert mode, it is possible to paste while in insert mode using CTRL-R ". https://stackoverflow.com/a/2861909/461834
Still three keystrokes, but no escape, and you save a keystroke if you want to end in insert anyway.
I use the following mapping in my Neovim config:
nnoremap <leader>p m`o<ESC>p``
nnoremap <leader>P m`O<ESC>p``
A little explanation:
m`: set a mark in the current cursor position.
o<Esc>p: create a new line below and paste the text in this line
O<Esc>P: create a new line above and paste the text in this line
``: put the cursor in the original position
See :h mark for more information about marks in Vim.
This solution only seems to apply when the block of copied text starts on a new line (as opposed to grabbing a snippet of text somewhere within a line), but you can always start your copy on the last character you want to grab, then navigate to the last character at the end of line prior to the start of your desired copy block. Then when you want to paste it, place the cursor at the end of the line under which you want your text to be pasted and hit p. If I haven't screwed up the explanation, this should provide the effect you're looking for.