Compare commits

...

14 Commits

Author SHA1 Message Date
Jaehwang Jung d0926e66a8
Merge 823b639a34 into 435dee74bb 2024-04-27 13:44:26 +09:00
zeertzjq 435dee74bb
vim-patch:9.1.0374: wrong botline in BufEnter (#28530)
Problem:  When :edit an existing buffer, line('w$') may return a
          wrong result.
Solution: Reset w_valid in curwin_init() (Jaehwang Jung)

`do_ecmd()` reinitializes the current window (`curwin_init()`) whose
`w_valid` field may have `VALID_BOTLINE` set. Resetting `w_botline`
without marking it as invalid makes subsequent `validate_botline()`
calls a no-op, thus resulting in wrong `line('w$')` value.

closes: vim/vim#14642

eb80b8304e

Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
2024-04-27 06:32:25 +08:00
zeertzjq 694756252b
Merge pull request #28529 from zeertzjq/vim-fe1e2b5e2d65
vim-patch: clarify syntax vs matching mechanism
2024-04-27 06:31:55 +08:00
zeertzjq e81eb34aa1 vim-patch:9525f6213604
runtime(doc): fix typo synconcealend -> synconcealed (vim/vim#14644)

9525f62136

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
2024-04-27 05:52:47 +08:00
zeertzjq a1568f5df0 vim-patch:00ae5c5cba7b
runtime(doc): fix typo

00ae5c5cba

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-04-27 05:52:15 +08:00
zeertzjq f1f5fb911b vim-patch:fe1e2b5e2d65
runtime(doc): clarify syntax vs matching mechanism

fixes: vim/vim#14643

fe1e2b5e2d

Co-authored-by: Christian Brabandt <cb@256bit.org>
2024-04-27 05:51:52 +08:00
Mathias Fußenegger 9b8a075539
fix(lsp): change `silent` in lsp.start.Opts to optional (#28524) 2024-04-26 20:26:21 +02:00
Gregory Anders 73034611c2
feat(diagnostic): add default mappings for diagnostics (#16230) 2024-04-26 13:16:12 -05:00
Brian Cao 3a7c30dc93
fix(man.vim): q quits after jump to different tag in MANPAGER modified (#28495) 2024-04-26 13:14:45 -05:00
Gregory Anders 6888607415
feat(lsp): add more LSP defaults (#28500)
- crn for rename
- crr for code actions
- gr for references
- <C-S> (in Insert mode) for signature help
2024-04-26 11:12:49 -05:00
Justin M. Keyes 9b028bd64f
refactor(vim.iter)!: rename xxback() => rxx() #28503
Problem:
vim.iter has both `rfind()` and various `*back()` methods, which work
in "reverse" or "backwards" order. It's inconsistent to have both kinds
of names, and "back" is fairly uncommon (rust) compared to python
(rfind, rstrip, rsplit, …).

Solution:
- Remove `nthback()` and let `nth()` take a negative index.
  - Because `rnth()` looks pretty obscure, and because it's intuitive
    for a function named `nth()` to take negative indexes.
- Rename `xxback()` methods to `rxx()`.
  - This informally groups the "list-iterator" functions under a common
    `r` prefix, which helps discoverability.
- Rename `peekback()` to `pop()`, in duality with the existing `peek`.
2024-04-26 08:43:29 -07:00
Lewis Russell b2c26a875b fix(lsp): ensure buffer is not attached more than once
Fixes regression introduced in #28030

If an LSP server is restarted, then the associated `nvim_buf_attach`
call will not detach if no buffer changes are sent between the client
stopping and a new one being created. This leads to `nvim_buf_attach`
being called multiple times for the same buffer, which then leads to
changetracking sending duplicate requests to the server (one per
attach).

To solve this, introduce separate tracking (client agnostic) on which
buffers have had calls to `nvim_buf_attach`.
2024-04-26 16:21:37 +01:00
Jaehwang Jung 823b639a34 fix(treesitter): clip end row early
Problem:
UINT32_MAX + 1 passed to vim._foldupdate.

Solution:
Clip the end row from treesitter asap to avoid such issues.
2024-04-23 01:40:18 +09:00
Jaehwang Jung 1590e21e9c refactor(fold): avoid coverity false-positive
Also add some more argument checks.
2024-04-23 00:36:37 +09:00
24 changed files with 572 additions and 449 deletions

View File

@ -8208,6 +8208,10 @@ synconcealed({lnum}, {col}) *synconcealed()*
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
Note: Doesn't consider |matchadd()| highlighting items,
since syntax and matching highlighting are two different
mechanisms |syntax-vs-match|.
synstack({lnum}, {col}) *synstack()*
Return a |List|, which is the stack of syntax items at the
position {lnum} and {col} in the current window. {lnum} is

View File

@ -281,6 +281,10 @@ gr{char} Replace the virtual characters under the cursor with
that have a special meaning in Insert mode, such as
most CTRL-keys, cannot be used.
*gr-default*
Mapped to |vim.lsp.buf.references()| by default.
|default-mappings|
*digraph-arg*
The argument for Normal mode commands like |r| and |t| is a single character.
When 'cpo' doesn't contain the 'D' flag, this character can also be entered

View File

@ -61,47 +61,41 @@ options are not restored when the LSP client is stopped or detached.
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
a custom keymap for `K` exists.
*crr* *v_crr* *crn* *i_CTRL-S*
Some keymaps are created unconditionally when Nvim starts:
- "crn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "crr" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "gr" is mapped in Normal mode to |vim.lsp.buf.references()| |gr-default|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
If not wanted, these keymaps can be removed at any time using
|vim.keymap.del()| or |:unmap|.
*lsp-defaults-disable*
To override the above defaults, set or unset the options on |LspAttach|: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
vim.bo[ev.buf].formatexpr = nil
vim.bo[ev.buf].omnifunc = nil
vim.keymap.del("n", "K", { buffer = ev.buf })
vim.keymap.del('n', 'K', { buffer = ev.buf })
end,
})
To use other LSP features like hover, rename, etc. you can set other keymaps
on |LspAttach|. Example: >lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = args.buf })
end,
})
To use other LSP features, set keymaps on |LspAttach|. Not all language
servers provide the same capabilities. To ensure you only set keymaps if the
language server supports a feature, guard keymaps behind capability checks.
Example: >lua
The most common functions are:
- |vim.lsp.buf.hover()|
- |vim.lsp.buf.format()|
- |vim.lsp.buf.references()|
- |vim.lsp.buf.implementation()|
- |vim.lsp.buf.code_action()|
Not all language servers provide the same capabilities. To ensure you only set
keymaps if the language server supports a feature, you can guard the keymap
calls behind capability checks:
>lua
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client.server_capabilities.hoverProvider then
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = args.buf })
if client.supports_method('textDocument/implementation') then
vim.keymap.set('n', 'g<C-I>', vim.lsp.buf.implementation, { buffer = args.buf })
end
end,
})
<
To learn what capabilities are available you can run the following command in
a buffer with a started LSP client: >vim
@ -875,7 +869,7 @@ start({config}, {opts}) *vim.lsp.start()*
re-uses a client if name and root_dir matches.
• {bufnr} (`integer`) Buffer handle to attach to if starting
or re-using a client (0 for current).
• {silent} (`boolean`) Suppress error reporting if the LSP
• {silent}? (`boolean`) Suppress error reporting if the LSP
server fails to start (default false).
Return: ~

