5

I've googled around but can't find anything about this.

There is a case: when I navigate deep down through large blocks of code in (for example) python, it would be useful to see which method, function, or loop I am currently in, when the start is not on screen (because it runs off the top of the screen).

So, consider such block of code:

def large_ugly_function():
    ... many lines of code ...
    for i in list_of_items:
        one_action(i)
        i.method()
        event_trigger()
        ... bla-bla-bla around 20-30 lines of code
        ... another for loop or function
        ... <current line>: screen goes down and I can't see the current line part of what loop 

So I need to see something like header of current fold in "sticky" way: while I navigate through code deep down. It can be written in status line or somewhere else. For this example for in status-line it would be something like:

large_ugly_function->[for i in list_of_items:]->[another for loop or function]

Does anybody know how it can be achieved? Maybe some extensions? How it can be googled?

UPDATE Just wrote this question and found close to what I need but not fully: https://stackoverflow.com/questions/13634826/vim-show-function-name-in-status-line

I want something closer to folding: so function or loop or other logical block of code

UPDATE 2 Also close to this thing can be achieved with TagBar status line integration.

  • 1
    This is not what you want but ?for<Esc> is a very quick and very cheap way to know where you are. – romainl Nov 22 '16 at 21:03
  • Thanks for reply! Well, it's quite interesting - try to use it. But really I want to find out this feature already implemented in status-line or something like it. I can't believe that there is no plugin which already do this. – pryg_skok Nov 23 '16 at 6:37
  • 1
    tagbar with airline does provide this. – Christian Brabandt Nov 23 '16 at 7:00
  • Could you please provide a config for this? Because the only way I see how TagBar can provide this is tagbar#currenttag function. And this is not what I need (but close as I wrote): it shows only the current function, and I'm talking about something like last fold level. – pryg_skok Nov 23 '16 at 7:34
  • @pryg_skok I know this is not what you want but maybe you could imagine a totally different way to do what you want: you could use 2 different splits :e foo.py, go to the line you want to keep, :sp to split your screen with the buffer at the same position in each split and then move only one split (make sure that scrollbind is off) – statox Nov 23 '16 at 8:59
6

So following the idea I suggested in comments here is what I've come up with:

First let's demonstrate it with a gif (I'm not sure why the cursor leaves this ugly mark):

enter image description here

The idea is to:

  • Set the foldmethod to indent because it works well with python. (But I guess using marker or manual would work too)
  • Open a split which will contain the "context information" i.e. the beginning of the fold the cursor is currently on.
  • Each time the cursor is moved, the upper split is updated to show the correct context information.

The code is in two parts, first the function:

function! PinFold()
    " save current position
    let saveCursor =  getcurpos()

    " Go to upper split, open all folds and go to the same line as bottom split
    wincmd k
    normal! zR
    execute "normal! " . saveCursor[1] . "G"
    " Go to the beginning of the fold and put the line top of the upper split
    normal! [zk
    normal! zt

    " Go back to bottom split and restore position
    wincmd j
    call setpos('.', saveCursor)
endfunction

It is pretty self-explained:

  • Save the position of the cursor
  • Go on the upper split, at the same line as the bottom split
  • Go to the beginning of the fold and put the line in the top of the split
  • Go back to bottom split

And to make it work automatically, an augroup:

augroup pythonFold
    autocmd BufReadPre *.py setlocal foldmethod=indent
    autocmd BufReadPost *.py wincmd k | resize 3 | wincmd j
    autocmd CursorMovedI *.py call PinFold()
    autocmd CursorMoved *.py call PinFold()
augroup END

It will set the correct foldmethod and open the upper split when opening a new python buffer. And then each time the cursor is moved in normal or in insert mode, the previous function is called.

Note The while process can probably be improved (better handling of already open buffer, multiple splits in a tab, etc) but this is left as an exercise to the reader ;-)


Related help topics:

  • Just small edit: to resize upper split you need to fix your command: autocmd BufReadPost *.py wincmd s | wincmd k | resize 3 | wincmd j – pryg_skok Nov 24 '16 at 8:17
  • Right, it's done. – statox Nov 24 '16 at 8:22
  • I've made small modifications on top of your idea to implement "intergration" :) with lightline here I've removed split and notice normal! [zkk -- it's still not perfect finding the beginning of fold and sometimes wrong detect it.Also double kk looks like hack. Do you know how it can be done better? – pryg_skok Nov 24 '16 at 9:23
  • @pryg_skok: Nice evolution. First I'd say that you can get rid of lines 13, 14 and 17. Then about [z, :h fold-commands seems to indicate that it is the way to go (kk should not be necessary) so if it doesn't work well maybe you can do something with a loop which will search the correct line based on the return of foldlevel() (See :h foldlevel()) – statox Nov 24 '16 at 9:35

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.