author: Chenzhu-Xie name: Library/xczphysics/CONFIG/Picker/Tags tags: meta/library
Practical tag search handles multi-tag intersections, which is both the advantage and the drawbacks (not one-to-one) of tags (Webs) over file systems (Trees).
One item can have many tags, and one tag can match many items.
Both are Webs, yet Tag is Star-like Set-theory, good at Filtering, Intersection, Classification Wiki is Mesh-like Graph-theory, good at Navigation, Association,
关于去重:
- 下面的代码是:收集完标签后,再一次性去重的
- 可以收集一次、去重一次,这样 效率会更高些(储存、处理得均更少)
- 像 Library/xczphysics/CONFIG/Mouse/History_+_Center#Logic behind|Click History 和 Library/xczphysics/CONFIG/Picker/Table#Implementation 3|Table Picker 一样
- 当然,我们更需要的是 Ah_LMYqd2CE #youtube SQL 中的 DUPLICATE 关键字
- SELECT DUPLICATE ssn FROM payments;
- 发现 luaQuerry 有个类似的关键字distinct query_collection.ts #github
- 通过 js silverbullet_c5736e4c 5f8d 4885 b3df 4767775ae5fb #deepwiki 中找寻 怎么在 js 中调用 SB 的 editor. API #项目经验
-- priority: 11
command.define {
name = "Navigate: Tags Picker",
key = "Ctrl-Alt-T",
run = function()
local selectedNames = {}
while true do
local potentialTags = {}
if #selectedNames == 0 then
potentialTags = query[from index.tag "tag" select {name = _.name}](from index.tag "tag" select {name = _.name})
else
local q = query[[from index.tag(selectedNames[1])]]
for i = 2, #selectedNames do
q = query[[
from q where table.includes(_.tags, selectedNames[i])
]]
end
local tagSet = {}
for _, obj in ipairs(q) do
if obj.tags and type(obj.tags) == "table" then
for _, t in ipairs(obj.tags) do
tagSet[t] = true
end
end
end
-- convert Set to list for Picker
for tagName, _ in pairs(tagSet) do
table.insert(potentialTags, {name = tagName})
end
table.sort(potentialTags, function(a, b) return a.name < b.name end)
end
local availableOptions = {}
for _, tagObj in ipairs(potentialTags) do
if not table.includes(selectedNames, tagObj.name) then
table.insert(availableOptions, tagObj)
end
end
if #availableOptions == 0 then
break
end
local description = "Select a Tag"
local placeholder = "🔖 a Tag"
if #selectedNames > 0 then
description = "Selected Tags ⏺️:" .. table.concat(selectedNames, ", ") .. " ➕ (ESC to Go)"
placeholder = string.rep("🔖", #selectedNames) .. " Filter next tag..."
end
local selection = editor.filterBox("🤏 Pick", availableOptions, description, placeholder)
if selection then
table.insert(selectedNames, selection.name)
else
if #selectedNames == 0 then
return
else
break
end
end
end
local targetPage = "tags:" .. table.concat(selectedNames, ",")
editor.navigate(targetPage)
end
}
-- priority: 11
command.define {
name = "Navigate: Tags Picker",
key = "Ctrl-Alt-T",
run = function()
local allTags = query[from index.tag "tag" select {name = _.name}](from index.tag "tag" select {name = _.name})
local selectedNames = {}
while true do
local availableOptions = {}
for _, tagObj in ipairs(allTags) do
if not table.includes(selectedNames, tagObj.name) then
table.insert(availableOptions, tagObj)
end
end
if #availableOptions == 0 then
break
end
local description = "Select a Tag"
local placeholder = "🔖 a Tag"
if #selectedNames > 0 then
description = "Selected Tags ⏺️:" .. table.concat(selectedNames, ", ") .. " ➕ (ESC to Go)"
placeholder = string.rep("🔖", #selectedNames) .. " a Tag"
end
local selection = editor.filterBox("🤏 Pick", availableOptions, description, placeholder)
if selection then
table.insert(selectedNames, selection.name)
else
if #selectedNames == 0 then
return
else
break
end
end
end
local targetPage = "tags:" .. table.concat(selectedNames, ",")
editor.navigate(targetPage)
end
}
-- priority: 11
virtualPage.define {
pattern = "tags:(.+)",
run = function(inputString)
local rawTags = inputString:split(",")
local Tags = {}
for _, t in ipairs(rawTags) do
local cleanTag = t:trim()
if cleanTag ~= "" then
table.insert(Tags, cleanTag)
end
end
if #Tags == 0 then return "No tags specified." end
local text = ""
local tagName = Tags[1]
local allObjects = query[
from index.tag(tagName)
order by ref
](
from index.tag(tagName)
order by ref
)
if #Tags == 1 then
text = "# Objects tagged with: " .. tagName .. "\n"
local tagParts = tagName:split("/")
local parentTags = {}
for i in ipairs(tagParts) do
local slice = table.pack(table.unpack(tagParts, 1, i))
if i ~= #tagParts then
table.insert(parentTags, {name=table.concat(slice, "/")})
end
end
if #parentTags > 0 then
text = text .. "## Parent tags\n"
.. template.each(parentTags, templates.tagItem)
end
local subTags = query[
from index.tag "tag"
where string.startsWith(_.name, tagName .. "/")
select {name=_.name}
](
from index.tag "tag"
where string.startsWith(_.name, tagName .. "/")
select {name=_.name}
)
if #subTags > 0 then
text = text .. "## Child tags\n"
.. template.each(subTags, templates.tagItem)
end
else
text = "# Objects tagged with: " .. table.concat(Tags, ", ") .. "\n"
for i = 2, #Tags do
allObjects = query[[
from allObjects
where table.includes(_.tags, Tags[i])
]]
end
end
local taggedPages = {}
local taggedTasks = {}
local taggedItems = {}
local taggedData = {}
local taggedParagraphs = {}
-- improve performance
for _, obj in ipairs(allObjects) do
if obj.itags and table.includes(obj.itags, "page") then
table.insert(taggedPages, obj)
end
if obj.itags and table.includes(obj.itags, "task") then
table.insert(taggedTasks, obj)
end
if obj.itags and table.includes(obj.itags, "item") then
table.insert(taggedItems, obj)
end
if obj.itags and table.includes(obj.itags, "data") then
table.insert(taggedData, obj)
end
if obj.itags and table.includes(obj.itags, "paragraph") then
table.insert(taggedParagraphs, obj)
end
end
if #taggedPages > 0 then
text = text .. "## Pages\n"
.. template.each(taggedPages, templates.pageItem)
end
if #taggedTasks > 0 then
text = text .. "## Tasks\n"
.. template.each(taggedTasks, templates.taskItem)
end
if #taggedItems > 0 then
text = text .. "## Items\n"
.. template.each(taggedItems, templates.itemItem)
end
if #taggedData > 0 then
text = text .. "## Data\n"
.. markdown.objectsToTable(taggedData) .. "\n"
end
if #taggedParagraphs > 0 then
text = text .. "## Paragraphs\n"
.. template.each(taggedParagraphs, templates.paragraphItem)
end
return text
end
}
${query[from index.tag "tag" select {name = _.name}](from index.tag "tag" select {name = _.name})} 中的 name 不含重复元素, 是个 set 集合。
${query[[from index.tag "tag"} 中的 name 含重复的元素。
https://community.silverbullet.md/t/quickly-search-open-tag-virtual-page/1104/15
official one: silverbullet 2 3 released share libraries library manager and repositories #community #silverbullet
-- priority: 11
command.define {
name = "Navigate: Tag Picker",
key = "Ctrl-Alt-t",
run = function()
local tags = query[from index.tag "tag" select {name = _.name}](from index.tag "tag" select {name = _.name})
local sel = editor.filterBox("🤏 Pick", tags, "Select a Tag", "🔖 a Tag")
if sel then editor.navigate("tag:" .. sel.name) end
end
}
command.define {
name = "Search All",
key = "Ctrl-Shift-t",
run = function()
-- Query all object types
local allHeaders = query[from index.tag "header" ](from index.tag "header" )
local allPages = query[from index.tag "page" ](from index.tag "page" )
local allItems = query[from index.tag "item" ](from index.tag "item" )
local allParagraph = query[from index.tag "paragraph" ](from index.tag "paragraph" )
-- Combine all results
local all = {}
for _, item in ipairs(allHeaders) do
table.insert(all, item)
end
for _, item in ipairs(allPages) do
table.insert(all, item)
end
for _, item in ipairs(allItems) do
table.insert(all, item)
end
for _, item in ipairs(allParagraph) do
table.insert(all, item)
end
-- Create filter options
local options = {}
for _, item in ipairs(all) do
table.insert(options, {
name = item.text or item.name or item.page,
description = item.page,
page = item.ref
})
end
-- Show filter box
local selected = editor.filterBox(
"Full Text Search",
options,
"Select the search"
)
if selected then
-- Find the original data item
local data = nil
for _, item in ipairs(all) do
if (item.text or item.name or item.page) == selected.name then
data = item
break
end
end
if data then
editor.navigate(data.ref)
end
end
end
}