diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2025-07-17 23:26:55 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-17 23:26:55 -0400 |
| commit | fd5d04fbffec9a4ba87add584b36abbefa21a69e (patch) | |
| tree | aa363c9fe287efa1ee0d7caab397270873d7fd23 /runtime/lua | |
| parent | 995bc31eafd2b3bee2ef10b1d0eb50313b2e6d46 (diff) | |
| parent | 1de2a03fc7f4cf2eb11300257c832f88422d4745 (diff) | |
| download | rneovim-fd5d04fbffec9a4ba87add584b36abbefa21a69e.tar.gz rneovim-fd5d04fbffec9a4ba87add584b36abbefa21a69e.tar.bz2 rneovim-fd5d04fbffec9a4ba87add584b36abbefa21a69e.zip | |
Merge #34921 tutor: reimplement interactive marks as extmarks
Diffstat (limited to 'runtime/lua')
| -rw-r--r-- | runtime/lua/nvim/tutor.lua | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/runtime/lua/nvim/tutor.lua b/runtime/lua/nvim/tutor.lua new file mode 100644 index 0000000000..2f7e571958 --- /dev/null +++ b/runtime/lua/nvim/tutor.lua @@ -0,0 +1,80 @@ +---@class nvim.TutorMetadata +---@field expect table<string, string|-1> + +---@alias nvim.TutorExtmarks table<string, string> + +---@type nvim.TutorExtmarks? +vim.b.tutor_extmarks = vim.b.tutor_extmarks + +---@type nvim.TutorMetadata? +vim.b.tutor_metadata = vim.b.tutor_metadata + +local sign_text_correct = '✓' +local sign_text_incorrect = '✗' +local tutor_mark_ns = vim.api.nvim_create_namespace('nvim.tutor.mark') +local tutor_hl_ns = vim.api.nvim_create_namespace('nvim.tutor.hl') + +local M = {} + +---@param line integer 1-based +local function check_line(line) + if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then + local ctext = vim.fn.getline(line) + + local extmarks = vim.api.nvim_buf_get_extmarks( + 0, + tutor_mark_ns, + { line - 1, 0 }, + { line - 1, -1 }, -- the extmark can move to col > 0 if users insert text there + {} + ) + for _, extmark in ipairs(extmarks) do + local mark_id = extmark[1] + local expct = vim.b.tutor_extmarks[tostring(mark_id)] + local expect = vim.b.tutor_metadata.expect[expct] + local is_correct = expect == -1 or ctext == expect + + vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, line - 1, 0, { + id = mark_id, + sign_text = is_correct and sign_text_correct or sign_text_incorrect, + sign_hl_group = is_correct and 'tutorOK' or 'tutorX', + -- This may be a hack. By default, all extmarks only move forward, so a line cannot contain + -- any extmarks that were originally created for later lines. + priority = tonumber(expct), + }) + end + end +end + +function M.apply_marks() + vim.cmd [[hi! link tutorExpect Special]] + if vim.b.tutor_metadata and vim.b.tutor_metadata.expect then + vim.b.tutor_extmarks = {} + for expct, _ in pairs(vim.b.tutor_metadata.expect) do + ---@diagnostic disable-next-line: assign-type-mismatch + local lnum = tonumber(expct) ---@type integer + vim.api.nvim_buf_set_extmark(0, tutor_hl_ns, lnum - 1, 0, { + line_hl_group = 'tutorExpect', + }) + + local mark_id = vim.api.nvim_buf_set_extmark(0, tutor_mark_ns, lnum - 1, 0, {}) + + -- Cannot edit field of a Vimscript dictionary from Lua directly, see `:h lua-vim-variables` + ---@type nvim.TutorExtmarks + local tutor_extmarks = vim.b.tutor_extmarks + tutor_extmarks[tostring(mark_id)] = expct + vim.b.tutor_extmarks = tutor_extmarks + + check_line(lnum) + end + end +end + +function M.apply_marks_on_changed() + if vim.b.tutor_metadata and vim.b.tutor_metadata.expect and vim.b.tutor_extmarks then + local lnum = vim.fn.line('.') + check_line(lnum) + end +end + +return M |