Skip to content

Commit 5e7d971

Browse files
feat(ts): use timestamp nodes for all dates
1 parent 36141c7 commit 5e7d971

File tree

7 files changed

+70
-357
lines changed

7 files changed

+70
-357
lines changed

lua/orgmode/files/file.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ end
172172
function OrgFile:get_ts_matches(query, node)
173173
self:parse()
174174
node = node or self.root
175+
if not node then
176+
return {}
177+
end
175178
local ts_query = ts_utils.get_query(query)
176179
local matches = {}
177180

lua/orgmode/files/headline.lua

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -759,39 +759,46 @@ memoize('get_non_plan_dates')
759759
function Headline:get_non_plan_dates()
760760
local headline_node = self:node()
761761
local section = headline_node:parent()
762-
local body = section and section:field('body')[1]
763-
local headline_text = self.file:get_node_text(headline_node) or ''
764-
local dates = Date.parse_all_from_line(headline_text, self:node():start() + 1)
765-
local properties_node = section and section:field('property_drawer')[1]
762+
if not section then
763+
return {}
764+
end
766765

767-
if properties_node then
768-
local properties_text = self.file:get_node_text_list(properties_node) or {}
769-
local start = properties_node:start()
770-
for i, line in ipairs(properties_text) do
771-
vim.list_extend(dates, Date.parse_all_from_line(line, start + i))
772-
end
766+
local body_node = section:field('body')[1]
767+
local property_node = section:field('property_drawer')[1]
768+
local matches = {}
769+
770+
local headline_matches = self.file:get_ts_matches('(item (timestamp) @timestamp)', headline_node)
771+
vim.list_extend(matches, headline_matches)
772+
773+
if property_node then
774+
local property_matches = self.file:get_ts_matches('(property (value (timestamp) @timestamp))', property_node)
775+
vim.list_extend(matches, property_matches)
773776
end
774777

775-
if not body then
776-
return dates
777-
end
778-
779-
local start_line = body:range()
780-
local lines = self.file:get_node_text_list(body, ts_utils.range_with_zero_start_col(body))
781-
for i, line in ipairs(lines) do
782-
local line_dates = Date.parse_all_from_line(line, start_line + i)
783-
local is_clock_line = line:match('^%s*:?CLOCK:') ~= nil
784-
for _, date in ipairs(line_dates) do
785-
-- Assume that the date is part of logbook if line starts with clock
786-
-- TODO: Make this more reliable
787-
if not date.active and is_clock_line then
788-
date.type = 'LOGBOOK'
789-
end
790-
end
791-
vim.list_extend(dates, line_dates)
778+
if body_node then
779+
local body_matches = self.file:get_ts_matches(
780+
[[
781+
(paragraph (timestamp) @timestamp)
782+
(table (row (cell (contents (timestamp) @timestamp))))
783+
(drawer (contents (timestamp) @timestamp))
784+
(fndef (description (timestamp) @timestamp))
785+
]],
786+
body_node
787+
)
788+
vim.list_extend(matches, body_matches)
792789
end
793790

794-
return dates
791+
local all_dates = {}
792+
local source = self.file:get_source()
793+
for _, match in ipairs(matches) do
794+
local dates = Date.from_org_date(match.timestamp.text, {
795+
range = Range.from_node(match.timestamp.node),
796+
type = ts_utils.is_date_in_drawer(match.timestamp.node, 'logbook', source) and 'LOGBOOK' or 'NONE',
797+
})
798+
vim.list_extend(all_dates, dates)
799+
end
800+
801+
return all_dates
795802
end
796803

797804
---@param sorted? boolean

lua/orgmode/objects/date.lua

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -127,34 +127,6 @@ local function parse_date(date, adjustments, data)
127127
return OrgDate:new(opts)
128128
end
129129

130-
---@param line string
131-
---@param lnum number
132-
---@param open string
133-
---@param datetime string
134-
---@param close string
135-
---@param last_match? OrgDate
136-
---@param type? string
137-
---@return OrgDate | nil
138-
local function from_match(line, lnum, open, datetime, close, last_match, type)
139-
local search_from = last_match ~= nil and last_match.range.end_col or 0
140-
local from, to = line:find(vim.pesc(open .. datetime .. close), search_from)
141-
local is_date_range_end = last_match and last_match.is_date_range_start and line:sub(from - 2, from - 1) == '--'
142-
local opts = {
143-
type = type,
144-
active = open == '<',
145-
range = Range:new({ start_line = lnum, end_line = lnum, start_col = from, end_col = to }),
146-
is_date_range_start = line:sub(to + 1, to + 2) == '--',
147-
}
148-
local parsed_date = OrgDate.from_string(vim.trim(datetime), opts)
149-
if is_date_range_end then
150-
parsed_date.is_date_range_end = true
151-
parsed_date.related_date = last_match
152-
last_match.related_date = parsed_date
153-
end
154-
155-
return parsed_date
156-
end
157-
158130
---@param opts OrgDateOpts
159131
---@return OrgDate
160132
function OrgDate:new(opts)
@@ -340,24 +312,6 @@ function OrgDate.is_date_instance(value)
340312
return getmetatable(value) == OrgDate
341313
end
342314

343-
---@param line string
344-
---@param lnum number
345-
---@return OrgDate[]
346-
function OrgDate.parse_all_from_line(line, lnum)
347-
local is_comment = line:match('^%s*#[^%+]')
348-
if is_comment then
349-
return {}
350-
end
351-
local dates = {}
352-
for open, datetime, close in line:gmatch(pattern) do
353-
local parsed_date = from_match(line, lnum, open, datetime, close, dates[#dates])
354-
if parsed_date then
355-
table.insert(dates, parsed_date)
356-
end
357-
end
358-
return dates
359-
end
360-
361315
---@param datestr string
362316
---@param opts? OrgDateOpts
363317
---@return OrgDate | nil

lua/orgmode/org/mappings.lua

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ local Babel = require('orgmode.babel')
1616
local Promise = require('orgmode.utils.promise')
1717
local Input = require('orgmode.ui.input')
1818
local Footnote = require('orgmode.objects.footnote')
19+
local Range = require('orgmode.files.elements.range')
1920

2021
---@class OrgMappings
2122
---@field capture OrgCapture
@@ -1123,19 +1124,22 @@ function OrgMappings:_get_date_under_cursor(col_offset)
11231124
local item = self.files:get_closest_headline_or_nil()
11241125
local dates = {}
11251126
if item then
1126-
dates = vim.tbl_filter(function(date)
1127-
return date.range:is_in_range(line, col)
1128-
end, item:get_all_dates())
1127+
dates = item:get_all_dates()
11291128
else
1130-
dates = Date.parse_all_from_line(vim.fn.getline('.'), line)
1131-
end
1132-
1133-
if #dates == 0 then
1134-
return nil
1129+
local date_node = ts_utils.closest_node(ts_utils.get_node(), 'timestamp')
1130+
if not date_node then
1131+
return nil
1132+
end
1133+
dates = Date.from_org_date(vim.treesitter.get_node_text(date_node, 0), {
1134+
range = Range.from_node(date_node),
1135+
type = ts_utils.is_date_in_drawer(date_node, 'logbook') and 'LOGBOOK' or 'NONE',
1136+
})
11351137
end
11361138

1137-
-- TODO: this will result in a bug, when more than one date is in the line
1138-
return dates[1]
1139+
local valid_dates = vim.tbl_filter(function(date)
1140+
return date.range:is_in_range(line, col)
1141+
end, dates)
1142+
return valid_dates[1]
11391143
end
11401144

11411145
---@param amount number

lua/orgmode/utils/treesitter/init.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ function M.parents_until(node, type)
118118
end
119119
end
120120

121+
---@param node TSNode
122+
---@param drawer string
123+
---@param source? number|string
124+
---@return boolean
125+
function M.is_date_in_drawer(node, drawer, source)
126+
if
127+
(node:parent() and node:parent():type() == 'contents')
128+
and (node:parent():parent() and node:parent():parent():type() == 'drawer')
129+
then
130+
local drawer_node = node:parent():parent() --[[@as TSNode]]
131+
local drawer_name = vim.treesitter.get_node_text(drawer_node:field('name')[1], source or 0)
132+
return drawer_name:lower() == drawer
133+
end
134+
135+
return false
136+
end
137+
121138
function M.node_to_lsp_range(node)
122139
local start_line, start_col, end_line, end_col = vim.treesitter.get_node_range(node)
123140
local rtn = {}

queries/org/injections.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
(block parameter: (expr) @_lang (contents) @injection.content (#set! injection.include-children) (#org-set-block-language! @_lang))
2+
; (inline_code_block language: (language) @_lang contents: (contents) @injection.content (#set! injection.include-children) (#org-set-block-language! @_lang))
23
(latex_env (contents) @injection.content (#set! injection.include-children) (#set! injection.language "tex"))

0 commit comments

Comments
 (0)