From 33b148752008aef20b460ebd61d71a3cd850a0da Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 28 Sep 2026 14:19:41 +0100 Subject: fix(editorconfig): handle root separately from properties Problem: A child root=false masks a parent root=true during merging. Solution: Return the search boundary separately from string properties. Exclude root from property callbacks and b:editorconfig. AI-assisted --- runtime/lua/editorconfig.lua | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'runtime/lua/editorconfig.lua') diff --git a/runtime/lua/editorconfig.lua b/runtime/lua/editorconfig.lua index 9941a7ccdc..9ac54096e2 100644 --- a/runtime/lua/editorconfig.lua +++ b/runtime/lua/editorconfig.lua @@ -59,7 +59,7 @@ local nvim_on = require('vim._core.util').nvim_on ---- @type table +--- @type table)> local properties = {} --- Modified version of the builtin assert that does not include error position information @@ -82,8 +82,9 @@ end --- If "true", then stop searching for `.editorconfig` files in parent --- directories. This property must be at the top-level of the --- `.editorconfig` file (i.e. it must not be within a glob section). +--- It only controls the search and is excluded from property callbacks and [b:editorconfig]. function properties.root() - -- Unused + -- Documentation only. The parser handles root separately. end --- One of `"utf-8"`, `"utf-8-bom"`, `"latin1"`, `"utf-16be"`, or `"utf-16le"`. @@ -267,13 +268,16 @@ end --- Parse options from an `.editorconfig` file --- @param filepath string File path of the file to apply EditorConfig settings to --- @param dir string Current directory ---- @return table Table of options to apply to the given file +--- @return table options to apply to the given file +--- @return boolean is_root Whether to stop searching parent directories local function parse(filepath, dir) local pat --- @type vim.regex? - local opts = {} --- @type table + local opts = {} --- @type table + local is_root = false local f = io.open(dir .. '/.editorconfig') if f then for line in f:lines() do + --- @cast line string local glob, key, val = parse_line(line) if glob then glob = glob:find('/') and (dir .. '/' .. glob:gsub('^/', '')) or ('**/' .. glob) @@ -287,7 +291,7 @@ local function parse(filepath, dir) elseif key ~= nil and val ~= nil then if key == 'root' then assert(val == 'true' or val == 'false', 'root must be either "true" or "false"') - opts.root = val == 'true' + is_root = val == 'true' elseif pat and pat:match_str(filepath) then opts[key] = val end @@ -295,7 +299,7 @@ local function parse(filepath, dir) end f:close() end - return opts + return opts, is_root end local M = {} @@ -317,20 +321,21 @@ function M.config(buf) return end - local opts = {} --- @type table + local opts = {} --- @type table for parent in vim.fs.parents(path) do - for k, v in pairs(parse(path, parent)) do + local parent_opts, is_root = parse(path, parent) + for k, v in pairs(parent_opts) do if opts[k] == nil then opts[k] = v end end - if opts.root then + if is_root then break end end - local applied = {} --- @type table + local applied = {} --- @type table for opt, val in pairs(opts) do if val ~= 'unset' then local func = M.properties[opt] -- cgit