Lua: tweaks and fixes

pull/1224/head
Zef Hemel 2025-01-25 08:29:11 +01:00
parent 6f3d021da7
commit 236b2a7fdd
9 changed files with 76 additions and 23 deletions

View File

@ -315,6 +315,11 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
return this.arrayPart.length;
}
hasKeys(): boolean {
return !!(Object.keys(this.stringKeys).length > 0 ||
this.arrayPart.length > 0 || (this.otherKeys && this.otherKeys.size > 0));
}
keys(): any[] {
const keys: any[] = Object.keys(this.stringKeys);
for (let i = 0; i < this.arrayPart.length; i++) {
@ -695,7 +700,7 @@ export function luaTruthy(value: any): boolean {
return false;
}
if (value instanceof LuaTable) {
return value.length > 0;
return value.hasKeys();
}
return true;
}
@ -773,6 +778,17 @@ export function jsToLuaValue(value: any): any {
return value;
} else if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
return value;
} else if (Array.isArray(value) && "index" in value && "input" in value) {
// This is a RegExpMatchArray
const regexMatch = value as RegExpMatchArray;
const regexMatchTable = new LuaTable();
for (let i = 0; i < regexMatch.length; i++) {
regexMatchTable.set(i + 1, regexMatch[i]);
}
regexMatchTable.set("index", regexMatch.index);
regexMatchTable.set("input", regexMatch.input);
regexMatchTable.set("groups", regexMatch.groups);
return regexMatchTable;
} else if (Array.isArray(value)) {
const table = new LuaTable();
for (let i = 0; i < value.length; i++) {

View File

@ -1,4 +1,5 @@
import {
jsToLuaValue,
LuaBuiltinFunction,
luaCall,
LuaMultiRes,
@ -213,4 +214,13 @@ export const stringApi = new LuaTable({
trim_end: new LuaBuiltinFunction((_sf, s: string) => {
return s.trimEnd();
}),
match_regex: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
const regex = new RegExp(pattern);
const result = s.match(regex);
return jsToLuaValue(result);
// if (!result) {
// return new LuaMultiRes([]);
// }
// return new LuaMultiRes(result.slice(1));
}),
});

View File

@ -1,6 +1,7 @@
import {
type ILuaFunction,
LuaBuiltinFunction,
type LuaEnv,
luaEquals,
LuaRuntimeError,
LuaTable,
@ -17,7 +18,10 @@ export const tableApi = new LuaTable({
* @returns The concatenated string.
*/
concat: new LuaBuiltinFunction(
(_sf, tbl: LuaTable, sep?: string, i?: number, j?: number) => {
(_sf, tbl: LuaTable | any[], sep?: string, i?: number, j?: number) => {
if (Array.isArray(tbl)) {
return tbl.join(sep);
}
sep = sep ?? "";
i = i ?? 1;
j = j ?? tbl.length;
@ -70,7 +74,8 @@ export const tableApi = new LuaTable({
* @param tbl - The table to get the keys from.
* @returns The keys of the table.
*/
keys: new LuaBuiltinFunction((_sf, tbl: LuaTable) => {
keys: new LuaBuiltinFunction((_sf, tbl: LuaTable | LuaEnv) => {
console.log("Keys", tbl);
return tbl.keys();
}),
/**

View File

@ -38,7 +38,7 @@ export function commandSyscalls(
const sf = new LuaStackFrame(tl, null);
try {
return luaValueToJS(
await luaCall(def.run, args.map(jsToLuaValue), sf),
await luaCall(def.run, args.map(jsToLuaValue), {}, sf),
);
} catch (e: any) {
await handleLuaError(e, commonSystem.system);
@ -60,7 +60,7 @@ export function commandSyscalls(
const sf = new LuaStackFrame(tl, null);
try {
return luaValueToJS(
await luaCall(def.run, args.map(jsToLuaValue), sf),
await luaCall(def.run, args.map(jsToLuaValue), {}, sf),
);
} catch (e: any) {
await handleLuaError(e, commonSystem.system);

View File

@ -35,9 +35,10 @@ export function eventListenerSyscalls(
);
const sf = new LuaStackFrame(tl, null);
try {
return luaValueToJS(
await luaCall(def.run, args.map(jsToLuaValue), sf),
const val = luaValueToJS(
await luaCall(def.run, args.map(jsToLuaValue), {}, sf),
);
return val;
} catch (e: any) {
await handleLuaError(e, commonSystem.system);
}

View File

@ -53,6 +53,8 @@ export type SlashCommandDef = {
name: string;
description?: string;
boost?: number;
// Parent AST nodes in which this slash command is available
contexts?: string[];
};
export type SlashCommandHookT = {
slashCommand?: SlashCommandDef;

View File

@ -19,7 +19,7 @@ function config.set(key, value)
error("Config key not defined: " .. key)
end
if schema != true then
result = jsonschema.validate_object(schema, value)
local result = jsonschema.validate_object(schema, value)
if result != nil then
error("Validation error (" .. key .. "): " .. result)
end

View File

@ -2,7 +2,7 @@ import type {
CompletionContext,
CompletionResult,
} from "@codemirror/autocomplete";
import type { Compartment } from "@codemirror/state";
import type { Compartment, EditorState } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { syntaxTree } from "@codemirror/language";
import { compile as gitIgnoreCompiler } from "gitignore-parser";
@ -892,21 +892,13 @@ export class Client implements ConfigContainer {
const linePrefix = line.text.slice(0, selection.from - line.from);
// Build up list of parent nodes, some completions need this
const parentNodes: string[] = [];
const sTree = syntaxTree(editorState);
const currentNode = sTree.resolveInner(selection.from);
if (currentNode) {
let node: SyntaxNode | null = currentNode;
do {
if (node.name === "FencedCode" || node.name === "FrontMatter") {
const body = editorState.sliceDoc(node.from + 3, node.to - 3);
parentNodes.push(`${node.name}:${body}`);
} else {
parentNodes.push(node.name);
}
node = node.parent;
} while (node);
}
const currentNode = sTree.resolveInner(editorState.selection.main.from);
const parentNodes: string[] = this.extractParentNodes(
editorState,
currentNode,
);
// Dispatch the event
const results = await this.dispatchAppEvent(eventName, {
@ -949,6 +941,23 @@ export class Client implements ConfigContainer {
return currentResult;
}
public extractParentNodes(editorState: EditorState, currentNode: SyntaxNode) {
const parentNodes: string[] = [];
if (currentNode) {
let node: SyntaxNode | null = currentNode;
do {
if (node.name === "FencedCode" || node.name === "FrontMatter") {
const body = editorState.sliceDoc(node.from + 3, node.to - 3);
parentNodes.push(`${node.name}:${body}`);
} else {
parentNodes.push(node.name);
}
node = node.parent;
} while (node);
}
return parentNodes;
}
editorComplete(
context: CompletionContext,
): Promise<CompletionResult | null> {

View File

@ -108,7 +108,17 @@ export class SlashCommandHook implements Hook<SlashCommandHookT> {
return null;
}
// Check if the slash command is available in the current context
const parentNodes = this.editor.extractParentNodes(ctx.state, currentNode);
// console.log("Parent nodes", parentNodes);
for (const def of this.slashCommands.values()) {
if (
def.slashCommand.contexts && !def.slashCommand.contexts.some(
(context) => parentNodes.some((node) => node.startsWith(context)),
)
) {
continue;
}
options.push({
label: def.slashCommand.name,
detail: def.slashCommand.description,