Can empty lines be displayed as something else in Vim? - vim

I want my Vim to display empty lines as a string of ### characters, like so:
I would like it to be work similarly to how I replace my tabs char to >--- with set listchars=tab:>-. Just display it that way, not actually insert them.
Also, it would be great if it could adapt to size of my terminal.

The desired effect can be achieved via folding. If we create one-line
folds separately containing empty lines of a buffer, they all will be
marked out as folded. The only thing left will be to customize the
highlighting accordingly.
First of all, we need to automatically create the folds. For this
purpose, we can switch folding to the expr method and then set
the foldexpr option to evaluate to a non-zero value for empty
lines only:
:setl foldmethod=expr
:setl foldexpr=empty(getline(v:lnum))
What we should do next for the trick to work out is to make those
folds close automatically in order to trigger the folding
highlighting:
:setl foldminlines=0
:setl foldlevel=0
:set foldclose=all
Finally, to repeat a custom character in the folding line, we just
empty the text displayed for a closed fold, and change the filling
character:
:setl foldtext=''
:set fillchars+=fold:#
Combining the above commands in one function for convenience,
we obtain the following:
function! FoldEmptyLine()
setl foldmethod=expr
setl foldexpr=empty(getline(v:lnum))
setl foldminlines=0
setl foldlevel=0
set foldclose=all
setl foldtext=''
set fillchars+=fold:#
endfunction
The downside of this trick, of course, is that it interferes with the
usual applications of folding, and cannot be easily used without
modifications if the user extensively relies on folding for other
purposes.

Related

How can I have *both* Markdown header folding and indent folding in Vim

Vim now has built-in Markdown folding, yay!
I want to fold on Markdown headers, and within headers, fold on indents also.
How can I have both Markdown header folding + indent fold method at the same time?
There can only be one of Vim's standard fold methods used within an individual window, but what you ask should still be possible. Here are a few options that I can think of:
You can use the expr method option and create your own custom rules with that. This is probably the only "real" way to get what you want, but it's the most complicated option.
You could also use two windows in a tab, each pointing at the same buffer, and set different fold methods locally for each split.
Finally, you could always hack something together with autocommands. From the Vim wiki page on folding, about having both indent and manual folding:
augroup vimrc
au BufReadPre * setlocal foldmethod=indent
au BufWinEnter * if &fdm == 'indent' | setlocal foldmethod=manual | endif
augroup END
This hack takes advantage of modelines, and Vim's behavior for setting variables before vs. after the modeline is read. Note that you have to have Vim's nocompatible option set for this sort of trick to work.

Is it possible to set different textwidths for go code and comment in vim?

