Vim Quickfix prefixes double-bar "||" — explain? - vim

I use the Quickfix view in Vim often.
The text in there always has a prefix of || added to it.
So, for instance, when I copy/paste out of that buffer, etc. I get those characters included by default.
Is there a way to disable this?
I haven't had luck finding any documentation or configuration for this...

Quickfix buffer is supposed to be used for parsing specially formatted strings (like compiler messages). This is done with the help of :h 'errorformat' option. And those "bars" are output separators between "filename", "line number" and "the message body".
If you have only "double bars" at the beginning of a line then you either have errorformat set wrong, or you misuse the quickfix buffer.
UPD. If you're interested, "Bars" are hardcoded in Vim's source (src/quickfix.c):
static int
qf_buf_add_line(buf_T *buf, linenr_T lnum, qfline_T *qfp, char_u *dirname)
{
...
if (qfp->qf_module != NULL)
...
if (len < IOSIZE - 1)
IObuff[len++] = '|';
if (qfp->qf_lnum > 0)
...
if (len < IOSIZE - 2)
{
IObuff[len++] = '|';
IObuff[len++] = ' ';
}
...
}

It is now possible to customize the display of the quickfix window.
vim has introduced the quickfixtextfunc (:h qftf).
It allows exactly to customize the rendering of the quickfix window. The documentation includes an example, you can also see an example in the nvim-bqf README, although it's neovim/lua based.
You can see an example in the vim documentation in :h quickfix-window-function.
To implement a general-purpose qftf (not a specific one as in the vim documentation), you should start similarly than in the nvim-bqf readme, meaning, check if the info parameter quickfix field is 1, you should display items from getqflist, otherwise items from getloclist

Related

How to use expand modifiers with Vim map/filter?

I'm trying to get the list of absolute paths to my buffers, but cannot work out how to add the :p to expand as in expand("v:val:p") into map.
let l:buffers = filter(range(1, bufnr('$')), 'buflisted(v:val)')
let l:buffiles = map(copy(l:buffers), 'expand(bufname(v:val).":p")')
The above does not work and append :p to end of each filename loaded as buffer. .e.g.
['.vim/vimrc:p']
What's the right way to pass an expand modifier inside map or filter expression?
The right way is :h getbufinfo().
let l:files = map(getbufinfo({'buflisted': 1}), 'v:val.name')
Concerning arbitrary file name expansion, it is what :h fnamemodify() is used for.
echo fnamemodify('filename.ext', ':p')
On the other hand, :h expand() performs an expansion of :h cmdline-special.

vim: set fix jump marker in a source comment of the current file

