mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 02:34:59 -07:00
Compare commits
6 Commits
a5d8f6f5bb
...
09785d68aa
Author | SHA1 | Date | |
---|---|---|---|
|
09785d68aa | ||
|
02bc40c194 | ||
|
160cbd0ef4 | ||
|
3db3947b0e | ||
|
10298f4533 | ||
|
743ddaa764 |
@ -60,7 +60,7 @@ hi('PmenuMatch', { link = 'Pmenu' })
|
|||||||
hi('PmenuMatchSel', { link = 'PmenuSel' })
|
hi('PmenuMatchSel', { link = 'PmenuSel' })
|
||||||
hi('PmenuExtra', { link = 'Pmenu' })
|
hi('PmenuExtra', { link = 'Pmenu' })
|
||||||
hi('PmenuExtraSel', { link = 'PmenuSel' })
|
hi('PmenuExtraSel', { link = 'PmenuSel' })
|
||||||
hi('ComplMatchIns', { link = 'Normal' })
|
hi('ComplMatchIns', {})
|
||||||
hi('Substitute', { link = 'Search' })
|
hi('Substitute', { link = 'Search' })
|
||||||
hi('Whitespace', { link = 'NonText' })
|
hi('Whitespace', { link = 'NonText' })
|
||||||
hi('MsgSeparator', { link = 'StatusLine' })
|
hi('MsgSeparator', { link = 'StatusLine' })
|
||||||
|
@ -2772,6 +2772,10 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
|
|||||||
When a character is supplied it is used as |:syn-cchar|.
|
When a character is supplied it is used as |:syn-cchar|.
|
||||||
"hl_group" is used as highlight for the cchar if provided,
|
"hl_group" is used as highlight for the cchar if provided,
|
||||||
otherwise it defaults to |hl-Conceal|.
|
otherwise it defaults to |hl-Conceal|.
|
||||||
|
• conceal_lines: string which should be either empty or a
|
||||||
|
single character. When provided, lines in the range are
|
||||||
|
not drawn at all; the next unconcealed line is drawn
|
||||||
|
instead.
|
||||||
• spell: boolean indicating that spell checking should be
|
• spell: boolean indicating that spell checking should be
|
||||||
performed within this extmark
|
performed within this extmark
|
||||||
• ui_watched: boolean that indicates the mark should be
|
• ui_watched: boolean that indicates the mark should be
|
||||||
|
@ -178,6 +178,7 @@ API
|
|||||||
|
|
||||||
• |nvim__ns_set()| can set properties for a namespace
|
• |nvim__ns_set()| can set properties for a namespace
|
||||||
• |vim.json.encode()| has an option to enable forward slash escaping
|
• |vim.json.encode()| has an option to enable forward slash escaping
|
||||||
|
• New |nvim_buf_set_extmark()| flag `conceal_lines` to conceal an entire line.
|
||||||
|
|
||||||
DEFAULTS
|
DEFAULTS
|
||||||
|
|
||||||
@ -303,6 +304,8 @@ TREESITTER
|
|||||||
• |treesitter-directive-trim!| can trim all whitespace (not just empty lines)
|
• |treesitter-directive-trim!| can trim all whitespace (not just empty lines)
|
||||||
from both sides of a node.
|
from both sides of a node.
|
||||||
• |vim.treesitter.get_captures_at_pos()| now returns the `id` of each capture
|
• |vim.treesitter.get_captures_at_pos()| now returns the `id` of each capture
|
||||||
|
• Bundled markdown highlight queries use `conceal_lines` metadata to conceal
|
||||||
|
code block fence lines vertically.
|
||||||
|
|
||||||
TUI
|
TUI
|
||||||
|
|
||||||
|
@ -493,10 +493,10 @@ capture marks comments as to be checked: >query
|
|||||||
There is also `@nospell` which disables spellchecking regions with `@spell`.
|
There is also `@nospell` which disables spellchecking regions with `@spell`.
|
||||||
|
|
||||||
*treesitter-highlight-conceal*
|
*treesitter-highlight-conceal*
|
||||||
Treesitter highlighting supports |conceal| via the `conceal` metadata. By
|
Treesitter highlighting supports |conceal| via the `conceal` and `conceal_lines`
|
||||||
convention, nodes to be concealed are captured as `@conceal`, but any capture
|
metadata. By convention, nodes to be concealed are captured as `@conceal`, but
|
||||||
can be used. For example, the following query can be used to hide code block
|
any capture can be used. For example, the following query can be used to hide
|
||||||
delimiters in Markdown: >query
|
code block delimiters in Markdown: >query
|
||||||
|
|
||||||
(fenced_code_block_delimiter @conceal (#set! conceal ""))
|
(fenced_code_block_delimiter @conceal (#set! conceal ""))
|
||||||
<
|
<
|
||||||
@ -507,7 +507,13 @@ still highlighted the same as other operators: >query
|
|||||||
|
|
||||||
"!=" @operator (#set! conceal "≠")
|
"!=" @operator (#set! conceal "≠")
|
||||||
<
|
<
|
||||||
Conceals specified in this way respect 'conceallevel'.
|
To conceal an entire line (do not draw it at all), a query with `conceal_lines`
|
||||||
|
metadata can be used: >query
|
||||||
|
|
||||||
|
((comment) @comment @spell
|
||||||
|
(#set! conceal_lines ""))
|
||||||
|
<
|
||||||
|
Conceals specified in this way respect 'conceallevel' and 'concealcursor'.
|
||||||
|
|
||||||
*treesitter-highlight-priority*
|
*treesitter-highlight-priority*
|
||||||
Treesitter uses |nvim_buf_set_extmark()| to set highlights with a default
|
Treesitter uses |nvim_buf_set_extmark()| to set highlights with a default
|
||||||
|
3
runtime/lua/vim/_meta/api.lua
generated
3
runtime/lua/vim/_meta/api.lua
generated
@ -686,6 +686,9 @@ function vim.api.nvim_buf_line_count(buffer) end
|
|||||||
--- When a character is supplied it is used as `:syn-cchar`.
|
--- When a character is supplied it is used as `:syn-cchar`.
|
||||||
--- "hl_group" is used as highlight for the cchar if provided,
|
--- "hl_group" is used as highlight for the cchar if provided,
|
||||||
--- otherwise it defaults to `hl-Conceal`.
|
--- otherwise it defaults to `hl-Conceal`.
|
||||||
|
--- - conceal_lines: string which should be either empty or a single
|
||||||
|
--- character. When provided, lines in the range are not drawn
|
||||||
|
--- at all; the next unconcealed line is drawn instead.
|
||||||
--- - spell: boolean indicating that spell checking should be
|
--- - spell: boolean indicating that spell checking should be
|
||||||
--- performed within this extmark
|
--- performed within this extmark
|
||||||
--- - ui_watched: boolean that indicates the mark should be drawn
|
--- - ui_watched: boolean that indicates the mark should be drawn
|
||||||
|
2
runtime/lua/vim/_meta/api_keysets.lua
generated
2
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -234,6 +234,7 @@ error('Cannot require a meta file')
|
|||||||
--- @field on_end? fun(_: "end", tick: integer)
|
--- @field on_end? fun(_: "end", tick: integer)
|
||||||
--- @field _on_hl_def? fun(_: "hl_def")
|
--- @field _on_hl_def? fun(_: "hl_def")
|
||||||
--- @field _on_spell_nav? fun(_: "spell_nav")
|
--- @field _on_spell_nav? fun(_: "spell_nav")
|
||||||
|
--- @field _on_conceal_line? fun(_: "conceal_line")
|
||||||
|
|
||||||
--- @class vim.api.keyset.set_extmark
|
--- @class vim.api.keyset.set_extmark
|
||||||
--- @field id? integer
|
--- @field id? integer
|
||||||
@ -263,6 +264,7 @@ error('Cannot require a meta file')
|
|||||||
--- @field line_hl_group? integer|string
|
--- @field line_hl_group? integer|string
|
||||||
--- @field cursorline_hl_group? integer|string
|
--- @field cursorline_hl_group? integer|string
|
||||||
--- @field conceal? string
|
--- @field conceal? string
|
||||||
|
--- @field conceal_lines? string
|
||||||
--- @field spell? boolean
|
--- @field spell? boolean
|
||||||
--- @field ui_watched? boolean
|
--- @field ui_watched? boolean
|
||||||
--- @field undo_restore? boolean
|
--- @field undo_restore? boolean
|
||||||
|
@ -67,6 +67,8 @@ end
|
|||||||
--- This state is kept during rendering across each line update.
|
--- This state is kept during rendering across each line update.
|
||||||
---@field private _highlight_states vim.treesitter.highlighter.State[]
|
---@field private _highlight_states vim.treesitter.highlighter.State[]
|
||||||
---@field private _queries table<string,vim.treesitter.highlighter.Query>
|
---@field private _queries table<string,vim.treesitter.highlighter.Query>
|
||||||
|
---@field _conceal_line boolean?
|
||||||
|
---@field _conceal_checked table<integer, boolean>
|
||||||
---@field tree vim.treesitter.LanguageTree
|
---@field tree vim.treesitter.LanguageTree
|
||||||
---@field private redraw_count integer
|
---@field private redraw_count integer
|
||||||
local TSHighlighter = {
|
local TSHighlighter = {
|
||||||
@ -114,7 +116,7 @@ function TSHighlighter.new(tree, opts)
|
|||||||
|
|
||||||
self.bufnr = source
|
self.bufnr = source
|
||||||
self.redraw_count = 0
|
self.redraw_count = 0
|
||||||
self._highlight_states = {}
|
self._conceal_checked = {}
|
||||||
self._queries = {}
|
self._queries = {}
|
||||||
|
|
||||||
-- Queries for a specific language can be overridden by a custom
|
-- Queries for a specific language can be overridden by a custom
|
||||||
@ -122,6 +124,7 @@ function TSHighlighter.new(tree, opts)
|
|||||||
if opts.queries then
|
if opts.queries then
|
||||||
for lang, query_string in pairs(opts.queries) do
|
for lang, query_string in pairs(opts.queries) do
|
||||||
self._queries[lang] = TSHighlighterQuery.new(lang, query_string)
|
self._queries[lang] = TSHighlighterQuery.new(lang, query_string)
|
||||||
|
self._conceal_line = self._conceal_line or self._queries[lang]:query().conceal_line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -140,7 +143,7 @@ function TSHighlighter.new(tree, opts)
|
|||||||
-- immediately afterwards will not error.
|
-- immediately afterwards will not error.
|
||||||
if vim.g.syntax_on ~= 1 then
|
if vim.g.syntax_on ~= 1 then
|
||||||
vim.cmd.runtime({ 'syntax/synload.vim', bang = true })
|
vim.cmd.runtime({ 'syntax/synload.vim', bang = true })
|
||||||
vim.api.nvim_create_augroup('syntaxset', { clear = false })
|
api.nvim_create_augroup('syntaxset', { clear = false })
|
||||||
end
|
end
|
||||||
|
|
||||||
vim._with({ buf = self.bufnr }, function()
|
vim._with({ buf = self.bufnr }, function()
|
||||||
@ -148,6 +151,7 @@ function TSHighlighter.new(tree, opts)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
self.tree:parse()
|
self.tree:parse()
|
||||||
|
self:set_decoration_provider()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@ -160,6 +164,7 @@ function TSHighlighter:destroy()
|
|||||||
if api.nvim_buf_is_loaded(self.bufnr) then
|
if api.nvim_buf_is_loaded(self.bufnr) then
|
||||||
vim.bo[self.bufnr].spelloptions = self.orig_spelloptions
|
vim.bo[self.bufnr].spelloptions = self.orig_spelloptions
|
||||||
vim.b[self.bufnr].ts_highlight = nil
|
vim.b[self.bufnr].ts_highlight = nil
|
||||||
|
api.nvim_buf_clear_namespace(self.bufnr, ns, 0, -1)
|
||||||
if vim.g.syntax_on == 1 then
|
if vim.g.syntax_on == 1 then
|
||||||
api.nvim_exec_autocmds('FileType', { group = 'syntaxset', buffer = self.bufnr })
|
api.nvim_exec_autocmds('FileType', { group = 'syntaxset', buffer = self.bufnr })
|
||||||
end
|
end
|
||||||
@ -185,10 +190,14 @@ function TSHighlighter:prepare_highlight_states(srow, erow)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local highlighter_query = self:get_query(tree:lang())
|
local hl_query = self:get_query(tree:lang())
|
||||||
|
if hl_query:query().conceal_line and not self._conceal_line then
|
||||||
|
self._conceal_line = true
|
||||||
|
self:set_decoration_provider()
|
||||||
|
end
|
||||||
|
|
||||||
-- Some injected languages may not have highlight queries.
|
-- Some injected languages may not have highlight queries.
|
||||||
if not highlighter_query:query() then
|
if not hl_query:query() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -198,7 +207,7 @@ function TSHighlighter:prepare_highlight_states(srow, erow)
|
|||||||
tstree = tstree,
|
tstree = tstree,
|
||||||
next_row = 0,
|
next_row = 0,
|
||||||
iter = nil,
|
iter = nil,
|
||||||
highlighter_query = highlighter_query,
|
highlighter_query = hl_query,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@ -220,7 +229,10 @@ end
|
|||||||
---@param changes Range6[]
|
---@param changes Range6[]
|
||||||
function TSHighlighter:on_changedtree(changes)
|
function TSHighlighter:on_changedtree(changes)
|
||||||
for _, ch in ipairs(changes) do
|
for _, ch in ipairs(changes) do
|
||||||
api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] + 1 }, flush = false })
|
api.nvim__redraw({ buf = self.bufnr, range = { ch[1], ch[4] }, flush = false })
|
||||||
|
for i = ch[1], self._conceal_line and ch[4] or 0 do
|
||||||
|
self._conceal_checked[i] = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -279,8 +291,10 @@ end
|
|||||||
---@param self vim.treesitter.highlighter
|
---@param self vim.treesitter.highlighter
|
||||||
---@param buf integer
|
---@param buf integer
|
||||||
---@param line integer
|
---@param line integer
|
||||||
---@param is_spell_nav boolean
|
---@param on_spell boolean
|
||||||
local function on_line_impl(self, buf, line, is_spell_nav)
|
---@param on_conceal boolean
|
||||||
|
local function on_line_impl(self, buf, line, on_spell, on_conceal)
|
||||||
|
self._conceal_checked[line] = true
|
||||||
self:for_each_highlight_state(function(state)
|
self:for_each_highlight_state(function(state)
|
||||||
local root_node = state.tstree:root()
|
local root_node = state.tstree:root()
|
||||||
local root_start_row, _, root_end_row, _ = root_node:range()
|
local root_start_row, _, root_end_row, _ = root_node:range()
|
||||||
@ -326,7 +340,7 @@ local function on_line_impl(self, buf, line, is_spell_nav)
|
|||||||
|
|
||||||
local url = get_url(match, buf, capture, metadata)
|
local url = get_url(match, buf, capture, metadata)
|
||||||
|
|
||||||
if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then
|
if hl and end_row >= line and not on_conceal and (not on_spell or spell ~= nil) then
|
||||||
api.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
|
api.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
|
||||||
end_line = end_row,
|
end_line = end_row,
|
||||||
end_col = end_col,
|
end_col = end_col,
|
||||||
@ -338,6 +352,16 @@ local function on_line_impl(self, buf, line, is_spell_nav)
|
|||||||
url = url,
|
url = url,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if
|
||||||
|
(metadata.conceal_lines or metadata[capture] and metadata[capture].conceal_lines)
|
||||||
|
and #api.nvim_buf_get_extmarks(buf, ns, { start_row, 0 }, { start_row, 0 }, {}) == 0
|
||||||
|
then
|
||||||
|
api.nvim_buf_set_extmark(buf, ns, start_row, 0, {
|
||||||
|
end_line = end_row,
|
||||||
|
conceal_lines = '',
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if start_row > line then
|
if start_row > line then
|
||||||
@ -357,7 +381,7 @@ function TSHighlighter._on_line(_, _win, buf, line, _)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
on_line_impl(self, buf, line, false)
|
on_line_impl(self, buf, line, false, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
@ -376,17 +400,45 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
|||||||
self:prepare_highlight_states(srow, erow)
|
self:prepare_highlight_states(srow, erow)
|
||||||
|
|
||||||
for row = srow, erow do
|
for row = srow, erow do
|
||||||
on_line_impl(self, buf, row, true)
|
on_line_impl(self, buf, row, true, false)
|
||||||
end
|
end
|
||||||
self._highlight_states = highlight_states
|
self._highlight_states = highlight_states
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
---@param _win integer
|
---@param buf integer
|
||||||
|
---@param row integer
|
||||||
|
function TSHighlighter._on_conceal_line(_, _, buf, row)
|
||||||
|
local self = TSHighlighter.active[buf]
|
||||||
|
if not self or self._conceal_checked[row] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Do not affect potentially populated highlight state.
|
||||||
|
local highlight_states = self._highlight_states
|
||||||
|
self:prepare_highlight_states(row, row)
|
||||||
|
on_line_impl(self, buf, row, false, true)
|
||||||
|
self._highlight_states = highlight_states
|
||||||
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
--- Clear conceal_lines marks whenever we redraw for a buffer change. Marks are
|
||||||
|
--- added back as either the _conceal_line or on_win callback comes across them.
|
||||||
|
function TSHighlighter._on_buf(_, buf)
|
||||||
|
local self = TSHighlighter.active[buf]
|
||||||
|
if not self then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
||||||
|
self._conceal_checked = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
---@param buf integer
|
---@param buf integer
|
||||||
---@param topline integer
|
---@param topline integer
|
||||||
---@param botline integer
|
---@param botline integer
|
||||||
function TSHighlighter._on_win(_, _win, buf, topline, botline)
|
function TSHighlighter._on_win(_, _, buf, topline, botline)
|
||||||
local self = TSHighlighter.active[buf]
|
local self = TSHighlighter.active[buf]
|
||||||
if not self then
|
if not self then
|
||||||
return false
|
return false
|
||||||
@ -397,10 +449,15 @@ function TSHighlighter._on_win(_, _win, buf, topline, botline)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
api.nvim_set_decoration_provider(ns, {
|
---@private
|
||||||
on_win = TSHighlighter._on_win,
|
function TSHighlighter:set_decoration_provider()
|
||||||
on_line = TSHighlighter._on_line,
|
api.nvim_set_decoration_provider(ns, {
|
||||||
_on_spell_nav = TSHighlighter._on_spell_nav,
|
on_win = TSHighlighter._on_win,
|
||||||
})
|
on_line = TSHighlighter._on_line,
|
||||||
|
_on_spell_nav = TSHighlighter._on_spell_nav,
|
||||||
|
_on_conceal_line = self._conceal_line and TSHighlighter._on_conceal_line or nil,
|
||||||
|
on_buf = self._conceal_line and TSHighlighter._on_buf or nil,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
return TSHighlighter
|
return TSHighlighter
|
||||||
|
@ -11,6 +11,7 @@ local M = {}
|
|||||||
---@field lang string name of the language for this parser
|
---@field lang string name of the language for this parser
|
||||||
---@field captures string[] list of (unique) capture names defined in query
|
---@field captures string[] list of (unique) capture names defined in query
|
||||||
---@field info vim.treesitter.QueryInfo contains information used in the query (e.g. captures, predicates, directives)
|
---@field info vim.treesitter.QueryInfo contains information used in the query (e.g. captures, predicates, directives)
|
||||||
|
---@field conceal_line boolean whether this query sets conceal_lines metadata.
|
||||||
---@field query TSQuery userdata query object
|
---@field query TSQuery userdata query object
|
||||||
local Query = {}
|
local Query = {}
|
||||||
Query.__index = Query
|
Query.__index = Query
|
||||||
@ -30,6 +31,17 @@ function Query.new(lang, ts_query)
|
|||||||
patterns = query_info.patterns,
|
patterns = query_info.patterns,
|
||||||
}
|
}
|
||||||
self.captures = self.info.captures
|
self.captures = self.info.captures
|
||||||
|
|
||||||
|
-- Instruct highlighter to place marks when query contains conceal_lines metadata.
|
||||||
|
for _, preds in pairs(self.info.patterns) do
|
||||||
|
for _, pred in ipairs(preds) do
|
||||||
|
if vim.deep_equal(pred, { 'set!', 'conceal_lines', '' }) then
|
||||||
|
self.conceal_line = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@
|
|||||||
|
|
||||||
(fenced_code_block
|
(fenced_code_block
|
||||||
(fenced_code_block_delimiter) @markup.raw.block
|
(fenced_code_block_delimiter) @markup.raw.block
|
||||||
(#set! conceal ""))
|
(#set! conceal_lines ""))
|
||||||
|
|
||||||
(fenced_code_block
|
(fenced_code_block
|
||||||
(info_string
|
(info_string
|
||||||
(language) @label
|
(language) @label
|
||||||
(#set! conceal "")))
|
(#set! conceal_lines "")))
|
||||||
|
|
||||||
(link_destination) @markup.link.url
|
(link_destination) @markup.link.url
|
||||||
|
|
||||||
|
@ -475,6 +475,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
/// When a character is supplied it is used as |:syn-cchar|.
|
/// When a character is supplied it is used as |:syn-cchar|.
|
||||||
/// "hl_group" is used as highlight for the cchar if provided,
|
/// "hl_group" is used as highlight for the cchar if provided,
|
||||||
/// otherwise it defaults to |hl-Conceal|.
|
/// otherwise it defaults to |hl-Conceal|.
|
||||||
|
/// - conceal_lines: string which should be either empty or a single
|
||||||
|
/// character. When provided, lines in the range are not drawn
|
||||||
|
/// at all; the next unconcealed line is drawn instead.
|
||||||
/// - spell: boolean indicating that spell checking should be
|
/// - spell: boolean indicating that spell checking should be
|
||||||
/// performed within this extmark
|
/// performed within this extmark
|
||||||
/// - ui_watched: boolean that indicates the mark should be drawn
|
/// - ui_watched: boolean that indicates the mark should be drawn
|
||||||
@ -575,6 +578,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(opts, set_extmark, conceal_lines)) {
|
||||||
|
hl.flags |= kSHConcealLines;
|
||||||
|
has_hl = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (HAS_KEY(opts, set_extmark, virt_text)) {
|
if (HAS_KEY(opts, set_extmark, virt_text)) {
|
||||||
virt_text.data.virt_text = parse_virt_text(opts->virt_text, err, &virt_text.width);
|
virt_text.data.virt_text = parse_virt_text(opts->virt_text, err, &virt_text.width);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
@ -793,6 +801,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hl.flags & kSHConcealLines) {
|
||||||
|
decor_flags |= MT_FLAG_DECOR_CONCEAL_LINES;
|
||||||
|
}
|
||||||
|
|
||||||
DecorInline decor = DECOR_INLINE_INIT;
|
DecorInline decor = DECOR_INLINE_INIT;
|
||||||
if (decor_alloc || decor_indexed != DECOR_ID_INVALID || url != NULL
|
if (decor_alloc || decor_indexed != DECOR_ID_INVALID || url != NULL
|
||||||
|| schar_high(hl.conceal_char)) {
|
|| schar_high(hl.conceal_char)) {
|
||||||
@ -1052,6 +1064,7 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *
|
|||||||
{ "on_end", &opts->on_end, &p->redraw_end },
|
{ "on_end", &opts->on_end, &p->redraw_end },
|
||||||
{ "_on_hl_def", &opts->_on_hl_def, &p->hl_def },
|
{ "_on_hl_def", &opts->_on_hl_def, &p->hl_def },
|
||||||
{ "_on_spell_nav", &opts->_on_spell_nav, &p->spell_nav },
|
{ "_on_spell_nav", &opts->_on_spell_nav, &p->spell_nav },
|
||||||
|
{ "_on_conceal_line", &opts->_on_conceal_line, &p->conceal_line },
|
||||||
{ NULL, NULL, NULL },
|
{ NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ typedef struct {
|
|||||||
LuaRefOf(("end" _, Integer tick)) on_end;
|
LuaRefOf(("end" _, Integer tick)) on_end;
|
||||||
LuaRefOf(("hl_def" _)) _on_hl_def;
|
LuaRefOf(("hl_def" _)) _on_hl_def;
|
||||||
LuaRefOf(("spell_nav" _)) _on_spell_nav;
|
LuaRefOf(("spell_nav" _)) _on_spell_nav;
|
||||||
|
LuaRefOf(("conceal_line" _)) _on_conceal_line;
|
||||||
} Dict(set_decoration_provider);
|
} Dict(set_decoration_provider);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -51,6 +52,7 @@ typedef struct {
|
|||||||
HLGroupID line_hl_group;
|
HLGroupID line_hl_group;
|
||||||
HLGroupID cursorline_hl_group;
|
HLGroupID cursorline_hl_group;
|
||||||
String conceal;
|
String conceal;
|
||||||
|
String conceal_lines;
|
||||||
Boolean spell;
|
Boolean spell;
|
||||||
Boolean ui_watched;
|
Boolean ui_watched;
|
||||||
Boolean undo_restore;
|
Boolean undo_restore;
|
||||||
|
@ -811,6 +811,7 @@ typedef struct {
|
|||||||
uint16_t wl_size; // height in screen lines
|
uint16_t wl_size; // height in screen lines
|
||||||
char wl_valid; // true values are valid for text in buffer
|
char wl_valid; // true values are valid for text in buffer
|
||||||
char wl_folded; // true when this is a range of folded lines
|
char wl_folded; // true when this is a range of folded lines
|
||||||
|
linenr_T wl_foldend; // last buffer line number for folded line
|
||||||
linenr_T wl_lastlnum; // last buffer line number for logical line
|
linenr_T wl_lastlnum; // last buffer line number for logical line
|
||||||
} wline_T;
|
} wline_T;
|
||||||
|
|
||||||
|
@ -206,9 +206,10 @@ static void changed_lines_invalidate_win(win_T *wp, linenr_T lnum, colnr_T col,
|
|||||||
} else if (xtra != 0) {
|
} else if (xtra != 0) {
|
||||||
// line below change
|
// line below change
|
||||||
wp->w_lines[i].wl_lnum += xtra;
|
wp->w_lines[i].wl_lnum += xtra;
|
||||||
|
wp->w_lines[i].wl_foldend += xtra;
|
||||||
wp->w_lines[i].wl_lastlnum += xtra;
|
wp->w_lines[i].wl_lastlnum += xtra;
|
||||||
}
|
}
|
||||||
} else if (wp->w_lines[i].wl_lastlnum >= lnum) {
|
} else if (wp->w_lines[i].wl_foldend >= lnum) {
|
||||||
// change somewhere inside this range of folded lines,
|
// change somewhere inside this range of folded lines,
|
||||||
// may need to be redrawn
|
// may need to be redrawn
|
||||||
wp->w_lines[i].wl_valid = false;
|
wp->w_lines[i].wl_valid = false;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/change.h"
|
#include "nvim/change.h"
|
||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
|
#include "nvim/decoration_provider.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
#include "nvim/fold.h"
|
#include "nvim/fold.h"
|
||||||
@ -125,6 +126,13 @@ void decor_redraw_sh(buf_T *buf, int row1, int row2, DecorSignHighlight sh)
|
|||||||
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
|
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sh.flags & kSHConcealLines) {
|
||||||
|
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||||
|
if (wp->w_buffer == buf) {
|
||||||
|
changed_window_setting(wp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sh.flags & kSHUIWatched) {
|
if (sh.flags & kSHUIWatched) {
|
||||||
redraw_buf_line_later(buf, row1 + 1, false);
|
redraw_buf_line_later(buf, row1 + 1, false);
|
||||||
}
|
}
|
||||||
@ -833,8 +841,56 @@ int sign_item_cmp(const void *p1, const void *p2)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t sign_filter[4] = {[kMTMetaSignText] = kMTFilterSelect,
|
static const uint32_t conceal_filter[kMTMetaCount] = {[kMTMetaConcealLines] = kMTFilterSelect };
|
||||||
[kMTMetaSignHL] = kMTFilterSelect };
|
|
||||||
|
bool decor_conceal_line(win_T *wp, int row, bool check_cursor)
|
||||||
|
{
|
||||||
|
if (wp->w_p_cole < 2
|
||||||
|
|| (!check_cursor && ((row + 1 == wp->w_cursor.lnum) && !conceal_cursor_line(wp)))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t keys = wp->w_buffer->b_marktree->n_keys;
|
||||||
|
if (!buf_meta_total(wp->w_buffer, kMTMetaConcealLines)) {
|
||||||
|
decor_providers_invoke_conceal_line(wp, row);
|
||||||
|
return wp->w_buffer->b_marktree->n_keys > keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTPair pair;
|
||||||
|
MarkTreeIter itr[1];
|
||||||
|
marktree_itr_get_overlap(wp->w_buffer->b_marktree, row, 0, itr);
|
||||||
|
while (marktree_itr_step_overlap(wp->w_buffer->b_marktree, itr, &pair)) {
|
||||||
|
if (mt_conceal_lines(pair.start) && ns_in_win(pair.start.ns, wp)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marktree_itr_step_out_filter(wp->w_buffer->b_marktree, itr, conceal_filter);
|
||||||
|
|
||||||
|
while (itr->x) {
|
||||||
|
MTKey mark = marktree_itr_current(itr);
|
||||||
|
if (mark.pos.row > row) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mt_conceal_lines(mark) && ns_in_win(pair.start.ns, wp)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
marktree_itr_next_filter(wp->w_buffer->b_marktree, itr, row + 1, 0, conceal_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
decor_providers_invoke_conceal_line(wp, row);
|
||||||
|
return wp->w_buffer->b_marktree->n_keys > keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool win_lines_concealed(win_T *wp)
|
||||||
|
{
|
||||||
|
return hasAnyFolding(wp)
|
||||||
|
|| (wp->w_p_cole >= 2
|
||||||
|
&& (conceal_provider || buf_meta_total(wp->w_buffer, kMTMetaConcealLines)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t sign_filter[kMTMetaCount] = {[kMTMetaSignText] = kMTFilterSelect,
|
||||||
|
[kMTMetaSignHL] = kMTFilterSelect };
|
||||||
|
|
||||||
/// Return the sign attributes on the currently refreshed row.
|
/// Return the sign attributes on the currently refreshed row.
|
||||||
///
|
///
|
||||||
@ -856,7 +912,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
|
|||||||
// TODO(bfredl): integrate with main decor loop.
|
// TODO(bfredl): integrate with main decor loop.
|
||||||
marktree_itr_get_overlap(buf->b_marktree, row, 0, itr);
|
marktree_itr_get_overlap(buf->b_marktree, row, 0, itr);
|
||||||
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
|
||||||
if (!mt_invalid(pair.start) && mt_decor_sign(pair.start)) {
|
if (!mt_invalid(pair.start) && mt_decor_sign(pair.start) && ns_in_win(pair.start.ns, wp)) {
|
||||||
DecorSignHighlight *sh = decor_find_sign(mt_decor(pair.start));
|
DecorSignHighlight *sh = decor_find_sign(mt_decor(pair.start));
|
||||||
num_text += (sh->text[0] != NUL);
|
num_text += (sh->text[0] != NUL);
|
||||||
kv_push(signs, ((SignItem){ sh, pair.start.id }));
|
kv_push(signs, ((SignItem){ sh, pair.start.id }));
|
||||||
@ -923,7 +979,7 @@ DecorSignHighlight *decor_find_sign(DecorInline decor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t signtext_filter[4] = {[kMTMetaSignText] = kMTFilterSelect };
|
static const uint32_t signtext_filter[kMTMetaCount] = {[kMTMetaSignText] = kMTFilterSelect };
|
||||||
|
|
||||||
/// Count the number of signs in a range after adding/removing a sign, or to
|
/// Count the number of signs in a range after adding/removing a sign, or to
|
||||||
/// (re-)initialize a range in "b_signcols.count".
|
/// (re-)initialize a range in "b_signcols.count".
|
||||||
@ -1018,7 +1074,7 @@ bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col)
|
|||||||
return has_virt_pos;
|
return has_virt_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t lines_filter[4] = {[kMTMetaLines] = kMTFilterSelect };
|
static const uint32_t lines_filter[kMTMetaCount] = {[kMTMetaLines] = kMTFilterSelect };
|
||||||
|
|
||||||
/// @param apply_folds Only count virtual lines that are not in folds.
|
/// @param apply_folds Only count virtual lines that are not in folds.
|
||||||
int decor_virt_lines(win_T *wp, int start_row, int end_row, VirtLines *lines, bool apply_folds)
|
int decor_virt_lines(win_T *wp, int start_row, int end_row, VirtLines *lines, bool apply_folds)
|
||||||
@ -1049,7 +1105,8 @@ int decor_virt_lines(win_T *wp, int start_row, int end_row, VirtLines *lines, bo
|
|||||||
int mrow = mark.pos.row;
|
int mrow = mark.pos.row;
|
||||||
int draw_row = mrow + (above ? 0 : 1);
|
int draw_row = mrow + (above ? 0 : 1);
|
||||||
if (draw_row >= start_row && draw_row < end_row
|
if (draw_row >= start_row && draw_row < end_row
|
||||||
&& (!apply_folds || !hasFolding(wp, mrow + 1, NULL, NULL))) {
|
&& (!apply_folds || !(hasFolding(wp, mrow + 1, NULL, NULL)
|
||||||
|
|| decor_conceal_line(wp, mrow, false)))) {
|
||||||
virt_lines += (int)kv_size(vt->data.virt_lines);
|
virt_lines += (int)kv_size(vt->data.virt_lines);
|
||||||
if (lines) {
|
if (lines) {
|
||||||
kv_splice(*lines, vt->data.virt_lines);
|
kv_splice(*lines, vt->data.virt_lines);
|
||||||
@ -1116,6 +1173,10 @@ void decor_to_dict_legacy(Dict *dict, DecorInline decor, bool hl_name, Arena *ar
|
|||||||
PUT_C(*dict, "conceal", CSTR_TO_ARENA_OBJ(arena, buf));
|
PUT_C(*dict, "conceal", CSTR_TO_ARENA_OBJ(arena, buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sh_hl.flags & kSHConcealLines) {
|
||||||
|
PUT_C(*dict, "conceal_lines", STRING_OBJ(cstr_as_string("")));
|
||||||
|
}
|
||||||
|
|
||||||
if (sh_hl.flags & kSHSpellOn) {
|
if (sh_hl.flags & kSHSpellOn) {
|
||||||
PUT_C(*dict, "spell", BOOLEAN_OBJ(true));
|
PUT_C(*dict, "spell", BOOLEAN_OBJ(true));
|
||||||
} else if (sh_hl.flags & kSHSpellOff) {
|
} else if (sh_hl.flags & kSHSpellOff) {
|
||||||
|
@ -46,6 +46,7 @@ enum {
|
|||||||
kSHSpellOn = 16,
|
kSHSpellOn = 16,
|
||||||
kSHSpellOff = 32,
|
kSHSpellOff = 32,
|
||||||
kSHConceal = 64,
|
kSHConceal = 64,
|
||||||
|
kSHConcealLines = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -143,6 +144,7 @@ typedef struct {
|
|||||||
LuaRef redraw_end;
|
LuaRef redraw_end;
|
||||||
LuaRef hl_def;
|
LuaRef hl_def;
|
||||||
LuaRef spell_nav;
|
LuaRef spell_nav;
|
||||||
|
LuaRef conceal_line;
|
||||||
int hl_valid;
|
int hl_valid;
|
||||||
bool hl_cached;
|
bool hl_cached;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
|
|||||||
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
||||||
{ ns_id, kDecorProviderDisabled, LUA_NOREF, LUA_NOREF, \
|
{ ns_id, kDecorProviderDisabled, LUA_NOREF, LUA_NOREF, \
|
||||||
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
||||||
LUA_NOREF, -1, false, false, 0 }
|
LUA_NOREF, LUA_NOREF, -1, false, false, 0 }
|
||||||
|
|
||||||
static void decor_provider_error(DecorProvider *provider, const char *name, const char *msg)
|
static void decor_provider_error(DecorProvider *provider, const char *name, const char *msg)
|
||||||
{
|
{
|
||||||
@ -92,6 +92,21 @@ void decor_providers_invoke_spell(win_T *wp, int start_row, int start_col, int e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decor_providers_invoke_conceal_line(win_T *wp, int row)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < kv_size(decor_providers); i++) {
|
||||||
|
DecorProvider *p = &kv_A(decor_providers, i);
|
||||||
|
if (p->state != kDecorProviderDisabled && p->conceal_line != LUA_NOREF) {
|
||||||
|
conceal_provider = true;
|
||||||
|
MAXSIZE_TEMP_ARRAY(args, 4);
|
||||||
|
ADD_C(args, INTEGER_OBJ(wp->handle));
|
||||||
|
ADD_C(args, INTEGER_OBJ(wp->w_buffer->handle));
|
||||||
|
ADD_C(args, INTEGER_OBJ(row));
|
||||||
|
decor_provider_invoke((int)i, "conceal_line", p->conceal_line, args, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// For each provider invoke the 'start' callback
|
/// For each provider invoke the 'start' callback
|
||||||
///
|
///
|
||||||
/// @param[out] providers Decoration providers
|
/// @param[out] providers Decoration providers
|
||||||
@ -264,6 +279,7 @@ void decor_provider_clear(DecorProvider *p)
|
|||||||
NLUA_CLEAR_REF(p->redraw_line);
|
NLUA_CLEAR_REF(p->redraw_line);
|
||||||
NLUA_CLEAR_REF(p->redraw_end);
|
NLUA_CLEAR_REF(p->redraw_end);
|
||||||
NLUA_CLEAR_REF(p->spell_nav);
|
NLUA_CLEAR_REF(p->spell_nav);
|
||||||
|
NLUA_CLEAR_REF(p->conceal_line);
|
||||||
p->state = kDecorProviderDisabled;
|
p->state = kDecorProviderDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||||
|
|
||||||
EXTERN bool provider_active INIT( = false);
|
EXTERN bool provider_active INIT( = false);
|
||||||
|
EXTERN bool conceal_provider INIT( = false);
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "decoration_provider.h.generated.h"
|
# include "decoration_provider.h.generated.h"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "nvim/change.h"
|
#include "nvim/change.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/diff.h"
|
#include "nvim/diff.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/errors.h"
|
#include "nvim/errors.h"
|
||||||
@ -2082,7 +2083,7 @@ int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A closed fold never has filler lines.
|
// A closed fold never has filler lines.
|
||||||
if (hasFolding(wp, lnum, NULL, NULL)) {
|
if (hasFolding(wp, lnum, NULL, NULL) || decor_conceal_line(wp, lnum - 1, false)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +955,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
bool area_highlighting = false; // Visual or incsearch highlighting in this line
|
bool area_highlighting = false; // Visual or incsearch highlighting in this line
|
||||||
int vi_attr = 0; // attributes for Visual and incsearch highlighting
|
int vi_attr = 0; // attributes for Visual and incsearch highlighting
|
||||||
int area_attr = 0; // attributes desired by highlighting
|
int area_attr = 0; // attributes desired by highlighting
|
||||||
int search_attr = 0; // attributes desired by 'hlsearch'
|
int search_attr = 0; // attributes desired by 'hlsearch' or ComplMatchIns
|
||||||
int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
|
int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
|
||||||
int decor_attr = 0; // attributes desired by syntax and extmarks
|
int decor_attr = 0; // attributes desired by syntax and extmarks
|
||||||
bool has_syntax = false; // this buffer has syntax highl.
|
bool has_syntax = false; // this buffer has syntax highl.
|
||||||
@ -969,7 +969,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
int spell_attr = 0; // attributes desired by spelling
|
int spell_attr = 0; // attributes desired by spelling
|
||||||
int word_end = 0; // last byte with same spell_attr
|
int word_end = 0; // last byte with same spell_attr
|
||||||
int cur_checked_col = 0; // checked column for current line
|
int cur_checked_col = 0; // checked column for current line
|
||||||
bool extra_check = 0; // has syntax or linebreak
|
bool extra_check = false; // has extra highlighting
|
||||||
int multi_attr = 0; // attributes desired by multibyte
|
int multi_attr = 0; // attributes desired by multibyte
|
||||||
int mb_l = 1; // multi-byte byte length
|
int mb_l = 1; // multi-byte byte length
|
||||||
int mb_c = 0; // decoded multi-byte character
|
int mb_c = 0; // decoded multi-byte character
|
||||||
@ -1495,6 +1495,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
ptr = line + v; // "line" may have been updated
|
ptr = line + v; // "line" may have been updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
|
||||||
|
area_highlighting = true;
|
||||||
|
}
|
||||||
|
|
||||||
win_line_start(wp, &wlv);
|
win_line_start(wp, &wlv);
|
||||||
bool draw_cols = true;
|
bool draw_cols = true;
|
||||||
int leftcols_width = 0;
|
int leftcols_width = 0;
|
||||||
@ -1740,6 +1744,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
if (*ptr == NUL) {
|
if (*ptr == NUL) {
|
||||||
has_match_conc = 0;
|
has_match_conc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if ComplMatchIns highlight is needed.
|
||||||
|
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
|
||||||
|
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
|
||||||
|
if (ins_match_attr > 0) {
|
||||||
|
search_attr = hl_combine_attr(search_attr, ins_match_attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlv.diff_hlf != (hlf_T)0) {
|
if (wlv.diff_hlf != (hlf_T)0) {
|
||||||
@ -1787,16 +1799,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
|
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply ComplMatchIns highlight if needed.
|
|
||||||
if (wlv.filler_todo <= 0
|
|
||||||
&& (State & MODE_INSERT) && in_curline && ins_compl_active()) {
|
|
||||||
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
|
|
||||||
if (ins_match_attr > 0) {
|
|
||||||
char_attr_pri = hl_combine_attr(char_attr_pri, ins_match_attr);
|
|
||||||
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
|
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
|
||||||
const int v = (int)(ptr - line);
|
const int v = (int)(ptr - line);
|
||||||
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
|
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
|
||||||
|
@ -148,6 +148,11 @@ void conceal_check_cursor_line(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
redrawWinline(curwin, curwin->w_cursor.lnum);
|
redrawWinline(curwin, curwin->w_cursor.lnum);
|
||||||
|
|
||||||
|
// Concealed line visibility toggled.
|
||||||
|
if (decor_conceal_line(curwin, curwin->w_cursor.lnum - 1, true)) {
|
||||||
|
changed_window_setting(curwin);
|
||||||
|
}
|
||||||
// Need to recompute cursor column, e.g., when starting Visual mode
|
// Need to recompute cursor column, e.g., when starting Visual mode
|
||||||
// without concealing.
|
// without concealing.
|
||||||
curs_columns(curwin, true);
|
curs_columns(curwin, true);
|
||||||
@ -1622,7 +1627,7 @@ static void win_update(win_T *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mod_top != 0 && hasAnyFolding(wp)) {
|
if (mod_top != 0 && (win_lines_concealed(wp))) {
|
||||||
// A change in a line can cause lines above it to become folded or
|
// A change in a line can cause lines above it to become folded or
|
||||||
// unfolded. Find the top most buffer line that may be affected.
|
// unfolded. Find the top most buffer line that may be affected.
|
||||||
// If the line was previously folded and displayed, get the first
|
// If the line was previously folded and displayed, get the first
|
||||||
@ -1719,12 +1724,12 @@ static void win_update(win_T *wp)
|
|||||||
&& wp->w_topfill > wp->w_old_topfill))) {
|
&& wp->w_topfill > wp->w_old_topfill))) {
|
||||||
// New topline is above old topline: May scroll down.
|
// New topline is above old topline: May scroll down.
|
||||||
int j;
|
int j;
|
||||||
if (hasAnyFolding(wp)) {
|
if (win_lines_concealed(wp)) {
|
||||||
// count the number of lines we are off, counting a sequence
|
// Count the number of lines we are off, counting a sequence
|
||||||
// of folded lines as one
|
// of folded lines as one, and skip concealed lines.
|
||||||
j = 0;
|
j = 0;
|
||||||
for (linenr_T ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) {
|
for (linenr_T ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) {
|
||||||
j++;
|
j += !decor_conceal_line(wp, ln - 1, false);
|
||||||
if (j >= wp->w_grid.rows - 2) {
|
if (j >= wp->w_grid.rows - 2) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2109,6 +2114,28 @@ static void win_update(win_T *wp)
|
|||||||
top_to_mod = false;
|
top_to_mod = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When lines are folded, display one line for all of them.
|
||||||
|
// Otherwise, display normally (can be several display lines when
|
||||||
|
// 'wrap' is on).
|
||||||
|
foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum
|
||||||
|
? cursorline_fi : fold_info(wp, lnum);
|
||||||
|
|
||||||
|
// Concealed line: continue to next line on the same row.
|
||||||
|
if (decor_conceal_line(wp, lnum - 1, false)) {
|
||||||
|
if (wp == curwin && lnum == curwin->w_cursor.lnum) {
|
||||||
|
conceal_cursor_used = conceal_cursor_line(curwin);
|
||||||
|
}
|
||||||
|
if (idx > 0) {
|
||||||
|
wp->w_lines[idx - 1].wl_lastlnum = lnum + foldinfo.fi_lines - 1;
|
||||||
|
}
|
||||||
|
if (lnum == mod_top && lnum < mod_bot) {
|
||||||
|
mod_top += foldinfo.fi_lines ? foldinfo.fi_lines : 1;
|
||||||
|
}
|
||||||
|
lnum += foldinfo.fi_lines ? foldinfo.fi_lines : 1;
|
||||||
|
spv.spv_capcol_lnum = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// When at start of changed lines: May scroll following lines
|
// When at start of changed lines: May scroll following lines
|
||||||
// up or down to minimize redrawing.
|
// up or down to minimize redrawing.
|
||||||
// Don't do this when the change continues until the end.
|
// Don't do this when the change continues until the end.
|
||||||
@ -2158,8 +2185,10 @@ static void win_update(win_T *wp)
|
|||||||
// rows, and may insert/delete lines
|
// rows, and may insert/delete lines
|
||||||
int j = idx;
|
int j = idx;
|
||||||
for (l = lnum; l < mod_bot; l++) {
|
for (l = lnum; l < mod_bot; l++) {
|
||||||
|
linenr_T first = l;
|
||||||
|
int prev_rows = new_rows;
|
||||||
if (hasFolding(wp, l, NULL, &l)) {
|
if (hasFolding(wp, l, NULL, &l)) {
|
||||||
new_rows++;
|
new_rows += !decor_conceal_line(wp, first - 1, false);
|
||||||
} else if (l == wp->w_topline) {
|
} else if (l == wp->w_topline) {
|
||||||
int n = plines_win_nofill(wp, l, false) + wp->w_topfill
|
int n = plines_win_nofill(wp, l, false) + wp->w_topfill
|
||||||
- adjust_plines_for_skipcol(wp);
|
- adjust_plines_for_skipcol(wp);
|
||||||
@ -2168,7 +2197,8 @@ static void win_update(win_T *wp)
|
|||||||
} else {
|
} else {
|
||||||
new_rows += plines_win(wp, l, true);
|
new_rows += plines_win(wp, l, true);
|
||||||
}
|
}
|
||||||
j++;
|
// Do not increment when height was 0 (for a concealed line).
|
||||||
|
j += (prev_rows != new_rows);
|
||||||
if (new_rows > wp->w_grid.rows - row - 2) {
|
if (new_rows > wp->w_grid.rows - row - 2) {
|
||||||
// it's getting too much, must redraw the rest
|
// it's getting too much, must redraw the rest
|
||||||
new_rows = 9999;
|
new_rows = 9999;
|
||||||
@ -2250,12 +2280,6 @@ static void win_update(win_T *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When lines are folded, display one line for all of them.
|
|
||||||
// Otherwise, display normally (can be several display lines when
|
|
||||||
// 'wrap' is on).
|
|
||||||
foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum
|
|
||||||
? cursorline_fi : fold_info(wp, lnum);
|
|
||||||
|
|
||||||
if (foldinfo.fi_lines == 0
|
if (foldinfo.fi_lines == 0
|
||||||
&& idx < wp->w_lines_valid
|
&& idx < wp->w_lines_valid
|
||||||
&& wp->w_lines[idx].wl_valid
|
&& wp->w_lines[idx].wl_valid
|
||||||
@ -2290,11 +2314,13 @@ static void win_update(win_T *wp)
|
|||||||
|
|
||||||
if (foldinfo.fi_lines == 0) {
|
if (foldinfo.fi_lines == 0) {
|
||||||
wp->w_lines[idx].wl_folded = false;
|
wp->w_lines[idx].wl_folded = false;
|
||||||
|
wp->w_lines[idx].wl_foldend = lnum;
|
||||||
wp->w_lines[idx].wl_lastlnum = lnum;
|
wp->w_lines[idx].wl_lastlnum = lnum;
|
||||||
did_update = DID_LINE;
|
did_update = DID_LINE;
|
||||||
} else {
|
} else {
|
||||||
foldinfo.fi_lines--;
|
foldinfo.fi_lines--;
|
||||||
wp->w_lines[idx].wl_folded = true;
|
wp->w_lines[idx].wl_folded = true;
|
||||||
|
wp->w_lines[idx].wl_foldend = lnum + foldinfo.fi_lines;
|
||||||
wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines;
|
wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines;
|
||||||
did_update = DID_FOLD;
|
did_update = DID_FOLD;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "nvim/change.h"
|
#include "nvim/change.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/digraph.h"
|
#include "nvim/digraph.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/edit.h"
|
#include "nvim/edit.h"
|
||||||
@ -2577,15 +2578,15 @@ int oneleft(void)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the cursor up "n" lines in window "wp".
|
/// Move the cursor up "n" lines in window "wp". Takes care of closed folds.
|
||||||
/// Takes care of closed folds.
|
/// Skips over concealed lines when "skip_conceal" is true.
|
||||||
void cursor_up_inner(win_T *wp, linenr_T n)
|
void cursor_up_inner(win_T *wp, linenr_T n, bool skip_conceal)
|
||||||
{
|
{
|
||||||
linenr_T lnum = wp->w_cursor.lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
|
|
||||||
if (n >= lnum) {
|
if (n >= lnum) {
|
||||||
lnum = 1;
|
lnum = 1;
|
||||||
} else if (hasAnyFolding(wp)) {
|
} else if (win_lines_concealed(wp)) {
|
||||||
// Count each sequence of folded lines as one logical line.
|
// Count each sequence of folded lines as one logical line.
|
||||||
|
|
||||||
// go to the start of the current fold
|
// go to the start of the current fold
|
||||||
@ -2594,6 +2595,7 @@ void cursor_up_inner(win_T *wp, linenr_T n)
|
|||||||
while (n--) {
|
while (n--) {
|
||||||
// move up one line
|
// move up one line
|
||||||
lnum--;
|
lnum--;
|
||||||
|
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
|
||||||
if (lnum <= 1) {
|
if (lnum <= 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2619,7 +2621,7 @@ int cursor_up(linenr_T n, bool upd_topline)
|
|||||||
if (n > 0 && curwin->w_cursor.lnum <= 1) {
|
if (n > 0 && curwin->w_cursor.lnum <= 1) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
cursor_up_inner(curwin, n);
|
cursor_up_inner(curwin, n, false);
|
||||||
|
|
||||||
// try to advance to the column we want to be at
|
// try to advance to the column we want to be at
|
||||||
coladvance(curwin, curwin->w_curswant);
|
coladvance(curwin, curwin->w_curswant);
|
||||||
@ -2631,16 +2633,16 @@ int cursor_up(linenr_T n, bool upd_topline)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the cursor down "n" lines in window "wp".
|
/// Move the cursor down "n" lines in window "wp". Takes care of closed folds.
|
||||||
/// Takes care of closed folds.
|
/// Skips over concealed lines when "skip_conceal" is true.
|
||||||
void cursor_down_inner(win_T *wp, int n)
|
void cursor_down_inner(win_T *wp, int n, bool skip_conceal)
|
||||||
{
|
{
|
||||||
linenr_T lnum = wp->w_cursor.lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
|
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
|
||||||
|
|
||||||
if (lnum + n >= line_count) {
|
if (lnum + n >= line_count) {
|
||||||
lnum = line_count;
|
lnum = line_count;
|
||||||
} else if (hasAnyFolding(wp)) {
|
} else if (win_lines_concealed(wp)) {
|
||||||
linenr_T last;
|
linenr_T last;
|
||||||
|
|
||||||
// count each sequence of folded lines as one logical line
|
// count each sequence of folded lines as one logical line
|
||||||
@ -2650,6 +2652,7 @@ void cursor_down_inner(win_T *wp, int n)
|
|||||||
} else {
|
} else {
|
||||||
lnum++;
|
lnum++;
|
||||||
}
|
}
|
||||||
|
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
|
||||||
if (lnum >= line_count) {
|
if (lnum >= line_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2671,7 +2674,7 @@ int cursor_down(int n, bool upd_topline)
|
|||||||
if (n > 0 && lnum >= curwin->w_buffer->b_ml.ml_line_count) {
|
if (n > 0 && lnum >= curwin->w_buffer->b_ml.ml_line_count) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
cursor_down_inner(curwin, n);
|
cursor_down_inner(curwin, n, false);
|
||||||
|
|
||||||
// try to advance to the column we want to be at
|
// try to advance to the column we want to be at
|
||||||
coladvance(curwin, curwin->w_curswant);
|
coladvance(curwin, curwin->w_curswant);
|
||||||
|
@ -194,7 +194,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp
|
|||||||
const int x = find_wl_entry(win, lnum);
|
const int x = find_wl_entry(win, lnum);
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
first = win->w_lines[x].wl_lnum;
|
first = win->w_lines[x].wl_lnum;
|
||||||
last = win->w_lines[x].wl_lastlnum;
|
last = win->w_lines[x].wl_foldend;
|
||||||
had_folded = win->w_lines[x].wl_folded;
|
had_folded = win->w_lines[x].wl_folded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -971,7 +971,7 @@ int find_wl_entry(win_T *win, linenr_T lnum)
|
|||||||
if (lnum < win->w_lines[i].wl_lnum) {
|
if (lnum < win->w_lines[i].wl_lnum) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lnum <= win->w_lines[i].wl_lastlnum) {
|
if (lnum <= win->w_lines[i].wl_foldend) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ static const char *highlight_init_both[] = {
|
|||||||
"default link PmenuKind Pmenu",
|
"default link PmenuKind Pmenu",
|
||||||
"default link PmenuKindSel PmenuSel",
|
"default link PmenuKindSel PmenuSel",
|
||||||
"default link PmenuSbar Pmenu",
|
"default link PmenuSbar Pmenu",
|
||||||
"default link ComplMatchIns Normal",
|
"default link ComplMatchIns NONE",
|
||||||
"default link Substitute Search",
|
"default link Substitute Search",
|
||||||
"default link StatusLineTerm StatusLine",
|
"default link StatusLineTerm StatusLine",
|
||||||
"default link StatusLineTermNC StatusLineNC",
|
"default link StatusLineTermNC StatusLineNC",
|
||||||
|
@ -958,7 +958,7 @@ static void ins_compl_insert_bytes(char *p, int len)
|
|||||||
}
|
}
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
ins_bytes_len(p, (size_t)len);
|
ins_bytes_len(p, (size_t)len);
|
||||||
compl_ins_end_col = curwin->w_cursor.col - 1;
|
compl_ins_end_col = curwin->w_cursor.col;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the column is within the currently inserted completion text
|
/// Checks if the column is within the currently inserted completion text
|
||||||
@ -2147,6 +2147,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
|
|||||||
&& pum_visible()) {
|
&& pum_visible()) {
|
||||||
word = xstrdup(compl_shown_match->cp_str);
|
word = xstrdup(compl_shown_match->cp_str);
|
||||||
retval = true;
|
retval = true;
|
||||||
|
// May need to remove ComplMatchIns highlight.
|
||||||
|
redrawWinline(curwin, curwin->w_cursor.lnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL-E means completion is Ended, go back to the typed text.
|
// CTRL-E means completion is Ended, go back to the typed text.
|
||||||
@ -3648,6 +3650,7 @@ void ins_compl_delete(bool new_leader)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
backspace_until_column(col);
|
backspace_until_column(col);
|
||||||
|
compl_ins_end_col = curwin->w_cursor.col;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(vim): is this sufficient for redrawing? Redrawing everything
|
// TODO(vim): is this sufficient for redrawing? Redrawing everything
|
||||||
|
@ -250,7 +250,7 @@ static inline void split_node(MarkTree *b, MTNode *x, const int i, MTKey next)
|
|||||||
refkey(b, x, i);
|
refkey(b, x, i);
|
||||||
x->n++;
|
x->n++;
|
||||||
|
|
||||||
uint32_t meta_inc[4];
|
uint32_t meta_inc[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc, x->key[i]);
|
meta_describe_key(meta_inc, x->key[i]);
|
||||||
for (int m = 0; m < kMTMetaCount; m++) {
|
for (int m = 0; m < kMTMetaCount; m++) {
|
||||||
// y used contain all of z and x->key[i], discount those
|
// y used contain all of z and x->key[i], discount those
|
||||||
@ -451,6 +451,7 @@ static void meta_describe_key_inc(uint32_t *meta_inc, MTKey *k)
|
|||||||
meta_inc[kMTMetaLines] += (k->flags & MT_FLAG_DECOR_VIRT_LINES) ? 1 : 0;
|
meta_inc[kMTMetaLines] += (k->flags & MT_FLAG_DECOR_VIRT_LINES) ? 1 : 0;
|
||||||
meta_inc[kMTMetaSignHL] += (k->flags & MT_FLAG_DECOR_SIGNHL) ? 1 : 0;
|
meta_inc[kMTMetaSignHL] += (k->flags & MT_FLAG_DECOR_SIGNHL) ? 1 : 0;
|
||||||
meta_inc[kMTMetaSignText] += (k->flags & MT_FLAG_DECOR_SIGNTEXT) ? 1 : 0;
|
meta_inc[kMTMetaSignText] += (k->flags & MT_FLAG_DECOR_SIGNTEXT) ? 1 : 0;
|
||||||
|
meta_inc[kMTMetaConcealLines] += (k->flags & MT_FLAG_DECOR_CONCEAL_LINES) ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,10 +506,10 @@ void marktree_put_key(MarkTree *b, MTKey k)
|
|||||||
r = s;
|
r = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t meta_inc[4];
|
uint32_t meta_inc[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc, k);
|
meta_describe_key(meta_inc, k);
|
||||||
marktree_putp_aux(b, r, k, meta_inc);
|
marktree_putp_aux(b, r, k, meta_inc);
|
||||||
for (int m = 0; m < 4; m++) {
|
for (int m = 0; m < kMTMetaCount; m++) {
|
||||||
b->meta_root[m] += meta_inc[m];
|
b->meta_root[m] += meta_inc[m];
|
||||||
}
|
}
|
||||||
b->n_keys++;
|
b->n_keys++;
|
||||||
@ -579,7 +580,7 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
|
|||||||
assert(x->level == 0);
|
assert(x->level == 0);
|
||||||
MTKey intkey = x->key[itr->i];
|
MTKey intkey = x->key[itr->i];
|
||||||
|
|
||||||
uint32_t meta_inc[4];
|
uint32_t meta_inc[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc, intkey);
|
meta_describe_key(meta_inc, intkey);
|
||||||
if (x->n > itr->i + 1) {
|
if (x->n > itr->i + 1) {
|
||||||
memmove(&x->key[itr->i], &x->key[itr->i + 1],
|
memmove(&x->key[itr->i], &x->key[itr->i + 1],
|
||||||
@ -776,7 +777,7 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
|
|||||||
|
|
||||||
void marktree_revise_meta(MarkTree *b, MarkTreeIter *itr, MTKey old_key)
|
void marktree_revise_meta(MarkTree *b, MarkTreeIter *itr, MTKey old_key)
|
||||||
{
|
{
|
||||||
uint32_t meta_old[4], meta_new[4];
|
uint32_t meta_old[kMTMetaCount], meta_new[kMTMetaCount];
|
||||||
meta_describe_key(meta_old, old_key);
|
meta_describe_key(meta_old, old_key);
|
||||||
meta_describe_key(meta_new, rawkey(itr));
|
meta_describe_key(meta_new, rawkey(itr));
|
||||||
|
|
||||||
@ -1038,7 +1039,7 @@ static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
|
|||||||
relative(p->key[i - 1].pos, &x->key[x->n].pos);
|
relative(p->key[i - 1].pos, &x->key[x->n].pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t meta_inc[4];
|
uint32_t meta_inc[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc, x->key[x->n]);
|
meta_describe_key(meta_inc, x->key[x->n]);
|
||||||
|
|
||||||
memmove(&x->key[x->n + 1], y->key, (size_t)y->n * sizeof(MTKey));
|
memmove(&x->key[x->n + 1], y->key, (size_t)y->n * sizeof(MTKey));
|
||||||
@ -1128,9 +1129,9 @@ static void pivot_right(MarkTree *b, MTPos p_pos, MTNode *p, const int i)
|
|||||||
p->key[i] = x->key[x->n - 1];
|
p->key[i] = x->key[x->n - 1];
|
||||||
refkey(b, p, i);
|
refkey(b, p, i);
|
||||||
|
|
||||||
uint32_t meta_inc_y[4];
|
uint32_t meta_inc_y[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_y, y->key[0]);
|
meta_describe_key(meta_inc_y, y->key[0]);
|
||||||
uint32_t meta_inc_x[4];
|
uint32_t meta_inc_x[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_x, p->key[i]);
|
meta_describe_key(meta_inc_x, p->key[i]);
|
||||||
|
|
||||||
for (int m = 0; m < kMTMetaCount; m++) {
|
for (int m = 0; m < kMTMetaCount; m++) {
|
||||||
@ -1214,9 +1215,9 @@ static void pivot_left(MarkTree *b, MTPos p_pos, MTNode *p, int i)
|
|||||||
p->key[i] = y->key[0];
|
p->key[i] = y->key[0];
|
||||||
refkey(b, p, i);
|
refkey(b, p, i);
|
||||||
|
|
||||||
uint32_t meta_inc_x[4];
|
uint32_t meta_inc_x[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_x, x->key[x->n]);
|
meta_describe_key(meta_inc_x, x->key[x->n]);
|
||||||
uint32_t meta_inc_y[4];
|
uint32_t meta_inc_y[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_y, p->key[i]);
|
meta_describe_key(meta_inc_y, p->key[i]);
|
||||||
for (int m = 0; m < kMTMetaCount; m++) {
|
for (int m = 0; m < kMTMetaCount; m++) {
|
||||||
p->meta[i][m] += meta_inc_x[m];
|
p->meta[i][m] += meta_inc_x[m];
|
||||||
@ -1619,8 +1620,13 @@ bool marktree_itr_next_filter(MarkTree *b, MarkTreeIter *itr, int stop_row, int
|
|||||||
return marktree_itr_check_filter(b, itr, stop_row, stop_col, meta_filter);
|
return marktree_itr_check_filter(b, itr, stop_row, stop_col, meta_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t meta_map[4] = { MT_FLAG_DECOR_VIRT_TEXT_INLINE, MT_FLAG_DECOR_VIRT_LINES,
|
const uint32_t meta_map[kMTMetaCount] = {
|
||||||
MT_FLAG_DECOR_SIGNHL, MT_FLAG_DECOR_SIGNTEXT };
|
MT_FLAG_DECOR_VIRT_TEXT_INLINE,
|
||||||
|
MT_FLAG_DECOR_VIRT_LINES,
|
||||||
|
MT_FLAG_DECOR_SIGNHL,
|
||||||
|
MT_FLAG_DECOR_SIGNTEXT,
|
||||||
|
MT_FLAG_DECOR_CONCEAL_LINES
|
||||||
|
};
|
||||||
static bool marktree_itr_check_filter(MarkTree *b, MarkTreeIter *itr, int stop_row, int stop_col,
|
static bool marktree_itr_check_filter(MarkTree *b, MarkTreeIter *itr, int stop_row, int stop_col,
|
||||||
MetaFilter meta_filter)
|
MetaFilter meta_filter)
|
||||||
{
|
{
|
||||||
@ -1860,9 +1866,9 @@ static void swap_keys(MarkTree *b, MarkTreeIter *itr1, MarkTreeIter *itr2, Damag
|
|||||||
itr2->i, itr1->i }));
|
itr2->i, itr1->i }));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t meta_inc_1[4];
|
uint32_t meta_inc_1[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_1, rawkey(itr1));
|
meta_describe_key(meta_inc_1, rawkey(itr1));
|
||||||
uint32_t meta_inc_2[4];
|
uint32_t meta_inc_2[kMTMetaCount];
|
||||||
meta_describe_key(meta_inc_2, rawkey(itr2));
|
meta_describe_key(meta_inc_2, rawkey(itr2));
|
||||||
|
|
||||||
if (memcmp(meta_inc_1, meta_inc_2, sizeof(meta_inc_1)) != 0) {
|
if (memcmp(meta_inc_1, meta_inc_2, sizeof(meta_inc_1)) != 0) {
|
||||||
@ -2373,7 +2379,7 @@ size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right
|
|||||||
*last = x->key[x->n - 1].pos;
|
*last = x->key[x->n - 1].pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t meta_node[4];
|
uint32_t meta_node[kMTMetaCount];
|
||||||
meta_describe_node(meta_node, x);
|
meta_describe_node(meta_node, x);
|
||||||
for (int m = 0; m < kMTMetaCount; m++) {
|
for (int m = 0; m < kMTMetaCount; m++) {
|
||||||
assert(meta_node_ref[m] == meta_node[m]);
|
assert(meta_node_ref[m] == meta_node[m]);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#define MT_FLAG_DECOR_SIGNHL (((uint16_t)1) << 10)
|
#define MT_FLAG_DECOR_SIGNHL (((uint16_t)1) << 10)
|
||||||
#define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11)
|
#define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11)
|
||||||
#define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12)
|
#define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12)
|
||||||
|
#define MT_FLAG_DECOR_CONCEAL_LINES (((uint16_t)1) << 13)
|
||||||
|
|
||||||
// These _must_ be last to preserve ordering of marks
|
// These _must_ be last to preserve ordering of marks
|
||||||
#define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14)
|
#define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14)
|
||||||
@ -43,8 +44,8 @@
|
|||||||
| MT_FLAG_DECOR_SIGNHL | MT_FLAG_DECOR_VIRT_LINES \
|
| MT_FLAG_DECOR_SIGNHL | MT_FLAG_DECOR_VIRT_LINES \
|
||||||
| MT_FLAG_DECOR_VIRT_TEXT_INLINE)
|
| MT_FLAG_DECOR_VIRT_TEXT_INLINE)
|
||||||
|
|
||||||
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \
|
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO | MT_FLAG_INVALIDATE \
|
||||||
| MT_FLAG_INVALIDATE | MT_FLAG_INVALID)
|
| MT_FLAG_INVALID | MT_FLAG_DECOR_CONCEAL_LINES)
|
||||||
|
|
||||||
// this is defined so that start and end of the same range have adjacent ids
|
// this is defined so that start and end of the same range have adjacent ids
|
||||||
#define MARKTREE_END_FLAG ((uint64_t)1)
|
#define MARKTREE_END_FLAG ((uint64_t)1)
|
||||||
@ -108,6 +109,11 @@ static inline bool mt_decor_sign(MTKey key)
|
|||||||
return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL);
|
return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool mt_conceal_lines(MTKey key)
|
||||||
|
{
|
||||||
|
return key.flags & MT_FLAG_DECOR_CONCEAL_LINES;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext)
|
static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext)
|
||||||
{
|
{
|
||||||
return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0)
|
return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0)
|
||||||
|
@ -22,13 +22,12 @@ typedef struct {
|
|||||||
} MTPos;
|
} MTPos;
|
||||||
#define MTPos(r, c) ((MTPos){ .row = (r), .col = (c) })
|
#define MTPos(r, c) ((MTPos){ .row = (r), .col = (c) })
|
||||||
|
|
||||||
// Currently there are four counts, which makes for a uint32_t[4] per node
|
|
||||||
// which makes for nice autovectorization into a single XMM or NEON register
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kMTMetaInline,
|
kMTMetaInline,
|
||||||
kMTMetaLines,
|
kMTMetaLines,
|
||||||
kMTMetaSignHL,
|
kMTMetaSignHL,
|
||||||
kMTMetaSignText,
|
kMTMetaSignText,
|
||||||
|
kMTMetaConcealLines,
|
||||||
kMTMetaCount, // sentinel, must be last
|
kMTMetaCount, // sentinel, must be last
|
||||||
} MetaIndex;
|
} MetaIndex;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/diff.h"
|
#include "nvim/diff.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/edit.h"
|
#include "nvim/edit.h"
|
||||||
@ -318,14 +319,13 @@ void update_topline(win_T *wp)
|
|||||||
halfheight = 2;
|
halfheight = 2;
|
||||||
}
|
}
|
||||||
int64_t n;
|
int64_t n;
|
||||||
if (hasAnyFolding(wp)) {
|
if (win_lines_concealed(wp)) {
|
||||||
// Count the number of logical lines between the cursor and
|
// Count the number of logical lines between the cursor and
|
||||||
// topline + p_so (approximation of how much will be
|
// topline + p_so (approximation of how much will be
|
||||||
// scrolled).
|
// scrolled).
|
||||||
n = 0;
|
n = 0;
|
||||||
for (linenr_T lnum = wp->w_cursor.lnum;
|
for (linenr_T lnum = wp->w_cursor.lnum; lnum < wp->w_topline + *so_ptr; lnum++) {
|
||||||
lnum < wp->w_topline + *so_ptr; lnum++) {
|
n += !decor_conceal_line(wp, lnum, false);
|
||||||
n++;
|
|
||||||
// stop at end of file or when we know we are far off
|
// stop at end of file or when we know we are far off
|
||||||
assert(wp->w_buffer != 0);
|
assert(wp->w_buffer != 0);
|
||||||
if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) {
|
if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) {
|
||||||
@ -367,7 +367,7 @@ void update_topline(win_T *wp)
|
|||||||
assert(wp->w_buffer != 0);
|
assert(wp->w_buffer != 0);
|
||||||
if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) {
|
if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) {
|
||||||
if (wp->w_cursor.lnum < wp->w_botline) {
|
if (wp->w_cursor.lnum < wp->w_botline) {
|
||||||
if ((wp->w_cursor.lnum >= wp->w_botline - *so_ptr || hasAnyFolding(wp))) {
|
if ((wp->w_cursor.lnum >= wp->w_botline - *so_ptr || win_lines_concealed(wp))) {
|
||||||
lineoff_T loff;
|
lineoff_T loff;
|
||||||
|
|
||||||
// Cursor is (a few lines) above botline, check if there are
|
// Cursor is (a few lines) above botline, check if there are
|
||||||
@ -399,13 +399,12 @@ void update_topline(win_T *wp)
|
|||||||
}
|
}
|
||||||
if (check_botline) {
|
if (check_botline) {
|
||||||
int line_count = 0;
|
int line_count = 0;
|
||||||
if (hasAnyFolding(wp)) {
|
if (win_lines_concealed(wp)) {
|
||||||
// Count the number of logical lines between the cursor and
|
// Count the number of logical lines between the cursor and
|
||||||
// botline - p_so (approximation of how much will be
|
// botline - p_so (approximation of how much will be
|
||||||
// scrolled).
|
// scrolled).
|
||||||
for (linenr_T lnum = wp->w_cursor.lnum;
|
for (linenr_T lnum = wp->w_cursor.lnum; lnum >= wp->w_botline - *so_ptr; lnum--) {
|
||||||
lnum >= wp->w_botline - *so_ptr; lnum--) {
|
line_count += !decor_conceal_line(wp, lnum - 1, false);
|
||||||
line_count++;
|
|
||||||
// stop at end of file or when we know we are far off
|
// stop at end of file or when we know we are far off
|
||||||
if (lnum <= 0 || line_count > wp->w_height_inner + 1) {
|
if (lnum <= 0 || line_count > wp->w_height_inner + 1) {
|
||||||
break;
|
break;
|
||||||
@ -462,7 +461,7 @@ static int scrolljump_value(win_T *wp)
|
|||||||
static bool check_top_offset(win_T *wp)
|
static bool check_top_offset(win_T *wp)
|
||||||
{
|
{
|
||||||
int so = get_scrolloff_value(wp);
|
int so = get_scrolloff_value(wp);
|
||||||
if (wp->w_cursor.lnum < wp->w_topline + so || hasAnyFolding(wp)) {
|
if (wp->w_cursor.lnum < wp->w_topline + so || win_lines_concealed(wp)) {
|
||||||
lineoff_T loff;
|
lineoff_T loff;
|
||||||
loff.lnum = wp->w_cursor.lnum;
|
loff.lnum = wp->w_cursor.lnum;
|
||||||
loff.fill = 0;
|
loff.fill = 0;
|
||||||
@ -506,6 +505,13 @@ void check_cursor_moved(win_T *wp)
|
|||||||
if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) {
|
if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) {
|
||||||
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
|
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
|
||||||
|VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
|
|VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
|
||||||
|
|
||||||
|
// Concealed line visibility toggled.
|
||||||
|
if (wp->w_p_cole >= 2 && !conceal_cursor_line(wp)
|
||||||
|
&& (decor_conceal_line(wp, wp->w_cursor.lnum - 1, true)
|
||||||
|
|| decor_conceal_line(wp, wp->w_valid_cursor.lnum - 1, true))) {
|
||||||
|
changed_window_setting(wp);
|
||||||
|
}
|
||||||
wp->w_valid_cursor = wp->w_cursor;
|
wp->w_valid_cursor = wp->w_cursor;
|
||||||
wp->w_valid_leftcol = wp->w_leftcol;
|
wp->w_valid_leftcol = wp->w_leftcol;
|
||||||
wp->w_valid_skipcol = wp->w_skipcol;
|
wp->w_valid_skipcol = wp->w_skipcol;
|
||||||
@ -1341,13 +1347,14 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
|
|||||||
// A sequence of folded lines only counts for one logical line
|
// A sequence of folded lines only counts for one logical line
|
||||||
linenr_T first;
|
linenr_T first;
|
||||||
if (hasFolding(wp, wp->w_topline, &first, NULL)) {
|
if (hasFolding(wp, wp->w_topline, &first, NULL)) {
|
||||||
done++;
|
done += !decor_conceal_line(wp, first - 1, false);
|
||||||
if (!byfold) {
|
if (!byfold) {
|
||||||
todo -= wp->w_topline - first - 1;
|
todo -= wp->w_topline - first - 1;
|
||||||
}
|
}
|
||||||
wp->w_botline -= wp->w_topline - first;
|
wp->w_botline -= wp->w_topline - first;
|
||||||
wp->w_topline = first;
|
wp->w_topline = first;
|
||||||
} else {
|
} else {
|
||||||
|
todo += decor_conceal_line(wp, wp->w_topline - 1, false);
|
||||||
if (do_sms) {
|
if (do_sms) {
|
||||||
int size = win_linetabsize(wp, wp->w_topline,
|
int size = win_linetabsize(wp, wp->w_topline,
|
||||||
ml_get_buf(wp->w_buffer, wp->w_topline), MAXCOL);
|
ml_get_buf(wp->w_buffer, wp->w_topline), MAXCOL);
|
||||||
@ -1391,12 +1398,8 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold)
|
|||||||
while (wrow >= wp->w_height_inner && wp->w_cursor.lnum > 1) {
|
while (wrow >= wp->w_height_inner && wp->w_cursor.lnum > 1) {
|
||||||
linenr_T first;
|
linenr_T first;
|
||||||
if (hasFolding(wp, wp->w_cursor.lnum, &first, NULL)) {
|
if (hasFolding(wp, wp->w_cursor.lnum, &first, NULL)) {
|
||||||
wrow--;
|
wrow -= !decor_conceal_line(wp, wp->w_cursor.lnum - 1, false);
|
||||||
if (first == 1) {
|
wp->w_cursor.lnum = MAX(first - 1, 1);
|
||||||
wp->w_cursor.lnum = 1;
|
|
||||||
} else {
|
|
||||||
wp->w_cursor.lnum = first - 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
wrow -= plines_win(wp, wp->w_cursor.lnum--, true);
|
wrow -= plines_win(wp, wp->w_cursor.lnum--, true);
|
||||||
}
|
}
|
||||||
@ -1424,7 +1427,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
|
|||||||
linenr_T botline = wp->w_botline;
|
linenr_T botline = wp->w_botline;
|
||||||
bool do_sms = wp->w_p_wrap && wp->w_p_sms;
|
bool do_sms = wp->w_p_wrap && wp->w_p_sms;
|
||||||
|
|
||||||
if (do_sms || (byfold && hasAnyFolding(wp)) || win_may_fill(wp)) {
|
if (do_sms || (byfold && win_lines_concealed(wp)) || win_may_fill(wp)) {
|
||||||
int width1 = wp->w_width_inner - win_col_off(wp);
|
int width1 = wp->w_width_inner - win_col_off(wp);
|
||||||
int width2 = width1 + win_col_off2(wp);
|
int width2 = width1 + win_col_off2(wp);
|
||||||
int size = 0;
|
int size = 0;
|
||||||
@ -1439,6 +1442,7 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
|
|||||||
// the line, then advance to the next line.
|
// the line, then advance to the next line.
|
||||||
// folding: count each sequence of folded lines as one logical line.
|
// folding: count each sequence of folded lines as one logical line.
|
||||||
for (int todo = line_count; todo > 0; todo--) {
|
for (int todo = line_count; todo > 0; todo--) {
|
||||||
|
todo += decor_conceal_line(wp, wp->w_topline - 1, false);
|
||||||
if (wp->w_topfill > 0) {
|
if (wp->w_topfill > 0) {
|
||||||
wp->w_topfill--;
|
wp->w_topfill--;
|
||||||
} else {
|
} else {
|
||||||
@ -1495,10 +1499,8 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold)
|
|||||||
|
|
||||||
check_topfill(wp, false);
|
check_topfill(wp, false);
|
||||||
|
|
||||||
if (hasAnyFolding(wp)) {
|
// Make sure w_topline is at the first of a sequence of folded lines.
|
||||||
// Make sure w_topline is at the first of a sequence of folded lines.
|
hasFolding(wp, wp->w_topline, &wp->w_topline, NULL);
|
||||||
hasFolding(wp, wp->w_topline, &wp->w_topline, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
|
wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
|
||||||
if (wp->w_cursor.lnum < wp->w_topline) {
|
if (wp->w_cursor.lnum < wp->w_topline) {
|
||||||
@ -1702,8 +1704,8 @@ static void topline_back_winheight(win_T *wp, lineoff_T *lp, int winheight)
|
|||||||
if (lp->lnum < 1) {
|
if (lp->lnum < 1) {
|
||||||
lp->height = MAXCOL;
|
lp->height = MAXCOL;
|
||||||
} else if (hasFolding(wp, lp->lnum, &lp->lnum, NULL)) {
|
} else if (hasFolding(wp, lp->lnum, &lp->lnum, NULL)) {
|
||||||
// Add a closed fold
|
// Add a closed fold unless concealed.
|
||||||
lp->height = 1;
|
lp->height = !decor_conceal_line(wp, lp->lnum - 1, false);
|
||||||
} else {
|
} else {
|
||||||
lp->height = plines_win_nofill(wp, lp->lnum, winheight);
|
lp->height = plines_win_nofill(wp, lp->lnum, winheight);
|
||||||
}
|
}
|
||||||
@ -1732,8 +1734,8 @@ static void botline_forw(win_T *wp, lineoff_T *lp)
|
|||||||
if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) {
|
if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) {
|
||||||
lp->height = MAXCOL;
|
lp->height = MAXCOL;
|
||||||
} else if (hasFolding(wp, lp->lnum, NULL, &lp->lnum)) {
|
} else if (hasFolding(wp, lp->lnum, NULL, &lp->lnum)) {
|
||||||
// Add a closed fold
|
// Add a closed fold unless concealed.
|
||||||
lp->height = 1;
|
lp->height = !decor_conceal_line(wp, lp->lnum - 1, false);
|
||||||
} else {
|
} else {
|
||||||
lp->height = plines_win_nofill(wp, lp->lnum, true);
|
lp->height = plines_win_nofill(wp, lp->lnum, true);
|
||||||
}
|
}
|
||||||
@ -1785,9 +1787,8 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always)
|
|||||||
// Check if the lines from "top" to "bot" fit in the window. If they do,
|
// Check if the lines from "top" to "bot" fit in the window. If they do,
|
||||||
// set new_topline and advance "top" and "bot" to include more lines.
|
// set new_topline and advance "top" and "bot" to include more lines.
|
||||||
while (top > 0) {
|
while (top > 0) {
|
||||||
int i = hasFolding(wp, top, &top, NULL)
|
int i = plines_win_nofill(wp, top, true);
|
||||||
? 1 // count one logical line for a sequence of folded lines
|
hasFolding(wp, top, &top, NULL);
|
||||||
: plines_win_nofill(wp, top, true);
|
|
||||||
if (top < wp->w_topline) {
|
if (top < wp->w_topline) {
|
||||||
scrolled += i;
|
scrolled += i;
|
||||||
}
|
}
|
||||||
@ -1799,12 +1800,7 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always)
|
|||||||
|
|
||||||
used += i;
|
used += i;
|
||||||
if (extra + i <= off && bot < wp->w_buffer->b_ml.ml_line_count) {
|
if (extra + i <= off && bot < wp->w_buffer->b_ml.ml_line_count) {
|
||||||
if (hasFolding(wp, bot, NULL, &bot)) {
|
used += plines_win_full(wp, bot, &bot, NULL, true, true);
|
||||||
// count one logical line for a sequence of folded lines
|
|
||||||
used++;
|
|
||||||
} else {
|
|
||||||
used += plines_win(wp, bot, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (used > wp->w_height_inner) {
|
if (used > wp->w_height_inner) {
|
||||||
break;
|
break;
|
||||||
@ -2265,7 +2261,7 @@ void cursor_correct(win_T *wp)
|
|||||||
linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number
|
linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number
|
||||||
if (cln >= wp->w_topline + above_wanted
|
if (cln >= wp->w_topline + above_wanted
|
||||||
&& cln < wp->w_botline - below_wanted
|
&& cln < wp->w_botline - below_wanted
|
||||||
&& !hasAnyFolding(wp)) {
|
&& !win_lines_concealed(wp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2290,19 +2286,12 @@ void cursor_correct(win_T *wp)
|
|||||||
int below = wp->w_filler_rows; // screen lines below botline
|
int below = wp->w_filler_rows; // screen lines below botline
|
||||||
while ((above < above_wanted || below < below_wanted) && topline < botline) {
|
while ((above < above_wanted || below < below_wanted) && topline < botline) {
|
||||||
if (below < below_wanted && (below <= above || above >= above_wanted)) {
|
if (below < below_wanted && (below <= above || above >= above_wanted)) {
|
||||||
if (hasFolding(wp, botline, &botline, NULL)) {
|
below += plines_win_full(wp, botline, &botline, NULL, true, true);
|
||||||
below++;
|
|
||||||
} else {
|
|
||||||
below += plines_win(wp, botline, true);
|
|
||||||
}
|
|
||||||
botline--;
|
botline--;
|
||||||
}
|
}
|
||||||
if (above < above_wanted && (above < below || below >= below_wanted)) {
|
if (above < above_wanted && (above < below || below >= below_wanted)) {
|
||||||
if (hasFolding(wp, topline, NULL, &topline)) {
|
above += plines_win_nofill(wp, topline, true);
|
||||||
above++;
|
hasFolding(wp, topline, NULL, &topline);
|
||||||
} else {
|
|
||||||
above += plines_win_nofill(wp, topline, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count filler lines below this line as context.
|
// Count filler lines below this line as context.
|
||||||
if (topline < botline) {
|
if (topline < botline) {
|
||||||
@ -2456,7 +2445,8 @@ int pagescroll(Direction dir, int count, bool half)
|
|||||||
int curscount = count;
|
int curscount = count;
|
||||||
// Adjust count so as to not reveal end of buffer lines.
|
// Adjust count so as to not reveal end of buffer lines.
|
||||||
if (dir == FORWARD
|
if (dir == FORWARD
|
||||||
&& (curwin->w_topline + curwin->w_height_inner + count > buflen || hasAnyFolding(curwin))) {
|
&& (curwin->w_topline + curwin->w_height_inner + count > buflen
|
||||||
|
|| win_lines_concealed(curwin))) {
|
||||||
int n = plines_correct_topline(curwin, curwin->w_topline, NULL, false, NULL);
|
int n = plines_correct_topline(curwin, curwin->w_topline, NULL, false, NULL);
|
||||||
if (n - count < curwin->w_height_inner && curwin->w_topline < buflen) {
|
if (n - count < curwin->w_height_inner && curwin->w_topline < buflen) {
|
||||||
n += plines_m_win(curwin, curwin->w_topline + 1, buflen, curwin->w_height_inner + count);
|
n += plines_m_win(curwin, curwin->w_topline + 1, buflen, curwin->w_height_inner + count);
|
||||||
@ -2474,13 +2464,14 @@ int pagescroll(Direction dir, int count, bool half)
|
|||||||
curwin->w_curswant = prev_curswant;
|
curwin->w_curswant = prev_curswant;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the cursor the same amount of screen lines.
|
// Move the cursor the same amount of screen lines, skipping over
|
||||||
|
// concealed lines as those were not included in "curscount".
|
||||||
if (curwin->w_p_wrap) {
|
if (curwin->w_p_wrap) {
|
||||||
nv_screengo(&oa, dir, curscount);
|
nv_screengo(&oa, dir, curscount, true);
|
||||||
} else if (dir == FORWARD) {
|
} else if (dir == FORWARD) {
|
||||||
cursor_down_inner(curwin, curscount);
|
cursor_down_inner(curwin, curscount, true);
|
||||||
} else {
|
} else {
|
||||||
cursor_up_inner(curwin, curscount);
|
cursor_up_inner(curwin, curscount, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Scroll [count] times 'window' or current window height lines.
|
// Scroll [count] times 'window' or current window height lines.
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cmdhist.h"
|
#include "nvim/cmdhist.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/diff.h"
|
#include "nvim/diff.h"
|
||||||
#include "nvim/digraph.h"
|
#include "nvim/digraph.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
@ -2486,7 +2487,7 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar
|
|||||||
/// 'dist' must be positive.
|
/// 'dist' must be positive.
|
||||||
///
|
///
|
||||||
/// @return true if able to move cursor, false otherwise.
|
/// @return true if able to move cursor, false otherwise.
|
||||||
bool nv_screengo(oparg_T *oap, int dir, int dist)
|
bool nv_screengo(oparg_T *oap, int dir, int dist, bool skip_conceal)
|
||||||
{
|
{
|
||||||
int linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
int linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
@ -2548,7 +2549,7 @@ bool nv_screengo(oparg_T *oap, int dir, int dist)
|
|||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cursor_up_inner(curwin, 1);
|
cursor_up_inner(curwin, 1, skip_conceal);
|
||||||
|
|
||||||
linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||||
if (linelen > width1) {
|
if (linelen > width1) {
|
||||||
@ -2573,7 +2574,7 @@ bool nv_screengo(oparg_T *oap, int dir, int dist)
|
|||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cursor_down_inner(curwin, 1);
|
cursor_down_inner(curwin, 1, skip_conceal);
|
||||||
curwin->w_curswant %= width2;
|
curwin->w_curswant %= width2;
|
||||||
|
|
||||||
// Check if the cursor has moved below the number display
|
// Check if the cursor has moved below the number display
|
||||||
@ -3616,12 +3617,11 @@ static void nv_scroll(cmdarg_T *cap)
|
|||||||
if (cap->count1 - 1 >= curwin->w_cursor.lnum) {
|
if (cap->count1 - 1 >= curwin->w_cursor.lnum) {
|
||||||
curwin->w_cursor.lnum = 1;
|
curwin->w_cursor.lnum = 1;
|
||||||
} else {
|
} else {
|
||||||
if (hasAnyFolding(curwin)) {
|
if (win_lines_concealed(curwin)) {
|
||||||
// Count a fold for one screen line.
|
// Count a fold for one screen line.
|
||||||
for (n = cap->count1 - 1; n > 0
|
for (n = cap->count1 - 1; n > 0 && curwin->w_cursor.lnum > curwin->w_topline; n--) {
|
||||||
&& curwin->w_cursor.lnum > curwin->w_topline; n--) {
|
hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL);
|
||||||
hasFolding(curwin, curwin->w_cursor.lnum,
|
n += decor_conceal_line(curwin, curwin->w_cursor.lnum, true);
|
||||||
&curwin->w_cursor.lnum, NULL);
|
|
||||||
if (curwin->w_cursor.lnum > curwin->w_topline) {
|
if (curwin->w_cursor.lnum > curwin->w_topline) {
|
||||||
curwin->w_cursor.lnum--;
|
curwin->w_cursor.lnum--;
|
||||||
}
|
}
|
||||||
@ -3634,8 +3634,7 @@ static void nv_scroll(cmdarg_T *cap)
|
|||||||
if (cap->cmdchar == 'M') {
|
if (cap->cmdchar == 'M') {
|
||||||
int used = 0;
|
int used = 0;
|
||||||
// Don't count filler lines above the window.
|
// Don't count filler lines above the window.
|
||||||
used -= win_get_fill(curwin, curwin->w_topline)
|
used -= win_get_fill(curwin, curwin->w_topline) - curwin->w_topfill;
|
||||||
- curwin->w_topfill;
|
|
||||||
validate_botline(curwin); // make sure w_empty_rows is valid
|
validate_botline(curwin); // make sure w_empty_rows is valid
|
||||||
int half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2;
|
int half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2;
|
||||||
for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) {
|
for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) {
|
||||||
@ -3658,10 +3657,11 @@ static void nv_scroll(cmdarg_T *cap)
|
|||||||
}
|
}
|
||||||
} else { // (cap->cmdchar == 'H')
|
} else { // (cap->cmdchar == 'H')
|
||||||
n = cap->count1 - 1;
|
n = cap->count1 - 1;
|
||||||
if (hasAnyFolding(curwin)) {
|
if (win_lines_concealed(curwin)) {
|
||||||
// Count a fold for one screen line.
|
// Count a fold for one screen line.
|
||||||
lnum = curwin->w_topline;
|
lnum = curwin->w_topline;
|
||||||
while (n-- > 0 && lnum < curwin->w_botline - 1) {
|
while ((decor_conceal_line(curwin, lnum - 1, true) || n-- > 0)
|
||||||
|
&& lnum < curwin->w_botline - 1) {
|
||||||
hasFolding(curwin, lnum, NULL, &lnum);
|
hasFolding(curwin, lnum, NULL, &lnum);
|
||||||
lnum++;
|
lnum++;
|
||||||
}
|
}
|
||||||
@ -5316,7 +5316,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap)
|
|||||||
curwin->w_cursor.col--;
|
curwin->w_cursor.col--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == false) {
|
} else if (nv_screengo(oap, FORWARD, cap->count1 - 1, false) == false) {
|
||||||
clearopbeep(oap);
|
clearopbeep(oap);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -5443,7 +5443,7 @@ static void nv_g_cmd(cmdarg_T *cap)
|
|||||||
oap->motion_type = kMTLineWise;
|
oap->motion_type = kMTLineWise;
|
||||||
i = cursor_down(cap->count1, oap->op_type == OP_NOP);
|
i = cursor_down(cap->count1, oap->op_type == OP_NOP);
|
||||||
} else {
|
} else {
|
||||||
i = nv_screengo(oap, FORWARD, cap->count1);
|
i = nv_screengo(oap, FORWARD, cap->count1, false);
|
||||||
}
|
}
|
||||||
if (!i) {
|
if (!i) {
|
||||||
clearopbeep(oap);
|
clearopbeep(oap);
|
||||||
@ -5457,7 +5457,7 @@ static void nv_g_cmd(cmdarg_T *cap)
|
|||||||
oap->motion_type = kMTLineWise;
|
oap->motion_type = kMTLineWise;
|
||||||
i = cursor_up(cap->count1, oap->op_type == OP_NOP);
|
i = cursor_up(cap->count1, oap->op_type == OP_NOP);
|
||||||
} else {
|
} else {
|
||||||
i = nv_screengo(oap, BACKWARD, cap->count1);
|
i = nv_screengo(oap, BACKWARD, cap->count1, false);
|
||||||
}
|
}
|
||||||
if (!i) {
|
if (!i) {
|
||||||
clearopbeep(oap);
|
clearopbeep(oap);
|
||||||
|
@ -80,7 +80,7 @@ int linetabsize(win_T *wp, linenr_T lnum)
|
|||||||
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), MAXCOL);
|
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), MAXCOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t inline_filter[4] = {[kMTMetaInline] = kMTFilterSelect };
|
static const uint32_t inline_filter[kMTMetaCount] = {[kMTMetaInline] = kMTFilterSelect };
|
||||||
|
|
||||||
/// Prepare the structure passed to charsize functions.
|
/// Prepare the structure passed to charsize functions.
|
||||||
///
|
///
|
||||||
@ -749,6 +749,10 @@ int plines_win(win_T *wp, linenr_T lnum, bool limit_winheight)
|
|||||||
/// @param limit_winheight when true limit to window height
|
/// @param limit_winheight when true limit to window height
|
||||||
int plines_win_nofill(win_T *wp, linenr_T lnum, bool limit_winheight)
|
int plines_win_nofill(win_T *wp, linenr_T lnum, bool limit_winheight)
|
||||||
{
|
{
|
||||||
|
if (decor_conceal_line(wp, lnum - 1, false)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wp->w_p_wrap) {
|
if (!wp->w_p_wrap) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -885,6 +889,11 @@ int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const
|
|||||||
if (foldedp != NULL) {
|
if (foldedp != NULL) {
|
||||||
*foldedp = folded;
|
*foldedp = folded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decor_conceal_line(wp, lnum - 1, false)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return ((folded ? 1 : plines_win_nofill(wp, lnum, limit_winheight)) +
|
return ((folded ? 1 : plines_win_nofill(wp, lnum, limit_winheight)) +
|
||||||
(lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum)));
|
(lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum)));
|
||||||
}
|
}
|
||||||
@ -963,8 +972,8 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_
|
|||||||
|
|
||||||
if (start_vcol >= 0) {
|
if (start_vcol >= 0) {
|
||||||
linenr_T lnum_next = lnum;
|
linenr_T lnum_next = lnum;
|
||||||
const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next);
|
hasFolding(wp, lnum, &lnum, &lnum_next);
|
||||||
height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false);
|
height_cur_nofill = plines_win_nofill(wp, lnum, false);
|
||||||
height_sum_nofill += height_cur_nofill;
|
height_sum_nofill += height_cur_nofill;
|
||||||
const int64_t row_off = (start_vcol < width1 || width2 <= 0)
|
const int64_t row_off = (start_vcol < width1 || width2 <= 0)
|
||||||
? 0
|
? 0
|
||||||
@ -975,9 +984,9 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_
|
|||||||
|
|
||||||
while (lnum <= end_lnum) {
|
while (lnum <= end_lnum) {
|
||||||
linenr_T lnum_next = lnum;
|
linenr_T lnum_next = lnum;
|
||||||
const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next);
|
hasFolding(wp, lnum, &lnum, &lnum_next);
|
||||||
height_sum_fill += win_get_fill(wp, lnum);
|
height_sum_fill += win_get_fill(wp, lnum);
|
||||||
height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false);
|
height_cur_nofill = plines_win_nofill(wp, lnum, false);
|
||||||
height_sum_nofill += height_cur_nofill;
|
height_sum_nofill += height_cur_nofill;
|
||||||
lnum = lnum_next + 1;
|
lnum = lnum_next + 1;
|
||||||
}
|
}
|
||||||
|
@ -641,9 +641,6 @@ bool terminal_enter(void)
|
|||||||
curwin->w_p_so = 0;
|
curwin->w_p_so = 0;
|
||||||
curwin->w_p_siso = 0;
|
curwin->w_p_siso = 0;
|
||||||
|
|
||||||
// Save the existing cursor entry since it may be modified by the application
|
|
||||||
cursorentry_T save_cursorentry = shape_table[SHAPE_IDX_TERM];
|
|
||||||
|
|
||||||
// Update the cursor shape table and flush changes to the UI
|
// Update the cursor shape table and flush changes to the UI
|
||||||
s->term->pending.cursor = true;
|
s->term->pending.cursor = true;
|
||||||
refresh_cursor(s->term);
|
refresh_cursor(s->term);
|
||||||
@ -674,8 +671,8 @@ bool terminal_enter(void)
|
|||||||
RedrawingDisabled = s->save_rd;
|
RedrawingDisabled = s->save_rd;
|
||||||
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
|
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
|
||||||
|
|
||||||
shape_table[SHAPE_IDX_TERM] = save_cursorentry;
|
// Restore the terminal cursor to what is set in 'guicursor'
|
||||||
ui_mode_info_set();
|
(void)parse_shape_opt(SHAPE_CURSOR);
|
||||||
|
|
||||||
if (save_curwin == curwin->handle) { // Else: window was closed.
|
if (save_curwin == curwin->handle) { // Else: window was closed.
|
||||||
curwin->w_p_cul = save_w_p_cul;
|
curwin->w_p_cul = save_w_p_cul;
|
||||||
|
@ -6465,9 +6465,9 @@ void win_fix_scroll(bool resize)
|
|||||||
|
|
||||||
// Add difference in height and row to botline.
|
// Add difference in height and row to botline.
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
cursor_down_inner(wp, diff);
|
cursor_down_inner(wp, diff, false);
|
||||||
} else {
|
} else {
|
||||||
cursor_up_inner(wp, -diff);
|
cursor_up_inner(wp, -diff, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll to put the new cursor position at the bottom of the
|
// Scroll to put the new cursor position at the bottom of the
|
||||||
@ -6514,11 +6514,11 @@ static void win_fix_cursor(bool normal)
|
|||||||
linenr_T lnum = wp->w_cursor.lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
|
|
||||||
wp->w_cursor.lnum = wp->w_topline;
|
wp->w_cursor.lnum = wp->w_topline;
|
||||||
cursor_down_inner(wp, so);
|
cursor_down_inner(wp, so, false);
|
||||||
linenr_T top = wp->w_cursor.lnum;
|
linenr_T top = wp->w_cursor.lnum;
|
||||||
|
|
||||||
wp->w_cursor.lnum = wp->w_botline - 1;
|
wp->w_cursor.lnum = wp->w_botline - 1;
|
||||||
cursor_up_inner(wp, so);
|
cursor_up_inner(wp, so, false);
|
||||||
linenr_T bot = wp->w_cursor.lnum;
|
linenr_T bot = wp->w_cursor.lnum;
|
||||||
|
|
||||||
wp->w_cursor.lnum = lnum;
|
wp->w_cursor.lnum = lnum;
|
||||||
@ -6612,7 +6612,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
|
|||||||
hasFolding(wp, lnum, &lnum, NULL);
|
hasFolding(wp, lnum, &lnum, NULL);
|
||||||
if (lnum == 1) {
|
if (lnum == 1) {
|
||||||
// first line in buffer is folded
|
// first line in buffer is folded
|
||||||
line_size = 1;
|
line_size = !decor_conceal_line(wp, lnum - 1, false);
|
||||||
sline--;
|
sline--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1552,6 +1552,7 @@ describe('API/extmarks', function()
|
|||||||
it('can get details', function()
|
it('can get details', function()
|
||||||
set_extmark(ns, marks[1], 0, 0, {
|
set_extmark(ns, marks[1], 0, 0, {
|
||||||
conceal = 'c',
|
conceal = 'c',
|
||||||
|
conceal_lines = '',
|
||||||
cursorline_hl_group = 'Statement',
|
cursorline_hl_group = 'Statement',
|
||||||
end_col = 0,
|
end_col = 0,
|
||||||
end_right_gravity = true,
|
end_right_gravity = true,
|
||||||
@ -1586,6 +1587,7 @@ describe('API/extmarks', function()
|
|||||||
0,
|
0,
|
||||||
{
|
{
|
||||||
conceal = 'c',
|
conceal = 'c',
|
||||||
|
conceal_lines = '',
|
||||||
cursorline_hl_group = 'Statement',
|
cursorline_hl_group = 'Statement',
|
||||||
end_col = 0,
|
end_col = 0,
|
||||||
end_right_gravity = true,
|
end_right_gravity = true,
|
||||||
|
@ -15,9 +15,20 @@ local skip = t.skip
|
|||||||
describe(':terminal cursor', function()
|
describe(':terminal cursor', function()
|
||||||
local screen
|
local screen
|
||||||
|
|
||||||
|
local terminal_mode_idx ---@type number
|
||||||
|
|
||||||
before_each(function()
|
before_each(function()
|
||||||
clear()
|
clear()
|
||||||
screen = tt.setup_screen()
|
screen = tt.setup_screen()
|
||||||
|
|
||||||
|
if terminal_mode_idx == nil then
|
||||||
|
for i, v in ipairs(screen._mode_info) do
|
||||||
|
if v.name == 'terminal' then
|
||||||
|
terminal_mode_idx = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(terminal_mode_idx)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('moves the screen cursor when focused', function()
|
it('moves the screen cursor when focused', function()
|
||||||
@ -143,13 +154,6 @@ describe(':terminal cursor', function()
|
|||||||
|
|
||||||
it('can be modified by application #3681', function()
|
it('can be modified by application #3681', function()
|
||||||
skip(is_os('win'), '#31587')
|
skip(is_os('win'), '#31587')
|
||||||
local idx ---@type number
|
|
||||||
for i, v in ipairs(screen._mode_info) do
|
|
||||||
if v.name == 'terminal' then
|
|
||||||
idx = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert(idx)
|
|
||||||
|
|
||||||
local states = {
|
local states = {
|
||||||
[1] = { blink = true, shape = 'block' },
|
[1] = { blink = true, shape = 'block' },
|
||||||
@ -171,13 +175,13 @@ describe(':terminal cursor', function()
|
|||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
if v.blink then
|
if v.blink then
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
else
|
else
|
||||||
eq(0, screen._mode_info[idx].blinkon)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(0, screen._mode_info[idx].blinkoff)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
end
|
end
|
||||||
eq(v.shape, screen._mode_info[idx].cursor_shape)
|
eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@ -191,20 +195,13 @@ describe(':terminal cursor', function()
|
|||||||
]])
|
]])
|
||||||
|
|
||||||
-- Cursor returns to default on TermLeave
|
-- Cursor returns to default on TermLeave
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('block', screen._mode_info[idx].cursor_shape)
|
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can be modified per terminal', function()
|
it('can be modified per terminal', function()
|
||||||
skip(is_os('win'), '#31587')
|
skip(is_os('win'), '#31587')
|
||||||
local idx ---@type number
|
|
||||||
for i, v in ipairs(screen._mode_info) do
|
|
||||||
if v.name == 'terminal' then
|
|
||||||
idx = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert(idx)
|
|
||||||
|
|
||||||
-- Set cursor to vertical bar with blink
|
-- Set cursor to vertical bar with blink
|
||||||
tt.feed_csi('5 q')
|
tt.feed_csi('5 q')
|
||||||
@ -216,9 +213,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -231,9 +228,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -256,9 +253,9 @@ describe(':terminal cursor', function()
|
|||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
-- New terminal, cursor resets to defaults
|
-- New terminal, cursor resets to defaults
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('block', screen._mode_info[idx].cursor_shape)
|
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -275,9 +272,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(0, screen._mode_info[idx].blinkon)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(0, screen._mode_info[idx].blinkoff)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('horizontal', screen._mode_info[idx].cursor_shape)
|
eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -294,9 +291,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
@ -326,6 +323,32 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('preserves guicursor value on TermLeave #31612', function()
|
||||||
|
eq(3, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
|
||||||
|
-- Change 'guicursor' while terminal mode is active
|
||||||
|
command('set guicursor+=t:Error')
|
||||||
|
|
||||||
|
local error_hl_id = call('hlID', 'Error')
|
||||||
|
|
||||||
|
screen:expect({
|
||||||
|
condition = function()
|
||||||
|
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Exit terminal mode
|
||||||
|
feed([[<C-\><C-N>]])
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
tty ready |
|
||||||
|
^ |
|
||||||
|
|*5
|
||||||
|
]])
|
||||||
|
|
||||||
|
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('buffer cursor position is correct in terminal without number column', function()
|
describe('buffer cursor position is correct in terminal without number column', function()
|
||||||
@ -350,12 +373,6 @@ describe('buffer cursor position is correct in terminal without number column',
|
|||||||
}, {
|
}, {
|
||||||
cols = 70,
|
cols = 70,
|
||||||
})
|
})
|
||||||
screen:set_default_attr_ids({
|
|
||||||
[1] = { foreground = 253, background = 11 },
|
|
||||||
[2] = { reverse = true },
|
|
||||||
[3] = { bold = true },
|
|
||||||
[4] = { background = 11 },
|
|
||||||
})
|
|
||||||
-- Also check for real cursor position, as it is used for stuff like input methods
|
-- Also check for real cursor position, as it is used for stuff like input methods
|
||||||
screen._handle_busy_start = function() end
|
screen._handle_busy_start = function() end
|
||||||
screen._handle_busy_stop = function() end
|
screen._handle_busy_stop = function() end
|
||||||
@ -667,13 +684,6 @@ describe('buffer cursor position is correct in terminal with number column', fun
|
|||||||
}, {
|
}, {
|
||||||
cols = 70,
|
cols = 70,
|
||||||
})
|
})
|
||||||
screen:set_default_attr_ids({
|
|
||||||
[1] = { foreground = 253, background = 11 },
|
|
||||||
[2] = { reverse = true },
|
|
||||||
[3] = { bold = true },
|
|
||||||
[4] = { background = 11 },
|
|
||||||
[7] = { foreground = 130 },
|
|
||||||
})
|
|
||||||
-- Also check for real cursor position, as it is used for stuff like input methods
|
-- Also check for real cursor position, as it is used for stuff like input methods
|
||||||
screen._handle_busy_start = function() end
|
screen._handle_busy_start = function() end
|
||||||
screen._handle_busy_stop = function() end
|
screen._handle_busy_stop = function() end
|
||||||
|
@ -1119,14 +1119,16 @@ describe('treesitter highlighting (markdown)', function()
|
|||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with spellchecked and smoothscrolled topline', function()
|
local code_block = [[
|
||||||
insert([[
|
|
||||||
- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$.
|
- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
printf('Hello World!');
|
printf('Hello World!');
|
||||||
```
|
```
|
||||||
]])
|
]]
|
||||||
|
|
||||||
|
it('works with spellchecked and smoothscrolled topline', function()
|
||||||
|
insert(code_block)
|
||||||
command('set spell smoothscroll')
|
command('set spell smoothscroll')
|
||||||
feed('gg<C-E>')
|
feed('gg<C-E>')
|
||||||
screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } })
|
screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } })
|
||||||
@ -1141,6 +1143,105 @@ printf('Hello World!');
|
|||||||
]],
|
]],
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('works with concealed lines', function()
|
||||||
|
insert(code_block)
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
|
|
||||||
|
{18:```}{15:c} |
|
||||||
|
{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{18:```} |
|
||||||
|
^ |
|
||||||
|
|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
feed('ggj')
|
||||||
|
command('set number conceallevel=3')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{|
|
||||||
|
{8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. |
|
||||||
|
{8: 2 }^ |
|
||||||
|
{8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 6 } |
|
||||||
|
|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
feed('j')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{|
|
||||||
|
{8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. |
|
||||||
|
{8: 2 } |
|
||||||
|
{8: 3 }{18:^```}{15:c} |
|
||||||
|
{8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
feed('j')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{|
|
||||||
|
{8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. |
|
||||||
|
{8: 2 } |
|
||||||
|
{8: 4 }{25:^printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 6 } |
|
||||||
|
|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
feed('j')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{|
|
||||||
|
{8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. |
|
||||||
|
{8: 2 } |
|
||||||
|
{8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 5 }{18:^```} |
|
||||||
|
|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
-- Concealed lines highlight until changed botline
|
||||||
|
screen:try_resize(screen._width, 16)
|
||||||
|
feed('y3k30P:<Esc><C-F><C-B>')
|
||||||
|
screen:expect([[
|
||||||
|
{8: 1 }{16:- }$f(0)=\sum_{k=1}^{\infty}\frac{2}{|
|
||||||
|
{8: }\pi^{2}k^{2}}+\lim_{w \to 0}x$. |
|
||||||
|
{8: 2 } |
|
||||||
|
{8: 4 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 6 } |
|
||||||
|
{8: 8 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 10 } |
|
||||||
|
{8: 12 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 14 } |
|
||||||
|
{8: 16 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 18 } |
|
||||||
|
{8: 20 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 22 } |
|
||||||
|
{8: 24 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8: 25 }{18:^```} |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('G')
|
||||||
|
screen:expect([[
|
||||||
|
{8: 98 } |
|
||||||
|
{8:100 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:102 } |
|
||||||
|
{8:104 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:106 } |
|
||||||
|
{8:108 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:110 } |
|
||||||
|
{8:112 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:114 } |
|
||||||
|
{8:116 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:118 } |
|
||||||
|
{8:120 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:122 } |
|
||||||
|
{8:124 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
|
||||||
|
{8:126 } ^ |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('starting and stopping treesitter highlight in init.lua works #29541', function()
|
it('starting and stopping treesitter highlight in init.lua works #29541', function()
|
||||||
|
@ -2495,6 +2495,209 @@ describe('extmark decorations', function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it ('conceal_lines', function()
|
||||||
|
insert(example_text)
|
||||||
|
exec('set number conceallevel=3')
|
||||||
|
feed('ggj')
|
||||||
|
local not_concealed = {
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 2 }^ local text, hl_id_cell, count = unpack(ite|
|
||||||
|
{2: }m) |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 4 } hl_id = hl_id_cell |
|
||||||
|
{2: 5 } end |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
screen:expect(not_concealed)
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = "" })
|
||||||
|
screen:expect_unchanged()
|
||||||
|
feed('j')
|
||||||
|
local concealed = {
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 }^ if hl_id_cell ~= nil then |
|
||||||
|
{2: 4 } hl_id = hl_id_cell |
|
||||||
|
{2: 5 } end |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*3
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
screen:expect(concealed)
|
||||||
|
feed('k')
|
||||||
|
screen:expect(not_concealed)
|
||||||
|
exec('set concealcursor=n')
|
||||||
|
screen:expect(concealed)
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 3, 0, { conceal_lines = "" })
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 }^ if hl_id_cell ~= nil then |
|
||||||
|
{2: 5 } end |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*4
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('kjj')
|
||||||
|
screen:expect_unchanged()
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = "" })
|
||||||
|
feed('kjjjC')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 5 }^ |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*4
|
||||||
|
{24:-- INSERT --} |
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('<esc>')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 6 }^ for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*5
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('kji')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 5 }^ |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*4
|
||||||
|
{24:-- INSERT --} |
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('conceal text')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 5 }conceal text^ |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*4
|
||||||
|
{24:-- INSERT --} |
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('<esc>')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 6 } for _ =^ 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*5
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('ggzfj')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }{33:^+-- 2 lines: for _,item in ipairs(items) do··}|
|
||||||
|
{2: 3 } if hl_id_cell ~= nil then |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*5
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('j')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }{33:+-- 2 lines: for _,item in ipairs(items) do··}|
|
||||||
|
{2: 3 }^ if hl_id_cell ~= nil then |
|
||||||
|
{2: 6 } for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*5
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('ggzdjzfj')
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
{2: 1 }for _,item in ipairs(items) do |
|
||||||
|
{2: 6 }^ for _ = 1, (count or 1) do |
|
||||||
|
{2: 7 } local cell = line[colpos] |
|
||||||
|
{2: 8 } cell.text = text |
|
||||||
|
{2: 9 } cell.hl_id = hl_id |
|
||||||
|
{2: 10 } colpos = colpos+1 |
|
||||||
|
{2: 11 } end |
|
||||||
|
{2: 12 }end |
|
||||||
|
{1:~ }|*6
|
||||||
|
|
|
||||||
|
]]
|
||||||
|
})
|
||||||
|
feed('jj')
|
||||||
|
screen:expect_unchanged()
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('decorations: inline virtual text', function()
|
describe('decorations: inline virtual text', function()
|
||||||
|
@ -94,7 +94,7 @@ describe('ui mode_change event', function()
|
|||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- oldtest: Test_indent_norm_with_gq()
|
-- oldtest: Test_mouse_shape_indent_norm_with_gq()
|
||||||
it('is restored to Normal mode after "gq" indents using :normal #12309', function()
|
it('is restored to Normal mode after "gq" indents using :normal #12309', function()
|
||||||
screen:try_resize(60, 6)
|
screen:try_resize(60, 6)
|
||||||
n.exec([[
|
n.exec([[
|
||||||
|
@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
|
|||||||
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
|
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
|
||||||
[7] = { background = Screen.colors.Yellow }, -- Search
|
[7] = { background = Screen.colors.Yellow }, -- Search
|
||||||
[8] = { foreground = Screen.colors.Red },
|
[8] = { foreground = Screen.colors.Red },
|
||||||
|
[9] = { foreground = Screen.colors.Yellow, background = Screen.colors.Green },
|
||||||
|
[10] = { foreground = Screen.colors.White, background = Screen.colors.Green },
|
||||||
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
|
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
|
||||||
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
|
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
|
||||||
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
|
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
|
||||||
@ -5625,6 +5627,114 @@ describe('builtin popupmenu', function()
|
|||||||
{2:-- INSERT --} |
|
{2:-- INSERT --} |
|
||||||
]])
|
]])
|
||||||
feed('<Esc>')
|
feed('<Esc>')
|
||||||
|
|
||||||
|
-- text after the inserted text shouldn't be highlighted
|
||||||
|
feed('0ea <C-X><C-O>')
|
||||||
|
screen:expect([[
|
||||||
|
αβγ {8:foo}^ foo |
|
||||||
|
{1:~ }{s: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
]])
|
||||||
|
feed('<C-P>')
|
||||||
|
screen:expect([[
|
||||||
|
αβγ ^ foo |
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{8:Back at original} |
|
||||||
|
]])
|
||||||
|
feed('<C-P>')
|
||||||
|
screen:expect([[
|
||||||
|
αβγ {8:你好}^ foo |
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{s: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{5:match 3 of 3} |
|
||||||
|
]])
|
||||||
|
feed('<C-Y>')
|
||||||
|
screen:expect([[
|
||||||
|
αβγ 你好^ foo |
|
||||||
|
{1:~ }|*18
|
||||||
|
{2:-- INSERT --} |
|
||||||
|
]])
|
||||||
|
feed('<Esc>')
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- oldtest: Test_pum_matchins_highlight_combine()
|
||||||
|
it('with ComplMatchIns, Normal and CursorLine highlights', function()
|
||||||
|
exec([[
|
||||||
|
func Omni_test(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return col(".")
|
||||||
|
endif
|
||||||
|
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
|
||||||
|
endfunc
|
||||||
|
set omnifunc=Omni_test
|
||||||
|
hi Normal guibg=blue
|
||||||
|
hi CursorLine guibg=green guifg=white
|
||||||
|
set cursorline
|
||||||
|
call setline(1, 'aaa bbb')
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- when ComplMatchIns is not set, CursorLine applies normally
|
||||||
|
feed('0ea <C-X><C-O>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa foo^ bbb }|
|
||||||
|
{1:~ }{s: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
]])
|
||||||
|
feed('<C-E>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa ^ bbb }|
|
||||||
|
{1:~ }|*18
|
||||||
|
{2:-- INSERT --} |
|
||||||
|
]])
|
||||||
|
feed('<BS><Esc>')
|
||||||
|
|
||||||
|
-- when ComplMatchIns is set, it is applied over CursorLine
|
||||||
|
command('hi ComplMatchIns guifg=Yellow')
|
||||||
|
feed('0ea <C-X><C-O>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa }{9:foo}{10:^ bbb }|
|
||||||
|
{1:~ }{s: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{5:match 1 of 3} |
|
||||||
|
]])
|
||||||
|
feed('<C-P>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa ^ bbb }|
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{8:Back at original} |
|
||||||
|
]])
|
||||||
|
feed('<C-P>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa }{9:你好}{10:^ bbb }|
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{s: 你好 }{1: }|
|
||||||
|
{1:~ }|*15
|
||||||
|
{2:-- }{5:match 3 of 3} |
|
||||||
|
]])
|
||||||
|
feed('<C-E>')
|
||||||
|
screen:expect([[
|
||||||
|
{10:aaa ^ bbb }|
|
||||||
|
{1:~ }|*18
|
||||||
|
{2:-- INSERT --} |
|
||||||
|
]])
|
||||||
|
feed('<Esc>')
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -308,7 +308,7 @@ endfunc
|
|||||||
|
|
||||||
" Test that mouse shape is restored to Normal mode after using "gq" when
|
" Test that mouse shape is restored to Normal mode after using "gq" when
|
||||||
" 'indentexpr' executes :normal.
|
" 'indentexpr' executes :normal.
|
||||||
func Test_indent_norm_with_gq()
|
func Test_mouse_shape_indent_norm_with_gq()
|
||||||
CheckFeature mouseshape
|
CheckFeature mouseshape
|
||||||
CheckCanRunGui
|
CheckCanRunGui
|
||||||
|
|
||||||
|
@ -1747,13 +1747,67 @@ func Test_pum_matchins_highlight()
|
|||||||
call TermWait(buf)
|
call TermWait(buf)
|
||||||
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
|
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
|
||||||
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
|
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
|
||||||
call term_sendkeys(buf, "\<C-E>\<Esc>")
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
" restore after cancel completion
|
" restore after cancel completion
|
||||||
call TermWait(buf)
|
call TermWait(buf)
|
||||||
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
|
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
|
||||||
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
|
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
|
||||||
call term_sendkeys(buf, "\<C-E>\<Esc>")
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
" text after the inserted text shouldn't be highlighted
|
||||||
|
call TermWait(buf)
|
||||||
|
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_07', {})
|
||||||
|
call term_sendkeys(buf, "\<C-P>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_08', {})
|
||||||
|
call term_sendkeys(buf, "\<C-P>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_09', {})
|
||||||
|
call term_sendkeys(buf, "\<C-Y>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_10', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
|
call StopVimInTerminal(buf)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_pum_matchins_highlight_combine()
|
||||||
|
CheckScreendump
|
||||||
|
let lines =<< trim END
|
||||||
|
func Omni_test(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return col(".")
|
||||||
|
endif
|
||||||
|
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
|
||||||
|
endfunc
|
||||||
|
set omnifunc=Omni_test
|
||||||
|
hi Normal ctermbg=blue
|
||||||
|
hi CursorLine cterm=underline ctermbg=green
|
||||||
|
set cursorline
|
||||||
|
call setline(1, 'aaa bbb')
|
||||||
|
END
|
||||||
|
call writefile(lines, 'Xscript', 'D')
|
||||||
|
let buf = RunVimInTerminal('-S Xscript', {})
|
||||||
|
|
||||||
|
" when ComplMatchIns is not set, CursorLine applies normally
|
||||||
|
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_01', {})
|
||||||
|
call term_sendkeys(buf, "\<C-E>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_02', {})
|
||||||
|
call term_sendkeys(buf, "\<BS>\<Esc>")
|
||||||
|
|
||||||
|
" when ComplMatchIns is set, it is applied over CursorLine
|
||||||
|
call TermWait(buf)
|
||||||
|
call term_sendkeys(buf, ":hi ComplMatchIns ctermbg=red ctermfg=yellow\<CR>")
|
||||||
|
call TermWait(buf)
|
||||||
|
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_03', {})
|
||||||
|
call term_sendkeys(buf, "\<C-P>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_04', {})
|
||||||
|
call term_sendkeys(buf, "\<C-P>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_05', {})
|
||||||
|
call term_sendkeys(buf, "\<C-E>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_06', {})
|
||||||
|
call term_sendkeys(buf, "\<Esc>")
|
||||||
|
|
||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
endfunc
|
||||||
|
Loading…
Reference in New Issue
Block a user