@@ -17,14 +17,13 @@ local Memoize = require('orgmode.utils.memoize')
1717
1818--- @class  OrgFileOpts 
1919--- @field  filename  string 
20- --- @field  lines  string[] 
21- --- @field  bufnr ? number 
20+ --- @field  buf  number 
2221
2322--- @class  OrgFile 
2423--- @field  filename  string 
24+ --- @field  buf  number 
2525--- @field  index  number 
2626--- @field  lines  string[] 
27- --- @field  content  string 
2827--- @field  metadata  OrgFileMetadata 
2928--- @field  parser  vim.treesitter.LanguageTree 
3029--- @field  root  TSNode 
@@ -44,15 +43,17 @@ function OrgFile:new(opts)
4443  local  stat  =  vim .uv .fs_stat (opts .filename )
4544  local  data  =  {
4645    filename  =  opts .filename ,
47-     lines  =  opts .lines ,
48-     content  =  table.concat (opts .lines , ' \n ' 
4946    index  =  0 ,
47+     buf  =  opts .buf  or  - 1 ,
5048    metadata  =  {
5149      mtime  =  stat  and  stat .mtime .nsec  or  0 ,
5250      mtime_sec  =  stat  and  stat .mtime .sec  or  0 ,
53-       changedtick  =  opts .bufnr  and  vim .api .nvim_buf_get_changedtick (opts .bufnr ) or  0 ,
51+       changedtick  =  opts .buf  and  vim .api .nvim_buf_get_changedtick (opts .buf ) or  0 ,
5452    },
5553  }
54+   if  data .buf  >  0  then 
55+     data .lines  =  self :_get_lines (data .buf )
56+   end 
5657  setmetatable (data , self )
5758  return  data 
5859end 
6263function  OrgFile .load (filename )
6364  local  bufnr  =  utils .get_buffer_by_filename (filename )
6465
65-   if 
66-     bufnr  >  - 1 
67-     and  vim .api .nvim_buf_is_loaded (bufnr )
68-     and  vim .api .nvim_get_option_value (' filetype' buf  =  bufnr  }) ==  ' org' 
69-   then 
66+   if  bufnr  >  - 1  and  vim .api .nvim_buf_is_loaded (bufnr ) and  vim .bo [bufnr ].filetype  ==  ' org'  then 
7067    return  Promise .resolve (OrgFile :new ({
7168      filename  =  filename ,
72-       lines  =  vim .api .nvim_buf_get_lines (bufnr , 0 , - 1 , false ),
73-       bufnr  =  bufnr ,
69+       buf  =  bufnr ,
7470    }))
7571  end 
7672
7773  if  not  vim .uv .fs_stat (filename ) or  not  utils .is_org_file (filename ) then 
7874    return  Promise .resolve (false )
7975  end 
8076
81-   return  utils .readfile (filename , { schedule  =  true  }):next (function (lines )
82-     return  OrgFile :new ({
83-       filename  =  filename ,
84-       lines  =  lines ,
85-     })
86-   end )
77+   bufnr  =  vim .fn .bufadd (filename )
78+ 
79+   if  bufnr  ==  0  then 
80+     return  Promise .resolve (false )
81+   end 
82+ 
83+   vim .fn .bufload (bufnr )
84+ 
85+   return  Promise .resolve (OrgFile :new ({
86+     filename  =  filename ,
87+     buf  =  bufnr ,
88+   }))
8789end 
8890
8991--- Reload the file if it has been modified
@@ -94,15 +96,34 @@ function OrgFile:reload()
9496  end 
9597
9698  local  bufnr  =  self :bufnr ()
99+   local  buf_changed  =  false 
100+   local  file_changed  =  false 
97101
98-   if  bufnr  >  - 1  then 
99-     local  updated_file  =  self :_update_lines (vim .api .nvim_buf_get_lines (bufnr , 0 , - 1 , false ), bufnr )
100-     return  Promise .resolve (updated_file )
102+   if  bufnr  then 
103+     local  new_changedtick  =  vim .api .nvim_buf_get_changedtick (bufnr )
104+     buf_changed  =  self .metadata .changedtick  ~=  new_changedtick 
105+     self .metadata .changedtick  =  new_changedtick 
106+     if  buf_changed  then 
107+       self .lines  =  self :_get_lines (bufnr )
108+     end 
101109  end 
102- 
103-   return  utils .readfile (self .filename , { schedule  =  true  }):next (function (lines )
104-     return  self :_update_lines (lines )
105-   end )
110+   local  stat  =  vim .uv .fs_stat (self .filename )
111+   if  stat  then 
112+     local  new_mtime_nsec  =  stat .mtime .nsec 
113+     local  new_mtime_sec  =  stat .mtime .sec 
114+     file_changed  =  (new_mtime_nsec  >  0  and  self .metadata .mtime  ~=  new_mtime_nsec )
115+       or  self .metadata .mtime_sec  ~=  new_mtime_sec 
116+     self .metadata .mtime  =  new_mtime_nsec 
117+     self .metadata .mtime_sec  =  new_mtime_sec 
118+   end 
119+ 
120+   if  file_changed  and  not  buf_changed  then 
121+     return  utils .readfile (self .filename , { schedule  =  true  }):next (function (lines )
122+       self .lines  =  lines 
123+       return  self 
124+     end )
125+   end 
126+   return  Promise .resolve (self )
106127end 
107128
108129--- sync reload the file if it has been modified
@@ -146,7 +167,9 @@ function OrgFile:is_modified()
146167  local  bufnr  =  self :bufnr ()
147168  if  bufnr  >  - 1  then 
148169    local  cur_changedtick  =  vim .api .nvim_buf_get_changedtick (bufnr )
149-     return  cur_changedtick  ~=  self .metadata .changedtick 
170+     if  cur_changedtick  ~=  self .metadata .changedtick  then 
171+       return  true 
172+     end 
150173  end 
151174  local  stat  =  vim .uv .fs_stat (self .filename )
152175  if  not  stat  then 
@@ -166,7 +189,7 @@ function OrgFile:parse(skip_if_not_modified)
166189  if  skip_if_not_modified  and  self .root  and  not  self :is_modified () then 
167190    return  self .root 
168191  end 
169-   self .parser  =  self :_get_parser ( )
192+   self .parser  =  ts . get_parser ( self :bufnr (),  ' org ' , {} )
170193  local  trees  =  self .parser :parse ()
171194  self .root  =  trees [1 ]:root ()
172195  return  self .root 
@@ -185,7 +208,7 @@ function OrgFile:get_ts_matches(query, parent_node)
185208  local  ts_query  =  ts_utils .get_query (query )
186209  local  matches  =  {}
187210
188-   for  _ , match , _  in  ts_query :iter_matches (parent_node , self :get_source (), nil , nil , { all  =  true  }) do 
211+   for  _ , match , _  in  ts_query :iter_matches (parent_node , self :bufnr (), nil , nil , { all  =  true  }) do 
189212    local  items  =  {}
190213    for  id , nodes  in  pairs (match ) do 
191214      local  name  =  ts_query .captures [id ]
@@ -215,7 +238,7 @@ function OrgFile:get_ts_captures(query, node)
215238  local  ts_query  =  ts_utils .get_query (query )
216239  local  matches  =  {}
217240
218-   for  _ , match  in  ts_query :iter_captures (node , self :get_source ()) do 
241+   for  _ , match  in  ts_query :iter_captures (node , self :bufnr ()) do 
219242    table.insert (matches , match )
220243  end 
221244  return  matches 
@@ -466,13 +489,13 @@ function OrgFile:get_node_text(node, range)
466489    return  ' ' 
467490  end 
468491  if  range  then 
469-     return  ts .get_node_text (node , self :get_source (), {
492+     return  ts .get_node_text (node , self :bufnr (), {
470493      metadata  =  {
471494        range  =  range ,
472495      },
473496    })
474497  end 
475-   return  ts .get_node_text (node , self :get_source ())
498+   return  ts .get_node_text (node , self :bufnr ())
476499end 
477500
478501--- @param  node ?  TSNode 
@@ -534,19 +557,22 @@ end
534557
535558--- @return  number 
536559function  OrgFile :bufnr ()
537-   local  bufnr  =  utils . get_buffer_by_filename ( self .filename ) 
560+   local  bufnr  =  self .buf 
538561  --  Do not consider unloaded buffers as valid
539562  --  Treesitter is not working in them
540563  if  bufnr  >  - 1  and  vim .api .nvim_buf_is_loaded (bufnr ) then 
541564    return  bufnr 
542565  end 
543-   return  - 1 
566+   local  new_bufnr  =  vim .fn .bufadd (self .filename )
567+   vim .fn .bufload (new_bufnr )
568+   self .buf  =  new_bufnr 
569+   return  new_bufnr 
544570end 
545571
546572--- Return valid buffer handle or throw an error if it's not valid
547573--- @return  number 
548574function  OrgFile :get_valid_bufnr ()
549-   local  bufnr  =  utils . get_buffer_by_filename ( self . filename )
575+   local  bufnr  =  self : bufnr ( )
550576  if  bufnr  <  0  then 
551577    error (' [orgmode] No valid buffer for file '  ..  self .filename  ..  '  to edit' 0 )
552578  end 
@@ -784,7 +810,7 @@ function OrgFile:get_links()
784810    (link_desc) @link 
785811  ]]  )
786812
787-   local  source  =  self :get_source ()
813+   local  source  =  self :bufnr ()
788814  for  _ , node  in  ipairs (matches ) do 
789815    table.insert (links , Hyperlink .from_node (node , source ))
790816  end 
@@ -805,7 +831,7 @@ function OrgFile:get_footnote_references()
805831
806832  local  footnotes  =  {}
807833  local  processed_lines  =  {}
808-   for  _ , match  in  ts_query :iter_captures (self .root , self :get_source ()) do 
834+   for  _ , match  in  ts_query :iter_captures (self .root , self :bufnr ()) do 
809835    local  line_start , _ , line_end  =  match :range ()
810836    if  not  processed_lines [line_start ] then 
811837      if  line_start  ==  line_end  then 
@@ -895,51 +921,14 @@ function OrgFile:_get_directive(directive_name)
895921end 
896922
897923--- @private 
898- --- @param  lines  string[] 
899- --- @param  bufnr ?  number 
900- function  OrgFile :_update_lines (lines , bufnr )
901-   self .lines  =  lines 
902-   self .content  =  table.concat (lines , ' \n ' 
903-   self :parse ()
904-   if  bufnr  then 
905-     self .metadata .changedtick  =  vim .api .nvim_buf_get_changedtick (bufnr )
906-   end 
907-   local  stat  =  vim .uv .fs_stat (self .filename )
908-   if  stat  then 
909-     self .metadata .mtime  =  stat .mtime .nsec 
910-     self .metadata .mtime_sec  =  stat .mtime .sec 
911-   end 
912-   return  self 
913- end 
914- 
915- --- @private 
916- --- @return  vim.treesitter.LanguageTree 
917- function  OrgFile :_get_parser ()
918-   local  bufnr  =  self :bufnr ()
919- 
920-   if  bufnr  >  - 1  then 
921-     --  Always get the fresh parser for the buffer
922-     return  ts .get_parser (bufnr , ' org' 
923-   end 
924- 
925-   --  In case the buffer got unloaded, go back to string parser
926-   if  not  self .parser  or  self :is_modified () or  type (self .parser :source ()) ==  ' number'  then 
927-     return  ts .get_string_parser (self .content , ' org' 
928-   end 
929- 
930-   return  self .parser 
931- end 
932- 
933- ---  Get the ts source for the file
934- ---  If there is a buffer, return buffer number
935- ---  Otherwise, return the string content
936- --- @return  integer  |  string 
937- function  OrgFile :get_source ()
938-   local  bufnr  =  self :bufnr ()
939-   if  bufnr  >  - 1  then 
940-     return  bufnr 
924+ --- Get all buffer lines, ensure empty buffer returns empty table
925+ --- @return  string[] 
926+ function  OrgFile :_get_lines (bufnr )
927+   local  lines  =  vim .api .nvim_buf_get_lines (bufnr , 0 , - 1 , false )
928+   if  # lines  ==  1  and  lines [1 ] ==  ' '  then 
929+     lines  =  {}
941930  end 
942-   return  self . content 
931+   return  lines 
943932end 
944933
945934return  OrgFile 
0 commit comments