From a169406d3721f4f75933a034a9a18c038b24cbca Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Thu, 6 Feb 2025 10:04:45 +0100 Subject: [PATCH] Lua: huge API breaking change: converted all snake_case APIs to camelCase --- common/space_lua/eval.test.ts | 4 +- common/space_lua/stdlib.ts | 4 +- common/space_lua/stdlib/js.ts | 2 +- common/space_lua/stdlib/math.md | 4 +- common/space_lua/stdlib/math.ts | 4 +- common/space_lua/stdlib/math_test.lua | 58 +++---- common/space_lua/stdlib/space_lua.ts | 8 +- common/space_lua/stdlib/space_lua_test.lua | 17 +- common/space_lua/stdlib/string.ts | 8 +- common/space_lua/stdlib/string_test.lua | 76 ++++----- common/space_lua_api.ts | 10 +- common/syscalls/command.ts | 2 +- common/syscalls/index.ts | 2 +- plugs/core/Library/Std/Config.md | 15 +- plugs/core/Library/Std/Lua.md | 67 ++++---- plugs/core/Library/Std/Query Templates.md | 12 +- plugs/core/Library/Std/Template.md | 33 ++-- web/cm_plugins/lua_directive.ts | 2 +- web/cm_plugins/lua_widget.ts | 4 +- website/API.md | 2 +- website/API/clientStore.md | 1 - website/API/command.md | 16 +- website/API/datastore.md | 15 +- website/API/debug.md | 5 +- website/API/editor.md | 188 ++++++--------------- website/API/event.md | 15 +- website/API/index.md | 13 +- website/API/js.md | 29 ++-- website/API/jsonschema.md | 9 +- website/API/language.md | 8 +- website/API/markdown.md | 11 +- website/API/mq.md | 13 +- website/API/space.md | 63 ++++--- website/API/space_lua.md | 21 --- website/API/spacelua.md | 21 +++ website/API/sync.md | 17 +- website/API/system.md | 47 +++--- website/API/template.md | 6 +- website/API/yaml.md | 6 +- website/CHANGELOG.md | 2 +- website/Library/Lua API/OpenAI.md | 70 -------- website/Space Lua.md | 66 ++------ 42 files changed, 377 insertions(+), 599 deletions(-) delete mode 100644 website/API/space_lua.md create mode 100644 website/API/spacelua.md delete mode 100644 website/Library/Lua API/OpenAI.md diff --git a/common/space_lua/eval.test.ts b/common/space_lua/eval.test.ts index 6d20be78..c518b7d5 100644 --- a/common/space_lua/eval.test.ts +++ b/common/space_lua/eval.test.ts @@ -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, ), diff --git a/common/space_lua/stdlib.ts b/common/space_lua/stdlib.ts index a993f7fd..b9b6ad9a 100644 --- a/common/space_lua/stdlib.ts +++ b/common/space_lua/stdlib.ts @@ -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; } diff --git a/common/space_lua/stdlib/js.ts b/common/space_lua/stdlib/js.ts index c812b294..1b96412a 100644 --- a/common/space_lua/stdlib/js.ts +++ b/common/space_lua/stdlib/js.ts @@ -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(); diff --git a/common/space_lua/stdlib/math.md b/common/space_lua/stdlib/math.md index f8a5eee6..c4196a52 100644 --- a/common/space_lua/stdlib/math.md +++ b/common/space_lua/stdlib/math.md @@ -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 ``` diff --git a/common/space_lua/stdlib/math.ts b/common/space_lua/stdlib/math.ts index a2db14a3..8ad44235 100644 --- a/common/space_lua/stdlib/math.ts +++ b/common/space_lua/stdlib/math.ts @@ -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) { diff --git a/common/space_lua/stdlib/math_test.lua b/common/space_lua/stdlib/math_test.lua index 8996180a..ac06e240 100644 --- a/common/space_lua/stdlib/math_test.lua +++ b/common/space_lua/stdlib/math_test.lua @@ -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) diff --git a/common/space_lua/stdlib/space_lua.ts b/common/space_lua/stdlib/space_lua.ts index 4e3cfdce..0c221182 100644 --- a/common/space_lua/stdlib/space_lua.ts +++ b/common/space_lua/stdlib/space_lua.ts @@ -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") { diff --git a/common/space_lua/stdlib/space_lua_test.lua b/common/space_lua/stdlib/space_lua_test.lua index 3775e246..660e42d1 100644 --- a/common/space_lua/stdlib/space_lua_test.lua +++ b/common/space_lua/stdlib/space_lua_test.lua @@ -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") \ No newline at end of file +local parsedExpr = spacelua.parseExpression("tostring(a + 1)") +local evalResult = spacelua.evalExpression(parsedExpr, { a = 1 }) +assert(evalResult == "2", "Eval should return 2 as a string") diff --git a/common/space_lua/stdlib/string.ts b/common/space_lua/stdlib/string.ts index b00e3281..c3333d22 100644 --- a/common/space_lua/stdlib/string.ts +++ b/common/space_lua/stdlib/string.ts @@ -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); diff --git a/common/space_lua/stdlib/string_test.lua b/common/space_lua/stdlib/string_test.lua index fbe3d57a..0a532bf3 100644 --- a/common/space_lua/stdlib/string_test.lua +++ b/common/space_lua/stdlib/string_test.lua @@ -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") diff --git a/common/space_lua_api.ts b/common/space_lua_api.ts index ff32ed7d..71190a22 100644 --- a/common/space_lua_api.ts +++ b/common/space_lua_api.ts @@ -34,9 +34,7 @@ function exposeSyscalls(env: LuaEnv, system: System) { 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) { 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) { ]); } } - -function snakeCase(s: string) { - return s.replace(/([A-Z])/g, "_$1").toLowerCase(); -} diff --git a/common/syscalls/command.ts b/common/syscalls/command.ts index 6cd6e2d2..744d5b96 100644 --- a/common/syscalls/command.ts +++ b/common/syscalls/command.ts @@ -46,7 +46,7 @@ export function commandSyscalls( }, ); }, - "slash_command.define": ( + "slashcommand.define": ( _ctx, def: CallbackCommandDef, ) => { diff --git a/common/syscalls/index.ts b/common/syscalls/index.ts index c9dbb55f..4fa012db 100644 --- a/common/syscalls/index.ts +++ b/common/syscalls/index.ts @@ -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", diff --git a/plugs/core/Library/Std/Config.md b/plugs/core/Library/Std/Config.md index d551ddb7..907485d7 100644 --- a/plugs/core/Library/Std/Config.md +++ b/plugs/core/Library/Std/Config.md @@ -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 -``` \ No newline at end of file diff --git a/plugs/core/Library/Std/Lua.md b/plugs/core/Library/Std/Lua.md index e3c51e67..56b30116 100644 --- a/plugs/core/Library/Std/Lua.md +++ b/plugs/core/Library/Std/Lua.md @@ -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 } -``` diff --git a/plugs/core/Library/Std/Query Templates.md b/plugs/core/Library/Std/Query Templates.md index 474ff454..d62eb629 100644 --- a/plugs/core/Library/Std/Query Templates.md +++ b/plugs/core/Library/Std/Query Templates.md @@ -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)} diff --git a/plugs/core/Library/Std/Template.md b/plugs/core/Library/Std/Template.md index 6e289562..1a649e56 100644 --- a/plugs/core/Library/Std/Template.md +++ b/plugs/core/Library/Std/Template.md @@ -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 -``` diff --git a/web/cm_plugins/lua_directive.ts b/web/cm_plugins/lua_directive.ts index f21b9a8f..9b0806af 100644 --- a/web/cm_plugins/lua_directive.ts +++ b/web/cm_plugins/lua_directive.ts @@ -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 diff --git a/web/cm_plugins/lua_widget.ts b/web/cm_plugins/lua_widget.ts index 9ca1c5da..bdfe4058 100644 --- a/web/cm_plugins/lua_widget.ts +++ b/web/cm_plugins/lua_widget.ts @@ -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( diff --git a/website/API.md b/website/API.md index bcf592f5..41cfb02b 100644 --- a/website/API.md +++ b/website/API.md @@ -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)} \ No newline at end of file +]], templates.pageItem)} \ No newline at end of file diff --git a/website/API/clientStore.md b/website/API/clientStore.md index c9fd2527..921f4178 100644 --- a/website/API/clientStore.md +++ b/website/API/clientStore.md @@ -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. diff --git a/website/API/command.md b/website/API/command.md index 334d537c..243c05bc 100644 --- a/website/API/command.md +++ b/website/API/command.md @@ -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 } -``` diff --git a/website/API/datastore.md b/website/API/datastore.md index ac7435cb..85db7f82 100644 --- a/website/API/datastore.md +++ b/website/API/datastore.md @@ -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) diff --git a/website/API/debug.md b/website/API/debug.md index 52d36775..aa3c2e97 100644 --- a/website/API/debug.md +++ b/website/API/debug.md @@ -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") -``` \ No newline at end of file diff --git a/website/API/editor.md b/website/API/editor.md index 1f103363..083cdcdc 100644 --- a/website/API/editor.md +++ b/website/API/editor.md @@ -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, "

