can we specify multiple foldmarkers in vim? - vim

I am trying to fold multiple lines in vim with :set foldmethod=marker I have done :set foldmarker={,} is there any way such that we can fold function that has starting braces='[' and end braces=']' and also fold a function with starting braces='{' and end braces='}' like in vscode we can fold any function with any starting and ending braces.

From :help folding:
There are six methods to select folds:
manual manually define folds
indent more indent means a higher fold level
expr specify an expression to define folds
syntax folds defined by syntax highlighting
diff folds for unchanged text
marker folds defined by markers in the text
marker won't help for the reason given under :help 'foldmarker':
The marker is a literal string (a regular expression would be too slow).
See :help fold-marker.
diff is irrelevant.
See :help fold-diff.
syntax may help, depending on the language and how the syntax script for that language was written.
See :help fold-syntax.
expr is the most powerful method because it lets you decide exactly what to fold and how to fold it.
It is also the hardest to set up, for obvious reasons. See :help fold-expr.
indent is a pretty dumb method, which makes it very memory efficient and versatile. You could try that one because it doesn't care about braces at all.
See :help fold-indent.
And then there is the manual method, which lets you define folds with motions.
This lets you do things like zfi{ or zf12j.
See :help fold-manual.

Related

Vim doesn't use tabstop distance in insert-mode

I'm having problems with auto indentation in vim while programming in lisp.
My .vimrc had the following settings for tabs:
set noexpandtab
set autoindent
set softtabstop=0
set shiftwidth=8
set tabstop=8
When I type (if <enter> in insert-mode, a new line is created with an indentation of two spaces.
None of my settings say anything about two spaces, so why don't I get a tab?
What setting can I use to change the indentation while in insert-mode?
Thanks in advance!
Update:
Thanks for the answers, the settings are not overwritten.
It has to do with the "default lisp indenting".
In the :help lisp it says something about changing the p flag in
cpoptions. This is what it says in the help for the cpoptions flags:
p - Vi compatible Lisp indenting. When not present, a slightly better algorithm is used.
Setting it does change the indent to one space instead of two spaces.
Still not sure how to change this to something else though.
Looks like this is two-space indentation is a hard coded behavior of :set lisp mode which ignores shiftwidth.
We can trace this to the source code which contains a hard-coded amount += 2; increment statement.
It's that way for a good reason; it has come to be the predominant way of writing Lisp.
As I wrote this answer, I peeked at samples of source code the following projects (all Lisp or Lisp-like languages):
Steel Bank Common Lisp (SBCL);
Clozure Common Lisp (CCL);
GNU Emacs;
Clojure;
GNU Guile;
Racket;
and GNU CLISP.
I did not spot a single example of anything but two-space indentation! With two-space indentation, you are in good/large company. You might as well get used to that; even if you somehow get Vim to follow your way, if you upstream anything into anyone's Lisp project, you will likely have to reformat.
Now, I have seen Lisp code using four-space indentation, like in very old code bases and some books.
By the way, sometimes you see if indented like this:
(if (condition)
(then)
(else))
This may happen where indentation is four spaces, but I'm referring situations when this is alignment, and not four space indentation. This formatting is, of course, standard for function arguments, but controversial for operators such as if. Some people like it that way in their code bases. For instance, this institution's randomly found coding style guide recommends this way of writing if, while also recommending two-space indentation.
Vim will do the above if you remove if from lispwords.
The :set lispwords=... parameter contains a comma-separated list of identifiers which follow operator-like indentation, meaning two spaces rather than function-like alignment: second and third lines align with argument. By default, if is found in lispwords.
Lisp mode also applies two space indentation to a function (i.e. form not listed in lispwords, if there is no argument):
(gobbledygook 1 2
2 3)
(gobbledygook
1)
That's also "canonical". Sometimes this comes in handy if you're trying to conform to some maximum line length; a function call running past the limit can sometimes be made to fit by moving all its arguments down, and just giving them two space indentation.
Each filetype can have its own settings in vim. So your .vimrc values can be overwritten in filetype plugins. To learn the current values of the settings for lisp filetype open the lisp file and run the following commands in vim command line:
:set noexpandtab?
:set autoindent?
:set softtabstop?
:set shiftwidth?
:set tabstop?
If they are different from the ones in .vimrc, then your values are overwritten in some plugin.
In order to overwrite them again with your custom values, create the ~/.vim/after/ftplugin/lisp.vim file with the required values:
set noexpandtab
set autoindent
set softtabstop=0
set shiftwidth=8
set tabstop=8

Vim: language independent fall back to syntax folding with foldmethod=expr

My goal is to extend the foldmethod=syntax with an additional custom defined rule of my own.
My approach in doing so is to use foldmethod=expr and define this rule in my foldexpr (e.g. add a fold for '///' comments). After that the resources I found usually fall back to something similar to indentation folding. So is there a good way to fall back to syntax folding after the custom rules, without reproducing the complete grammar for whatever language I am using?
My attempt so far is this, which is not a very satisfying approximation of syntax folding:
function! GetFold(lnum)
let this_line=getline(a:lnum)
let pprev_i=indent(a:lnum - 2)/&shiftwidth
let prev_i=indent(a:lnum - 1)/&shiftwidth
let this_i=indent(a:lnum)/&shiftwidth
" comments
if this_line =~? '^\s*\/\/\/.*'
return this_i + 1
endif
" like indent folding, but includes the closing bracket line to the fold
if empty(this_line)
if prev_i < pprev_i
return prev_i
endif
return -1
endif
if this_i < prev_i
return prev_i
endif
return this_i
endfunction
The solution is to just use set fold=syntax and add a syntax region for the comments to your .vimrc. There you can use the fold keyword to mark the region as foldable (see :h syn-fold for more information):
syn region myFold start="///" end="///" transparent fold
(Note, take also a look at :h syn-transparent it is quite useful here)
No, there isn't a way to make Vim "fall back"; only one 'foldmethod' can be active at a time, and there's no API to evaluate another fold method "as if".
You could temporarily switch to syntax folding, store the generated folds, and then use that information in your fold information, extended with what your algorithm determines. (Or you could keep the same buffer in a window split, have syntax folding enabled there, and query it from the; this would save the complete re-creation of the folds, but you'd probably need to synchronize the cursor positions.)
This is cumbersome and possibly slow; I wouldn't recommend it.

How can i fold both code and comments in Vim?

Vim can fold Ruby code, but not comments.
After adding this in .vimrc to change foldmethod to comments, i can no longer fold code.
autocmd FileType ruby,eruby
\ set foldmethod=expr |
\ set foldexpr=getline(v:lnum)=~'^\\s*#'
How can i configure Vim to fold both comments and code?
In my recent Vim 7.3.823 snapshot, the $VIMRUNTIME/syntax/ruby.vim (version 2009 Dec 2) has both folding for Ruby constructs and comment blocks.
Just put
:let g:ruby_fold = 1
into ~/.vimrc. (And make sure you don't have a variable named ruby_no_comment_fold.)
You could use foldmethod=marker and add {{{ / }}} markers (or other markers of your choosing) to indicate where folds begin and end.
You could also modify the file which defines ruby syntax highlighting to adjust what it considers as eligible for folding with foldmethod=syntax.
A third option would be to develop a more complex routine for use with foldmethod=expr. For example, I use the vim functions defined here to define how ruby code should be folded. It automatically defines folds for modules, classes and methods along with any comment lines that immediately precede those; and it supports the standard fold markers for folding other sections. It gets used with foldexpr=ruby#MethodFold(v:lnum).
Further information on how fold expressions should behave can be found by doing :help fold-expr. There's also a nice vimcast about that.
Setting foldmethod to indent will fold lines based on indent level,
regardless of whether the line is a comment or code.
:set foldmethod=indent
:help fold-indent
I think you are looking for
set foldignore=#
If you want to fold block comments (like /* .... */ in multiple line), watch my other post in vi.stackechange

Reading vim plugin - strange notation and navigation

Im reading great tpope rails.vim and what does it mean:
" }}}1
" Abbreviations {{{1
exactly here: https://github.com/tpope/vim-rails/blob/master/autoload/rails.vim#L3921
Is it for better navigation?
This file is quite huge, how to navigate on it properly - using ctags?
These are so called foldmarkers. Vim 6 introduced code folding and the triple braces are the default string to mark the beginning and the end of a fold. In addition, if you prepend the opening mark {{{ with text, it'll show in the collapsed line as a header. This is only one way to fold code. Being a manual method, it is easily controlled and thus preferred by many.
See :h folding and :h fold-marker.

Display some special character as a linebreak in Vim

I would like to display some (arbitrary) special character as linebreak <CR> in vim.
So far I tried misusing (certainly extreme misuse:) the non-breakable space typing
:set list listchars=nbsp:<CR>
which does not work, seemingly because the command does not accept the <CR>.
Is there anything which I can use here for <CR>? \r didn't work either.
Note that I don't want to edit the text file. The goal is to have blocks of lines (some related code) treated as a single line with respect to vim actions but displayed as multiple lines. The special character (to be defined) would be used only to save this block structure in the file replacing the linebreak \r in these cases.
Given the wider context of the problem that you have provided in a
later comment, I would suggest the following solution. Group dependent
lines of code in folds by indentation, language’s syntax, or markers.
All of these three methods are automatic and do not require manual
creation of folds. Which one to choose depends on the language you
use. See :help foldmethod, and feel free to comment this answer if
you need any help with folding.
Unless the syntax of the language you use has extensive support in
Vim, the most convenient methods would be using fold markers or
defining a custom expression to calculate fold level of each line.
The former method implies surrounding every group of lines to fold
with special text markers (which could be enclosed in a comment not
to break the syntax rules of the language). By default, those markers
are {{{ and }}}; see :help fold-marker and :help foldmarker
to find out how to change them. Use
:set foldmethod=marker
to enable this mode of folding.
Defining an expression to calculate fold level for every line is an
even more flexible method. It allows to use any logic (that can be
expressed in Vimscript) to determine the fold level. For example, to
fold groups of lines that start with a single space use the following
settings:
:set foldmethod=expr
:set foldexpr=getline(v:lnum)[0]=='\ '
See :help fold-expr for further details on customizing the fold
expression.
When the lines that depend on each other are grouped into folds, you
can easily pass the contents of any particular fold to a filter
program. Move the cursor to a line inside a target fold, then type
[zV]z to select the entire fold, followed by !, and enter the
command to run. To save typing, you can define the mapping
:nnoremap <leader>z [zV]z!
If the command is always the same, you can include it in the mapping:
:nnoremap <leader>z [zV]z!cat -n<cr>
Substitute the cat -n portion above—my example command—with the
appropriate command in your case.
I think you might want check out this vimcasts episode. May not be exactly what you want, but could get you there. Good luck!
My solution, in the end, was to insert non-breaking spaces and linebreaks in the respective places in the file. :set list listchars=nbsp:$ can then be used to display these 'special linebreaks'. Their presence allows interpreting code to identify the blocks of lines separated by this combination as related lines.
Of course this doesn't answer the question. The answer, according to my best knowledge now, is that neither :set list nor :wrap can be used to achieve this.

Resources