From b27be35872e675e17b424bbe59ae78f21bfbd85e Mon Sep 17 00:00:00 2001 From: Kristijan Husak Date: Fri, 3 Oct 2025 12:21:29 +0200 Subject: [PATCH 1/2] fix(files): remove string tree-sitter parser With the change on nightly https://github.com/neovim/neovim/pull/35988, string parser creates a scratch buffer under the hood, and uses that as a source. This drastically decreases the performance of the current code. This commit refactors the code to remove the string parser, and adds own loading of the org buffers for the tree-sitter usage. Performance should be same as before, with the downside that all of the org files that are in org_agenda_files are now loaded as unlisted buffers. --- .../colors/highlighter/markup/init.lua | 2 +- lua/orgmode/files/file.lua | 151 ++++++++---------- lua/orgmode/files/headline.lua | 4 +- lua/orgmode/init.lua | 9 ++ tests/plenary/agenda/agenda_item_spec.lua | 2 +- tests/plenary/capture/capture_spec.lua | 8 +- tests/plenary/capture/datetree_spec.lua | 78 ++++----- tests/plenary/files/file_spec.lua | 47 +----- tests/plenary/files/headline_spec.lua | 10 +- tests/plenary/helpers.lua | 18 +-- 10 files changed, 139 insertions(+), 190 deletions(-) diff --git a/lua/orgmode/colors/highlighter/markup/init.lua b/lua/orgmode/colors/highlighter/markup/init.lua index d68c421b6..5b22cf99e 100644 --- a/lua/orgmode/colors/highlighter/markup/init.lua +++ b/lua/orgmode/colors/highlighter/markup/init.lua @@ -169,7 +169,7 @@ end ---@return OrgMarkupPreparedHighlight[] function OrgMarkup:get_prepared_headline_highlights(headline) local highlights = - self:get_node_highlights(headline:node(), headline.file:get_source(), select(1, headline:node():range())) + self:get_node_highlights(headline:node(), headline.file:bufnr(), select(1, headline:node():range())) local result = {} diff --git a/lua/orgmode/files/file.lua b/lua/orgmode/files/file.lua index cd125dc82..0b471e33e 100644 --- a/lua/orgmode/files/file.lua +++ b/lua/orgmode/files/file.lua @@ -17,14 +17,13 @@ local Memoize = require('orgmode.utils.memoize') ---@class OrgFileOpts ---@field filename string ----@field lines string[] ----@field bufnr? number +---@field buf number ---@class OrgFile ---@field filename string +---@field buf number ---@field index number ---@field lines string[] ----@field content string ---@field metadata OrgFileMetadata ---@field parser vim.treesitter.LanguageTree ---@field root TSNode @@ -44,15 +43,17 @@ function OrgFile:new(opts) local stat = vim.uv.fs_stat(opts.filename) local data = { filename = opts.filename, - lines = opts.lines, - content = table.concat(opts.lines, '\n'), index = 0, + buf = opts.buf or -1, metadata = { mtime = stat and stat.mtime.nsec or 0, mtime_sec = stat and stat.mtime.sec or 0, - changedtick = opts.bufnr and vim.api.nvim_buf_get_changedtick(opts.bufnr) or 0, + changedtick = opts.buf and vim.api.nvim_buf_get_changedtick(opts.buf) or 0, }, } + if data.buf > 0 then + data.lines = self:_get_lines(data.buf) + end setmetatable(data, self) return data end @@ -62,15 +63,10 @@ end function OrgFile.load(filename) local bufnr = utils.get_buffer_by_filename(filename) - if - bufnr > -1 - and vim.api.nvim_buf_is_loaded(bufnr) - and vim.api.nvim_get_option_value('filetype', { buf = bufnr }) == 'org' - then + if bufnr > -1 and vim.api.nvim_buf_is_loaded(bufnr) and vim.bo[bufnr].filetype == 'org' then return Promise.resolve(OrgFile:new({ filename = filename, - lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), - bufnr = bufnr, + buf = bufnr, })) end @@ -78,12 +74,18 @@ function OrgFile.load(filename) return Promise.resolve(false) end - return utils.readfile(filename, { schedule = true }):next(function(lines) - return OrgFile:new({ - filename = filename, - lines = lines, - }) - end) + bufnr = vim.fn.bufadd(filename) + + if bufnr == 0 then + return Promise.resolve(false) + end + + vim.fn.bufload(bufnr) + + return Promise.resolve(OrgFile:new({ + filename = filename, + buf = bufnr, + })) end ---Reload the file if it has been modified @@ -94,15 +96,34 @@ function OrgFile:reload() end local bufnr = self:bufnr() + local buf_changed = false + local file_changed = false - if bufnr > -1 then - local updated_file = self:_update_lines(vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), bufnr) - return Promise.resolve(updated_file) + if bufnr then + local new_changedtick = vim.api.nvim_buf_get_changedtick(bufnr) + buf_changed = self.metadata.changedtick ~= new_changedtick + self.metadata.changedtick = new_changedtick + if buf_changed then + self.lines = self:_get_lines(bufnr) + end end - - return utils.readfile(self.filename, { schedule = true }):next(function(lines) - return self:_update_lines(lines) - end) + local stat = vim.uv.fs_stat(self.filename) + if stat then + local new_mtime_nsec = stat.mtime.nsec + local new_mtime_sec = stat.mtime.sec + file_changed = (new_mtime_nsec > 0 and self.metadata.mtime ~= new_mtime_nsec) + or self.metadata.mtime_sec ~= new_mtime_sec + self.metadata.mtime = new_mtime_nsec + self.metadata.mtime_sec = new_mtime_sec + end + + if file_changed and not buf_changed then + return utils.readfile(self.filename, { schedule = true }):next(function(lines) + self.lines = lines + return self + end) + end + return Promise.resolve(self) end ---sync reload the file if it has been modified @@ -146,7 +167,9 @@ function OrgFile:is_modified() local bufnr = self:bufnr() if bufnr > -1 then local cur_changedtick = vim.api.nvim_buf_get_changedtick(bufnr) - return cur_changedtick ~= self.metadata.changedtick + if cur_changedtick ~= self.metadata.changedtick then + return true + end end local stat = vim.uv.fs_stat(self.filename) if not stat then @@ -166,7 +189,7 @@ function OrgFile:parse(skip_if_not_modified) if skip_if_not_modified and self.root and not self:is_modified() then return self.root end - self.parser = self:_get_parser() + self.parser = ts.get_parser(self:bufnr(), 'org', {}) local trees = self.parser:parse() self.root = trees[1]:root() return self.root @@ -185,7 +208,7 @@ function OrgFile:get_ts_matches(query, parent_node) local ts_query = ts_utils.get_query(query) local matches = {} - for _, match, _ in ts_query:iter_matches(parent_node, self:get_source(), nil, nil, { all = true }) do + for _, match, _ in ts_query:iter_matches(parent_node, self:bufnr(), nil, nil, { all = true }) do local items = {} for id, nodes in pairs(match) do local name = ts_query.captures[id] @@ -215,7 +238,7 @@ function OrgFile:get_ts_captures(query, node) local ts_query = ts_utils.get_query(query) local matches = {} - for _, match in ts_query:iter_captures(node, self:get_source()) do + for _, match in ts_query:iter_captures(node, self:bufnr()) do table.insert(matches, match) end return matches @@ -466,13 +489,13 @@ function OrgFile:get_node_text(node, range) return '' end if range then - return ts.get_node_text(node, self:get_source(), { + return ts.get_node_text(node, self:bufnr(), { metadata = { range = range, }, }) end - return ts.get_node_text(node, self:get_source()) + return ts.get_node_text(node, self:bufnr()) end ---@param node? TSNode @@ -534,19 +557,22 @@ end ---@return number function OrgFile:bufnr() - local bufnr = utils.get_buffer_by_filename(self.filename) + local bufnr = self.buf -- Do not consider unloaded buffers as valid -- Treesitter is not working in them if bufnr > -1 and vim.api.nvim_buf_is_loaded(bufnr) then return bufnr end - return -1 + local new_bufnr = vim.fn.bufadd(self.filename) + vim.fn.bufload(new_bufnr) + self.buf = new_bufnr + return new_bufnr end ---Return valid buffer handle or throw an error if it's not valid ---@return number function OrgFile:get_valid_bufnr() - local bufnr = utils.get_buffer_by_filename(self.filename) + local bufnr = self:bufnr() if bufnr < 0 then error('[orgmode] No valid buffer for file ' .. self.filename .. ' to edit', 0) end @@ -784,7 +810,7 @@ function OrgFile:get_links() (link_desc) @link ]]) - local source = self:get_source() + local source = self:bufnr() for _, node in ipairs(matches) do table.insert(links, Hyperlink.from_node(node, source)) end @@ -805,7 +831,7 @@ function OrgFile:get_footnote_references() local footnotes = {} local processed_lines = {} - for _, match in ts_query:iter_captures(self.root, self:get_source()) do + for _, match in ts_query:iter_captures(self.root, self:bufnr()) do local line_start, _, line_end = match:range() if not processed_lines[line_start] then if line_start == line_end then @@ -895,51 +921,14 @@ function OrgFile:_get_directive(directive_name) end ---@private ----@param lines string[] ----@param bufnr? number -function OrgFile:_update_lines(lines, bufnr) - self.lines = lines - self.content = table.concat(lines, '\n') - self:parse() - if bufnr then - self.metadata.changedtick = vim.api.nvim_buf_get_changedtick(bufnr) - end - local stat = vim.uv.fs_stat(self.filename) - if stat then - self.metadata.mtime = stat.mtime.nsec - self.metadata.mtime_sec = stat.mtime.sec - end - return self -end - ----@private ----@return vim.treesitter.LanguageTree -function OrgFile:_get_parser() - local bufnr = self:bufnr() - - if bufnr > -1 then - -- Always get the fresh parser for the buffer - return ts.get_parser(bufnr, 'org', {}) - end - - -- In case the buffer got unloaded, go back to string parser - if not self.parser or self:is_modified() or type(self.parser:source()) == 'number' then - return ts.get_string_parser(self.content, 'org', {}) - end - - return self.parser -end - ---- Get the ts source for the file ---- If there is a buffer, return buffer number ---- Otherwise, return the string content ----@return integer | string -function OrgFile:get_source() - local bufnr = self:bufnr() - if bufnr > -1 then - return bufnr +---Get all buffer lines, ensure empty buffer returns empty table +---@return string[] +function OrgFile:_get_lines(bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + if #lines == 1 and lines[1] == '' then + lines = {} end - return self.content + return lines end return OrgFile diff --git a/lua/orgmode/files/headline.lua b/lua/orgmode/files/headline.lua index 79ab092d7..415074fdb 100644 --- a/lua/orgmode/files/headline.lua +++ b/lua/orgmode/files/headline.lua @@ -738,7 +738,7 @@ function Headline:get_plan_dates() if name ~= 'NONE' then has_plan_dates = true end - dates[name:upper()] = Date.from_node(timestamp, self.file:get_source(), { + dates[name:upper()] = Date.from_node(timestamp, self.file:bufnr(), { type = name:upper(), }) dates_nodes[name:upper()] = node @@ -792,7 +792,7 @@ function Headline:get_non_plan_dates() end local all_dates = {} - local source = self.file:get_source() + local source = self.file:bufnr() for _, match in ipairs(matches) do local dates = Date.from_node(match, source) vim.list_extend(all_dates, dates) diff --git a/lua/orgmode/init.lua b/lua/orgmode/init.lua index f04a50b91..616c084a6 100644 --- a/lua/orgmode/init.lua +++ b/lua/orgmode/init.lua @@ -91,6 +91,15 @@ end function Org:setup_autocmds() local org_augroup = vim.api.nvim_create_augroup('orgmode_nvim', { clear = true }) + vim.api.nvim_create_autocmd('BufWinEnter', { + pattern = { '*.org', '*.org_archive' }, + group = org_augroup, + callback = function(event) + if not vim.bo[event.buf].filetype or vim.bo[event.buf].filetype == '' then + vim.bo[event.buf].filetype = 'org' + end + end, + }) vim.api.nvim_create_autocmd('BufWritePost', { pattern = { '*.org', '*.org_archive' }, group = org_augroup, diff --git a/tests/plenary/agenda/agenda_item_spec.lua b/tests/plenary/agenda/agenda_item_spec.lua index 56981f572..5f785573e 100644 --- a/tests/plenary/agenda/agenda_item_spec.lua +++ b/tests/plenary/agenda/agenda_item_spec.lua @@ -8,7 +8,7 @@ local helpers = require('tests.plenary.helpers') local function generate(content_line, keyword) keyword = keyword or 'TODO' - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '* ' .. keyword .. ' This is some content', content_line, }) diff --git a/tests/plenary/capture/capture_spec.lua b/tests/plenary/capture/capture_spec.lua index 13191b83c..e4c06a4eb 100644 --- a/tests/plenary/capture/capture_spec.lua +++ b/tests/plenary/capture/capture_spec.lua @@ -198,7 +198,7 @@ describe('Refile', function() }) local capture_lines = { '** baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) local item = capture_file:get_headlines()[1] ---@diagnostic disable-next-line: invisible @@ -226,7 +226,7 @@ describe('Capture', function() local destination_file = helpers.create_file({}) local capture_lines = { '* foo' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) local item = capture_file:get_headlines()[1] local template = Template:new({ properties = { @@ -310,7 +310,7 @@ describe('Capture', function() }) local capture_lines = { '** baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) local item = capture_file:get_headlines()[1] local template = Template:new({ properties = { @@ -355,7 +355,7 @@ describe('Capture', function() }) local capture_lines = { '** baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) local item = capture_file:get_headlines()[1] local template = Template:new({ regexp = 'appendhere', diff --git a/tests/plenary/capture/datetree_spec.lua b/tests/plenary/capture/datetree_spec.lua index 4a818b102..62e48eedb 100644 --- a/tests/plenary/capture/datetree_spec.lua +++ b/tests/plenary/capture/datetree_spec.lua @@ -32,7 +32,7 @@ describe('Datetree', function() local date = Date.from_string('2024-02-05') local opts = get_template(date) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -55,7 +55,7 @@ describe('Datetree', function() '*** ' .. in_two_years:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -81,7 +81,7 @@ describe('Datetree', function() '*** ' .. two_years_ago:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -111,7 +111,7 @@ describe('Datetree', function() '*** ' .. in_two_years:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -139,7 +139,7 @@ describe('Datetree', function() '* ' .. date:format('%Y'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -162,7 +162,7 @@ describe('Datetree', function() '**** future month note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -191,7 +191,7 @@ describe('Datetree', function() '**** two months ago', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -225,7 +225,7 @@ describe('Datetree', function() '**** in two months', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -254,7 +254,7 @@ describe('Datetree', function() '** ' .. date:format('%Y-%m %B'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -277,7 +277,7 @@ describe('Datetree', function() '**** future day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -302,7 +302,7 @@ describe('Datetree', function() '**** past day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -331,7 +331,7 @@ describe('Datetree', function() '**** future day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -361,7 +361,7 @@ describe('Datetree', function() '**** existing day second note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -405,7 +405,7 @@ describe('Datetree', function() local date = Date.from_string('2024-02-05') local opts = get_template(date) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -428,7 +428,7 @@ describe('Datetree', function() '*** ' .. two_years_ago:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -454,7 +454,7 @@ describe('Datetree', function() '*** ' .. in_two_years:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -484,7 +484,7 @@ describe('Datetree', function() '*** ' .. two_years_ago:format('%Y-%m-%d %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -512,7 +512,7 @@ describe('Datetree', function() '* ' .. date:format('%Y'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -535,7 +535,7 @@ describe('Datetree', function() '**** future month note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -564,7 +564,7 @@ describe('Datetree', function() '**** two months ago', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -598,7 +598,7 @@ describe('Datetree', function() '**** two months ago', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -627,7 +627,7 @@ describe('Datetree', function() '** ' .. date:format('%Y-%m %B'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -650,7 +650,7 @@ describe('Datetree', function() '**** future day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -675,7 +675,7 @@ describe('Datetree', function() '**** past day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -702,7 +702,7 @@ describe('Datetree', function() '**** past day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -732,7 +732,7 @@ describe('Datetree', function() '**** existing day second note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -793,7 +793,7 @@ describe('Datetree', function() local date = Date.from_string('2024-02-05') local opts = get_template(date) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -816,7 +816,7 @@ describe('Datetree', function() '*** ' .. in_two_years:format('%m/%d/%Y %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -842,7 +842,7 @@ describe('Datetree', function() '*** ' .. two_years_ago:format('%m/%d/%Y %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -872,7 +872,7 @@ describe('Datetree', function() '*** ' .. in_two_years:format('%m/%d/%Y %A'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -900,7 +900,7 @@ describe('Datetree', function() '* ' .. date:format('%Y'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -923,7 +923,7 @@ describe('Datetree', function() '**** future month note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -952,7 +952,7 @@ describe('Datetree', function() '**** two months ago', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -986,7 +986,7 @@ describe('Datetree', function() '**** in two months', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -1015,7 +1015,7 @@ describe('Datetree', function() '** ' .. date:format('%m/%Y %B'), }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -1038,7 +1038,7 @@ describe('Datetree', function() '**** future day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -1063,7 +1063,7 @@ describe('Datetree', function() '**** past day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -1092,7 +1092,7 @@ describe('Datetree', function() '**** future day note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] @@ -1122,7 +1122,7 @@ describe('Datetree', function() '**** existing day second note', }) local capture_lines = { '* baz' } - local capture_file = helpers.create_file_instance(capture_lines) + local capture_file = helpers.create_file(capture_lines) opts.source_file = capture_file opts.source_headline = capture_file:get_headlines()[1] diff --git a/tests/plenary/files/file_spec.lua b/tests/plenary/files/file_spec.lua index 0f9e8977b..c5d0d3959 100644 --- a/tests/plenary/files/file_spec.lua +++ b/tests/plenary/files/file_spec.lua @@ -17,11 +17,10 @@ describe('OrgFile', function() assert.are.same(filename, file.filename) assert.are.same({ '* Headline 1' }, file.lines) - assert.are.same('* Headline 1', file.content) local stat = vim.uv.fs_stat(filename) or {} assert.are.same(stat.mtime.nsec, file.metadata.mtime) assert.are.same(stat.mtime.sec, file.metadata.mtime_sec) - assert.are.same(0, file.metadata.changedtick) + assert.are.same(2, file.metadata.changedtick) end) it('should not load a file that is not an org file', function() @@ -37,14 +36,13 @@ describe('OrgFile', function() assert.are.same(filename, file.filename) assert.are.same({ '* Headline 2' }, file.lines) - assert.are.same('* Headline 2', file.content) local stat = vim.uv.fs_stat(filename) or {} assert.are.same(stat.mtime.nsec, file.metadata.mtime) assert.are.same(stat.mtime.sec, file.metadata.mtime_sec) - assert.are.same(0, file.metadata.changedtick) + assert.are.same(2, file.metadata.changedtick) vim.cmd('write!') file:reload_sync() - assert.are.same(4, file.metadata.changedtick) + assert.are.same(2, file.metadata.changedtick) end) it('should load files with special characters in filename from buffer', function() @@ -72,7 +70,6 @@ describe('OrgFile', function() file = file:reload_sync() assert.are.not_same(old_mtime, file.metadata.mtime) assert.are.same({ '* Headline 3 edited' }, file.lines) - assert.are.same('* Headline 3 edited', file.content) end) it('should reload a buffer if its modified', function() @@ -88,7 +85,6 @@ describe('OrgFile', function() assert.are.same(old_mtime, file.metadata.mtime) assert.are.not_same(old_changedtick, file.metadata.changedtick) assert.are.same({ '* Headline 3', '* Headline 4' }, file.lines) - assert.are.same('* Headline 3\n* Headline 4', file.content) end) end) @@ -481,18 +477,6 @@ describe('OrgFile', function() end) describe('set_node_text', function() - it('should throw an error if file is not loaded in buffer', function() - local file = load_file_sync({ - '* Headline 1 :TAG:', - ' The content', - ' Multi line', - }) - local paragraph_node = file:get_node_at_cursor():parent() - assert.is.error_matches(function() - return file:set_node_text(paragraph_node, 'New Text') - end, '%[orgmode%] No valid buffer for file ' .. file.filename .. ' to edit') - end) - it('should set node text', function() local file = load_file_sync({ '* Headline 1 :TAG:', @@ -546,15 +530,6 @@ describe('OrgFile', function() end) describe('bufnr', function() - it('should return -1 if there is no buffer', function() - local file = load_file_sync({ - '* Headline 1 :TAG:', - ' The content', - ' Multi line', - }) - assert.are.same(-1, file:bufnr()) - end) - it('should return buffer number if file is loaded', function() local file = load_file_sync({ '* Headline 1 :TAG:', @@ -565,19 +540,6 @@ describe('OrgFile', function() assert.is.True(file:bufnr() > 0) end) - it('should return -1 if file is loaded in buffer but buffer is not loaded', function() - local file = load_file_sync({ - '* Headline 1 :TAG:', - ' The content', - ' Multi line', - }) - vim.cmd('edit ' .. file.filename) - assert.is.True(file:bufnr() > 0) - vim.cmd('bdelete') - assert.are.same(-1, file:bufnr()) - assert.is.True(vim.fn.bufnr(file.filename) > 0) - end) - it('should work with filenames containing special characters', function() -- Test various special characters that have regex meaning local test_cases = { @@ -599,9 +561,6 @@ describe('OrgFile', function() ' Content in special file', }, full_filename) - -- Test that bufnr() works correctly - assert.are.same(-1, file:bufnr()) - -- Test that loading the buffer works vim.cmd('edit ' .. vim.fn.fnameescape(file.filename)) assert.is.True(file:bufnr() > 0, 'Failed for filename: ' .. special_filename) diff --git a/tests/plenary/files/headline_spec.lua b/tests/plenary/files/headline_spec.lua index 19d492467..9bc1ea06c 100644 --- a/tests/plenary/files/headline_spec.lua +++ b/tests/plenary/files/headline_spec.lua @@ -4,7 +4,7 @@ local config = require('orgmode.config') describe('Headline', function() describe('get_category', function() it('should get category from file name', function() - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '* Headline 1', '* Headline 2', }, 'category.org') @@ -13,7 +13,7 @@ describe('Headline', function() end) it('should get category from category directive in file', function() - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '#+CATEGORY: file_category', '* Headline 1', '* Headline 2', @@ -24,7 +24,7 @@ describe('Headline', function() end) it('should get category from parent headline category prop', function() - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '#+CATEGORY: file_category', '* Headline 1', ':PROPERTIES:', @@ -38,7 +38,7 @@ describe('Headline', function() end) it('should get category from own category prop', function() - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '#+CATEGORY: file_category', '* Headline 1', ':PROPERTIES:', @@ -56,7 +56,7 @@ describe('Headline', function() end) describe('use_property_inheritance', function() - local file = helpers.create_file_instance({ + local file = helpers.create_file({ '#+CATEGORY: file_category', '* Headline 1', ':PROPERTIES:', diff --git a/tests/plenary/helpers.lua b/tests/plenary/helpers.lua index 425bb1808..6b63b78a9 100644 --- a/tests/plenary/helpers.lua +++ b/tests/plenary/helpers.lua @@ -34,8 +34,12 @@ function M.load_file(path) end ---@param lines string[] -function M.create_file(lines) +---@param filename? string +function M.create_file(lines, filename) local fname = vim.fn.tempname() .. '.org' + if filename then + fname = vim.fn.fnamemodify(fname, ':p:h') .. '/' .. filename + end vim.fn.writefile(lines or {}, fname) return M.load_file(fname) end @@ -55,18 +59,6 @@ function M.create_agenda_file(lines, config) return M.load_file(fname) end ----@param lines string[] ----@param filename string ----@return OrgFile -function M.create_file_instance(lines, filename) - local file = OrgFile:new({ - filename = filename or vim.fn.tempname() .. '.org', - lines = lines, - }) - file:parse() - return file -end - ---@param fixtures {filename: string, content: string[] }[] ---@param config? table ---@return table From 1b2c306d2820a73acc96085fa927e423b4dafaac Mon Sep 17 00:00:00 2001 From: Kristijan Husak Date: Fri, 3 Oct 2025 12:53:51 +0200 Subject: [PATCH 2/2] ci(tests): Run tests only on version 0.11.3+ For some reason, tests on older versions fail without reporting any actual issues in the tests. Skip running tests on those versions. --- .github/workflows/tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7b4bd115a..dfb2cb49f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,9 +29,6 @@ jobs: - windows-latest - macos-latest version: - - v0.11.0 - - v0.11.1 - - v0.11.2 - v0.11.3 - v0.11.4 - nightly