Invalid argument error when using a script in neovim (which does work with classical vim) - vim

I'm using the plugin vim-slime-cells with Vim 8.1, which does work nicely.
However, when I try to open Neovim v0.4.3 it complains about this function in particular:
function! slime_cells#select_current_cell(include_header=0) abort
let cell_delimiter = slime_cells#get_delimiter()
if cell_delimiter == ""
return
endif
let [line_ini, col_ini] = searchpos(cell_delimiter, 'bcnW')
let line_end = search(cell_delimiter, 'nW')
if !line_ini
let line_ini = 1
elseif !a:include_header
let line_ini = line_ini + 1
let col_ini = 1
end
" line before delimiter or bottom of file
let line_end = line_end ? line_end - 1 : line("$")
let col_end = strlen(getline(line_end))
call setpos("'<", [0, line_ini, col_ini, 0])
call setpos("'>", [0, line_end, col_end, 0])
normal! gv
let current_mode = mode()
if current_mode != "V"
normal! V
endif
endfunction
The error is exactly (sorry, in Spanish, but I think it can be understood OK):
Se ha detectado un error al procesar /home/navarro/.vim/bundle/vim-slime-cells/autoload/slime_cells.vim:
línea 13
E475: El argumento no es válido: include_header=0) abort
línea 16
E133: ":return" no está dentro de una función
línea 39
E193: ¡":endfunction" no está dentro de una función!
Is there anything in this function that makes it incompatible with Neovim? If so, how can I work around this?

Related

vim - folding with more than one marker

I have a debug file which looks like this:
==>func1:
.....
..
==>func2:
......
...
<==func2
..
<==func1
==>func3:
......
...
<==func3
Basically, I would like to be able to fold each one of the functions to eventually see something like this:
+-- x lines: ==> func1:
+-- x lines: ==> func3:
but still be able to expand func1 and see func2 folded:
==>func1:
.....
..
+-- x lines: ==> func2:
..
<==func1
is there any way to do so? thanks.
The unmatched markers need extra handle, here's an expr solution( see :h fold-expr):
setlocal foldmethod=expr
setlocal foldexpr=GetFoldlevel(v:lnum)
function GetFoldlevel(lnum)
let line = getline(a:lnum)
let ret = '='
if line[0:2] == '==>'
let name = matchstr(line, '^==>\zs\w*')
let has_match = HasMarkerMatch(a:lnum, name)
if has_match
let ret = 'a1'
endif
elseif line[0:2] == '<=='
let ret ='s1'
endif
return ret
endfunction
function HasMarkerMatch(lnum, name)
let endline = line('$')
let current = a:lnum + 1
let has_match = 0
while current <= endline
let line = getline(current)
if line =~ '^<=='.a:name
let has_match = 1
break
endif
let current += 1
endwhile
return has_match
endfunction

Get "usable" window width in vim script

How do I get the width of 3 (marked with green color in the image) in vim script?
If there is no signs column, and there are no other "special columns", I can get it with
winwidth(0) - (max([len(line('$')), &numberwidth-1]) + 1)
I think, you should be able to get that width using:
:set virtualedit=all
:norm! g$
:echo virtcol('.')
Alternatively, you could check, whether a signcolumn is present (e.g. using redir)
:redir =>a |exe "sil sign place buffer=".bufnr('')|redir end
:let signlist=split(a, '\n')
:let width=winwidth(0) - ((&number||&relativenumber) ? &numberwidth : 0) - &foldcolumn - (len(signlist) > 1 ? 2 : 0)
My ingo-library plugin has a ingo#window#dimensions#NetWindowWidth() function for that.
Answering because I can't comment yet:
Christian's answer gives the wrong result in the case that the actual number of lines in the file exceeds &numberwidth (because &numberwidth is just a minimum, as kshenoy pointed out). The fix is pretty simple, though, just take the max() of &numberwidth and the number of digits in the last line in the buffer (plus one to account for the padding vim adds):
redir =>a | exe "silent sign place buffer=".bufnr('') | redir end
let signlist = split(a, '\n')
let lineno_cols = max([&numberwidth, strlen(line('$')) + 1])
return winwidth(0)
\ - &foldcolumn
\ - ((&number || &relativenumber) ? lineno_cols : 0)
\ - (len(signlist) > 2 ? 2 : 0)
Kale's answer corrected one corner case where the number of lines is exceeding what &numberwidth can display. Here I fix another corner case where the signcolumn option is not set to auto
function! BufWidth()
let width = winwidth(0)
let numberwidth = max([&numberwidth, strlen(line('$'))+1])
let numwidth = (&number || &relativenumber)? numberwidth : 0
let foldwidth = &foldcolumn
if &signcolumn == 'yes'
let signwidth = 2
elseif &signcolumn == 'auto'
let signs = execute(printf('sign place buffer=%d', bufnr('')))
let signs = split(signs, "\n")
let signwidth = len(signs)>2? 2: 0
else
let signwidth = 0
endif
return width - numwidth - foldwidth - signwidth
endfunction
None of the above answers take into account the following points -
Plugins use sign-groups (if available), so simply running exe "silent sign place buffer=".bufnr('') does not show the sign's placed in the plugin's group
Neovim has support for variable signcolumn width
So this is the answer that finally set the ball rolling for me. Of course it is influenced by all of the above answers -
function! BufferWidth()
let width = winwidth(0)
let numberwidth = max([&numberwidth, strlen(line('$')) + 1])
let numwidth = (&number || &relativenumber) ? numberwidth : 0
let foldwidth = &foldcolumn
if &signcolumn == 'yes'
let signwidth = 2
elseif &signcolumn =~ 'yes'
let signwidth = &signcolumn
let signwidth = split(signwidth, ':')[1]
let signwidth *= 2 " each signcolumn is 2-char wide
elseif &signcolumn == 'auto'
let supports_sign_groups = has('nvim-0.4.2') || has('patch-8.1.614')
let signlist = execute(printf('sign place ' . (supports_sign_groups ? 'group=* ' : '') . 'buffer=%d', bufnr('')))
let signlist = split(signlist, "\n")
let signwidth = len(signlist) > 2 ? 2 : 0
elseif &signcolumn =~ 'auto'
let signwidth = 0
if len(sign_getplaced(bufnr(),{'group':'*'})[0].signs)
let signwidth = 0
for l:sign in sign_getplaced(bufnr(),{'group':'*'})[0].signs
let lnum = l:sign.lnum
let signs = len(sign_getplaced(bufnr(),{'group':'*', 'lnum':lnum})[0].signs)
let signwidth = (signs > signwidth ? signs : signwidth)
endfor
endif
let signwidth *= 2 " each signcolumn is 2-char wide
else
let signwidth = 0
endif
return width - numwidth - foldwidth - signwidth
endfunction
Starting from Vim 8.2.3627, getwininfo()'s output has a textoff containing the
number of columns occupied by any 'foldcolumn', 'signcolumn' and line number in front of the text
therefore subtracting that to the width entry, e.g. computing
getwininfo(win_getid()).width - getwininfo(win_getid()).textoff
should give the desired result.
Before textoff was available, it seems to me that the followinig computation does cut it:
let textoff = max([&numberwidth, (&number ? len(line('$')) + 1 : (&relativenumber ? winfo.height + 1 : 0))])
\ + &foldcolumn
\ + (empty(sign_getplaced(bufname(), {'group': '*'})[0].signs) ? 0 : 2)
I made use of both solutions in this plugin of mine for showing soft-wrapped lines.

Is there any way to make VIM fold one line more?

