diff --git a/doc/indent_blankline.txt b/doc/indent_blankline.txt index 7b21a304..13101498 100644 --- a/doc/indent_blankline.txt +++ b/doc/indent_blankline.txt @@ -201,6 +201,9 @@ config *ibl.config* • {scope} (|ibl.config.scope|) Configures the scope + • {current_indent} (|ibl.config.current_indent|) + Configures the current_indent + • {exclude} (|ibl.config.exclude|) Configures what is excluded from indent-blankline @@ -211,6 +214,7 @@ config *ibl.config* indent = { char = "|" }, whitespace = { highlight = { "Whitespace", "NonText" } }, scope = { exclude = { language = { "lua" } } }, + current_indent = { enabled = true }, } < @@ -541,6 +545,92 @@ config.scope.exclude *ibl.config.scope.exclude* } < +config.current_indent *ibl.config.current_indent* + + Configures the current indent + + The current indent *is* the current indentation level (unlike scope). + + Example: ~ + + In Python, using the same example as above, current_indent will highlight the + current inner most indentation guide. With scope disabled, this will look like + this: + >python + def foo(); + if True: + ┋ a = "foo █ar" + ┋ # ↳ cursor here + print(a) +< + If we have the same code with scope enabled, it will look like this: + >python + def foo(); + ┋ if True: + ┋ ┋ a = "foo █ar" + ┋ ┋ # ↳ cursor here + ┋ print(a) +< + If you have both scope and current_indent enabled and the two overlap, the + scope will take priority by default. So the Rust example from above will look + identical since the scope matches the current indent level. To make + current_indent take priority, make sure that its priority is set to a higher + value than scope's priority. + (this code would not compile) + >rust + fn foo() { + if true { + ┋ let a = "foo █ar"; + ┋ // ↳ cursor here + } + print(a); + } +< + Fields: ~ + *ibl.config.current_indent.enabled* + • {enabled} (boolean) + Enables or disables current_indent + + Default: `false` ~ + + *ibl.config.current_indent.char* + • {char} (string) + Character that gets used to display the current + indents indentation guide + Each character has to have a display width + of 0 or 1 + + Default: |ibl.config.indent.char| ~ + + + *ibl.config.current_indent.highlight* + • {highlight} (string) + Highlight group that gets applied to the current + indent + + Default: |hl-IblCurrentIndent| ~ + + *ibl.config.current_indent.show_start* + • {show_start} (boolean) + Shows an underline on the line above the current + indent level + + Default: `true` ~ + + *ibl.config.current_indent.show_end* + • {show_end} (boolean) + Shows an underline on the line below the current + indent level + + Default: `true` ~ + + *ibl.config.current_indent.priority* + • {priority} (number) + Virtual text priority for the current_indent + + Default: `64` ~ + + config.exclude *ibl.config.exclude* Configures what is excluded from indent-blankline diff --git a/lua/ibl/config.lua b/lua/ibl/config.lua index 9fa36595..2948b2c3 100644 --- a/lua/ibl/config.lua +++ b/lua/ibl/config.lua @@ -62,6 +62,14 @@ M.default_config = { }, }, }, + current_indent = { + enabled = false, + char = nil, + highlight = "IblCurrentIndent", + show_start = false, + show_end = false, + priority = 64, + }, exclude = { filetypes = { "lspinfo", @@ -116,6 +124,7 @@ local validate_config = function(config) indent = { config.indent, "table", true }, whitespace = { config.whitespace, "table", true }, scope = { config.scope, "table", true }, + current_indent = { config.current_indent, "table", true }, exclude = { config.exclude, "table", true }, }, config, "ibl.config") @@ -229,6 +238,26 @@ local validate_config = function(config) end end + if config.current_indent then + utils.validate({ + enabled = { config.current_indent.enabled, "boolean", true }, + char = { config.current_indent.char, "string", true }, + highlight = { config.current_indent.highlight, "string", true }, + show_start = { config.current_indent.show_start, "boolean", true }, + show_end = { config.current_indent.show_end, "boolean", true }, + priority = { config.current_indent.priority, "number", true }, + }, config.current_indent, "ibl.config.current_indent") + if config.current_indent.char then + vim.validate { + char = { + config.current_indent.char, + validate_char, + "current_indent.char to have a display width of 0 or 1", + }, + } + end + end + if config.exclude then if config.exclude then utils.validate({ diff --git a/lua/ibl/config.types.lua b/lua/ibl/config.types.lua index eb13694b..2ec96583 100644 --- a/lua/ibl/config.types.lua +++ b/lua/ibl/config.types.lua @@ -15,6 +15,8 @@ ---@field whitespace ibl.config.whitespace? --- Configures the scope ---@field scope ibl.config.scope? +--- Configures the current_indent +---@field current_indent ibl.config.current_indent? --- Configures what is excluded from indent-blankline ---@field exclude ibl.config.exclude? @@ -109,6 +111,22 @@ --- ---@field node_type table? +---@class ibl.config.current_indent +--- Enables or disables current_indent +---@field enabled boolean? +--- Character that gets used to display the current_indent indentation guide +--- +--- The character has to have a display width of 0 or 1 +---@field char string? +--- Highlight group that get applied to the current_indent +---@field highlight string? +--- Shows an underline on the first line of the current_indent +---@field show_start boolean? +--- Shows an underline on the last line of the current_indent +---@field show_end boolean? +--- Virtual text priority for the current_indent +---@field priority number? + ---@class ibl.config.exclude --- List of `filetypes` for which indent-blankline is disabled ---@field filetypes string[]? @@ -130,7 +148,9 @@ --- Configures the whitespace ---@field whitespace ibl.config.full.whitespace: ibl.config.whitespace --- Configures the scope ----@field scope ibl.config.full.scope: ig.config.scope +---@field scope ibl.config.full.scope: ibl.config.scope +--- Configures the current_indent +---@field current_indent ibl.config.full.current_indent: ibl.config.current_indent --- Configures what is excluded from indent-blankline ---@field exclude ibl.config.full.exclude: ibl.config.exclude @@ -225,6 +245,22 @@ --- ---@field node_type table +---@class ibl.config.full.current_indent: ibl.config.current_indent +--- Enables or disables current_indent +---@field enabled boolean +--- Character that gets used to display the current_indent indentation guide +--- +--- The character has to have a display width of 0 or 1 +---@field char string? +--- Highlight group that get applied to the current_indent +---@field highlight string +--- Shows an underline on the first line of the current_indent +---@field show_start boolean +--- Shows an underline on the last line of the current_indent +---@field show_end boolean +--- Virtual text priority for the current_indent +---@field priority number + ---@class ibl.config.full.exclude: ibl.config.exclude --- List of `filetypes` for which indent-blankline is disabled ---@field filetypes string[] diff --git a/lua/ibl/highlights.lua b/lua/ibl/highlights.lua index 6bb876f6..b2203f17 100644 --- a/lua/ibl/highlights.lua +++ b/lua/ibl/highlights.lua @@ -12,6 +12,8 @@ local M = { whitespace = {}, ---@type ibl.highlight[] scope = {}, + ---@type ibl.highlight[] + current_indent = {}, } ---@param name string @@ -33,9 +35,11 @@ end local setup_builtin_hl_groups = function() local whitespace_hl = get "Whitespace" local line_nr_hl = get "LineNr" + local cursor_line_nr_hl = get "CursorLineNr" local ibl_indent_hl_name = "IblIndent" local ibl_whitespace_hl_name = "IblWhitespace" local ibl_scope_hl_name = "IblScope" + local ibl_current_indent_hl_name = "IblCurrentIndent" if not_set(get(ibl_indent_hl_name)) then vim.api.nvim_set_hl(0, ibl_indent_hl_name, whitespace_hl) @@ -46,6 +50,9 @@ local setup_builtin_hl_groups = function() if not_set(get(ibl_scope_hl_name)) then vim.api.nvim_set_hl(0, ibl_scope_hl_name, line_nr_hl) end + if not_set(get(ibl_current_indent_hl_name)) then + vim.api.nvim_set_hl(0, ibl_current_indent_hl_name, cursor_line_nr_hl) + end end M.setup = function() @@ -107,6 +114,20 @@ M.setup = function() vim.api.nvim_set_hl(0, M.scope[i].char, char_hl) vim.api.nvim_set_hl(0, M.scope[i].underline, { sp = char_hl.fg, underline = true }) end + + local current_indent_highlights = config.current_indent.highlight + M.current_indent = {} + local char_hl = get(current_indent_highlights) + if not_set(char_hl) then + error(string.format("No highlight group '%s' found", current_indent_highlights)) + end + char_hl.nocombine = true + M.current_indent = { + char = "@ibl.current_indent.char", + underline = "@ibl.current_indent.underline", + } + vim.api.nvim_set_hl(0, M.current_indent.char, char_hl) + vim.api.nvim_set_hl(0, M.current_indent.underline, { sp = char_hl.fg, underline = true }) end return M diff --git a/lua/ibl/indent.lua b/lua/ibl/indent.lua index 0e394719..1c30f0b7 100644 --- a/lua/ibl/indent.lua +++ b/lua/ibl/indent.lua @@ -45,6 +45,7 @@ M.get = function(whitespace, opts, indent_state) if shiftwidth == 0 then shiftwidth = tabstop end + local whitespace_tbl = {} for ch in whitespace:gmatch "." do diff --git a/lua/ibl/init.lua b/lua/ibl/init.lua index e5683a93..5ad64b2a 100644 --- a/lua/ibl/init.lua +++ b/lua/ibl/init.lua @@ -169,7 +169,7 @@ M.refresh = function(bufnr) end end - local left_offset, top_offset, win_end, win_height = utils.get_offset(bufnr) + local left_offset, top_offset, win_end, win_height, cursor_row = utils.get_offset(bufnr) if top_offset > win_end then return end @@ -211,7 +211,6 @@ M.refresh = function(bufnr) end local indent_state - local next_whitespace_tbl = {} local empty_line_counter = 0 local buffer_state = global_buffer_state[bufnr] @@ -244,14 +243,18 @@ M.refresh = function(bufnr) end local exact_scope_col_start = scope_col_start - ---@type ibl.indent.whitespace[] - local last_whitespace_tbl = {} + local cursor_row_stack_size = -1 + local current_indent_row_start = offset + 1 + local current_indent_row_end = range + ---@type table local line_skipped = {} + ---@type ibl.hooks.cb.skip_line[] local skip_line_hooks = hooks.get(bufnr, hooks.type.SKIP_LINE) for i, line in ipairs(lines) do local row = i + offset + line_skipped[i] = false for _, fn in pairs(skip_line_hooks) do if fn(buffer_state.tick, bufnr, row - 1, line) then line_skipped[i] = true @@ -260,8 +263,56 @@ M.refresh = function(bufnr) end end + local get_indent_details = function(ws_tbl) + local number_of_indents = 0 + local last_indent_col = -1 + if not ws_tbl then + return number_of_indents, last_indent_col + end + local k = 0 + local has_seen_indent = false + while k < #ws_tbl do + if indent.is_indent(ws_tbl[#ws_tbl - k]) then + if not has_seen_indent then + has_seen_indent = true + last_indent_col = #ws_tbl - k - 1 + end + number_of_indents = number_of_indents + 1 + end + k = k + 1 + end + return number_of_indents, last_indent_col + end + + ---@type number + local cur_indent_stack_size = 0 + + ---@type number + local current_indent_col = -1 + + ---@type ibl.indent.whitespace[] + local next_whitespace_tbl = {} + + -- array of tables + ---@type table + local arr_whitespace_tbl = {} + + -- arrays of numbers + ---@type table + local current_indent_stack = {} -- current indent stack of line nr + ---@type table + local arr_whitespace_len = {} + + -- boolean arrays + ---@type table + local arr_blankline = {} + ---@type table + local arr_whitespace_only = {} + + -- in the first loop we calculate the things we need to setup the virtual text via extmarks for i, line in ipairs(lines) do local row = i + offset + if line_skipped[i] then vt.clear_buffer(bufnr, row) goto continue @@ -269,23 +320,31 @@ M.refresh = function(bufnr) local whitespace = utils.get_whitespace(line) local foldclosed = vim.fn.foldclosed(row) + if is_current_buffer and foldclosed == row then local foldtext = vim.fn.foldtextresult(row) local foldtext_whitespace = utils.get_whitespace(foldtext) if vim.fn.strdisplaywidth(foldtext_whitespace, 0) < vim.fn.strdisplaywidth(whitespace, 0) then vt.clear_buffer(bufnr, row) + line_skipped[i] = true goto continue end end if is_current_buffer and foldclosed > -1 and foldclosed + win_height < row then vt.clear_buffer(bufnr, row) + line_skipped[i] = true goto continue end ---@type ibl.indent.whitespace[] local whitespace_tbl + local blankline = line:len() == 0 + arr_blankline[i] = blankline + + arr_whitespace_len[i] = #whitespace + arr_whitespace_only[i] = not blankline and line == whitespace -- #### calculate indent #### if not blankline then @@ -309,6 +368,7 @@ M.refresh = function(bufnr) whitespace_tbl, indent_state = indent.get(j_whitespace, indent_opts, indent_state) if utils.has_end(lines[j]) then + local last_whitespace_tbl = arr_whitespace_tbl[i - 1] or {} local trail = last_whitespace_tbl[indent_state.stack[#indent_state.stack] + 1] local trail_whitespace = last_whitespace_tbl[indent_state.stack[#indent_state.stack]] if trail then @@ -325,25 +385,6 @@ M.refresh = function(bufnr) next_whitespace_tbl = whitespace_tbl end - local scope_active = row >= scope_row_start and row <= scope_row_end - if - scope_active - and scope_col_start_single > -1 - and (whitespace_tbl[scope_col_start_single + 1] or blankline) - and not indent.is_indent(whitespace_tbl[scope_col_start_single + 1]) - then - if indent.is_space_indent(whitespace_tbl[scope_col_start_single + 1]) then - whitespace_tbl[scope_col_start_single + 1] = indent.whitespace.INDENT - else - whitespace_tbl[scope_col_start_single + 1] = indent.whitespace.TAB_START - end - local k = scope_col_start_single - while not whitespace_tbl[k] and k >= 0 do - whitespace_tbl[k] = indent.whitespace.SPACE - k = k - 1 - end - end - -- remove blankline trail if blankline and config.whitespace.remove_blankline_trail then while #whitespace_tbl > 0 do @@ -354,6 +395,40 @@ M.refresh = function(bufnr) end end + if config.current_indent.enabled then + local number_of_indents, last_indent_col = get_indent_details(whitespace_tbl) + + local prev_indent_stack_size = cur_indent_stack_size + + cur_indent_stack_size = number_of_indents + + if row <= cursor_row then + if prev_indent_stack_size > cur_indent_stack_size then + -- we need to take into account that we might jump back more than + -- only one indent level at once + while prev_indent_stack_size > cur_indent_stack_size do + current_indent_stack[#current_indent_stack] = nil + prev_indent_stack_size = prev_indent_stack_size - 1 + end + elseif prev_indent_stack_size < cur_indent_stack_size then + current_indent_stack[#current_indent_stack + 1] = row + end + else + -- row > cursor_row + if cursor_row_stack_size >= 0 and cursor_row_stack_size > cur_indent_stack_size then + current_indent_row_end = row - 1 + cursor_row_stack_size = -1 + end + end + if row == cursor_row then + cursor_row_stack_size = cur_indent_stack_size + current_indent_col = last_indent_col + if current_indent_stack[#current_indent_stack] then + current_indent_row_start = current_indent_stack[#current_indent_stack] + end + end + end + -- Fix horizontal scroll local current_left_offset = left_offset while #whitespace_tbl > 0 and current_left_offset > 0 do @@ -367,13 +442,59 @@ M.refresh = function(bufnr) whitespace_tbl = fn(buffer_state.tick, bufnr, row - 1, whitespace_tbl) end - last_whitespace_tbl = whitespace_tbl + -- this do block is purely to help stylua with the scope + do + arr_whitespace_tbl[i] = whitespace_tbl + end + + ::continue:: + end + + -- set up the virtual text via extmarks + for i, line in ipairs(lines) do + if line_skipped[i] then + goto continue1 + end + + local row = i + offset + local whitespace_len = arr_whitespace_len[i] + + local blankline = arr_blankline[i] + local whitespace_tbl = arr_whitespace_tbl[i] + local whitespace_only = arr_whitespace_only[i] + + local scope_active = row >= scope_row_start and row <= scope_row_end + if + scope_active + and scope_col_start_single > -1 + and (whitespace_tbl[scope_col_start_single + 1] or blankline) + and not indent.is_indent(whitespace_tbl[scope_col_start_single + 1]) + then + if indent.is_space_indent(whitespace_tbl[scope_col_start_single + 1]) then + whitespace_tbl[scope_col_start_single + 1] = indent.whitespace.INDENT + else + whitespace_tbl[scope_col_start_single + 1] = indent.whitespace.TAB_START + end + local k = scope_col_start_single + while not whitespace_tbl[k] and k >= 0 do + whitespace_tbl[k] = indent.whitespace.SPACE + k = k - 1 + end + end -- #### make virtual text #### local scope_start = row == scope_row_start local scope_end = row == scope_row_end + + local current_indent_start = row == current_indent_row_start - 1 + local current_indent_end = row == current_indent_row_end + 1 + + local current_indent_active = row >= current_indent_row_start + and row <= current_indent_row_end + and config.current_indent.enabled + if scope_start and scope then - scope_col_start = #whitespace + scope_col_start = whitespace_len scope_col_start_single = #whitespace_tbl scope_index = #vim.tbl_filter(function(w) return indent.is_indent(w) @@ -385,16 +506,24 @@ M.refresh = function(bufnr) end end - local whitespace_only = not blankline and line == whitespace local char_map = vt.get_char_map(config, listchars, whitespace_only, blankline) - local virt_text, scope_hl = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local virt_text, scope_hl, current_indent_hl = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) -- #### set virtual text #### vt.clear_buffer(bufnr, row) -- Show exact scope - local scope_col_start_draw = #whitespace + local scope_col_start_draw = whitespace_len local scope_show_end_cond = #whitespace_tbl > scope_col_start_single if config.scope.show_exact_scope then @@ -410,7 +539,7 @@ M.refresh = function(bufnr) priority = config.scope.priority, strict = false, }) - inlay_hints.set(bufnr, row - 1, #whitespace, scope_hl.underline, scope_hl.underline) + inlay_hints.set(bufnr, row - 1, whitespace_len, scope_hl.underline, scope_hl.underline) end -- Scope end @@ -421,7 +550,34 @@ M.refresh = function(bufnr) priority = config.scope.priority, strict = false, }) - inlay_hints.set(bufnr, row - 1, #whitespace, scope_hl.underline, scope_hl.underline) + inlay_hints.set(bufnr, row - 1, whitespace_len, scope_hl.underline, scope_hl.underline) + end + + -- current_indent start + if config.current_indent.show_start and current_indent_start and current_indent_col >= 0 then + vim.api.nvim_buf_set_extmark(bufnr, namespace, row - 1, current_indent_col, { + end_col = #line, + hl_group = current_indent_hl.underline, + priority = config.current_indent.priority, + strict = false, + }) + inlay_hints.set(bufnr, row - 1, whitespace_len, current_indent_hl.underline, current_indent_hl.underline) + end + + -- current_indent end + if + config.current_indent.show_end + and current_indent_end + and #whitespace_tbl >= current_indent_col + and current_indent_col >= 0 + then + vim.api.nvim_buf_set_extmark(bufnr, namespace, row - 1, current_indent_col, { + end_col = #line, + hl_group = current_indent_hl.underline, + priority = config.current_indent.priority, + strict = false, + }) + inlay_hints.set(bufnr, row - 1, whitespace_len, current_indent_hl.underline, current_indent_hl.underline) end for _, fn in @@ -441,7 +597,7 @@ M.refresh = function(bufnr) }) end - ::continue:: + ::continue1:: end end diff --git a/lua/ibl/utils.lua b/lua/ibl/utils.lua index addbfa34..b4e48be3 100644 --- a/lua/ibl/utils.lua +++ b/lua/ibl/utils.lua @@ -168,7 +168,7 @@ M.get_offset = function(bufnr) else local win_list = vim.fn.win_findbuf(bufnr) if not win_list or not win_list[1] then - return 0, 0, 0, 0 + return 0, 0, 0, 0, 0 end win = win_list[1] win_view = vim.api.nvim_win_call(win, vim.fn.winsaveview) @@ -183,7 +183,7 @@ M.get_offset = function(bufnr) win_end = win_view.lnum + win_height end - return win_view.leftcol or 0, win_view.topline or 0, win_end, win_height + return win_view.leftcol or 0, win_view.topline or 0, win_end, win_height, win_view.lnum or 0 end ---@param bufnr number diff --git a/lua/ibl/virt_text.lua b/lua/ibl/virt_text.lua index d59c8d9d..bead6dab 100644 --- a/lua/ibl/virt_text.lua +++ b/lua/ibl/virt_text.lua @@ -61,9 +61,22 @@ end ---@param scope_index number ---@param scope_end boolean ---@param scope_col_start_single number ----@return ibl.virtual_text, ibl.highlight -M.get = function(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) +---@param current_indent_active boolean +---@param current_indent_col number +---@return ibl.virtual_text, ibl.highlight, ibl.highlight +M.get = function( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col +) local scope_hl = utils.tbl_get_index(highlights.scope, scope_index) + local current_indent_hl = highlights.current_indent local indent_index = 1 local virt_text = {} for i, ws in ipairs(whitespace_tbl) do @@ -71,6 +84,7 @@ M.get = function(config, char_map, whitespace_tbl, scope_active, scope_index, sc local indent_hl local underline_hl local sa = scope_active + local ca = current_indent_active local char = get_char(char_map[ws], indent_index) if indent.is_indent(ws) then @@ -89,18 +103,70 @@ M.get = function(config, char_map, whitespace_tbl, scope_active, scope_index, sc underline_hl = scope_hl.underline end - if sa and i - 1 == scope_col_start_single then - indent_hl = scope_hl.char + if config.scope.priority >= config.current_indent.priority then + if ca and i - 1 == current_indent_col then + indent_hl = current_indent_hl.char - if config.scope.char then - local scope_char = get_char(config.scope.char, scope_index) - if vim.fn.strdisplaywidth(scope_char) == 1 then - char = scope_char + if config.current_indent.char then + local current_indent_char = config.current_indent.char + if vim.fn.strdisplaywidth(current_indent_char or "") == 1 then + char = current_indent_char or "" + end + elseif not indent.is_indent(ws) then + if indent.is_space_indent(ws) then + char = get_char(char_map[whitespace.INDENT], indent_index) + else + char = get_char(char_map[whitespace.TAB_START], indent_index) + end end end - if config.scope.show_end and scope_end then - underline_hl = scope_hl.underline + if sa and i - 1 == scope_col_start_single then + indent_hl = scope_hl.char + + if config.scope.char then + local scope_char = get_char(config.scope.char, scope_index) + if vim.fn.strdisplaywidth(scope_char) == 1 then + char = scope_char + end + end + + if config.scope.show_end and scope_end then + underline_hl = scope_hl.underline + end + end + else + -- config.scope.priority < config.current_indent.priority + if sa and i - 1 == scope_col_start_single then + indent_hl = scope_hl.char + + if config.scope.char then + local scope_char = get_char(config.scope.char, scope_index) + if vim.fn.strdisplaywidth(scope_char) == 1 then + char = scope_char + end + end + + if config.scope.show_end and scope_end then + underline_hl = scope_hl.underline + end + end + + if ca and i - 1 == current_indent_col then + indent_hl = current_indent_hl.char + + if config.current_indent.char then + local current_indent_char = config.current_indent.char + if vim.fn.strdisplaywidth(current_indent_char or "") == 1 then + char = current_indent_char or "" + end + elseif not indent.is_indent(ws) then + if indent.is_space_indent(ws) then + char = get_char(char_map[whitespace.INDENT], indent_index) + else + char = get_char(char_map[whitespace.TAB_START], indent_index) + end + end end end @@ -112,7 +178,7 @@ M.get = function(config, char_map, whitespace_tbl, scope_active, scope_index, sc }) end - return virt_text, scope_hl + return virt_text, scope_hl, current_indent_hl end return M diff --git a/specs/features/virt_text_spec.lua b/specs/features/virt_text_spec.lua index 2e39c927..e3c173d4 100644 --- a/specs/features/virt_text_spec.lua +++ b/specs/features/virt_text_spec.lua @@ -282,9 +282,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, {}) end) @@ -305,9 +316,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -333,9 +355,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "a", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -363,9 +396,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "a", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -393,9 +437,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "e", { "@ibl.whitespace.char.1" } }, @@ -421,15 +476,143 @@ describe("virt_text", function() local scope_index = 1 local scope_end = false local scope_col_start_single = 2 + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + assert.are.same(virt_text, { + { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, + { "e", { "@ibl.whitespace.char.1" } }, + { "f", { "@ibl.whitespace.char.1", "@ibl.scope.char.1" } }, + { "e", { "@ibl.whitespace.char.1" } }, + }) + end) + + it("handles current_indent", function() + local config = conf.set_config() + highlights.setup() + local char_map = { + [TAB_START] = "a", + [TAB_START_SINGLE] = "b", + [TAB_FILL] = "c", + [TAB_END] = "d", + [SPACE] = "e", + [INDENT] = "f", + } + local whitespace_tbl = { INDENT, SPACE, INDENT, SPACE } + local scope_active = false + local scope_index = -1 + local scope_end = false + local scope_col_start_single = -1 + local current_indent_active = true + local current_indent_col = 2 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, { "e", { "@ibl.whitespace.char.1" } }, + { "f", { "@ibl.whitespace.char.1", "@ibl.current_indent.char" } }, + { "e", { "@ibl.whitespace.char.1" } }, + }) + end) + + it("handles current_indent and scope together", function() + local config = conf.set_config() + highlights.setup() + local char_map = { + [TAB_START] = "a", + [TAB_START_SINGLE] = "b", + [TAB_FILL] = "c", + [TAB_END] = "d", + [SPACE] = "e", + [INDENT] = "f", + } + local whitespace_tbl = { INDENT, SPACE, INDENT, SPACE } + local scope_active = true + local scope_index = 1 + local scope_end = false + local scope_col_start_single = 0 + local current_indent_active = true + local current_indent_col = 2 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) + + assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.scope.char.1" } }, { "e", { "@ibl.whitespace.char.1" } }, + { "f", { "@ibl.whitespace.char.1", "@ibl.current_indent.char" } }, + { "e", { "@ibl.whitespace.char.1" } }, + }) + end) + + it("handles current_indent and scope with priority in mind", function() + local config = conf.set_config { current_indent = { priority = 2000 } } + highlights.setup() + local char_map = { + [TAB_START] = "a", + [TAB_START_SINGLE] = "b", + [TAB_FILL] = "c", + [TAB_END] = "d", + [SPACE] = "e", + [INDENT] = "f", + } + local whitespace_tbl = { INDENT, SPACE, INDENT, SPACE } + local scope_active = true + local scope_index = 1 + local scope_end = false + local scope_col_start_single = 0 + local current_indent_active = true + local current_indent_col = 0 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) + + assert.are.same(virt_text, { + { "f", { "@ibl.whitespace.char.1", "@ibl.current_indent.char" } }, + { "e", { "@ibl.whitespace.char.1" } }, + { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, + { "e", { "@ibl.whitespace.char.1" } }, }) end) @@ -449,9 +632,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "a", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -481,9 +675,20 @@ describe("virt_text", function() local scope_index = -1 local scope_end = false local scope_col_start_single = 0 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -515,9 +720,20 @@ describe("virt_text", function() local scope_index = 2 local scope_end = false local scope_col_start_single = 2 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } }, @@ -549,9 +765,20 @@ describe("virt_text", function() local scope_index = 2 local scope_end = true local scope_col_start_single = 2 - - local virt_text = - vt.get(config, char_map, whitespace_tbl, scope_active, scope_index, scope_end, scope_col_start_single) + local current_indent_active = false + local current_indent_col = -1 + + local virt_text = vt.get( + config, + char_map, + whitespace_tbl, + scope_active, + scope_index, + scope_end, + scope_col_start_single, + current_indent_active, + current_indent_col + ) assert.are.same(virt_text, { { "f", { "@ibl.whitespace.char.1", "@ibl.indent.char.1" } },