[vim/vim] Add support for customizing the quickfix buffer contents (#5465)

145 views
Skip to first unread message

Yegappan Lakshmanan

unread,
Jan 9, 2020, 10:56:16 PM1/9/20
to vim/vim, Subscribed

You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/5465

Commit Summary

  • Add support for customizing the quickfix buffer contents

File Changes

Patch Links:


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

Yegappan Lakshmanan

unread,
Jan 10, 2020, 12:44:58 AM1/10/20
to vim/vim, Push

@yegappan pushed 1 commit.

  • ec44d4e Use an empty string as the default value for the qfbuffunc option


You are receiving this because you are subscribed to this thread.

View it on GitHub or unsubscribe.

Codecov

unread,
Jan 10, 2020, 1:06:07 AM1/10/20
to vim/vim, Subscribed

Codecov Report

Merging #5465 into master will decrease coverage by <.01%.
The diff coverage is 87.5%.

Impacted file tree graph

@@            Coverage Diff             @@

##           master    #5465      +/-   ##

==========================================

- Coverage   82.86%   82.86%   -0.01%     

==========================================

  Files         134      134              

  Lines      147840   147878      +38     

==========================================

+ Hits       122512   122537      +25     

- Misses      25328    25341      +13
Impacted Files Coverage Δ
src/quickfix.c 94.87% <87.5%> (-0.28%) ⬇️
src/drawline.c 84.64% <0%> (-0.14%) ⬇️
src/ui.c 72.32% <0%> (-0.09%) ⬇️
src/channel.c 84.22% <0%> (-0.08%) ⬇️
src/terminal.c 81.85% <0%> (+0.03%) ⬆️
src/gui.c 63.63% <0%> (+0.05%) ⬆️
src/if_xcmdsrv.c 86.35% <0%> (+0.17%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2963456...ec44d4e. Read the comment docs.

Bram Moolenaar

unread,
Jan 10, 2020, 12:49:07 PM1/10/20
to vim/vim, Subscribed

I wonder if we should make the function argument a dictionary, with the three entries that are currently the arguments. That makes it a lot easier to later add another argument.

The help text mostly refers to the "quickfix buffer". However, existing help text refers to "quickfix window", as it's the window that matters to the user. That it contains a special buffer is more an implementation detail.

Shortening "quickfix" to "qf" in the option name is a bit obscure, it would be the first. How about "quickfixtext"? Or "quickfixtextfunc" to be more accurate, but also quite long. The short version can be 'qftf', which is OK.

Linwei

unread,
Jan 10, 2020, 1:36:31 PM1/10/20
to vim/vim, Subscribed

What can I do if I want to keep the original text in the quickfix ?? Do I have to write a callback function for this simple purpose ??

Yegappan Lakshmanan

unread,
Jan 11, 2020, 9:58:32 AM1/11/20
to vim_dev, reply+ACY5DGEUWKAKEDYS6O...@reply.github.com, vim/vim, Subscribed
Hi,

On Sat, Jan 11, 2020 at 12:06 AM Linwei <vim-dev...@256bit.org> wrote:

What can I do if I want to keep the original text in the quickfix ?? Do I have to write a callback function for this simple purpose ??



The original text is not kept internally. After the original text is parsed
using the 'errorformat' option, only the parsed values (like the file name,
line number, column number and the error message) are kept.
Even if we support the 'raw' value for the new 'quickfixtextfunc' option,
only the error message can be displayed in the quickfix window.
This message is most probably different from the original line of
text (depending on the 'efm' setting). Will that be sufficient for
your use case?

- Yegappan

vim-dev ML

unread,
Jan 11, 2020, 9:58:57 AM1/11/20
to vim/vim, vim-dev ML, Your activity

Linwei

unread,
Jan 11, 2020, 11:38:15 AM1/11/20
to vim/vim, vim-dev ML, Comment

@yegappan , just one more step, provide a way to leave the original output as what it is. Let me explain why.

Compilers and linters are continually evolving, ten years ago, the output of compilers are still simply enough, just take gcc 4.2 (released in 2008) for example:

test3.cpp:4: error: invalid conversion from 'const char*' to 'int'

They are simply enough and you can interpret them line by line, each line represents a single message, not relevant to the previous or next lines. So you can format them into what ever you like.

But things got changed, let's see the gcc 9.4 output:

test.cpp: In function ‘int main()’:

test.cpp:4:9: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]

    4 |     x = "hello";

      |         ^~~~~~~

      |         |

      |         const char*

In these days, modern compilers and linters trend to use multiple well-formated lines to represent one error. The adjacent lines are relevant to each other. If you change one of them, you will hurt their readabilities and make them hard to understand.

What if another compiler output like this:

quickfix1

After some so called clever conversion, it will look like this in quickfix:

quickfix2

I would rather wish you to keep text untouched in the quickfix window. Any conversion would be unnecessary and will make the result confusion in this simple situation.

I believe the purpose of quickfix is to make information more understandable, not to confuse people. If we agree so, why are we still insist to reformat texts in quickfix ?

And if you think this is still not convincing enough, I'd like show you another example:

The output of rspec is well-formated, beautiful and easy to understand in the shell. But if you notice what neomake/asyncrun/dispatch.vim make out of it in the quickfix window:

图片

Do you still consider the converted text is more understandable than the original text ??

Maybe someone would suggest we should run this compilers or linters directly in a built-in terminal, or output them in another buffer instead of putting them in the quickfix window.

I suppose quickfix is the most brilliant infrastructure in vim. Plugins using quickfix can collaborate with each other:

  • neomake/asyncrun/dispatch can generate outputs in quickfix
  • errormarker can retrive information from qf and set error markers for lines with compile errors.
  • vim-preview can preview errors in the preview window when you press a p in the quickfix.

If every plugin invent their own quickfix window, that would be a disarster.

So, please give us an option to keep the original text in the quickfix window, errors and warnings can still be highlighted and remain selectable.

@brammool & @yegappan , do you think it is a reasonable suggestion ??


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
Jan 11, 2020, 7:49:55 PM1/11/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • a70139e Change option name to quickfixtestfunc. The callback function now takes a dict argument. Updtae the doc


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Jan 11, 2020, 8:24:34 PM1/11/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 77d81f9 Update the example in the doc


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Jan 11, 2020, 8:25:41 PM1/11/20
to vim_dev, reply+ACY5DGA6HGHQ6IHF6F...@reply.github.com, vim/vim, Subscribed
Hi Bram,

On Fri, Jan 10, 2020 at 11:19 PM Bram Moolenaar
<vim-dev...@256bit.org> wrote:
>
> I wonder if we should make the function argument a dictionary, with the three entries
> that are currently the arguments. That makes it a lot easier to later add another argument.
>

I have updated the PR with this change. The callback function now takes a
dict argument.

>
> The help text mostly refers to the "quickfix buffer". However, existing help text refers to
> "quickfix window", as it's the window that matters to the user. That it contains a special
> buffer is more an implementation detail.
>

Updated the doc to use "quickfix window" instead of "quickfix buffer".

>
> Shortening "quickfix" to "qf" in the option name is a bit obscure, it would be the first.
> How about "quickfixtext"? Or "quickfixtextfunc" to be more accurate, but also quite
> long. The short version can be 'qftf', which is OK.
>

Changed the option name to "quickfixtextfunc".

Regards,
Yegappan

vim-dev ML

unread,
Jan 11, 2020, 8:25:47 PM1/11/20
to vim/vim, vim-dev ML, Your activity

Yegappan Lakshmanan

unread,
Jan 11, 2020, 8:38:16 PM1/11/20
to vim_dev, reply+ACY5DGF7KLB24GL6Y5...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sat, Jan 11, 2020 at 10:08 PM Linwei <vim-dev...@256bit.org> wrote:

@yegappan , just one more step, provide a way to leave the original output as what it is. Let me explain why.


I understand the need for showing the raw output in the quickfix window without any formatting.
But note that Vim still needs to process the output using 'efm' and extract the location
information. A user can jump to a location from some lines in the quickfix window and from some
lines he cannot jump to a location. We need to somehow distinctly highlight the lines which
are active.
 

Compilers and linters are continually evolving, ten years ago, the output of compilers are still simply enough, just take gcc 4.2 (released in 2008) for example:

test3.cpp:4: error: invalid conversion from 'const char*' to 'int'

They are simply enough and you can interpret them line by line, each line represents a single message, not relevant to the previous or next lines. So you can format them into what ever you like.

But things got changed, let's see the gcc 9.4 output:

test.cpp: In function ‘int main()’:

test.cpp:4:9: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]

    4 |     x = "hello";

      |         ^~~~~~~

      |         |

      |         const char*

