Add support for customizing the quickfix buffer contents#5465
Add support for customizing the quickfix buffer contents#5465yegappan wants to merge 1 commit intovim:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #5465 +/- ##
==========================================
+ Coverage 87.09% 87.10% +0.01%
==========================================
Files 142 142
Lines 156609 156651 +42
==========================================
+ Hits 136397 136450 +53
+ Misses 20212 20201 -11
Continue to review full report at Codecov.
|
|
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. |
|
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 ?? |
|
Hi,
On Sat, Jan 11, 2020 at 12:06 AM Linwei ***@***.***> 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
|
|
@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: 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: 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: After some so called clever conversion, it will look like this in quickfix: 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:
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 ?? |
|
Hi Bram,
On Fri, Jan 10, 2020 at 11:19 PM Bram Moolenaar ***@***.***> 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
|
|
Hi,
On Sat, Jan 11, 2020 at 10:08 PM Linwei ***@***.***> 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 ??
|
|
Yegappan wrote:
On Fri, Jan 10, 2020 at 11:19 PM Bram Moolenaar
***@***.***> 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".
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 -- Bram@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 ///
|
b741cf4 to
8a11149
Compare
afbb130 to
1da47ee
Compare
393f6b0 to
ce8c790
Compare
03c683c to
b567f1b
Compare
puremourning
left a comment
There was a problem hiding this comment.
Just reviewed the docs because i was curious about this feature. I sort of left feeling that i didn't really get it.
runtime/doc/quickfix.txt
Outdated
| 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 |
There was a problem hiding this comment.
what else would it be set to ? Presumably 0 for location list ?
There was a problem hiding this comment.
Yes. I will update the help text.
|
|
||
| The example below tries to mimic the default behavior for the quickfix | ||
| and location list windows. | ||
| Example: > |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
runtime/doc/quickfix.txt
Outdated
|
|
||
| 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: |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
runtime/doc/quickfix.txt
Outdated
|
|
||
| <filename>|<lnum> col <n>|<text> | ||
|
|
||
| This can be customized by setting the 'quickfixtextfunc' option to a Vim |
There was a problem hiding this comment.
worth introducing the "why" early - the what is fine, but not the why - e.g. what's a motivating use case for this ?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
533a173 to
c2d0622
Compare
| 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:.') |
There was a problem hiding this comment.
why only return the file name instead of whole line?
|
Hi,
On Thu, Apr 30, 2020 at 8:19 PM Wang Shidong ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In runtime/doc/quickfix.txt
<#5465 (comment)>:
> +|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
|
2802eb8 to
415e4d7
Compare
|
@yegappan Thank you for working on this feature. The more entries a quickfix list contains, the more costly the I tried to write what seems to be a simple function: And tested it with this command: On my machine, the test took about 2 minutes to complete. Here are the results: As you can see, for a quickfix list with more than a hundred thousand entries, 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 entries. They would be displayed as if the option was not set. |
|
I'm not sure if it works, but you could try defining QuickFixTextFunc() with :def. |
|
Hi,
On Sun, Jun 7, 2020 at 2:30 AM lacygoill ***@***.***> wrote:
@yegappan <https://github.com/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.
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.
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
|
|
Hi,
On Sun, Jun 7, 2020 at 2:30 AM lacygoill ***@***.***> wrote:
@yegappan <https://github.com/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.
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
|
|
Hi,
On Wed, Jun 10, 2020 at 8:22 AM Yegappan Lakshmanan <yegappanl@gmail.com>
wrote:
Hi,
On Sun, Jun 7, 2020 at 2:30 AM lacygoill ***@***.***>
wrote:
> @yegappan <https://github.com/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.
>
>
> 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.
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
|
|
Hi,
On Sun, Jun 7, 2020 at 2:30 AM lacygoill ***@***.***> wrote:
@yegappan <https://github.com/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:
#6234
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
|
So, I finally converted the code into Vim9 script, and it's indeed much quicker. 5 times quicker on average. Old code: Results from New code: Results from The results are clear, Vim9 helps a lot. When it'll be ready, maybe the help at |
|
@yegappan Do you think it would be possible for 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: But it would be easier to read/write if I could use a lambda: Btw, returning an empty list makes Vim display the lines unchanged; this is very useful, but I don't think it's documented. |
|
Hi,
On Sat, Jul 11, 2020 at 9:05 AM lacygoill ***@***.***> 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
|
|
@yegappan Currently the Another issue is that different quickfix formats might need different syntax files. When I permanently override the default quickfix format in my |
Would it help if the option became global-local instead of simply global? You could then set |
I don't think that's possible because the buffer displayed in the quickfix window is generated using the |
|
Another thing which may need to be documented at And it will work as expected. But if you close the quickfix window with And if Then I don't think it's a bug. It's probably just that the code which handles the 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: |
|
Why aren't you using a call setqflist([], ' ', {'items': items, 'quickfixtextfunc': funcref('s:func')})Just make sure the function is defined before the call to |
|
Ah, good idea; a funcref avoids the pitfall. |
|
Actually no, you can't provide a funcref: vim9script
set qftf=GlobalOption
def GlobalOption(info: dict<number>): list<string>
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
setqflist([], ' ', {'lines': v:oldfiles, 'efm': '%f', 'quickfixtextfunc': function('QfAttribute')})
cwWhich makes sense because – I guess – the implementation of the quickfix list attribute |
|
So it seems when |
|
For me the funcref never works, even when 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')})
cwAlthough, 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 |
|
Yes, you're right. |
|
Hi,
On Sat, Jul 11, 2020 at 9:05 AM lacygoill ***@***.***> 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.
|
|
Hi,
On Sat, Jul 11, 2020 at 9:54 AM bfrg ***@***.***> 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.
|
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06
…ow contents Problem: It is not possible to customize the quickfix window contents. Solution: Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465) vim/vim@858ba06




No description provided.