For example, textwidth=100 for go code and textwidth=80 for go comment.
With my OnSyntaxChange plugin, you can trigger settings changes based on the syntax element you're currently in.
call OnSyntaxChange#Install('GoComment', '^Comment$', 1, 'a')
autocmd User SyntaxGoCommentEnterA setlocal textwidth=80
autocmd User SyntaxGoCommentLeaveA setlocal textwidth=100
Put this into ~/.vim/after/ftplugin/go.vim. (This requires that you have :filetype plugin on. Alternatively, you could define an :autocmd FileType go ... (for each line) directly in your ~/.vimrc, but this tends to become unwieldy once you have many customizations.
Alternative
A smaller, non-plugin variant would be a custom gq mapping that changes 'textwidth' temporarily, performs the reformatting, and then restores the original value. But that only works for manually triggered reformatting of paragraphs.

Can two foldexpr coexist in my .vimrc?

1) I have in my .vimrc a fold expr (cf. the third example under the :help fold-expr section) which makes a fold out of paragraphs separated by blank lines :
set foldmethod=expr
set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
Most of my files are files with paragraphs (to begin with my .vimrc)
2) But I have two or three text files which are simply lists with no paragraphs and I would like to be able to fold everything except for matches to my search. I found in Vim Wikia (Tip 282) the following "Simple Folding" (at the bottom of the Tip's page) which I would like to implement :
:set foldexpr=getline(v:lnum)!~#/
:nnoremap <F8> :set foldmethod=expr<CR><Bar>zM
How can I have both of them peacefully coexist in my .vimrc ?
Is setlocal (for the second foldexpr) the solution ? Tried, failed…
Is it possible to have a fold expression (the second one) apply only to two files (file1.txt, file2.txt) ?
Is it possible to merge the 2 foldexpr in one ?
Thanks for your help
Option foldexpr is local to window, so:
:set will establish both global and local values. Global value will be used as a default for subsequent windows where local value is not specified.
:setlocal will determine local value only.
It's not clear to me what merging the two expressions would mean, but of course you can create a fold function containing all the complicated logic you want.
What is definitely easy is to set different values for foldexpr depending on the file (or file type). Use an autocommand for that.
So, the whole thing could be, in your .vimrc:
" Default: for all files
set foldmethod=expr
set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
nnoremap <F8> :setlocal foldmethod=expr<CR><Bar>zM
" Only for specific files
augroup NonDefaultFoldMethod
autocmd!
autocmd BufNewFile,BufRead file1.txt,file2.txt setlocal foldexpr=getline(v:lnum)!~#/
augroup end
The augroup/autocmd! idiom is there just to avoid duplicating autocommands if you source .vimrc repeatedly. It's best practice when establishing autocommands.

Collapse comments and all functions in vim/gvim

I'm a novice user to vim and I haven't been able to find in the internet how to collapse functions and I've figured out how to collapse the argument list in C with zfa} and zfa). but I can't figure out how to collapse the comments sections. How do I do that?
Second question but related, is there a way to collapse all functions/argument lists/comments in a file at the same time?
The functionality you're referring to is called "folding" (see :help usr_28). The zf command is used to manually create a fold and is only used if the foldmethod option is set to either "marker" or "manual". In the examples you gave, you're creating folds over the regions specified by the a} and a) text objects (see :help usr_4.8).
For C, you can setlocal foldmethod=syntax and the folding regions will be automatically determined by the syntax rules. This should only be done for C files by either putting the setting in ~/.vim/ftplugin/c.vim or putting the following autocmd in your ~/.vimrc.
autocmd FileType c setlocal foldmethod=syntax
N.B. both of those require that filetype detection is enabled (filetype on), and the ftplugin solution requires that filetype plugins are enabled (filetype plugin on). The latter is a superset of the former, so you don't need both commands in your ~/.vimrc.
As for opening/closing all folds in the current buffer, those are the zR and zM commands respectively.
Add the following settings to ~/.gvimrc:
"folding settings
set foldmethod=indent "fold based on indent
set foldnestmax=10 "deepest fold is 10 levels
set nofoldenable "dont fold by default
set foldlevel=1 "this is just what i use
Then you can toggle folding with za. You can fold everything with zM and unfold everything with zR. zm and zr can be used to get those folds just right. Always remember the almighty help file at “help :folding” if you get stuck.
Source: http://smartic.us/2009/04/06/code-folding-in-vim/
Assuming you have set up your fold regions how you want them, set foldlevel to the desired level.

Soft wrap at 80 characters in Vim in window of arbitrary width

