diff --git a/config/absytree_config.nim b/config/absytree_config.nim index 658733c0..da2f3a1f 100644 --- a/config/absytree_config.nim +++ b/config/absytree_config.nim @@ -1,11 +1,6 @@ import absytree_runtime import std/[strutils, sugar, sequtils, macros] -import keybindings_vim -import keybindings_vim_like -import keybindings_helix -import keybindings_normal - proc handleAction*(action: string, args: JsonNode): bool {.wasmexport.} = when not defined(wasm): return false @@ -78,9 +73,14 @@ proc postInitialize*(): bool {.wasmexport.} = import default_config when defined(wasm): + import keybindings_vim + import keybindings_vim_like + import keybindings_helix + import keybindings_normal + loadDefaultOptions() loadDefaultKeybindings() - loadVimLikeKeybindings() + loadVimKeybindings() # Triple click to selects a line setOption "editor.text.triple-click-command", "extend-select-move" diff --git a/config/absytree_config_wasm.wasm b/config/absytree_config_wasm.wasm index cc7bf7b3..5481f0dd 100755 Binary files a/config/absytree_config_wasm.wasm and b/config/absytree_config_wasm.wasm differ diff --git a/config/keybindings_normal.nim b/config/keybindings_normal.nim index b67a3b34..f295f12d 100644 --- a/config/keybindings_normal.nim +++ b/config/keybindings_normal.nim @@ -6,6 +6,7 @@ proc setModeChangedHandler*(handler: proc(editor: TextDocumentEditor, oldMode: s if modeChangedHandler != "": onEditorModeChanged.unsubscribe(parseId(modeChangedHandler)) let id = onEditorModeChanged.subscribe proc(arg: auto) = + # infof"onEditorModeChanged: {arg.editor}, {arg.oldMode}, {arg.newMode}" if arg.editor.isTextEditor(editor) and not editor.isRunningSavedCommands: handler(editor, arg.oldMode, arg.newMode) setOption("editor.text.mode-changed-handler", $id) diff --git a/scripting/absytree_runtime.nim b/scripting/absytree_runtime.nim index 5c0f7191..f0a2b283 100644 --- a/scripting/absytree_runtime.nim +++ b/scripting/absytree_runtime.nim @@ -92,6 +92,7 @@ template isModelEditor*(editorId: EditorId, injected: untyped): bool = (scriptIsModelEditor(editorId) and ((let injected {.inject.} = ModelDocumentEditor(id: editorId); true))) proc handleCallbackImpl*(id: int, args: JsonNode): bool = + # infof"handleCallbackImpl {id}, {args}" if voidCallbacks.contains(id): voidCallbacks[id](args) return true @@ -102,9 +103,10 @@ proc handleCallbackImpl*(id: int, args: JsonNode): bool = return false proc handleAnyCallbackImpl*(id: int, args: JsonNode): JsonNode = + # infof"handleAnyCallbackImpl {id}, {args}" if voidCallbacks.contains(id): voidCallbacks[id](args) - return nil + return newJNull() elif boolCallbacks.contains(id): return newJBool(boolCallbacks[id](args)) elif anyCallbacks.contains(id): @@ -112,7 +114,7 @@ proc handleAnyCallbackImpl*(id: int, args: JsonNode): JsonNode = return nil proc handleScriptActionImpl*(name: string, args: JsonNode): JsonNode = - # echo "handleScriptActionImpl ", name, ", ", args + # infof"handleScriptActionImpl {name}, {args}" if scriptActions.contains(name): return scriptActions[name](args) return nil @@ -202,9 +204,14 @@ macro addCommand*(context: string, keys: string, action: string, args: varargs[u addCommandScript(context, keysPrefix & keys, action, str) proc addCommand*(context: string, keys: string, action: proc(): void) = - let key = context & keys - lambdaActions[key] = action - addCommandScript(context, keysPrefix & keys, "lambda-action", key.toJsonString) + let key = "$" & context & keys + # lambdaActions[key] = action + scriptActions[key] = proc(args: JsonNode): JsonNode = + action() + return newJNull() + + # addCommandScript(context, keysPrefix & keys, "lambda-action", key.toJsonString) + addCommandScript(context, keysPrefix & keys, key, "") template addCommandBlock*(context: static[string], keys: string, body: untyped): untyped = addCommand context, keys, proc() = @@ -246,7 +253,7 @@ template addTextCommandBlock*(mode: static[string], keys: string, body: untyped) except: let m {.inject.} = mode let k {.inject.} = keys - infof "TextCommandBlock {m} {k}: {getCurrentExceptionMsg()}" + infof"TextCommandBlock {m} {k}: {getCurrentExceptionMsg()}" proc addTextCommand*(mode: string, keys: string, action: proc(editor: TextDocumentEditor): void) = let context = if mode.len == 0: "editor.text" else: "editor.text." & mode @@ -256,7 +263,7 @@ proc addTextCommand*(mode: string, keys: string, action: proc(editor: TextDocume except: let m {.inject.} = mode let k {.inject.} = keys - infof "TextCommand {m} {k}: {getCurrentExceptionMsg()}" + infof"TextCommand {m} {k}: {getCurrentExceptionMsg()}" macro addTextCommand*(mode: static[string], keys: string, action: string, args: varargs[untyped]): untyped = let context = if mode.len == 0: "editor.text" else: "editor.text." & mode @@ -271,18 +278,18 @@ proc setTextInputHandler*(context: string, action: proc(editor: TextDocumentEdit let input = args.str return action(TextDocumentEditor(id: getActiveEditor()), input) except: - infof "TextInputHandler {context}: {getCurrentExceptionMsg()}" + infof"TextInputHandler {context}: {getCurrentExceptionMsg()}" scriptSetCallback("editor.text.input-handler." & context, id) setHandleInputs("editor.text." & context, true) var customMoves = initTable[string, proc(editor: TextDocumentEditor, cursor: Cursor, count: int): Selection]() -proc handleCustomTextMove*(editor: TextDocumentEditor, move: string, cursor: Cursor, count: int): Selection = +proc handleCustomTextMove*(editor: TextDocumentEditor, move: string, cursor: Cursor, count: int): Option[Selection] = if customMoves.contains(move): - return customMoves[move](editor, cursor, count) - return cursor.toSelection + return customMoves[move](editor, cursor, count).some + return Selection.none -when defined(wasm): +block: # Custom moves let id = addCallback proc(args: JsonNode): JsonNode = type Payload = object editor: EditorId @@ -293,7 +300,9 @@ when defined(wasm): let input = args.jsonTo(Payload) if input.editor.isTextEditor editor: let selection = handleCustomTextMove(editor, input.move, input.cursor, input.count) - return selection.toJson + if selection.isSome: + return selection.toJson + return nil else: infof"Custom move: editor {input.editor} is not a text editor" return nil @@ -313,7 +322,7 @@ template addModelCommandBlock*(mode: static[string], keys: string, body: untyped except: let m {.inject.} = mode let k {.inject.} = keys - infof "modelCommandBlock {m} {k}: {getCurrentExceptionMsg()}" + infof"ModelCommandBlock {m} {k}: {getCurrentExceptionMsg()}" proc addModelCommand*(mode: string, keys: string, action: proc(editor: ModelDocumentEditor): void) = let context = if mode.len == 0: "editor.model" else: "editor.model." & mode diff --git a/scripting/absytree_runtime_impl.nim b/scripting/absytree_runtime_impl.nim index 02614149..288b8de5 100644 --- a/scripting/absytree_runtime_impl.nim +++ b/scripting/absytree_runtime_impl.nim @@ -27,6 +27,7 @@ proc handleUnknownPopupAction*(id: EditorId, action: string, args: JsonNode): bo return handlePopupAction(id, action, args) proc handleEditorModeChanged*(editor: EditorId, oldMode: string, newMode: string) = + # infof"handleEditorModeChanged {editor} {oldMode} {newMode}" onEditorModeChanged.invoke (editor, oldMode, newMode) when defined(wasm): @@ -53,6 +54,7 @@ when defined(wasm): return false proc handleEditorModeChangedWasm(id: int32, oldMode: cstring, newMode: cstring) {.wasmexport.} = + # infof"handleEditorModeChangedWasm {id} {oldMode} {newMode}" try: handleEditorModeChanged(id.EditorId, $oldMode, $newMode) except: diff --git a/src/absytree.nim b/src/absytree.nim index 6d8ed384..55f6a5f2 100644 --- a/src/absytree.nim +++ b/src/absytree.nim @@ -228,7 +228,9 @@ proc runApp(): Future[void] {.async.} = logger.flush() + log lvlInfo, "Shutting down editor" ed.shutdown() + log lvlInfo, "Shutting down platform" rend.deinit() waitFor runApp() diff --git a/src/misc/wrap.nim b/src/misc/wrap.nim index 1b7c9ff0..9051d3a4 100644 --- a/src/misc/wrap.nim +++ b/src/misc/wrap.nim @@ -68,12 +68,7 @@ proc createJsonWrapper*(def: NimNode, newName: NimNode): NimNode = result = genAst(functionName = newName, call, argName = jsonArg): proc functionName*(argName: JsonNode): JsonNode {.nimcall, used.} = - # try: call - # except CatchableError: - # let name = `pureFunctionNameStr` - # echo "[editor] Failed to run function " & name & fmt": Invalid arguments: {getCurrentExceptionMsg()}" - # echo getCurrentException().getStackTrace proc serializeArgumentsToJson*(def: NimNode, targetUiae: NimNode): (NimNode, NimNode) = let argsName = genSym(nskVar) diff --git a/src/scripting/expose.nim b/src/scripting/expose.nim index f3f49782..7bd6f886 100644 --- a/src/scripting/expose.nim +++ b/src/scripting/expose.nim @@ -1,6 +1,7 @@ import std/[json, strutils, sequtils, tables, options, macros, genasts, macrocache, typetraits, sugar] +from std/logging import nil import fusion/matching import misc/[util, custom_logger, macro_utils, wrap] import compilation_config, dispatch_tables @@ -293,7 +294,7 @@ macro expose*(moduleName: static string, def: untyped): untyped = let lineNumber = def.lineInfoObj.line if returnType.isSome: - let uiae = genAst(res=callJsonStringWrapperFunctionWasmRes, resStr="resStr".ident): + let uiae = genAst(res=callJsonStringWrapperFunctionWasmRes): result = parseJson($res).jsonTo(typeof(result)) callJsonStringWrapperFunctionWasm.add uiae @@ -330,14 +331,17 @@ macro expose*(moduleName: static string, def: untyped): untyped = result.add quote do: var `jsonStringWrapperFunctionReturnValue`: string = "" proc `jsonStringWrapperFunctionName`*(arg: cstring): cstring {.exportc, used.} = - # try: - let argJson = parseJson($arg) - `jsonStringWrapperFunctionReturnValue` = $`jsonWrapperFunctionName`(argJson) - return `jsonStringWrapperFunctionReturnValue`.cstring - # except CatchableError: - # let name = `pureFunctionNameStr` - # echo "[editor] Failed to run function " & name & fmt": Invalid arguments: {getCurrentExceptionMsg()}" - # echo getCurrentException().getStackTrace + try: + let argJson = parseJson($arg) + let res = `jsonWrapperFunctionName`(argJson) + if res.isNil: + `jsonStringWrapperFunctionReturnValue` = "" + else: + `jsonStringWrapperFunctionReturnValue` = $res + return `jsonStringWrapperFunctionReturnValue`.cstring + except: + let name = `pureFunctionNameStr` + logging.log lvlError, "Failed to run function " & name & &": Invalid arguments: {getCurrentExceptionMsg()}\n{getStackTrace()}" static: addWasmImportedFunction(`moduleName`, `jsonStringWrapperFunctionName`, `jsonStringWrapperFunctionWasm`): @@ -417,10 +421,16 @@ macro genDispatcher*(moduleName: static string): untyped = else: alternative.add c + let call = genAst(target, arg): + let res = target(arg) + if res.isNil: + return JsonNode.none + return res.some + if name == alternative: - switch.add nnkOfBranch.newTree(newLit(name), quote do: `target`(`arg`).some) + switch.add nnkOfBranch.newTree(newLit(name), call) else: - switch.add nnkOfBranch.newTree(newLit(name), newLit(alternative), quote do: `target`(`arg`).some) + switch.add nnkOfBranch.newTree(newLit(name), newLit(alternative), call) switch.add nnkElse.newTree(quote do: JsonNode.none) diff --git a/src/scripting/scripting_nim.nim b/src/scripting/scripting_nim.nim index 78e5fd87..1010f51c 100644 --- a/src/scripting/scripting_nim.nim +++ b/src/scripting/scripting_nim.nim @@ -84,11 +84,11 @@ proc createInterpreterAsync(args: (ptr Interpreter, string, seq[string], seq[(st var intr = createInterpreter(args[1], args[2], flags = {allowInfiniteLoops}, defines = args[3]) for uProc in args[4].procs: - intr.implementRoutine("Absytree", args[6], uProc.name, uProc.vmProc) + intr.implementRoutine("absytree", args[6], uProc.name, uProc.vmProc) for (module, addins) in args[5]: for uProc in addins.procs: - intr.implementRoutine("Absytree", module, uProc.name, uProc.vmProc) + intr.implementRoutine("absytree", module, uProc.name, uProc.vmProc) setUseIc(true) @@ -98,12 +98,6 @@ import std/[strformat, sequtils, macros, tables, options, sugar, strutils, genas import scripting_api import misc/[util, myjsonutils] import absytree_runtime - -import keybindings_vim -import keybindings_helix -import keybindings_normal - -import languages """ intr.evalString(initCode) @@ -315,13 +309,14 @@ macro invoke*(self: ScriptContext; pName: untyped; call.add x call.add nnkExprEqExpr.newTree(ident"returnType", returnType) - return genAst(self, call): + return genAst(self, call, name = pName.repr.newLit): if self.state != Initialized: - log lvlError, fmt"ScriptContext not initialized yet. State is {self.state}" + log lvlWarn, fmt"ScriptContext not initialized yet. State is {self.state} (trying to invoke" & name & ")" return if self.inter.isNone: - log(lvlError, fmt"Interpreter is none. State is {self.state}") + log lvlError, fmt"Interpreter is none. State is {self.state}" return + call method handleUnknownPopupAction*(self: ScriptContextNim, popup: Popup, action: string, arg: JsonNode): bool = diff --git a/src/scripting/scripting_wasm.nim b/src/scripting/scripting_wasm.nim index b64d6ead..b53dc727 100644 --- a/src/scripting/scripting_wasm.nim +++ b/src/scripting/scripting_wasm.nim @@ -76,7 +76,9 @@ method init*(self: ScriptContextWasm, path: string): Future[void] {.async.} = self.handleScriptActionCallbacks.add (module, f) if findFunction(module, "absytree_main", void, proc(): void).getSome(f): + log lvlInfo, "Run absytree_main" f() + log lvlInfo, "Finished absytree_main" self.modules.add module