From ac1db1af1df4dd39ebbc778d43789034ddad252d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Fr=C3=B3es=20Franco?= Date: Sun, 28 Jun 2026 12:19:21 +0000 Subject: [PATCH] refactor(lua): extract shared heading_level/is_table_row; dedup wiki_list in search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pulls the duplicated heading_level (keymaps/folding/textobjects) and is_table_row (commands/textobjects) helpers into lua/nuwiki/util.lua. The copies had drifted — only folding capped level >6 and only commands nil-guarded is_table_row; the unified versions keep both (cap + nil-safe), which also aligns the keymap/textobject paths with the server's level cap. search() now resolves config.wiki_list() once instead of twice. No behaviour change beyond the >6 cap now applying everywhere. Full editor harness green (10/10). Co-Authored-By: Claude Opus 4.8 --- lua/nuwiki/commands.lua | 9 ++++----- lua/nuwiki/folding.lua | 11 +---------- lua/nuwiki/keymaps.lua | 8 +------- lua/nuwiki/textobjects.lua | 12 ++---------- lua/nuwiki/util.lua | 31 +++++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 lua/nuwiki/util.lua diff --git a/lua/nuwiki/commands.lua b/lua/nuwiki/commands.lua index 7b310e3..db05b00 100644 --- a/lua/nuwiki/commands.lua +++ b/lua/nuwiki/commands.lua @@ -331,8 +331,9 @@ function M.search(args) end local config = require('nuwiki.config') local file = vim.fn.expand('%:p') + local wikis = config.wiki_list() local root, ext = '', '.wiki' - for _, w in ipairs(config.wiki_list()) do + for _, w in ipairs(wikis) do local wroot = vim.fn.fnamemodify(vim.fn.expand(w.root), ':p') if file:sub(1, #wroot) == wroot then root, ext = wroot, w.ext or ext @@ -340,7 +341,7 @@ function M.search(args) end end if root == '' then - local first = config.wiki_list()[1] + local first = wikis[1] if first then root = vim.fn.fnamemodify(vim.fn.expand(first.root), ':p') ext = first.ext or ext @@ -818,9 +819,7 @@ end -- *before* placing the cursor, all in a single `vim.schedule` tick. -- The algorithm matches the LSP server's implementation in nuwiki-rs. -local function is_table_row(line) - return line ~= nil and line:match('^%s*|.*|%s*$') ~= nil -end +local is_table_row = require('nuwiki.util').is_table_row local function table_cell_starts(line) -- Returns 1-based byte positions of each `|` separator. Cell N spans diff --git a/lua/nuwiki/folding.lua b/lua/nuwiki/folding.lua index 243aa12..2def6cc 100644 --- a/lua/nuwiki/folding.lua +++ b/lua/nuwiki/folding.lua @@ -9,16 +9,7 @@ local M = {} --- Heading level from one line of source. Returns 0 for non-headings. -local function heading_level(line) - local lead = line:match('^%s*(=+)%s') - if not lead then return 0 end - local lvl = #lead - if lvl > 6 then return 0 end - -- Require a matching trailing run of `=`s. - local trail = line:match('%s(=+)%s*$') - if not trail or #trail ~= lvl then return 0 end - return lvl -end +local heading_level = require('nuwiki.util').heading_level --- `foldexpr` body. Returns a fold-marker string per `:help fold-expr`. function M.expr() diff --git a/lua/nuwiki/keymaps.lua b/lua/nuwiki/keymaps.lua index 1ca7d7f..5c80ab5 100644 --- a/lua/nuwiki/keymaps.lua +++ b/lua/nuwiki/keymaps.lua @@ -29,13 +29,7 @@ end -- vimwiki's `vimwiki#base#goto_*_header` family does, just simpler: -- match `^\s*=` runs as heading lines. -local function heading_level(line) - local lead = line and line:match('^%s*(=+)%s') - if not lead then return 0 end - local trail = line:match('%s(=+)%s*$') - if not trail or #trail ~= #lead then return 0 end - return #lead -end +local heading_level = require('nuwiki.util').heading_level local function jump_heading(direction, predicate) local total = vim.api.nvim_buf_line_count(0) diff --git a/lua/nuwiki/textobjects.lua b/lua/nuwiki/textobjects.lua index f687094..1b7f395 100644 --- a/lua/nuwiki/textobjects.lua +++ b/lua/nuwiki/textobjects.lua @@ -15,13 +15,7 @@ local M = {} -- ===== Heading helpers ===== -local function heading_level(line) - local lead = line and line:match('^%s*(=+)%s') - if not lead then return 0 end - local trail = line:match('%s(=+)%s*$') - if not trail or #trail ~= #lead then return 0 end - return #lead -end +local heading_level = require('nuwiki.util').heading_level --- Find the start/end of the heading block at `lnum`. --- `with_subtree` controls whether we descend into sub-headings: @@ -123,9 +117,7 @@ end -- ===== Table cell / column ===== -local function is_table_row(line) - return line:match('^%s*|.*|%s*$') ~= nil -end +local is_table_row = require('nuwiki.util').is_table_row --- Compute the byte ranges of cells on a `|`-delimited row. --- Returns a list of `{start_byte, end_byte}` 1-based inclusive of the diff --git a/lua/nuwiki/util.lua b/lua/nuwiki/util.lua new file mode 100644 index 0000000..86c8d05 --- /dev/null +++ b/lua/nuwiki/util.lua @@ -0,0 +1,31 @@ +-- lua/nuwiki/util.lua — small pure-text helpers shared across the client +-- layers (keymaps, folding, textobjects, commands). Dependency-free so any +-- module can require it without load-order concerns. + +local M = {} + +-- Heading level of `line` (1-6), or 0 when it isn't a heading. Mirrors the +-- server lexer: balanced leading/trailing runs of `=` around non-empty text, +-- capped at level 6 (a 7+ `=` run is not a heading). `nil`-safe. +function M.heading_level(line) + local lead = line and line:match('^%s*(=+)%s') + if not lead then + return 0 + end + local lvl = #lead + if lvl > 6 then + return 0 + end + local trail = line:match('%s(=+)%s*$') + if not trail or #trail ~= lvl then + return 0 + end + return lvl +end + +-- True when `line` looks like a table row (`| … |`). `nil`-safe. +function M.is_table_row(line) + return line ~= nil and line:match('^%s*|.*|%s*$') ~= nil +end + +return M