I want to use Vim's soft wrap capability (:set wrap) to wrap some code at 80 characters, regardless of my actual window width.
I haven't been able to find a way to do this yet - all the soft wrapping seems tied to the width of the window
textwidth and wrapmargin are both for hard wrapping (they insert newline characters into the file)
vertical splitting into multiple windows and using :vertical resize 80 (possibly with :set breakat= to allow breaks on any character) on one of them sort of works (even though it's a bit hackish), but breaks when using :set number as the line numbers take up a variable number of columns (depending on the file length) and these are part of the 80.
Is there any way to do this in vim? It doesn't look promising, according to other sources.
Right now my approximation is just to have /^.\{80}\zs.\+ as my default search so it's at least highlighted. I thought about adding a :syntax item for it, but that broke when it overlapped other syntax items, so I dropped that idea.
You could
set a large minimum width for the line numbers column via :set numberwidth=6 and
then you could resize your window with :set columns=86 (or with the mouse) to the proper size.
If you edit a file with a million lines in it, you may have trouble, but that's unlikely. You're wasting 6 columns of screen real estate this way too. So there are still all kinds of problems.
You can highlight past the 80th column using :match like it says here and here.
Beyond that I can't see any way to do this. Seems like it'd be a nice feature though.
Try this:
set columns=80
autocmd VimResized * if (&columns > 80) | set columns=80 | endif
set wrap
set linebreak
set showbreak=+++
You can remove the if (&columns > 80) | if you always want 80 columns.
I don't have a solution to the soft wrap, but as for marking a column, as of Vim 7.3 (released 2010-08-15) :set colorcolumn=80 will highlight column 80. The color will depend on your syntax file.
See Vim 80 column layout concerns, :h colorcolumn.
Have you tried 'linebreak'?
*'linebreak'* *'lbr'* *'nolinebreak'* *'nolbr'*
'linebreak' 'lbr' boolean (default off)
local to window
{not in Vi}
{not available when compiled without the |+linebreak|
feature}
If on Vim will wrap long lines at a character in 'breakat' rather
than at the last character that fits on the screen. Unlike
'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
it only affects the way the file is displayed, not its contents. The
value of 'showbreak' is used to put in front of wrapped lines.
This option is not used when the 'wrap' option is off or 'list' is on.
Note that <Tab> characters after an <EOL> are mostly not displayed
with the right amount of white space.
Combining eborisch's answer with some other answers I found here and things I had to work around, I came up with the following two-part solution:
This first part makes it easier to edit text with long lines:
" Allow enabling by running the command ":Freeform", or <leader>sw
command! Softwrap :call SetupSoftwrap()
map <Leader>sw :call SetupSoftwrap() <CR>
func! SetupFreeform()
" Use setlocal for all of these so they don't affect other buffers
" Enable line wrapping.
setlocal wrap
" Only break at words.
setlocal linebreak
" Turn on spellchecking
setlocal spell
" Make jk and 0$ work on visual lines.
nnoremap <buffer> j gj
nnoremap <buffer> k gk
nnoremap <buffer> 0 g0
nnoremap <buffer> $ g$
" Disable colorcolumn, in case you use it as a column-width indicator
" I use: let &colorcolumn = join(range(101, 300), ",")
" so this overrides that.
setlocal colorcolumn=
" cursorline and cursorcolumn don't work as well in wrap mode, so
" you may want to disable them. cursorline highlights the whole line,
" so if you write a whole paragraph on a single line, the whole
" paragraph will be highlighted. cursorcolumn only highlights the actual
" column number, not the visual line, so the highlighting will be broken
" up on wrapped lines.
setlocal nocursorline
setlocal nocursorcolumn
endfunc
With this alone you can get decent text wrapping for writing something like markdown, or a Readme.
As noted in other answers, getting wrapping at an exact column width requires telling vim exactly how many columns there are, and overwriting that each time vim gets resized:
command! -nargs=? Draft :call SetupDraftMode(<args>)
func! SetupDraftMode()
" I like 80 columns + 4 for line numbers
set columns=84
autocmd VimResized * if (&columns > 84) | set columns=84 | endif
:Softwrap
endfunc
There are still a couple of problems with this:
vim won't clear the screen outside of the columns you specify after calling set columns, and I can't figure out how to tell it to, so ideally you should call this immediately after opening vim
vim shows a prompt with the version number and some helpful commands when you open it, so these won't be cleared. You can add set shm+=I to disable that prompt
You can't open any vertical splits, because then both splits will be ~40 column. You would need to set columns to 2x your desired width and then always have a split open.
My vimscript is awful, but ideally someone could modify the Draft function above to take a column width as an argument, or use a global variable (g:explicit_vim_width?) that can be set manually if your window size changes.
There is no good way to do it. We can hack a makeshift setlocal softwrap with autocmd if we modify #eborisch answer. If we resize every time we enter a buffer, and we resize to a particular length when the local variable softwrap is set, we get the desired behaviour.
Let's suppose that we want to soft wrap to 80 columns, we can write the following in .vimrc.
augroup softwrap
autocmd VimResized * if (exists('b:softwrap') && &columns > 80) | set columns=80 | endif
autocmd BufEnter * set columns=999
augroup END
To turn on the mode for a particular buffer, use the following commands:
let b:softwrap=1
set columns=80

Resources