3

I'm writing small liniting plugin and I want to show errors in the quickfix as soon as errorfile changes.

fu! OpenErrors(job_id, data, event)
    let l:winid = win_getid()
    let l:output = split(a:data[0])
    echom l:output[0] . l:output[2]
    let l:view = winsaveview()
    exe 'silent! cfile! ' . escape(l:output[0] . l:output[2], '%#/')
    call winrestview(l:view)
    if len(getqflist()) > 0
        copen
    else
        cclose
    endif
    call win_gotoid(l:winid)
endfu

The problems with this code is that it the cursor jumps to quickfix window and it's annoying when errorfile changes fast.

1

In Build-Tools-Wrapper, the callback receives the new line to display (as the job simply executes make (or equivalent) and doesn't play with any intermediary file), the line is processed with :caddexpr. If I'm supposed to be at the bottom I simply execute :cbottom -- moving the cursor (in the qf windows) changes that. These two commands don't change the current window I'm in.

Also when I start the compilation, I open the quickfix window without jumping to it. Actually, I jump to it in order to apply a few hooks (like syntax highlighting, concealment...) and eventually I jump back to the window I was in before starting the background compilation. Along the way I've an old trick able to detect if we need a qf window in other situations.

7
  • I'm doing this to display quickfix only if the output of a linter changed. This way If I want to ignore errors I just close quickfix and until output is changed it wouldn't be opened. I guess I could clean quickfix maybe and add to it line by line from a file, but this sounds stupid. Aug 8 '17 at 12:00
  • I can close the qf window while I compile and open it back when the job is finished. It's not incompatible. Aug 8 '17 at 12:38
  • I don't understand what you are talking about unfortunately. I want to open quickfix only if linter results changed. I also don't want my cursor to jump into quickfix window to show it. How can I achieve that? Aug 8 '17 at 13:45
  • When I compile something in the background. make is running and feeds its result back though job_start() callbacks. On each line fed back, I use caddexpr which doesn't trigger to qf-window to open. You can check it by yourself with :cclose + :caddexpr expand('%').":1: Error: test". This means that when I run :Make+:cclose, I can do my :COpen any time I want. Aug 8 '17 at 14:06
  • In your case, you can simply close the qf-window whenever you want, and force it to pop-open when there is something new to feed with :caddexpr. You'll want to do it with :cwindow I guess, or some other trick (see my code) that keep the cursor where it was. Aug 8 '17 at 14:06
1

Try this quickfix preview plugin: https://github.com/ronakg/quickr-preview.vim

enter image description here

1
  • Not sure how this should help me, but introducing dependency for my plugin isn't a good idea. Aug 8 '17 at 13:37
1

Here is what I ended up using to prevent the cursor from moving after executing copen:

function! OpenErrors(job_id, data, event)
    " Store the original window number
    let l:winnr = winnr()

    " Open a window to show the current list of errors

    " If focus changed, jump to the last window
    if l:winnr !=# winnr()
        wincmd p
    endif
endfunction

Also, the vim-qf plugin makes it easier to work with the location/quickfix list.

1
  • Well, that's the same as what I do with win_gotoid. Aug 20 '17 at 7:02
0

cwindow does your open/close behaviour but jumps to the quickfix if opening.

wincmd p jumps to the previous window (and should maintain the cursor position).

A simple method:

cclose | copen | wincmd p | cwindow

A modification of your code that probably works (untested):

fu! OpenErrors(job_id, data, event)
    let l:was_in_qf = &buftype == 'quickfix'
    let l:output = split(a:data[0])
    echom l:output[0] . l:output[2]
    exe 'silent! cgetfile! ' . escape(l:output[0] . l:output[2], '%#/')
    cwindow
    if !l:was_in_qf && &ft == 'qf'
        wincmd p
    endif
endfu
4
  • This introduces flickering, so the real answer is “You can’t” Jul 30 at 5:49
  • Do you still see flickering with set lazyredraw? For something like this, I'd turn that on at the top of a function and restore its value at the end.
    – idbrii
    Jul 30 at 18:37
  • That was a long time ago, but I think I’ve tried all the options and the flickering was still present, but it was bearable. What I was doing at the time is trying to updating quick fix windows in a background automatically after running linter. Jul 31 at 8:39
  • ale and asyncrun both update the quickfix in the background, but don't open it automatically. Since you don't know what the user could be doing when the timer fires (in the middle of typing a multi-key mapping or a : command), maybe it'd be better to separate updating from opening and open the window from a CursorHold or SafeState autocmd.
    – idbrii
    Aug 2 at 1:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.