Last active
April 11, 2023 00:03
-
-
Save yegappan/3b50ec9ea86ad4511d3a213ee39f1ee0 to your computer and use it in GitHub Desktop.
Updating a quickfix/location list asynchronously without interfering with another plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Vim has many plugins (vim-go, ale, etc.) that use the quickfix/location list | |
feature. Some of these plugins process the output of an external command and | |
update the quickfix list asynchronously as the output becomes available. | |
Updating a quickfix or location list asynchronously opens up the possibility | |
that two or more plugins may try to update the same quickfix list with | |
different output. Also when a plugin is updating a quickfix list in the | |
background, the user may issue a command that creates or updates a quickfix | |
list. The plugin may then incorrectly use this new list to add the entries. | |
The various Vim commands that create or modify a quickfix list (cfile, | |
cgetfile, caddfile, cbuffer, cgetbuffer, caddbuffer, cexpr, cgetexpr, | |
caddexpr, make, grep, grepadd, vimgrep and vimgrepadd) operate only on the | |
current quickfix list. A plugin using these commands to update the quickfix | |
list can interfere with another plugin. | |
To avoid these issues, the Vim functions getqflist() and setqflist() can be | |
used to operate on a specific list in the quickfix stack. Each list in the | |
quickfix stack has an unique identifier, which doesn't change within a Vim | |
session. A list in the stack can be specified using the quickfix identifier | |
when calling the getqflist() and setqflist() functions. So if a Vim plugin | |
uses the identifier to operate on a specific quickfix list then it can avoid | |
interfering with the operations of another plugin using another quickfix list. | |
The identifier of a quickfix list can be obtained using: | |
let qfid = getqflist({'id' : 0}).id | |
When adding new entries, the plugin can use setqflist() with this identifier: | |
call setqflist([], 'a', {'id' : qfid, 'items' : newitems}) | |
To parse the output of a command and add the quickfix entries, the plugin can | |
use the following: | |
call setqflist([], 'a', {'id' : qfid, 'lines' : cmdoutput}) | |
Note that in the previous command, the current 'errorformat' option setting is | |
used to parse the command output. This setting might have been changed either | |
by the user or by some other plugin to some other value. To parse the command | |
output using a specific 'errorformat' setting, the plugin can use: | |
call setqflist([], 'a', {'id' : qfid, 'lines' : cmdoutput, 'efm' : myefm}) | |
If more than 10 quickfix lists are added to the quickfix stack, then the | |
oldest quickfix list is removed from the stack. When a plugin is using a quickfix | |
list, if another plugin or user adds a new quickfix list to the stack, then there | |
is a possibility that the quickfix list that is in use is removed from the stack. | |
So the plugin should check whether the quickfix list it is using is still valid | |
using the following command: | |
if getqflist({'id' : qfid}).id == qfid | |
" List is still valid | |
endif | |
In summary, a plugin can use the following steps to asynchronously process | |
a command output and update a quickfix list: | |
1. Create an empty quickfix list: | |
call setqflist([], ' ', {'title' : 'Output from command abc'}) | |
2. Save the newly created quickfix list identifier: | |
let qfid = getqflist({'id' : 0}).id | |
3. Start a command in the background using job_start() | |
4. In the job callback function, check if the quickfix list is still present: | |
if getqflist({'id' : qfid}).id == qfid | |
" Still present | |
" Update the list | |
else | |
" List is removed. Stop the background job. | |
job_stop(....) | |
endif | |
5. Process the command output and update the quickfix list using one of the following calls: | |
call setqflist([], 'a', {'id' : qfid, 'lines' : cmdoutput, 'efm' : myefm}) | |
or | |
call setqflist([], 'a', {'id' : qfid, 'items' : newitems}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment