Skip to content

Commit 8df4c1b

Browse files
committed
Migrate to a more OO style
1 parent e63d52f commit 8df4c1b

File tree

3 files changed

+148
-130
lines changed

3 files changed

+148
-130
lines changed

lua/orgmode/org/mappings.lua

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local constants = require('orgmode.utils.constants')
1111
local ts_utils = require('nvim-treesitter.ts_utils')
1212
local utils = require('orgmode.utils')
1313
local tree_utils = require('orgmode.utils.treesitter')
14+
local Headline = require('orgmode.treesitter.headline')
1415

1516
---@class OrgMappings
1617
---@field capture Capture
@@ -308,11 +309,8 @@ function OrgMappings:priority_down()
308309
end
309310

310311
function OrgMappings:set_priority(direction)
311-
local extract_priority = function(node)
312-
return string.match(vim.treesitter.query.get_node_text(node, 0), '%[#(%w+)%]')
313-
end
314-
local headline = tree_utils.closest_headline()
315-
local priority_node, current_priority = tree_utils.get_priority(headline)
312+
local headline = Headline:new(tree_utils.closest_headline())
313+
local _, current_priority = headline:priority()
316314
local priority_state = PriorityState:new(current_priority)
317315

318316
local new_priority
@@ -324,7 +322,7 @@ function OrgMappings:set_priority(direction)
324322
new_priority = priority_state:prompt_user()
325323
end
326324

327-
tree_utils.set_priority(headline, new_priority)
325+
headline:set_priority(new_priority)
328326
end
329327

330328
function OrgMappings:todo_next_state()
@@ -366,8 +364,8 @@ function OrgMappings:toggle_heading()
366364
end
367365

368366
function OrgMappings:_todo_change_state(direction)
369-
local headline = tree_utils.closest_headline()
370-
local _, old_state, was_done = tree_utils.get_todo(headline)
367+
local headline = Headline:new(tree_utils.closest_headline())
368+
local _, old_state, was_done = headline:todo()
371369
local changed = self:_change_todo_state(direction, true)
372370
if not changed then
373371
return
@@ -381,10 +379,10 @@ function OrgMappings:_todo_change_state(direction)
381379
if #repeater_dates == 0 then
382380
local log_time = config.org_log_done == 'time'
383381
if log_time and item:is_done() and not was_done then
384-
tree_utils.add_closed_date(headline)
382+
headline:add_closed_date()
385383
end
386384
if log_time and not item:is_done() and was_done then
387-
tree_utils.remove_closed_date(headline)
385+
headline:remove_closed_date()
388386
end
389387
return item
390388
end
@@ -755,8 +753,8 @@ end
755753
---@param use_fast_access boolean
756754
---@return string
757755
function OrgMappings:_change_todo_state(direction, use_fast_access)
758-
local headline = tree_utils.closest_headline()
759-
local todo, current_keyword = tree_utils.get_todo(headline)
756+
local headline = Headline:new(tree_utils.closest_headline())
757+
local todo, current_keyword = headline:todo()
760758
local todo_state = TodoState:new({ current_state = current_keyword })
761759
local next_state = nil
762760
if use_fast_access and todo_state:has_fast_access() then
@@ -782,7 +780,7 @@ function OrgMappings:_change_todo_state(direction, use_fast_access)
782780
return false
783781
end
784782

785-
tree_utils.set_todo(headline, next_state.value)
783+
headline:set_todo(next_state.value)
786784
return true
787785
end
788786

lua/orgmode/treesitter/headline.lua

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
local ts_utils = require('nvim-treesitter.ts_utils')
2+
local tree_utils = require('orgmode.utils.treesitter')
3+
local config = require('orgmode.config')
4+
local query = vim.treesitter.query
5+
6+
local Headline = {}
7+
8+
---@param headline userdata tree sitter headline node
9+
function Headline:new(headline_node)
10+
local data = { headline = headline_node }
11+
setmetatable(data, self)
12+
self.__index = self
13+
return data
14+
end
15+
16+
function Headline:stars()
17+
return self.headline:field('stars')[1]
18+
end
19+
20+
function Headline:priority()
21+
return self:parse('%[#(%w+)%]')
22+
end
23+
24+
function Headline:set_priority(priority)
25+
local current_priority = self:priority()
26+
if current_priority then
27+
local text = (vim.trim(priority) == '') and '' or ('[#%s]'):format(priority)
28+
tree_utils.set_node_text(current_priority, text)
29+
return
30+
end
31+
32+
local todo = self:todo()
33+
if todo then
34+
local text = query.get_node_text(todo, 0)
35+
tree_utils.set_node_text(todo, ('%s [#%s]'):format(text, priority))
36+
return
37+
end
38+
39+
local stars = self:stars()
40+
local text = query.get_node_text(stars, 0)
41+
tree_utils.set_node_text(stars,('%s [#%s]'):format(text, priority))
42+
end
43+
44+
function Headline:set_todo(keyword)
45+
local current_todo = self:todo()
46+
if current_todo then
47+
tree_utils.set_node_text(current_todo, keyword)
48+
return
49+
end
50+
51+
local stars = self:stars()
52+
local text = query.get_node_text(stars, 0)
53+
tree_utils.set_node_text(stars, string.format('%s %s', text, keyword))
54+
end
55+
56+
function Headline:item()
57+
return self.headline:field('item')[1]
58+
end
59+
60+
-- Returns the headlines todo node, it's keyword,
61+
-- and if it's in done state
62+
-- @return Node, string, boolean
63+
function Headline:todo()
64+
local keywords = config.todo_keywords.ALL
65+
local done_keywords = config.todo_keywords.DONE
66+
for _, word in ipairs(keywords) do
67+
local todo = self:parse(word:gsub('-', '%%-'))
68+
if todo then
69+
return todo, word, vim.tbl_contains(done_keywords, word)
70+
end
71+
end
72+
end
73+
74+
function Headline:plan()
75+
local section = self.headline:parent()
76+
for _, node in ipairs(ts_utils.get_named_children(section)) do
77+
if node:type() == 'plan' then
78+
return node
79+
end
80+
end
81+
end
82+
83+
function Headline:dates()
84+
local plan = self:plan()
85+
local dates = {}
86+
for _, node in ipairs(ts_utils.get_named_children(plan)) do
87+
local name = vim.treesitter.query.get_node_text(node:named_child(0), 0)
88+
dates[name] = node
89+
end
90+
return dates
91+
end
92+
93+
function Headline:repeater_dates()
94+
return vim.tbl_filter(function(entry)
95+
local timestamp = entry:field('timestamp')[1]
96+
for _, node in ipairs(ts_utils.get_named_children(timestamp)) do
97+
if node:type() == 'repeat' then
98+
return true
99+
end
100+
end
101+
end, self:dates())
102+
end
103+
104+
function Headline:add_closed_date()
105+
local dates = self:dates()
106+
if vim.tbl_count(dates) == 0 or dates['CLOSED'] then
107+
return
108+
end
109+
local last_child = dates['DEADLINE'] or dates['SCHEDULED']
110+
local ptext = query.get_node_text(last_child, 0)
111+
local text = ptext .. ' CLOSED: [' .. vim.fn.strftime('%Y-%m-%d %a %H:%M') .. ']'
112+
tree_utils.set_node_text(last_child, text)
113+
end
114+
115+
function Headline:remove_closed_date()
116+
local dates = self:dates()
117+
if vim.tbl_count(dates) == 0 or not dates['CLOSED'] then
118+
return
119+
end
120+
tree_utils.set_node_text(dates['CLOSED'], '', true)
121+
end
122+
123+
-- @return tsnode, string
124+
function Headline:parse(pattern)
125+
local match = ''
126+
local matching_nodes = vim.tbl_filter(function(node)
127+
local text = query.get_node_text(node, 0) or ''
128+
local m = text:match(pattern)
129+
if m then
130+
match = text:match(pattern)
131+
return true
132+
end
133+
end, ts_utils.get_named_children(self:item()))
134+
return matching_nodes[1], match
135+
end
136+
137+
return Headline

lua/orgmode/utils/treesitter.lua

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,6 @@ local ts_utils = require('nvim-treesitter.ts_utils')
22
local config = require('orgmode.config')
33
local M = {}
44

5-
-- Searches headline item nodes for a match
6-
local function parse_item(headline, pattern)
7-
local match = ''
8-
local matching_nodes = vim.tbl_filter(function(node)
9-
local text = vim.treesitter.query.get_node_text(node, 0) or ''
10-
local m = string.match(text, pattern)
11-
if m then
12-
match = string.match(text, pattern)
13-
return true
14-
end
15-
end, ts_utils.get_named_children(headline:field('item')[1]))
16-
return matching_nodes[1], match
17-
end
18-
195
-- walks the tree to find a headline
206
function M.find_headline(node)
217
if node:type() == 'headline' then
@@ -36,28 +22,6 @@ function M.closest_headline()
3622
return M.find_headline(ts_utils.get_node_at_cursor(vim.api.nvim_get_current_win()))
3723
end
3824

39-
function M.get_priority(headline)
40-
return parse_item(headline, '%[#(%w+)%]')
41-
end
42-
43-
-- Returns the headlines todo node, it's keyword,
44-
-- and if it's in done state
45-
-- @return Node, string, boolean
46-
function M.get_todo(headline)
47-
local keywords = config.todo_keywords.ALL
48-
local done_keywords = config.todo_keywords.DONE
49-
for _, word in ipairs(keywords) do
50-
local todo = parse_item(headline, string.gsub(word, '-', '%%-'))
51-
if todo then
52-
return todo, word, vim.tbl_contains(done_keywords, word)
53-
end
54-
end
55-
end
56-
57-
function M.get_stars(headline)
58-
return headline:field('stars')[1]
59-
end
60-
6125
-- @param front_trim boolean
6226
function M.set_node_text(node, text, front_trim)
6327
local sr, sc, er, ec = node:range()
@@ -71,85 +35,4 @@ function M.set_node_text(node, text, front_trim)
7135
vim.api.nvim_buf_set_text(0, sr, sc, er, ec, { text })
7236
end
7337

74-
function M.set_priority(headline, priority)
75-
local current_priority = M.get_priority(headline)
76-
if current_priority then
77-
local text = (vim.trim(priority) == '') and '' or string.format('[#%s]', priority)
78-
M.set_node_text(current_priority, text)
79-
return
80-
end
81-
82-
local todo = M.get_todo(headline)
83-
if todo then
84-
local text = vim.treesitter.query.get_node_text(todo, 0)
85-
M.set_node_text(todo, string.format('%s [#%s]', text, priority))
86-
return
87-
end
88-
89-
local stars = M.get_stars(headline)
90-
local text = vim.treesitter.query.get_node_text(stars, 0)
91-
M.set_node_text(stars, string.format('%s [#%s]', text, priority))
92-
end
93-
94-
function M.set_todo(headline, keyword)
95-
local current_todo = M.get_todo(headline)
96-
if current_todo then
97-
M.set_node_text(current_todo, keyword)
98-
return
99-
end
100-
101-
local stars = M.get_stars(headline)
102-
local text = vim.treesitter.query.get_node_text(stars, 0)
103-
M.set_node_text(stars, string.format('%s %s', text, keyword))
104-
end
105-
106-
function M.get_plan(headline)
107-
local section = headline:parent()
108-
for _, node in ipairs(ts_utils.get_named_children(section)) do
109-
if node:type() == 'plan' then
110-
return node
111-
end
112-
end
113-
end
114-
115-
function M.get_dates(headline)
116-
local plan = M.get_plan(headline)
117-
local dates = {}
118-
for _, node in ipairs(ts_utils.get_named_children(plan)) do
119-
local name = vim.treesitter.query.get_node_text(node:named_child(0), 0)
120-
dates[name] = node
121-
end
122-
return dates
123-
end
124-
125-
function M.repeater_dates(headline)
126-
return vim.tbl_filter(function(entry)
127-
local timestamp = entry:field('timestamp')[1]
128-
for _, node in ipairs(ts_utils.get_named_children(timestamp)) do
129-
if node:type() == 'repeat' then
130-
return true
131-
end
132-
end
133-
end, M.get_dates(headline))
134-
end
135-
136-
function M.add_closed_date(headline)
137-
local dates = M.get_dates(headline)
138-
if vim.tbl_count(dates) == 0 or dates['CLOSED'] then
139-
return
140-
end
141-
local last_child = dates['DEADLINE'] or dates['SCHEDULED']
142-
local ptext = vim.treesitter.query.get_node_text(last_child, 0)
143-
local text = ptext .. ' CLOSED: [' .. vim.fn.strftime('%Y-%m-%d %a %H:%M') .. ']'
144-
M.set_node_text(last_child, text)
145-
end
146-
147-
function M.remove_closed_date(headline)
148-
local dates = M.get_dates(headline)
149-
if vim.tbl_count(dates) == 0 or not dates['CLOSED'] then
150-
return
151-
end
152-
M.set_node_text(dates['CLOSED'], '', true)
153-
end
154-
15538
return M

0 commit comments

Comments
 (0)