In these days, modern compilers and linters trend to use multiple well-formated lines to represent one error. The adjacent lines are relevant to each other. If you change one of them, you will hurt their readabilities and make them hard to understand.


Note that Vim can still properly parse the multi-line error messages using 'efm' and display the
caret symbol at the proper location.

I will look into a way to support displaying the raw text in the quickfix window.

Regards,
Yegappan

vim-dev ML

unread,
Jan 11, 2020, 8:38:21 PM1/11/20
to vim/vim, vim-dev ML, Your activity
Hi,

On Sat, Jan 11, 2020 at 10:08 PM Linwei <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> , just one more step, provide a

> way to leave the original output as what it is. Let me explain why.
>

I understand the need for showing the raw output in the quickfix window
without any formatting.
But note that Vim still needs to process the output using 'efm' and extract
the location
information. A user can jump to a location from some lines in the quickfix
window and from some
lines he cannot jump to a location. We need to somehow distinctly highlight
the lines which
are active.


> Compilers and linters are continually evolving, ten years ago, the output
> of compilers are still simply enough, just take *gcc 4.2* (released in

> 2008) for example:
>
> test3.cpp:4: error: invalid conversion from 'const char*' to 'int'
>
>
> They are simply enough and you can interpret them line by line, each line
> represents a single message, not relevant to the previous or next lines. So
> you can format them into what ever you like.
>
> But things got changed, let's see the *gcc 9.4* output:

>
> test.cpp: In function ‘int main()’:
>
> test.cpp:4:9: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
>
> 4 | x = "hello";
>
> | ^~~~~~~
>
> | |
>
> | const char*
>
>
> In these days, modern compilers and linters trend to use multiple
> well-formated lines to represent one error. The adjacent lines are relevant
> to each other. *If you change one of them, you will hurt their
> readabilities* and make them hard to understand.

>

Note that Vim can still properly parse the multi-line error messages using
'efm' and display the
caret symbol at the proper location.

I will look into a way to support displaying the raw text in the quickfix
window.

Regards,
Yegappan


> What if another compiler output like this:
>
> [image: quickfix1]
> <https://user-images.githubusercontent.com/3035071/72207040-b8b58580-34cf-11ea-9951-8b15b480a3db.png>
>
> After some so called *clever* conversion, it will look like this in
> quickfix:
>
> [image: quickfix2]
> <https://user-images.githubusercontent.com/3035071/72207059-df73bc00-34cf-11ea-82d6-baa363340d78.png>

>
> I would rather wish you to keep text untouched in the quickfix window. Any
> conversion would be unnecessary and will make the result confusion in this
> simple situation.
>
> I believe the purpose of quickfix is to make information more
> understandable, not to confuse people. If we agree so, why are we still
> insist to reformat texts in quickfix ?
>
> And if you think this is still not convincing enough, I'd like show you
> another example:
>
>
> <https://user-images.githubusercontent.com/3035071/71560565-d8e44e00-2aa6-11ea-963b-e9442550ec67.png>

>
> The output of rspec is well-formated, beautiful and easy to understand in
> the shell. But if you notice what neomake/asyncrun/dispatch.vim make out of
> it in the quickfix window:
>
> [image: 图片]
> <https://user-images.githubusercontent.com/3035071/72207190-7725da00-34d1-11ea-9b76-30637db815d3.png>

>
> Do you still consider the converted text is more understandable than the
> original text ??
>
> Maybe someone would suggest we should run this compilers or linters
> directly in a built-in terminal, or output them in another buffer instead
> of putting them in the quickfix window.
>
> I suppose quickfix is the most brilliant infrastructure in vim. Plugins
> using quickfix can collaborate with each other:
>
> - neomake/asyncrun/dispatch can generate outputs in quickfix
> - errormarker can retrive information from qf and set error markers

> for lines with compile errors.
> - vim-preview can preview errors in the preview window when you press

> a p in the quickfix.
>
> If every plugin invent their own quickfix window, that would be a
> disarster.
>
> So, please give us an option to keep the original text in the quickfix
> window, errors and warnings can still be highlighted and remain selectable.
>
> @brammool <https://github.com/brammool> & @yegappan
> <https://github.com/yegappan> , do you think it is a reasonable
> suggestion ??
>
>
>

Bram Moolenaar

unread,
Jan 12, 2020, 7:54:07 AM1/12/20
to vim...@googlegroups.com, Yegappan Lakshmanan, reply+ACY5DGA6HGHQ6IHF6F...@reply.github.com
Thanks.

I'll give it a few days for others to comment.

--
No children may attend school with their breath smelling of "wild onions."
[real standing law in West Virginia, United States of America]

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

vim-dev ML

unread,
Jan 12, 2020, 7:54:12 AM1/12/20
to vim/vim, vim-dev ML, Your activity

Yegappan Lakshmanan

unread,
Apr 21, 2020, 9:53:46 PM4/21/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 24a8eac Free the string returned by the qftextfunc


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Apr 27, 2020, 1:34:11 AM4/27/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.


You are receiving this because you are subscribed to this thread.

Ben Jackson

unread,
Apr 27, 2020, 6:58:45 AM4/27/20
to vim/vim, vim-dev ML, Comment

@puremourning commented on this pull request.

