# Native Kotlin Editor Prototype This is the first slice of an Odin-native editor architecture backed by a small Kotlin/JVM daemon. The boundary is intentionally simple: newline-delimited JSON over localhost TCP. The native client tracks daemon request ids for interactive requests so concurrent popups and panels consume only their matching responses. Text edits are debounced before sending `text/change` to the daemon; file switches, saves, navigation, and daemon-backed requests flush the active buffer immediately. ## Layout - `client/odin/` - Odin client smoke test for the future native editor. - `daemon/` - Kotlin/JVM TCP daemon for Gradle/Kotlin intelligence. - `protocol.md` - current TCP message shape. ## Run Start the daemon: ```sh gradle -p daemon run ``` It prints a line like: ```text PORT 49321 ``` In another terminal, run the Odin client with that port: ```sh odin run client/odin -- 49321 /path/to/workspace ``` The client sends `ping` and `workspace/open` requests and prints daemon responses. Run the SDL editor window: ```sh odin run client/odin -- --sdl /path/to/workspace /path/to/file.kt ``` The SDL mode starts the daemon automatically when no port is passed. You can still connect to an already-running daemon by passing its port before the file path: Auto-started daemons are restarted automatically if the process exits or the TCP connection drops. Explicit-port mode does not restart external daemons. ```sh odin run client/odin -- --sdl /path/to/workspace /path/to/file.kt ``` The file path is optional. If no file is passed, the editor restores the last open files, active tab, and cursor positions for the workspace. If there is no saved state, it opens the current prototype default file under the workspace. SDL mode shows a simple workspace file tree in the left sidebar. Click a file to open or focus it. Open files appear in the editor tab strip; click a tab to switch active buffers or drag tabs to reorder them. Use `Ctrl+W` to close the active buffer, or click a tab's `x`. Dirty buffers are not closed until saved. SDL mode creates an SDL3 `GPUDevice` and uses a direct SDL3 GPU command-buffer renderer when a GPU backend is available. It batches editor rectangles, selections, cursor lines, panels, and `stb_truetype` font-atlas text into GPU vertices. It falls back to the regular SDL renderer in unsupported environments such as `SDL_VIDEODRIVER=dummy` smoke tests. The bundled Noto Sans Mono font is embedded into the client binary at build time, so the editor always has a working monospace font. Place a `client/odin/assets/fonts/EditorMono.ttf` file to override it. The GPU editor path includes lightweight Kotlin/Java syntax highlighting for comments, block comments, strings, character literals, triple-quoted Kotlin strings, keywords, numbers, and type-like identifiers. Kotlin and Java diagnostics are shown in the gutter/status area with active-file error/warning/info counts, and as red dashed underlines in the GPU editor path. Kotlin diagnostics include Java source files from the same Gradle source roots for mixed-source projects, and unsaved Kotlin/Java buffers are compiled under their declared package path. Use `F8` and `Shift+F8` to move to the next/previous diagnostic in the active file. Use `Ctrl+Shift+M` to toggle the diagnostics panel. Use Up/Down, PageUp/PageDown, Home/End, mouse wheel, Enter, or row clicks to navigate issues. Use `Ctrl+Shift+P` to open the command palette. Type to filter commands, use Up/Down, PageUp/PageDown, Home/End, mouse wheel, Enter, or row clicks to run actions. The palette includes Reload Workspace, which refreshes the file tree, reopens the Gradle workspace, clears stale diagnostics, and resyncs the active file. Gradle workspace import records module source roots, test source roots, resource roots, classpath entries, tasks, and common generated source directories when they already exist under `build/generated/`. Diagnostics also include existing module output directories from `build/classes/` and `build/resources/` on their compiler classpath. Use `Ctrl+Shift+T` to toggle Gradle tasks in the right sidebar. Use Up/Down, PageUp/PageDown, Home/End, mouse wheel, or row clicks to select tasks, and Enter to run the selected task; the sidebar shows the loaded task count and reports started/finished/failed events, the final response, and recent stdout/stderr output. The SDL3 GPU shaders are compiled to SPIR-V under `client/odin/shaders/compiled/` and embedded into the client binary at build time, so the editor has no runtime shader files to find. The compiled files are committed; after editing the GLSL sources, regenerate them with: ```sh scripts/compile-shaders.sh ``` The script uses `glslc` from shaderc. On Fedora, install it with `sudo dnf install glslc`. Run autonomous opencode continuation loops with: ```sh scripts/autopilot-opencode.sh ``` By default it runs `opencode run --dir "$PWD" --continue --dangerously-skip-permissions` repeatedly with an instruction to keep working through the task list and choose new tasks when the list is complete. Configure it with environment variables, for example: ```sh OPENCODE_SESSION= AUTOPILOT_MAX_RUNS=5 scripts/autopilot-opencode.sh ``` Create `.opencode-autopilot-stop` to stop the loop cleanly between iterations. Set `AUTOPILOT_ALLOW_PERMISSIONS=0` to disable automatic permission approval. The editor supports basic editing keys: arrows, `Ctrl+Left`/`Ctrl+Right` word movement, PageUp/PageDown, Home/End, Shift+movement selection, Backspace, Delete, Tab as four spaces, Shift+Tab outdent, auto-indent on Enter, mouse click/drag cursor selection, `Ctrl+C`/`Ctrl+X`/`Ctrl+V`, `Ctrl+F` find, `Ctrl+Z`/`Ctrl+Y` undo/redo, `Ctrl+S` save, and `Ctrl+Shift+S` save all. Replacing a selection with typed text, Enter, Tab, or a completion is one undo step, and undo/redo updates the dirty marker when returning to the saved version. Use `Ctrl+Shift+E` to toggle the Explorer sidebar. The editor and sidebars scroll independently based on mouse position. Window size, sidebar widths, sidebar visibility, open files, active tab, and cursor positions are saved under the user cache directory and restored on startup. In the find panel, Enter finds next and Shift+Enter finds previous. Visible matches are highlighted in the GPU editor path. Press `Ctrl+M` in SDL GPU mode to toggle a font metrics overlay for debugging cursor/text alignment. Press `Ctrl+Space` to open the completion popup. It sends `kotlin/completion` to the daemon and renders returned item labels with kind hints. Use Up/Down, PageUp/PageDown, Home/End, mouse wheel, Enter, or row clicks to choose and apply a completion by replacing the identifier prefix before the cursor. Completion returns Kotlin/Java keywords plus heuristic identifiers/declarations from the current buffer and workspace. Press `Ctrl+H` to request hover information at the cursor. Hover describes language keywords and shows heuristic Kotlin/Java declaration lines/locations for identifiers when found in the current buffer or workspace. Press `Ctrl+B` to go to definition. Definition currently uses a heuristic source scan for simple Kotlin/Java declarations and includes the current unsaved buffer. Use `Alt+Left` and `Alt+Right` to navigate backward and forward through definition jumps. Press `Ctrl+R` to find references for the identifier at the cursor. References currently use a heuristic source scan and are shown in a popup; use Up/Down, PageUp/PageDown, Home/End, mouse wheel, Enter, or row clicks to jump to a result. Press `Ctrl+Shift+R` to open the rename preview panel. Enter a new name and press Enter to request preview edits. Rename remains preview-only and does not modify files yet.