Hello

") +editor.showPanel("rhs", 1, "

Hello

") ``` -### 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() diff --git a/website/API/event.md b/website/API/event.md index a8801fbf..a4b327c6 100644 --- a/website/API/event.md +++ b/website/API/event.md @@ -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 -``` \ No newline at end of file diff --git a/website/API/index.md b/website/API/index.md index c71108d9..daae7b32 100644 --- a/website/API/index.md +++ b/website/API/index.md @@ -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 -``` diff --git a/website/API/js.md b/website/API/js.md index 87e6b16a..7a556111 100644 --- a/website/API/js.md +++ b/website/API/js.md @@ -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 -``` \ No newline at end of file diff --git a/website/API/jsonschema.md b/website/API/jsonschema.md index 09091c06..34628c8b 100644 --- a/website/API/jsonschema.md +++ b/website/API/jsonschema.md @@ -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 -``` \ No newline at end of file diff --git a/website/API/language.md b/website/API/language.md index c16e1214..073f15c7 100644 --- a/website/API/language.md +++ b/website/API/language.md @@ -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()} \ No newline at end of file +${language.listLanguages()} diff --git a/website/API/markdown.md b/website/API/markdown.md index 579e91a9..a05e8f69 100644 --- a/website/API/markdown.md +++ b/website/API/markdown.md @@ -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) -``` \ No newline at end of file diff --git a/website/API/mq.md b/website/API/mq.md index 75f6d235..24a9b7ee 100644 --- a/website/API/mq.md +++ b/website/API/mq.md @@ -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) -``` \ No newline at end of file diff --git a/website/API/space.md b/website/API/space.md index a6839c87..6cb93022 100644 --- a/website/API/space.md +++ b/website/API/space.md @@ -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 -``` diff --git a/website/API/space_lua.md b/website/API/space_lua.md deleted file mode 100644 index d6878636..00000000 --- a/website/API/space_lua.md +++ /dev/null @@ -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"})} \ No newline at end of file diff --git a/website/API/spacelua.md b/website/API/spacelua.md new file mode 100644 index 00000000..f94fb067 --- /dev/null +++ b/website/API/spacelua.md @@ -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"})} diff --git a/website/API/sync.md b/website/API/sync.md index 2421ee7b..ac9eaf49 100644 --- a/website/API/sync.md +++ b/website/API/sync.md @@ -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) -``` \ No newline at end of file diff --git a/website/API/system.md b/website/API/system.md index 5a2b5c6b..2aa6a42c 100644 --- a/website/API/system.md +++ b/website/API/system.md @@ -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") -``` \ No newline at end of file diff --git a/website/API/template.md b/website/API/template.md index 9dbab9b0..90c85dbe 100644 --- a/website/API/template.md +++ b/website/API/template.md @@ -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} -]==])} \ No newline at end of file +]==])} diff --git a/website/API/yaml.md b/website/API/yaml.md index a092071c..70dbfaed 100644 --- a/website/API/yaml.md +++ b/website/API/yaml.md @@ -29,6 +29,6 @@ local data = { hobbies = {"reading", "hiking"} } -local yaml_text = yaml.stringify(data) -print(yaml_text) -``` \ No newline at end of file +local yamlText = yaml.stringify(data) +print(yamlText) +``` diff --git a/website/CHANGELOG.md b/website/CHANGELOG.md index 8839a76a..0fed1603 100644 --- a/website/CHANGELOG.md +++ b/website/CHANGELOG.md @@ -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. - diff --git a/website/Library/Lua API/OpenAI.md b/website/Library/Lua API/OpenAI.md deleted file mode 100644 index 76240144..00000000 --- a/website/Library/Lua API/OpenAI.md +++ /dev/null @@ -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 - -``` diff --git a/website/Space Lua.md b/website/Space Lua.md index 7abf8c04..da3a957f 100644 --- a/website/Space Lua.md +++ b/website/Space Lua.md @@ -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. \ No newline at end of file +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.