From 58d7029b1a72a97a48f26221ffeae503f0b90075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tautvydas=20S=CC=8Cidlauskas?= Date: Mon, 28 Sep 2026 20:39:59 +0300 Subject: [PATCH] feat(guides): allow configuring widget guide characters Closes #555 --- README.md | 3 ++ lua/flutter-tools/config.lua | 8 ++++- lua/flutter-tools/guides.lua | 8 +---- tests/guides_spec.lua | 63 ++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 tests/guides_spec.lua diff --git a/README.md b/README.md index 539cafb2..f0011c51 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,9 @@ require("flutter-tools").setup { analyzer_web_port = nil, -- if set, the analysis server is started with `--port=` so it can be inspected in the browser widget_guides = { enabled = false, + -- characters used to draw the guides, each must be a single cell wide + -- e.g. `{ vertical = "┆", horizontal = "┄" }` for dashed lines + markers = { bottom = "└", middle = "├", vertical = "│", horizontal = "─" }, }, closing_tags = { highlight = "ErrorMsg", -- highlight for the closing tag diff --git a/lua/flutter-tools/config.lua b/lua/flutter-tools/config.lua index 75ddbb72..86ef260b 100644 --- a/lua/flutter-tools/config.lua +++ b/lua/flutter-tools/config.lua @@ -44,7 +44,7 @@ local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.util ---@field root_patterns? string[] Patterns to find project root ---@field fvm? boolean Whether to use FVM (Flutter Version Manager) ---@field default_run_args? flutter.RunArgsOpts Default options for run command ----@field widget_guides? {enabled: boolean, debug: boolean} +---@field widget_guides? {enabled: boolean, debug: boolean, markers?: {bottom?: string, middle?: string, vertical?: string, horizontal?: string}} ---@field ui? {border: string} ---@field decorations? {statusline: {app_version: boolean, device: boolean, project_config: boolean}} ---@field debugger? {enabled: boolean, exception_breakpoints?: table, evaluate_to_string_in_debug_views?: boolean, register_configurations?: fun(paths: table)} @@ -116,6 +116,12 @@ local config = { widget_guides = { enabled = false, debug = false, + markers = { + bottom = "└", + middle = "├", + vertical = "│", + horizontal = "─", + }, }, ui = { border = "single", diff --git a/lua/flutter-tools/guides.lua b/lua/flutter-tools/guides.lua index 336cac87..d0ef9df2 100644 --- a/lua/flutter-tools/guides.lua +++ b/lua/flutter-tools/guides.lua @@ -12,13 +12,6 @@ local widget_kind = "NEW_INSTANCE" local hl_group = "FlutterWidgetGuides" local widget_outline_ns_id = api.nvim_create_namespace("flutter_tools_outline_guides") -local markers = { - bottom = "└", - middle = "├", - vertical = "│", - horizontal = "─", -} - -- These offsets represent the points at which each character -- should should be added relative to the symbol it is for -- @@ -53,6 +46,7 @@ end ---@param children table[] ---@return string local function get_guide_character(lnum, end_line, parent_start, indent_size, children, lines) + local markers = config.widget_guides.markers for index, child in ipairs(children) do -- if the child is within the parent range but not at the end local child_lnum = child.range.start.line diff --git a/tests/guides_spec.lua b/tests/guides_spec.lua new file mode 100644 index 00000000..559d0dbb --- /dev/null +++ b/tests/guides_spec.lua @@ -0,0 +1,63 @@ +describe("widget guides", function() + local config + local guides + local bufnr + local api = vim.api + + local function widget(line, children) + return { + kind = "NEW_INSTANCE", + range = { start = { line = line, character = 0 } }, + children = children, + } + end + + local function render(guides_config) + config.set({ widget_guides = vim.tbl_extend("force", { enabled = true }, guides_config or {}) }) + guides.widget_guides(nil, { + uri = vim.uri_from_bufnr(bufnr), + outline = { children = { widget(0, { widget(2), widget(3) }) } }, + }) + local ns = api.nvim_get_namespaces()["flutter_tools_outline_guides"] + local result = {} + for _, mark in ipairs(api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, { details = true })) do + result[mark[2]] = mark[4].virt_text[1][1] + end + return result + end + + before_each(function() + package.loaded["flutter-tools.config"] = nil + package.loaded["flutter-tools.guides"] = nil + config = require("flutter-tools.config") + guides = require("flutter-tools.guides") + bufnr = api.nvim_create_buf(true, false) + api.nvim_buf_set_name(bufnr, "/tmp/guides_spec.dart") + api.nvim_buf_set_lines(bufnr, 0, -1, false, { + "Column(", + " children: [", + ' Text("a"),', + ' Text("b"),', + " ],", + ")", + }) + api.nvim_set_current_buf(bufnr) + end) + + after_each(function() api.nvim_buf_delete(bufnr, { force = true }) end) + + it("draws solid guides by default", function() + local result = render() + assert.are.same({ [1] = "│", [2] = "├───", [3] = "└───" }, result) + end) + + it("uses marker overrides and falls back to the defaults", function() + local result = render({ markers = { vertical = "┆", horizontal = "┄" } }) + assert.are.same({ [1] = "┆", [2] = "├┄┄┄", [3] = "└┄┄┄" }, result) + end) + + it("draws nothing when disabled", function() + local result = render({ enabled = false }) + assert.are.same({}, result) + end) +end)