From 64e398fd90c4a6a339e15aced2a7a6046c8602bf Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Fri, 11 Oct 2024 15:34:27 +0200 Subject: [PATCH] deno fmt --- .gitpod.yml | 5 +- .vscode/settings.json | 3 +- cmd/test/test_plug_run.plug.yaml | 6 +- common/space_lua.ts | 75 ++--------- common/space_lua/language.test.ts | 58 ++++----- common/space_lua/runtime.test.ts | 74 +++++------ common/space_lua/runtime.ts | 6 +- common/space_lua/stdlib.ts | 180 +++++++++++++-------------- common/space_lua/stdlib/js.ts | 56 ++++----- common/space_lua/stdlib/os.ts | 191 ++++++++++++++-------------- common/space_lua/stdlib/string.ts | 200 +++++++++++++++--------------- common/space_lua/stdlib/table.ts | 62 ++++----- common/space_lua_api.ts | 91 ++++++++++++++ common/syscalls/lua.ts | 10 +- plug-api/syscalls/lua.ts | 4 +- plugs/core/core.plug.yaml | 2 +- plugs/index/index.plug.yaml | 4 +- plugs/search/search.plug.yaml | 8 +- plugs/share/share.plug.yaml | 10 +- plugs/sync/sync.plug.yaml | 1 - plugs/tasks/tasks.plug.yaml | 6 +- web/auth.html | 200 +++++++++++++++++------------- web/client.ts | 3 +- web/index.html | 147 +++++++++++----------- web/styles/colors.scss | 12 +- web/styles/editor.scss | 14 +-- web/styles/main.scss | 5 +- web/styles/theme.scss | 22 ++-- 28 files changed, 771 insertions(+), 684 deletions(-) create mode 100644 common/space_lua_api.ts diff --git a/.gitpod.yml b/.gitpod.yml index 319e9ea4..4fc471ce 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,3 @@ - image: file: .gitpod.Dockerfile @@ -20,7 +19,7 @@ tasks: deno task install gp sync-done setup - name: Server watcher - init: | + init: | gp sync-await setup mkdir pages command: deno task watch-server pages @@ -33,4 +32,4 @@ tasks: vscode: extensions: - - denoland.vscode-deno \ No newline at end of file + - denoland.vscode-deno diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ff58e63..392ee26e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,5 +14,6 @@ }, "[typescript]": { "editor.defaultFormatter": "denoland.vscode-deno" - } + }, + "editor.tabSize": 2 } diff --git a/cmd/test/test_plug_run.plug.yaml b/cmd/test/test_plug_run.plug.yaml index 1f7a0680..696c0961 100644 --- a/cmd/test/test_plug_run.plug.yaml +++ b/cmd/test/test_plug_run.plug.yaml @@ -1,6 +1,6 @@ name: test requiredPermissions: -- shell + - shell functions: - run: - path: plug_test.ts:run + run: + path: plug_test.ts:run diff --git a/common/space_lua.ts b/common/space_lua.ts index ec7db0b9..6f140fd8 100644 --- a/common/space_lua.ts +++ b/common/space_lua.ts @@ -6,7 +6,6 @@ import { LuaNativeJSFunction, LuaRuntimeError, } from "$common/space_lua/runtime.ts"; -import { luaBuildStandardEnv } from "$common/space_lua/stdlib.ts"; import { parse as parseLua } from "$common/space_lua/parse.ts"; import { evalStatement } from "$common/space_lua/eval.ts"; import { jsToLuaValue } from "$common/space_lua/runtime.ts"; @@ -19,6 +18,9 @@ import { import type { ScriptEnvironment } from "$common/space_script.ts"; import { luaValueToJS } from "$common/space_lua/runtime.ts"; import type { ASTCtx } from "$common/space_lua/ast.ts"; +import { lua } from "@silverbulletmd/silverbullet/syscalls"; +import type { ObjectQuery } from "@silverbulletmd/silverbullet/types"; +import { buildLuaEnv } from "$common/space_lua_api.ts"; export class SpaceLuaEnvironment { env: LuaEnv = new LuaEnv(); @@ -30,71 +32,17 @@ export class SpaceLuaEnvironment { async reload(system: System, scriptEnv: ScriptEnvironment) { const allScripts: ScriptObject[] = await system.invokeFunction( "index.queryObjects", - ["space-lua", {}], + ["space-lua", { + // This is a bit silly, but at least makes the order deterministic + orderBy: [{ expr: ["attr", "ref"] }], + } as ObjectQuery], ); - // We start from scratch - this.env = new LuaEnv(luaBuildStandardEnv()); - const env = this.env; - - // Expose all syscalls to Lua - for (const syscallName of system.registeredSyscalls.keys()) { - const [ns, fn] = syscallName.split("."); - if (!env.get(ns)) { - env.set(ns, new LuaTable()); - } - env.get(ns).set( - fn, - new LuaNativeJSFunction((...args) => { - return system.localSyscall(syscallName, args); - }), - ); - } - env.set( - "command", - new LuaBuiltinFunction( - (def: LuaTable) => { - if (def.get(1) === undefined) { - throw new Error("Callback is required"); - } - console.log("Registering Lua command", def.get("name")); - scriptEnv.registerCommand( - def.toJSObject() as any, - async (...args: any[]) => { - try { - return await def.get(1).call(...args.map(jsToLuaValue)); - } catch (e: any) { - console.error("Lua eval exception", e.message, e.context); - if (e.context && e.context.ref) { - // We got an error and actually know where it came from, let's navigate there to help debugging - const pageRef = parsePageRef(e.context.ref); - await system.localSyscall("editor.flashNotification", [ - `Lua error: ${e.message}`, - "error", - ]); - await system.localSyscall("editor.flashNotification", [ - `Navigating to the place in the code where this error occurred in ${pageRef.page}`, - "info", - ]); - await system.localSyscall("editor.navigate", [ - { - page: pageRef.page, - pos: pageRef.pos + e.context.from + - "```space-lua\n".length, - }, - ]); - } - } - }, - ); - }, - ), - ); - + this.env = buildLuaEnv(system, scriptEnv); for (const script of allScripts) { try { const ast = parseLua(script.script, { ref: script.ref }); // We create a local scope for each script - const scriptEnv = new LuaEnv(env); + const scriptEnv = new LuaEnv(this.env); await evalStatement(ast, scriptEnv); } catch (e: any) { if (e instanceof LuaRuntimeError) { @@ -111,9 +59,10 @@ export class SpaceLuaEnvironment { ); } } + // Find all functions and register them - for (const globalName of env.keys()) { - const value = env.get(globalName); + for (const globalName of this.env.keys()) { + const value = this.env.get(globalName); if (value instanceof LuaFunction) { console.log("Now registering Lua function", globalName); scriptEnv.registerFunction({ name: globalName }, (...args: any[]) => { diff --git a/common/space_lua/language.test.ts b/common/space_lua/language.test.ts index b7f191dc..698287b5 100644 --- a/common/space_lua/language.test.ts +++ b/common/space_lua/language.test.ts @@ -5,38 +5,38 @@ import { evalStatement } from "$common/space_lua/eval.ts"; import { assert } from "@std/assert/assert"; Deno.test("Lua language tests", async () => { - // Read the Lua file - const luaFile = await Deno.readTextFile( - new URL("./language_test.lua", import.meta.url).pathname, - ); - const chunk = parse(luaFile, {}); - const env = new LuaEnv(luaBuildStandardEnv()); + // Read the Lua file + const luaFile = await Deno.readTextFile( + new URL("./language_test.lua", import.meta.url).pathname, + ); + const chunk = parse(luaFile, {}); + const env = new LuaEnv(luaBuildStandardEnv()); - try { - await evalStatement(chunk, env); - } catch (e: any) { - console.error(`Error evaluating script:`, toPrettyString(e, luaFile)); - assert(false); - } + try { + await evalStatement(chunk, env); + } catch (e: any) { + console.error(`Error evaluating script:`, toPrettyString(e, luaFile)); + assert(false); + } }); function toPrettyString(err: LuaRuntimeError, code: string): string { - if (!err.context || !err.context.from || !err.context.to) { - return err.toString(); + if (!err.context || !err.context.from || !err.context.to) { + return err.toString(); + } + const from = err.context.from; + // Find the line and column + let line = 1; + let column = 0; + for (let i = 0; i < from; i++) { + if (code[i] === "\n") { + line++; + column = 0; + } else { + column++; } - const from = err.context.from; - // Find the line and column - let line = 1; - let column = 0; - for (let i = 0; i < from; i++) { - if (code[i] === "\n") { - line++; - column = 0; - } else { - column++; - } - } - return `LuaRuntimeError: ${err.message} at ${line}:${column}:\n ${ - code.substring(from, err.context.to) - }`; + } + return `LuaRuntimeError: ${err.message} at ${line}:${column}:\n ${ + code.substring(from, err.context.to) + }`; } diff --git a/common/space_lua/runtime.test.ts b/common/space_lua/runtime.test.ts index 2caf5f11..fdefe30f 100644 --- a/common/space_lua/runtime.test.ts +++ b/common/space_lua/runtime.test.ts @@ -1,44 +1,44 @@ import { assertEquals } from "@std/assert/equals"; import { - jsToLuaValue, - luaLen, - LuaMultiRes, + jsToLuaValue, + luaLen, + LuaMultiRes, } from "$common/space_lua/runtime.ts"; Deno.test("Test Lua Rutime", () => { - // Test LuaMultires - assertEquals(new LuaMultiRes([]).flatten().values, []); - assertEquals(new LuaMultiRes([1, 2, 3]).flatten().values, [1, 2, 3]); - assertEquals( - new LuaMultiRes([1, new LuaMultiRes([2, 3])]).flatten().values, - [ - 1, - 2, - 3, - ], - ); + // Test LuaMultires + assertEquals(new LuaMultiRes([]).flatten().values, []); + assertEquals(new LuaMultiRes([1, 2, 3]).flatten().values, [1, 2, 3]); + assertEquals( + new LuaMultiRes([1, new LuaMultiRes([2, 3])]).flatten().values, + [ + 1, + 2, + 3, + ], + ); - // Test JavaScript to Lua conversion - assertEquals(jsToLuaValue(1), 1); - assertEquals(jsToLuaValue("hello"), "hello"); - // Arrays - let luaVal = jsToLuaValue([1, 2, 3]); - assertEquals(luaLen(luaVal), 3); - assertEquals(luaVal.get(1), 1); - // Objects - luaVal = jsToLuaValue({ name: "Pete", age: 10 }); - assertEquals(luaVal.get("name"), "Pete"); - assertEquals(luaVal.get("age"), 10); - // Nested objects - luaVal = jsToLuaValue({ name: "Pete", list: [1, 2, 3] }); - assertEquals(luaVal.get("name"), "Pete"); - assertEquals(luaLen(luaVal.get("list")), 3); - assertEquals(luaVal.get("list").get(2), 2); - luaVal = jsToLuaValue([{ name: "Pete" }, { name: "John" }]); - assertEquals(luaLen(luaVal), 2); - assertEquals(luaVal.get(1).get("name"), "Pete"); - assertEquals(luaVal.get(2).get("name"), "John"); - // Functions in objects - luaVal = jsToLuaValue({ name: "Pete", first: (l: any[]) => l[0] }); - assertEquals(luaVal.get("first").call([1, 2, 3]), 1); + // Test JavaScript to Lua conversion + assertEquals(jsToLuaValue(1), 1); + assertEquals(jsToLuaValue("hello"), "hello"); + // Arrays + let luaVal = jsToLuaValue([1, 2, 3]); + assertEquals(luaLen(luaVal), 3); + assertEquals(luaVal.get(1), 1); + // Objects + luaVal = jsToLuaValue({ name: "Pete", age: 10 }); + assertEquals(luaVal.get("name"), "Pete"); + assertEquals(luaVal.get("age"), 10); + // Nested objects + luaVal = jsToLuaValue({ name: "Pete", list: [1, 2, 3] }); + assertEquals(luaVal.get("name"), "Pete"); + assertEquals(luaLen(luaVal.get("list")), 3); + assertEquals(luaVal.get("list").get(2), 2); + luaVal = jsToLuaValue([{ name: "Pete" }, { name: "John" }]); + assertEquals(luaLen(luaVal), 2); + assertEquals(luaVal.get(1).get("name"), "Pete"); + assertEquals(luaVal.get(2).get("name"), "John"); + // Functions in objects + luaVal = jsToLuaValue({ name: "Pete", first: (l: any[]) => l[0] }); + assertEquals(luaVal.get("first").call([1, 2, 3]), 1); }); diff --git a/common/space_lua/runtime.ts b/common/space_lua/runtime.ts index 0b363c18..ec0261fe 100644 --- a/common/space_lua/runtime.ts +++ b/common/space_lua/runtime.ts @@ -295,7 +295,7 @@ export class LuaTable implements ILuaSettable, ILuaGettable { } } - toJSObject(): Record { + asJSObject(): Record { const result: Record = {}; for (const key of this.keys()) { result[key] = luaValueToJS(this.get(key)); @@ -303,6 +303,10 @@ export class LuaTable implements ILuaSettable, ILuaGettable { return result; } + asJSArray(): any[] { + return this.arrayPart.map(luaValueToJS); + } + toString(): string { if (this.metatable?.has("__tostring")) { const metaValue = this.metatable.get("__tostring"); diff --git a/common/space_lua/stdlib.ts b/common/space_lua/stdlib.ts index 80d04904..e44a5d14 100644 --- a/common/space_lua/stdlib.ts +++ b/common/space_lua/stdlib.ts @@ -1,12 +1,12 @@ import { - type ILuaFunction, - LuaBuiltinFunction, - LuaEnv, - LuaMultiRes, - type LuaTable, - luaToString, - luaTypeOf, - type LuaValue, + type ILuaFunction, + LuaBuiltinFunction, + LuaEnv, + LuaMultiRes, + type LuaTable, + luaToString, + luaTypeOf, + type LuaValue, } from "$common/space_lua/runtime.ts"; import { stringApi } from "$common/space_lua/stdlib/string.ts"; import { tableApi } from "$common/space_lua/stdlib/table.ts"; @@ -14,129 +14,129 @@ import { osApi } from "$common/space_lua/stdlib/os.ts"; import { jsApi } from "$common/space_lua/stdlib/js.ts"; const printFunction = new LuaBuiltinFunction((...args) => { - console.log("[Lua]", ...args.map(luaToString)); + console.log("[Lua]", ...args.map(luaToString)); }); const assertFunction = new LuaBuiltinFunction( - async (value: any, message?: string) => { - if (!await value) { - throw new Error(`Assertion failed: ${message}`); - } - }, + async (value: any, message?: string) => { + if (!await value) { + throw new Error(`Assertion failed: ${message}`); + } + }, ); const ipairsFunction = new LuaBuiltinFunction((ar: LuaTable) => { - let i = 1; - return () => { - if (i > ar.length) { - return; - } - const result = new LuaMultiRes([i, ar.get(i)]); - i++; - return result; - }; + let i = 1; + return () => { + if (i > ar.length) { + return; + } + const result = new LuaMultiRes([i, ar.get(i)]); + i++; + return result; + }; }); const pairsFunction = new LuaBuiltinFunction((t: LuaTable) => { - const keys = t.keys(); - let i = 0; - return () => { - if (i >= keys.length) { - return; - } - const key = keys[i]; - i++; - return new LuaMultiRes([key, t.get(key)]); - }; + const keys = t.keys(); + let i = 0; + return () => { + if (i >= keys.length) { + return; + } + const key = keys[i]; + i++; + return new LuaMultiRes([key, t.get(key)]); + }; }); const unpackFunction = new LuaBuiltinFunction((t: LuaTable) => { - const values: LuaValue[] = []; - for (let i = 1; i <= t.length; i++) { - values.push(t.get(i)); - } - return new LuaMultiRes(values); + const values: LuaValue[] = []; + for (let i = 1; i <= t.length; i++) { + values.push(t.get(i)); + } + return new LuaMultiRes(values); }); const typeFunction = new LuaBuiltinFunction((value: LuaValue): string => { - return luaTypeOf(value); + return luaTypeOf(value); }); const tostringFunction = new LuaBuiltinFunction((value: any) => { - return luaToString(value); + return luaToString(value); }); const tonumberFunction = new LuaBuiltinFunction((value: LuaValue) => { - return Number(value); + return Number(value); }); const errorFunction = new LuaBuiltinFunction((message: string) => { - throw new Error(message); + throw new Error(message); }); const pcallFunction = new LuaBuiltinFunction( - async (fn: ILuaFunction, ...args) => { - try { - return new LuaMultiRes([true, await fn.call(...args)]); - } catch (e: any) { - return new LuaMultiRes([false, e.message]); - } - }, + async (fn: ILuaFunction, ...args) => { + try { + return new LuaMultiRes([true, await fn.call(...args)]); + } catch (e: any) { + return new LuaMultiRes([false, e.message]); + } + }, ); const xpcallFunction = new LuaBuiltinFunction( - async (fn: ILuaFunction, errorHandler: ILuaFunction, ...args) => { - try { - return new LuaMultiRes([true, await fn.call(...args)]); - } catch (e: any) { - return new LuaMultiRes([false, await errorHandler.call(e.message)]); - } - }, + async (fn: ILuaFunction, errorHandler: ILuaFunction, ...args) => { + try { + return new LuaMultiRes([true, await fn.call(...args)]); + } catch (e: any) { + return new LuaMultiRes([false, await errorHandler.call(e.message)]); + } + }, ); const setmetatableFunction = new LuaBuiltinFunction( - (table: LuaTable, metatable: LuaTable) => { - table.metatable = metatable; - return table; - }, + (table: LuaTable, metatable: LuaTable) => { + table.metatable = metatable; + return table; + }, ); const rawsetFunction = new LuaBuiltinFunction( - (table: LuaTable, key: LuaValue, value: LuaValue) => { - table.rawSet(key, value); - return table; - }, + (table: LuaTable, key: LuaValue, value: LuaValue) => { + table.rawSet(key, value); + return table; + }, ); const getmetatableFunction = new LuaBuiltinFunction((table: LuaTable) => { - return table.metatable; + return table.metatable; }); export function luaBuildStandardEnv() { - const env = new LuaEnv(); - // Top-level builtins - env.set("print", printFunction); - env.set("assert", assertFunction); - env.set("type", typeFunction); - env.set("tostring", tostringFunction); - env.set("tonumber", tonumberFunction); - env.set("unpack", unpackFunction); - // Iterators - env.set("pairs", pairsFunction); - env.set("ipairs", ipairsFunction); - // meta table stuff - env.set("setmetatable", setmetatableFunction); - env.set("getmetatable", getmetatableFunction); - env.set("rawset", rawsetFunction); - // Error handling - env.set("error", errorFunction); - env.set("pcall", pcallFunction); - env.set("xpcall", xpcallFunction); + const env = new LuaEnv(); + // Top-level builtins + env.set("print", printFunction); + env.set("assert", assertFunction); + env.set("type", typeFunction); + env.set("tostring", tostringFunction); + env.set("tonumber", tonumberFunction); + env.set("unpack", unpackFunction); + // Iterators + env.set("pairs", pairsFunction); + env.set("ipairs", ipairsFunction); + // meta table stuff + env.set("setmetatable", setmetatableFunction); + env.set("getmetatable", getmetatableFunction); + env.set("rawset", rawsetFunction); + // Error handling + env.set("error", errorFunction); + env.set("pcall", pcallFunction); + env.set("xpcall", xpcallFunction); - // APIs - env.set("string", stringApi); - env.set("table", tableApi); - env.set("os", osApi); - env.set("js", jsApi); - return env; + // APIs + env.set("string", stringApi); + env.set("table", tableApi); + env.set("os", osApi); + env.set("js", jsApi); + return env; } diff --git a/common/space_lua/stdlib/js.ts b/common/space_lua/stdlib/js.ts index 5c468756..748fe4f3 100644 --- a/common/space_lua/stdlib/js.ts +++ b/common/space_lua/stdlib/js.ts @@ -1,33 +1,33 @@ import { - jsToLuaValue, - LuaBuiltinFunction, - LuaTable, - luaValueToJS, + jsToLuaValue, + LuaBuiltinFunction, + LuaTable, + luaValueToJS, } from "$common/space_lua/runtime.ts"; export const jsApi = new LuaTable({ - new: new LuaBuiltinFunction( - (constructorFn: any, ...args) => { - return new constructorFn( - ...args.map(luaValueToJS), - ); - }, - ), - importModule: new LuaBuiltinFunction((url) => { - return import(url); - }), - /** - * Binds a function to an object, so that the function can be called with the object as `this`. Some JS APIs require this. - */ - bind: new LuaBuiltinFunction((fn: any, obj: any, ...args: any[]) => { - return fn.bind(obj, ...args); - }), - tolua: new LuaBuiltinFunction(jsToLuaValue), - tojs: new LuaBuiltinFunction(luaValueToJS), - log: new LuaBuiltinFunction((...args) => { - console.log(...args); - }), - // assignGlobal: new LuaBuiltinFunction((name: string, value: any) => { - // (globalThis as any)[name] = value; - // }), + new: new LuaBuiltinFunction( + (constructorFn: any, ...args) => { + return new constructorFn( + ...args.map(luaValueToJS), + ); + }, + ), + importModule: new LuaBuiltinFunction((url) => { + return import(url); + }), + /** + * Binds a function to an object, so that the function can be called with the object as `this`. Some JS APIs require this. + */ + bind: new LuaBuiltinFunction((fn: any, obj: any, ...args: any[]) => { + return fn.bind(obj, ...args); + }), + tolua: new LuaBuiltinFunction(jsToLuaValue), + tojs: new LuaBuiltinFunction(luaValueToJS), + log: new LuaBuiltinFunction((...args) => { + console.log(...args); + }), + // assignGlobal: new LuaBuiltinFunction((name: string, value: any) => { + // (globalThis as any)[name] = value; + // }), }); diff --git a/common/space_lua/stdlib/os.ts b/common/space_lua/stdlib/os.ts index b1f7a41f..39ede481 100644 --- a/common/space_lua/stdlib/os.ts +++ b/common/space_lua/stdlib/os.ts @@ -1,103 +1,102 @@ import { LuaBuiltinFunction, LuaTable } from "$common/space_lua/runtime.ts"; export const osApi = new LuaTable({ - time: new LuaBuiltinFunction((tbl?: LuaTable) => { - if (tbl) { - // Build a date object from the table - const date = new Date(); - if (!tbl.has("year")) { - throw new Error("time(): year is required"); - } - date.setFullYear(tbl.get("year")); - if (!tbl.has("month")) { - throw new Error("time(): month is required"); - } - date.setMonth(tbl.get("month") - 1); - if (!tbl.has("day")) { - throw new Error("time(): day is required"); - } - date.setDate(tbl.get("day")); - date.setHours(tbl.get("hour") ?? 12); - date.setMinutes(tbl.get("min") ?? 0); - date.setSeconds(tbl.get("sec") ?? 0); - return Math.floor(date.getTime() / 1000); - } else { - return Math.floor(Date.now() / 1000); - } - }), - /** - * Returns a string or a table containing date and time, formatted according to the given string format. - * If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time. - * If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61, due to leap seconds), wday (weekday, 1–7, Sunday is 1), yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available. - * If format is not "*t", then date returns the date as a string, formatted according to the same rules as the ISO C function strftime. - * If format is absent, it defaults to "%c", which gives a human-readable date and time representation using the current locale. - */ - date: new LuaBuiltinFunction((format: string, timestamp?: number) => { - const date = timestamp ? new Date(timestamp * 1000) : new Date(); + time: new LuaBuiltinFunction((tbl?: LuaTable) => { + if (tbl) { + // Build a date object from the table + const date = new Date(); + if (!tbl.has("year")) { + throw new Error("time(): year is required"); + } + date.setFullYear(tbl.get("year")); + if (!tbl.has("month")) { + throw new Error("time(): month is required"); + } + date.setMonth(tbl.get("month") - 1); + if (!tbl.has("day")) { + throw new Error("time(): day is required"); + } + date.setDate(tbl.get("day")); + date.setHours(tbl.get("hour") ?? 12); + date.setMinutes(tbl.get("min") ?? 0); + date.setSeconds(tbl.get("sec") ?? 0); + return Math.floor(date.getTime() / 1000); + } else { + return Math.floor(Date.now() / 1000); + } + }), + /** + * Returns a string or a table containing date and time, formatted according to the given string format. + * If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time. + * If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61, due to leap seconds), wday (weekday, 1–7, Sunday is 1), yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available. + * If format is not "*t", then date returns the date as a string, formatted according to the same rules as the ISO C function strftime. + * If format is absent, it defaults to "%c", which gives a human-readable date and time representation using the current locale. + */ + date: new LuaBuiltinFunction((format: string, timestamp?: number) => { + const date = timestamp ? new Date(timestamp * 1000) : new Date(); - // Default Lua-like format when no format string is provided - if (!format) { - return date.toDateString() + " " + date.toLocaleTimeString(); - } + // Default Lua-like format when no format string is provided + if (!format) { + return date.toDateString() + " " + date.toLocaleTimeString(); + } - // Define mappings for Lua-style placeholders - const formatMap: { [key: string]: () => string } = { - // Year - "%Y": () => date.getFullYear().toString(), - "%y": () => (date.getFullYear() % 100).toString().padStart(2, "0"), - // Month - "%m": () => (date.getMonth() + 1).toString().padStart(2, "0"), - "%b": () => date.toLocaleString("en-US", { month: "short" }), - "%B": () => date.toLocaleString("en-US", { month: "long" }), - // Day - "%d": () => date.getDate().toString().padStart(2, "0"), - "%e": () => date.getDate().toString(), - // Hour - "%H": () => date.getHours().toString().padStart(2, "0"), - "%I": () => - (date.getHours() % 12 || 12).toString().padStart(2, "0"), - // Minute - "%M": () => date.getMinutes().toString().padStart(2, "0"), - // Second - "%S": () => date.getSeconds().toString().padStart(2, "0"), - // AM/PM - "%p": () => date.getHours() >= 12 ? "PM" : "AM", - // Day of the week - "%A": () => date.toLocaleString("en-US", { weekday: "long" }), - "%a": () => date.toLocaleString("en-US", { weekday: "short" }), - "%w": () => date.getDay().toString(), - // Day of the year - "%j": () => { - const start = new Date(date.getFullYear(), 0, 0); - const diff = date.getTime() - start.getTime(); - const oneDay = 1000 * 60 * 60 * 24; - const dayOfYear = Math.floor(diff / oneDay); - return dayOfYear.toString().padStart(3, "0"); - }, - // Time zone - "%Z": () => { - const match = date.toTimeString().match(/\((.*)\)/); - return match ? match[1] : ""; - }, - "%z": () => { - const offset = -date.getTimezoneOffset(); - const sign = offset >= 0 ? "+" : "-"; - const absOffset = Math.abs(offset); - const hours = Math.floor(absOffset / 60).toString().padStart( - 2, - "0", - ); - const minutes = (absOffset % 60).toString().padStart(2, "0"); - return `${sign}${hours}${minutes}`; - }, - // Literal % - "%%": () => "%", - }; + // Define mappings for Lua-style placeholders + const formatMap: { [key: string]: () => string } = { + // Year + "%Y": () => date.getFullYear().toString(), + "%y": () => (date.getFullYear() % 100).toString().padStart(2, "0"), + // Month + "%m": () => (date.getMonth() + 1).toString().padStart(2, "0"), + "%b": () => date.toLocaleString("en-US", { month: "short" }), + "%B": () => date.toLocaleString("en-US", { month: "long" }), + // Day + "%d": () => date.getDate().toString().padStart(2, "0"), + "%e": () => date.getDate().toString(), + // Hour + "%H": () => date.getHours().toString().padStart(2, "0"), + "%I": () => (date.getHours() % 12 || 12).toString().padStart(2, "0"), + // Minute + "%M": () => date.getMinutes().toString().padStart(2, "0"), + // Second + "%S": () => date.getSeconds().toString().padStart(2, "0"), + // AM/PM + "%p": () => date.getHours() >= 12 ? "PM" : "AM", + // Day of the week + "%A": () => date.toLocaleString("en-US", { weekday: "long" }), + "%a": () => date.toLocaleString("en-US", { weekday: "short" }), + "%w": () => date.getDay().toString(), + // Day of the year + "%j": () => { + const start = new Date(date.getFullYear(), 0, 0); + const diff = date.getTime() - start.getTime(); + const oneDay = 1000 * 60 * 60 * 24; + const dayOfYear = Math.floor(diff / oneDay); + return dayOfYear.toString().padStart(3, "0"); + }, + // Time zone + "%Z": () => { + const match = date.toTimeString().match(/\((.*)\)/); + return match ? match[1] : ""; + }, + "%z": () => { + const offset = -date.getTimezoneOffset(); + const sign = offset >= 0 ? "+" : "-"; + const absOffset = Math.abs(offset); + const hours = Math.floor(absOffset / 60).toString().padStart( + 2, + "0", + ); + const minutes = (absOffset % 60).toString().padStart(2, "0"); + return `${sign}${hours}${minutes}`; + }, + // Literal % + "%%": () => "%", + }; - // Replace format placeholders with corresponding values - return format.replace(/%[A-Za-z%]/g, (match) => { - const formatter = formatMap[match]; - return formatter ? formatter() : match; - }); - }), + // Replace format placeholders with corresponding values + return format.replace(/%[A-Za-z%]/g, (match) => { + const formatter = formatMap[match]; + return formatter ? formatter() : match; + }); + }), }); diff --git a/common/space_lua/stdlib/string.ts b/common/space_lua/stdlib/string.ts index c4ac8503..ae3d1031 100644 --- a/common/space_lua/stdlib/string.ts +++ b/common/space_lua/stdlib/string.ts @@ -1,106 +1,106 @@ import { - LuaBuiltinFunction, - LuaMultiRes, - LuaTable, - luaToString, + LuaBuiltinFunction, + LuaMultiRes, + LuaTable, + luaToString, } from "$common/space_lua/runtime.ts"; export const stringApi = new LuaTable({ - byte: new LuaBuiltinFunction((s: string, i?: number, j?: number) => { - i = i ?? 1; - j = j ?? i; - const result = []; - for (let k = i; k <= j; k++) { - result.push(s.charCodeAt(k - 1)); + byte: new LuaBuiltinFunction((s: string, i?: number, j?: number) => { + i = i ?? 1; + j = j ?? i; + const result = []; + for (let k = i; k <= j; k++) { + result.push(s.charCodeAt(k - 1)); + } + return new LuaMultiRes(result); + }), + char: new LuaBuiltinFunction((...args: number[]) => { + return String.fromCharCode(...args); + }), + find: new LuaBuiltinFunction( + (s: string, pattern: string, init?: number, plain?: boolean) => { + init = init ?? 1; + plain = plain ?? false; + const result = s.slice(init - 1).match(pattern); + if (!result) { + return new LuaMultiRes([]); + } + return new LuaMultiRes([ + result.index! + 1, + result.index! + result[0].length, + ]); + }, + ), + format: new LuaBuiltinFunction((format: string, ...args: any[]) => { + return format.replace(/%./g, (match) => { + switch (match) { + case "%s": + return luaToString(args.shift()); + case "%d": + return String(args.shift()); + default: + return match; + } + }); + }), + gmatch: new LuaBuiltinFunction((s: string, pattern: string) => { + const regex = new RegExp(pattern, "g"); + return () => { + const result = regex.exec(s); + if (!result) { + return; + } + return new LuaMultiRes(result.slice(1)); + }; + }), + gsub: new LuaBuiltinFunction( + (s: string, pattern: string, repl: string, n?: number) => { + n = n ?? Infinity; + const regex = new RegExp(pattern, "g"); + let result = s; + let match: RegExpExecArray | null; + for (let i = 0; i < n; i++) { + match = regex.exec(result); + if (!match) { + break; } - return new LuaMultiRes(result); - }), - char: new LuaBuiltinFunction((...args: number[]) => { - return String.fromCharCode(...args); - }), - find: new LuaBuiltinFunction( - (s: string, pattern: string, init?: number, plain?: boolean) => { - init = init ?? 1; - plain = plain ?? false; - const result = s.slice(init - 1).match(pattern); - if (!result) { - return new LuaMultiRes([]); - } - return new LuaMultiRes([ - result.index! + 1, - result.index! + result[0].length, - ]); - }, - ), - format: new LuaBuiltinFunction((format: string, ...args: any[]) => { - return format.replace(/%./g, (match) => { - switch (match) { - case "%s": - return luaToString(args.shift()); - case "%d": - return String(args.shift()); - default: - return match; - } - }); - }), - gmatch: new LuaBuiltinFunction((s: string, pattern: string) => { - const regex = new RegExp(pattern, "g"); - return () => { - const result = regex.exec(s); - if (!result) { - return; - } - return new LuaMultiRes(result.slice(1)); - }; - }), - gsub: new LuaBuiltinFunction( - (s: string, pattern: string, repl: string, n?: number) => { - n = n ?? Infinity; - const regex = new RegExp(pattern, "g"); - let result = s; - let match: RegExpExecArray | null; - for (let i = 0; i < n; i++) { - match = regex.exec(result); - if (!match) { - break; - } - result = result.replace(match[0], repl); - } - return result; - }, - ), - len: new LuaBuiltinFunction((s: string) => { - return s.length; - }), - lower: new LuaBuiltinFunction((s: string) => { - return luaToString(s.toLowerCase()); - }), - upper: new LuaBuiltinFunction((s: string) => { - return luaToString(s.toUpperCase()); - }), - match: new LuaBuiltinFunction( - (s: string, pattern: string, init?: number) => { - init = init ?? 1; - const result = s.slice(init - 1).match(pattern); - if (!result) { - return new LuaMultiRes([]); - } - return new LuaMultiRes(result.slice(1)); - }, - ), - rep: new LuaBuiltinFunction((s: string, n: number, sep?: string) => { - sep = sep ?? ""; - return s.repeat(n) + sep; - }), - reverse: new LuaBuiltinFunction((s: string) => { - return s.split("").reverse().join(""); - }), - sub: new LuaBuiltinFunction((s: string, i: number, j?: number) => { - j = j ?? s.length; - return s.slice(i - 1, j); - }), - split: new LuaBuiltinFunction((s: string, sep: string) => { - return s.split(sep); - }), + result = result.replace(match[0], repl); + } + return result; + }, + ), + len: new LuaBuiltinFunction((s: string) => { + return s.length; + }), + lower: new LuaBuiltinFunction((s: string) => { + return luaToString(s.toLowerCase()); + }), + upper: new LuaBuiltinFunction((s: string) => { + return luaToString(s.toUpperCase()); + }), + match: new LuaBuiltinFunction( + (s: string, pattern: string, init?: number) => { + init = init ?? 1; + const result = s.slice(init - 1).match(pattern); + if (!result) { + return new LuaMultiRes([]); + } + return new LuaMultiRes(result.slice(1)); + }, + ), + rep: new LuaBuiltinFunction((s: string, n: number, sep?: string) => { + sep = sep ?? ""; + return s.repeat(n) + sep; + }), + reverse: new LuaBuiltinFunction((s: string) => { + return s.split("").reverse().join(""); + }), + sub: new LuaBuiltinFunction((s: string, i: number, j?: number) => { + j = j ?? s.length; + return s.slice(i - 1, j); + }), + split: new LuaBuiltinFunction((s: string, sep: string) => { + return s.split(sep); + }), }); diff --git a/common/space_lua/stdlib/table.ts b/common/space_lua/stdlib/table.ts index 91942b29..b6644c03 100644 --- a/common/space_lua/stdlib/table.ts +++ b/common/space_lua/stdlib/table.ts @@ -1,36 +1,36 @@ import { - type ILuaFunction, - LuaBuiltinFunction, - LuaTable, + type ILuaFunction, + LuaBuiltinFunction, + LuaTable, } from "$common/space_lua/runtime.ts"; export const tableApi = new LuaTable({ - concat: new LuaBuiltinFunction( - (tbl: LuaTable, sep?: string, i?: number, j?: number) => { - sep = sep ?? ""; - i = i ?? 1; - j = j ?? tbl.length; - const result = []; - for (let k = i; k <= j; k++) { - result.push(tbl.get(k)); - } - return result.join(sep); - }, - ), - insert: new LuaBuiltinFunction( - (tbl: LuaTable, posOrValue: number | any, value?: any) => { - if (value === undefined) { - value = posOrValue; - posOrValue = tbl.length + 1; - } - tbl.insert(posOrValue, value); - }, - ), - remove: new LuaBuiltinFunction((tbl: LuaTable, pos?: number) => { - pos = pos ?? tbl.length; - tbl.remove(pos); - }), - sort: new LuaBuiltinFunction((tbl: LuaTable, comp?: ILuaFunction) => { - return tbl.sort(comp); - }), + concat: new LuaBuiltinFunction( + (tbl: LuaTable, sep?: string, i?: number, j?: number) => { + sep = sep ?? ""; + i = i ?? 1; + j = j ?? tbl.length; + const result = []; + for (let k = i; k <= j; k++) { + result.push(tbl.get(k)); + } + return result.join(sep); + }, + ), + insert: new LuaBuiltinFunction( + (tbl: LuaTable, posOrValue: number | any, value?: any) => { + if (value === undefined) { + value = posOrValue; + posOrValue = tbl.length + 1; + } + tbl.insert(posOrValue, value); + }, + ), + remove: new LuaBuiltinFunction((tbl: LuaTable, pos?: number) => { + pos = pos ?? tbl.length; + tbl.remove(pos); + }), + sort: new LuaBuiltinFunction((tbl: LuaTable, comp?: ILuaFunction) => { + return tbl.sort(comp); + }), }); diff --git a/common/space_lua_api.ts b/common/space_lua_api.ts new file mode 100644 index 00000000..14cae352 --- /dev/null +++ b/common/space_lua_api.ts @@ -0,0 +1,91 @@ +import { luaBuildStandardEnv } from "$common/space_lua/stdlib.ts"; +import { parsePageRef } from "@silverbulletmd/silverbullet/lib/page_ref"; +import { + jsToLuaValue, + LuaBuiltinFunction, + LuaEnv, + LuaNativeJSFunction, + LuaTable, +} from "$common/space_lua/runtime.ts"; +import type { System } from "$lib/plugos/system.ts"; +import type { ScriptEnvironment } from "$common/space_script.ts"; + +export function buildLuaEnv(system: System, scriptEnv: ScriptEnvironment) { + const env = new LuaEnv(luaBuildStandardEnv()); + + // Expose all syscalls to Lua + for (const syscallName of system.registeredSyscalls.keys()) { + const [ns, fn] = syscallName.split("."); + if (!env.get(ns)) { + env.set(ns, new LuaTable()); + } + 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).set(fn, luaFn); + env.get(ns).set(snakeCase(fn), luaFn); + } + + // Expose the command registration function to Lua + env.set( + "command", + new LuaBuiltinFunction( + (def: LuaTable) => { + if (def.get(1) === undefined) { + throw new Error("Callback is required"); + } + if (!def.get("name")) { + throw new Error("Name is required"); + } + console.log("Registering Lua command", def.get("name")); + scriptEnv.registerCommand( + def.asJSObject() as any, + async (...args: any[]) => { + try { + return await def.get(1).call( + ...args.map(jsToLuaValue), + ); + } catch (e: any) { + console.error( + "Lua eval exception", + e.message, + e.context, + ); + if (e.context && e.context.ref) { + // We got an error and actually know where it came from, let's navigate there to help debugging + const pageRef = parsePageRef(e.context.ref); + await system.localSyscall( + "editor.flashNotification", + [ + `Lua error: ${e.message}`, + "error", + ], + ); + await system.localSyscall( + "editor.flashNotification", + [ + `Navigating to the place in the code where this error occurred in ${pageRef.page}`, + "info", + ], + ); + await system.localSyscall("editor.navigate", [ + { + page: pageRef.page, + pos: pageRef.pos + e.context.from + + "```space-lua\n".length, + }, + ]); + } + } + }, + ); + }, + ), + ); + return env; +} + +function snakeCase(s: string) { + return s.replace(/([A-Z])/g, "_$1").toLowerCase(); +} diff --git a/common/syscalls/lua.ts b/common/syscalls/lua.ts index bd675e31..f4971e36 100644 --- a/common/syscalls/lua.ts +++ b/common/syscalls/lua.ts @@ -2,9 +2,9 @@ import type { SysCallMapping } from "$lib/plugos/system.ts"; import { parse } from "../space_lua/parse.ts"; export function luaSyscalls(): SysCallMapping { - return { - "lua.parse": (_ctx, code: string) => { - return parse(code); - }, - }; + return { + "lua.parse": (_ctx, code: string) => { + return parse(code); + }, + }; } diff --git a/plug-api/syscalls/lua.ts b/plug-api/syscalls/lua.ts index da1cbe35..bd558f67 100644 --- a/plug-api/syscalls/lua.ts +++ b/plug-api/syscalls/lua.ts @@ -2,7 +2,7 @@ import { syscall } from "../syscall.ts"; import type { ParseTree } from "../lib/tree.ts"; export function parse( - code: string, + code: string, ): Promise { - return syscall("lua.parse", code); + return syscall("lua.parse", code); } diff --git a/plugs/core/core.plug.yaml b/plugs/core/core.plug.yaml index dcf9c76a..89a83d10 100644 --- a/plugs/core/core.plug.yaml +++ b/plugs/core/core.plug.yaml @@ -106,4 +106,4 @@ config: nullable: true spaceIgnore: type: string - nullable: true \ No newline at end of file + nullable: true diff --git a/plugs/index/index.plug.yaml b/plugs/index/index.plug.yaml index 1012b0f6..f3e1af52 100644 --- a/plugs/index/index.plug.yaml +++ b/plugs/index/index.plug.yaml @@ -44,7 +44,7 @@ functions: command: name: "Space: Reindex" requireMode: rw - + processIndexQueue: path: ./command.ts:processIndexQueue mqSubscriptions: @@ -242,7 +242,7 @@ functions: events: - query:command config: - # Schema for the built-in tags indexed by this plug + # Schema for the built-in tags indexed by this plug schema.tag: page: type: object diff --git a/plugs/search/search.plug.yaml b/plugs/search/search.plug.yaml index 20c1c1d1..83b58e5e 100644 --- a/plugs/search/search.plug.yaml +++ b/plugs/search/search.plug.yaml @@ -1,9 +1,9 @@ name: search functions: indexPage: - path: search.ts:indexPage - events: - - page:index + path: search.ts:indexPage + events: + - page:index searchQueryProvider: path: ./search.ts:queryProvider @@ -32,4 +32,4 @@ functions: path: ./search.ts:getFileMetaSearch pageNamespace: pattern: "🔍 .+" - operation: getFileMeta \ No newline at end of file + operation: getFileMeta diff --git a/plugs/share/share.plug.yaml b/plugs/share/share.plug.yaml index 5efdae0e..f783b8ae 100644 --- a/plugs/share/share.plug.yaml +++ b/plugs/share/share.plug.yaml @@ -10,24 +10,24 @@ functions: clipboardShareOptions: path: share.ts:clipboardShareOptions events: - - share:options + - share:options clipboardMarkdownShare: path: share.ts:clipboardMarkdownShare events: - - share:clean-markdown + - share:clean-markdown clipboardRichTextShare: path: share.ts:clipboardRichTextShare events: - - share:rich-text + - share:rich-text publishShareOptions: path: publish.ts:publishShareOptions events: - - share:options + - share:options publishShare: path: publish.ts:publishShare events: - - share:publish \ No newline at end of file + - share:publish diff --git a/plugs/sync/sync.plug.yaml b/plugs/sync/sync.plug.yaml index 8e515387..8282e5dd 100644 --- a/plugs/sync/sync.plug.yaml +++ b/plugs/sync/sync.plug.yaml @@ -6,4 +6,3 @@ functions: name: "Sync: Now" key: "Alt-Shift-s" mac: "Cmd-Shift-s" - diff --git a/plugs/tasks/tasks.plug.yaml b/plugs/tasks/tasks.plug.yaml index 4086ecf3..ebd7b3ca 100644 --- a/plugs/tasks/tasks.plug.yaml +++ b/plugs/tasks/tasks.plug.yaml @@ -7,7 +7,7 @@ functions: indexTasks: path: "./task.ts:indexTasks" events: - - page:index + - page:index taskToggle: path: "./task.ts:taskToggle" events: @@ -34,7 +34,7 @@ functions: taskComplete: path: ./complete.ts:completeTaskState events: - - editor:complete + - editor:complete removeCompletedTasksCommand: path: task.ts:removeCompletedTasksCommand @@ -101,4 +101,4 @@ config: state: type: string count: - type: number \ No newline at end of file + type: number diff --git a/web/auth.html b/web/auth.html index 227cf473..6ea9def2 100644 --- a/web/auth.html +++ b/web/auth.html @@ -1,99 +1,129 @@ + + + + + Login to SilverBullet + + - .error-message { - color: red; - } - + +
+

+ Login to + SilverBullet +

+
+
+
+
+ +
+
+ +
+
+ +
+ +
- + - - - \ No newline at end of file + document.getElementById("login").appendChild(input); + } + + + diff --git a/web/client.ts b/web/client.ts index 6fdea817..6fcc499e 100644 --- a/web/client.ts +++ b/web/client.ts @@ -147,7 +147,8 @@ export class Client implements ConfigContainer { this.fullSyncCompleted = true; } // Generate a semi-unique prefix for the database so not to reuse databases for different space paths - this.dbPrefix = "" + simpleHash(globalThis.silverBulletConfig.spaceFolderPath); + this.dbPrefix = "" + + simpleHash(globalThis.silverBulletConfig.spaceFolderPath); this.onLoadPageRef = parsePageRefFromURI(); } diff --git a/web/index.html b/web/index.html index e0e10eaf..5a840df3 100644 --- a/web/index.html +++ b/web/index.html @@ -1,82 +1,89 @@ + + + + + + + + - - - - - - - - + {{TITLE}} + + - {{TITLE}} - - - - - - - - - - + window.silverBulletConfig = { + // These {{VARIABLES}} are replaced by http_server.ts + spaceFolderPath: "{{SPACE_PATH}}", + syncOnly: "{{SYNC_ONLY}}" === "true", + enableSpaceScript: "{{ENABLE_SPACE_SCRIPT}}" === "true", + readOnly: "{{READ_ONLY}}" === "true", + }; + // But in case these variables aren't replaced by the server, fall back sync only mode + if (window.silverBulletConfig.spaceFolderPath.includes("{{")) { + window.silverBulletConfig = { + spaceFolderPath: "", + syncOnly: true, + readOnly: false, + enableSpaceScripts: false, + }; + } + + + + + + + - -
- -
-
-
-
- {{CONTENT}} + +
+
+
+
+
+ {{CONTENT}} +
-
- - - \ No newline at end of file + + diff --git a/web/styles/colors.scss b/web/styles/colors.scss index 5ca6bccf..779974d9 100644 --- a/web/styles/colors.scss +++ b/web/styles/colors.scss @@ -60,7 +60,7 @@ font-family: var(--editor-font); } -.sb-notifications>div { +.sb-notifications > div { border: var(--notifications-border-color) 1px solid; } @@ -361,7 +361,11 @@ tbody tr:nth-of-type(even) { } .sb-admonition-title { - background-color: color-mix(in srgb, var(--admonition-color), transparent 90%) + background-color: color-mix( + in srgb, + var(--admonition-color), + transparent 90% + ); } .sb-admonition-type::before { @@ -424,7 +428,7 @@ a, } a.sb-wiki-link-page-missing, -.sb-wiki-link-page-missing>.sb-wiki-link-page { +.sb-wiki-link-page-missing > .sb-wiki-link-page { color: var(--editor-wiki-link-page-missing-color); background-color: var(--editor-wiki-link-page-background-color); } @@ -443,4 +447,4 @@ a.sb-wiki-link-page-missing, .sb-line-comment { background-color: var(--editor-code-comment-color); // rgba(255, 255, 0, 0.5); -} \ No newline at end of file +} diff --git a/web/styles/editor.scss b/web/styles/editor.scss index 0a3a0d76..8b61fa66 100644 --- a/web/styles/editor.scss +++ b/web/styles/editor.scss @@ -264,7 +264,7 @@ text-indent: -7ch; } - .sb-checkbox>input[type="checkbox"] { + .sb-checkbox > input[type="checkbox"] { width: 3ch; } @@ -339,7 +339,7 @@ } a.sb-wiki-link-page-missing, - .sb-wiki-link-page-missing>.sb-wiki-link-page { + .sb-wiki-link-page-missing > .sb-wiki-link-page { border-radius: 5px; padding: 0 5px; // white-space: nowrap; @@ -360,7 +360,7 @@ } .sb-task-deadline { - background-color: rgba(22, 22, 22, 0.07) + background-color: rgba(22, 22, 22, 0.07); } .sb-line-frontmatter-outside, @@ -420,7 +420,6 @@ white-space: nowrap; } - // dont apply background color twice for (fenced) code blocks .sb-line-code .sb-code { background-color: transparent; @@ -439,7 +438,7 @@ margin: 0 3px; } - .sb-code-copy-button>svg { + .sb-code-copy-button > svg { height: 1rem; width: 1rem; } @@ -592,7 +591,6 @@ button:last-of-type { margin-right: 2px; } - } } @@ -614,7 +612,7 @@ } } - .sb-line-blockquote.sb-line-ul.sb-line-li>.sb-quote.sb-meta:first-child { + .sb-line-blockquote.sb-line-ul.sb-line-li > .sb-quote.sb-meta:first-child { margin-left: -1ch; } @@ -650,4 +648,4 @@ div:not(.cm-focused).cm-fat-cursor { outline: none !important; -} \ No newline at end of file +} diff --git a/web/styles/main.scss b/web/styles/main.scss index b450e4b3..59f18a3f 100644 --- a/web/styles/main.scss +++ b/web/styles/main.scss @@ -84,15 +84,13 @@ body { font-size: 15px; z-index: 100; - >div { + > div { padding: 3px; margin-bottom: 3px; border-radius: 5px; } } - } - } #sb-current-page { @@ -169,7 +167,6 @@ body { border-radius: 5px; } - #sb-main { display: flex; flex-direction: row; diff --git a/web/styles/theme.scss b/web/styles/theme.scss index ac91d0a2..0be35033 100644 --- a/web/styles/theme.scss +++ b/web/styles/theme.scss @@ -50,7 +50,11 @@ html { --button-color: black; --button-border-color: #6c6c6c; --primary-button-background-color: var(--ui-accent-color); - --primary-button-hover-background-color: color-mix(in srgb, var(--ui-accent-color), black 35%); + --primary-button-hover-background-color: color-mix( + in srgb, + var(--ui-accent-color), + black 35% + ); --primary-button-color: var(--ui-accent-contrast-color); --primary-button-border-color: transparent; @@ -120,10 +124,10 @@ html { --editor-directive-color: #696969; --editor-directive-background-color: #ebebeb7d; - - --ui-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, - "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", - "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --ui-font: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", + Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol", "Noto Color Emoji"; --editor-font: "iA-Mono", "Menlo"; --editor-width: 800px; } @@ -186,7 +190,11 @@ html[data-theme="dark"] { --button-color: white; --button-border-color: #666; --primary-button-background-color: var(--ui-accent-color); - --primary-button-hover-background-color: color-mix(in srgb, var(--ui-accent-color), black 35%); + --primary-button-hover-background-color: color-mix( + in srgb, + var(--ui-accent-color), + black 35% + ); --primary-button-color: var(--ui-accent-contrast-color); --primary-button-border-color: transparent; @@ -271,4 +279,4 @@ html[data-theme="dark"] { --admonition-icon: url('data:image/svg+xml,'); --admonition-color: #ff9100; -} \ No newline at end of file +}