Implement new slash commands and enhance editor functionality
- Added slash commands for inserting today's, yesterday's, and tomorrow's dates. - Introduced new admonition commands for notes and warnings. - Implemented a table command for quick table insertion. - Enhanced the `insertAtCursor` function to support a cursor placeholder option. - Updated `getSelection` to return the selected text along with cursor positions. - Added a new widget function to display linked tasks in the editor.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#meta
|
||||
|
||||
This is the start of the standard library distributed as part of SilverBullet core. All pages under this prefix are read-only.
|
||||
|
||||
${template.each(query[[
|
||||
@@ -27,6 +27,27 @@ end
|
||||
function date.time()
|
||||
return os.date(date.time_format)
|
||||
end
|
||||
|
||||
slashcommand.define {
|
||||
name = "today",
|
||||
run = function()
|
||||
editor.insertAtCursor(date.today())
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "yesterday",
|
||||
run = function()
|
||||
editor.insertAtCursor(date.yesterday())
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "tomorrow",
|
||||
run = function()
|
||||
editor.insertAtCursor(date.tomorrow())
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
This is your ${widgets.commandButton("Quick Note")} inbox.
|
||||
|
||||
${template.each(query[[
|
||||
from index.tag "page"
|
||||
where _.name:startsWith("Inbox/")
|
||||
order by _.lastModified desc
|
||||
]], templates.fullPageItem)}
|
||||
@@ -8,6 +8,11 @@ templates.pageItem = template.new([==[
|
||||
* [[${name}]]
|
||||
]==])
|
||||
|
||||
-- Renders a page object as a linked list item with full path
|
||||
templates.fullPageItem = template.new([==[
|
||||
* [[${name}|${name}]]
|
||||
]==])
|
||||
|
||||
-- Renders a task object as a togglable task
|
||||
templates.taskItem = template.new([==[
|
||||
* [${state}] [[${ref}]] ${name}
|
||||
|
||||
@@ -58,4 +58,44 @@ slashcommand.define {
|
||||
editor.replaceRange(line.from, line.to, ws .. "* [ ] " .. rest, true)
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "hr",
|
||||
run = function()
|
||||
editor.insertAtCursor("---\n")
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "note-admonition",
|
||||
run = function()
|
||||
editor.insertAtCursor([==[
|
||||
> **note** Note
|
||||
> |^|
|
||||
]==], false, true)
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "warning-admonition",
|
||||
run = function()
|
||||
editor.insertAtCursor([==[
|
||||
> **warning** Warning
|
||||
> |^|
|
||||
]==], false, true)
|
||||
end
|
||||
}
|
||||
|
||||
slashcommand.define {
|
||||
name = "table",
|
||||
exceptContexts = {"FencedCode"},
|
||||
run = function()
|
||||
editor.insertAtCursor([==[
|
||||
| Header A | Header B |
|
||||
|----------|----------|
|
||||
| Cell A|^| | Cell B |
|
||||
]==], false, true)
|
||||
end
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+32
-2
@@ -123,8 +123,8 @@ local mentionTemplate = template.new [==[
|
||||
* [[${_.ref}]]: “${_.snippet}”
|
||||
]==]
|
||||
|
||||
function widgets.linkedMentions()
|
||||
local pageName = editor.getCurrentPage()
|
||||
function widgets.linkedMentions(pageName)
|
||||
pageName = pageName or editor.getCurrentPage()
|
||||
local linkedMentions = query[[
|
||||
from index.tag "link"
|
||||
where _.page != pageName and _.toPage == pageName
|
||||
@@ -145,3 +145,33 @@ event.listen {
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
# Linked tasks
|
||||
```space-lua
|
||||
function widgets.linkedTasks(pageName)
|
||||
pageName = pageName or editor.getCurrentPage()
|
||||
local tasks = query[[
|
||||
from index.tag "task"
|
||||
where not _.done
|
||||
and string.find(_.name, "[[" .. pageName .. "]]", 1, true)
|
||||
]]
|
||||
local md = ""
|
||||
if #tasks > 0 then
|
||||
md = "# Linked Tasks\n"
|
||||
.. template.each(tasks, templates.taskItem)
|
||||
else
|
||||
md = ""
|
||||
end
|
||||
return widget.new {
|
||||
markdown = md
|
||||
}
|
||||
end
|
||||
|
||||
event.listen {
|
||||
name = "hooks:renderTopWidgets",
|
||||
run = function(e)
|
||||
print("Linked tasks")
|
||||
return widgets.linkedTasks()
|
||||
end
|
||||
}
|
||||
```
|
||||
@@ -282,13 +282,15 @@ export class LuaNativeJSFunction implements ILuaFunction {
|
||||
constructor(readonly fn: (...args: JSValue[]) => JSValue) {
|
||||
}
|
||||
|
||||
// Performs automatic conversion between Lua and JS values
|
||||
// Performs automatic conversion between Lua and JS values for arguments, but not for return values
|
||||
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
||||
const result = this.fn(...args.map((v) => luaValueToJS(v, sf)));
|
||||
if (result instanceof Promise) {
|
||||
return result.then(jsToLuaValue);
|
||||
const evaluatedArgs = evalPromiseValues(
|
||||
args.map((v) => luaValueToJS(v, sf)),
|
||||
);
|
||||
if (evaluatedArgs instanceof Promise) {
|
||||
return evaluatedArgs.then((args) => this.fn(...args));
|
||||
} else {
|
||||
return jsToLuaValue(result);
|
||||
return this.fn(...evaluatedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
jsToLuaValue,
|
||||
LuaBuiltinFunction,
|
||||
LuaNativeJSFunction,
|
||||
LuaTable,
|
||||
luaValueToJS,
|
||||
} from "$common/space_lua/runtime.ts";
|
||||
@@ -75,4 +76,10 @@ export const jsApi = new LuaTable({
|
||||
createTextNode: new LuaBuiltinFunction((_sf, text) =>
|
||||
document.createTextNode(text)
|
||||
),
|
||||
Blob: new LuaNativeJSFunction((
|
||||
blobParts: any[],
|
||||
options: BlobPropertyBag,
|
||||
) => {
|
||||
return new Blob(blobParts, options);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -70,7 +70,9 @@ export function getCursor(): Promise<number> {
|
||||
/**
|
||||
* Returns the line number and column number of the cursor in the editor
|
||||
*/
|
||||
export function getSelection(): Promise<{ from: number; to: number }> {
|
||||
export function getSelection(): Promise<
|
||||
{ from: number; to: number; text: string }
|
||||
> {
|
||||
return syscall("editor.getSelection");
|
||||
}
|
||||
|
||||
@@ -299,8 +301,14 @@ export function moveCursorToLine(
|
||||
export function insertAtCursor(
|
||||
text: string,
|
||||
scrollIntoView = false,
|
||||
cursorPlaceHolder = false,
|
||||
): Promise<void> {
|
||||
return syscall("editor.insertAtCursor", text, scrollIntoView);
|
||||
return syscall(
|
||||
"editor.insertAtCursor",
|
||||
text,
|
||||
scrollIntoView,
|
||||
cursorPlaceHolder,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+11
-2
@@ -59,8 +59,17 @@ export function editorSyscalls(client: Client): SysCallMapping {
|
||||
"editor.getCursor": (): number => {
|
||||
return client.editorView.state.selection.main.from;
|
||||
},
|
||||
"editor.getSelection": (): { from: number; to: number } => {
|
||||
return client.editorView.state.selection.main;
|
||||
"editor.getSelection": (): { from: number; to: number; text: string } => {
|
||||
const selection = client.editorView.state.selection.main;
|
||||
const text = client.editorView.state.sliceDoc(
|
||||
selection.from,
|
||||
selection.to,
|
||||
);
|
||||
return {
|
||||
from: selection.from,
|
||||
to: selection.to,
|
||||
text,
|
||||
};
|
||||
},
|
||||
"editor.save": () => {
|
||||
return client.save(true);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
description: Create a New Page template
|
||||
tags: template
|
||||
hooks.newPage:
|
||||
suggestedName: "Library/Personal/New Page/"
|
||||
confirmName: true
|
||||
frontmatter: |
|
||||
tags: template
|
||||
displayName: "|^|"
|
||||
hooks.newPage:
|
||||
suggestedName: ""
|
||||
---
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: Create a new Snippet template
|
||||
hooks.newPage:
|
||||
suggestedName: Library/Personal/Snippet/
|
||||
confirmName: true
|
||||
frontmatter: |
|
||||
tags: template
|
||||
hooks.snippet:
|
||||
slashCommand: "|^|"
|
||||
---
|
||||
@@ -1,7 +0,0 @@
|
||||
#meta
|
||||
|
||||
This page lists all `#meta` tagged pages currently available in your space. You can also navigate to them via the {[Navigate: Meta Picker]}.
|
||||
|
||||
```query
|
||||
page where tags = "meta" render [[Library/Core/Query/Page]]
|
||||
```
|
||||
@@ -1,8 +0,0 @@
|
||||
This is your {[Quick Note]} inbox.
|
||||
|
||||
```query
|
||||
page
|
||||
where name =~ /^Inbox\//
|
||||
render [[Library/Core/Query/Full Page]]
|
||||
order by lastModified desc
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: Insert a horizontal rule
|
||||
hooks.snippet:
|
||||
slashCommand: hr
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
---
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: Insert a "note" admonition
|
||||
hooks.snippet.slashCommand: note-admonition
|
||||
---
|
||||
> **note** Note
|
||||
> |^|
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: Insert a table
|
||||
hooks.snippet:
|
||||
slashCommand: table
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
| Header A | Header B |
|
||||
|----------|----------|
|
||||
| Cell A|^| | Cell B |
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: "Today's date"
|
||||
hooks.snippet.slashCommand: today
|
||||
---
|
||||
{{today}}
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: "Tomorrow's date"
|
||||
hooks.snippet.slashCommand: tomorrow
|
||||
---
|
||||
{{tomorrow}}
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
description: Insert a "warning" admonition
|
||||
tags: template
|
||||
hooks.snippet.slashCommand: warning-admonition
|
||||
---
|
||||
> **warning** Warning
|
||||
> |^|
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: "Yesterday's date"
|
||||
hooks.snippet.slashCommand: yesterday
|
||||
---
|
||||
{{yesterday}}
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: |
|
||||
Shows all tasks that contain a link the current page. For instance a task that references `[[John]]` in its name, would appear on the `John` page.
|
||||
hooks.top:
|
||||
where: 'true'
|
||||
order: 1
|
||||
---
|
||||
{{#let @linkedTasks = {task where not done and (contains(name, "[[" + @page.name + "]]") or contains(name, "[[" + @page.name + "|"))}}}
|
||||
{{#if @linkedTasks}}
|
||||
# Linked Tasks
|
||||
{{#each @linkedTasks}}
|
||||
{{template([[Library/Core/Query/Task]], .)}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
tags: template
|
||||
description: Queries all tasks tagged with a specific tag.
|
||||
usage: Pass in the tag to filter on as the `value` of this template
|
||||
---
|
||||
|
||||
```query
|
||||
task where tags = "{{.}}" and not done render [[Library/Core/Query/Task]]
|
||||
```
|
||||
Reference in New Issue
Block a user