View File

@ -4053,6 +4053,9 @@ Iter:last() *Iter:last()*
Return: ~
(`any`)
See also: ~
• Iter.rpeek
Iter:map({f}) *Iter:map()*
Maps the items of an iterator pipeline to the values returned by `f`.
@ -4094,53 +4097,28 @@ Iter:next() *Iter:next()*
Return: ~
(`any`)
Iter:nextback() *Iter:nextback()*
"Pops" a value from a |list-iterator| (gets the last value and decrements
the tail).
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:nextback()
-- 4
it:nextback()
-- 3
<
Return: ~
(`any`)
Iter:nth({n}) *Iter:nth()*
Gets the nth value of an iterator (and advances to it).
Example: >lua
If `n` is negative, offsets from the end of a |list-iterator|.
Example: >lua
local it = vim.iter({ 3, 6, 9, 12 })
it:nth(2)
-- 6
it:nth(2)
-- 12
<
Parameters: ~
• {n} (`number`) The index of the value to return.
Return: ~
(`any`)
Iter:nthback({n}) *Iter:nthback()*
Gets the nth value from the end of a |list-iterator| (and advances to it).
Example: >lua
local it = vim.iter({ 3, 6, 9, 12 })
it:nthback(2)
local it2 = vim.iter({ 3, 6, 9, 12 })
it2:nth(-2)
-- 9
it:nthback(2)
it2:nth(-2)
-- 3
<
Parameters: ~
• {n} (`number`) The index of the value to return.
• {n} (`number`) Index of the value to return. May be negative if the
source is a |list-iterator|.
Return: ~
(`any`)
@ -4162,19 +4140,16 @@ Iter:peek() *Iter:peek()*
Return: ~
(`any`)
Iter:peekback() *Iter:peekback()*
Gets the last value of a |list-iterator| without consuming it.
See also |Iter:last()|.
Iter:pop() *Iter:pop()*
"Pops" a value from a |list-iterator| (gets the last value and decrements
the tail).
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:peekback()
-- 4
it:peekback()
-- 4
it:nextback()
it:pop()
-- 4
it:pop()
-- 3
<
Return: ~
@ -4194,8 +4169,8 @@ Iter:rev() *Iter:rev()*
(`Iter`)
Iter:rfind({f}) *Iter:rfind()*
Gets the first value in a |list-iterator| that satisfies a predicate,
starting from the end.
Gets the first value satisfying a predicate, from the end of a
|list-iterator|.
Advances the iterator. Returns nil and drains the iterator if no value is
found.
@ -4218,6 +4193,42 @@ Iter:rfind({f}) *Iter:rfind()*
See also: ~
• Iter.find
Iter:rpeek() *Iter:rpeek()*
Gets the last value of a |list-iterator| without consuming it.
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:rpeek()
-- 4
it:rpeek()
-- 4
it:pop()
-- 4
<
Return: ~
(`any`)
See also: ~
• Iter.last
Iter:rskip({n}) *Iter:rskip()*
Discards `n` values from the end of a |list-iterator| pipeline.
Example: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
it:next()
-- 1
it:pop()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:skip({n}) *Iter:skip()*
Skips `n` values of an iterator pipeline.
@ -4234,27 +4245,10 @@ Iter:skip({n}) *Iter:skip()*
Return: ~
(`Iter`)
Iter:skipback({n}) *Iter:skipback()*
Skips `n` values backwards from the end of a |list-iterator| pipeline.
Example: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
it:next()
-- 1
it:nextback()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:slice({first}, {last}) *Iter:slice()*
Sets the start and end of a |list-iterator| pipeline.
Equivalent to `:skip(first - 1):skipback(len - last + 1)`.
Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
Parameters: ~
• {first} (`number`)

View File