Just reviewed the docs because i was curious about this feature. I sort of left feeling that i didn't really get it.


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim
+function.  This function will be called with a dict argument for every entry
+in the quickfix list. The dict argument will have the following fields:
+
+    quickfix	set to 1 when called for a quickfix list

what else would it be set to ? Presumably 0 for location list ?


In runtime/doc/quickfix.txt:

> +in the quickfix list. The dict argument will have the following fields:
+
+    quickfix	set to 1 when called for a quickfix list
+    id		quickfix or location list identifier
+    idx		index of the entry in the quickfix or location list
+
+The function should return a single line of text to display in the quickfix
+window for the entry identified by idx.
+
+If a quickfix or location list specific customization is needed, then the
+'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
+|setloclist()| function. This overrides the 'quickfixtextfunc' option setting.
+
+The example below tries to mimic the default behavior for the quickfix
+and location list windows.
+Example: >

i suspect this example is too complex. Is it better to use a simpler, motivating example? Like why this feature was added in a nutshell?


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim
+function.  This function will be called with a dict argument for every entry
+in the quickfix list. The dict argument will have the following fields:

how do you get the text of the current "index"? presumably using getqflist and specifying the index in the options dict. Worth saying that here to avoid confusion. It's clear in the example below, but:

  • the example is complex
  • the example contains no commentary explaining what it is doing or why

In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim

worth introducing the "why" early - the what is fine, but not the why - e.g. what's a motivating use case for this ?


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
Apr 27, 2020, 11:31:19 AM4/27/20
to vim/vim, vim-dev ML, Comment

@yegappan commented on this pull request.


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim

There have been asks in the past for customizing the quickfix buffer contents.

For example, you search for a pattern from the top of a source tree ,
and populate the quickfix list with the search results (using a tool like ripgrep).
If you change the current directory now (because you have set 'autochdir' or
used the lcd or tcd commands), then the quickfix window will show the
complete path to the files. If the source tree is deeply nested, then the
results in the quickfix window will be hard to read. It will be useful in
this scenario to abbreviate the file path and show only the last few
characters to to show SRCROOT to replace the path before the
project root directory.

Similarly there was an ask to show the module information in the
quickfix buffer. This was supported by modifying the Vim source
code. Instead of modifying the source code, we can use this
function to customize the quickfix fix line.


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim
+function.  This function will be called with a dict argument for every entry
+in the quickfix list. The dict argument will have the following fields:

Yes. You can get the contents of a specific quickfix item using 'index' in
getqflst(). I will update the help text to explicitly state this. I will also
add comments to the example function.


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim
+function.  This function will be called with a dict argument for every entry
+in the quickfix list. The dict argument will have the following fields:
+
+    quickfix	set to 1 when called for a quickfix list

Yes. I will update the help text.


In runtime/doc/quickfix.txt:

> +in the quickfix list. The dict argument will have the following fields:
+
+    quickfix	set to 1 when called for a quickfix list
+    id		quickfix or location list identifier
+    idx		index of the entry in the quickfix or location list
+
+The function should return a single line of text to display in the quickfix
+window for the entry identified by idx.
+
+If a quickfix or location list specific customization is needed, then the
+'quickfixtextfunc' attribute of the list can be set using the |setqflist()| or
+|setloclist()| function. This overrides the 'quickfixtextfunc' option setting.
+
+The example below tries to mimic the default behavior for the quickfix
+and location list windows.
+Example: >

To keep most of the contents of the quickfix/location list buffer but only modify
selected components like path name or other parts of the line, you still need to
handle all the cases. I will add comments to this example.


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
Apr 27, 2020, 1:58:30 PM4/27/20
to vim/vim, vim-dev ML, Comment

@yegappan commented on this pull request.


In runtime/doc/quickfix.txt:

> @@ -1921,6 +1922,63 @@ error messages into a format that quickfix mode will understand.  See the
 start of the file about how to use it.  (This script is deprecated, see
 |compiler-perl|.)
 
-
+=============================================================================
+10. Customizing the quickfix window		*quickfix-window-function*
+
+The default format for the lines displayed in the quickfix window and location
+list window is:
+
+    <filename>|<lnum> col <n>|<text>
+
+This can be customized by setting the 'quickfixtextfunc' option to a Vim

An example to illustrate how to substitute the project source root directory
with SRCROOT in the quickfix buffer is below:

func Myqffunc(info)
" get the quickfix list entry
let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
\ 'items' : 1}).items[0]
" substitute the source root directory with SRCROOT
let s = fnamemodify(bufname(e.bufnr),
\ ':p:.:s#/project/source/root#SRCROOT#')
" add the line number and the line text
let s ..= '|' .. e.lnum .. '| ' .. substitute(e.text, '^\s+', '', '')
return s
endfunc
set quickfixtextfunc=Myqffunc


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
Apr 30, 2020, 6:44:10 PM4/30/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 533a173 Add support for customizing the quickfix buffer contents


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Apr 30, 2020, 7:19:19 PM4/30/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.


You are receiving this because you are subscribed to this thread.

Wang Shidong

unread,
Apr 30, 2020, 11:19:52 PM4/30/20
to vim/vim, vim-dev ML, Comment

@wsdjeg commented on this pull request.


In runtime/doc/quickfix.txt:

> +|setloclist()| function. This overrides the 'quickfixtextfunc' option setting.
+
+The example below displays the list of old files (|v:oldfiles|) in a quickfix
+window. As there is no line, column number and error text information
+associated with each entry, the 'quickfixtextfunc' function returns only the
+filename.
+Example: >
+    " create a quickfix list from v:oldfiles
+    call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
+					\ 'quickfixtextfunc' : 'QfOldFiles'})
+    func QfOldFiles(info)
+	" get information about the specific quickfix entry
+	let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
+						\ 'items' : 1}).items[0]
+	" return the simplified file name
+	return fnamemodify(bufname(e.bufnr), ':p:.')

why only return the file name instead of whole line?


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
May 1, 2020, 12:05:17 AM5/1/20
to vim_dev, reply+ACY5DGBN757SGT7QR6...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Thu, Apr 30, 2020 at 8:19 PM Wang Shidong <vim-dev...@256bit.org> wrote:

@wsdjeg commented on this pull request.


In runtime/doc/quickfix.txt:

> +|setloclist()| function. This overrides the 'quickfixtextfunc' option setting.
+
+The example below displays the list of old files (|v:oldfiles|) in a quickfix
+window. As there is no line, column number and error text information
+associated with each entry, the 'quickfixtextfunc' function returns only the
+filename.
+Example: >
+    " create a quickfix list from v:oldfiles
+    call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
+					\ 'quickfixtextfunc' : 'QfOldFiles'})
+    func QfOldFiles(info)
+	" get information about the specific quickfix entry
+	let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
+						\ 'items' : 1}).items[0]
+	" return the simplified file name
+	return fnamemodify(bufname(e.bufnr), ':p:.')

why only return the file name instead of whole line?



