Lua: huge API breaking change: converted all snake_case APIs to camelCase
parent
0635faabfc
commit
a169406d37
|
@ -436,7 +436,7 @@ Deno.test("Thread local _CTX - advanced cases", async () => {
|
||||||
sf.threadLocal.setLocal("_GLOBAL", env);
|
sf.threadLocal.setLocal("_GLOBAL", env);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
await evalExpr(
|
await evalExpr(
|
||||||
"space_lua.interpolate('Hello, ${globalEnv} and ${loc}!', {loc='local'})",
|
"spacelua.interpolate('Hello, ${globalEnv} and ${loc}!', {loc='local'})",
|
||||||
env,
|
env,
|
||||||
sf,
|
sf,
|
||||||
),
|
),
|
||||||
|
@ -446,7 +446,7 @@ Deno.test("Thread local _CTX - advanced cases", async () => {
|
||||||
// Some more complex string interpolation with more complex lua expressions, with nested {}
|
// Some more complex string interpolation with more complex lua expressions, with nested {}
|
||||||
assertEquals(
|
assertEquals(
|
||||||
await evalExpr(
|
await evalExpr(
|
||||||
`space_lua.interpolate('Some JSON \${js.stringify(js.tojs({name="Pete"}))}!')`,
|
`spacelua.interpolate('Some JSON \${js.stringify(js.tojs({name="Pete"}))}!')`,
|
||||||
env,
|
env,
|
||||||
sf,
|
sf,
|
||||||
),
|
),
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { stringApi } from "$common/space_lua/stdlib/string.ts";
|
||||||
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
||||||
import { osApi } from "$common/space_lua/stdlib/os.ts";
|
import { osApi } from "$common/space_lua/stdlib/os.ts";
|
||||||
import { jsApi } from "$common/space_lua/stdlib/js.ts";
|
import { jsApi } from "$common/space_lua/stdlib/js.ts";
|
||||||
import { spaceLuaApi } from "$common/space_lua/stdlib/space_lua.ts";
|
import { spaceluaApi } from "$common/space_lua/stdlib/space_lua.ts";
|
||||||
import { mathApi } from "$common/space_lua/stdlib/math.ts";
|
import { mathApi } from "$common/space_lua/stdlib/math.ts";
|
||||||
import { parse } from "$common/space_lua/parse.ts";
|
import { parse } from "$common/space_lua/parse.ts";
|
||||||
import { evalStatement } from "$common/space_lua/eval.ts";
|
import { evalStatement } from "$common/space_lua/eval.ts";
|
||||||
|
@ -193,7 +193,7 @@ export function luaBuildStandardEnv() {
|
||||||
env.set("math", mathApi);
|
env.set("math", mathApi);
|
||||||
// Non-standard
|
// Non-standard
|
||||||
env.set("each", eachFunction);
|
env.set("each", eachFunction);
|
||||||
env.set("space_lua", spaceLuaApi);
|
env.set("spacelua", spaceluaApi);
|
||||||
// env.set("template", templateApi);
|
// env.set("template", templateApi);
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ export const jsApi = new LuaTable({
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}),
|
}),
|
||||||
each_iterable: new LuaBuiltinFunction((_sf, val) => {
|
eachIterable: new LuaBuiltinFunction((_sf, val) => {
|
||||||
const iterator = val[Symbol.asyncIterator]();
|
const iterator = val[Symbol.asyncIterator]();
|
||||||
return async () => {
|
return async () => {
|
||||||
const result = await iterator.next();
|
const result = await iterator.next();
|
||||||
|
|
|
@ -210,12 +210,12 @@ print(math.ult(2, 1)) -- prints: false
|
||||||
```
|
```
|
||||||
|
|
||||||
# Non-standard Extensions
|
# Non-standard Extensions
|
||||||
## math.cosine_similarity(vecA, vecB)
|
## math.cosineSimilarity(vecA, vecB)
|
||||||
Returns the cosine similarity between two vectors.
|
Returns the cosine similarity between two vectors.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local vec1 = {1, 2, 3}
|
local vec1 = {1, 2, 3}
|
||||||
local vec2 = {4, 5, 6}
|
local vec2 = {4, 5, 6}
|
||||||
print(math.cosine_similarity(vec1, vec2)) -- prints: 0.9746318461970762
|
print(math.cosineSimilarity(vec1, vec2)) -- prints: 0.9746318461970762
|
||||||
```
|
```
|
||||||
|
|
|
@ -71,8 +71,8 @@ export const mathApi = new LuaTable({
|
||||||
return (m >>> 0) < (n >>> 0);
|
return (m >>> 0) < (n >>> 0);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Keep the cosine_similarity utility function
|
// Keep the cosineSimilarity utility function
|
||||||
cosine_similarity: new LuaBuiltinFunction(
|
cosineSimilarity: new LuaBuiltinFunction(
|
||||||
(sf, vecA: LuaTable | number[], vecB: LuaTable | number[]) => {
|
(sf, vecA: LuaTable | number[], vecB: LuaTable | number[]) => {
|
||||||
// Convert LuaTable to number[]
|
// Convert LuaTable to number[]
|
||||||
if (vecA instanceof LuaTable) {
|
if (vecA instanceof LuaTable) {
|
||||||
|
|
|
@ -1,48 +1,48 @@
|
||||||
local function assert_equal(a, b)
|
local function assertEqual(a, b)
|
||||||
if a ~= b then
|
if a ~= b then
|
||||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Trigonometric functions
|
-- Trigonometric functions
|
||||||
assert_equal(math.cos(0), 1)
|
assertEqual(math.cos(0), 1)
|
||||||
assert_equal(math.sin(0), 0)
|
assertEqual(math.sin(0), 0)
|
||||||
assert_equal(math.tan(0), 0)
|
assertEqual(math.tan(0), 0)
|
||||||
assert_equal(math.acos(1), 0)
|
assertEqual(math.acos(1), 0)
|
||||||
assert_equal(math.asin(0), 0)
|
assertEqual(math.asin(0), 0)
|
||||||
assert_equal(math.atan(0), 0)
|
assertEqual(math.atan(0), 0)
|
||||||
|
|
||||||
-- Hyperbolic functions
|
-- Hyperbolic functions
|
||||||
assert_equal(math.cosh(0), 1)
|
assertEqual(math.cosh(0), 1)
|
||||||
assert_equal(math.sinh(0), 0)
|
assertEqual(math.sinh(0), 0)
|
||||||
assert_equal(math.tanh(0), 0)
|
assertEqual(math.tanh(0), 0)
|
||||||
|
|
||||||
-- Basic functions
|
-- Basic functions
|
||||||
assert_equal(math.abs(-5), 5)
|
assertEqual(math.abs(-5), 5)
|
||||||
assert_equal(math.ceil(3.3), 4)
|
assertEqual(math.ceil(3.3), 4)
|
||||||
assert_equal(math.floor(3.7), 3)
|
assertEqual(math.floor(3.7), 3)
|
||||||
assert_equal(math.max(1, 2, 3, 4), 4)
|
assertEqual(math.max(1, 2, 3, 4), 4)
|
||||||
assert_equal(math.min(1, 2, 3, 4), 1)
|
assertEqual(math.min(1, 2, 3, 4), 1)
|
||||||
|
|
||||||
-- Rounding and remainder
|
-- Rounding and remainder
|
||||||
assert_equal(math.fmod(7, 3), 1)
|
assertEqual(math.fmod(7, 3), 1)
|
||||||
|
|
||||||
-- Power and logarithms
|
-- Power and logarithms
|
||||||
assert_equal(math.exp(0), 1)
|
assertEqual(math.exp(0), 1)
|
||||||
assert_equal(math.log(math.exp(1)), 1)
|
assertEqual(math.log(math.exp(1)), 1)
|
||||||
assert_equal(math.log(8, 2), 3) -- log base 2 of 8
|
assertEqual(math.log(8, 2), 3) -- log base 2 of 8
|
||||||
assert_equal(math.pow(2, 3), 8)
|
assertEqual(math.pow(2, 3), 8)
|
||||||
assert_equal(math.sqrt(9), 3)
|
assertEqual(math.sqrt(9), 3)
|
||||||
|
|
||||||
|
|
||||||
-- Random number tests (basic range checks)
|
-- Random number tests (basic range checks)
|
||||||
local rand = math.random()
|
local rand = math.random()
|
||||||
assert_equal(rand >= 0 and rand < 1, true)
|
assertEqual(rand >= 0 and rand < 1, true)
|
||||||
local rand_n = math.random(10)
|
local randN = math.random(10)
|
||||||
assert_equal(rand_n >= 1 and rand_n <= 10, true)
|
assertEqual(randN >= 1 and randN <= 10, true)
|
||||||
local rand_range = math.random(5, 10)
|
local randRange = math.random(5, 10)
|
||||||
assert_equal(rand_range >= 5 and rand_range <= 10, true)
|
assertEqual(randRange >= 5 and randRange <= 10, true)
|
||||||
|
|
||||||
-- Unsigned less than comparison
|
-- Unsigned less than comparison
|
||||||
assert_equal(math.ult(1, 2), true)
|
assertEqual(math.ult(1, 2), true)
|
||||||
assert_equal(math.ult(2, 1), false)
|
assertEqual(math.ult(2, 1), false)
|
||||||
|
|
|
@ -100,7 +100,7 @@ export async function interpolateLuaString(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const spaceLuaApi = new LuaTable({
|
export const spaceluaApi = new LuaTable({
|
||||||
/**
|
/**
|
||||||
* Parses a lua expression and returns the parsed expression.
|
* Parses a lua expression and returns the parsed expression.
|
||||||
*
|
*
|
||||||
|
@ -108,7 +108,7 @@ export const spaceLuaApi = new LuaTable({
|
||||||
* @param luaExpression - The lua expression to parse.
|
* @param luaExpression - The lua expression to parse.
|
||||||
* @returns The parsed expression.
|
* @returns The parsed expression.
|
||||||
*/
|
*/
|
||||||
parse_expression: new LuaBuiltinFunction(
|
parseExpression: new LuaBuiltinFunction(
|
||||||
(_sf, luaExpression: string) => {
|
(_sf, luaExpression: string) => {
|
||||||
return parseExpressionString(luaExpression);
|
return parseExpressionString(luaExpression);
|
||||||
},
|
},
|
||||||
|
@ -121,7 +121,7 @@ export const spaceLuaApi = new LuaTable({
|
||||||
* @param envAugmentation - An optional environment to augment the global environment with.
|
* @param envAugmentation - An optional environment to augment the global environment with.
|
||||||
* @returns The result of the evaluated expression.
|
* @returns The result of the evaluated expression.
|
||||||
*/
|
*/
|
||||||
eval_expression: new LuaBuiltinFunction(
|
evalExpression: new LuaBuiltinFunction(
|
||||||
async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
|
async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
|
||||||
const env = createAugmentedEnv(sf, envAugmentation);
|
const env = createAugmentedEnv(sf, envAugmentation);
|
||||||
return luaValueToJS(await evalExpression(parsedExpr, env, sf));
|
return luaValueToJS(await evalExpression(parsedExpr, env, sf));
|
||||||
|
@ -138,7 +138,7 @@ export const spaceLuaApi = new LuaTable({
|
||||||
/**
|
/**
|
||||||
* Returns your SilverBullet instance's base URL, or `undefined` when run on the server
|
* Returns your SilverBullet instance's base URL, or `undefined` when run on the server
|
||||||
*/
|
*/
|
||||||
base_url: new LuaBuiltinFunction(
|
baseUrl: new LuaBuiltinFunction(
|
||||||
() => {
|
() => {
|
||||||
// Deal with Deno
|
// Deal with Deno
|
||||||
if (typeof location === "undefined") {
|
if (typeof location === "undefined") {
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
local function assert_equal(a, b)
|
local parsedExpr = spacelua.parseExpression("1 + 1")
|
||||||
if a ~= b then
|
local evalResult = spacelua.evalExpression(parsedExpr)
|
||||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Test space_lua stuff
|
|
||||||
local parsedExpr = space_lua.parse_expression("1 + 1")
|
|
||||||
local evalResult = space_lua.eval_expression(parsedExpr)
|
|
||||||
assert(evalResult == 2, "Eval should return 2")
|
assert(evalResult == 2, "Eval should return 2")
|
||||||
|
|
||||||
-- Slightly more advanced example with augmented environment
|
-- Slightly more advanced example with augmented environment
|
||||||
local parsedExpr = space_lua.parse_expression("tostring(a + 1)")
|
local parsedExpr = spacelua.parseExpression("tostring(a + 1)")
|
||||||
local evalResult = space_lua.eval_expression(parsedExpr, { a = 1 })
|
local evalResult = spacelua.evalExpression(parsedExpr, { a = 1 })
|
||||||
assert(evalResult == "2", "Eval should return 2 as a string")
|
assert(evalResult == "2", "Eval should return 2 as a string")
|
|
@ -207,18 +207,18 @@ export const stringApi = new LuaTable({
|
||||||
trim: new LuaBuiltinFunction((_sf, s: string) => {
|
trim: new LuaBuiltinFunction((_sf, s: string) => {
|
||||||
return s.trim();
|
return s.trim();
|
||||||
}),
|
}),
|
||||||
trim_start: new LuaBuiltinFunction((_sf, s: string) => {
|
trimStart: new LuaBuiltinFunction((_sf, s: string) => {
|
||||||
return s.trimStart();
|
return s.trimStart();
|
||||||
}),
|
}),
|
||||||
trim_end: new LuaBuiltinFunction((_sf, s: string) => {
|
trimEnd: new LuaBuiltinFunction((_sf, s: string) => {
|
||||||
return s.trimEnd();
|
return s.trimEnd();
|
||||||
}),
|
}),
|
||||||
match_regex: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
matchRegex: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
||||||
const regex = new RegExp(pattern);
|
const regex = new RegExp(pattern);
|
||||||
const result = s.match(regex);
|
const result = s.match(regex);
|
||||||
return jsToLuaValue(result);
|
return jsToLuaValue(result);
|
||||||
}),
|
}),
|
||||||
match_regex_all: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
matchRegexAll: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
||||||
const regex = new RegExp(pattern, "g");
|
const regex = new RegExp(pattern, "g");
|
||||||
return () => {
|
return () => {
|
||||||
const match = regex.exec(s);
|
const match = regex.exec(s);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
local function assert_equal(a, b)
|
local function assertEqual(a, b)
|
||||||
if a ~= b then
|
if a ~= b then
|
||||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||||
end
|
end
|
||||||
|
@ -73,80 +73,80 @@ assert(result == "hello-world", "Magic character replacement failed")
|
||||||
|
|
||||||
-- Test string.match
|
-- Test string.match
|
||||||
local m1, m2 = string.match("hello world", "(h)(ello)")
|
local m1, m2 = string.match("hello world", "(h)(ello)")
|
||||||
assert_equal(m1, "h")
|
assertEqual(m1, "h")
|
||||||
assert_equal(m2, "ello")
|
assertEqual(m2, "ello")
|
||||||
|
|
||||||
-- Test match with init position - need to capture the group
|
-- Test match with init position - need to capture the group
|
||||||
local init_match = string.match("hello world", "(world)", 7)
|
local initMatch = string.match("hello world", "(world)", 7)
|
||||||
assert_equal(init_match, "world")
|
assertEqual(initMatch, "world")
|
||||||
|
|
||||||
-- Test string.gmatch
|
-- Test string.gmatch
|
||||||
local words = {}
|
local words = {}
|
||||||
for word in string.gmatch("hello world lua", "%w+") do
|
for word in string.gmatch("hello world lua", "%w+") do
|
||||||
table.insert(words, word)
|
table.insert(words, word)
|
||||||
end
|
end
|
||||||
assert_equal(words[1], "hello")
|
assertEqual(words[1], "hello")
|
||||||
assert_equal(words[2], "world")
|
assertEqual(words[2], "world")
|
||||||
assert_equal(words[3], "lua")
|
assertEqual(words[3], "lua")
|
||||||
|
|
||||||
-- Test string.reverse
|
-- Test string.reverse
|
||||||
assert_equal(string.reverse("hello"), "olleh")
|
assertEqual(string.reverse("hello"), "olleh")
|
||||||
assert_equal(string.reverse(""), "")
|
assertEqual(string.reverse(""), "")
|
||||||
|
|
||||||
-- Test string.split
|
-- Test string.split
|
||||||
local parts = string.split("a,b,c", ",")
|
local parts = string.split("a,b,c", ",")
|
||||||
assert_equal(parts[1], "a")
|
assertEqual(parts[1], "a")
|
||||||
assert_equal(parts[2], "b")
|
assertEqual(parts[2], "b")
|
||||||
assert_equal(parts[3], "c")
|
assertEqual(parts[3], "c")
|
||||||
|
|
||||||
-- Test non-standard string extensions
|
-- Test non-standard string extensions
|
||||||
assert_equal(string.startswith("hello world", "hello"), true)
|
assertEqual(string.startswith("hello world", "hello"), true)
|
||||||
assert_equal(string.startswith("hello world", "world"), false)
|
assertEqual(string.startswith("hello world", "world"), false)
|
||||||
|
|
||||||
assert_equal(string.endswith("hello world", "world"), true)
|
assertEqual(string.endswith("hello world", "world"), true)
|
||||||
assert_equal(string.endswith("hello world", "hello"), false)
|
assertEqual(string.endswith("hello world", "hello"), false)
|
||||||
|
|
||||||
-- Extended string.match tests
|
-- Extended string.match tests
|
||||||
-- Basic pattern matching
|
-- Basic pattern matching
|
||||||
assert_equal(string.match("hello", "h"), "h")
|
assertEqual(string.match("hello", "h"), "h")
|
||||||
assert_equal(string.match("hello", "hello"), "hello")
|
assertEqual(string.match("hello", "hello"), "hello")
|
||||||
|
|
||||||
-- Test with no matches
|
-- Test with no matches
|
||||||
assert_equal(string.match("hello", "x"), nil)
|
assertEqual(string.match("hello", "x"), nil)
|
||||||
|
|
||||||
-- Test with captures
|
-- Test with captures
|
||||||
local m1, m2 = string.match("hello", "(h)(ello)")
|
local m1, m2 = string.match("hello", "(h)(ello)")
|
||||||
assert_equal(m1, "h")
|
assertEqual(m1, "h")
|
||||||
assert_equal(m2, "ello")
|
assertEqual(m2, "ello")
|
||||||
|
|
||||||
-- Test with init position
|
-- Test with init position
|
||||||
local init_match = string.match("hello world", "(world)", 7)
|
local initMatch = string.match("hello world", "(world)", 7)
|
||||||
assert_equal(init_match, "world")
|
assertEqual(initMatch, "world")
|
||||||
|
|
||||||
-- Test init position with no match
|
-- Test init position with no match
|
||||||
assert_equal(string.match("hello world", "hello", 7), nil)
|
assertEqual(string.match("hello world", "hello", 7), nil)
|
||||||
|
|
||||||
-- Test pattern characters
|
-- Test pattern characters
|
||||||
assert_equal(string.match("123", "%d+"), "123")
|
assertEqual(string.match("123", "%d+"), "123")
|
||||||
assert_equal(string.match("abc123", "%a+"), "abc")
|
assertEqual(string.match("abc123", "%a+"), "abc")
|
||||||
assert_equal(string.match(" abc", "%s+"), " ")
|
assertEqual(string.match(" abc", "%s+"), " ")
|
||||||
|
|
||||||
-- Test multiple captures
|
-- Test multiple captures
|
||||||
local day, month, year = string.match("2024-03-14", "(%d+)-(%d+)-(%d+)")
|
local day, month, year = string.match("2024-03-14", "(%d+)-(%d+)-(%d+)")
|
||||||
assert_equal(day, "2024")
|
assertEqual(day, "2024")
|
||||||
assert_equal(month, "03")
|
assertEqual(month, "03")
|
||||||
assert_equal(year, "14")
|
assertEqual(year, "14")
|
||||||
|
|
||||||
-- Test optional captures
|
-- Test optional captures
|
||||||
local word = string.match("The quick brown fox", "%s*(%w+)%s*")
|
local word = string.match("The quick brown fox", "%s*(%w+)%s*")
|
||||||
assert_equal(word, "The")
|
assertEqual(word, "The")
|
||||||
|
|
||||||
-- Test match_regex_all
|
-- Test matchRegexAll
|
||||||
local matches = {}
|
local matches = {}
|
||||||
for match in string.match_regex_all("hellolllbl", "(l+)") do
|
for match in string.matchRegexAll("hellolllbl", "(l+)") do
|
||||||
table.insert(matches, match)
|
table.insert(matches, match)
|
||||||
end
|
end
|
||||||
assert_equal(#matches, 3)
|
assertEqual(#matches, 3)
|
||||||
assert_equal(matches[1][1], "ll")
|
assertEqual(matches[1][1], "ll")
|
||||||
assert_equal(matches[2][1], "lll")
|
assertEqual(matches[2][1], "lll")
|
||||||
assert_equal(matches[3][1], "l")
|
assertEqual(matches[3][1], "l")
|
||||||
|
|
|
@ -34,9 +34,7 @@ function exposeSyscalls(env: LuaEnv, system: System<any>) {
|
||||||
const luaFn = new LuaNativeJSFunction((...args) => {
|
const luaFn = new LuaNativeJSFunction((...args) => {
|
||||||
return system.localSyscall(syscallName, args);
|
return system.localSyscall(syscallName, args);
|
||||||
});
|
});
|
||||||
// Register the function with the same name as the syscall both in regular and snake_case
|
|
||||||
env.get(ns, nativeFs).set(fn, luaFn, nativeFs);
|
env.get(ns, nativeFs).set(fn, luaFn, nativeFs);
|
||||||
env.get(ns, nativeFs).set(snakeCase(fn), luaFn, nativeFs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,9 +64,9 @@ export async function handleLuaError(e: LuaRuntimeError, system: System<any>) {
|
||||||
console.error(
|
console.error(
|
||||||
"Lua eval exception",
|
"Lua eval exception",
|
||||||
e.message,
|
e.message,
|
||||||
e.sf.astCtx,
|
e.sf?.astCtx,
|
||||||
);
|
);
|
||||||
if (e.sf.astCtx && e.sf.astCtx.ref) {
|
if (e.sf?.astCtx && e.sf.astCtx.ref) {
|
||||||
// We got an error and actually know where it came from, let's navigate there to help debugging
|
// We got an error and actually know where it came from, let's navigate there to help debugging
|
||||||
const pageRef = parsePageRef(e.sf.astCtx.ref);
|
const pageRef = parsePageRef(e.sf.astCtx.ref);
|
||||||
await system.localSyscall(
|
await system.localSyscall(
|
||||||
|
@ -95,7 +93,3 @@ export async function handleLuaError(e: LuaRuntimeError, system: System<any>) {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function snakeCase(s: string) {
|
|
||||||
return s.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ export function commandSyscalls(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
"slash_command.define": (
|
"slashcommand.define": (
|
||||||
_ctx,
|
_ctx,
|
||||||
def: CallbackCommandDef,
|
def: CallbackCommandDef,
|
||||||
) => {
|
) => {
|
||||||
|
|
|
@ -111,7 +111,7 @@ export function indexSyscalls(commonSystem: CommonSystem): SysCallMapping {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (await global.get("datastore").get("query_lua").call(
|
return (await global.get("datastore").get("queryLua").call(
|
||||||
sf,
|
sf,
|
||||||
[
|
[
|
||||||
"idx",
|
"idx",
|
||||||
|
|
|
@ -6,11 +6,11 @@ Config library for defining and getting config values
|
||||||
-- priority: 10
|
-- priority: 10
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
local config_values = {}
|
local configValues = {}
|
||||||
local config_schema = {}
|
local configSchema = {}
|
||||||
|
|
||||||
function config.define(key, schema)
|
function config.define(key, schema)
|
||||||
config_schema[key] = schema or true
|
configSchema[key] = schema or true
|
||||||
end
|
end
|
||||||
|
|
||||||
function config.set(keyOrTable, value)
|
function config.set(keyOrTable, value)
|
||||||
|
@ -21,20 +21,19 @@ function config.set(keyOrTable, value)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local key = keyOrTable
|
local key = keyOrTable
|
||||||
local schema = config_schema[key]
|
local schema = configSchema[key]
|
||||||
if schema == nil then
|
if schema == nil then
|
||||||
error("Config key not defined: " .. key)
|
error("Config key not defined: " .. key)
|
||||||
end
|
end
|
||||||
if schema != true then
|
if schema != true then
|
||||||
local result = jsonschema.validate_object(schema, value)
|
local result = jsonschema.validateObject(schema, value)
|
||||||
if result != nil then
|
if result != nil then
|
||||||
error("Validation error (" .. key .. "): " .. result)
|
error("Validation error (" .. key .. "): " .. result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
config_values[key] = value
|
configValues[key] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
function config.get(key)
|
function config.get(key)
|
||||||
return config_values[key]
|
return configValues[key]
|
||||||
end
|
end
|
||||||
```
|
|
|
@ -7,28 +7,28 @@ Editor support for Lua, implemented in Lua. Of course.
|
||||||
local LUA_KEYWORDS = {"do", "if", "then", "for", "else", "end", "function", "local", "return"}
|
local LUA_KEYWORDS = {"do", "if", "then", "for", "else", "end", "function", "local", "return"}
|
||||||
|
|
||||||
-- Are we in a comment?
|
-- Are we in a comment?
|
||||||
local function in_comment(line)
|
local function inComment(line)
|
||||||
return string.find(line, "--")
|
return string.find(line, "--")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Are we in a string?
|
-- Are we in a string?
|
||||||
local function in_string(line)
|
local function inString(line)
|
||||||
local single_quotes = 0
|
local singleQuotes = 0
|
||||||
local double_quotes = 0
|
local doubleQuotes = 0
|
||||||
local brackets = 0
|
local brackets = 0
|
||||||
for i = 1, string.len(line) do
|
for i = 1, string.len(line) do
|
||||||
local c = line[i]
|
local c = line[i]
|
||||||
if c == "'" then
|
if c == "'" then
|
||||||
single_quotes = single_quotes + 1
|
singleQuotes = singleQuotes + 1
|
||||||
elseif c == '"' then
|
elseif c == '"' then
|
||||||
double_quotes = double_quotes + 1
|
doubleQuotes = doubleQuotes + 1
|
||||||
elseif c == "[" and line[i+1] == "[" then
|
elseif c == "[" and line[i+1] == "[" then
|
||||||
brackets = brackets + 1
|
brackets = brackets + 1
|
||||||
elseif c == "]" and line[i-1] == "]" then
|
elseif c == "]" and line[i-1] == "]" then
|
||||||
brackets = brackets - 1
|
brackets = brackets - 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return single_quotes % 2 == 1 or double_quotes % 2 == 1 or brackets > 0
|
return singleQuotes % 2 == 1 or doubleQuotes % 2 == 1 or brackets > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- API code completion for Lua
|
-- API code completion for Lua
|
||||||
|
@ -37,33 +37,33 @@ event.listen {
|
||||||
name = "editor:complete",
|
name = "editor:complete",
|
||||||
run = function(e)
|
run = function(e)
|
||||||
local parents = e.data.parentNodes
|
local parents = e.data.parentNodes
|
||||||
local found_space_lua = false
|
local foundSpaceLua = false
|
||||||
for _, parent in ipairs(parents) do
|
for _, parent in ipairs(parents) do
|
||||||
if string.startswith(parent, "FencedCode:space-lua") then
|
if string.startswith(parent, "FencedCode:space-lua") then
|
||||||
found_space_lua = true
|
foundSpaceLua = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not found_space_lua then
|
if not foundSpaceLua then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local line_prefix = e.data.linePrefix
|
local linePrefix = e.data.linePrefix
|
||||||
if in_comment(line_prefix) or in_string(line_prefix) then
|
if inComment(linePrefix) or inString(linePrefix) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local pos = e.data.pos
|
local pos = e.data.pos
|
||||||
local propaccess_prefix = string.match_regex(line_prefix, "([a-zA-Z_0-9]+\\.)*([a-zA-Z_0-9]*)$")
|
local propaccessPrefix = string.matchRegex(linePrefix, "([a-zA-Z_0-9]+\\.)*([a-zA-Z_0-9]*)$")
|
||||||
if not propaccess_prefix or not propaccess_prefix[1] then
|
if not propaccessPrefix or not propaccessPrefix[1] then
|
||||||
-- No propaccess prefix, so we can't complete
|
-- No propaccess prefix, so we can't complete
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- Split propaccess and traverse
|
-- Split propaccess and traverse
|
||||||
local prop_parts = string.split(propaccess_prefix[1], ".")
|
local propParts = string.split(propaccessPrefix[1], ".")
|
||||||
local current_value = _CTX._GLOBAL
|
local currentValue = _CTX._GLOBAL
|
||||||
local failed = false
|
local failed = false
|
||||||
for i = 1, #prop_parts-1 do
|
for i = 1, #propParts-1 do
|
||||||
local prop = prop_parts[i]
|
local prop = propParts[i]
|
||||||
if current_value then
|
if currentValue then
|
||||||
current_value = current_value[prop]
|
currentValue = currentValue[prop]
|
||||||
else
|
else
|
||||||
failed = true
|
failed = true
|
||||||
end
|
end
|
||||||
|
@ -71,13 +71,13 @@ event.listen {
|
||||||
if failed then
|
if failed then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local last_prop = prop_parts[#prop_parts]
|
local lastProp = propParts[#propParts]
|
||||||
if table.includes(LUA_KEYWORDS, last_prop) then
|
if table.includes(LUA_KEYWORDS, lastProp) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local options = {}
|
local options = {}
|
||||||
for key, val in pairs(current_value) do
|
for key, val in pairs(currentValue) do
|
||||||
if string.startswith(key, last_prop) and val then
|
if string.startswith(key, lastProp) and val then
|
||||||
if val.call then
|
if val.call then
|
||||||
-- We got a function
|
-- We got a function
|
||||||
if val.body then
|
if val.body then
|
||||||
|
@ -106,7 +106,7 @@ event.listen {
|
||||||
end
|
end
|
||||||
if #options > 0 then
|
if #options > 0 then
|
||||||
return {
|
return {
|
||||||
from = pos - string.len(last_prop),
|
from = pos - string.len(lastProp),
|
||||||
options = options
|
options = options
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -118,34 +118,33 @@ event.listen {
|
||||||
Various useful slash templates.
|
Various useful slash templates.
|
||||||
|
|
||||||
```space-lua
|
```space-lua
|
||||||
template.define_slash_command {
|
template.defineSlashCommand {
|
||||||
name = "function",
|
name = "function",
|
||||||
description = "Lua function",
|
description = "Lua function",
|
||||||
only_contexts = {"FencedCode:space-lua"},
|
onlyContexts = {"FencedCode:space-lua"},
|
||||||
template = template.new [==[function |^|()
|
template = template.new [==[function |^|()
|
||||||
end]==]
|
end]==]
|
||||||
}
|
}
|
||||||
|
|
||||||
template.define_slash_command {
|
template.defineSlashCommand {
|
||||||
name = "tpl",
|
name = "tpl",
|
||||||
description = "Lua template",
|
description = "Lua template",
|
||||||
only_contexts = {"FencedCode:space-lua"},
|
onlyContexts = {"FencedCode:space-lua"},
|
||||||
template = template.new "template.new[==[|^|]==]"
|
template = template.new "template.new[==[|^|]==]"
|
||||||
}
|
}
|
||||||
|
|
||||||
template.define_slash_command {
|
template.defineSlashCommand {
|
||||||
name = "lua-query",
|
name = "lua-query",
|
||||||
description = "Lua query",
|
description = "Lua query",
|
||||||
only_contexts = {"FencedCode:space-lua", "LuaDirective"},
|
onlyContexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||||
template = template.new 'query[[from index.tag "|^|"]]'
|
template = template.new 'query[[from index.tag "|^|"]]'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
-- A query embedded in ${}
|
-- A query embedded in ${}
|
||||||
template.define_slash_command {
|
template.defineSlashCommand {
|
||||||
name = "query",
|
name = "query",
|
||||||
description = "Lua query",
|
description = "Lua query",
|
||||||
except_contexts = {"FencedCode:space-lua", "LuaDirective"},
|
exceptContexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||||
template = function() return '${query[[from index.tag "|^|"]]}' end
|
template = function() return '${query[[from index.tag "|^|"]]}' end
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
|
@ -4,23 +4,23 @@ A work-in-progress library of generally useful templates for rendering queries.
|
||||||
|
|
||||||
```space-lua
|
```space-lua
|
||||||
-- Renders a page object as a linked list item
|
-- Renders a page object as a linked list item
|
||||||
templates.page_item = template.new([==[
|
templates.pageItem = template.new([==[
|
||||||
* [[${name}]]
|
* [[${name}]]
|
||||||
]==])
|
]==])
|
||||||
|
|
||||||
-- Renders a task object as a togglable task
|
-- Renders a task object as a togglable task
|
||||||
templates.task_item = template.new([==[
|
templates.taskItem = template.new([==[
|
||||||
* [${state}] [[${ref}]] ${name}
|
* [${state}] [[${ref}]] ${name}
|
||||||
]==])
|
]==])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
`template.page_item`:
|
`template.pageItem`:
|
||||||
${template.each(query[[from index.tag "page" limit 3]], templates.page_item)}
|
${template.each(query[[from index.tag "page" limit 3]], templates.pageItem)}
|
||||||
|
|
||||||
`template.task_item`:
|
`template.taskItem`:
|
||||||
* [ ] Task 1
|
* [ ] Task 1
|
||||||
* [ ] Task 2
|
* [ ] Task 2
|
||||||
|
|
||||||
${template.each(query[[from index.tag "task" where page == _CTX.currentPage.name]], templates.task_item)}
|
${template.each(query[[from index.tag "task" where page == _CTX.currentPage.name]], templates.taskItem)}
|
||||||
|
|
|
@ -20,42 +20,41 @@ function template.each(tbl, fn)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Creates a new template function from a string template
|
-- Creates a new template function from a string template
|
||||||
function template.new(template_str)
|
function template.new(templateStr)
|
||||||
-- Preprocess: strip indentation
|
-- Preprocess: strip indentation
|
||||||
local lines = {}
|
local lines = {}
|
||||||
local split_lines = string.split(template_str, "\n")
|
local splitLines = string.split(templateStr, "\n")
|
||||||
for _, line in ipairs(split_lines) do
|
for _, line in ipairs(splitLines) do
|
||||||
line = string.gsub(line, "^ ", "")
|
line = string.gsub(line, "^ ", "")
|
||||||
table.insert(lines, line)
|
table.insert(lines, line)
|
||||||
end
|
end
|
||||||
template_str = table.concat(lines, "\n")
|
templateStr = table.concat(lines, "\n")
|
||||||
return function(obj)
|
return function(obj)
|
||||||
return space_lua.interpolate(template_str, obj)
|
return spacelua.interpolate(templateStr, obj)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Creates a template-based slash command, keys for def are:
|
-- Creates a template-based slash command, keys for def are:
|
||||||
-- name: name of the slash command
|
-- name: name of the slash command
|
||||||
-- description: description of the slash command
|
-- description: description of the slash command
|
||||||
-- only_contexts: parent AST nodes in which this slash command is available, defaults to everywhere
|
-- onlyContexts: parent AST nodes in which this slash command is available, defaults to everywhere
|
||||||
-- except_contexts: parent AST nodes in which this slash command is not available
|
-- exceptContexts: parent AST nodes in which this slash command is not available
|
||||||
-- template: template function to apply
|
-- template: template function to apply
|
||||||
-- insert_at: position to insert the template into
|
-- insertAt: position to insert the template into
|
||||||
-- match: match string to apply the template to
|
-- match: match string to apply the template to
|
||||||
-- match_regex: match regex to apply the template to
|
-- matchRegex: match regex to apply the template to
|
||||||
function template.define_slash_command(def)
|
function template.defineSlashCommand(def)
|
||||||
slash_command.define {
|
slashcommand.define {
|
||||||
name = def.name,
|
name = def.name,
|
||||||
description = def.description,
|
description = def.description,
|
||||||
onlyContexts = def.only_contexts,
|
onlyContexts = def.onlyContexts,
|
||||||
exceptContexts = def.except_contexts,
|
exceptContexts = def.exceptContexts,
|
||||||
run = function()
|
run = function()
|
||||||
system.invoke_function("template.applySnippetTemplate", def.template(), {
|
system.invokeFunction("template.applySnippetTemplate", def.template(), {
|
||||||
insertAt = def.insert_at,
|
insertAt = def.insertAt,
|
||||||
match = def.match,
|
match = def.match,
|
||||||
matchRegex = def.match_regex
|
matchRegex = def.matchRegex
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
```
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ export function luaDirectivePlugin(client: Client) {
|
||||||
return result;
|
return result;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e instanceof LuaRuntimeError) {
|
if (e instanceof LuaRuntimeError) {
|
||||||
if (e.sf.astCtx) {
|
if (e.sf?.astCtx) {
|
||||||
const source = resolveASTReference(e.sf.astCtx);
|
const source = resolveASTReference(e.sf.astCtx);
|
||||||
if (source) {
|
if (source) {
|
||||||
// We know the origin node of the error, let's reference it
|
// We know the origin node of the error, let's reference it
|
||||||
|
|
|
@ -89,9 +89,9 @@ export class LuaWidget extends WidgetType {
|
||||||
html = widgetContent.html;
|
html = widgetContent.html;
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
if ((widgetContent as any)?.display === "block") {
|
if ((widgetContent as any)?.display === "block") {
|
||||||
div.className = "sb-lua-directive-block";
|
div.className += " sb-lua-directive-block";
|
||||||
} else {
|
} else {
|
||||||
div.className = "sb-lua-directive-inline";
|
div.className += " sb-lua-directive-inline";
|
||||||
}
|
}
|
||||||
attachWidgetEventHandlers(div, this.client, this.from);
|
attachWidgetEventHandlers(div, this.client, this.from);
|
||||||
this.client.setWidgetCache(
|
this.client.setWidgetCache(
|
||||||
|
|
|
@ -2,4 +2,4 @@ This describes the APIs available in [[Space Lua]]
|
||||||
|
|
||||||
${template.each(query[[
|
${template.each(query[[
|
||||||
from index.tag "page" where string.startswith(name, "API/")
|
from index.tag "page" where string.startswith(name, "API/")
|
||||||
]], templates.page_item)}
|
]], templates.pageItem)}
|
|
@ -1,6 +1,5 @@
|
||||||
The Client Store API provides a simple key-value store for client-specific states and preferences.
|
The Client Store API provides a simple key-value store for client-specific states and preferences.
|
||||||
|
|
||||||
|
|
||||||
## clientStore.set(key, value)
|
## clientStore.set(key, value)
|
||||||
Sets a value in the client store.
|
Sets a value in the client store.
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,24 @@
|
||||||
APIs related to editor commands
|
APIs related to editor commands
|
||||||
|
|
||||||
### command.define(command_def)
|
### command.define(commandDef)
|
||||||
Registers a command.
|
Registers a command.
|
||||||
|
|
||||||
|
Available keys:
|
||||||
|
|
||||||
|
* `name`: Name of the command
|
||||||
|
* `run`: Callback function
|
||||||
|
* `contexts`: AST node context in which this command should be available
|
||||||
|
* `priority`: Command priority (how high it appears in the list)
|
||||||
|
* `key`: Windows/Linux key binding (and mac, if not separately defined)
|
||||||
|
* `mac`: Mac-specific key binding
|
||||||
|
* `hide`: Hide this command from the [[Command Palette]]
|
||||||
|
* `requireMode`: `rw` or `ro` — only enable this command in a particular mode (read-write, or read-only)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
command.define {
|
command.define {
|
||||||
name = "My custom command",
|
name = "My custom command",
|
||||||
run = function()
|
run = function()
|
||||||
editor.flash_notification "Triggered my custom command"
|
editor.flashNotification "Triggered my custom command"
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
The Datastore API provides functions for interacting with a key-value store that has query capabilities.
|
The Datastore API provides functions for interacting with a key-value store that has query capabilities.
|
||||||
|
|
||||||
# Key-Value Operations
|
# Key-Value Operations
|
||||||
|
@ -30,7 +29,7 @@ datastore.del("user:123")
|
||||||
|
|
||||||
# Batch Operations
|
# Batch Operations
|
||||||
|
|
||||||
## datastore.batch_set(kvs)
|
## datastore.batchSet(kvs)
|
||||||
Sets multiple key-value pairs in a single operation.
|
Sets multiple key-value pairs in a single operation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -39,27 +38,25 @@ local kvs = {
|
||||||
{key = "user:1", value = {name = "Alice"}},
|
{key = "user:1", value = {name = "Alice"}},
|
||||||
{key = "user:2", value = {name = "Bob"}}
|
{key = "user:2", value = {name = "Bob"}}
|
||||||
}
|
}
|
||||||
datastore.batch_set(kvs)
|
datastore.batchSet(kvs)
|
||||||
```
|
```
|
||||||
|
|
||||||
## datastore.batch_get(keys)
|
## datastore.batchGet(keys)
|
||||||
Gets multiple values in a single operation.
|
Gets multiple values in a single operation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local keys = {"user:1", "user:2"}
|
local keys = {"user:1", "user:2"}
|
||||||
local values = datastore.batch_get(keys)
|
local values = datastore.batchGet(keys)
|
||||||
for _, value in ipairs(values) do
|
for _, value in ipairs(values) do
|
||||||
print(value.name)
|
print(value.name)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## datastore.batch_del(keys)
|
## datastore.batchDel(keys)
|
||||||
Deletes multiple values in a single operation.
|
Deletes multiple values in a single operation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local keys = {"user:1", "user:2"}
|
local keys = {"user:1", "user:2"}
|
||||||
datastore.batch_del(keys)
|
datastore.batchDel(keys)
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
The Debug API provides functions for debugging and resetting the application state.
|
The Debug API provides functions for debugging and resetting the application state.
|
||||||
|
|
||||||
## debug.reset_client()
|
## debug.resetClient()
|
||||||
Completely wipes the client state, including cached files and databases.
|
Completely wipes the client state, including cached files and databases.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
debug.reset_client()
|
debug.resetClient()
|
||||||
print("Client state has been reset")
|
print("Client state has been reset")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,4 +18,3 @@ Example:
|
||||||
```lua
|
```lua
|
||||||
debug.cleanup()
|
debug.cleanup()
|
||||||
print("All KV stores have been wiped")
|
print("All KV stores have been wiped")
|
||||||
```
|
|
|
@ -1,280 +1,192 @@
|
||||||
The `editor` API provides functions for interacting with the editor interface, including text manipulation, cursor control, and UI operations.
|
The Editor API provides functions for interacting with the editor interface.
|
||||||
|
|
||||||
## Page Operations
|
### editor.getCurrentPage()
|
||||||
|
|
||||||
### editor.get_current_page()
|
|
||||||
Returns the name of the page currently open in the editor.
|
Returns the name of the page currently open in the editor.
|
||||||
|
|
||||||
Example:
|
Example: ${editor.getCurrentPage()}
|
||||||
```lua
|
|
||||||
local page = editor.get_current_page()
|
|
||||||
print("Current page: " .. page)
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.get_current_page_meta()
|
### editor.getCurrentPageMeta()
|
||||||
Returns the meta data of the page currently open in the editor.
|
Returns the meta data of the page currently open in the editor.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
${editor.getCurrentPageMeta()}
|
||||||
local meta = editor.get_current_page_meta()
|
|
||||||
print("Last modified: " .. meta.last_modified)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Text Operations
|
### editor.getText()
|
||||||
|
|
||||||
### editor.get_text()
|
|
||||||
Returns the full text of the currently open page.
|
Returns the full text of the currently open page.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local text = editor.get_text()
|
local text = editor.getText()
|
||||||
print("Document length: " .. #text)
|
print("Document length: " .. #text)
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.set_text(text, isolate_history)
|
### editor.setText(text, isolateHistory)
|
||||||
Updates the editor text while preserving cursor location.
|
Updates the editor text while preserving cursor location.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local text = editor.get_text()
|
local text = editor.getText()
|
||||||
editor.set_text(text:upper(), false) -- Convert to uppercase
|
editor.setText(text:upper(), false) -- Convert to uppercase
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.insert_at_pos(text, pos)
|
### editor.insertAtPos(text, pos)
|
||||||
Insert text at the specified position.
|
Insert text at the specified position.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.insert_at_pos("Hello!", 0) -- Insert at beginning
|
editor.insertAtPos("Hello!", 0) -- Insert at beginning
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.replace_range(from, to, text)
|
### editor.replaceRange(from, to, text)
|
||||||
Replace text in the specified range.
|
Replace text in the specified range.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.replace_range(0, 5, "New text")
|
editor.replaceRange(0, 5, "New text")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.insert_at_cursor(text)
|
### editor.insertAtCursor(text, scrollIntoView?)
|
||||||
Insert text at the current cursor position.
|
Insert text at the current cursor position.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.insert_at_cursor("Inserted at cursor")
|
editor.insertAtCursor("Inserted at cursor")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cursor Control
|
### editor.getCursor()
|
||||||
|
|
||||||
### editor.get_cursor()
|
|
||||||
Returns the cursor position as character offset.
|
Returns the cursor position as character offset.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local pos = editor.get_cursor()
|
local pos = editor.getCursor()
|
||||||
print("Cursor at position: " .. pos)
|
print("Cursor at position: " .. pos)
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.get_selection()
|
### editor.getSelection()
|
||||||
Returns the current selection range.
|
Returns the current selection range.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local sel = editor.get_selection()
|
local sel = editor.getSelection()
|
||||||
print("Selection from " .. sel.from .. " to " .. sel.to)
|
print("Selection from " .. sel.from .. " to " .. sel.to)
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.set_selection(from, to)
|
### editor.setSelection(from, to)
|
||||||
Sets the current selection range.
|
Sets the current selection range.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.set_selection(0, 10) -- Select first 10 characters
|
editor.setSelection(0, 10) -- Select first 10 characters
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.move_cursor(pos, center)
|
### editor.moveCursor(pos, center)
|
||||||
Move the cursor to a specific position.
|
Move the cursor to a specific position.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.move_cursor(0, true) -- Move to start and center
|
editor.moveCursor(0, true) -- Move to start and center
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.move_cursor_to_line(line, column, center)
|
### editor.moveCursorToLine(line, column, center)
|
||||||
Move the cursor to a specific line and column.
|
Move the cursor to a specific line and column.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.move_cursor_to_line(1, 1, true) -- Move to start of first line
|
editor.moveCursorToLine(1, 1, true) -- Move to start of first line
|
||||||
```
|
```
|
||||||
|
|
||||||
## Navigation
|
### editor.openPageNavigator(mode)
|
||||||
|
|
||||||
### editor.navigate(page_ref, replace_state, new_window)
|
|
||||||
Navigates to the specified page.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
editor.navigate({page = "welcome"}, false, false)
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.open_page_navigator(mode)
|
|
||||||
Opens the page navigator.
|
Opens the page navigator.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.open_page_navigator("page")
|
editor.openPageNavigator("page")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.open_command_palette()
|
### editor.openCommandPalette()
|
||||||
Opens the command palette.
|
Opens the command palette.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.open_command_palette()
|
editor.openCommandPalette()
|
||||||
```
|
```
|
||||||
|
|
||||||
## UI Operations
|
### editor.showPanel(id, mode, html, script)
|
||||||
|
|
||||||
### editor.show_panel(id, mode, html, script)
|
|
||||||
Shows a panel in the editor.
|
Shows a panel in the editor.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.show_panel("rhs", 1, "<h1>Hello</h1>")
|
editor.showPanel("rhs", 1, "<h1>Hello</h1>")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.hide_panel(id)
|
### editor.hidePanel(id)
|
||||||
Hides a panel in the editor.
|
Hides a panel in the editor.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.hide_panel("rhs")
|
editor.hidePanel("rhs")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.flash_notification(message, type)
|
### editor.flashNotification(message, type)
|
||||||
Shows a flash notification.
|
Shows a flash notification.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.flash_notification("Operation completed", "info")
|
editor.flashNotification("Operation completed", "info")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.prompt(message, default_value)
|
### editor.downloadFile(filename, dataUrl)
|
||||||
Prompts the user for input.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
local name = editor.prompt("Enter your name:", "")
|
|
||||||
print("Hello, " .. name)
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.confirm(message)
|
|
||||||
Shows a confirmation dialog.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
if editor.confirm("Are you sure?") then
|
|
||||||
print("User confirmed")
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## File Operations
|
|
||||||
|
|
||||||
### editor.download_file(filename, data_url)
|
|
||||||
Triggers a file download in the browser.
|
Triggers a file download in the browser.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.download_file("test.txt", "data:text/plain;base64,SGVsbG8=")
|
editor.downloadFile("test.txt", "data:text/plain;base64,SGVsbG8=")
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.upload_file(accept, capture)
|
### editor.uploadFile(accept, capture)
|
||||||
Opens a file upload dialog.
|
Opens a file upload dialog.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local file = editor.upload_file(".txt", nil)
|
local file = editor.uploadFile(".txt", nil)
|
||||||
print("Uploaded: " .. file.name)
|
print("Uploaded: " .. file.name)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Clipboard Operations
|
### editor.copyToClipboard(data)
|
||||||
|
|
||||||
### editor.copy_to_clipboard(data)
|
|
||||||
Copies data to the clipboard.
|
Copies data to the clipboard.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.copy_to_clipboard("Copied text")
|
editor.copyToClipboard("Copied text")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Code Folding
|
### editor.toggleFold()
|
||||||
|
|
||||||
### editor.fold()
|
|
||||||
Folds code at the current cursor position.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
editor.fold()
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.unfold()
|
|
||||||
Unfolds code at the current cursor position.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
editor.unfold()
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.toggle_fold()
|
|
||||||
Toggles code folding at the current position.
|
Toggles code folding at the current position.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.toggle_fold()
|
editor.toggleFold()
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.fold_all()
|
### editor.foldAll()
|
||||||
Folds all foldable regions.
|
Folds all foldable regions.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.fold_all()
|
editor.foldAll()
|
||||||
```
|
```
|
||||||
|
|
||||||
### editor.unfold_all()
|
### editor.unfoldAll()
|
||||||
Unfolds all folded regions.
|
Unfolds all folded regions.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.unfold_all()
|
editor.unfoldAll()
|
||||||
```
|
```
|
||||||
|
|
||||||
## History Operations
|
### editor.openSearchPanel()
|
||||||
|
|
||||||
### editor.undo()
|
|
||||||
Undoes the last edit operation.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
editor.undo()
|
|
||||||
```
|
|
||||||
|
|
||||||
### editor.redo()
|
|
||||||
Redoes the last undone operation.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```lua
|
|
||||||
editor.redo()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Search Operations
|
|
||||||
|
|
||||||
### editor.open_search_panel()
|
|
||||||
Opens the editor's search panel.
|
Opens the editor's search panel.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
editor.open_search_panel()
|
editor.openSearchPanel()
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ The Event API provides functions for working with SilverBullet's event bus syste
|
||||||
|
|
||||||
## Event Operations
|
## Event Operations
|
||||||
|
|
||||||
### event.listen(listener_def)
|
### event.listen(listenerDef)
|
||||||
Register an event listener.
|
Register an event listener.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
@ -16,7 +16,7 @@ event.listen {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### event.dispatch(event_name, data, timeout)
|
### event.dispatch(eventName, data, timeout)
|
||||||
Triggers an event on the SilverBullet event bus. Event handlers can return values, which are accumulated and returned to the caller.
|
Triggers an event on the SilverBullet event bus. Event handlers can return values, which are accumulated and returned to the caller.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -25,19 +25,18 @@ Example:
|
||||||
event.dispatch("custom.event", {message = "Hello"})
|
event.dispatch("custom.event", {message = "Hello"})
|
||||||
|
|
||||||
-- Event dispatch with timeout and response handling
|
-- Event dispatch with timeout and response handling
|
||||||
local responses = event.dispatch_event("data.request", {id = 123}, 5000)
|
local responses = event.dispatchEvent("data.request", {id = 123}, 5000)
|
||||||
for _, response in ipairs(responses) do
|
for _, response in ipairs(responses) do
|
||||||
print(response)
|
print(response)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### event.list_events()
|
### event.listEvents()
|
||||||
Lists all events currently registered (listened to) on the SilverBullet event bus.
|
Lists all events currently registered (listened to) on the SilverBullet event bus.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local events = event.list_events()
|
local events = event.listEvents()
|
||||||
for _, event_name in ipairs(events) do
|
for _, eventName in ipairs(events) do
|
||||||
print("Registered event: " .. event_name)
|
print("Registered event: " .. eventName)
|
||||||
end
|
end
|
||||||
```
|
|
|
@ -9,7 +9,7 @@ Example:
|
||||||
|
|
||||||
${query[[from index.tag("page") limit 1]]}
|
${query[[from index.tag("page") limit 1]]}
|
||||||
|
|
||||||
## index.index_objects(page, objects)
|
## index.indexObjects(page, objects)
|
||||||
Indexes an array of objects for a specific page.
|
Indexes an array of objects for a specific page.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -18,24 +18,23 @@ local objects = {
|
||||||
{tag = "mytask", ref="task1", content = "Buy groceries"},
|
{tag = "mytask", ref="task1", content = "Buy groceries"},
|
||||||
{tag = "mytask", ref="task2", content = "Write docs"}
|
{tag = "mytask", ref="task2", content = "Write docs"}
|
||||||
}
|
}
|
||||||
index.index_objects("my page", objects)
|
index.indexObjects("my page", objects)
|
||||||
```
|
```
|
||||||
|
|
||||||
## index.query_lua_objects(tag, query, scoped_variables?)
|
## index.queryLuaObjects(tag, query, scopedVariables?)
|
||||||
Queries objects using a Lua-based collection query.
|
Queries objects using a Lua-based collection query.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local tasks = index.query_lua_objects("mytask", {limit=3})
|
local tasks = index.queryLuaObjects("mytask", {limit=3})
|
||||||
```
|
```
|
||||||
|
|
||||||
## index.get_object_by_ref(page, tag, ref)
|
## index.getObjectByRef(page, tag, ref)
|
||||||
Retrieves a specific object by its reference.
|
Retrieves a specific object by its reference.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local task = index.get_object_by_ref("my page", "mytask", "task1")
|
local task = index.getObjectByRef("my page", "mytask", "task1")
|
||||||
if task then
|
if task then
|
||||||
print("Found task: " .. task.content)
|
print("Found task: " .. task.content)
|
||||||
end
|
end
|
||||||
```
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ Imports a JavaScript module from a URL. Returns the imported module.
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
-- Import lodash library
|
-- Import lodash library
|
||||||
local lodash = js.import("https://esm.sh/lodash@4.17.21")
|
local lodashLib = js.import("https://esm.sh/lodash@4.17.21")
|
||||||
local result = lodash.chunk({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3)
|
local result = lodashLib.chunk({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3)
|
||||||
|
|
||||||
-- Import moment.js for date handling
|
-- Import moment.js for date handling
|
||||||
local moment = js.import("https://esm.sh/moment@2.30.1")
|
local momentLib = js.import("https://esm.sh/moment@2.30.1")
|
||||||
local day = moment("1995-12-25")
|
local dateObj = momentLib("1995-12-25")
|
||||||
print(day.format("DD-MM-YYYY")) -- prints: 25-12-1995
|
print(dateObj.format("DD-MM-YYYY")) -- prints: 25-12-1995
|
||||||
```
|
```
|
||||||
|
|
||||||
## js.new(constructor, ...)
|
## js.new(constructor, ...)
|
||||||
|
@ -20,8 +20,8 @@ Creates a new instance of a JavaScript class. Takes a constructor function and i
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local Date = js.import("https://esm.sh/date-fns")
|
local DateClass = js.import("https://esm.sh/date-fns")
|
||||||
local date = js.new(Date, "2024-03-14")
|
local dateObj = js.new(DateClass, "2024-03-14")
|
||||||
```
|
```
|
||||||
|
|
||||||
## js.stringify(value)
|
## js.stringify(value)
|
||||||
|
@ -29,11 +29,11 @@ Converts a Lua value to a JSON string representation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local data = {1, 2, 3}
|
local dataArray = {1, 2, 3}
|
||||||
print(js.stringify(data)) -- prints: [1,2,3]
|
print(js.stringify(dataArray)) -- prints: [1,2,3]
|
||||||
|
|
||||||
local nested = lodash.chunk({1, 2, 3, 4, 5, 6}, 2)
|
local nestedArray = lodashLib.chunk({1, 2, 3, 4, 5, 6}, 2)
|
||||||
print(js.stringify(nested)) -- prints: [[1,2],[3,4],[5,6]]
|
print(js.stringify(nestedArray)) -- prints: [[1,2],[3,4],[5,6]]
|
||||||
```
|
```
|
||||||
|
|
||||||
## js.tolua(value)
|
## js.tolua(value)
|
||||||
|
@ -63,13 +63,12 @@ js.log("Debug message")
|
||||||
js.log("User data:", {name = "John", age = 30})
|
js.log("User data:", {name = "John", age = 30})
|
||||||
```
|
```
|
||||||
|
|
||||||
## js.each_iterable(iterable)
|
## js.eachIterable(iterable)
|
||||||
Creates an iterator for JavaScript async iterables.
|
Creates an iterator for JavaScript async iterables.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local async_iterator = js.each_iterable(some_js_async_iterable)
|
local asyncIterator = js.eachIterable(someJsAsyncIterable)
|
||||||
for value in async_iterator do
|
for value in asyncIterator do
|
||||||
print(value)
|
print(value)
|
||||||
end
|
end
|
||||||
```
|
|
|
@ -4,7 +4,7 @@ The JSON Schema API provides functions for validating JSON objects against JSON
|
||||||
|
|
||||||
## Validation Operations
|
## Validation Operations
|
||||||
|
|
||||||
### jsonschema.validate_object(schema, object)
|
### jsonschema.validateObject(schema, object)
|
||||||
Validates a JSON object against a JSON schema.
|
Validates a JSON object against a JSON schema.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -19,7 +19,7 @@ local schema = {
|
||||||
}
|
}
|
||||||
|
|
||||||
local object = {name = "John", age = 30}
|
local object = {name = "John", age = 30}
|
||||||
local error = jsonschema.validate_object(schema, object)
|
local error = jsonschema.validateObject(schema, object)
|
||||||
if error then
|
if error then
|
||||||
print("Validation error: " .. error)
|
print("Validation error: " .. error)
|
||||||
else
|
else
|
||||||
|
@ -27,7 +27,7 @@ else
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### jsonschema.validate_schema(schema)
|
### jsonschema.validateSchema(schema)
|
||||||
Validates a JSON schema itself to ensure it's well-formed.
|
Validates a JSON schema itself to ensure it's well-formed.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -39,10 +39,9 @@ local schema = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local error = jsonschema.validate_schema(schema)
|
local error = jsonschema.validateSchema(schema)
|
||||||
if error then
|
if error then
|
||||||
print("Schema error: " .. error)
|
print("Schema error: " .. error)
|
||||||
else
|
else
|
||||||
print("Schema is valid")
|
print("Schema is valid")
|
||||||
end
|
end
|
||||||
```
|
|
|
@ -2,7 +2,7 @@ The Language API provides functions for parsing code in various programming lang
|
||||||
|
|
||||||
## Language Operations
|
## Language Operations
|
||||||
|
|
||||||
### language.parse_language(language, code)
|
### language.parseLanguage(language, code)
|
||||||
Parses a piece of code using any of the supported SilverBullet languages.
|
Parses a piece of code using any of the supported SilverBullet languages.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -13,7 +13,7 @@ function hello() {
|
||||||
}
|
}
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local tree = language.parse_language("javascript", [[
|
local tree = language.parseLanguage("javascript", [[
|
||||||
function hello() {
|
function hello() {
|
||||||
console.log("Hello, world!");
|
console.log("Hello, world!");
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ function hello() {
|
||||||
print("Parsed syntax tree:", tree)
|
print("Parsed syntax tree:", tree)
|
||||||
```
|
```
|
||||||
|
|
||||||
### language.list_languages()
|
### language.listLanguages()
|
||||||
Lists all supported languages in fenced code blocks.
|
Lists all supported languages in fenced code blocks.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
${language.list_languages()}
|
${language.listLanguages()}
|
||||||
|
|
|
@ -4,7 +4,7 @@ The Markdown API provides functions for parsing and rendering Markdown content.
|
||||||
|
|
||||||
## Markdown Operations
|
## Markdown Operations
|
||||||
|
|
||||||
### markdown.parse_markdown(text)
|
### markdown.parseMarkdown(text)
|
||||||
Parses a piece of markdown text into a ParseTree.
|
Parses a piece of markdown text into a ParseTree.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -15,18 +15,17 @@ local text = [[
|
||||||
This is a **bold** statement.
|
This is a **bold** statement.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local tree = markdown.parse_markdown(text)
|
local tree = markdown.parseMarkdown(text)
|
||||||
print("Parsed markdown tree:", tree)
|
print("Parsed markdown tree:", tree)
|
||||||
```
|
```
|
||||||
|
|
||||||
### markdown.render_parse_tree(tree)
|
### markdown.renderParseTree(tree)
|
||||||
Renders a ParseTree back to markdown text.
|
Renders a ParseTree back to markdown text.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local text = "# Title\n\nSome text"
|
local text = "# Title\n\nSome text"
|
||||||
local tree = markdown.parse_markdown(text)
|
local tree = markdown.parseMarkdown(text)
|
||||||
-- Modify tree if needed
|
-- Modify tree if needed
|
||||||
local rendered = markdown.render_parse_tree(tree)
|
local rendered = markdown.renderParseTree(tree)
|
||||||
print("Rendered markdown:", rendered)
|
print("Rendered markdown:", rendered)
|
||||||
```
|
|
|
@ -12,7 +12,7 @@ Example:
|
||||||
mq.send("tasks", {type = "process", data = "sample"})
|
mq.send("tasks", {type = "process", data = "sample"})
|
||||||
```
|
```
|
||||||
|
|
||||||
### mq.batch_send(queue, bodies)
|
### mq.batchSend(queue, bodies)
|
||||||
Sends multiple messages to a queue in a single operation.
|
Sends multiple messages to a queue in a single operation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -21,7 +21,7 @@ local messages = {
|
||||||
{type = "task1", data = "sample1"},
|
{type = "task1", data = "sample1"},
|
||||||
{type = "task2", data = "sample2"}
|
{type = "task2", data = "sample2"}
|
||||||
}
|
}
|
||||||
mq.batch_send("tasks", messages)
|
mq.batchSend("tasks", messages)
|
||||||
```
|
```
|
||||||
|
|
||||||
### mq.ack(queue, id)
|
### mq.ack(queue, id)
|
||||||
|
@ -32,23 +32,22 @@ Example:
|
||||||
mq.ack("tasks", "message-123")
|
mq.ack("tasks", "message-123")
|
||||||
```
|
```
|
||||||
|
|
||||||
### mq.batch_ack(queue, ids)
|
### mq.batchAck(queue, ids)
|
||||||
Acknowledges multiple messages from a queue in a single operation.
|
Acknowledges multiple messages from a queue in a single operation.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local messageIds = {"msg1", "msg2", "msg3"}
|
local messageIds = {"msg1", "msg2", "msg3"}
|
||||||
mq.batch_ack("tasks", messageIds)
|
mq.batchAck("tasks", messageIds)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Queue Management
|
## Queue Management
|
||||||
|
|
||||||
### mq.get_queue_stats(queue)
|
### mq.getQueueStats(queue)
|
||||||
Retrieves statistics about a particular queue.
|
Retrieves statistics about a particular queue.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local stats = mq.get_queue_stats("tasks")
|
local stats = mq.getQueueStats("tasks")
|
||||||
print("Queue size: " .. stats.size)
|
print("Queue size: " .. stats.size)
|
||||||
print("Processing: " .. stats.processing)
|
print("Processing: " .. stats.processing)
|
||||||
```
|
|
|
@ -2,149 +2,148 @@ The Space API provides functions for interacting with pages, attachments, and fi
|
||||||
|
|
||||||
# Page Operations
|
# Page Operations
|
||||||
|
|
||||||
## space.list_pages()
|
## space.listPages()
|
||||||
Returns a list of all pages in the space.
|
Returns a list of all pages in the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local pages = space.list_pages()
|
local pages = space.listPages()
|
||||||
for page in each(pages) do
|
for page in each(pages) do
|
||||||
print(page.name)
|
print(page.name)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.read_page(name)
|
## space.readPage(name)
|
||||||
Reads the content of a page.
|
Reads the content of a page.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local content = space.read_page("welcome")
|
local content = space.readPage("welcome")
|
||||||
print(content) -- prints the content of the "welcome" page
|
print(content) -- prints the content of the "welcome" page
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.get_page_meta(name)
|
## space.getPageMeta(name)
|
||||||
Gets metadata for a specific page.
|
Gets metadata for a specific page.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local meta = space.get_page_meta("welcome")
|
local meta = space.getPageMeta("welcome")
|
||||||
print(meta.name, meta.lastModified) -- prints page name and last modified date
|
print(meta.name, meta.lastModified) -- prints page name and last modified date
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.write_page(name, text)
|
## space.writePage(name, text)
|
||||||
Writes content to a page.
|
Writes content to a page.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local meta = space.write_page("notes", "My new note content")
|
local meta = space.writePage("notes", "My new note content")
|
||||||
print("Page updated at: " .. meta.lastModified)
|
print("Page updated at: " .. meta.lastModified)
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.delete_page(name)
|
## space.deletePage(name)
|
||||||
Deletes a page from the space.
|
Deletes a page from the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
space.delete_page("old-notes")
|
space.deletePage("old-notes")
|
||||||
```
|
```
|
||||||
|
|
||||||
# Attachment Operations
|
# Attachment Operations
|
||||||
|
|
||||||
## space.list_attachments()
|
## space.listAttachments()
|
||||||
Returns a list of all attachments in the space.
|
Returns a list of all attachments in the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local attachments = space.list_attachments()
|
local attachments = space.listAttachments()
|
||||||
for att in each(attachments) do
|
for att in each(attachments) do
|
||||||
print(att.name, att.size)
|
print(att.name, att.size)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.read_attachment(name)
|
## space.readAttachment(name)
|
||||||
Reads the content of an attachment.
|
Reads the content of an attachment.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local data = space.read_attachment("image.png")
|
local data = space.readAttachment("image.png")
|
||||||
print("Attachment size: " .. #data .. " bytes")
|
print("Attachment size: " .. #data .. " bytes")
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.write_attachment(name, data)
|
## space.writeAttachment(name, data)
|
||||||
Writes binary data to an attachment.
|
Writes binary data to an attachment.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local binary_data = string.char(72, 69, 76, 76, 79) -- "HELLO" in binary
|
local binaryData = string.char(72, 69, 76, 76, 79) -- "HELLO" in binary
|
||||||
local meta = space.write_attachment("test.bin", binary_data)
|
local meta = space.writeAttachment("test.bin", binaryData)
|
||||||
print("Attachment saved with size: " .. meta.size)
|
print("Attachment saved with size: " .. meta.size)
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.delete_attachment(name)
|
## space.deleteAttachment(name)
|
||||||
Deletes an attachment from the space.
|
Deletes an attachment from the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
space.delete_attachment("old-image.png")
|
space.deleteAttachment("old-image.png")
|
||||||
```
|
```
|
||||||
|
|
||||||
# File Operations
|
# File Operations
|
||||||
|
|
||||||
## space.list_files()
|
## space.listFiles()
|
||||||
Returns a list of all files in the space.
|
Returns a list of all files in the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local files = space.list_files()
|
local files = space.listFiles()
|
||||||
for _, file in ipairs(files) do
|
for _, file in ipairs(files) do
|
||||||
print(file.name, file.size)
|
print(file.name, file.size)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.get_file_meta(name)
|
## space.getFileMeta(name)
|
||||||
Gets metadata for a specific file.
|
Gets metadata for a specific file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local meta = space.get_file_meta("document.txt")
|
local meta = space.getFileMeta("document.txt")
|
||||||
print(meta.name, meta.modified, meta.size)
|
print(meta.name, meta.modified, meta.size)
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.read_file(name)
|
## space.readFile(name)
|
||||||
Reads the content of a file.
|
Reads the content of a file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local content = space.read_file("document.txt")
|
local content = space.readFile("document.txt")
|
||||||
print("File size: " .. #content .. " bytes")
|
print("File size: " .. #content .. " bytes")
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.write_file(name, data)
|
## space.writeFile(name, data)
|
||||||
Writes binary data to a file.
|
Writes binary data to a file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local text = "Hello, World!"
|
local text = "Hello, World!"
|
||||||
local meta = space.write_file("greeting.txt", text)
|
local meta = space.writeFile("greeting.txt", text)
|
||||||
print("File written with size: " .. meta.size)
|
print("File written with size: " .. meta.size)
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.delete_file(name)
|
## space.deleteFile(name)
|
||||||
Deletes a file from the space.
|
Deletes a file from the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
space.delete_file("old-document.txt")
|
space.deleteFile("old-document.txt")
|
||||||
```
|
```
|
||||||
|
|
||||||
## space.file_exists(name)
|
## space.fileExists(name)
|
||||||
Checks if a file exists in the space.
|
Checks if a file exists in the space.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
if space.file_exists("config.json") then
|
if space.fileExists("config.json") then
|
||||||
print("Config file exists!")
|
print("Config file exists!")
|
||||||
else
|
else
|
||||||
print("Config file not found")
|
print("Config file not found")
|
||||||
end
|
end
|
||||||
```
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
Space Lua specific functions that are available to all scripts, but are not part of the standard Lua language.
|
|
||||||
|
|
||||||
## space_lua.parse_expression(luaExpression)
|
|
||||||
Parses a lua expression and returns the parsed expression as an AST.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
space_lua.parse_expression("1 + 1")
|
|
||||||
|
|
||||||
|
|
||||||
## space_lua.eval_expression(parsedExpr, envAugmentation?)
|
|
||||||
Evaluates a parsed Lua expression and returns the result. Optionally accepts an environment table to augment the global environment.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
${space_lua.eval_expression(space_lua.parse_expression("x + y"), {x = 1, y = 2})}
|
|
||||||
|
|
||||||
## space_lua.interpolate(template, envAugmentation?)
|
|
||||||
Interpolates a string with lua expressions and returns the result. Expressions are wrapped in ${...} syntax. Optionally accepts an environment table to augment the global environment.
|
|
||||||
|
|
||||||
${space_lua.interpolate("Hello ${name}!", {name="Pete"})}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
The Space Lua API provides functions for working with Lua expressions and templates.
|
||||||
|
|
||||||
|
## spacelua.parseExpression(luaExpression)
|
||||||
|
Parses a lua expression and returns the parsed expression as an AST.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```lua
|
||||||
|
local parsedExpression = spacelua.parseExpression("1 + 1")
|
||||||
|
```
|
||||||
|
|
||||||
|
## spacelua.evalExpression(parsedExpr, envAugmentation?)
|
||||||
|
Evaluates a parsed Lua expression and returns the result. Optionally accepts an environment table to augment the global environment.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
${spacelua.evalExpression(spacelua.parseExpression("x + y"), {x = 1, y = 2})}
|
||||||
|
|
||||||
|
## spacelua.interpolate(template, envAugmentation?)
|
||||||
|
Interpolates a string with lua expressions and returns the result. Expressions are wrapped in ${...} syntax. Optionally accepts an environment table to augment the global environment.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
${spacelua.interpolate("Hello ${name}!", {name="Pete"})}
|
|
@ -4,41 +4,40 @@ The Sync API provides functions for interacting with the sync engine when the cl
|
||||||
|
|
||||||
## Sync Operations
|
## Sync Operations
|
||||||
|
|
||||||
### sync.is_syncing()
|
### sync.isSyncing()
|
||||||
Checks if a sync is currently in progress.
|
Checks if a sync is currently in progress.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
if sync.is_syncing() then
|
if sync.isSyncing() then
|
||||||
print("Sync in progress...")
|
print("Sync in progress...")
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### sync.has_initial_sync_completed()
|
### sync.hasInitialSyncCompleted()
|
||||||
Checks if an initial sync has completed.
|
Checks if an initial sync has completed.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
if sync.has_initial_sync_completed() then
|
if sync.hasInitialSyncCompleted() then
|
||||||
print("Initial sync completed")
|
print("Initial sync completed")
|
||||||
else
|
else
|
||||||
print("Waiting for initial sync...")
|
print("Waiting for initial sync...")
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### sync.schedule_file_sync(path)
|
### sync.scheduleFileSync(path)
|
||||||
Actively schedules a file to be synced. Sync will happen by default too, but this prioritizes the file.
|
Actively schedules a file to be synced. Sync will happen by default too, but this prioritizes the file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
sync.schedule_file_sync("notes/important.md")
|
sync.scheduleFileSync("notes/important.md")
|
||||||
```
|
```
|
||||||
|
|
||||||
### sync.schedule_space_sync()
|
### sync.scheduleSpaceSync()
|
||||||
Schedules a sync without waiting for the usual sync interval.
|
Schedules a sync without waiting for the usual sync interval.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local changes = sync.schedule_space_sync()
|
local changes = sync.scheduleSpaceSync()
|
||||||
print("Number of changes synced: " .. changes)
|
print("Number of changes synced: " .. changes)
|
||||||
```
|
|
|
@ -4,114 +4,113 @@ The System API provides system-level functions for interacting with the SilverBu
|
||||||
|
|
||||||
## Function Operations
|
## Function Operations
|
||||||
|
|
||||||
### system.invoke_function(name, ...)
|
### system.invokeFunction(name, ...)
|
||||||
Invokes a plug function by name.
|
Invokes a plug function by name.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
-- Invoke a function from a plug
|
-- Invoke a function from a plug
|
||||||
system.invoke_function("myplug.process_data", "input", 123)
|
system.invokeFunction("myplug.processData", "input", 123)
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.invoke_command(name, args)
|
### system.invokeCommand(name, args)
|
||||||
Invokes a client command by name.
|
Invokes a client command by name.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
system.invoke_command("editor.save", {})
|
system.invokeCommand("editor.save", {})
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.invoke_space_function(name, ...)
|
### system.invokeSpaceFunction(name, ...)
|
||||||
Invokes a space function by name.
|
Invokes a space function by name.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local result = system.invoke_space_function("custom_function", "arg1", "arg2")
|
local result = system.invokeSpaceFunction("customFunction", "arg1", "arg2")
|
||||||
print("Function result:", result)
|
print("Function result:", result)
|
||||||
```
|
```
|
||||||
|
|
||||||
## System Information
|
## System Information
|
||||||
|
|
||||||
### system.list_commands()
|
### system.listCommands()
|
||||||
Lists all available commands.
|
Lists all available commands.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local commands = system.list_commands()
|
local commands = system.listCommands()
|
||||||
for name, def in pairs(commands) do
|
for name, def in pairs(commands) do
|
||||||
print(name .. ": " .. def.description)
|
print(name .. ": " .. def.description)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.list_syscalls()
|
### system.listSyscalls()
|
||||||
Lists all available syscalls.
|
Lists all available syscalls.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local syscalls = system.list_syscalls()
|
local syscalls = system.listSyscalls()
|
||||||
for _, syscall in ipairs(syscalls) do
|
for _, syscall in ipairs(syscalls) do
|
||||||
print(syscall.name)
|
print(syscall.name)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.get_env()
|
### system.getEnv()
|
||||||
Returns the runtime environment ("server", "client", or undefined for hybrid).
|
Returns the runtime environment ("server", "client", or undefined for hybrid).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local env = system.get_env()
|
local env = system.getEnv()
|
||||||
print("Running in environment: " .. (env or "hybrid"))
|
print("Running in environment: " .. (env or "hybrid"))
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.get_mode()
|
### system.getMode()
|
||||||
Returns the current mode of the system ("ro" or "rw").
|
Returns the current mode of the system ("ro" or "rw").
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local mode = system.get_mode()
|
local mode = system.getMode()
|
||||||
print("System mode: " .. mode)
|
print("System mode: " .. mode)
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.get_version()
|
### system.getVersion()
|
||||||
Returns the SilverBullet version.
|
Returns the SilverBullet version.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local version = system.get_version()
|
local version = system.getVersion()
|
||||||
print("SilverBullet version: " .. version)
|
print("SilverBullet version: " .. version)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### system.get_space_config(key, default_value)
|
### system.getSpaceConfig(key, defaultValue)
|
||||||
Loads space configuration values.
|
Loads space configuration values.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
-- Get specific config value
|
-- Get specific config value
|
||||||
local value = system.get_space_config("theme", "light")
|
local value = system.getSpaceConfig("theme", "light")
|
||||||
|
|
||||||
-- Get all config values
|
-- Get all config values
|
||||||
local config = system.get_space_config()
|
local config = system.getSpaceConfig()
|
||||||
for key, value in pairs(config) do
|
for key, value in pairs(config) do
|
||||||
print(key .. ": " .. value)
|
print(key .. ": " .. value)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.reload_config()
|
### system.reloadConfig()
|
||||||
Triggers an explicit reload of the configuration.
|
Triggers an explicit reload of the configuration.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
local new_config = system.reload_config()
|
system.reloadConfig()
|
||||||
print("Configuration reloaded")
|
print("Configuration reloaded")
|
||||||
```
|
```
|
||||||
|
|
||||||
### system.reload_plugs()
|
### system.reloadPlugs()
|
||||||
Triggers a reload of all plugs.
|
Triggers a reload of all plugs.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```lua
|
```lua
|
||||||
system.reload_plugs()
|
system.reloadPlugs()
|
||||||
print("All plugs reloaded")
|
print("All plugs reloaded")
|
||||||
```
|
|
|
@ -8,10 +8,10 @@ Example:
|
||||||
```space-lua
|
```space-lua
|
||||||
examples = examples or {}
|
examples = examples or {}
|
||||||
|
|
||||||
examples.say_hello = template.new[==[Hello ${name}!]==]
|
examples.sayHello = template.new[==[Hello ${name}!]==]
|
||||||
```
|
```
|
||||||
|
|
||||||
And its use: ${examples.say_hello {name="Pete"}}
|
And its use: ${examples.sayHello {name="Pete"}}
|
||||||
|
|
||||||
## template.each(collection, template)
|
## template.each(collection, template)
|
||||||
Iterates over a collection and renders a template for each item.
|
Iterates over a collection and renders a template for each item.
|
||||||
|
|
|
@ -29,6 +29,6 @@ local data = {
|
||||||
hobbies = {"reading", "hiking"}
|
hobbies = {"reading", "hiking"}
|
||||||
}
|
}
|
||||||
|
|
||||||
local yaml_text = yaml.stringify(data)
|
local yamlText = yaml.stringify(data)
|
||||||
print(yaml_text)
|
print(yamlText)
|
||||||
```
|
```
|
|
@ -5,6 +5,7 @@ An attempt at documenting the changes/new features introduced in each release.
|
||||||
## Edge
|
## Edge
|
||||||
_These features are not yet properly released, you need to use [the edge builds](https://community.silverbullet.md/t/living-on-the-edge-builds/27) to try them._
|
_These features are not yet properly released, you need to use [the edge builds](https://community.silverbullet.md/t/living-on-the-edge-builds/27) to try them._
|
||||||
|
|
||||||
|
* **Lua Breaking change**: Converted all custom (non-standard) Lua APIs from snake_case to camelCase. This will likely result in a lot of `calling nil as function` style errors, but it's a necessary step to make the API more consistent and easier to use. Also, error reporting should now be better, and often directly navigate to the place in the code where the error occurred.
|
||||||
* (Security) Implemented a lockout mechanism after a number of failed login attempts for [[Authentication]] (configured via [[Install/Configuration#Authentication]]) (by [Peter Weston](https://github.com/silverbulletmd/silverbullet/pull/1152))
|
* (Security) Implemented a lockout mechanism after a number of failed login attempts for [[Authentication]] (configured via [[Install/Configuration#Authentication]]) (by [Peter Weston](https://github.com/silverbulletmd/silverbullet/pull/1152))
|
||||||
|
|
||||||
## 0.10.1
|
## 0.10.1
|
||||||
|
@ -405,4 +406,3 @@ Other notable changes:
|
||||||
* [BLOCKED] A task that’s blocked
|
* [BLOCKED] A task that’s blocked
|
||||||
[[Plugs/Tasks|Read more]]
|
[[Plugs/Tasks|Read more]]
|
||||||
* Removed [[Cloud Links]] support in favor of [[Federation]]. If you still have legacy cloud links, simply replace the 🌩️ with a `!` and things should work as before.
|
* Removed [[Cloud Links]] support in favor of [[Federation]]. If you still have legacy cloud links, simply replace the 🌩️ with a `!` and things should work as before.
|
||||||
|
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
#meta
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
Create a [[SECRETS]] page in your space, with a YAML block:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
OPENAI_API_KEY: yourapikeyhere
|
|
||||||
```
|
|
||||||
|
|
||||||
# Implementation
|
|
||||||
```space-lua
|
|
||||||
openai = {
|
|
||||||
Client = {}
|
|
||||||
}
|
|
||||||
openai.Client.__index = openai.Client
|
|
||||||
|
|
||||||
-- Create a new OpenAI client instance
|
|
||||||
function openai.Client.new(apiKey)
|
|
||||||
-- Read SECRETS if no API key provided
|
|
||||||
if not apiKey then
|
|
||||||
local secretsPage = space.readPage("SECRETS")
|
|
||||||
apiKey = string.match(secretsPage, "OPENAI_API_KEY: (%S+)")
|
|
||||||
end
|
|
||||||
if not apiKey then
|
|
||||||
error("No OpenAI API key supplied")
|
|
||||||
end
|
|
||||||
|
|
||||||
local openai_lib = js.import("https://esm.sh/openai")
|
|
||||||
local client = js.new(openai_lib.OpenAI, {
|
|
||||||
apiKey = apiKey,
|
|
||||||
dangerouslyAllowBrowser = true
|
|
||||||
})
|
|
||||||
|
|
||||||
local self = setmetatable({
|
|
||||||
client = client
|
|
||||||
}, OpenAIClient)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Chat completion method
|
|
||||||
function openai.Client:chat(message)
|
|
||||||
local r = self.client.chat.completions.create({
|
|
||||||
model = "gpt-4o-mini",
|
|
||||||
messages = {
|
|
||||||
{ role = "user", content = message },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return r.choices[1].message.content
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Streaming chat completion method
|
|
||||||
function openai.Client:stream_chat(message)
|
|
||||||
local r = self.client.chat.completions.create({
|
|
||||||
model = "gpt-4o-mini",
|
|
||||||
messages = {
|
|
||||||
{ role = "user", content = message },
|
|
||||||
},
|
|
||||||
stream = true,
|
|
||||||
})
|
|
||||||
local iterator = js.each_iterable(r)
|
|
||||||
return function()
|
|
||||||
local el = iterator()
|
|
||||||
if el then
|
|
||||||
return el.choices[1].delta.content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
```
|
|
|
@ -12,7 +12,7 @@ The introduction of Lua aims to unify and simplify a few SilverBullet features,
|
||||||
* Replace [[Expression Language]], [[Template Language]] and [[Query Language]] with Lua-based equivalents.
|
* Replace [[Expression Language]], [[Template Language]] and [[Query Language]] with Lua-based equivalents.
|
||||||
* (Potentially) provide an alternative way to specify [[Space Config]]
|
* (Potentially) provide an alternative way to specify [[Space Config]]
|
||||||
|
|
||||||
# Introduction approach
|
# Strategy
|
||||||
This is a big effort. During its development, Space Lua will be offered as a kind of “alternative universe” to the things mentioned above. Existing [[Live Templates]], [[Live Queries]] and [[Space Script]] will continue to work as before, unaltered.
|
This is a big effort. During its development, Space Lua will be offered as a kind of “alternative universe” to the things mentioned above. Existing [[Live Templates]], [[Live Queries]] and [[Space Script]] will continue to work as before, unaltered.
|
||||||
|
|
||||||
Once these features stabilize and best practices are ironed out, old mechanisms will likely be deprecated and possibly removed at some point.
|
Once these features stabilize and best practices are ironed out, old mechanisms will likely be deprecated and possibly removed at some point.
|
||||||
|
@ -101,13 +101,13 @@ ${marquee "Finally, marqeeeeeeee!"}
|
||||||
Oh boy, the times we live in!
|
Oh boy, the times we live in!
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
Custom commands can be defined using `command.define`:
|
Custom commands can be defined using [[API/command#command.define(commandDef)]]:
|
||||||
|
|
||||||
```space-lua
|
```space-lua
|
||||||
command.define {
|
command.define {
|
||||||
name = "Hello World",
|
name = "Hello World",
|
||||||
run = function()
|
run = function()
|
||||||
editor.flash_notification "Hello world!"
|
editor.flashNotification "Hello world!"
|
||||||
event.dispatch("my-custom-event", {name="Pete"})
|
event.dispatch("my-custom-event", {name="Pete"})
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
@ -116,13 +116,13 @@ command.define {
|
||||||
Try it: {[Hello World]}
|
Try it: {[Hello World]}
|
||||||
|
|
||||||
## Event listeners
|
## Event listeners
|
||||||
You can listen to events using `event.listen`:
|
You can listen to events using [[API/event#event.listen(listenerDef)]]:
|
||||||
|
|
||||||
```space-lua
|
```space-lua
|
||||||
event.listen {
|
event.listen {
|
||||||
name = "my-custom-event";
|
name = "my-custom-event";
|
||||||
run = function(e)
|
run = function(e)
|
||||||
editor.flash_notification("Custom triggered: "
|
editor.flashNotification("Custom triggered: "
|
||||||
.. e.data.name)
|
.. e.data.name)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
@ -135,64 +135,20 @@ Space Lua currently introduces a few new features on top core Lua:
|
||||||
2. Thread locals
|
2. Thread locals
|
||||||
|
|
||||||
## Thread locals
|
## Thread locals
|
||||||
There’s a magic `_CTX` global variable available from which you can access useful context-specific values. Currently the following keys are available:
|
There's a magic `_CTX` global variable available from which you can access useful context-specific values. Currently the following keys are available:
|
||||||
|
|
||||||
* `_CTX.currentPage` providing access (in the client only) to the currently open page (PageMeta object)
|
* `_CTX.currentPage` providing access (in the client only) to the currently open page (PageMeta object)
|
||||||
* `_CTX._GLOBAL` providing access to the global scope
|
* `_CTX._GLOBAL` providing access to the global scope
|
||||||
|
|
||||||
# API
|
# API
|
||||||
Lua APIs, which should be (roughly) implemented according to the Lua standard.
|
All of these are available via the global namespace:
|
||||||
* `print`
|
${template.each(query[[from index.tag "page" where string.startswith(name, "API/")]], templates.pageItem)}
|
||||||
* `assert`
|
|
||||||
* `ipairs`
|
|
||||||
* `pairs`
|
|
||||||
* `unpack`
|
|
||||||
* `type`
|
|
||||||
* `tostring`
|
|
||||||
* `tonumber`
|
|
||||||
* `error`
|
|
||||||
* `pcall`
|
|
||||||
* `xpcall`
|
|
||||||
* `setmetatable`
|
|
||||||
* `getmetatable`
|
|
||||||
* `rawset`
|
|
||||||
* `string`:
|
|
||||||
* `byte`
|
|
||||||
* `char`
|
|
||||||
* `find`
|
|
||||||
* `format`
|
|
||||||
* `gmatch`
|
|
||||||
* `gsub`
|
|
||||||
* `len`
|
|
||||||
* `lower`
|
|
||||||
* `upper`
|
|
||||||
* `match`
|
|
||||||
* `rep`
|
|
||||||
* `reverse`
|
|
||||||
* `sub`
|
|
||||||
* `split`
|
|
||||||
* `table`
|
|
||||||
* `concat`
|
|
||||||
* `insert`
|
|
||||||
* `remove`
|
|
||||||
* `sort`
|
|
||||||
* `os`
|
|
||||||
* `time`
|
|
||||||
* `date`
|
|
||||||
* `js` (Warning: this will be revised): JavaScript interop functions
|
|
||||||
* `new`: instantiate a JavaScript constructor
|
|
||||||
* `importModule`: import a JavaScript from a URL (`import` equivalent)
|
|
||||||
* `tolua`: convert a JS value to a Lua value
|
|
||||||
* `tojs`: convert a Lua value to a JS value
|
|
||||||
* `log`: console.log
|
|
||||||
|
|
||||||
In addition, [all SilverBullet syscalls](https://jsr.io/@silverbulletmd/silverbullet/doc/syscalls) are exposed. However since the Lua naming convention prefers using `snake_case` it is recommended you call them that way. For instance: `editor.flash_notification` is more Lua’y than `editor.flashNotification` (although both are supported at this time -- again, subject to change).
|
|
||||||
|
|
||||||
While in [[Space Script]] all syscalls are asynchronous and need to be called with `await`, this is happens transparently in Space Lua leading to cleaner code:
|
While in [[Space Script]] all syscalls are asynchronous and need to be called with `await`, this is happens transparently in Space Lua leading to cleaner code:
|
||||||
|
|
||||||
```space-lua
|
```space-lua
|
||||||
local function call_some_things()
|
local function callSomeThings()
|
||||||
local text = space.read_page(editor.get_current_page())
|
local text = space.readPage(editor.getCurrentPage())
|
||||||
print("Current page text", text)
|
print("Current page text", text)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue