Skip to content

Commit 373c447

Browse files
author
troiganto
committed
feat(files): add method OrgHeadline:toggle_tag()
1 parent 500004f commit 373c447

File tree

3 files changed

+115
-13
lines changed

3 files changed

+115
-13
lines changed

lua/orgmode/files/headline.lua

+24-2
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,28 @@ function Headline:set_tags(tags)
288288
vim.api.nvim_buf_set_text(bufnr, pred_end_row, pred_end_col, pred_end_row, end_col, { text })
289289
end
290290

291+
---@param tag string
292+
---@param onoff? boolean true=>add, false=>remove, nil=>toggle the tag
293+
function Headline:toggle_tag(tag, onoff)
294+
local current_tags = self:get_own_tags()
295+
296+
local present = vim.tbl_contains(current_tags, tag)
297+
if onoff == nil then
298+
onoff = not present
299+
end
300+
301+
if present and not onoff then
302+
current_tags = vim.tbl_filter(function(i)
303+
return i ~= tag
304+
end, current_tags)
305+
elseif not present and onoff then
306+
table.insert(current_tags, tag)
307+
end
308+
309+
self:set_tags(utils.tags_to_string(current_tags))
310+
return onoff
311+
end
312+
291313
function Headline:align_tags()
292314
local own_tags, node = self:get_own_tags()
293315
if node then
@@ -946,8 +968,8 @@ end
946968

947969
function Headline:is_same(other_headline)
948970
return self.file.filename == other_headline.filename
949-
and self:get_range():is_same(other_headline:get_range())
950-
and self:get_headline_line_content() == other_headline:get_headline_line_content()
971+
and self:get_range():is_same(other_headline:get_range())
972+
and self:get_headline_line_content() == other_headline:get_headline_line_content()
951973
end
952974

953975
function Headline:id_get_or_create()

lua/orgmode/org/mappings.lua

+2-11
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,10 @@ function OrgMappings:set_tags(tags)
7171
end)
7272
end
7373

74+
---@return nil
7475
function OrgMappings:toggle_archive_tag()
7576
local headline = self.files:get_closest_headline()
76-
local current_tags = headline:get_own_tags()
77-
78-
if vim.tbl_contains(current_tags, 'ARCHIVE') then
79-
current_tags = vim.tbl_filter(function(tag)
80-
return tag ~= 'ARCHIVE'
81-
end, current_tags)
82-
else
83-
table.insert(current_tags, 'ARCHIVE')
84-
end
85-
86-
return headline:set_tags(utils.tags_to_string(current_tags))
77+
headline:toggle_tag('ARCHIVE')
8778
end
8879

8980
function OrgMappings:cycle()

tests/plenary/files/headline_spec.lua

+89
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,93 @@ describe('Headline', function()
152152
assert_range(second_headline_dates[3], { 5, 3, 5, 18 })
153153
end)
154154
end)
155+
156+
describe('toggle_tag', function()
157+
---@type OrgFile
158+
local file
159+
local orig_tags_column
160+
161+
before_each(function()
162+
-- Put tags flush to headlines for shorter tests.
163+
if not orig_tags_column then
164+
orig_tags_column = config.org_tags_column
165+
end
166+
config:extend({ org_tags_column = 0 })
167+
-- Reinitialize test file to same state.
168+
if not file then
169+
file = helpers.load_file(vim.fn.tempname() .. '.org')
170+
end
171+
local bufnr = file:get_valid_bufnr()
172+
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {
173+
'* Headline 1',
174+
'* Headline 2 :other:',
175+
'* Headline 3 :other:more:ARCHIVE:',
176+
})
177+
file:reload_sync()
178+
end)
179+
180+
after_each(function()
181+
config:extend({ org_tags_column = orig_tags_column })
182+
end)
183+
184+
it('adds a tag where there is none', function()
185+
file:get_headlines()[1]:toggle_tag('ARCHIVE')
186+
local expected = {
187+
'* Headline 1 :ARCHIVE:',
188+
'* Headline 2 :other:',
189+
'* Headline 3 :other:more:ARCHIVE:',
190+
}
191+
assert.are.same(expected, file:reload_sync().lines)
192+
end)
193+
194+
it('adds a tag if another already exists', function()
195+
file:get_headlines()[2]:toggle_tag('ARCHIVE')
196+
local expected = {
197+
'* Headline 1',
198+
'* Headline 2 :other:ARCHIVE:',
199+
'* Headline 3 :other:more:ARCHIVE:',
200+
}
201+
assert.are.same(expected, file:reload_sync().lines)
202+
end)
203+
204+
it('does not add the same tag twice', function()
205+
file:get_headlines()[2]:toggle_tag('other', true)
206+
local expected = {
207+
'* Headline 1',
208+
'* Headline 2 :other:',
209+
'* Headline 3 :other:more:ARCHIVE:',
210+
}
211+
assert.are.same(expected, file:reload_sync().lines)
212+
end)
213+
214+
it('removes an existing tag', function()
215+
file:get_headlines()[2]:toggle_tag('other')
216+
local expected = {
217+
'* Headline 1',
218+
'* Headline 2',
219+
'* Headline 3 :other:more:ARCHIVE:',
220+
}
221+
assert.are.same(expected, file:reload_sync().lines)
222+
end)
223+
224+
it('keeps other tags when removing one', function()
225+
file:get_headlines()[3]:toggle_tag('more')
226+
local expected = {
227+
'* Headline 1',
228+
'* Headline 2 :other:',
229+
'* Headline 3 :other:ARCHIVE:',
230+
}
231+
assert.are.same(expected, file:reload_sync().lines)
232+
end)
233+
234+
it('does nothing when removing a non-existent tag', function()
235+
file:get_headlines()[1]:toggle_tag('other', false)
236+
local expected = {
237+
'* Headline 1',
238+
'* Headline 2 :other:',
239+
'* Headline 3 :other:more:ARCHIVE:',
240+
}
241+
assert.are.same(expected, file:reload_sync().lines)
242+
end)
243+
end)
155244
end)

0 commit comments

Comments
 (0)