vim fold text with spaces in front - vim

I'm trying to customize vim folding style and stuck with indentation. I know it has been asked multiple times here and I use this command (which seem to work for others) to test the appearance of fold:
:set foldtext=' '.foldtext()
This however gives me 'unknown option' error. Apparently, it doesn't accept the string containing only space(s), because this
:set foldtext='mytext'.foldtext()
works fine and adds 'mytext' to the beginning of folds.
Why doesn't it work and what's the way around it?

You just need to escape the space. Use this instead.
:set foldtext='\ '.foldtext()
The space is causing vim to think you want to set foldtext to ' and then '.foldtext() is the next argument to set. However this isn't what you want and the reason the error message is
E518: Unknown option: '.foldtext()
Escaping the space tell vim that foldtext='\ '.foldtext() is one argument instead of two.

You can use the EightHeader plugin if you prefer aligned foldtext. Example from the help:
If you don't like the default 'foldtext' you can customize it by setting to
EightHeaderFolds().
For example the closed folds looks like this by default:
```+-- 45 lines: Fold level one
+--- 67 lines: Fold level two
If you would like to change it to this kind:
Fold level one................45 lines
Fold level two..............67 lines
... then you can use this function:
let &foldtext = "EightHeaderFolds( '\\=s:fullwidth-2', 'left', [ repeat( ' ', v:foldlevel - 1 ), '.', '' ], '\\= s:foldlines . \" lines\"', '' )"

Related

Vim errorformat string to show message in QuickFix removing part of it

I'm writing an errorformat string, and it works for the most part. My problem is that I have lines like this as the makeprg output:
Some text I want to show in the QuickFix window^M
Yes, the line ends with an spurious ^M character I want to remove. So, what I want in my QuickFix window is this, without the ^M character:
|| Some text I want to show in the QuickFix window
but I have this instead:
|| Some text I want to show in the QuickFix window^M
So far, this is the relevant part of my errorformat:
set errorformat=%+GSome text%m
I've tested, without success, something like this:
set errorformat=%+GSome text%m%-G^M%.%#
but it throws an error (not from the ^M which is a literal control-M char, not a caret followed by an M).
Obviously the solution is not using %G but I am at a loss here.
How can I remove the line ending character from the line here? And also, removing the initial || would be a plus, but I think it's impossible to do in Vim.
Thanks in advance!
Edited to make clearer how the input text looks
Well, turns out I found a solution, probably not very good but it works, using trial and error.
set errorformat=%\\(Some Text%*[^.]).%\\)%\\#=%m
That is, the solution is using the Vim pattern (regex) expressions within errorformat, which has a quite arcane look but works, together with %* to match unknown text on the rest of the line
The solution uses \#=, a zero-width match, and requires some kind of terminator for the line, which appears before the ^M character I want to ignore, and some kind of text appearing somewhere on the line to match that line and not others.
Probably there is a much better solution but this is the best I could do myself.

Get rid of extra fold dashes in Vim folding

I am using the script from here, and it seems setting the g:custom_foldtext_max_width variable cannot get rid of the extra "--" symbols in the end of the folded lines.
Is there any way to make the folded line not go beyond 80 characters ?
Try this command.
%!fold -sw80

How to efficiently switch arguments in vim

I come upon one scenario when editing a file in vim and I still haven't found a way to do it quickly in vim way. When editing a call of a function, I offently put my arguments in a wrong order.
anyFunction(arg2, arg1)
When arriving on this situation, I have to find arg2 / delete it / append it before the ')' / deal with the ', ' / etc.
Isn't it a better way to this task quickly ? I am open to any idea (macro/ shortcut / plugin) even if I'd rather have a 'vim only' way of doing this
You need two things:
A text object to quickly select an argument (as they aren't always that simple like in your example). argtextobj plugin (my improved fork here) does this.
Though you can use delete + visual mode + paste + go back + paste, a plugin to swap text makes this much easier. My SwapText plugin or the already mentioned exchange plugin both do that job.
put this mapping in your _vimrc.
" gw : Swap word with next word
nmap <silent> gw :s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/<cr><c-o><c-l>
then in normal mode with the cursor anywhere in arg1 type gw to swap parameters
anyFunction(arg1, arg2)
Explanation:-
arg1 the separator (here a comma) and arg2 are put into regexp memories 1 2 3
the substitute reverses them to 3 2 1
Control-O return to last position
Control-L redraw the screen
Note that the separator is any non-alphanumeric character or string e,g whitespace
I actually made a plugin to deal with a exact situation called argumentative.vim. (Sorry for the plug.)
Argumentative.vim provides the following mappings:
[, and ], motions which will go to the previous or next argument
<, and >, to shift an argument left or right
i, and a, argument text objects. e.g. da,, ci, or yi,
So with this plugin you move to the argument in question and then do a <, or >, as many times as needed. It can also take a count e.g. 2>,.
If you have Tim Pope's excellent repeat.vim plugin installed <, and >, become repeatable with the . command.
I would recommend a plugin: vim-exchange for that:
https://github.com/tommcdo/vim-exchange
This is a perfect use for a regular expression search and replace.
You want to find "anyFunction(", then swap anything up to the ',' with anything from the ',' to the ')'. This is fairly straightforward, using [^,]* for "anything up to the ','" and [^)]* for "anything up to the ')'". Use \(...\) to capture each thing, and \1, \2 to refer to those things in the replacement:
:s#anyFunction(\s*\([^,]*\),\s*\([^)]*\)#anyFunction(\2, \1#g
Note how I use \s* to allow any whitespace between the "anyFunction(" and the first thing, and also between the ',' and the second thing.
If you want this to be able to span multiple lines, you can use \_s instead of \s, and capture the whitespace if you want to maintain the multi-line format:
:s#anyFunction(\(\_s*\)\([^,]*\),\(\_s*\)\([^)]*\)#anyFunction(\1\4,\3\2#g
There is also a multi-line variant of [...] collections, for example \_[^,] meaning "anything (even a new line) except for a ',' " which you could use in the pattern if your use case demands it.
For details, consult the help topics for: /\s, /\_s, /\1, /\(, and /[.
If you want a more general-purpose mapping to use at every location, you can use the cursor position in your regular expression, rather than keying off the function name. The cursor position in a regular expression is matched using \%# as demonstrated here: http://vim.wikia.com/wiki/Exchanging_adjacent_words
Similar to what Peter Rincker suggested (Argumentative), sideways also does what you describe.

Vim folding : how to hide all the single lines not containing a search pattern (or fold zero line)?

I have text files which are simply lists with no paragraphs.
When I want to focus on an item, I am able to fold everything except for matches to my search, thanks to Vim Wikia (Tip 282 :"Simple Folding") :
:set foldexpr=getline(v:lnum)!~#/
:nnoremap <F8> :set foldmethod=expr<CR><Bar>zM
This proves to be useful : thus I can see very clearly the items I am looking for : they appear in white on a black background, whereas the folds are darkgrey (ctermfg) on grey (ctermbg).
But there is a - minor - glitch. It may happen (and, in fact, it often happens) that a single line not containing the pattern remains between two lines containing the pattern, eg :
1 pattern
2 not pattern
3 not pattern
4 pattern
5 not pattern
6 pattern
Simple foldind will fold away lines 2 and 3, not line 5.
How should I proceed to hide away this single line ?
Is there a way to fold zero line (this reminds me of the koan about one hand clapping…) ? I suppose that this is not possible.
So, is there a way to simply hide the line (e.g. with the same highlighting as the folds) with a function ?
try to set another option:
set fml=0
for details about this option:
:h 'fml'
relevant to your question:
With the default value of
one a fold can only be closed if it takes up two or more screen lines.
Set to zero to be able to close folds of just one screen line.

Vim errorformat: include part of expression in message string

With vim's errorformat syntax, is there any way to use part of the message in filtering results?
As an example, some linker errors don't have anything explicit to distinguish them as an error on the line, other than the error itself:
/path/to/foo.cpp:42: undefined reference to 'UnimplementedFunction'
or
/path/to/foo.cpp:43: multiple definition of 'MultiplyDefinedFunction'
Using an errorformat of:
set efm=%f:%l:\ %m
would catch and display both of these correctly, but will falsely match many other cases (any line that starts with "[string]:[number]: ").
Or, explicitly specifying them both:
set efm=
set efm+=%f:%l:\ undefined\ reference\ to\ %m
set efm+=%f:%l:\ multiple\ definition\ of\ %m
removes the false positives, but the 'message' becomes far less useful -- the actual error is no longer included (just whatever is after it).
Is there anything in the syntax I'm missing to deal with this situation?
Ideally I'd like to be able to say something along the lines of:
set efm+=%f:%l:\ %{StartMessage}undefined\ reference\ to\ %*\\S%{EndMessage}
set efm+=%f:%l:\ %{StartMessage}multiple\ definition\ of\ %*\\S%{EndMessage}
... where everything matched between StartMessage and EndMessage is used as the error's message.
The errorformat can also use vim's regular expression syntax (albeit in a rather awkward way) which gives us a solution to the problem. We can use a non-capturing group and a zero-width assertion to require the presence of these signaling phrases without consuming them. This then allows the %m to pick them up. As plain regular expression syntax this zero-width assertion looks like:
\%(undefined reference\|multiple definition\)\#=
But in order to use it in efm we need to replace \ by %\ and % by %% and for use in a :set line we need to escape the backslashes, spaces and vertical bar so we finally have:
:set efm=%f:%l:\ %\\%%(undefined\ reference%\\\|multiple\ definitions%\\)%\\#=%m
With that the error file
/path/to/foo.cpp:42: undefined reference to 'UnimplementedFunction'
/path/to/foo.cpp:43: multiple definition of 'MultiplyDefinedFunction'
notafile:123: just some other text
comes out as the following in :copen:
/path/to/foo.cpp|42| undefined reference to 'UnimplementedFunction'
/path/to/foo.cpp|43| multiple definition of 'MultiplyDefinedFunction'
|| notafile:123: just some other text
I've been using sed to rewrite the output in cases like this where I want to get some arbitrary output that's not nessicarily homogenous into the quickfix window.
You could write make.sh that fires off make (or whatever your're using to build) and trims off stuff you're not concerned with:
make | sed '/undefined reference\|multiple definition/!d'
(Deletes lines not containing 'undefined reference' or 'multiple definition')
If that's going to get too unweildly because of the number of error strings you care about, you could do the inverse and just kill stuff you don't care about:
make | sed 's/some garbage\|other useless message//'
then :set makeprg=make.sh in vim

Resources