https://github.com/vim/vim/pull/5465
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.![]()
Merging #5465 into master will decrease coverage by
<.01%.
The diff coverage is87.5%.
@@ 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.
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 ??
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 , 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:
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 ??
—
You are receiving this because you commented.
@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.
@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.
> @@ -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 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?
> @@ -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:
> @@ -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 commented on this pull request.
> @@ -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.
> @@ -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.
> @@ -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 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 commented on this pull request.
> @@ -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.
@wsdjeg commented on this pull request.
> +|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.
@wsdjeg commented on this pull request.
> +|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?
Merging #5465 into master will decrease coverage by
0.00%.
The diff coverage is98.91%.
@@ 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 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'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 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]
—
You are receiving this because you are subscribed to this thread.
@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 8On 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 slowerAs you can see, for a quickfix list with more than a thousand entries,
'quickfixtextfunc'makes:copenaround 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'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.
@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 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 [] endfuBut 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.
—
You are receiving this because you are subscribed to this thread.
@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.
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?
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.
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:
Why aren't you using a funcref?
call setqflist([], ' ', {'items': items, 'quickfixtextfunc': funcref('s:func')})
Ah, good idea; a funcref avoids the pitfall.
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')})
cwWhich 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.
So it seems when 'qftf' is set the funcref is ignored, but when 'qftf' it not set to any function, the funcref works.
For me the funcref never works, even when 'qftf' is not set:
vim9scriptdef 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.
Yes, you're right.
@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 [] endfuBut 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.
—
You are receiving this because you are subscribed to this thread.
@yegappan Currently the
quickfixtextfuncentry can be set insetqflist()but it can't be obtained fromgetqflist(). Imagine I filter a quickfix list that has a specificquickfixtextfunc. After filtering the list I need to reapply the samequickfixtextfunc. But there's no easy way to obtain it for the current list.