Skip to content

Commit 210874b

Browse files
authored
Merge pull request #362 from epwalsh/epwalsh/list-tags
Add `Client:list_tags()` method
2 parents 8ea05a3 + c8cf296 commit 210874b

File tree

3 files changed

+41
-9
lines changed

3 files changed

+41
-9
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Added configuration option `image_name_func: (fun(): string)|?` for customizing the default image name/prefix when pasting images via `:ObsidianPasteImg`.
1313
- Added client method `Client:current_note()` to get the note corresponding to the current buffer.
14+
- Added client method `Client:list_tags()` for listing all tags in the vault, along with async version `Client:list_tags_async(callback: fun(tags: string[]))`.
1415
- Added note method `Note.add_field(key: string, value: any)` to add/update an additional field in the frontmatter.
1516
- Added note method `Note.get_field(key: string)`.
1617
- Added note method ` Note.save_to_buffer(bufnr: integer|?, frontmatter: table|?)` for saving the frontmatter to a buffer.

lua/obsidian/client.lua

+38-8
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ end
575575
---
576576
---@param term string|string[]
577577
---@param opts obsidian.SearchOpts|boolean|? search options or a boolean indicating if sorting should be used
578-
---@param timeout integer|?
578+
---@param timeout integer|? Timeout in milliseconds.
579579
---
580580
---@return obsidian.TagLocation[]
581581
Client.find_tags = function(self, term, opts, timeout)
@@ -599,10 +599,7 @@ Client.find_tags_async = function(self, term, opts, callback)
599599
end
600600

601601
for i, t in ipairs(terms) do
602-
if string.len(t) == 0 then
603-
log.err "Empty search terms are not allowed when searching for tags"
604-
return
605-
elseif vim.startswith(t, "#") then
602+
if vim.startswith(t, "#") then
606603
terms[i] = string.sub(t, 2)
607604
end
608605
end
@@ -680,6 +677,7 @@ Client.find_tags_async = function(self, term, opts, callback)
680677
local m_start, m_end, _ = unpack(match)
681678
local tag = string.sub(line, m_start + 1, m_end)
682679
for t in iter(terms) do
680+
-- NOTE: this works when 't' is an empty string too.
683681
if vim.startswith(string.lower(tag), t) then
684682
add_match(tag, path, note, match_data.line_number, line, m_start, m_end)
685683
n_matches = n_matches + 1
@@ -707,9 +705,15 @@ Client.find_tags_async = function(self, term, opts, callback)
707705

708706
local search_terms = {}
709707
for t in iter(terms) do
710-
search_terms[#search_terms + 1] = "#" .. t .. search.Patterns.TagChars -- tag in the wild
711-
search_terms[#search_terms + 1] = "\\s*- " .. t .. search.Patterns.TagChars -- frontmatter tag in multiline list
712-
search_terms[#search_terms + 1] = "tags: .*" .. t .. search.Patterns.TagChars -- frontmatter tag in inline list
708+
if string.len(t) > 0 then
709+
search_terms[#search_terms + 1] = "#" .. t .. search.Patterns.TagCharsOptional -- tag in the wild
710+
search_terms[#search_terms + 1] = "\\s*- " .. t .. search.Patterns.TagCharsOptional -- frontmatter tag in multiline list
711+
search_terms[#search_terms + 1] = "tags: .*" .. t .. search.Patterns.TagCharsOptional -- frontmatter tag in inline list
712+
else
713+
search_terms[#search_terms + 1] = "#" .. search.Patterns.TagCharsRequired -- tag in the wild
714+
search_terms[#search_terms + 1] = "\\s*- " .. search.Patterns.TagCharsRequired -- frontmatter tag in multiline list
715+
search_terms[#search_terms + 1] = "tags: .*" .. search.Patterns.TagCharsRequired -- frontmatter tag in inline list
716+
end
713717
end
714718

715719
search.search_async(
@@ -762,6 +766,32 @@ Client.find_tags_async = function(self, term, opts, callback)
762766
end, callback)
763767
end
764768

769+
--- Gather a list of all tags in the vault.
770+
---
771+
---@param timeout integer|? Timeout in milliseconds.
772+
---
773+
---@return string[]
774+
Client.list_tags = function(self, timeout)
775+
local tags = {}
776+
for _, tag_loc in ipairs(self:find_tags("", nil, timeout)) do
777+
tags[tag_loc.tag] = true
778+
end
779+
return vim.tbl_keys(tags)
780+
end
781+
782+
--- An async version of 'list_tags()'.
783+
---
784+
---@param callback fun(tags: string[])
785+
Client.list_tags_async = function(self, callback)
786+
self:find_tags_async("", nil, function(tag_locations)
787+
local tags = {}
788+
for _, tag_loc in ipairs(tag_locations) do
789+
tags[tag_loc.tag] = true
790+
end
791+
callback(vim.tbl_keys(tags))
792+
end)
793+
end
794+
765795
--- Apply a function over all notes in the current vault.
766796
---
767797
---@param on_note fun(note: obsidian.Note)

lua/obsidian/search.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ M.RefTypes = {
2424
---@enum obsidian.search.Patterns
2525
M.Patterns = {
2626
-- Miscellaneous
27-
TagChars = "[A-Za-z0-9_/-]*",
27+
TagCharsOptional = "[A-Za-z0-9_/-]*",
28+
TagCharsRequired = "[A-Za-z]+[A-Za-z0-9_/-]*[A-Za-z0-9]+", -- assumes tag is at least 2 chars
2829
Highlight = "==[^=]+==", -- ==text==
2930

3031
-- References

0 commit comments

Comments
 (0)