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);
|
||||
assertEquals(
|
||||
await evalExpr(
|
||||
"space_lua.interpolate('Hello, ${globalEnv} and ${loc}!', {loc='local'})",
|
||||
"spacelua.interpolate('Hello, ${globalEnv} and ${loc}!', {loc='local'})",
|
||||
env,
|
||||
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 {}
|
||||
assertEquals(
|
||||
await evalExpr(
|
||||
`space_lua.interpolate('Some JSON \${js.stringify(js.tojs({name="Pete"}))}!')`,
|
||||
`spacelua.interpolate('Some JSON \${js.stringify(js.tojs({name="Pete"}))}!')`,
|
||||
env,
|
||||
sf,
|
||||
),
|
||||
|
|
|
@ -15,7 +15,7 @@ import { stringApi } from "$common/space_lua/stdlib/string.ts";
|
|||
import { tableApi } from "$common/space_lua/stdlib/table.ts";
|
||||
import { osApi } from "$common/space_lua/stdlib/os.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 { parse } from "$common/space_lua/parse.ts";
|
||||
import { evalStatement } from "$common/space_lua/eval.ts";
|
||||
|
@ -193,7 +193,7 @@ export function luaBuildStandardEnv() {
|
|||
env.set("math", mathApi);
|
||||
// Non-standard
|
||||
env.set("each", eachFunction);
|
||||
env.set("space_lua", spaceLuaApi);
|
||||
env.set("spacelua", spaceluaApi);
|
||||
// env.set("template", templateApi);
|
||||
return env;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ export const jsApi = new LuaTable({
|
|||
}
|
||||
return m;
|
||||
}),
|
||||
each_iterable: new LuaBuiltinFunction((_sf, val) => {
|
||||
eachIterable: new LuaBuiltinFunction((_sf, val) => {
|
||||
const iterator = val[Symbol.asyncIterator]();
|
||||
return async () => {
|
||||
const result = await iterator.next();
|
||||
|
|
|
@ -210,12 +210,12 @@ print(math.ult(2, 1)) -- prints: false
|
|||
```
|
||||
|
||||
# Non-standard Extensions
|
||||
## math.cosine_similarity(vecA, vecB)
|
||||
## math.cosineSimilarity(vecA, vecB)
|
||||
Returns the cosine similarity between two vectors.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local vec1 = {1, 2, 3}
|
||||
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);
|
||||
}),
|
||||
|
||||
// Keep the cosine_similarity utility function
|
||||
cosine_similarity: new LuaBuiltinFunction(
|
||||
// Keep the cosineSimilarity utility function
|
||||
cosineSimilarity: new LuaBuiltinFunction(
|
||||
(sf, vecA: LuaTable | number[], vecB: LuaTable | number[]) => {
|
||||
// Convert LuaTable to number[]
|
||||
if (vecA instanceof LuaTable) {
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
local function assert_equal(a, b)
|
||||
local function assertEqual(a, b)
|
||||
if a ~= b then
|
||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||
end
|
||||
end
|
||||
|
||||
-- Trigonometric functions
|
||||
assert_equal(math.cos(0), 1)
|
||||
assert_equal(math.sin(0), 0)
|
||||
assert_equal(math.tan(0), 0)
|
||||
assert_equal(math.acos(1), 0)
|
||||
assert_equal(math.asin(0), 0)
|
||||
assert_equal(math.atan(0), 0)
|
||||
assertEqual(math.cos(0), 1)
|
||||
assertEqual(math.sin(0), 0)
|
||||
assertEqual(math.tan(0), 0)
|
||||
assertEqual(math.acos(1), 0)
|
||||
assertEqual(math.asin(0), 0)
|
||||
assertEqual(math.atan(0), 0)
|
||||
|
||||
-- Hyperbolic functions
|
||||
assert_equal(math.cosh(0), 1)
|
||||
assert_equal(math.sinh(0), 0)
|
||||
assert_equal(math.tanh(0), 0)
|
||||
assertEqual(math.cosh(0), 1)
|
||||
assertEqual(math.sinh(0), 0)
|
||||
assertEqual(math.tanh(0), 0)
|
||||
|
||||
-- Basic functions
|
||||
assert_equal(math.abs(-5), 5)
|
||||
assert_equal(math.ceil(3.3), 4)
|
||||
assert_equal(math.floor(3.7), 3)
|
||||
assert_equal(math.max(1, 2, 3, 4), 4)
|
||||
assert_equal(math.min(1, 2, 3, 4), 1)
|
||||
assertEqual(math.abs(-5), 5)
|
||||
assertEqual(math.ceil(3.3), 4)
|
||||
assertEqual(math.floor(3.7), 3)
|
||||
assertEqual(math.max(1, 2, 3, 4), 4)
|
||||
assertEqual(math.min(1, 2, 3, 4), 1)
|
||||
|
||||
-- Rounding and remainder
|
||||
assert_equal(math.fmod(7, 3), 1)
|
||||
assertEqual(math.fmod(7, 3), 1)
|
||||
|
||||
-- Power and logarithms
|
||||
assert_equal(math.exp(0), 1)
|
||||
assert_equal(math.log(math.exp(1)), 1)
|
||||
assert_equal(math.log(8, 2), 3) -- log base 2 of 8
|
||||
assert_equal(math.pow(2, 3), 8)
|
||||
assert_equal(math.sqrt(9), 3)
|
||||
assertEqual(math.exp(0), 1)
|
||||
assertEqual(math.log(math.exp(1)), 1)
|
||||
assertEqual(math.log(8, 2), 3) -- log base 2 of 8
|
||||
assertEqual(math.pow(2, 3), 8)
|
||||
assertEqual(math.sqrt(9), 3)
|
||||
|
||||
|
||||
-- Random number tests (basic range checks)
|
||||
local rand = math.random()
|
||||
assert_equal(rand >= 0 and rand < 1, true)
|
||||
local rand_n = math.random(10)
|
||||
assert_equal(rand_n >= 1 and rand_n <= 10, true)
|
||||
local rand_range = math.random(5, 10)
|
||||
assert_equal(rand_range >= 5 and rand_range <= 10, true)
|
||||
assertEqual(rand >= 0 and rand < 1, true)
|
||||
local randN = math.random(10)
|
||||
assertEqual(randN >= 1 and randN <= 10, true)
|
||||
local randRange = math.random(5, 10)
|
||||
assertEqual(randRange >= 5 and randRange <= 10, true)
|
||||
|
||||
-- Unsigned less than comparison
|
||||
assert_equal(math.ult(1, 2), true)
|
||||
assert_equal(math.ult(2, 1), false)
|
||||
assertEqual(math.ult(1, 2), true)
|
||||
assertEqual(math.ult(2, 1), false)
|
||||
|
|
|
@ -100,7 +100,7 @@ export async function interpolateLuaString(
|
|||
return result;
|
||||
}
|
||||
|
||||
export const spaceLuaApi = new LuaTable({
|
||||
export const spaceluaApi = new LuaTable({
|
||||
/**
|
||||
* 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.
|
||||
* @returns The parsed expression.
|
||||
*/
|
||||
parse_expression: new LuaBuiltinFunction(
|
||||
parseExpression: new LuaBuiltinFunction(
|
||||
(_sf, luaExpression: string) => {
|
||||
return parseExpressionString(luaExpression);
|
||||
},
|
||||
|
@ -121,7 +121,7 @@ export const spaceLuaApi = new LuaTable({
|
|||
* @param envAugmentation - An optional environment to augment the global environment with.
|
||||
* @returns The result of the evaluated expression.
|
||||
*/
|
||||
eval_expression: new LuaBuiltinFunction(
|
||||
evalExpression: new LuaBuiltinFunction(
|
||||
async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
|
||||
const env = createAugmentedEnv(sf, envAugmentation);
|
||||
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
|
||||
*/
|
||||
base_url: new LuaBuiltinFunction(
|
||||
baseUrl: new LuaBuiltinFunction(
|
||||
() => {
|
||||
// Deal with Deno
|
||||
if (typeof location === "undefined") {
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
local function assert_equal(a, b)
|
||||
if a ~= b then
|
||||
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)
|
||||
local parsedExpr = spacelua.parseExpression("1 + 1")
|
||||
local evalResult = spacelua.evalExpression(parsedExpr)
|
||||
assert(evalResult == 2, "Eval should return 2")
|
||||
|
||||
-- Slightly more advanced example with augmented environment
|
||||
local parsedExpr = space_lua.parse_expression("tostring(a + 1)")
|
||||
local evalResult = space_lua.eval_expression(parsedExpr, { a = 1 })
|
||||
assert(evalResult == "2", "Eval should return 2 as a string")
|
||||
local parsedExpr = spacelua.parseExpression("tostring(a + 1)")
|
||||
local evalResult = spacelua.evalExpression(parsedExpr, { a = 1 })
|
||||
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) => {
|
||||
return s.trim();
|
||||
}),
|
||||
trim_start: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
trimStart: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.trimStart();
|
||||
}),
|
||||
trim_end: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
trimEnd: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
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 result = s.match(regex);
|
||||
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");
|
||||
return () => {
|
||||
const match = regex.exec(s);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
local function assert_equal(a, b)
|
||||
local function assertEqual(a, b)
|
||||
if a ~= b then
|
||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||
end
|
||||
|
@ -73,80 +73,80 @@ assert(result == "hello-world", "Magic character replacement failed")
|
|||
|
||||
-- Test string.match
|
||||
local m1, m2 = string.match("hello world", "(h)(ello)")
|
||||
assert_equal(m1, "h")
|
||||
assert_equal(m2, "ello")
|
||||
assertEqual(m1, "h")
|
||||
assertEqual(m2, "ello")
|
||||
|
||||
-- Test match with init position - need to capture the group
|
||||
local init_match = string.match("hello world", "(world)", 7)
|
||||
assert_equal(init_match, "world")
|
||||
local initMatch = string.match("hello world", "(world)", 7)
|
||||
assertEqual(initMatch, "world")
|
||||
|
||||
-- Test string.gmatch
|
||||
local words = {}
|
||||
for word in string.gmatch("hello world lua", "%w+") do
|
||||
table.insert(words, word)
|
||||
end
|
||||
assert_equal(words[1], "hello")
|
||||
assert_equal(words[2], "world")
|
||||
assert_equal(words[3], "lua")
|
||||
assertEqual(words[1], "hello")
|
||||
assertEqual(words[2], "world")
|
||||
assertEqual(words[3], "lua")
|
||||
|
||||
-- Test string.reverse
|
||||
assert_equal(string.reverse("hello"), "olleh")
|
||||
assert_equal(string.reverse(""), "")
|
||||
assertEqual(string.reverse("hello"), "olleh")
|
||||
assertEqual(string.reverse(""), "")
|
||||
|
||||
-- Test string.split
|
||||
local parts = string.split("a,b,c", ",")
|
||||
assert_equal(parts[1], "a")
|
||||
assert_equal(parts[2], "b")
|
||||
assert_equal(parts[3], "c")
|
||||
assertEqual(parts[1], "a")
|
||||
assertEqual(parts[2], "b")
|
||||
assertEqual(parts[3], "c")
|
||||
|
||||
-- Test non-standard string extensions
|
||||
assert_equal(string.startswith("hello world", "hello"), true)
|
||||
assert_equal(string.startswith("hello world", "world"), false)
|
||||
assertEqual(string.startswith("hello world", "hello"), true)
|
||||
assertEqual(string.startswith("hello world", "world"), false)
|
||||
|
||||
assert_equal(string.endswith("hello world", "world"), true)
|
||||
assert_equal(string.endswith("hello world", "hello"), false)
|
||||
assertEqual(string.endswith("hello world", "world"), true)
|
||||
assertEqual(string.endswith("hello world", "hello"), false)
|
||||
|
||||
-- Extended string.match tests
|
||||
-- Basic pattern matching
|
||||
assert_equal(string.match("hello", "h"), "h")
|
||||
assert_equal(string.match("hello", "hello"), "hello")
|
||||
assertEqual(string.match("hello", "h"), "h")
|
||||
assertEqual(string.match("hello", "hello"), "hello")
|
||||
|
||||
-- Test with no matches
|
||||
assert_equal(string.match("hello", "x"), nil)
|
||||
assertEqual(string.match("hello", "x"), nil)
|
||||
|
||||
-- Test with captures
|
||||
local m1, m2 = string.match("hello", "(h)(ello)")
|
||||
assert_equal(m1, "h")
|
||||
assert_equal(m2, "ello")
|
||||
assertEqual(m1, "h")
|
||||
assertEqual(m2, "ello")
|
||||
|
||||
-- Test with init position
|
||||
local init_match = string.match("hello world", "(world)", 7)
|
||||
assert_equal(init_match, "world")
|
||||
local initMatch = string.match("hello world", "(world)", 7)
|
||||
assertEqual(initMatch, "world")
|
||||
|
||||
-- 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
|
||||
assert_equal(string.match("123", "%d+"), "123")
|
||||
assert_equal(string.match("abc123", "%a+"), "abc")
|
||||
assert_equal(string.match(" abc", "%s+"), " ")
|
||||
assertEqual(string.match("123", "%d+"), "123")
|
||||
assertEqual(string.match("abc123", "%a+"), "abc")
|
||||
assertEqual(string.match(" abc", "%s+"), " ")
|
||||
|
||||
-- Test multiple captures
|
||||
local day, month, year = string.match("2024-03-14", "(%d+)-(%d+)-(%d+)")
|
||||
assert_equal(day, "2024")
|
||||
assert_equal(month, "03")
|
||||
assert_equal(year, "14")
|
||||
assertEqual(day, "2024")
|
||||
assertEqual(month, "03")
|
||||
assertEqual(year, "14")
|
||||
|
||||
-- Test optional captures
|
||||
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 = {}
|
||||
for match in string.match_regex_all("hellolllbl", "(l+)") do
|
||||
for match in string.matchRegexAll("hellolllbl", "(l+)") do
|
||||
table.insert(matches, match)
|
||||
end
|
||||
assert_equal(#matches, 3)
|
||||
assert_equal(matches[1][1], "ll")
|
||||
assert_equal(matches[2][1], "lll")
|
||||
assert_equal(matches[3][1], "l")
|
||||
assertEqual(#matches, 3)
|
||||
assertEqual(matches[1][1], "ll")
|
||||
assertEqual(matches[2][1], "lll")
|
||||
assertEqual(matches[3][1], "l")
|
||||
|
|
|
@ -34,9 +34,7 @@ function exposeSyscalls(env: LuaEnv, system: System<any>) {
|
|||
const luaFn = new LuaNativeJSFunction((...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(snakeCase(fn), luaFn, nativeFs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,9 +64,9 @@ export async function handleLuaError(e: LuaRuntimeError, system: System<any>) {
|
|||
console.error(
|
||||
"Lua eval exception",
|
||||
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
|
||||
const pageRef = parsePageRef(e.sf.astCtx.ref);
|
||||
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,
|
||||
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,
|
||||
[
|
||||
"idx",
|
||||
|
|
|
@ -6,11 +6,11 @@ Config library for defining and getting config values
|
|||
-- priority: 10
|
||||
config = {}
|
||||
|
||||
local config_values = {}
|
||||
local config_schema = {}
|
||||
local configValues = {}
|
||||
local configSchema = {}
|
||||
|
||||
function config.define(key, schema)
|
||||
config_schema[key] = schema or true
|
||||
configSchema[key] = schema or true
|
||||
end
|
||||
|
||||
function config.set(keyOrTable, value)
|
||||
|
@ -21,20 +21,19 @@ function config.set(keyOrTable, value)
|
|||
return
|
||||
end
|
||||
local key = keyOrTable
|
||||
local schema = config_schema[key]
|
||||
local schema = configSchema[key]
|
||||
if schema == nil then
|
||||
error("Config key not defined: " .. key)
|
||||
end
|
||||
if schema != true then
|
||||
local result = jsonschema.validate_object(schema, value)
|
||||
local result = jsonschema.validateObject(schema, value)
|
||||
if result != nil then
|
||||
error("Validation error (" .. key .. "): " .. result)
|
||||
end
|
||||
end
|
||||
config_values[key] = value
|
||||
configValues[key] = value
|
||||
end
|
||||
|
||||
function config.get(key)
|
||||
return config_values[key]
|
||||
return configValues[key]
|
||||
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"}
|
||||
|
||||
-- Are we in a comment?
|
||||
local function in_comment(line)
|
||||
local function inComment(line)
|
||||
return string.find(line, "--")
|
||||
end
|
||||
|
||||
-- Are we in a string?
|
||||
local function in_string(line)
|
||||
local single_quotes = 0
|
||||
local double_quotes = 0
|
||||
local function inString(line)
|
||||
local singleQuotes = 0
|
||||
local doubleQuotes = 0
|
||||
local brackets = 0
|
||||
for i = 1, string.len(line) do
|
||||
local c = line[i]
|
||||
if c == "'" then
|
||||
single_quotes = single_quotes + 1
|
||||
singleQuotes = singleQuotes + 1
|
||||
elseif c == '"' then
|
||||
double_quotes = double_quotes + 1
|
||||
doubleQuotes = doubleQuotes + 1
|
||||
elseif c == "[" and line[i+1] == "[" then
|
||||
brackets = brackets + 1
|
||||
elseif c == "]" and line[i-1] == "]" then
|
||||
brackets = brackets - 1
|
||||
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
|
||||
|
||||
-- API code completion for Lua
|
||||
|
@ -37,33 +37,33 @@ event.listen {
|
|||
name = "editor:complete",
|
||||
run = function(e)
|
||||
local parents = e.data.parentNodes
|
||||
local found_space_lua = false
|
||||
local foundSpaceLua = false
|
||||
for _, parent in ipairs(parents) do
|
||||
if string.startswith(parent, "FencedCode:space-lua") then
|
||||
found_space_lua = true
|
||||
foundSpaceLua = true
|
||||
end
|
||||
end
|
||||
if not found_space_lua then
|
||||
if not foundSpaceLua then
|
||||
return
|
||||
end
|
||||
local line_prefix = e.data.linePrefix
|
||||
if in_comment(line_prefix) or in_string(line_prefix) then
|
||||
local linePrefix = e.data.linePrefix
|
||||
if inComment(linePrefix) or inString(linePrefix) then
|
||||
return
|
||||
end
|
||||
local pos = e.data.pos
|
||||
local propaccess_prefix = string.match_regex(line_prefix, "([a-zA-Z_0-9]+\\.)*([a-zA-Z_0-9]*)$")
|
||||
if not propaccess_prefix or not propaccess_prefix[1] then
|
||||
local propaccessPrefix = string.matchRegex(linePrefix, "([a-zA-Z_0-9]+\\.)*([a-zA-Z_0-9]*)$")
|
||||
if not propaccessPrefix or not propaccessPrefix[1] then
|
||||
-- No propaccess prefix, so we can't complete
|
||||
return
|
||||
end
|
||||
-- Split propaccess and traverse
|
||||
local prop_parts = string.split(propaccess_prefix[1], ".")
|
||||
local current_value = _CTX._GLOBAL
|
||||
local propParts = string.split(propaccessPrefix[1], ".")
|
||||
local currentValue = _CTX._GLOBAL
|
||||
local failed = false
|
||||
for i = 1, #prop_parts-1 do
|
||||
local prop = prop_parts[i]
|
||||
if current_value then
|
||||
current_value = current_value[prop]
|
||||
for i = 1, #propParts-1 do
|
||||
local prop = propParts[i]
|
||||
if currentValue then
|
||||
currentValue = currentValue[prop]
|
||||
else
|
||||
failed = true
|
||||
end
|
||||
|
@ -71,13 +71,13 @@ event.listen {
|
|||
if failed then
|
||||
return
|
||||
end
|
||||
local last_prop = prop_parts[#prop_parts]
|
||||
if table.includes(LUA_KEYWORDS, last_prop) then
|
||||
local lastProp = propParts[#propParts]
|
||||
if table.includes(LUA_KEYWORDS, lastProp) then
|
||||
return
|
||||
end
|
||||
local options = {}
|
||||
for key, val in pairs(current_value) do
|
||||
if string.startswith(key, last_prop) and val then
|
||||
for key, val in pairs(currentValue) do
|
||||
if string.startswith(key, lastProp) and val then
|
||||
if val.call then
|
||||
-- We got a function
|
||||
if val.body then
|
||||
|
@ -106,7 +106,7 @@ event.listen {
|
|||
end
|
||||
if #options > 0 then
|
||||
return {
|
||||
from = pos - string.len(last_prop),
|
||||
from = pos - string.len(lastProp),
|
||||
options = options
|
||||
}
|
||||
end
|
||||
|
@ -118,34 +118,33 @@ event.listen {
|
|||
Various useful slash templates.
|
||||
|
||||
```space-lua
|
||||
template.define_slash_command {
|
||||
template.defineSlashCommand {
|
||||
name = "function",
|
||||
description = "Lua function",
|
||||
only_contexts = {"FencedCode:space-lua"},
|
||||
onlyContexts = {"FencedCode:space-lua"},
|
||||
template = template.new [==[function |^|()
|
||||
end]==]
|
||||
}
|
||||
|
||||
template.define_slash_command {
|
||||
template.defineSlashCommand {
|
||||
name = "tpl",
|
||||
description = "Lua template",
|
||||
only_contexts = {"FencedCode:space-lua"},
|
||||
onlyContexts = {"FencedCode:space-lua"},
|
||||
template = template.new "template.new[==[|^|]==]"
|
||||
}
|
||||
|
||||
template.define_slash_command {
|
||||
template.defineSlashCommand {
|
||||
name = "lua-query",
|
||||
description = "Lua query",
|
||||
only_contexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||
onlyContexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||
template = template.new 'query[[from index.tag "|^|"]]'
|
||||
}
|
||||
|
||||
|
||||
-- A query embedded in ${}
|
||||
template.define_slash_command {
|
||||
template.defineSlashCommand {
|
||||
name = "query",
|
||||
description = "Lua query",
|
||||
except_contexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||
exceptContexts = {"FencedCode:space-lua", "LuaDirective"},
|
||||
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
|
||||
-- Renders a page object as a linked list item
|
||||
templates.page_item = template.new([==[
|
||||
templates.pageItem = template.new([==[
|
||||
* [[${name}]]
|
||||
]==])
|
||||
|
||||
-- Renders a task object as a togglable task
|
||||
templates.task_item = template.new([==[
|
||||
templates.taskItem = template.new([==[
|
||||
* [${state}] [[${ref}]] ${name}
|
||||
]==])
|
||||
```
|
||||
|
||||
|
||||
# Examples
|
||||
`template.page_item`:
|
||||
${template.each(query[[from index.tag "page" limit 3]], templates.page_item)}
|
||||
`template.pageItem`:
|
||||
${template.each(query[[from index.tag "page" limit 3]], templates.pageItem)}
|
||||
|
||||
`template.task_item`:
|
||||
`template.taskItem`:
|
||||
* [ ] Task 1
|
||||
* [ ] 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
|
||||
|
||||
-- Creates a new template function from a string template
|
||||
function template.new(template_str)
|
||||
function template.new(templateStr)
|
||||
-- Preprocess: strip indentation
|
||||
local lines = {}
|
||||
local split_lines = string.split(template_str, "\n")
|
||||
for _, line in ipairs(split_lines) do
|
||||
local splitLines = string.split(templateStr, "\n")
|
||||
for _, line in ipairs(splitLines) do
|
||||
line = string.gsub(line, "^ ", "")
|
||||
table.insert(lines, line)
|
||||
end
|
||||
template_str = table.concat(lines, "\n")
|
||||
templateStr = table.concat(lines, "\n")
|
||||
return function(obj)
|
||||
return space_lua.interpolate(template_str, obj)
|
||||
return spacelua.interpolate(templateStr, obj)
|
||||
end
|
||||
end
|
||||
|
||||
-- Creates a template-based slash command, keys for def are:
|
||||
-- name: name 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
|
||||
-- except_contexts: parent AST nodes in which this slash command is not available
|
||||
-- onlyContexts: parent AST nodes in which this slash command is available, defaults to everywhere
|
||||
-- exceptContexts: parent AST nodes in which this slash command is not available
|
||||
-- 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_regex: match regex to apply the template to
|
||||
function template.define_slash_command(def)
|
||||
slash_command.define {
|
||||
-- matchRegex: match regex to apply the template to
|
||||
function template.defineSlashCommand(def)
|
||||
slashcommand.define {
|
||||
name = def.name,
|
||||
description = def.description,
|
||||
onlyContexts = def.only_contexts,
|
||||
exceptContexts = def.except_contexts,
|
||||
onlyContexts = def.onlyContexts,
|
||||
exceptContexts = def.exceptContexts,
|
||||
run = function()
|
||||
system.invoke_function("template.applySnippetTemplate", def.template(), {
|
||||
insertAt = def.insert_at,
|
||||
system.invokeFunction("template.applySnippetTemplate", def.template(), {
|
||||
insertAt = def.insertAt,
|
||||
match = def.match,
|
||||
matchRegex = def.match_regex
|
||||
matchRegex = def.matchRegex
|
||||
})
|
||||
end
|
||||
}
|
||||
end
|
||||
```
|
||||
|
|
|
@ -81,7 +81,7 @@ export function luaDirectivePlugin(client: Client) {
|
|||
return result;
|
||||
} catch (e: any) {
|
||||
if (e instanceof LuaRuntimeError) {
|
||||
if (e.sf.astCtx) {
|
||||
if (e.sf?.astCtx) {
|
||||
const source = resolveASTReference(e.sf.astCtx);
|
||||
if (source) {
|
||||
// We know the origin node of the error, let's reference it
|
||||
|
|
|
@ -89,9 +89,9 @@ export class LuaWidget extends WidgetType {
|
|||
html = widgetContent.html;
|
||||
div.innerHTML = html;
|
||||
if ((widgetContent as any)?.display === "block") {
|
||||
div.className = "sb-lua-directive-block";
|
||||
div.className += " sb-lua-directive-block";
|
||||
} else {
|
||||
div.className = "sb-lua-directive-inline";
|
||||
div.className += " sb-lua-directive-inline";
|
||||
}
|
||||
attachWidgetEventHandlers(div, this.client, this.from);
|
||||
this.client.setWidgetCache(
|
||||
|
|
|
@ -2,4 +2,4 @@ This describes the APIs available in [[Space Lua]]
|
|||
|
||||
${template.each(query[[
|
||||
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.
|
||||
|
||||
|
||||
## clientStore.set(key, value)
|
||||
Sets a value in the client store.
|
||||
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
APIs related to editor commands
|
||||
|
||||
### command.define(command_def)
|
||||
### command.define(commandDef)
|
||||
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:
|
||||
```lua
|
||||
command.define {
|
||||
name = "My custom command",
|
||||
run = function()
|
||||
editor.flash_notification "Triggered my custom command"
|
||||
editor.flashNotification "Triggered my custom command"
|
||||
end
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
The Datastore API provides functions for interacting with a key-value store that has query capabilities.
|
||||
|
||||
# Key-Value Operations
|
||||
|
@ -30,7 +29,7 @@ datastore.del("user:123")
|
|||
|
||||
# Batch Operations
|
||||
|
||||
## datastore.batch_set(kvs)
|
||||
## datastore.batchSet(kvs)
|
||||
Sets multiple key-value pairs in a single operation.
|
||||
|
||||
Example:
|
||||
|
@ -39,27 +38,25 @@ local kvs = {
|
|||
{key = "user:1", value = {name = "Alice"}},
|
||||
{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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local keys = {"user:1", "user:2"}
|
||||
local values = datastore.batch_get(keys)
|
||||
local values = datastore.batchGet(keys)
|
||||
for _, value in ipairs(values) do
|
||||
print(value.name)
|
||||
end
|
||||
```
|
||||
|
||||
## datastore.batch_del(keys)
|
||||
## datastore.batchDel(keys)
|
||||
Deletes multiple values in a single operation.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
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.
|
||||
|
||||
## debug.reset_client()
|
||||
## debug.resetClient()
|
||||
Completely wipes the client state, including cached files and databases.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
debug.reset_client()
|
||||
debug.resetClient()
|
||||
print("Client state has been reset")
|
||||
```
|
||||
|
||||
|
@ -18,4 +18,3 @@ Example:
|
|||
```lua
|
||||
debug.cleanup()
|
||||
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.get_current_page()
|
||||
### editor.getCurrentPage()
|
||||
Returns the name of the page currently open in the editor.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local page = editor.get_current_page()
|
||||
print("Current page: " .. page)
|
||||
```
|
||||
Example: ${editor.getCurrentPage()}
|
||||
|
||||
### editor.get_current_page_meta()
|
||||
### editor.getCurrentPageMeta()
|
||||
Returns the meta data of the page currently open in the editor.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local meta = editor.get_current_page_meta()
|
||||
print("Last modified: " .. meta.last_modified)
|
||||
```
|
||||
${editor.getCurrentPageMeta()}
|
||||
|
||||
## Text Operations
|
||||
|
||||
### editor.get_text()
|
||||
### editor.getText()
|
||||
Returns the full text of the currently open page.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local text = editor.get_text()
|
||||
local text = editor.getText()
|
||||
print("Document length: " .. #text)
|
||||
```
|
||||
|
||||
### editor.set_text(text, isolate_history)
|
||||
### editor.setText(text, isolateHistory)
|
||||
Updates the editor text while preserving cursor location.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local text = editor.get_text()
|
||||
editor.set_text(text:upper(), false) -- Convert to uppercase
|
||||
local text = editor.getText()
|
||||
editor.setText(text:upper(), false) -- Convert to uppercase
|
||||
```
|
||||
|
||||
### editor.insert_at_pos(text, pos)
|
||||
### editor.insertAtPos(text, pos)
|
||||
Insert text at the specified position.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.insert_at_cursor("Inserted at cursor")
|
||||
editor.insertAtCursor("Inserted at cursor")
|
||||
```
|
||||
|
||||
## Cursor Control
|
||||
|
||||
### editor.get_cursor()
|
||||
### editor.getCursor()
|
||||
Returns the cursor position as character offset.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local pos = editor.get_cursor()
|
||||
local pos = editor.getCursor()
|
||||
print("Cursor at position: " .. pos)
|
||||
```
|
||||
|
||||
### editor.get_selection()
|
||||
### editor.getSelection()
|
||||
Returns the current selection range.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local sel = editor.get_selection()
|
||||
local sel = editor.getSelection()
|
||||
print("Selection from " .. sel.from .. " to " .. sel.to)
|
||||
```
|
||||
|
||||
### editor.set_selection(from, to)
|
||||
### editor.setSelection(from, to)
|
||||
Sets the current selection range.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```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.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)
|
||||
### editor.openPageNavigator(mode)
|
||||
Opens the page navigator.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.open_page_navigator("page")
|
||||
editor.openPageNavigator("page")
|
||||
```
|
||||
|
||||
### editor.open_command_palette()
|
||||
### editor.openCommandPalette()
|
||||
Opens the command palette.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.open_command_palette()
|
||||
editor.openCommandPalette()
|
||||
```
|
||||
|
||||
## UI Operations
|
||||
|
||||
### editor.show_panel(id, mode, html, script)
|
||||
### editor.showPanel(id, mode, html, script)
|
||||
Shows a panel in the editor.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.hide_panel("rhs")
|
||||
editor.hidePanel("rhs")
|
||||
```
|
||||
|
||||
### editor.flash_notification(message, type)
|
||||
### editor.flashNotification(message, type)
|
||||
Shows a flash notification.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.flash_notification("Operation completed", "info")
|
||||
editor.flashNotification("Operation completed", "info")
|
||||
```
|
||||
|
||||
### editor.prompt(message, default_value)
|
||||
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)
|
||||
### editor.downloadFile(filename, dataUrl)
|
||||
Triggers a file download in the browser.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local file = editor.upload_file(".txt", nil)
|
||||
local file = editor.uploadFile(".txt", nil)
|
||||
print("Uploaded: " .. file.name)
|
||||
```
|
||||
|
||||
## Clipboard Operations
|
||||
|
||||
### editor.copy_to_clipboard(data)
|
||||
### editor.copyToClipboard(data)
|
||||
Copies data to the clipboard.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.copy_to_clipboard("Copied text")
|
||||
editor.copyToClipboard("Copied text")
|
||||
```
|
||||
|
||||
## Code Folding
|
||||
|
||||
### 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()
|
||||
### editor.toggleFold()
|
||||
Toggles code folding at the current position.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.toggle_fold()
|
||||
editor.toggleFold()
|
||||
```
|
||||
|
||||
### editor.fold_all()
|
||||
### editor.foldAll()
|
||||
Folds all foldable regions.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.fold_all()
|
||||
editor.foldAll()
|
||||
```
|
||||
|
||||
### editor.unfold_all()
|
||||
### editor.unfoldAll()
|
||||
Unfolds all folded regions.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
editor.unfold_all()
|
||||
editor.unfoldAll()
|
||||
```
|
||||
|
||||
## History Operations
|
||||
|
||||
### 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()
|
||||
### editor.openSearchPanel()
|
||||
Opens the editor's search panel.
|
||||
|
||||
Example:
|
||||
```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.listen(listener_def)
|
||||
### event.listen(listenerDef)
|
||||
Register an event listener.
|
||||
|
||||
```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.
|
||||
|
||||
Example:
|
||||
|
@ -25,19 +25,18 @@ Example:
|
|||
event.dispatch("custom.event", {message = "Hello"})
|
||||
|
||||
-- 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
|
||||
print(response)
|
||||
end
|
||||
```
|
||||
|
||||
### event.list_events()
|
||||
### event.listEvents()
|
||||
Lists all events currently registered (listened to) on the SilverBullet event bus.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local events = event.list_events()
|
||||
for _, event_name in ipairs(events) do
|
||||
print("Registered event: " .. event_name)
|
||||
local events = event.listEvents()
|
||||
for _, eventName in ipairs(events) do
|
||||
print("Registered event: " .. eventName)
|
||||
end
|
||||
```
|
|
@ -9,7 +9,7 @@ Example:
|
|||
|
||||
${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.
|
||||
|
||||
Example:
|
||||
|
@ -18,24 +18,23 @@ local objects = {
|
|||
{tag = "mytask", ref="task1", content = "Buy groceries"},
|
||||
{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.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local task = index.get_object_by_ref("my page", "mytask", "task1")
|
||||
local task = index.getObjectByRef("my page", "mytask", "task1")
|
||||
if task then
|
||||
print("Found task: " .. task.content)
|
||||
end
|
||||
```
|
||||
|
|
|
@ -6,13 +6,13 @@ Imports a JavaScript module from a URL. Returns the imported module.
|
|||
Example:
|
||||
```lua
|
||||
-- Import lodash library
|
||||
local lodash = 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 lodashLib = js.import("https://esm.sh/lodash@4.17.21")
|
||||
local result = lodashLib.chunk({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3)
|
||||
|
||||
-- Import moment.js for date handling
|
||||
local moment = js.import("https://esm.sh/moment@2.30.1")
|
||||
local day = moment("1995-12-25")
|
||||
print(day.format("DD-MM-YYYY")) -- prints: 25-12-1995
|
||||
local momentLib = js.import("https://esm.sh/moment@2.30.1")
|
||||
local dateObj = momentLib("1995-12-25")
|
||||
print(dateObj.format("DD-MM-YYYY")) -- prints: 25-12-1995
|
||||
```
|
||||
|
||||
## js.new(constructor, ...)
|
||||
|
@ -20,8 +20,8 @@ Creates a new instance of a JavaScript class. Takes a constructor function and i
|
|||
|
||||
Example:
|
||||
```lua
|
||||
local Date = js.import("https://esm.sh/date-fns")
|
||||
local date = js.new(Date, "2024-03-14")
|
||||
local DateClass = js.import("https://esm.sh/date-fns")
|
||||
local dateObj = js.new(DateClass, "2024-03-14")
|
||||
```
|
||||
|
||||
## js.stringify(value)
|
||||
|
@ -29,11 +29,11 @@ Converts a Lua value to a JSON string representation.
|
|||
|
||||
Example:
|
||||
```lua
|
||||
local data = {1, 2, 3}
|
||||
print(js.stringify(data)) -- prints: [1,2,3]
|
||||
local dataArray = {1, 2, 3}
|
||||
print(js.stringify(dataArray)) -- prints: [1,2,3]
|
||||
|
||||
local nested = lodash.chunk({1, 2, 3, 4, 5, 6}, 2)
|
||||
print(js.stringify(nested)) -- prints: [[1,2],[3,4],[5,6]]
|
||||
local nestedArray = lodashLib.chunk({1, 2, 3, 4, 5, 6}, 2)
|
||||
print(js.stringify(nestedArray)) -- prints: [[1,2],[3,4],[5,6]]
|
||||
```
|
||||
|
||||
## js.tolua(value)
|
||||
|
@ -63,13 +63,12 @@ js.log("Debug message")
|
|||
js.log("User data:", {name = "John", age = 30})
|
||||
```
|
||||
|
||||
## js.each_iterable(iterable)
|
||||
## js.eachIterable(iterable)
|
||||
Creates an iterator for JavaScript async iterables.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local async_iterator = js.each_iterable(some_js_async_iterable)
|
||||
for value in async_iterator do
|
||||
local asyncIterator = js.eachIterable(someJsAsyncIterable)
|
||||
for value in asyncIterator do
|
||||
print(value)
|
||||
end
|
||||
```
|
|
@ -4,7 +4,7 @@ The JSON Schema API provides functions for validating JSON objects against JSON
|
|||
|
||||
## Validation Operations
|
||||
|
||||
### jsonschema.validate_object(schema, object)
|
||||
### jsonschema.validateObject(schema, object)
|
||||
Validates a JSON object against a JSON schema.
|
||||
|
||||
Example:
|
||||
|
@ -19,7 +19,7 @@ local schema = {
|
|||
}
|
||||
|
||||
local object = {name = "John", age = 30}
|
||||
local error = jsonschema.validate_object(schema, object)
|
||||
local error = jsonschema.validateObject(schema, object)
|
||||
if error then
|
||||
print("Validation error: " .. error)
|
||||
else
|
||||
|
@ -27,7 +27,7 @@ else
|
|||
end
|
||||
```
|
||||
|
||||
### jsonschema.validate_schema(schema)
|
||||
### jsonschema.validateSchema(schema)
|
||||
Validates a JSON schema itself to ensure it's well-formed.
|
||||
|
||||
Example:
|
||||
|
@ -39,10 +39,9 @@ local schema = {
|
|||
}
|
||||
}
|
||||
|
||||
local error = jsonschema.validate_schema(schema)
|
||||
local error = jsonschema.validateSchema(schema)
|
||||
if error then
|
||||
print("Schema error: " .. error)
|
||||
else
|
||||
print("Schema is valid")
|
||||
end
|
||||
```
|
|
@ -2,7 +2,7 @@ The Language API provides functions for parsing code in various programming lang
|
|||
|
||||
## Language Operations
|
||||
|
||||
### language.parse_language(language, code)
|
||||
### language.parseLanguage(language, code)
|
||||
Parses a piece of code using any of the supported SilverBullet languages.
|
||||
|
||||
Example:
|
||||
|
@ -13,7 +13,7 @@ function hello() {
|
|||
}
|
||||
]]
|
||||
|
||||
local tree = language.parse_language("javascript", [[
|
||||
local tree = language.parseLanguage("javascript", [[
|
||||
function hello() {
|
||||
console.log("Hello, world!");
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ function hello() {
|
|||
print("Parsed syntax tree:", tree)
|
||||
```
|
||||
|
||||
### language.list_languages()
|
||||
### language.listLanguages()
|
||||
Lists all supported languages in fenced code blocks.
|
||||
|
||||
Example:
|
||||
${language.list_languages()}
|
||||
${language.listLanguages()}
|
||||
|
|
|
@ -4,7 +4,7 @@ The Markdown API provides functions for parsing and rendering Markdown content.
|
|||
|
||||
## Markdown Operations
|
||||
|
||||
### markdown.parse_markdown(text)
|
||||
### markdown.parseMarkdown(text)
|
||||
Parses a piece of markdown text into a ParseTree.
|
||||
|
||||
Example:
|
||||
|
@ -15,18 +15,17 @@ local text = [[
|
|||
This is a **bold** statement.
|
||||
]]
|
||||
|
||||
local tree = markdown.parse_markdown(text)
|
||||
local tree = markdown.parseMarkdown(text)
|
||||
print("Parsed markdown tree:", tree)
|
||||
```
|
||||
|
||||
### markdown.render_parse_tree(tree)
|
||||
### markdown.renderParseTree(tree)
|
||||
Renders a ParseTree back to markdown text.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local text = "# Title\n\nSome text"
|
||||
local tree = markdown.parse_markdown(text)
|
||||
local tree = markdown.parseMarkdown(text)
|
||||
-- Modify tree if needed
|
||||
local rendered = markdown.render_parse_tree(tree)
|
||||
local rendered = markdown.renderParseTree(tree)
|
||||
print("Rendered markdown:", rendered)
|
||||
```
|
|
@ -12,7 +12,7 @@ Example:
|
|||
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.
|
||||
|
||||
Example:
|
||||
|
@ -21,7 +21,7 @@ local messages = {
|
|||
{type = "task1", data = "sample1"},
|
||||
{type = "task2", data = "sample2"}
|
||||
}
|
||||
mq.batch_send("tasks", messages)
|
||||
mq.batchSend("tasks", messages)
|
||||
```
|
||||
|
||||
### mq.ack(queue, id)
|
||||
|
@ -32,23 +32,22 @@ Example:
|
|||
mq.ack("tasks", "message-123")
|
||||
```
|
||||
|
||||
### mq.batch_ack(queue, ids)
|
||||
### mq.batchAck(queue, ids)
|
||||
Acknowledges multiple messages from a queue in a single operation.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local messageIds = {"msg1", "msg2", "msg3"}
|
||||
mq.batch_ack("tasks", messageIds)
|
||||
mq.batchAck("tasks", messageIds)
|
||||
```
|
||||
|
||||
## Queue Management
|
||||
|
||||
### mq.get_queue_stats(queue)
|
||||
### mq.getQueueStats(queue)
|
||||
Retrieves statistics about a particular queue.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local stats = mq.get_queue_stats("tasks")
|
||||
local stats = mq.getQueueStats("tasks")
|
||||
print("Queue size: " .. stats.size)
|
||||
print("Processing: " .. stats.processing)
|
||||
```
|
|
@ -2,149 +2,148 @@ The Space API provides functions for interacting with pages, attachments, and fi
|
|||
|
||||
# Page Operations
|
||||
|
||||
## space.list_pages()
|
||||
## space.listPages()
|
||||
Returns a list of all pages in the space.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local pages = space.list_pages()
|
||||
local pages = space.listPages()
|
||||
for page in each(pages) do
|
||||
print(page.name)
|
||||
end
|
||||
```
|
||||
|
||||
## space.read_page(name)
|
||||
## space.readPage(name)
|
||||
Reads the content of a page.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local content = space.read_page("welcome")
|
||||
local content = space.readPage("welcome")
|
||||
print(content) -- prints the content of the "welcome" page
|
||||
```
|
||||
|
||||
## space.get_page_meta(name)
|
||||
## space.getPageMeta(name)
|
||||
Gets metadata for a specific page.
|
||||
|
||||
Example:
|
||||
```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
|
||||
```
|
||||
|
||||
## space.write_page(name, text)
|
||||
## space.writePage(name, text)
|
||||
Writes content to a page.
|
||||
|
||||
Example:
|
||||
```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)
|
||||
```
|
||||
|
||||
## space.delete_page(name)
|
||||
## space.deletePage(name)
|
||||
Deletes a page from the space.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
space.delete_page("old-notes")
|
||||
space.deletePage("old-notes")
|
||||
```
|
||||
|
||||
# Attachment Operations
|
||||
|
||||
## space.list_attachments()
|
||||
## space.listAttachments()
|
||||
Returns a list of all attachments in the space.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local attachments = space.list_attachments()
|
||||
local attachments = space.listAttachments()
|
||||
for att in each(attachments) do
|
||||
print(att.name, att.size)
|
||||
end
|
||||
```
|
||||
|
||||
## space.read_attachment(name)
|
||||
## space.readAttachment(name)
|
||||
Reads the content of an attachment.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local data = space.read_attachment("image.png")
|
||||
local data = space.readAttachment("image.png")
|
||||
print("Attachment size: " .. #data .. " bytes")
|
||||
```
|
||||
|
||||
## space.write_attachment(name, data)
|
||||
## space.writeAttachment(name, data)
|
||||
Writes binary data to an attachment.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local binary_data = string.char(72, 69, 76, 76, 79) -- "HELLO" in binary
|
||||
local meta = space.write_attachment("test.bin", binary_data)
|
||||
local binaryData = string.char(72, 69, 76, 76, 79) -- "HELLO" in binary
|
||||
local meta = space.writeAttachment("test.bin", binaryData)
|
||||
print("Attachment saved with size: " .. meta.size)
|
||||
```
|
||||
|
||||
## space.delete_attachment(name)
|
||||
## space.deleteAttachment(name)
|
||||
Deletes an attachment from the space.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
space.delete_attachment("old-image.png")
|
||||
space.deleteAttachment("old-image.png")
|
||||
```
|
||||
|
||||
# File Operations
|
||||
|
||||
## space.list_files()
|
||||
## space.listFiles()
|
||||
Returns a list of all files in the space.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local files = space.list_files()
|
||||
local files = space.listFiles()
|
||||
for _, file in ipairs(files) do
|
||||
print(file.name, file.size)
|
||||
end
|
||||
```
|
||||
|
||||
## space.get_file_meta(name)
|
||||
## space.getFileMeta(name)
|
||||
Gets metadata for a specific file.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local meta = space.get_file_meta("document.txt")
|
||||
local meta = space.getFileMeta("document.txt")
|
||||
print(meta.name, meta.modified, meta.size)
|
||||
```
|
||||
|
||||
## space.read_file(name)
|
||||
## space.readFile(name)
|
||||
Reads the content of a file.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local content = space.read_file("document.txt")
|
||||
local content = space.readFile("document.txt")
|
||||
print("File size: " .. #content .. " bytes")
|
||||
```
|
||||
|
||||
## space.write_file(name, data)
|
||||
## space.writeFile(name, data)
|
||||
Writes binary data to a file.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
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)
|
||||
```
|
||||
|
||||
## space.delete_file(name)
|
||||
## space.deleteFile(name)
|
||||
Deletes a file from the space.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
if space.file_exists("config.json") then
|
||||
if space.fileExists("config.json") then
|
||||
print("Config file exists!")
|
||||
else
|
||||
print("Config file not found")
|
||||
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.is_syncing()
|
||||
### sync.isSyncing()
|
||||
Checks if a sync is currently in progress.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
if sync.is_syncing() then
|
||||
if sync.isSyncing() then
|
||||
print("Sync in progress...")
|
||||
end
|
||||
```
|
||||
|
||||
### sync.has_initial_sync_completed()
|
||||
### sync.hasInitialSyncCompleted()
|
||||
Checks if an initial sync has completed.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
if sync.has_initial_sync_completed() then
|
||||
if sync.hasInitialSyncCompleted() then
|
||||
print("Initial sync completed")
|
||||
else
|
||||
print("Waiting for initial sync...")
|
||||
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.
|
||||
|
||||
Example:
|
||||
```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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local changes = sync.schedule_space_sync()
|
||||
local changes = sync.scheduleSpaceSync()
|
||||
print("Number of changes synced: " .. changes)
|
||||
```
|
|
@ -4,114 +4,113 @@ The System API provides system-level functions for interacting with the SilverBu
|
|||
|
||||
## Function Operations
|
||||
|
||||
### system.invoke_function(name, ...)
|
||||
### system.invokeFunction(name, ...)
|
||||
Invokes a plug function by name.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
-- 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.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
system.invoke_command("editor.save", {})
|
||||
system.invokeCommand("editor.save", {})
|
||||
```
|
||||
|
||||
### system.invoke_space_function(name, ...)
|
||||
### system.invokeSpaceFunction(name, ...)
|
||||
Invokes a space function by name.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local result = system.invoke_space_function("custom_function", "arg1", "arg2")
|
||||
local result = system.invokeSpaceFunction("customFunction", "arg1", "arg2")
|
||||
print("Function result:", result)
|
||||
```
|
||||
|
||||
## System Information
|
||||
|
||||
### system.list_commands()
|
||||
### system.listCommands()
|
||||
Lists all available commands.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local commands = system.list_commands()
|
||||
local commands = system.listCommands()
|
||||
for name, def in pairs(commands) do
|
||||
print(name .. ": " .. def.description)
|
||||
end
|
||||
```
|
||||
|
||||
### system.list_syscalls()
|
||||
### system.listSyscalls()
|
||||
Lists all available syscalls.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local syscalls = system.list_syscalls()
|
||||
local syscalls = system.listSyscalls()
|
||||
for _, syscall in ipairs(syscalls) do
|
||||
print(syscall.name)
|
||||
end
|
||||
```
|
||||
|
||||
### system.get_env()
|
||||
### system.getEnv()
|
||||
Returns the runtime environment ("server", "client", or undefined for hybrid).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local env = system.get_env()
|
||||
local env = system.getEnv()
|
||||
print("Running in environment: " .. (env or "hybrid"))
|
||||
```
|
||||
|
||||
### system.get_mode()
|
||||
### system.getMode()
|
||||
Returns the current mode of the system ("ro" or "rw").
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local mode = system.get_mode()
|
||||
local mode = system.getMode()
|
||||
print("System mode: " .. mode)
|
||||
```
|
||||
|
||||
### system.get_version()
|
||||
### system.getVersion()
|
||||
Returns the SilverBullet version.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local version = system.get_version()
|
||||
local version = system.getVersion()
|
||||
print("SilverBullet version: " .. version)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### system.get_space_config(key, default_value)
|
||||
### system.getSpaceConfig(key, defaultValue)
|
||||
Loads space configuration values.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
-- Get specific config value
|
||||
local value = system.get_space_config("theme", "light")
|
||||
local value = system.getSpaceConfig("theme", "light")
|
||||
|
||||
-- Get all config values
|
||||
local config = system.get_space_config()
|
||||
local config = system.getSpaceConfig()
|
||||
for key, value in pairs(config) do
|
||||
print(key .. ": " .. value)
|
||||
end
|
||||
```
|
||||
|
||||
### system.reload_config()
|
||||
### system.reloadConfig()
|
||||
Triggers an explicit reload of the configuration.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local new_config = system.reload_config()
|
||||
system.reloadConfig()
|
||||
print("Configuration reloaded")
|
||||
```
|
||||
|
||||
### system.reload_plugs()
|
||||
### system.reloadPlugs()
|
||||
Triggers a reload of all plugs.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
system.reload_plugs()
|
||||
system.reloadPlugs()
|
||||
print("All plugs reloaded")
|
||||
```
|
|
@ -8,10 +8,10 @@ Example:
|
|||
```space-lua
|
||||
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)
|
||||
Iterates over a collection and renders a template for each item.
|
||||
|
@ -20,4 +20,4 @@ Example:
|
|||
|
||||
${template.each(query[[from index.tag "page" limit 3]], template.new[==[
|
||||
* ${name}
|
||||
]==])}
|
||||
]==])}
|
||||
|
|
|
@ -29,6 +29,6 @@ local data = {
|
|||
hobbies = {"reading", "hiking"}
|
||||
}
|
||||
|
||||
local yaml_text = yaml.stringify(data)
|
||||
print(yaml_text)
|
||||
```
|
||||
local yamlText = yaml.stringify(data)
|
||||
print(yamlText)
|
||||
```
|
||||
|
|
|
@ -5,6 +5,7 @@ An attempt at documenting the changes/new features introduced in each release.
|
|||
## 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._
|
||||
|
||||
* **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))
|
||||
|
||||
## 0.10.1
|
||||
|
@ -405,4 +406,3 @@ Other notable changes:
|
|||
* [BLOCKED] A task that’s blocked
|
||||
[[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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
* (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.
|
||||
|
||||
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!
|
||||
|
||||
## Commands
|
||||
Custom commands can be defined using `command.define`:
|
||||
Custom commands can be defined using [[API/command#command.define(commandDef)]]:
|
||||
|
||||
```space-lua
|
||||
command.define {
|
||||
name = "Hello World",
|
||||
run = function()
|
||||
editor.flash_notification "Hello world!"
|
||||
editor.flashNotification "Hello world!"
|
||||
event.dispatch("my-custom-event", {name="Pete"})
|
||||
end
|
||||
}
|
||||
|
@ -116,13 +116,13 @@ command.define {
|
|||
Try it: {[Hello World]}
|
||||
|
||||
## Event listeners
|
||||
You can listen to events using `event.listen`:
|
||||
You can listen to events using [[API/event#event.listen(listenerDef)]]:
|
||||
|
||||
```space-lua
|
||||
event.listen {
|
||||
name = "my-custom-event";
|
||||
run = function(e)
|
||||
editor.flash_notification("Custom triggered: "
|
||||
editor.flashNotification("Custom triggered: "
|
||||
.. e.data.name)
|
||||
end
|
||||
}
|
||||
|
@ -135,64 +135,20 @@ Space Lua currently introduces a few new features on top core Lua:
|
|||
2. 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._GLOBAL` providing access to the global scope
|
||||
|
||||
# API
|
||||
Lua APIs, which should be (roughly) implemented according to the Lua standard.
|
||||
* `print`
|
||||
* `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).
|
||||
All of these are available via the global namespace:
|
||||
${template.each(query[[from index.tag "page" where string.startswith(name, "API/")]], templates.pageItem)}
|
||||
|
||||
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
|
||||
local function call_some_things()
|
||||
local text = space.read_page(editor.get_current_page())
|
||||
local function callSomeThings()
|
||||
local text = space.readPage(editor.getCurrentPage())
|
||||
print("Current page text", text)
|
||||
end
|
||||
```
|
||||
|
@ -210,4 +166,4 @@ Space Lua is intended to be a more or less complete implementation of [Lua 5.4](
|
|||
Lua is purpose-designed to be a simple, [easy to learn](https://www.lua.org/manual/5.4/), yet powerful language for extending existing applications. It is commonly used in the gaming industry, but to extend many other applications. If you know any other programming language, you will be able to learn Lua within hours or less.
|
||||
|
||||
## Why a custom Lua runtime?
|
||||
Rather than using a WebAssembly or other implementation of Lua that could run in the browser and server, we have opted for a custom implementation. This is achievable because Lua is a relatively simple and small language to implement and allows for deep integration in the custom Lua runtime. The thing that triggered a custom implementation was the need to call asynchronous (JavaScipt) APIs from Lua, without having to resort to ugly asynchronous callback-style API design (Lua does not support async-await). In SilverBullet’s Lua implementation, the differences between asynchronous and synchronous APIs is fully abstracted away, which makes for a very clean development experience.
|
||||
Rather than using a WebAssembly or other implementation of Lua that could run in the browser and server, we have opted for a custom implementation. This is achievable because Lua is a relatively simple and small language to implement and allows for deep integration in the custom Lua runtime. The thing that triggered a custom implementation was the need to call asynchronous (JavaScipt) APIs from Lua, without having to resort to ugly asynchronous callback-style API design (Lua does not support async-await). In SilverBullet’s Lua implementation, the differences between asynchronous and synchronous APIs is fully abstracted away, which makes for a very clean development experience.
|
||||
|
|
Loading…
Reference in New Issue