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)
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)
&numberwidth
non-zero while no number column is being displayed. In the second snippet, one should probably replace &numberwidth
with something like ((&l:number || &l:relativenumber) ? &numberwidth : 0)
. –
Unaccomplished &numberwidth
is defined as the minimum number of columns to use for the line number. This means that this is useful only if line number < 1000. Or am I missing something here? –
Anfractuosity len(signs)
be 1
if the sign column is not present and 2
if it is? that would make the part len(signlist) > 1 ? 2 : 0
. At least that's the only thing that works for me. I'm running neovim-nightly v0.5.0-508-gc37d9fa3d, with ale. Redir returns ['--- Signs ---', 'Signs for file.py:']
when the signcolumn is present and only ['--- Signs ---']
when it isn't. On a side note, if/when I start using gitgutter with ale, how would I get the width of signcolumn if it increases beyond 2? –
Allot sign_getplaced()
to get the signs placed in a buffer. One does not need the redir anymore. I don't understand the comment about signcolumn increasing beyond 2, unless neovim changed that behaviour, the signcolumn can never have more than 2 columns –
Lusatia 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.
Based on the accepted answer (@Christian Brabandt), for Vims not having textoff
I came up with the following function, which I think is simple/reliable/safe enough despite temporarily messing up the window state a little bit:
" Returns the effective number of columns available for text editing
" in the current window.
"
" Apparently on Vim >= 8.2.3627 this should be equivalent:
"
" getwininfo(win_getid()).width - getwininfo(win_getid()).textoff
"
function! EffectiveWindowWidth()
let prev_ve = &virtualedit " Save current value of virtualedit
let &virtualedit = 'all' " Allow moving cursor beyond line end
let cur_pos = getpos('.') " Save current cursor position
" In case the cursor is on a wrapped line, go first to the first column,
" then go to last window column:
exec "norm! 0g$"
let width = virtcol('.') " Get the column number
call setpos('.', cur_pos) " Restore cursor position
let &virtualedit = prev_ve " Restore original value of virtualedit
return width
endfunction
© 2022 - 2024 — McMap. All rights reserved.
editareawidth()
. – Artificial