The v:oldfiles variable contains only the name of the files. The above example shows how to
populate the quickfix list from the v:oldfiles variable. So the function returns only the name
of the file.

- Yegappan
 

vim-dev ML

unread,
May 1, 2020, 12:05:36 AM5/1/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Thu, Apr 30, 2020 at 8:19 PM Wang Shidong <vim-dev...@256bit.org>
wrote:

> *@wsdjeg* commented on this pull request.
> ------------------------------
>
> In runtime/doc/quickfix.txt
> <https://github.com/vim/vim/pull/5465#discussion_r418399236>:

>
> > +|setloclist()| function. This overrides the 'quickfixtextfunc' option setting.
> +
> +The example below displays the list of old files (|v:oldfiles|) in a quickfix
> +window. As there is no line, column number and error text information
> +associated with each entry, the 'quickfixtextfunc' function returns only the
> +filename.
> +Example: >
> + " create a quickfix list from v:oldfiles
> + call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
> + \ 'quickfixtextfunc' : 'QfOldFiles'})
> + func QfOldFiles(info)
> + " get information about the specific quickfix entry
> + let e = getqflist({'id' : a:info.id, 'idx' : a:info.idx,
> + \ 'items' : 1}).items[0]
> + " return the simplified file name
> + return fnamemodify(bufname(e.bufnr), ':p:.')
>
> why only return the file name instead of whole line?
>
>
>
The v:oldfiles variable contains only the name of the files. The above
example shows how to
populate the quickfix list from the v:oldfiles variable. So the function
returns only the name
of the file.

- Yegappan

Yegappan Lakshmanan

unread,
May 3, 2020, 10:54:19 PM5/3/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 2 commits.

  • f7bad4a Add support for customizing the quickfix buffer contents
  • 2802eb8 Fix sync damage


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
May 7, 2020, 7:58:05 PM5/7/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 2 commits.

  • 78ccafe Add support for customizing the quickfix buffer contents
  • 415e4d7 Fix sync damage

Yegappan Lakshmanan

unread,
May 10, 2020, 2:17:29 AM5/10/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 28c260d Add support for customizing the quickfix buffer contents

Yegappan Lakshmanan

unread,
May 10, 2020, 6:27:05 PM5/10/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 1b24525 Add support for customizing the quickfix buffer contents

Yegappan Lakshmanan

unread,
May 15, 2020, 1:42:50 AM5/15/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 317a066 Add support for customizing the quickfix buffer contents

Yegappan Lakshmanan

unread,
May 22, 2020, 9:59:26 PM5/22/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 7959830 Add support for customizing the quickfix buffer contents

Yegappan Lakshmanan

unread,
May 27, 2020, 12:38:54 AM5/27/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • 28ccd08 Add support for customizing the quickfix buffer contents

Codecov Comments Bot

unread,
May 27, 2020, 1:43:43 AM5/27/20
to vim/vim, vim-dev ML, Comment

Codecov Report

Merging #5465 into master will decrease coverage by 0.00%.
The diff coverage is 98.91%.

Impacted file tree graph

@@            Coverage Diff             @@

##           master    #5465      +/-   ##

==========================================

- Coverage   87.30%   87.30%   -0.01%     

==========================================

  Files         141      141              

  Lines      157151   157193      +42     

==========================================

+ Hits       137201   137236      +35     