I'm a heavy VIM user but I missing one thing…
setting a fix jump marker in a comment on different parts of a (large) current open file
What I expect:
setting a marker in a comment like: // vim: marker(x)
jumping to the marker with: 'x
example (using tcl code) using 'x to jump to function p_structDEF_MqC
proc p_func_arg_name_DEF_MqC {key value} {
set cmd "N"
regexp {^(\w)#(.*)} $value dummy cmd value
set ::ARG_DEFAULT(k,$key) $cmd
set ::ARG_DEFAULT(v,$key) $value
}
proc p_arg_name_DEF_MqC {key value} {
func_arg_name_DEF_${::LANG}_MqC $key $value
}
## vim: marker(x)
proc p_structDEF_MqC {name} {
global xCLASS xPREFIX
set prefix [string range $name 0 end-1]
if {$prefix ne "Mq"} {
lappend xPREFIX "$prefix"
}
lappend xCLASS "${prefix}C"
}
proc p_enumDEF_MqC {name argv} {
}
proc p_typeDEF_MqC {VAR VALUE} {
}
proc p_fupuDEF_MqC {name ret argv} {
}
You can create an autocommand that scans files for those marks,
and create them using setpos(). You can go as complex as
you want in your scripting, i.e. to analyze the next line
and determine where the mark should be. Here is a simple
implementation in a single command that creates marks on the
first character of the next line:
au BufRead * g/vim: marker([a-z])/call setpos(
\ "'".matchstr(getline('.'), '(\zs\w'),
\ [0, getpos('.')[1]+1, 1, 0] )
This answer is based mainly on :autocmd and :g. You should
check the help files for both (:h :au and :h :g). An
autocommand runs the specified command when a certain event
happens for files matching a specific pattern. So, more help
topics for you to read:
autocmd-events
autocmd-patterns
You can use the pattern to restrict this to certain files.
Then, we have the :g command which searches for lines matching
a pattern and executes a command. The search is where you modify
which flags are you looking for. Based on your comment, let's say
for example you want to make the space after : optional. Then
update your regex to:
vim: *marker([a-z])
Modify this as you need.
The command is centered in the setpos() (again search the help
for it... everything I'm saying is in the help anyway). It takes
two arguments, one is what to set and the other is what to set
to. We want to set a mark, so we need to give it an expression
like "'a" to set mark a. To figure out which letter is the
mark supposed to be applied to, we use:
matchstr(getline('.', '(\zs\w')
Here we search for the first letter after the first parenthesis
(with (\zs\w) on the text of our current line, retrieved with
getline(). Search for the help of all these functions. This is
concatenated to a quote, with "'" . {expr} to make a "'x" if
the letter was x.
Then for the second argument, if must be an array similar to what
getpos() returns. Search the help again. However we are
modifying it, to set the mark on the beginning of the next
line. Thus we only use the line item returned by getpos(),
which is the second item, and add 1 to it.
[{buffer}, {line}, {col}, {virtual-offset}]
[0, getpos('.')[1]+1, 1, 0]
the working solution based on previous answer:
au BufRead *.c silent! g/vim: \*Marker(\[a-z])/call setpos(
\ "'".matchstr(getline('.'), '(\zs\w'),
\ [0, getpos('.')[1]+1, 1, 0] )
→ thanks to #sidyll for the help.

Best way to create substitution macros in vim

I'd like to set up some custom auto-complete macros in vim. I'm thinking something like this (| represents the cursor position):
it<TAB>|
immediately becomes:
it("|", function () {
});
Is this possible using straight vim, or would I need a plugin? If so, is there a preferred plugin out there?
Using an abbreviation you could write something like this:
inorea it it("", function () {<cr>});<c-o>k<c-o>f"
The purpose of <c-o>k<c-o>f" at the end is to reposition your cursor inside the double quotes, but it may not work all the time.
Using a mapping, you could try this:
ino <expr> <tab> <sid>expand_last_word()
let s:your_expansions = {
\ 'it': '\<c-w>it(\"\", function () {\<cr>});\<c-o>k\<right>',
\ }
fu! s:expand_last_word() abort
let last_word = matchstr(getline('.'), '\v<\k+%'.col('.').'c')
return has_key(s:your_expansions, last_word)
\ ? eval('"'.s:your_expansions[last_word].'"')
\ : "\<tab>"
endfu
You would have to add your abbreviations and their expansions inside the dictionary s:your_expansions.
Using the :read command, you could define larger snippets of code, and split them across several files:
ino <expr> <tab> <sid>expand_last_word()
fu! s:expand_last_word() abort
let last_word = matchstr(getline('.'), '\v<\k+%'.col('.').'c')
if last_word ==# 'it'
return "\<c-w>\<c-o>:r /path/to/some_file\<cr>\<c-o>f\"\<right>"
endif
return "\<tab>"
endfu
Here /path/to/some_file should contain your snippet:
it("", function () {
});
They are very simple solutions, if you want something more robust, you probably need a snippets plugin. One of them is UltiSnips, which requires that your Vim version has been compiled with Python support (:echo has('python') or :echo has('python3') returns 1).
With UltiSnips, you would write your snippet like this:
snippet it "your description" b
it("$0", function () {
});
endsnippet
Here the definition is included between the keywords snippet and endsnippet. On the 1st line, you can describe the purpose of your snippet, inside the string in double quotes. It will be displayed by UltiSnips inside a list, if you've defined several snippets with the same tab trigger, and there's an ambiguity.
The ending b is an option to prevent the tab trigger it from being expanded anywhere else than the beginning of a line.
$0 is a tabstop, it stands for the position in which you want the cursor to be, once the snippet has been fully expanded.
The readme page on github gives a quick start, and some links to videos.
If you want to have a look at the snippets written by other people, you can install vim-snippets.
There are other snippet managers but I don't know them well enough to describe the syntax of their snippets. If you want a comparison, here's one, and here are links for some of them:
snipmate
mu-template
neosnippet
xptemplate
Here is a abbreviation that you can use for your particular example
:inoreabbrev it it("", function () {<cr>});<esc>kf"a
Typing it followed by ctrl + ] in insert mode will render
it("|", function () {
});
and keep you in insert mode.
But I would definitely go for ultisnips and there is a screencast for creating snippets on the same page. That's why I am omitting the snippet here as you can do it yourself.

Vim statusline does not expand color/highlight group from expression

I wrote a function which returns a string:
function! StatusBricks()
let l:stat = Brick(statusbricks#ReportLinecount('raw'), {
\ 'brick_color': 'LineNr',
\ 'delimiter_position': 'right',
\ 'delimiter_right': '❯'
\ })
return l:stat
endfunction
The result has the following format, generated by Brick():
%#HighlightGroup#SomeData
When I use the function as an expression inside the statusline I expect the highlight group to get expanded in order to colorize the appropriate statusline section:
set statusline =%{StatusBricks()}
But what I get is a statusline literally showing %#HighlightGroup#ExpandedData rather than ExpandedData:
What am I doing wrong?
The result of %{ isn't interpreted further, however the result of %! is. Use
set statusline=%!StatusBricks()
%! doesn't appear to have a tag in the helpfile, but it's mentioned near the beginning of :help 'statusline'.
Following your comment: if you want different colours in the statusline depending on the state of each particular window, then you can highlight an empty string if you don't want a particular highlight to appear. E.g.
set stl=%#error#%r%#search#
Only read-only windows (e.g. open a help buffer) will have the read-only flag displayed in red. Admittedly this can get complicated depending on your highlighting requirements.
tl;dr - use {% %}
I realise this is an old question, but I found an answer that future readers might use.
Rather than
set statusline =%{StatusBricks()}
you need
set statusline =%{%StatusBricks()%}
From :help 'statusline':
{% - This is almost same as { except the result of the expression is
re-evaluated as a statusline format string. Thus if the
return value of expr contains % items they will get expanded.
The expression can contain the } character, the end of
expression is denoted by %}.
The For example:
func! Stl_filename() abort
return "%t"
endfunc
`stl=%{Stl_filename()}` results in `"%t"`
`stl=%{%Stl_filename()%}` results in `"Name of current file"`

Vim: Adding automatic alphabetic and/or numeric index to current file name?

I want to implement a loose version of Niklas Luhmann's
Zettelkasten
in Vim. At the core of his method are note snippets that Continue the current
note or Brahch off from it, introducing a slightly different topic or
concept. In the note name, letters indicate branches and numerals
indicate continuations. Like so:
note100
note101
note101a # branches off from note100 (related topic)
note101b # also branches off from note100 (related topic)
note101b01 # continues note101b (same topic)
note101b02 # also continues note101b (same topic)
note101c
note102
To implement this in Vim, I need new file
names that are automatically enumerated either as a "continuation" or
a "branch" of the note in current buffer. As a non-coder making first "real" steps in Vimscript, this is where I'm at with the Branching Note function:
function! ZettelkastenNewBranchingNote()
let b:current_note_name = expand('%:t:r')
let b:new_branching_note = call(BranchingFunctionThatReturnsNewNoteName)
silent execute 'edit' b:new_branching_note
echomsg 'New branching note ' b:new_branching_note 'created.'
endfunction
The BranchingFunctionThatReturnsNewNoteName() should take
b:current_note_name and extend it with automatic alphabetical(!)
index (counting alphabetically upwards). How could I accomplish this?
Also, for my New Continued Note function: how could I numerically
count upwards from the last numeric part of the current file name? (E.g. 100a01 > 100a02.)
Thanks for any advice!
(Somewhat relatedly, here
the Nexus plugin is suggested, but I'd prefer to keep my script
self-contained.)
You provide a great deal of context (which is great), but are light on the needed algorithm. To me, it looks like this: If the current file ends with a letter, increase it, else (it's a number), append an a to start the alphabetical sequence.
Checks are done in Vim with regular expressions; \a is a short form for [A-Za-z] (you could also write [[:alpha:]]; yes it's that flexible), and $ anchors it to the end of the name:
if b:current_note_name =~ '\a$'
...
Extract the last character with matchstr().
let lastAlpha = matchstr(b:current_note_name, '\a$')
if lastAlpha ==? 'z'
" TODO: Handle overflow
endif
To "increase" an alphabetical character, convert it first to a number, increase, then back:
let newAlpha = nr2char(char2nr(lastAlpha) + 1)
To replace, you use substitute(), again with the same regexp.
let b:new_branching_note = substitute(b:current_note_name, '\a$', newAlpha, '')
Appending is simple:
else
let b:new_branching_note = b:current_note_name . 'a'
endif

Resources