@ -159,6 +159,14 @@ unreleased features on Nvim HEAD.
• Changed |vim.ui.open()| return-signature to match pcall() convention.
• Renamed Iter:nextback() to Iter:pop()
• Renamed Iter:peekback() to Iter:rpeek()
• Renamed Iter:skipback() to Iter:rskip()
• Removed Iter:nthback(), use Iter:nth() with negative index instead.
==============================================================================
NEW FEATURES *news-features*
@ -400,6 +408,14 @@ The following changes to existing APIs or features add new behavior.
• 'comments' includes "fb:•".
• 'shortmess' includes the "C" flag.
• 'grepprg' defaults to using ripgrep if available.
• |crn| in Normal mode maps to |vim.lsp.buf.rename()|.
• |crr| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|.
• "gr" in Normal mode maps to |vim.lsp.buf.references()| |gr-default|
• |i_CTRL-S| in Insert mode maps to |vim.lsp.buf.signature_help()|
• "]d" and "[d" in Normal mode map to |vim.diagnostic.goto_next()| and
|vim.diagnostic.goto_prev()|, respectively. |]d-default| |[d-default|
• <C-W>d (and <C-W><C-D>) map to |vim.diagnostic.open_float()|
|CTRL-W_d-default|
• Automatic linting of treesitter query files (see |ft-query-plugin|).
Can be disabled via: >lua
vim.g.query_lint_on = {}
@ -430,9 +446,10 @@ The following changes to existing APIs or features add new behavior.
:call netrw#BrowseX(expand(exists("g:netrw_gx")? g:netrw_gx : '<cfile>'), netrw#CheckIfRemote())<CR>
• |vim.lsp.start()| now maps |K| to use |vim.lsp.buf.hover()| if the server
supports it, unless |'keywordprg'| was customized before calling
|vim.lsp.start()|.
• |vim.lsp.start()| now creates the following default keymaps (assuming the
server supports the feature):
- |K| in Normal mode maps to |vim.lsp.buf.hover()|, unless |'keywordprg'|
was customized before calling |vim.lsp.start()|.
• Terminal buffers started with no arguments (and use 'shell') close
automatically if the job exited without error, eliminating the (often

View File

@ -1375,6 +1375,19 @@ Finally, these constructs are unique to Perl:
==============================================================================
10. Highlighting matches *match-highlight*
*syntax-vs-match*
Note that the match highlight mechanism is independent
of |syntax-highlighting|, which is (usually) a buffer-local
highlighting, while matching is window-local, both methods
can be freely mixed. Match highlighting functions give you
a bit more flexibility in when and how to apply, but are
typically only used for temporary highlighting, without strict
rules. Both methods can be used to conceal text.
Thus the matching functions like |matchadd()| won't consider
syntax rules and functions like |synconcealed()| and the
other way around.
*:mat* *:match*
:mat[ch] {group} /{pattern}/
Define a pattern to highlight in the current window. It will

View File

@ -3825,7 +3825,9 @@ Whether or not it is actually concealed depends on the value of the
'conceallevel' option. The 'concealcursor' option is used to decide whether
concealable items in the current line are displayed unconcealed to be able to
edit the line.
Another way to conceal text is with |matchadd()|.
Another way to conceal text is with |matchadd()|, but internally this works a
bit differently |syntax-vs-match|.
concealends *:syn-concealends*
@ -3833,7 +3835,9 @@ When the "concealends" argument is given, the start and end matches of
the region, but not the contents of the region, are marked as concealable.
Whether or not they are actually concealed depends on the setting on the
'conceallevel' option. The ends of a region can only be concealed separately
in this way when they have their own highlighting via "matchgroup"
in this way when they have their own highlighting via "matchgroup". The
|synconcealed()| function can be used to retrieve information about conealed
items.
cchar *:syn-cchar*
*E844*

View File

@ -780,9 +780,17 @@ CTRL-W i Open a new window, with the cursor on the first line
beginning of the file. If a count is given, the
count'th matching line is displayed.
*[d-default*
Mapped to |vim.diagnostic.goto_prev()| by default.
|default-mappings|
*]d*
]d like "[d", but start at the current cursor position.
*]d-default*
Mapped to |vim.diagnostic.goto_next()| by default.
|default-mappings|
*:ds* *:dsearch*
:[range]ds[earch][!] [count] [/]string[/]
Like "[d" and "]d", but search in [range] lines
@ -829,6 +837,10 @@ CTRL-W d Open a new window, with the cursor on the first
beginning of the file. If a count is given, the
count'th matching line is jumped to.
*CTRL-W_d-default*
Mapped to |vim.diagnostic.open_float()| by default.
|default-mappings|
*:dsp* *:dsplit*
:[range]dsp[lit][!] [count] [/]string[/]
Like "CTRL-W d", but search in [range] lines

View File

@ -948,7 +948,7 @@ Syntax and highlighting: *syntax-functions* *highlighting-functions*
synIDattr() get a specific attribute of a syntax ID
synIDtrans() get translated syntax ID
synstack() get list of syntax IDs at a specific position
synconcealed() get info about concealing
synconcealed() get info about (syntax) concealing
diff_hlID() get highlight ID for diff mode at a position
matchadd() define a pattern to highlight (a "match")
matchaddpos() define a list of positions to highlight

View File

@ -137,6 +137,13 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
- * |v_star-default|
- gc |gc-default| |v_gc-default| |o_gc-default|
- gcc |gcc-default|
- |crn|
- |crr|
- gr |gr-default|
- <C-S> |i_CTRL-S|
- ]d |]d-default|
- [d |[d-default|
- <C-W>d |CTRL-W_d-default|
- Nvim LSP client defaults |lsp-defaults|
- K |K-lsp-default|

View File

@ -24,7 +24,7 @@ if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
nnoremap <silent> <buffer> k gk
nnoremap <silent> <buffer> gO :lua require'man'.show_toc()<CR>
nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR>
if get(b:, 'pager')
if get(g:, 'pager')
nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>q
else
nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c

View File

@ -411,15 +411,13 @@ local function find_man()
return false
end
---@param pager boolean
local function set_options(pager)
local function set_options()
vim.bo.swapfile = false
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'unload'
vim.bo.modified = false
vim.bo.readonly = true
vim.bo.modifiable = false
vim.b.pager = pager
vim.bo.filetype = 'man'
end
@ -475,7 +473,7 @@ local function put_page(page)
vim.cmd([[silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g]])
vim.cmd('1') -- Move cursor to first line
highlight_man_page()
set_options(false)
set_options()
end
local function format_candidate(path, psect)
@ -662,7 +660,8 @@ function M.init_pager()
vim.cmd.file({ 'man://' .. fn.fnameescape(ref):lower(), mods = { silent = true } })
end
set_options(true)
vim.g.pager = true
set_options()
end
---@param count integer
@ -730,7 +729,7 @@ function M.open_page(count, smods, args)
if not ok then
error(ret)
else
set_options(false)
set_options()
end
vim.b.man_sect = sect

View File

@ -127,7 +127,9 @@ do
end, { desc = gx_desc })
end
--- Default maps for built-in commenting
--- Default maps for built-in commenting.
---
--- See |gc-default| and |gcc-default|.
do
local operator_rhs = function()
return require('vim._comment').operator()
@ -144,6 +146,60 @@ do
end
vim.keymap.set({ 'o' }, 'gc', textobject_rhs, { desc = 'Comment textobject' })
end
--- Default maps for LSP functions.
---
--- These are mapped unconditionally to avoid confusion. If no server is attached, or if a server
--- does not support a capability, an error message is displayed rather than exhibiting different
--- behavior.
---
--- See |gr-default|, |crn|, |crr|, |i_CTRL-S|.
do
vim.keymap.set('n', 'crn', function()
vim.lsp.buf.rename()
end, { desc = 'vim.lsp.buf.rename()' })
vim.keymap.set({ 'n', 'v' }, 'crr', function()
vim.lsp.buf.code_action()
end, { desc = 'vim.lsp.buf.code_action()' })
vim.keymap.set('n', 'gr', function()
vim.lsp.buf.references()
end, { desc = 'vim.lsp.buf.references()' })
vim.keymap.set('i', '<C-S>', function()
vim.lsp.buf.signature_help()
end, { desc = 'vim.lsp.buf.signature_help()' })
end
--- Map [d and ]d to move to the previous/next diagnostic. Map <C-W>d to open a floating window
--- for the diagnostic under the cursor.
---
--- See |[d-default|, |]d-default|, and |CTRL-W_d-default|.
do
vim.keymap.set('n', ']d', function()
vim.diagnostic.goto_next({ float = false })
end, {
desc = 'Jump to the next diagnostic with the highest severity',
})
vim.keymap.set('n', '[d', function()
vim.diagnostic.goto_prev({ float = false })
end, {
desc = 'Jump to the previous diagnostic with the highest severity',
})
vim.keymap.set('n', '<C-W>d', function()
vim.diagnostic.open_float({ border = 'rounded' })
end, {
desc = 'Open a floating window showing diagnostics under the cursor',
})
vim.keymap.set('n', '<C-W><C-D>', '<C-W>d', {
remap = true,
desc = 'Open a floating window showing diagnostics under the cursor',
})
end
end
--- Default menus
@ -243,230 +299,140 @@ do
vim.notify(('W325: Ignoring swapfile from Nvim process %d'):format(info.pid))
end,
})
end
-- Only do the following when the TUI is attached
local tty = nil
for _, ui in ipairs(vim.api.nvim_list_uis()) do
if ui.chan == 1 and ui.stdout_tty then
tty = ui
break
end
end
if tty then
local group = vim.api.nvim_create_augroup('nvim_tty', {})
--- Set an option after startup (so that OptionSet is fired), but only if not
--- already set by the user.
---
--- @param option string Option name
--- @param value any Option value
local function setoption(option, value)
if vim.api.nvim_get_option_info2(option, {}).was_set then
-- Don't do anything if option is already set
return
end
-- Wait until Nvim is finished starting to set the option to ensure the
-- OptionSet event fires.
if vim.v.vim_did_enter == 1 then
--- @diagnostic disable-next-line:no-unknown
vim.o[option] = value
else
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
once = true,
nested = true,
callback = function()
setoption(option, value)
end,
})
-- Only do the following when the TUI is attached
local tty = nil
for _, ui in ipairs(vim.api.nvim_list_uis()) do
if ui.chan == 1 and ui.stdout_tty then
tty = ui
break
end
end
--- Guess value of 'background' based on terminal color.
---
--- We write Operating System Command (OSC) 11 to the terminal to request the
--- terminal's background color. We then wait for a response. If the response
--- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
--- compute the luminance[1] of the RGB color and classify it as light/dark
--- accordingly. Note that the color components may have anywhere from one to
--- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
--- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
--- ignored in the calculations.
---
--- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
do
--- Parse a string of hex characters as a color.
if tty then
local group = vim.api.nvim_create_augroup('nvim_tty', {})
--- Set an option after startup (so that OptionSet is fired), but only if not
--- already set by the user.
---
--- The string can contain 1 to 4 hex characters. The returned value is
--- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
---
--- For instance, if only a single hex char "a" is used, then this function
--- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
--- 256).
---
--- @param c string Color as a string of hex chars
--- @return number? Intensity of the color
local function parsecolor(c)
if #c == 0 or #c > 4 then
return nil
--- @param option string Option name
--- @param value any Option value
local function setoption(option, value)
if vim.api.nvim_get_option_info2(option, {}).was_set then
-- Don't do anything if option is already set
return
end
local val = tonumber(c, 16)
if not val then
return nil
-- Wait until Nvim is finished starting to set the option to ensure the
-- OptionSet event fires.
if vim.v.vim_did_enter == 1 then
--- @diagnostic disable-next-line:no-unknown
vim.o[option] = value
else
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
once = true,
nested = true,
callback = function()
setoption(option, value)
end,
})
end
local max = tonumber(string.rep('f', #c), 16)
return val / max
end
--- Parse an OSC 11 response
--- Guess value of 'background' based on terminal color.
---
--- Either of the two formats below are accepted:
--- We write Operating System Command (OSC) 11 to the terminal to request the
--- terminal's background color. We then wait for a response. If the response
--- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
--- compute the luminance[1] of the RGB color and classify it as light/dark
--- accordingly. Note that the color components may have anywhere from one to
--- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
--- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
--- ignored in the calculations.
---
--- OSC 11 ; rgb:<red>/<green>/<blue>
---
--- or
---
--- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
---
--- where
---
--- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
---
--- The alpha component is ignored, if present.
---
--- @param resp string OSC 11 response
--- @return string? Red component
--- @return string? Green component
--- @return string? Blue component
local function parseosc11(resp)
local r, g, b
r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
if not r and not g and not b then
local a
r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
if not a or #a > 4 then
return nil, nil, nil
--- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
do
--- Parse a string of hex characters as a color.
---
--- The string can contain 1 to 4 hex characters. The returned value is
--- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
---
--- For instance, if only a single hex char "a" is used, then this function
--- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
--- 256).
---
--- @param c string Color as a string of hex chars
--- @return number? Intensity of the color
local function parsecolor(c)
if #c == 0 or #c > 4 then
return nil
end
local val = tonumber(c, 16)
if not val then
return nil
end
local max = tonumber(string.rep('f', #c), 16)
return val / max
end
if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
return r, g, b
end
return nil, nil, nil
end
local timer = assert(vim.uv.new_timer())
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local r, g, b = parseosc11(resp)
if r and g and b then
local rr = parsecolor(r)
local gg = parsecolor(g)
local bb = parsecolor(b)
if rr and gg and bb then
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
local bg = luminance < 0.5 and 'dark' or 'light'
setoption('background', bg)
--- Parse an OSC 11 response
---
--- Either of the two formats below are accepted:
---
--- OSC 11 ; rgb:<red>/<green>/<blue>
---
--- or
---
--- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
---
--- where
---
--- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
---
--- The alpha component is ignored, if present.
---
--- @param resp string OSC 11 response
--- @return string? Red component
--- @return string? Green component
--- @return string? Blue component
local function parseosc11(resp)
local r, g, b
r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
if not r and not g and not b then
local a
r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
if not a or #a > 4 then
return nil, nil, nil
end
return true
end
end,
})
io.stdout:write('\027]11;?\007')
if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
return r, g, b
end
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
vim.schedule(function()
-- Suppress error if autocommand has already been deleted
pcall(vim.api.nvim_del_autocmd, id)
end)
if not timer:is_closing() then
timer:close()
return nil, nil, nil
end
end)
end
--- If the TUI (term_has_truecolor) was able to determine that the host
--- terminal supports truecolor, enable 'termguicolors'. Otherwise, query the
--- terminal (using both XTGETTCAP and SGR + DECRQSS). If the terminal's
--- response indicates that it does support truecolor enable 'termguicolors',
--- but only if the user has not already disabled it.
do
if tty.rgb then
-- The TUI was able to determine truecolor support
setoption('termguicolors', true)
else
local caps = {} ---@type table<string, boolean>
require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
if not found then
return
end
caps[cap] = true
if caps.Tc or caps.RGB or (caps.setrgbf and caps.setrgbb) then
setoption('termguicolors', true)
end
end)
local timer = assert(vim.uv.new_timer())
-- Arbitrary colors to set in the SGR sequence
local r = 1
local g = 2
local b = 3
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
local r, g, b = parseosc11(resp)
if r and g and b then
local rr = parsecolor(r)
local gg = parsecolor(g)
local bb = parsecolor(b)
if decrqss then
-- The DECRQSS SGR response first contains attributes separated by
-- semicolons, followed by the SGR itself with parameters separated
-- by colons. Some terminals include "0" in the attribute list
-- unconditionally; others do not. Our SGR sequence did not set any
-- attributes, so there should be no attributes in the list.
local attrs = vim.split(decrqss, ';')
if #attrs ~= 1 and (#attrs ~= 2 or attrs[1] ~= '0') then
return false
end
-- The returned SGR sequence should begin with 48:2
local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$')
if not sgr then
return false
end
-- The remaining elements of the SGR sequence should be the 3 colors
-- we set. Some terminals also include an additional parameter
-- (which can even be empty!), so handle those cases as well
local params = vim.split(sgr, ':')
if #params ~= 3 and (#params ~= 4 or (params[1] ~= '' and params[1] ~= '1')) then
return true
end
if
tonumber(params[#params - 2]) == r
and tonumber(params[#params - 1]) == g
and tonumber(params[#params]) == b
then
setoption('termguicolors', true)
if rr and gg and bb then
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
local bg = luminance < 0.5 and 'dark' or 'light'
setoption('background', bg)
end
return true
@ -474,16 +440,7 @@ if tty then
end,
})
-- Write SGR followed by DECRQSS. This sets the background color then
-- immediately asks the terminal what the background color is. If the
-- terminal responds to the DECRQSS with the same SGR sequence that we
-- sent then the terminal supports truecolor.
local decrqss = '\027P$qm\027\\'
if os.getenv('TMUX') then
decrqss = string.format('\027Ptmux;%s\027\\', decrqss:gsub('\027', '\027\027'))
end
-- Reset attributes first, as other code may have set attributes.
io.stdout:write(string.format('\027[0m\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
io.stdout:write('\027]11;?\007')
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
@ -497,13 +454,115 @@ if tty then
end
end)
end
--- If the TUI (term_has_truecolor) was able to determine that the host
--- terminal supports truecolor, enable 'termguicolors'. Otherwise, query the
--- terminal (using both XTGETTCAP and SGR + DECRQSS). If the terminal's
--- response indicates that it does support truecolor enable 'termguicolors',
--- but only if the user has not already disabled it.
do
if tty.rgb then
-- The TUI was able to determine truecolor support
setoption('termguicolors', true)
else
local caps = {} ---@type table<string, boolean>
require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
if not found then
return
end
caps[cap] = true
if caps.Tc or caps.RGB or (caps.setrgbf and caps.setrgbb) then
setoption('termguicolors', true)
end
end)
local timer = assert(vim.uv.new_timer())
-- Arbitrary colors to set in the SGR sequence
local r = 1
local g = 2
local b = 3
local id = vim.api.nvim_create_autocmd('TermResponse', {
group = group,
nested = true,
callback = function(args)
local resp = args.data ---@type string
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
if decrqss then
-- The DECRQSS SGR response first contains attributes separated by
-- semicolons, followed by the SGR itself with parameters separated
-- by colons. Some terminals include "0" in the attribute list
-- unconditionally; others do not. Our SGR sequence did not set any
-- attributes, so there should be no attributes in the list.
local attrs = vim.split(decrqss, ';')
if #attrs ~= 1 and (#attrs ~= 2 or attrs[1] ~= '0') then
return false
end
-- The returned SGR sequence should begin with 48:2
local sgr = attrs[#attrs]:match('^48:2:([%d:]+)$')
if not sgr then
return false
end
-- The remaining elements of the SGR sequence should be the 3 colors
-- we set. Some terminals also include an additional parameter
-- (which can even be empty!), so handle those cases as well
local params = vim.split(sgr, ':')
if #params ~= 3 and (#params ~= 4 or (params[1] ~= '' and params[1] ~= '1')) then
return true
end
if
tonumber(params[#params - 2]) == r
and tonumber(params[#params - 1]) == g
and tonumber(params[#params]) == b
then
setoption('termguicolors', true)
end
return true
end
end,
})
-- Write SGR followed by DECRQSS. This sets the background color then
-- immediately asks the terminal what the background color is. If the
-- terminal responds to the DECRQSS with the same SGR sequence that we
-- sent then the terminal supports truecolor.
local decrqss = '\027P$qm\027\\'
if os.getenv('TMUX') then
decrqss = string.format('\027Ptmux;%s\027\\', decrqss:gsub('\027', '\027\027'))
end
-- Reset attributes first, as other code may have set attributes.
io.stdout:write(string.format('\027[0m\027[48;2;%d;%d;%dm%s', r, g, b, decrqss))
timer:start(1000, 0, function()
-- Delete the autocommand if no response was received
vim.schedule(function()
-- Suppress error if autocommand has already been deleted
pcall(vim.api.nvim_del_autocmd, id)
end)
if not timer:is_closing() then
timer:close()
end
end)
end
end
end
end
--- Default 'grepprg' to ripgrep if available.
if vim.fn.executable('rg') == 1 then
-- Match :grep default, otherwise rg searches cwd by default
-- Use -uuu to make ripgrep not do its default filtering
vim.o.grepprg = 'rg --vimgrep -uuu $* ' .. (vim.fn.has('unix') == 1 and '/dev/null' or 'nul')
vim.o.grepformat = '%f:%l:%c:%m'
--- Default options
do
--- Default 'grepprg' to ripgrep if available.
if vim.fn.executable('rg') == 1 then
-- Match :grep default, otherwise rg searches cwd by default
-- Use -uuu to make ripgrep not do its default filtering
vim.o.grepprg = 'rg --vimgrep -uuu $* ' .. (vim.fn.has('unix') == 1 and '/dev/null' or 'nul')
vim.o.grepformat = '%f:%l:%c:%m'
end
end

View File

@ -9752,6 +9752,10 @@ function vim.fn.synIDtrans(synID) end
--- synconcealed(lnum, 5) [1, 'X', 2]
--- synconcealed(lnum, 6) [0, '', 0]
---
--- Note: Doesn't consider |matchadd()| highlighting items,
--- since syntax and matching highlighting are two different
--- mechanisms |syntax-vs-match|.
---
--- @param lnum integer
--- @param col integer
--- @return {[1]: integer, [2]: string, [3]: integer}

View File

@ -630,7 +630,7 @@ function Iter:find(f)
return unpack(result)
end
--- Gets the first value in a |list-iterator| that satisfies a predicate, starting from the end.
--- Gets the first value satisfying a predicate, from the end of a |list-iterator|.
---
--- Advances the iterator. Returns nil and drains the iterator if no value is found.
---
@ -717,19 +717,19 @@ end
---
--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:nextback()
--- it:pop()
--- -- 4
--- it:nextback()
--- it:pop()
--- -- 3
--- ```
---
---@return any
function Iter:nextback()
error('nextback() requires a list-like table')
function Iter:pop()
error('pop() requires a list-like table')
end
--- @nodoc
function ListIter:nextback()
function ListIter:pop()
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1
self._tail = self._tail - inc
@ -739,27 +739,27 @@ end
--- Gets the last value of a |list-iterator| without consuming it.
---
--- See also |Iter:last()|.
---
--- Example:
---
--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:peekback()
--- it:rpeek()
--- -- 4
--- it:peekback()
--- it:rpeek()
--- -- 4
--- it:nextback()
--- it:pop()
--- -- 4
--- ```
---
---@see Iter.last
---
---@return any
function Iter:peekback()
error('peekback() requires a list-like table')
function Iter:rpeek()
error('rpeek() requires a list-like table')
end
---@nodoc
function ListIter:peekback()
function ListIter:rpeek()
if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1
return self._table[self._tail - inc]
@ -797,27 +797,27 @@ function ListIter:skip(n)
return self
end
--- Skips `n` values backwards from the end of a |list-iterator| pipeline.
--- Discards `n` values from the end of a |list-iterator| pipeline.
---
--- Example:
---
--- ```lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
--- it:next()
--- -- 1
--- it:nextback()
--- it:pop()
--- -- 3
--- ```
---
---@param n number Number of values to skip.
---@return Iter
---@diagnostic disable-next-line: unused-local
function Iter:skipback(n) -- luacheck: no unused args
error('skipback() requires a list-like table')
function Iter:rskip(n) -- luacheck: no unused args
error('rskip() requires a list-like table')
end
---@private
function ListIter:skipback(n)
function ListIter:rskip(n)
local inc = self._head < self._tail and n or -n
self._tail = self._tail - inc
if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then
@ -828,51 +828,37 @@ end
--- Gets the nth value of an iterator (and advances to it).
---
--- If `n` is negative, offsets from the end of a |list-iterator|.
---
--- Example:
---
--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nth(2)
--- -- 6
--- it:nth(2)
--- -- 12
---
--- local it2 = vim.iter({ 3, 6, 9, 12 })
--- it2:nth(-2)
--- -- 9
--- it2:nth(-2)
--- -- 3
--- ```
---
---@param n number The index of the value to return.
---@param n number Index of the value to return. May be negative if the source is a |list-iterator|.
---@return any
function Iter:nth(n)
if n > 0 then
return self:skip(n - 1):next()
end
end
--- Gets the nth value from the end of a |list-iterator| (and advances to it).
---
--- Example:
---
--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nthback(2)
--- -- 9
--- it:nthback(2)
--- -- 3
---
--- ```
---
---@param n number The index of the value to return.
---@return any
function Iter:nthback(n)
if n > 0 then
return self:skipback(n - 1):nextback()
elseif n < 0 then
return self:rskip(math.abs(n) - 1):pop()
end
end
--- Sets the start and end of a |list-iterator| pipeline.
---
--- Equivalent to `:skip(first - 1):skipback(len - last + 1)`.
--- Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
---
---@param first number
---@param last number
@ -884,7 +870,7 @@ end
---@private
function ListIter:slice(first, last)
return self:skip(math.max(0, first - 1)):skipback(math.max(0, self._tail - last - 1))
return self:skip(math.max(0, first - 1)):rskip(math.max(0, self._tail - last - 1))
end
--- Returns true if any of the items in the iterator match the given predicate.
@ -950,6 +936,8 @@ end
---
--- ```
---
---@see Iter.rpeek
---
---@return any
function Iter:last()
local last = self:next()
@ -1016,6 +1004,26 @@ function ListIter:enumerate()
return self
end
---@deprecated
function Iter:nextback()
error('Iter:nextback() was renamed to Iter:pop()')
end
---@deprecated
function Iter:peekback()
error('Iter:peekback() was renamed to Iter:rpeek()')
end
---@deprecated
function Iter:skipback()
error('Iter:skipback() was renamed to Iter:rskip()')
end
---@deprecated
function Iter:nthback()
error('Iter:nthback() was removed, use Iter:nth() with negative index')
end
--- Creates a new Iter object from a table or other |iterable|.
---
---@param src table|function Table or iterator to drain values from

View File

@ -201,7 +201,7 @@ end
--- @field bufnr integer
---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent boolean
--- @field silent? boolean
--- Create a new LSP client and start a language server or reuses an already
--- running client if one is found matching `name` and `root_dir`.
@ -348,7 +348,7 @@ function lsp._set_defaults(client, bufnr)
and is_empty_or_default(bufnr, 'keywordprg')
and vim.fn.maparg('K', 'n', false, false) == ''
then
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr })
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'vim.lsp.buf.hover()' })
end
end)
if client.supports_method(ms.textDocument_diagnostic) then
@ -451,30 +451,6 @@ function lsp.start_client(config)
return client.id, nil
end
--- Notify all attached clients that a buffer has changed.
---@param _ integer
---@param bufnr integer
---@param changedtick integer
---@param firstline integer
---@param lastline integer
---@param new_lastline integer
---@return true?
local function text_document_did_change_handler(
_,
bufnr,
changedtick,
firstline,
lastline,
new_lastline
)
-- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
return true
end
util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
end
---Buffer lifecycle handler for textDocument/didSave
--- @param bufnr integer
local function text_document_did_save_handler(bufnr)
@ -516,11 +492,18 @@ local function text_document_did_save_handler(bufnr)
end
end
--- @type table<integer,true>
local attached_buffers = {}
--- @param bufnr integer
--- @param client_id integer
local function buf_attach(bufnr, client_id)
local function buf_attach(bufnr)
if attached_buffers[bufnr] then
return
end
attached_buffers[bufnr] = true
local uri = vim.uri_from_bufnr(bufnr)
local augroup = ('lsp_c_%d_b_%d_save'):format(client_id, bufnr)
local augroup = ('lsp_b_%d_save'):format(bufnr)
local group = api.nvim_create_augroup(augroup, { clear = true })
api.nvim_create_autocmd('BufWritePre', {
group = group,
@ -559,7 +542,14 @@ local function buf_attach(bufnr, client_id)
})
-- First time, so attach and set up stuff.
api.nvim_buf_attach(bufnr, false, {
on_lines = text_document_did_change_handler,
on_lines = function(_, _, changedtick, firstline, lastline, new_lastline)
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
return true -- detach
end
util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
end,
on_reload = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@ -570,6 +560,7 @@ local function buf_attach(bufnr, client_id)
client:_text_document_did_open_handler(bufnr)
end
end,
on_detach = function()
local params = { textDocument = { uri = uri } }
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
@ -582,7 +573,9 @@ local function buf_attach(bufnr, client_id)
client.attached_buffers[bufnr] = nil
end
util.buf_versions[bufnr] = nil
attached_buffers[bufnr] = nil
end,
-- TODO if we know all of the potential clients ahead of time, then we
-- could conditionally set this.
-- utf_sizes = size_index > 1;
@ -608,16 +601,14 @@ function lsp.buf_attach_client(bufnr, client_id)
log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
return false
end
-- This is our first time attaching to this buffer.
if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
buf_attach(bufnr, client_id)
end
local client = lsp.get_client_by_id(client_id)
if not client then
return false
end
buf_attach(bufnr)
if client.attached_buffers[bufnr] then
return true
end

View File

@ -103,20 +103,6 @@ local function edit_range(range, srow, erow_old, erow_new)
range[2] = math.max(range[2], erow_new)
end
--- If a parser doesn't have any ranges explicitly set, treesitter will
--- return a range with end_row and end_bytes with a value of UINT32_MAX,
--- so clip end_row to the max buffer line.
---
--- TODO(lewis6991): Handle this generally
---
--- @param bufnr integer
--- @param erow integer? 0-indexed, exclusive
--- @return integer
local function normalise_erow(bufnr, erow)
local max_erow = api.nvim_buf_line_count(bufnr)
return math.min(erow or max_erow, max_erow)
end
-- TODO(lewis6991): Setup a decor provider so injections folds can be parsed
-- as the window is redrawn
---@param bufnr integer
@ -126,7 +112,7 @@ end
---@param parse_injections? boolean
local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
srow = srow or 0
erow = normalise_erow(bufnr, erow)
erow = erow or api.nvim_buf_line_count(bufnr)
local parser = ts.get_parser(bufnr)
@ -314,9 +300,16 @@ end
local function on_changedtree(bufnr, foldinfo, tree_changes)
schedule_if_loaded(bufnr, function()
local srow_upd, erow_upd ---@type integer?, integer?
local max_erow = api.nvim_buf_line_count(bufnr)
for _, change in ipairs(tree_changes) do
local srow, _, erow, ecol = Range.unpack4(change)
if ecol > 0 then
-- If a parser doesn't have any ranges explicitly set, treesitter will
-- return a range with end_row and end_bytes with a value of UINT32_MAX,
-- so clip end_row to the max buffer line.
-- TODO(lewis6991): Handle this generally
if erow > max_erow then
erow = max_erow
elseif ecol > 0 then
erow = erow + 1
end
-- Start from `srow - foldminlines`, because this edit may have shrunken the fold below limit.

View File

@ -47,8 +47,8 @@ typedef struct {
#define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid
#define VALID_CHEIGHT 0x08 // w_cline_height and w_cline_folded valid
#define VALID_CROW 0x10 // w_cline_row is valid
#define VALID_BOTLINE 0x20 // w_botine and w_empty_rows are valid
#define VALID_BOTLINE_AP 0x40 // w_botine is approximated
#define VALID_BOTLINE 0x20 // w_botline and w_empty_rows are valid
#define VALID_BOTLINE_AP 0x40 // w_botline is approximated
#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position)
// flags for b_flags

View File

@ -11621,6 +11621,10 @@ M.funcs = {
synconcealed(lnum, 4) [1, 'X', 2]
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
Note: Doesn't consider |matchadd()| highlighting items,
since syntax and matching highlighting are two different
mechanisms |syntax-vs-match|.
]=],
name = 'synconcealed',
params = { { 'lnum', 'integer' }, { 'col', 'integer' } },

View File

@ -549,19 +549,21 @@ static int nlua_iconv(lua_State *lstate)
static int nlua_foldupdate(lua_State *lstate)
{
handle_T window = (handle_T)luaL_checkinteger(lstate, 1);
Error err = ERROR_INIT;
win_T *win = find_window_by_handle(window, &err);
if (ERROR_SET(&err)) {
nlua_push_errstr(lstate, err.msg);
api_clear_error(&err);
lua_error(lstate);
return 0;
win_T *win = handle_get_window(window);
if (!win) {
return luaL_error(lstate, "invalid window");
}
// input is zero-based end-exclusive range
linenr_T top = (linenr_T)luaL_checkinteger(lstate, 2) + 1;
if (top < 1 || top > win->w_buffer->b_ml.ml_line_count) {
return luaL_error(lstate, "invalid top");
}
linenr_T bot = (linenr_T)luaL_checkinteger(lstate, 3);
if (top > bot) {
return luaL_error(lstate, "invalid bot");
}
linenr_T start = (linenr_T)luaL_checkinteger(lstate, 2);
linenr_T end = (linenr_T)luaL_checkinteger(lstate, 3);
foldUpdate(win, start + 1, end);
foldUpdate(win, top, bot);
return 0;
}

View File

@ -2467,6 +2467,7 @@ void win_init_empty(win_T *wp)
wp->w_topline = 1;
wp->w_topfill = 0;
wp->w_botline = 2;
wp->w_valid = 0;
wp->w_s = &wp->w_buffer->b_s;
}

View File

@ -169,19 +169,19 @@ describe('vim.iter', function()
end
end)
it('skipback()', function()
it('rskip()', function()
do
local q = { 4, 3, 2, 1 }
eq(q, vim.iter(q):skipback(0):totable())
eq({ 4, 3, 2 }, vim.iter(q):skipback(1):totable())
eq({ 4, 3 }, vim.iter(q):skipback(2):totable())
eq({ 4 }, vim.iter(q):skipback(#q - 1):totable())
eq({}, vim.iter(q):skipback(#q):totable())
eq({}, vim.iter(q):skipback(#q + 1):totable())
eq(q, vim.iter(q):rskip(0):totable())
eq({ 4, 3, 2 }, vim.iter(q):rskip(1):totable())
eq({ 4, 3 }, vim.iter(q):rskip(2):totable())
eq({ 4 }, vim.iter(q):rskip(#q - 1):totable())
eq({}, vim.iter(q):rskip(#q):totable())
eq({}, vim.iter(q):rskip(#q + 1):totable())
end
local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0))
matches('rskip%(%) requires a list%-like table', pcall_err(it.rskip, it, 0))
end)
it('slice()', function()
@ -222,19 +222,19 @@ describe('vim.iter', function()
end
end)
it('nthback()', function()
it('nth(-x) advances in reverse order starting from end', function()
do
local q = { 4, 3, 2, 1 }
eq(nil, vim.iter(q):nthback(0))
eq(1, vim.iter(q):nthback(1))
eq(2, vim.iter(q):nthback(2))
eq(3, vim.iter(q):nthback(3))
eq(4, vim.iter(q):nthback(4))
eq(nil, vim.iter(q):nthback(5))
eq(nil, vim.iter(q):nth(0))
eq(1, vim.iter(q):nth(-1))
eq(2, vim.iter(q):nth(-2))
eq(3, vim.iter(q):nth(-3))
eq(4, vim.iter(q):nth(-4))
eq(nil, vim.iter(q):nth(-5))
end
local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1))
matches('rskip%(%) requires a list%-like table', pcall_err(it.nth, it, -1))
end)
it('take()', function()
@ -421,34 +421,34 @@ describe('vim.iter', function()
end
end)
it('nextback()', function()
it('pop()', function()
do
local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:nextback())
eq(3, it:nextback())
eq(2, it:nextback())
eq(1, it:nextback())
eq(nil, it:nextback())
eq(nil, it:nextback())
eq(4, it:pop())
eq(3, it:pop())
eq(2, it:pop())
eq(1, it:pop())
eq(nil, it:pop())
eq(nil, it:pop())
end
do
local it = vim.iter(vim.gsplit('hi', ''))
matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it))
matches('pop%(%) requires a list%-like table', pcall_err(it.pop, it))
end
end)
it('peekback()', function()
it('rpeek()', function()
do
local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:peekback())
eq(4, it:peekback())
eq(4, it:nextback())
eq(4, it:rpeek())
eq(4, it:rpeek())
eq(4, it:pop())
end
do
local it = vim.iter(vim.gsplit('hi', ''))
matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it))
matches('rpeek%(%) requires a list%-like table', pcall_err(it.rpeek, it))
end
end)

View File

@ -192,6 +192,7 @@ describe(':Man', function()
'--headless',
'+autocmd VimLeave * echo "quit works!!"',
'+Man!',
'+tag ls',
'+call nvim_input("q")',
}
matches('quit works!!', fn.system(args, { 'manpage contents' }))

View File

@ -4105,4 +4105,16 @@ func Test_SwapExists_set_other_buf_modified()
bwipe!
endfunc
func Test_BufEnter_botline()
set hidden
call writefile(range(10), 'Xxx1', 'D')
call writefile(range(20), 'Xxx2', 'D')
edit Xxx1
edit Xxx2
au BufEnter Xxx1 call assert_true(line('w$') > 1)
edit Xxx1
au! BufEnter Xxx1
set hidden&vim
endfunc
" vim: shiftwidth=2 sts=2 expandtab