I am using an adaptation of the VIM folding settings published here and here. Now, notice the program below:
When folded on my VIM, it produces the following result:
I don't really like that look, I'd prefer the following:
Which I got by rewriting the code:
But leaving the code like that is horrible. Is it possible to update the VimScript so I get the folding I want, without having to leave the JavaScript code like that?
Here is my exact setting:
setlocal foldmethod=expr
setlocal foldexpr=GetPotionFold(v:lnum)
setlocal foldminlines=0
function! s:NextNonBlankLine(lnum)
let numlines = line('$')
let current = a:lnum + 1
while current <= numlines
if getline(current) =~? '\v\S'
return current
endif
let current += 1
endwhile
return -2
endfunction
function! s:IndentLevel(lnum)
return indent(a:lnum) / &shiftwidth
endfunction
function! GetPotionFold(lnum)
if getline(a:lnum) =~? '\v^\s*$'
return '-1'
endif
let this_indent = <SID>IndentLevel(a:lnum)
let next_indent = <SID>IndentLevel(<SID>NextNonBlankLine(a:lnum))
if next_indent == this_indent
return this_indent
elseif next_indent < this_indent
return this_indent
elseif next_indent > this_indent
return '>' . next_indent
endif
endfunction
function! NeatFoldText()
let line = getline(v:foldstart)
let lines_count = v:foldend - v:foldstart + 1
let lines_count_text = '| ' . printf("%10s", lines_count . ' lines') . ' |'
let foldchar = ' '
let foldtextstart = strpart(line, 0, (winwidth(0)*2)/3)
let foldtextend = lines_count_text . repeat(foldchar, 6)
let foldtextlength = strlen(substitute(foldtextstart . foldtextend, '.', 'x', 'g')) + &foldcolumn
return foldtextstart . repeat(foldchar, winwidth(0)-foldtextlength) . foldtextend
endfunction
set foldtext=NeatFoldText()
hi Folded ctermbg=255 ctermfg=21
hi FoldColumn ctermbg=white ctermfg=darkred
And here is the sample code:
function foo(x){
var y = x*x;
var z = y+y;
return z;
};
function bar(x){
var y = x*x;
var z = y+y;
return z;
};
function foobar(x){
var y = x*x;
var z = y+y;
return z;
};
function barfoo(x){
var y = x*x;
var z = y+y;
return z;
};
set foldmethod=marker
set foldmarker={,}
Should give you what you want.
You are using a fold expression that is (as far as I can see from a glance) designed for indent folding (used for HAML, Python, Haskell and other indent-syntax languages).
For C, you should just be using :set foldmethod=syntax.

is there a way on vim to show all column numbers in the current buffer line?

It would be very nice to have an option that would show all the column numbers of the current line or maybe of all the buffer, so I could know where exactly to navigate. Is there such an option or do i have to program it myself (nooo XD)?
:h 'statusline'
It is as easy as defining exactly what you what to see printed. e.g.
" RulerStr() comes from http://www.vanhemert.co.uk/vim/vimacros/ruler2.vim
function! RulerStr()
let columns = &columns
let inc = 0
let str = ""
while (inc < columns)
let inc10 = inc / 10 + 1
let buffer = "."
if (inc10 > 9)
let buffer = ""
endif
let str .= "....+..." . buffer . inc10
let inc += 10
endwhile
let str = strpart(str, 0, columns)
return str
endfunction
let s:saved_stl = {}
function! s:ToggleRuler()
let buf = bufnr('%')
if has_key(s:saved_stl, buf)
let &l:stl = s:saved_stl[buf]
unlet s:saved_stl[buf]
else
let s:saved_stl[buf] = &l:stl
setlocal stl=%{RulerStr()}
endif
endfunction
nnoremap <silent> µ :call <sid>ToggleRuler()<cr>
You can use "set ruler". It will show the line number and column position at the bottom.

Configuring variable-width tab spacing in Vim

I sometimes want Vim to read tab-formatted files where the most reasonable formatting implies a non-uniform tab width. In other words, I want a tab stop at positions:
5, 30, 50, 60, 70, 80
How can I do this in Vim?
If you don't actually need to change the tabstops and can get away with just inserting the correct number of spaces, I would suggest you script it. Here's a quick and dirty version that might do what you want:
let s:tabstops = [0, 5, 30, 50, 60, 70, 80]
fun! Find_next(pos)
if a:pos > min(s:tabstops) && a:pos < max(s:tabstops)
let my_count = 0
while my_count < len(s:tabstops) - 1
if a:pos > get(s:tabstops, my_count) && a:pos < get(s:tabstops, my_count+1)
return get(s:tabstops, my_count+1)
endif
let my_count = my_count + 1
endwhile
return -1
endif
return -1
endfun
fun! Tabbing()
let pos = col('.')
let next_stop = Find_next(pos)
let the_command = "normal i"
let my_count = 0
while my_count < next_stop - pos
let the_command = the_command . " "
let my_count = my_count + 1
endwhile
let the_command = the_command . ""
execute the_command
endfun
imap <TAB> j<ESC>:call Tabbing()<CR>lxi
Currently no. Not with any official builds.
However, if you're willing to invest a little effort on your side, I remember there was a patch for something like that. Check out vim's patches page.

Resources