I am trying to debug the vim-fugitive plugin, to dig into how it works.

When I develop a piece of vim script, I am used to testing a function with the debug command. Here it does not work because the function I try to access is not in the current scope.

debug execute <SID>StageDiff('Gdiff')

But there is a mapping that call this function inside the plugin:

nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<CR>

So I tried

debug norm! D

But I get the following error (after a step):

E21: Cannot make changes, 'modifiable' is off

I guess it's because the context of the D is the debugger's window, so it's not modifiable.

My question is:

  • Do you know a way to debug an external function?
  • How can the debug norm! ... keep the focus on the current file, instead of jumping to the debug window? (see comments need to use norm)
  • 3
    With :norm! D you prevent the mapping to be triggered. Just use norm D – Luc Hermitte Apr 20 '16 at 14:41
  • So the context of the norm (and I guess every other command) is the file, and not the debug window ? – nobe4 Apr 20 '16 at 14:43
  • No. With the bang, you prevent the mapping to be executed, and in the end, the default behaviour will be triggered: d$. :h :normal – Luc Hermitte Apr 20 '16 at 15:39

Regarding the debugging of a script function, this is extremely tricky: you need to build the exact internal name of the function. Once you have that name you could use it to call the function.

Alas, it isn't that easy to obtain it.

  • First you need to know the related script number (:scriptnames may help),
  • then inject that number in a function name generator that'll generate the sequence <SNR>+thenumber+_+functionname that can be used with function().

My advice? Either debug these functions from the mapping they are meant to be executed from, or expose them through autoload plugins when you are their author.

  • Works great, maybe it should be put in a plugin to help the workflow. – nobe4 Apr 21 '16 at 10:09
  • In my snippets for mu-template, I have a function that I use to export internal functions. I also have code in lh-vim-lib where I can obtain a scriptname given a function name. scriptnames updating is lazily done: lh#askvim#scriptname(id) -- I use it in the logging sub-library. – Luc Hermitte Apr 21 '16 at 11:08
  • 1
    It is not that hard. You can do :breakadd func *funcname then execute your mapping and Vim will stop whenever it hits a function that matches the globbing pattern *funcname. – Christian Brabandt Jul 21 '16 at 19:27

This is not an answer to the question, as Luc Hermitte already answered it, but a development on his answer. I created a little piece of vimscript that try to generate the full name of a funciton:

function! s:GetFunctionFullName(plugin_name, function_name)
  let l:scriptnames = []

  " save previous content of register a
  let l:a = @a

  " capture the scriptname output in register a
  redir @a
  silent scriptnames
  redir END
  " split by new line
  let l:scriptnames = split(@a, '\n')

  " restore register a
  let @a = l:a

  " Filter the scriptnames with the plugin name / path
  call filter(l:scriptnames, 'v:val =~ "'.a:plugin_name.'"')

  " Accept only one answer
  if len(l:scriptnames) != 1
    echoerr("Please specify an existing unique filepath")
    echomsg("Your current result is:". l:scriptnames)

  " Get the script number
  let l:scriptnumber = substitute(
        \ split(l:scriptnames[0])[0],
        \  ':', '', '')

  " Return the function full name
  return '<SNR>'.l:scriptnumber.'_'.a:function_name.'()'

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.