You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Using Home/End to move cursor to start or end of line breaks after submitting prompt #56890
When I first launch OpenCode and am entering an initial prompt, the Home/End keys work to move the cursor to the start or end of the prompt. But after submitting the initial prompt, Home and End stop working when the prompt editor is focused, and instead unexpectedly scroll the output history.
Plugins
None
OpenCode version
2.0.32
Steps to reproduce
Launch OpenCode and type a short prompt.
Press Home key and notice that it moves the cursor to the start of the prompt, and End moves the cursor to the end of the prompt.
Press Enter to submit the prompt, then start typing a new prompt within the same context.
Notice that Home/End no longer move the cursor as expected, and instead scroll to the top/bottom of the output history.
This very much feels like a bug, since Home/End work initially before submitting the first prompt, but stop working after submitting it.
Thanks for the clear report, @theodorejb. I reproduced this on 2.0.32, and it still happens on the latest dev (501b15a).
Steps:
On the start screen, type hello world, press Home, type X, press End, type Y. The prompt reads Xhello worldY, as expected.
Submit a prompt and get a reply long enough to scroll.
Repeat step 1 in the session prompt. Home jumps the transcript to the first message and End jumps to the last, but the cursor doesn't move, so the prompt ends up as hello worldXY.
The recording and screenshots below show this, and the script below reproduces it. It looks like inside a session, the default bindings for jumping to the first and last message include home and end, and they take priority over the prompt.
Until this is addressed, ctrl+a / ctrl+e move the cursor to the start and end of the line. The older #54519 reported the same thing. It was filed against v1 and closed in the v1 cleanup.
recording.mp4
Reproduction script (drive.ts)
// Repro for #56890: Home/End move the prompt cursor on the start screen,// but inside a session they scroll the transcript instead.// Expected in both places: typing "hello world", Home, "X", End, "Y" gives "Xhello worldY".import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constprobe=(ui: any,label: string)=>Effect.gen(function*(){yield*ui.type("hello world")yield*Effect.sleep(300)yield*ui.press("home")yield*Effect.sleep(400)yield*ui.screenshot(`${label}-after-home`)yield*ui.type("X")yield*ui.press("end")yield*Effect.sleep(400)yield*ui.type("Y")yield*Effect.sleep(500)yield*ui.screenshot(`${label}-after-end`)constok=yield*ui.waitFor("Xhello worldY",{timeout: 2000}).pipe(Effect.as(true),Effect.catch(()=>Effect.succeed(false)),)constbad=yield*ui.waitFor("hello worldXY",{timeout: 1000}).pipe(Effect.as(true),Effect.catch(()=>Effect.succeed(false)),)yield*Effect.log(`${label}: Xhello worldY=${ok} hello worldXY=${bad}`)})asEffect.Effect<void,unknown,never>exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true,keypressOverlay: true},},({ ui, llm })=>Effect.gen(function*(){// 1) Start screen: worksyield*probe(ui,"start-screen")yield*ui.press("u",{ctrl: true})yield*ui.press("u",{ctrl: true})yield*Effect.sleep(300)// 2) Submit a prompt, get a reply long enough to scrollyield*llm.queue(Llm.text("First reply.\n\n"+Array.from({length: 60},(_,i)=>`line ${i+1}`).join("\n")),)yield*ui.submit("first message")yield*ui.waitFor("line 60")yield*Effect.sleep(800)// 3) Same keys inside the session: transcript scrolls, cursor does not moveyield*probe(ui,"session")yield*Effect.sleep(500)}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Tracing the cause to what the triage note already points at: session.first and session.last are bound to bare home / end in packages/tui/src/config/keybind.ts, and they are also listed in the ungated layer in packages/tui/src/routes/session/index.tsx. The layer that is gated on renderer.currentFocusedEditor === null is the one that should carry them; the second layer repeats them without that gate, so while the prompt editor is focused the transcript jump still claims the key before the editor can move the caret.
So the fix is to keep those two commands in the unfocused layer only, and cover it with a keymap test for both states: with the editor focused home/end must reach the input, and with it unfocused they must still jump to the first and last message.
Thanks for the report! Inside a session, Home and End are intentionally bound to jumping to the first and last message (#40123, #42066), so they don't move the prompt cursor there. To move within the prompt, use Ctrl+A / Ctrl+E for the start and end of the line, Alt+A / Alt+E for the visual line, or Shift+Home / Shift+End to select.
If you'd rather have Home/End edit the prompt, you can rebind them in tui.json:
It's confusing that the behavior when pressing Home and End changes when editing the initial prompt to start a session, vs. subsequent prompts in the session. IMO it should consistently do the same thing when editing any prompt and the focus is there. That's the expected behavior.
On a webpage, Home/End jump to the top or bottom of the page when no input is focused, but when a text input or textarea is focused they move the cursor to the beginning or end of the line. Couldn't OpenCode work like that?
Reacted by Stéphane Brunner, flamewave000 and phibel
Reacted by Stéphane Brunner, flamewave000 and phibel
Thanks for the report! Inside a session, Home and End are intentionally bound to jumping to the first and last message (#40123, #42066), so they don't move the prompt cursor there. To move within the prompt, use Ctrl+A / Ctrl+E for the start and end of the line, Alt+A / Alt+E for the visual line, or Shift+Home / Shift+End to select.
If you'd rather have Home/End edit the prompt, you can rebind them in tui.json:
This still doesn't make much sense to me. These keybindings appear to come from the Emacs editing model, but that's a very niche convention.
For decades, the de facto standard in text editors and IDEs has been:
Home / End: jump to the beginning/end of the current line
Ctrl+Home / Ctrl+End: jump to the beginning/end of the document
Ctrl+A: Select All
This behavior is consistent across editors such as nano, micro, vim (when not using vim specific binding), VS Code, Visual Studio, IntelliJ IDEA, Notepad++, and Sublime Text. It's what most users reasonably expect when editing text.
I agree with @theodorejb that Home and End should behave differently when focus is on the chat history rather than the input field. In that context, I'd expect behavior similar to other terminal applications like less: Home/End or Page Up/Page Down should navigate the history.
My main concern is using Emacs-style bindings as the default for everyone. While those bindings make sense for users who prefer them, they are not what the majority of users will expect. Defaults should generally follow the most common platform conventions and established UI standards, with alternative keymaps available as an opt-in preference.
As an analogy, I personally prefer tabs over spaces, but I recognize that many projects standardize on spaces. I don't expect the default to match my preference; I simply change the setting. Keyboard bindings should work the same way: use the convention most users are familiar with by default, and allow alternative schemes for those who prefer them.
Reacted by Theodore Brown, phibel, Stéphane Brunner and Jackson Legge
Reacted by Theodore Brown, phibel and Stéphane Brunner
Activity
opencode-agent commentedon Oct 18, 2026
Thanks for the clear report, @theodorejb. I reproduced this on 2.0.32, and it still happens on the latest
dev(501b15a).Steps:
hello world, press Home, typeX, press End, typeY. The prompt readsXhello worldY, as expected.hello worldXY.The recording and screenshots below show this, and the script below reproduces it. It looks like inside a session, the default bindings for jumping to the first and last message include
homeandend, and they take priority over the prompt.Until this is addressed,
ctrl+a/ctrl+emove the cursor to the start and end of the line. The older #54519 reported the same thing. It was filed against v1 and closed in the v1 cleanup.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.argszero commentedon Oct 18, 2026
I'd like to work on this.
Tracing the cause to what the triage note already points at:
session.firstandsession.lastare bound to barehome/endinpackages/tui/src/config/keybind.ts, and they are also listed in the ungated layer inpackages/tui/src/routes/session/index.tsx. The layer that is gated onrenderer.currentFocusedEditor === nullis the one that should carry them; the second layer repeats them without that gate, so while the prompt editor is focused the transcript jump still claims the key before the editor can move the caret.So the fix is to keep those two commands in the unfocused layer only, and cover it with a keymap test for both states: with the editor focused
home/endmust reach the input, and with it unfocused they must still jump to the first and last message.argszero commentedon Oct 19, 2026
Opened #56910 for this: the transcript jumps keep
ctrl+g,alt+homeandctrl+alt+g, andHome/Endnow reach the focused prompt again.Tarquinen commentedon Nov 6, 2026
Thanks for the report! Inside a session, Home and End are intentionally bound to jumping to the first and last message (#40123, #42066), so they don't move the prompt cursor there. To move within the prompt, use Ctrl+A / Ctrl+E for the start and end of the line, Alt+A / Alt+E for the visual line, or Shift+Home / Shift+End to select.
If you'd rather have Home/End edit the prompt, you can rebind them in
tui.json:{ "keybinds": { "session_first": "ctrl+g,alt+home", "session_last": "ctrl+alt+g", "input_buffer_home": "home", "input_buffer_end": "end" } }Closing this as working as intended.
— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊
theodorejb commentedon Nov 6, 2026
It's confusing that the behavior when pressing Home and End changes when editing the initial prompt to start a session, vs. subsequent prompts in the session. IMO it should consistently do the same thing when editing any prompt and the focus is there. That's the expected behavior.
On a webpage, Home/End jump to the top or bottom of the page when no input is focused, but when a text input or textarea is focused they move the cursor to the beginning or end of the line. Couldn't OpenCode work like that?
flamewave000 commentedon Nov 6, 2026
This still doesn't make much sense to me. These keybindings appear to come from the Emacs editing model, but that's a very niche convention.
For decades, the de facto standard in text editors and IDEs has been:
This behavior is consistent across editors such as nano, micro, vim (when not using vim specific binding), VS Code, Visual Studio, IntelliJ IDEA, Notepad++, and Sublime Text. It's what most users reasonably expect when editing text.
I agree with @theodorejb that Home and End should behave differently when focus is on the chat history rather than the input field. In that context, I'd expect behavior similar to other terminal applications like
less: Home/End or Page Up/Page Down should navigate the history.My main concern is using Emacs-style bindings as the default for everyone. While those bindings make sense for users who prefer them, they are not what the majority of users will expect. Defaults should generally follow the most common platform conventions and established UI standards, with alternative keymaps available as an opt-in preference.
As an analogy, I personally prefer tabs over spaces, but I recognize that many projects standardize on spaces. I don't expect the default to match my preference; I simply change the setting. Keyboard bindings should work the same way: use the convention most users are familiar with by default, and allow alternative schemes for those who prefer them.