Wrap comma-delimited lists - vim

I often use gq$ to wrap a line in Vim.
For example, if I have set textwidth=80 as my only line in .vimrc, then
option1, option2, option3, option4, option5, option6, option7, option8, option9, option10, option11
wraps to
option1, option2, option3, option4, option5, option6, option7, option8, option9,
option10, option11
However, if I want to wrap a comma-delimited list (without spaces), this command does not work, because Vim considers this line as a single word:
option1,option2,option3,option4,option5,option6,option7,option8,option9,option10,option11
Whereas desired output is:
option1,option2,option3,option4,option5,option6,option7,option8,option9,
option10,option11
How can I allow Vim to wrap by splitting a line on commas? I didn't see anything immediately in :help fo-table that is relevant to my case.

One way to do it is to use Par. It's the best program for reflowing text hands down, but you have to really like abstractions to digest the manual. My cheat sheet for it:
set the environment variable PARINIT:
export PARINIT='grTbEiq B=.,!?_A_a Q=_s>:|'
in my vimrc:
set equalprg=par\ s0\ 72
set formatprg=par\ s0\ 72
function! s:FormatPar()
let old_format = &formatprg
let textwidth = &textwidth > 0 ? &textwidth : 72
let &formatprg = 'par s0 ' . textwidth . (v:count > 0 ? 'h1p' . v:count : '')
normal }{gq}
normal }
let &formatprg = old_format
endfunc
nnoremap <silent> <F2> :<C-u>silent! call <SID>FormatPar()<CR>
With that F2 re-formats the current paragraph, and using it with a count adds a hanging indent (that is 4F2 formats the paragraph with a hanging indent of 4).
It works very well for email messages, comments in code, and the like. It also has no problem with dealing with lists like above.

Related

How to change a specific line number color in Vim

