Repository navigation
Conversation
Pi's Editor keeps state/moveCursor TypeScript-private (runtime-accessible), so getEditorInternals could cast directly. oh-my-pi's Editor uses ECMAScript-private #state/#moveCursor, making every motion and text edit silently no-op (mode switching still worked, which masked the failure). getEditorInternals now probes for native internals and, when absent, returns a cached adapter reproducing the EditorInternals surface on omp's public API: - buffer reads via getLines()/getCursor(), writes via setText() + cursor restore (setText anchors to end; fires onChange natively, so the adapter deliberately omits onChange to avoid double-firing) - cursor writes via synthetic legacy arrow keys dispatched to the base Editor input handler; omp's native step is grapheme-aware and wraps across logical lines, so left/right walks reach any (line, col) exactly - vertical arrows are never injected at the buffer edge, where omp would switch to prompt-history navigation - undo falls back to the plugin-owned stack; visual highlight keeps its existing scrollOffset/lastWidth fallbacks Closes 0xKahi#16
'prop in RECORD' also matches inherited Object.prototype names, so state.lines.toString (and friends) were routed through the mutating wrapper, causing a spurious setText + onChange. Found by codex review.
Visual mode crashed on omp for two reasons: - getPaddingX() is pi-only; omp resolves padding privately (override ?? theme.editorPaddingX ?? 2). The renderer now probes once and takes the theme hint (threaded from VimModalEditor) with the omp default of 2 as fallback. - pi text rows are bare 'padding + text + padding', which is exactly what the renderer rebuilt. omp rows carry box side chrome (│ + pad … pad + │) with the bottom border fused into the last text row (╰─…─╯), so the pi-style rewrite stripped the frame. On omp the renderer now column-slices the original row's chrome (glyph- and style-agnostic) and swaps only the content region, mirroring omp's right-chrome shrink when the end-of-line cursor overflows by a cell.
Owner
|
oh my bad i just saw this, can help resolve the merge conflicts. i just updated pi dependencies to v0.85.1 and simplified some of the editor internals. i think you can move the const host: EditorHostServices = {
isFocused: () => this.focused,
notifyChange: text => this.onChange?.(text),
requestRender: () => this.tui.requestRender(),
isHardwareCursorEnabled: () => tui.getShowHardwareCursor(),
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #16
Problem
On oh-my-pi (omp), every vim motion and text edit silently no-ops, while mode switching still works (Esc → normal mode, block cursor) — masking the failure.
Root cause: the plugin reaches pi-tui's editor buffer/cursor through
getEditorInternals(), which relies on pi'sstate/moveCursorbeing TypeScript-private(plain runtime properties). omp's@oh-my-pi/pi-tuiEditor uses ECMAScript-private#state/#moveCursor, so every internals read returnsundefinedandsetCursor()hits its silentif (!state) return;guard.Fix
getEditorInternalsnow probes for native internals (state+moveCursorpresent) and, when absent, returns a cachedOmpEditorInternalsAdapterthat reproduces the exactEditorInternalssurface on omp's public Editor API. Controllers are untouched — the fix lives entirely behind the seam the codebase already centralized for this.Adapter mechanics (verified against
packages/tui/src/components/editor.ts@ omp 17.1.3):getLines()/getCursor()setText()+ cursor restore (omp'ssetTextanchors the cursor to the end).state.linesis a write-through proxy: index writes, whole-array assignment, and mutating methods (splice, …) commit viasetText.\x1b[C/\x1b[D) dispatched to the baseEditor.prototype.handleInput(bypassing the modal override, which would re-enter vim dispatch). omp's native step is grapheme-aware and wraps across logical line boundaries, so a left/right walk reaches any(line, col)exactly — no visual-line ambiguity.onChange(omp'ssetTextfires it natively — exposing it would double-fire),undoStack/pushUndoSnapshot(plugin's own fallback stack is used),tui(host renders after dispatch),scrollOffset/lastWidth(renderer has fallbacks),segment(Intl.Segmenterfallback).Tests
test/omp-internals-adapter.test.ts: 15 new tests driving an omp-faithful double (public API only, omp's exact arrow/setText/onChangesemantics): host detection + adapter caching, state-proxy reads/writes/splice/assignment/clamping, the history-nav edge guard, and end-to-endMovementController(hjkl/w/b/0/$/G) andTextEditController(x, dd, p, u, o) through the adapter, plus single-fireonChange.bun test),bun run check(biome +tsc --noEmit) clean. The existingtest/editor-internals.test.tstripwire confirms the pi path still returns native internals.Limitations (honest list)
Editor.prototype.handleInput+tui.editor.cursor*default bindings), not a live TUI. Worst case it degrades back to today's behavior, never worse.scrollOffset = 0/ computed-lastWidthfallbacks — correct for unscrolled prompts, which is the common case.Review notes (codex gpt-5.5 high pass)
One finding fixed post-review: the lines-proxy mutator check used
prop in RECORD, which also matches inheritedObject.prototypenames (toString, …) and caused a spurious commit — nowObject.hasOwn.Two findings were confirmed real but intentionally not fixed, documented here as tradeoffs:
j/k: the vertical guard uses logical lines, so within a single long wrapped logical linej/kno-op (pi moves by visual row). The safe alternative doesn't exist plugin-side: omp's up/down at the first/last visual line triggers prompt-history navigation (which replaces the draft) or line-end jumps, and the wrap width (#lastWidth) is private, so we cannot tell when an arrow is safe. Conservative guard stays until omp exposes layout info.deleteForwardat EOL: assign +splice) commit each write, soonChangecan observe a transient intermediate buffer before the final one, synchronously, within one input dispatch. omp's change consumers are debounced, and the alternative (deferred commits flushed viatui.requestRender) breaks cursor feedback on direct-setCursorpaths likejumpWord/leap— worse than the transient.Update: visual mode fixed (was crashing under omp)
Live testing surfaced that
vbroke the editor entirely under omp. Two root causes, both fixed in the latest push:getPaddingX()is pi-only — omp resolves padding privately (override ?? theme.editorPaddingX ?? 2), so the renderer threw a TypeError on every frame in visual mode. It now probes the host once and uses the theme'seditorPaddingXhint (threaded fromVimModalEditor) with omp's default2as fallback.padding + text + padding(exactly what the renderer rebuilt); omp rows carry box side chrome (│ + pad … pad + │) with the bottom border fused into the last text row. On omp the renderer now column-slices the original row's chrome off and swaps only the content region — glyph- and style-agnostic across symbol presets — including omp's right-chrome shrink when the EOL cursor overflows one cell.Three new tests cover the omp row format (fused bottom row, middle-row chrome, width preservation under a width-neutral style). Suite: 189 pass / 0 fail.