@@ -9,6 +9,7 @@ local Hyperlink = require('orgmode.org.links.hyperlink')
99local Range = require (' orgmode.files.elements.range' )
1010local Footnote = require (' orgmode.objects.footnote' )
1111local Memoize = require (' orgmode.utils.memoize' )
12+ local is_nightly = vim .fn .has (' nvim-0.12' ) > 0
1213
1314--- @class OrgFileMetadata
1415--- @field mtime number File modified time in nanoseconds
@@ -17,13 +18,15 @@ local Memoize = require('orgmode.utils.memoize')
1718
1819--- @class OrgFileOpts
1920--- @field filename string
21+ --- @field lines ? string[]
2022--- @field buf ? number
2123
2224--- @class OrgFile
2325--- @field filename string
2426--- @field buf number
2527--- @field index number
2628--- @field lines string[]
29+ --- @field content string
2730--- @field metadata OrgFileMetadata
2831--- @field parser vim.treesitter.LanguageTree
2932--- @field root TSNode
@@ -45,18 +48,19 @@ function OrgFile:new(opts)
4548 filename = opts .filename ,
4649 index = 0 ,
4750 buf = opts .buf or - 1 ,
48- lines = {},
51+ lines = opts .lines or {},
52+ content = table.concat (opts .lines or {}, ' \n ' ),
4953 metadata = {
5054 mtime = stat and stat .mtime .nsec or 0 ,
5155 mtime_sec = stat and stat .mtime .sec or 0 ,
5256 changedtick = opts .buf and vim .api .nvim_buf_get_changedtick (opts .buf ) or 0 ,
5357 },
5458 }
55- if data .buf > 0 then
56- data .lines = self :_get_lines (data .buf )
59+ local this = setmetatable (data , self )
60+ if this .buf > 0 then
61+ this :_update_lines (this :_get_lines (this .buf ))
5762 end
58- setmetatable (data , self )
59- return data
63+ return this
6064end
6165
6266--- Load the file
@@ -75,12 +79,23 @@ function OrgFile.load(filename)
7579 return Promise .resolve (false )
7680 end
7781
78- bufnr = OrgFile ._load_buffer (filename )
82+ -- TODO: Remove once Neovim adds string parser back
83+ -- See: https://github.com/nvim-orgmode/orgmode/issues/1049
84+ if is_nightly then
85+ bufnr = OrgFile ._load_buffer (filename )
7986
80- return Promise .resolve (OrgFile :new ({
81- filename = filename ,
82- buf = bufnr ,
83- }))
87+ return Promise .resolve (OrgFile :new ({
88+ filename = filename ,
89+ buf = bufnr ,
90+ }))
91+ end
92+
93+ return utils .readfile (filename , { schedule = true }):next (function (lines )
94+ return OrgFile :new ({
95+ filename = filename ,
96+ lines = lines ,
97+ })
98+ end )
8499end
85100
86101--- Reload the file if it has been modified
@@ -94,12 +109,12 @@ function OrgFile:reload()
94109 local buf_changed = false
95110 local file_changed = false
96111
97- if bufnr then
112+ if bufnr > - 1 then
98113 local new_changedtick = vim .api .nvim_buf_get_changedtick (bufnr )
99114 buf_changed = self .metadata .changedtick ~= new_changedtick
100115 self .metadata .changedtick = new_changedtick
101116 if buf_changed then
102- self . lines = self :_get_lines (bufnr )
117+ self : _update_lines ( self :_get_lines (bufnr ) )
103118 end
104119 end
105120 local stat = vim .uv .fs_stat (self .filename )
@@ -114,7 +129,7 @@ function OrgFile:reload()
114129
115130 if file_changed and not buf_changed then
116131 return utils .readfile (self .filename , { schedule = true }):next (function (lines )
117- self . lines = lines
132+ self : _update_lines ( lines )
118133 return self
119134 end )
120135 end
@@ -184,7 +199,7 @@ function OrgFile:parse(skip_if_not_modified)
184199 if skip_if_not_modified and self .root and not self :is_modified () then
185200 return self .root
186201 end
187- self .parser = ts . get_parser ( self :bufnr (), ' org ' , {} )
202+ self .parser = self :_get_parser ( )
188203 local trees = self .parser :parse ()
189204 self .root = trees [1 ]:root ()
190205 return self .root
@@ -203,7 +218,7 @@ function OrgFile:get_ts_matches(query, parent_node)
203218 local ts_query = ts_utils .get_query (query )
204219 local matches = {}
205220
206- for _ , match , _ in ts_query :iter_matches (parent_node , self :bufnr (), nil , nil , { all = true }) do
221+ for _ , match , _ in ts_query :iter_matches (parent_node , self :get_source (), nil , nil , { all = true }) do
207222 local items = {}
208223 for id , nodes in pairs (match ) do
209224 local name = ts_query .captures [id ]
@@ -233,7 +248,7 @@ function OrgFile:get_ts_captures(query, node)
233248 local ts_query = ts_utils .get_query (query )
234249 local matches = {}
235250
236- for _ , match in ts_query :iter_captures (node , self :bufnr ()) do
251+ for _ , match in ts_query :iter_captures (node , self :get_source ()) do
237252 table.insert (matches , match )
238253 end
239254 return matches
@@ -489,13 +504,13 @@ function OrgFile:get_node_text(node, range)
489504 return ' '
490505 end
491506 if range then
492- return ts .get_node_text (node , self :bufnr (), {
507+ return ts .get_node_text (node , self :get_source (), {
493508 metadata = {
494509 range = range ,
495510 },
496511 })
497512 end
498- return ts .get_node_text (node , self :bufnr ())
513+ return ts .get_node_text (node , self :get_source ())
499514end
500515
501516--- @param node ? TSNode
@@ -557,15 +572,27 @@ end
557572
558573--- @return number
559574function OrgFile :bufnr ()
560- local bufnr = self .buf
575+ -- TODO: Remove once Neovim adds string parser back
576+ -- See: https://github.com/nvim-orgmode/orgmode/issues/1049
577+ if is_nightly then
578+ local bufnr = self .buf
579+ -- Do not consider unloaded buffers as valid
580+ -- Treesitter is not working in them
581+ if bufnr > - 1 and vim .api .nvim_buf_is_loaded (bufnr ) then
582+ return bufnr
583+ end
584+ local new_bufnr = self ._load_buffer (self .filename )
585+ self .buf = new_bufnr
586+ return new_bufnr
587+ end
588+
589+ local bufnr = utils .get_buffer_by_filename (self .filename )
561590 -- Do not consider unloaded buffers as valid
562591 -- Treesitter is not working in them
563592 if bufnr > - 1 and vim .api .nvim_buf_is_loaded (bufnr ) then
564593 return bufnr
565594 end
566- local new_bufnr = self ._load_buffer (self .filename )
567- self .buf = new_bufnr
568- return new_bufnr
595+ return - 1
569596end
570597
571598--- @private
@@ -819,7 +846,7 @@ function OrgFile:get_links()
819846 (link_desc) @link
820847 ]] )
821848
822- local source = self :bufnr ()
849+ local source = self :get_source ()
823850 for _ , node in ipairs (matches ) do
824851 table.insert (links , Hyperlink .from_node (node , source ))
825852 end
@@ -840,7 +867,7 @@ function OrgFile:get_footnote_references()
840867
841868 local footnotes = {}
842869 local processed_lines = {}
843- for _ , match in ts_query :iter_captures (self .root , self :bufnr ()) do
870+ for _ , match in ts_query :iter_captures (self .root , self :get_source ()) do
844871 local line_start , _ , line_end = match :range ()
845872 if not processed_lines [line_start ] then
846873 if line_start == line_end then
@@ -947,6 +974,13 @@ function OrgFile:_get_directive(directive_name, all_matches)
947974 return nil
948975end
949976
977+ function OrgFile :_update_lines (lines )
978+ self .lines = lines
979+ self .content = table.concat (lines , ' \n ' )
980+ self :parse ()
981+ return self
982+ end
983+
950984--- @private
951985--- Get all buffer lines, ensure empty buffer returns empty table
952986--- @return string[]
@@ -958,4 +992,34 @@ function OrgFile:_get_lines(bufnr)
958992 return lines
959993end
960994
995+ --- @private
996+ --- @return vim.treesitter.LanguageTree
997+ function OrgFile :_get_parser ()
998+ local bufnr = self :bufnr ()
999+
1000+ if bufnr > - 1 then
1001+ -- Always get the fresh parser for the buffer
1002+ return ts .get_parser (bufnr , ' org' , {})
1003+ end
1004+
1005+ -- In case the buffer got unloaded, go back to string parser
1006+ if not self .parser or self :is_modified () or type (self .parser :source ()) == ' number' then
1007+ return ts .get_string_parser (self .content , ' org' , {})
1008+ end
1009+
1010+ return self .parser
1011+ end
1012+
1013+ --- Get the ts source for the file
1014+ --- If there is a buffer, return buffer number
1015+ --- Otherwise, return the string content
1016+ --- @return integer | string
1017+ function OrgFile :get_source ()
1018+ local bufnr = self :bufnr ()
1019+ if bufnr > - 1 then
1020+ return bufnr
1021+ end
1022+ return self .content
1023+ end
1024+
9611025return OrgFile
0 commit comments