I've been wanted to do this for a while, sometimes when I have a file open I want to be able to highlight certain line numbers to a different color. For example, say my LineNr is blue, and my Current LineNr is red. Say I'm on line 25, is there anyway I can change the LineNr color of lines 28-30 to green WITHOUT leaving my current line?
As a quick answer, if you don't mind highlighting only by groups of at most 8 lignes at once, you can use the matchaddpos({group}, {pos}) function and create a command to apply a highlight group to a range of lines.
command! -range -nargs=1 -complete=highlight HiLine call matchaddpos(<f-args>, range(<line1>,<line2>))
Which you can use, for example to highlight as 'cursorline' :
:28,30HiLine CursorLine
Note that completion applies on the argument for highlight groups.
To remove the group(s) of previously highlighted lines you could remove thoses that contains a particular line. I can't find a simpler way than to go through all getmatches() dicts and matchdelete({id}) the ones that contains the line on one of their 'posX' key :
function! s:RemoveMatchOnLine(line) abort
for l:match in getmatches()
let l:matchlines = values(filter(copy(l:match), 'v:key =~# ''pos\d\+'''))
if index(l:matchlines, [a:line]) >= 0
call matchdelete(l:match['id'])
endif
endfor
endfunction
command! -nargs=? LoLine call <SID>RemoveMatchOnLine(<q-args> ? <q-args> : line('.'))
Now, you can :LoLine to undo the highlighting on lines near the current line, or you can give it an argument to specify another line, so you don't have to move your cursor there : :LoLine 28.
Finally, you can set mappings :
nnoremap <leader>hi :HiLine CursorLine<CR>
xnoremap <leader>hi :HiLine CursorLine<CR>
nnoremap <leader>hc :<c-u>execute 'LoLine ' . v:count<CR>
Typing [count]<leader>hi in normal mode will highlight count lines from the cursor. And [count]<leader>hc will remove the highlighting on the group of line count.
Addendum
We could work on larger ranges using matchadd({group}, {pattern}), using \%xl to match line x. Replace call matchaddpos(... by
execute 'call matchadd(<f-args>, ''\%'.<line1>.'l\(.*\n\)\+\%'.(<line2>+1).'l'')'
and line 2 and 3 of the function by
let l:a = matchlist(get(l:match,'pattern',''), '^\\%\(\d\+\)l.*\\%\(\d\+\)l$')
if !empty(l:a) && l:a[1] <= a:line && a:line <= l:a[2]
But for me it breaks on large ranges, I would prefer to have the first solution which seems more robust.

How to obtain command completion list

I created unite source cmdmatch which lets you among other things fuzzy complete wildmenu items. I would like to find a better method to obtain the completion list (method I use is given here and is problematic because with large number of completion items screen will be filled up entirely [to see why just press :<c-a> if you didn't remap <c-a>])
The other solution would be to hide vim's cmd line completely while I am grabbing the list although I don't think that is possible in vim (or at least limit the amount of text it displays so it doesn't fill up screen). Any ideas ?
EDIT
First try has the same flickering problem although it looks like it works faster
fu! GetCompletion(input)
call feedkeys(":" . a:input . "FF\<esc>\<cr>")
endf
cno FF <C-A><C-\>eg:Save()<CR>
fu! g:Save()
let g:x = getcmdline()
endf
Result can be seen as:
:call GetCompletion('help a')
:echo x
SOLUTION
let g:cmdmatch = {}
fu! g:cmdmatch.set_c( base ) dict
let self.c = a:base
endfu
fu! GetCommandCompletion( base )
cno [MATCH] <c-a><c-\>eg:cmdmatch.set_c(getcmdline())<cr>
sil! exe 'norm :' . a:base . '[MATCH]'
cu [MATCH]
retu g:unite_cmdmatch.c
endf
Test: echo GetCommandCompletion("help '")
The trick is to execute the entire completion with :silent, so that the output won't actually happen (but completion is still magically done). The following function retrieves the completions already parsed into a List, by triggering the completion and then wrapping the output in :return split('...'). Of course, you can also :return '...' if you need a single string.
function! GetCommandCompletion( base )
silent execute "normal! :" a:base . "\<C-a>')\<C-b>return split('\<CR>"
endfunction
demo
:let cmds = GetCommandCompletion('no')
:echo cmds
['noautocmd', 'nohlsearch', 'noreabbrev', 'noremap', 'noremenu', 'normal']

Is there a way to get string representation of boolean option in vim?

I'm using AppendModeline function to add a modeline to my vim files:
" Append modeline after last line in buffer.
" Use substitute() instead of printf() to handle '%%s' modeline in LaTeX
" files.
function! AppendModeline()
let l:modeline = printf(" vim: set ts=%d sw=%d tw=%d :",
\ &tabstop, &shiftwidth, &textwidth)
let l:modeline = substitute(&commentstring, "%s", l:modeline, "")
call append(line("$"), l:modeline)
endfunction
But I want to extend it. It shall support adding the current value of expandtab.
Using &expandtab, I can get a numeric representation of the current value. But something like set et=0 isn't supported by vim. It has to be set [no]expandtab.
Do I really have to test for &expandtab and append expandtab or noexpandtab to l:modeline or is there a way to get a string representation of the current value?
set expandtab? shows [no]expandtab, but I don't know how to use this in a script (or if it's even possible).
Yes, you have to do this. With :redir it is possible to capture output, but :redir-based solution is at least four lines long with regex to grab the value. Using &et is much cleaner:
… printf("… %set …", …, &expandtab ? '' : 'no', …)
Note: %set is %s followed by et (short for expandtab). Word set here is just an accident.

Is there a way to diff two registers in vim? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
(Vim)diff two subroutines in same file
Sometimes I see a block of code I suspect to be identical to another block in the same file, but it's a bit too long for visual inspection and I may just be missing something. I've tried to visually select the block and yank to the the default register, put that register into / (find), but it didn't match even the original block.
Is there a way to select a section, yank it in a register, select another section then diff the two, without creating a bunch of new files? I imagine the diff results opening in a new buffer in a tab or split.
EDIT: My question is basically a duplicate of This one. I found this answer to be the most helpful & closest to what I was looking for. The only thing I'd change is to make it output in Unified format so it looks like the diff output I'm used to (it has more info as well). I suppose this means using a different diff utility.
Inspired from my lh#path#strip_common() function:
echo matchstr(#a.'##'.#b, '^\zs\(.*\)\ze.\{-}##\1.*$')
will show what is common between registers #a and #b.
You can show more information with:
function ShowDiff(a,b)
" I expect neither string to contain '##'
let start = matchstr(a:a.'##'.a:b, '^\zs\(.*\)\ze.\{-}##\1.*$')
let end= matchstr(a:a.'##'.a:b, '^.\{-}\zs\(.*\)\ze##.\{-}\1$')
let a = a:a[len(start): -len(end)-1]
let b = a:b[len(start): -len(end)-1]
echo "identical beginning: ".strlen(start )." chars -> ".start
echo "identical ending : ".strlen(end)." chars -> ".end
echo "typical to a : ".strlen(a)." chars -> ".a
echo "typical to b : ".strlen(b)." chars -> ".b
endfunction
Used with:
:call ShowDiff(#a, #b)
You could use the following sequence assuming that the two segments are already in registers, 'a and 'b. Could probably be put into a macro or function.
new
only
put a
diffthis
vnew
put b
diffthis
This creates a new buffer, makes it the only visible buffer, puts 'a into it, sets it up to be diff'd, then opens a new buffer in a vertical split, puts 'b into this split empty buffer and also sets it up to diff. Immediately vim (or gvim) will show the differences.
When done, type :ls to get the list of buffers, use :buffer *N* to return back to the original file and use :bdel! *N* to delete the created buffers (named "[No Name]").
Here's a function to open two new windows side by side, each containing the specified register contents (called as DiffRegs(#a, #1), for instance) and diff them. The new buffers will not be written or modifiable:
" A list for bookkeeping..
let g:diffreg_buffers = []
function! DiffRegs(reg1, reg2)
" Preserve the unnamed register
let s:nonamereg = ##
let ## = a:reg1
" new window
:new
normal P
setlocal nomodifiable
setlocal buftype=nofile
diffthis
call add(g:diffreg_buffers, bufnr('%'))
let ## = a:reg2
:vsp +enew
normal P
setlocal nomodifiable
setlocal buftype=nofile
diffthis
call add(g:diffreg_buffers, bufnr('%'))
let ## = s:nonamereg
endfunction " DiffRegs(reg1, reg2)
" Function to wipe all buffers we're diffing with the function above
function! EndDiffs()
for buffer in g:diffreg_buffers
exe ':buffer ' . buffer
diffoff
quit
endfor
let g:diffreg_buffers = []
endfunction " EndDiffs()
You can bind those to key combinations of your choice, but if you don't call EndDiffs() after each call to DiffRegs(), you'll run into issues.
To compare quickly two different parts of a file, you can split the view in two by using:
:sp horizontal split
or
:vsp vertical split
Once you have splitted the screen, you must use :diffthis in each window to hightlight the differences. (Then :diffoff to leave diff mode)
Then to go back to a single window you can quit one of them with :q or use CTRLwo

Vim script: Buffer/CheatSheet Toggle

I want to make a vim cheat sheet plugin. It's real simple:
I want to toggle my cheatsheets. A vertsplit toggle, like Taglist or NERDTree.
I want the cheatsheet to be filetype specific. So I toggle my c++ cheatsheet when I have opened a .cpp file.
I want the cheatsheet to be horizontally split. So it shows two files, my syntax cheat sheet and my snippet trigger cheat sheet.
I already have a collection of these cheatsheets, in vimhelp format, but now I have to manually open them.
I haven't really done any vim scripting, but I imagine this would be really simple to put together. I'm sorta sick of googling unrelated codesnippets, so what I'm asking here is:
Could anyone give me a short sum-up of what I need to learn in regards to vim scripting to piece this together. What I have a hard time finding is how to toggle the buffer window.
If you know any intro tutorials that covers the material I need to get this up and running, please provide a link.
tx,
aktivb
The function below may not do exactly what you want, and I haven't tested it, but it should give you some ideas.
The main idea is that the function reads the filetype of the current buffer (you can test this by typing :echo &ft) and then sets the path of the appropriate cheat sheat. If it exists, this path is then opened (read-only and non-modifiable) in a split window. You can then call this function any way you wish, for example by mapping it to the {F5} key as shown.
I'm not sure about the toggling possibilities (is this really easier than just closing the split window?) but you could look at the bufloaded() function, which returns whether or not a given file is currently being accessed.
function! Load_Cheat_Sheet()
let l:ft = &ft
if l:ft == 'html'
let l:path = 'path/to/html/cheat/sheet'
elseif l:ft == 'c'
let l:path = 'path/to/c/cheat/sheet'
elseif l:ft == 'tex'
let l:path = 'path/to/tex/cheat/sheet'
endif
if l:path != '' && filereadable(l:path)
execute ':split +setlocal\ noma\ ro ' l:path
endif
endfunction
map <F5> :call Load_Cheat_Sheet()<CR>
Hope this helps. Just shout if anything is unclear, or you want to know more.
I had forgotten about this until I got a notice about Eduan's answer. Since I posted this question I've done quite a bit of vim scripting, including getting this to work:
let g:cheatsheet_dir = "~/.vim/bundle/cheatsheet/doc/"
let g:cheatsheet_ext = ".cs.txt"
command! -nargs=? -complete=customlist,CheatSheetComplete CS call ToggleCheatSheet(<f-args>)
nmap <F5> :CS<CR>
" strip extension from complete list
function! CheatSheetComplete(A,L,P)
return map(split(globpath(g:cheatsheet_dir, a:A.'*'.g:cheatsheet_ext)),
\ "v:val[".strlen(expand(g:cheatsheet_dir)).
\ ":-".(strlen(g:cheatsheet_ext) + 1)."]")
endfun
" specify cheatsheet or use filetype of open buffer as default
" instead of saving window status in a boolean variable,
" test if the file is open (by name). If a boolean is used,
" you'll run into trouble if you close the window manually with :wq etc
function! ToggleCheatSheet(...)
if a:0
let s:file = g:cheatsheet_dir.a:1.g:cheatsheet_ext
else
if !exists("s:file") || bufwinnr(s:file) == -1
let s:file = g:cheatsheet_dir.&ft.g:cheatsheet_ext
endif
endif
if bufwinnr(s:file) != -1
call ToggleWindowClose(s:file)
else
call ToggleWindowOpen(s:file)
endif
endfun
" stateless open and close so it can be used with other plugins
function! ToggleWindowOpen(file)
let splitr = &splitright
set splitright
exe ":vsp ".a:file
exe ":vertical resize 84"
if !splitr
set splitright
endif
endfun
function! ToggleWindowClose(file)
let w_orig = bufwinnr('%')
let w = bufwinnr(a:file)
exe w.'wincmd w'
exe ':silent wq!'
if w != w_orig
exe w_orig.'wincmd w'
endif
endfun
Thought I would add to Goulash's answer.
I think in order to implement the toggle you would simply use some if statements and a global variable.
let g:cheatsheet_toggle_on=0
if (g:cheatsheet_toggle_on == 0)
" Turn the cheatsheet on
" Also make sure to know that the toggle is on:
let g:cheatsheet_toggle_on=1
elseif (g:cheatsheet_toggle_on=1
" Do whatever you need to turn it off, here
endif
Hope this figures out that logic. :)

Resources