diff --git a/engine/src/main/kotlin/io/helicase/engine/Engine.kt b/engine/src/main/kotlin/io/helicase/engine/Engine.kt index 1151cd3..1e77ca5 100644 --- a/engine/src/main/kotlin/io/helicase/engine/Engine.kt +++ b/engine/src/main/kotlin/io/helicase/engine/Engine.kt @@ -616,6 +616,20 @@ class Engine { // plugin to handle. State is otherwise unchanged. ctx.state.copy(pendingAction = PendingAction.GotoWord) } + // LSP-style gotos. Engine emits a named effect; the plugin maps to + // IntelliJ's GotoDeclaration / GotoTypeDeclaration / etc. + val gotoDefinition = Command("goto_definition", "Go to definition") { ctx -> + ctx.state.copy(pendingAction = PendingAction.InvokeIdeCommand("goto_definition")) + } + val gotoTypeDefinition = Command("goto_type_definition", "Go to type definition") { ctx -> + ctx.state.copy(pendingAction = PendingAction.InvokeIdeCommand("goto_type_definition")) + } + val gotoImplementation = Command("goto_implementation", "Go to implementation") { ctx -> + ctx.state.copy(pendingAction = PendingAction.InvokeIdeCommand("goto_implementation")) + } + val gotoReference = Command("goto_reference", "Go to references") { ctx -> + ctx.state.copy(pendingAction = PendingAction.InvokeIdeCommand("goto_reference")) + } val gotoFirstNonWs = Command("goto_first_non_whitespace", "Go to first non-ws") { ctx -> val text = ctx.state.text moveAllRanges(ctx.state, ctx.extend) { r -> @@ -766,6 +780,10 @@ class Engine { KeyEvent.Char('l') to KeyMap.Leaf(commands.gotoLineEnd), KeyEvent.Char('s') to KeyMap.Leaf(commands.gotoFirstNonWs), KeyEvent.Char('w') to KeyMap.Leaf(commands.gotoWord), + KeyEvent.Char('d') to KeyMap.Leaf(commands.gotoDefinition), + KeyEvent.Char('y') to KeyMap.Leaf(commands.gotoTypeDefinition), + KeyEvent.Char('i') to KeyMap.Leaf(commands.gotoImplementation), + KeyEvent.Char('r') to KeyMap.Leaf(commands.gotoReference), ), description = "goto navigation", ), diff --git a/engine/src/main/kotlin/io/helicase/engine/Types.kt b/engine/src/main/kotlin/io/helicase/engine/Types.kt index ffa40de..76f1bc7 100644 --- a/engine/src/main/kotlin/io/helicase/engine/Types.kt +++ b/engine/src/main/kotlin/io/helicase/engine/Types.kt @@ -118,4 +118,16 @@ enum class Mode { Normal, Insert, Select } sealed class PendingAction { /** `gw` — show a jump-label overlay across visible words. */ data object GotoWord : PendingAction() + + /** + * Invoke a plugin-resolved command by name (matches an entry in the + * plugin's `HelicaseCommand` registry). The engine doesn't know about + * IntelliJ action IDs — it just emits a Helix-style command name and + * the plugin maps it to whatever IDE action does the job. + * + * Used by the LSP-style `g`-family commands (`gd`, `gy`, `gi`, `gr`) + * so they delegate to IntelliJ's existing goto / find-usages + * infrastructure rather than reimplementing it. + */ + data class InvokeIdeCommand(val name: String) : PendingAction() } diff --git a/plugin/src/main/kotlin/io/helicase/plugin/HelicaseCommand.kt b/plugin/src/main/kotlin/io/helicase/plugin/HelicaseCommand.kt index b2849b0..43a66e8 100644 --- a/plugin/src/main/kotlin/io/helicase/plugin/HelicaseCommand.kt +++ b/plugin/src/main/kotlin/io/helicase/plugin/HelicaseCommand.kt @@ -64,9 +64,20 @@ object HelicaseCommand { // `` minor mode bindings. Names match Helix's command names // where possible; each delegates to the IntelliJ action that does // the same thing under the hood. - "file_picker" to ideAction("Open recent files", "RecentFiles"), - "file_picker_workspace" to ideAction("Open file in workspace", "GotoFile"), - "buffer_picker" to ideAction("Switch buffer", "Switcher"), + // + // Mapping rationale: + // - file_picker (`f`) is Helix's universal "find file by + // name" fuzzy finder → IntelliJ's GotoFile. RecentFiles is more + // of a buffer list (matches Helix's `b` better). + // - file_picker_workspace (`F`) — Helix has it as the + // current-directory-scoped variant; IntelliJ doesn't really + // distinguish, so we point both at GotoFile. + // - buffer_picker (`b`) → RecentFiles popup, which lists + // recently-opened buffers and is closer to Helix's intent than + // Switcher's Ctrl-Tab cycle. + "file_picker" to ideAction("Find file by name", "GotoFile"), + "file_picker_workspace" to ideAction("Find file by name", "GotoFile"), + "buffer_picker" to ideAction("Recent files", "RecentFiles"), "global_search" to ideAction("Find in path", "FindInPath"), "code_action" to ideAction("Show intention actions", "ShowIntentionActions"), "hover" to ideAction("Quick documentation", "QuickJavaDoc"), @@ -79,6 +90,12 @@ object HelicaseCommand { "workspace_symbol" to ideAction("Go to symbol (project)", "GotoSymbol"), "diagnostic_next" to ideAction("Next error", "GotoNextError"), "command_palette" to ideAction("Find action", "GotoAction"), + // `g`-family LSP-style gotos. Engine emits InvokeIdeCommand(name) + // for these; the plugin resolves here. + "goto_definition" to ideAction("Go to declaration", "GotoDeclaration"), + "goto_type_definition" to ideAction("Go to type declaration", "GotoTypeDeclaration"), + "goto_implementation" to ideAction("Go to implementation", "GotoImplementation"), + "goto_reference" to ideAction("Show usages", "ShowUsages"), ) /**