- Misses      19950    19957       +7     
Impacted Files Coverage Δ
src/quickfix.c 95.00% <98.91%> (+0.06%) ⬆️
src/mbyte.c 65.69% <0.00%> (-0.19%) ⬇️
src/if_xcmdsrv.c 88.73% <0.00%> (-0.18%) ⬇️
src/search.c 91.38% <0.00%> (-0.12%) ⬇️
src/netbeans.c 75.18% <0.00%> (-0.08%) ⬇️
src/ex_getln.c 91.44% <0.00%> (-0.05%) ⬇️
src/gui_gtk_x11.c 58.33% <0.00%> (ø)
src/terminal.c 91.01% <0.00%> (+0.03%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 80a20df...28ccd08. Read the comment docs.


You are receiving this because you commented.

Yegappan Lakshmanan

unread,
May 29, 2020, 8:28:39 PM5/29/20
to vim/vim, vim-dev ML, Push

@yegappan pushed 1 commit.

  • d02ebb5 Add support for customizing the quickfix buffer contents

Bram Moolenaar

unread,
May 31, 2020, 5:12:31 PM5/31/20
to vim/vim, vim-dev ML, Comment

Closed #5465 via 858ba06.

lacygoill

unread,
Jun 7, 2020, 5:30:03 AM6/7/20
to vim/vim, vim-dev ML, Comment

@yegappan Thank you for working on this feature.

The more entries a quickfix list contains, the more costly the 'quickfixtextfunc' seems to be.

I tried to write what seems to be a simple function:

fu QuickFixTextFunc(info) abort

    if a:info.quickfix

        let e = getqflist({'id': a:info.id, 'idx': a:info.idx, 'items': 1}).items[0]

    else

        let e = getloclist(0, {'id': a:info.id, 'idx': a:info.idx, 'items': 1}).items[0]

    endif

    let fname = fnamemodify(bufname(e.bufnr), ':t')

    if strchars(fname, 1) <= 8

        let fname = printf('%8s', fname)

    else

        let fname = printf('%.7s', fname)..'…'

    endif

    let lnum = printf('%5d', e.lnum)

    let col = printf('%3d', e.col)

    return fname..'|'..lnum..' col '..col..'| '..e.text

endfu

And tested it with this command:

$ vim -Nu NONE -S <(curl -Ls https://gist.githubusercontent.com/lacygoill/57d3cd8b5313159f42af43704ebfa7a8/raw/a255cbc37efe18319690943129d0abdf661c1434/profile_quickfixtextfunc.vim)

:QfTf 8

On my machine, the test took about 2 minutes to complete. Here are the results:

   1000 entries:   0.001 seconds to run :copen

                   0.039 seconds to run :copen with 'qftf'  39 times slower

   2000 entries:   0.001 seconds to run :copen

                   0.084 seconds to run :copen with 'qftf'  84 times slower

   4000 entries:   0.003 seconds to run :copen

                   0.190 seconds to run :copen with 'qftf'  63 times slower

   8000 entries:   0.006 seconds to run :copen

                   0.457 seconds to run :copen with 'qftf'  76 times slower

  16000 entries:   0.012 seconds to run :copen

                   1.260 seconds to run :copen with 'qftf'  105 times slower

  32000 entries:   0.025 seconds to run :copen

                   4.983 seconds to run :copen with 'qftf'  199 times slower

  64000 entries:   0.054 seconds to run :copen

                  23.322 seconds to run :copen with 'qftf'  431 times slower

 128000 entries:   0.107 seconds to run :copen

                  97.002 seconds to run :copen with 'qftf'  906 times slower

As you can see, for a quickfix list with more than a thousand entries, 'quickfixtextfunc' makes :copen around a thousand times slower. And the more entries, the slower the feature is.

Do you think something could be done to prevent the function from being called when the quickfix list contains too many entries? Maybe the option could be set to a colon separated list of values: the name of the function to format the entry in the quickfix window, and an optional number. When the size of a quickfix list goes beyond that number, the function would not be invoked to format the entry. It would be displayed as if the option was not set.

Bram Moolenaar

unread,
Jun 7, 2020, 8:02:36 AM6/7/20
to vim/vim, vim-dev ML, Comment

I'm not sure if it works, but you could try defining QuickFixTextFunc() with :def.
Will require a slightly different syntax. Much of the work is still done by getqflist(), thus compiling might not help that much.
Otherwise, please try profiling this to find out where time is spent.

Yegappan Lakshmanan

unread,
Jun 7, 2020, 11:09:52 AM6/7/20
to vim_dev, reply+ACY5DGFW34HT3RIJZ6...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:

@yegappan Thank you for working on this feature.

The more entries a quickfix list contains, the more costly the 'quickfixtextfunc' seems to be.

I tried to write what seems to be a simple function:

fu QuickFixTextFunc(info) abort

    if a:info.quickfix

        let e = getqflist({'id': a:info.id, 'idx': a:info.idx, 'items': 1}).items[0]

    else

        let e = getloclist(0, {'id': a:info.id, 'idx': a:info.idx, 'items': 1}).items[0]

Note that there is currently an issue with using '0' for the window number. This function will fail
if you update the location list after opening and closing the location list window. (lexpr, lwindow,
lclose, lexpr). I will create a PR to address this.
We may not be able to predict the size of the quickfix list beforehand. For example, an async
plugin (running ripgrep for example), can incrementally add the search results to the
quickfix list. Initially the quickfix list may have a few hundred entries, but as the plugin
function asynchronously adds entries to the list, it may grow to a few thousand entries.
If the quickfix window is open when the plugin runs, then the first few entries will use
the 'qftf' function to format the output, but the later lines will look different.

- Yegappan

vim-dev ML

unread,
Jun 7, 2020, 11:10:15 AM6/7/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Thank you for working on this


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Jun 10, 2020, 11:22:59 AM6/10/20
to vim_dev, reply+ACY5DGFW34HT3RIJZ6...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:
I profiled the code with your test function. I see that the majority of the time is
spent in the cleanup_function_call() function. This function is called after
invoking a user defined function to cleanup the local hash table. I am not
sure whether using a Vim9 type script will help here. I wlll also profile with
a lambda function to see whether that will help.

- Yegappan

 

vim-dev ML

unread,
Jun 10, 2020, 11:23:18 AM6/10/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Thank you for working on this

Yegappan Lakshmanan

unread,
Jun 10, 2020, 11:25:40 AM6/10/20
to vim_dev, reply+ACY5DGFW34HT3RIJZ6...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

Another alternative is to call the function for a range of lines in the quickfix list
instead of for every line in the quickfix list. The function should return a list
of strings (one per line).

- Yegappan
 

vim-dev ML

unread,
Jun 10, 2020, 11:25:58 AM6/10/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Wed, Jun 10, 2020 at 8:22 AM Yegappan Lakshmanan <yega...@gmail.com>
wrote:

> Hi,
>
> On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org>
> wrote:
>
>> @yegappan <https://github.com/yegappan> Thank you for working on this

Yegappan Lakshmanan

unread,
Jun 10, 2020, 10:18:45 PM6/10/20
to vim_dev, reply+ACY5DGFW34HT3RIJZ6...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:

@yegappan Thank you for working on this feature.

The more entries a quickfix list contains, the more costly the 'quickfixtextfunc' seems to be.

I tried to write what seems to be a simple function:

And tested it with this command:
$ vim -Nu NONE -S <(curl -Ls https://gist.githubusercontent.com/lacygoill/57d3cd8b5313159f42af43704ebfa7a8/raw/a255cbc37efe18319690943129d0abdf661c1434/profile_quickfixtextfunc.vim)

:QfTf 8

On my machine, the test took about 2 minutes to complete. Here are the results:

   1000 entries:   0.001 seconds to run :copen

                   0.039 seconds to run :copen with 'qftf'  39 times slower

   2000 entries:   0.001 seconds to run :copen

                   0.084 seconds to run :copen with 'qftf'  84 times slower

   4000 entries:   0.003 seconds to run :copen

                   0.190 seconds to run :copen with 'qftf'  63 times slower

   8000 entries:   0.006 seconds to run :copen

                   0.457 seconds to run :copen with 'qftf'  76 times slower

  16000 entries:   0.012 seconds to run :copen

                   1.260 seconds to run :copen with 'qftf'  105 times slower

  32000 entries:   0.025 seconds to run :copen

                   4.983 seconds to run :copen with 'qftf'  199 times slower

  64000 entries:   0.054 seconds to run :copen

                  23.322 seconds to run :copen with 'qftf'  431 times slower

 128000 entries:   0.107 seconds to run :copen

                  97.002 seconds to run :copen with 'qftf'  906 times slower

As you can see, for a quickfix list with more than a thousand entries, 'quickfixtextfunc' makes :copen around a thousand times slower. And the more entries, the slower the feature is.

Do you think something could be done to prevent the function from being called when the quickfix list contains too many entries? Maybe the option could be set to a colon separated list of values: the name of the function to format the entry in the quickfix window, and an optional number. When the size of a quickfix list goes beyond that number, the function would not be invoked to format the entry. It would be displayed as if the option was not set.


To address this scalability problem, I have created following PR:


Instead of calling the 'quickfixtextfunc' for each entry in the quickfix list, now it will
be called for multiple entries (start_idx to end_idx). Now your test runs much
faster.

If entries are added to the quickfix list one at a time, then this will not help.
For example, if a plugin asynchronously runs a command and adds the
lines from the command output one at a time to the quickfix list, then the
overhead of calling the 'quickfixtextfunc' function cannot be avoided.
This overhead can be reduced if the plugin accumulates multiple lines
and then add it to the quickfix list.

- Yegappan

vim-dev ML

unread,
Jun 10, 2020, 10:19:03 PM6/10/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sun, Jun 7, 2020 at 2:30 AM lacygoill <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Thank you for working on this

lacygoill

unread,
Jul 5, 2020, 1:58:36 PM7/5/20
to vim/vim, vim-dev ML, Comment

I'm not sure if it works, but you could try defining QuickFixTextFunc() with :def.
Will require a slightly different syntax. Much of the work is still done by getqflist(), thus compiling might not help that much.

So, I finally converted the code into Vim9 script, and it's indeed much quicker. 5 times quicker on average.

Old code:

fu QuickFixTextFunc(info) abort

    if a:info.quickfix

        let qfl = getqflist({'id': a:info.id, 'items': 1}).items

    else

        let qfl = getloclist(a:info.winid, {'id': a:info.id, 'items': 1}).items

    endif

    let l = []

    for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)

        let e = qfl[idx]

        let fname = fnamemodify(bufname(e.bufnr), ':t')

        if strchars(fname, 1) <= 8

            let fname = printf('%8s', fname)

        else

            let fname = printf('%.7s', fname)..'…'

        endif

        let lnum = printf('%5d', e.lnum)

        let col = printf('%3d', e.col)

        call add(l, fname..'|'..lnum..' col '..col..'| '..e.text)

    endfor

    return l

endfu



com -bar -nargs=? QfTf call QfTf(<args>)



fu QfTf(...) abort

    mess clear

    let m = get(a:, '1', 5)

    for n in repeat([1], m)->map('1000*v:val*pow(2, v:key)->float2nr()')

        set qftf=

        call Test(n)

        set qftf=QuickFixTextFunc

        call Test(n, 1)

    endfor

    sil %d

    sil pu=execute('mess')

    sil v/seconds/d_

    g/qftf/call FormatLine()

endfu



fu Test(n, ...) abort

    e! /tmp/file

    sil %d

    sil pu=repeat(['some text'], a:n)

    vim /text/gj %

    let time = reltime()

    copen

    let time = matchstr(reltimestr(reltime(time)), '.*\..\{,3}')

    redraw

    let entries = printf('%7d entries: ', a:n)

    if a:0

        echom printf("%s%s seconds to run :copen with 'qftf'", repeat(' ', strlen(entries)), time)

    else

        echom printf('%s%s seconds to run :copen', entries, time)

    endif

    cclose

endfu



fu FormatLine() abort

    let time_here = getline('.')->matchlist('\(\d\+\)\.\(\d\+\)')[1:2]->join('')->str2nr()

    let time_above = getline(line('.')-1)->matchlist('\(\d\+\)\.\(\d\+\)')[1:2]->join('')->str2nr()

    let ratio = time_above ? time_here / time_above : '??'

    exe 'norm! A  '..ratio..' times slower'

endfu

Results from :QfTf 10:

  1000 entries:   0.000 seconds to run :copen

                  0.024 seconds to run :copen with 'qftf'  ?? times slower

  2000 entries:   0.001 seconds to run :copen

                  0.049 seconds to run :copen with 'qftf'  49 times slower

  4000 entries:   0.003 seconds to run :copen

                  0.098 seconds to run :copen with 'qftf'  32 times slower

  8000 entries:   0.006 seconds to run :copen

                  0.203 seconds to run :copen with 'qftf'  33 times slower

 16000 entries:   0.012 seconds to run :copen

                  0.401 seconds to run :copen with 'qftf'  33 times slower

 32000 entries:   0.024 seconds to run :copen

                  0.797 seconds to run :copen with 'qftf'  33 times slower

 64000 entries:   0.049 seconds to run :copen

                  1.587 seconds to run :copen with 'qftf'  32 times slower

128000 entries:   0.102 seconds to run :copen

                  3.197 seconds to run :copen with 'qftf'  31 times slower

256000 entries:   0.206 seconds to run :copen

                  6.442 seconds to run :copen with 'qftf'  31 times slower

512000 entries:   0.409 seconds to run :copen

                 12.775 seconds to run :copen with 'qftf'  31 times slower

New code:

vim9script



def QuickFixTextFunc(info: dict<number>): list<string>

    let qfl: list<any>

    if info.quickfix

        qfl = getqflist(#{id: info.id, items: 0}).items

    else

        qfl = getloclist(info.winid, #{id: info.id, items: 0}).items

    endif

    let l: list<string> = []

    for idx in range(info.start_idx - 1, info.end_idx - 1)

        let e = qfl[idx]

        let fname = bufname(e.bufnr)->fnamemodify(':t')

        if strchars(fname, 1) <= 8

            fname = printf('%8s', fname)

        else

            fname = printf('%.7s', fname) .. '…'

        endif

        let lnum = printf('%5d', e.lnum)

        let col = printf('%3d', e.col)

        add(l, fname .. '|' .. lnum .. ' col ' .. col .. '| ' .. e.text)

    endfor

    return l

enddef



com -bar -nargs=? QfTf call QfTf(<args>)



def QfTf(m = 5)

    mess clear

    let alist: list<number> = repeat([1], m)->map('1000*v:val*pow(2, v:key)->float2nr()')

    for n in alist

        set qftf=

        call Test(n)

        set qftf=QuickFixTextFunc

        call Test(n, v:true)

    endfor

    :sil %d

    sil pu=execute('mess')

    sil v/seconds/d_

    g/qftf/call FormatLine()

enddef



def Test(n: number, qftf = v:false)

    e! /tmp/file

    :sil %d

    setline(1, repeat(['some text'], n))

    vim /text/gj %

    let time = reltime()

    copen

    let _time = reltime(time)->reltimestr()->matchstr('.*\..\{,3}')

    redraw

    let entries = printf('%7d entries: ', n)

    if qftf

        echom printf("%s%s seconds to run :copen with 'qftf'", repeat(' ', strlen(entries)), _time)

    else

        echom printf('%s%s seconds to run :copen', entries, _time)

    endif

    cclose

enddef



fu FormatLine()

    let time_here = getline('.')->matchlist('\(\d\+\)\.\(\d\+\)')[1:2]->join('')->str2nr()

    let time_above = getline(line('.')-1)->matchlist('\(\d\+\)\.\(\d\+\)')[1:2]->join('')->str2nr()

    let ratio = time_above ? time_here / time_above : '??'

    exe 'norm! A  '..ratio..' times slower'

endfu

Results from :QfTf 10:

1000 entries:   0.001 seconds to run :copen

                0.005 seconds to run :copen with 'qftf'  5 times slower

2000 entries:   0.001 seconds to run :copen

                0.010 seconds to run :copen with 'qftf'  10 times slower

4000 entries:   0.003 seconds to run :copen

                0.021 seconds to run :copen with 'qftf'  7 times slower

8000 entries:   0.006 seconds to run :copen

                0.042 seconds to run :copen with 'qftf'  7 times slower

16000 entries:  0.012 seconds to run :copen

                0.085 seconds to run :copen with 'qftf'  7 times slower

32000 entries:  0.027 seconds to run :copen

                0.169 seconds to run :copen with 'qftf'  6 times slower

64000 entries:  0.050 seconds to run :copen

                0.354 seconds to run :copen with 'qftf'  7 times slower

128000 entries: 0.101 seconds to run :copen

                0.693 seconds to run :copen with 'qftf'  6 times slower

256000 entries: 0.218 seconds to run :copen

                1.374 seconds to run :copen with 'qftf'  6 times slower

512000 entries: 0.413 seconds to run :copen

                2.773 seconds to run :copen with 'qftf'  6 times slower

The results are clear, Vim9 helps a lot.

When it'll be ready, maybe the help at :h quickfix-window-function could include a Vim9 example:

vim9script

" create a quickfix list from v:oldfiles

setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f', 'quickfixtextfunc' : 'QfOldFiles'})

def g:QfOldFiles(info: dict<number>): list<string>

    " get information about a range of quickfix entries

    let items = getqflist({'id' : info.id, 'items' : 1}).items

    let l: list<string> = []

    for idx in range(info.start_idx - 1, info.end_idx - 1)

        " use the simplified file name

        add(l, bufname(items[idx].bufnr)->fnamemodify(':p:.'))

    endfor

    return l

enddef


You are receiving this because you commented.

lacygoill

unread,
Jul 11, 2020, 12:05:17 PM7/11/20
to vim/vim, vim-dev ML, Comment

@yegappan Do you think it would be possible for 'quickfixtextfunc' to be assigned a lambda, in addition to a function name?

I have currently set the option to a function which aligns the fields in the quickfix window; that's what I usually want. But it badly interferes with one of my plugins which assumes another specific formatting in the quickfix window. For the latter, I need to disable the feature; I can do it like so:

call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:disable_qftf'})
fu s:disable_qftf(info) abort
    return []
endfu

But it would be easier to read/write if I could use a lambda:

call setqflist([], ' ', { 'items': items, 'quickfixtextfunc': {-> []} })
                                                              ^-----^

Btw, returning an empty list makes Vim display the lines unchanged; this is very useful, but I don't think it's documented.

Yegappan Lakshmanan

unread,
Jul 11, 2020, 12:12:39 PM7/11/20
to vim_dev, reply+ACY5DGGIPA5E4SG2NS...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sat, Jul 11, 2020 at 9:05 AM lacygoill <vim-dev...@256bit.org> wrote:

@yegappan Do you think it would be possible for 'quickfixtextfunc' to be assigned a lambda, in addition to a function name?

I have currently set the option to a function which aligns the fields in the quickfix window; that's what I usually want. But it badly interferes with one of my plugins which assumes another specific formatting in the quickfix window. For the latter, I need to disable the feature; I can do it like so:

call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:disable_qftf'})
fu s:disable_qftf(info) abort
    return []
endfu

But it would be easier to read/write if I could use a lambda:

call setqflist([], ' ', { 'items': items, 'quickfixtextfunc': {-> []} })
                                                              ^-----^


I do have the changes that support using a lambda function for this. I have to fix some
issues in using it with the option setting. None of the Vim options currently support using
a lambda function.
 

Btw, returning an empty list makes Vim display the lines unchanged; this is very useful, but I don't think it's documented.


Yes. I will include the update to the help text in the next PR.

Thanks,
Yegappan
 

vim-dev ML

unread,
Jul 11, 2020, 12:12:55 PM7/11/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sat, Jul 11, 2020 at 9:05 AM lacygoill <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Do you think it would be possible

> for 'quickfixtextfunc' to be assigned a lambda, in addition to a function
> name?
>
> I have currently set the option to a function which aligns the fields in
> the quickfix window; that's what I usually want. But it badly interferes
> with one of my plugins which assumes another specific formatting in the
> quickfix window. For the latter, I need to disable the feature; I can do it
> like so:
>
> call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:disable_qftf'})
> fu s:disable_qftf(info) abort
> return []
> endfu
>
> But it would be easier to read/write if I could use a lambda:
>
> call setqflist([], ' ', { 'items': items, 'quickfixtextfunc': {-> []} })
> ^-----^
>
> ------------------------------

>
>
I do have the changes that support using a lambda function for this. I have
to fix some
issues in using it with the option setting. None of the Vim options
currently support using
a lambda function.


> Btw, returning an empty list makes Vim display the lines unchanged; this
> is very useful, but I don't think it's documented.
>

Yes. I will include the update to the help text in the next PR.

Thanks,
Yegappan


You are receiving this because you are subscribed to this thread.

bfrg

unread,
Jul 11, 2020, 12:54:29 PM7/11/20
to vim/vim, vim-dev ML, Comment

@yegappan Currently the quickfixtextfunc entry can be set in setqflist() but it can't be obtained from getqflist(). Imagine I filter a quickfix list that has a specific quickfixtextfunc. After filtering the list I need to reapply the same quickfixtextfunc. But there's no easy way to obtain it for the current list.

Another issue is that different quickfix formats might need different syntax files. When I permanently override the default quickfix format in my vimrc with set quickfixtextfunc=MyQuickfixTextFunc, I can simply also change the default syntax/qf.vim to my needs. But for locally specified quickfixtextfunc this is not easy. Maybe an additional entry 'filetype' could be specified in setqflist() as well as obtained from getqflist() in addition to the quickfixtextfunc?


You are receiving this because you commented.

lacygoill

unread,
Jul 11, 2020, 12:58:17 PM7/11/20
to vim/vim, vim-dev ML, Comment

Another issue is that different quickfix formats might need different syntax files. When I permanently override the default quickfix format in my vimrc with set quickfixtextfunc=MyQuickfixTextFunc, I can simply also change the default syntax/qf.vim to my needs. But for locally specified quickfixtextfunc this is not easy. Maybe an additional entry 'filetype' could be specified in setqflist() as well as obtained from getqflist() in addition to the quickfixtextfunc?

Would it help if the option became global-local instead of simply global?

bfrg

unread,
Jul 11, 2020, 1:12:23 PM7/11/20
to vim/vim, vim-dev ML, Comment

I don't think that's possible because the buffer displayed in the quickfix window is generated using the quickfixtextfunc with the given quickfix items. Once the buffer is generated the filetype plugin (currently qf.vim) is sourced.

lacygoill

unread,
Jul 12, 2020, 11:35:54 AM7/12/20
to vim/vim, vim-dev ML, Comment

Another thing which may need to be documented at :h quickfix-window-function, is the case of script local functions. You can write this:

let items = [{'filename': $VIMRUNTIME..'/doc/index.txt',
    \ 'lnum': 1124, 'valid': 1, 'text': 'You found it, Arthur!'}]
call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:func'})
"                                                             ^^
fu s:func(_)
    return []
endfu
cw

And it will work as expected. But if you close the quickfix window with :q, then reopen it with :cw, then E120 is raised:

E120: Using <SID> not in a script context: s:func

And if :cw is run from a function defined in another script:

nno cd :cw<cr>
fu Func()
    cw
endfu

Then E117 is raised:

Error detected while processing function Func:
line    1:
E117: Unknown function: s:func

I don't think it's a bug. It's probably just that the code which handles the 'quickfixtextfunc' property shares some code with the one handling the option. And in an option, you can't write s:. You need to translate the latter, with something like this:

fu s:sid() abort
    return matchstr(expand('<sfile>'), '.*\zs<SNR>\d\+_')
endfu
let s:sid = get(s:, 'sid', s:sid())

...

call setqflist([], ' ', {'items': items, 'quickfixtextfunc': s:sid .. 'func'})
                                                             ^------^

But it's a bit unexpected to see the code work initially, then fail on reopening the quickfix window:

This patch is an attempt at documenting the pitfall:

diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 293014b24..24402824a 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1989,5 +1989,19 @@ Example: >
 	return l
     endfunc
 <
+Note that if the function is local to a script, you need to translate `s:`
+manually for the code to work as expected after closing and reopening the
+quickfix window: >
+
+    func s:SID()
+        return matchstr(expand('<sfile>'), '.*\zs<SNR>\d\+_')
+    endfunc
+    let s:SID = s:SID()
+
+    call setqflist([], ' ', {'items': items, 'quickfixtextfunc': s:SID .. 'QfOldFiles'})
+    func s:QfOldFiles(info)
+        ...
+    endfunc
+<
 
  vim:tw=78:ts=8:noet:ft=help:norl:

bfrg

unread,
Jul 12, 2020, 11:45:52 AM7/12/20
to vim/vim, vim-dev ML, Comment

Why aren't you using a funcref?

call setqflist([], ' ', {'items': items, 'quickfixtextfunc': funcref('s:func')})

lacygoill

unread,
Jul 12, 2020, 11:51:26 AM7/12/20
to vim/vim, vim-dev ML, Comment

Ah, good idea; a funcref avoids the pitfall.

lacygoill

unread,
Jul 15, 2020, 10:00:29 PM7/15/20
to vim/vim, vim-dev ML, Comment

Actually no, you can't provide a funcref:

set qftf=GlobalOption

def GlobalOption(info: dict<number>): list<string>

    let qfl: list<any>

    qfl = getqflist(#{id: info.id, items: 0}).items

    
let l: list<string> = []

    for idx in range(info.start_idx - 1, info.end_idx - 1
)

        add(l, 'global option used')

    endfor

    return l

enddef

def QfAttribute(info: dict<number>): list<string>

    return []

enddef

call setqflist([], ' ', {'lines': v:oldfiles, 'efm': '%f', 'quickfixtextfunc': function('QfAttribute')})

cw

Which makes sense because – I guess – the implementation of the quickfix list attribute 'quickfixtextfunc' shares some code with the implementation of the global option. So you really have to manually translate the script local scope s:. Just like you would have for any '*func' option (e.g. 'operatorfunc', 'completefunc', ...) which expects a function name, and not a funcref.

bfrg

unread,
Jul 16, 2020, 5:27:19 AM7/16/20
to vim/vim, vim-dev ML, Comment

So it seems when 'qftf' is set the funcref is ignored, but when 'qftf' it not set to any function, the funcref works.

lacygoill

unread,
Jul 16, 2020, 8:07:46 AM7/16/20
to vim/vim, vim-dev ML, Comment

For me the funcref never works, even when 'qftf' is not set:

vim9script
def QfAttribute(info: dict<number>): list<string>
let l: list<string> = []
    for idx in range(info.start_idx - 1, info.end_idx - 1
)
        add(l, 'quickfix attribute used')
    endfor
    return l
enddef
setqflist([], ' ', {'lines': v:oldfiles, 'efm': '%f', 'quickfixtextfunc': function('QfAttribute')})
cw

Although, no error is raised which is why I first thought it was working. But it's really not; if it was, I would read the text quickfix attribute used on each line; instead, I can read the names of the files in v:oldfiles.

bfrg

unread,
Jul 16, 2020, 8:15:24 AM7/16/20
to vim/vim, vim-dev ML, Comment

Yes, you're right.

Yegappan Lakshmanan

unread,
Jul 20, 2020, 1:23:38 AM7/20/20
to vim_dev, reply+ACY5DGGIPA5E4SG2NS...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sat, Jul 11, 2020 at 9:05 AM lacygoill <vim-dev...@256bit.org> wrote:

@yegappan Do you think it would be possible for 'quickfixtextfunc' to be assigned a lambda, in addition to a function name?

I have currently set the option to a function which aligns the fields in the quickfix window; that's what I usually want. But it badly interferes with one of my plugins which assumes another specific formatting in the quickfix window. For the latter, I need to disable the feature; I can do it like so:

call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:disable_qftf'})
fu s:disable_qftf(info) abort
    return []
endfu

But it would be easier to read/write if I could use a lambda:

call setqflist([], ' ', { 'items': items, 'quickfixtextfunc': {-> []} })
                                                              ^-----^

Btw, returning an empty list makes Vim display the lines unchanged; this is very useful, but I don't think it's documented.



I have created PR #6499 to support using a lambda function for 'quickfixtextfunc'.


Can you try this out and let me know if you see any problems?

Thanks,
Yegappan

vim-dev ML

unread,
Jul 20, 2020, 1:23:56 AM7/20/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sat, Jul 11, 2020 at 9:05 AM lacygoill <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Do you think it would be possible

> for 'quickfixtextfunc' to be assigned a lambda, in addition to a function
> name?
>
> I have currently set the option to a function which aligns the fields in
> the quickfix window; that's what I usually want. But it badly interferes
> with one of my plugins which assumes another specific formatting in the
> quickfix window. For the latter, I need to disable the feature; I can do it
> like so:
>
> call setqflist([], ' ', {'items': items, 'quickfixtextfunc': 's:disable_qftf'})
> fu s:disable_qftf(info) abort
> return []
> endfu
>
> But it would be easier to read/write if I could use a lambda:
>
> call setqflist([], ' ', { 'items': items, 'quickfixtextfunc': {-> []} })
> ^-----^
>
> ------------------------------

>
> Btw, returning an empty list makes Vim display the lines unchanged; this
> is very useful, but I don't think it's documented.
>
>
>
I have created PR #6499 to support using a lambda function for
'quickfixtextfunc'.

https://github.com/vim/vim/pull/6499

Can you try this out and let me know if you see any problems?

Thanks,
Yegappan


You are receiving this because you are subscribed to this thread.

Yegappan Lakshmanan

unread,
Jul 20, 2020, 1:24:54 AM7/20/20
to vim_dev, reply+ACY5DGANIX3GUG453Z...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sat, Jul 11, 2020 at 9:54 AM bfrg <vim-dev...@256bit.org> wrote:

@yegappan Currently the quickfixtextfunc entry can be set in setqflist() but it can't be obtained from getqflist(). Imagine I filter a quickfix list that has a specific quickfixtextfunc. After filtering the list I need to reapply the same quickfixtextfunc. But there's no easy way to obtain it for the current list.



I have created PR #6499 to support this.


Regards,
Yegappan

vim-dev ML

unread,
Jul 20, 2020, 1:25:12 AM7/20/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sat, Jul 11, 2020 at 9:54 AM bfrg <vim-dev...@256bit.org> wrote:

> @yegappan <https://github.com/yegappan> Currently the quickfixtextfunc

> entry can be set in setqflist() but it can't be obtained from getqflist().
> Imagine I filter a quickfix list that has a specific quickfixtextfunc.
> After filtering the list I need to reapply the same quickfixtextfunc. But
> there's no easy way to obtain it for the current list.
>
>
>
I have created PR #6499 to support this.

https://github.com/vim/vim/pull/6499

Regards,
Yegappan
Reply all
Reply to author
Forward
0 new messages