Skip to content

Commit 9dee2c9

Browse files
author
Snir Turgeman
committed
fix: cursor position when switching terminal sessions
Add jobresize() calls to notify the terminal job of window dimensions when switching between sessions. This fixes the cursor appearing in the wrong position and line shifting after session switch. The terminal job needs to know its window dimensions to correctly calculate cursor position and line wrapping. Without this, the terminal renders based on stale window state from the previous session.
1 parent 8f8373b commit 9dee2c9

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

lua/claudecode/init.lua

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1197,11 +1197,64 @@ function M.show_session_picker()
11971197
end
11981198
end
11991199

1200-
---Try to use an enhanced picker (fzf-lua)
1200+
---Try to use an enhanced picker (Snacks or fzf-lua)
12011201
---@param items table[] Items to pick from
12021202
---@param on_select function Callback when item is selected
12031203
---@return boolean success Whether an enhanced picker was used
12041204
function M._try_picker(items, on_select)
1205+
-- Try Snacks picker first
1206+
local snacks_ok, Snacks = pcall(require, "snacks")
1207+
if snacks_ok and Snacks and Snacks.picker then
1208+
local picker_items = {}
1209+
for _, item in ipairs(items) do
1210+
table.insert(picker_items, {
1211+
text = item.display,
1212+
item = item,
1213+
})
1214+
end
1215+
1216+
Snacks.picker.pick({
1217+
source = "claude_sessions",
1218+
items = picker_items,
1219+
format = function(item)
1220+
return { { item.text } }
1221+
end,
1222+
layout = {
1223+
preview = false,
1224+
},
1225+
confirm = function(picker, item)
1226+
picker:close()
1227+
if item and item.item then
1228+
on_select(item.item)
1229+
end
1230+
end,
1231+
actions = {
1232+
close_session = function(picker, item)
1233+
if item and item.item and item.item.session then
1234+
local terminal_mod = require("claudecode.terminal")
1235+
terminal_mod.close_session(item.item.session.id)
1236+
vim.notify("Closed session: " .. item.item.session.name, vim.log.levels.INFO)
1237+
picker:close()
1238+
end
1239+
end,
1240+
},
1241+
win = {
1242+
input = {
1243+
keys = {
1244+
["<C-x>"] = { "close_session", mode = { "i", "n" }, desc = "Close session" },
1245+
},
1246+
},
1247+
list = {
1248+
keys = {
1249+
["<C-x>"] = { "close_session", mode = { "n" }, desc = "Close session" },
1250+
},
1251+
},
1252+
},
1253+
title = "Claude Sessions (Ctrl-X: close)",
1254+
})
1255+
return true
1256+
end
1257+
12051258
-- Try fzf-lua
12061259
local fzf_ok, fzf = pcall(require, "fzf-lua")
12071260
if fzf_ok and fzf then
@@ -1223,6 +1276,23 @@ function M._try_picker(items, on_select)
12231276
end
12241277
end
12251278
end,
1279+
["ctrl-x"] = {
1280+
fn = function(selected)
1281+
if selected and selected[1] then
1282+
local item = item_map[selected[1]]
1283+
if item and item.session then
1284+
local terminal_mod = require("claudecode.terminal")
1285+
terminal_mod.close_session(item.session.id)
1286+
vim.notify("Closed session: " .. item.session.name, vim.log.levels.INFO)
1287+
end
1288+
end
1289+
end,
1290+
-- Close picker after action since session list changed
1291+
exec_silent = true,
1292+
},
1293+
},
1294+
fzf_opts = {
1295+
["--header"] = "Enter: switch | Ctrl-X: close session",
12261296
},
12271297
})
12281298
return true

lua/claudecode/terminal/native.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,12 @@ local function show_hidden_session_terminal_impl(session_id, effective_config, f
712712
vim.api.nvim_win_set_buf(new_winid, state.bufnr)
713713
state.winid = new_winid
714714

715+
-- Notify terminal of window dimensions to fix cursor position after session switch
716+
local chan = vim.bo[state.bufnr].channel
717+
if chan and chan > 0 then
718+
pcall(vim.fn.jobresize, chan, width, full_height)
719+
end
720+
715721
if focus then
716722
vim.api.nvim_set_current_win(new_winid)
717723
vim.cmd("startinsert")
@@ -777,6 +783,17 @@ function M.focus_session(session_id, effective_config)
777783
return
778784
end
779785

786+
-- Notify terminal of window dimensions to fix cursor position after session switch
787+
local state = terminals[session_id]
788+
if state and state.bufnr and vim.api.nvim_buf_is_valid(state.bufnr) then
789+
local chan = vim.bo[state.bufnr].channel
790+
if chan and chan > 0 then
791+
local width = vim.api.nvim_win_get_width(win)
792+
local height = vim.api.nvim_win_get_height(win)
793+
pcall(vim.fn.jobresize, chan, width, height)
794+
end
795+
end
796+
780797
vim.api.nvim_set_current_win(win)
781798
vim.cmd("startinsert")
782799
end

lua/claudecode/terminal/snacks.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,14 @@ function M.focus_session(session_id, config)
498498
local term_buf_id = term_instance.buf
499499
if term_buf_id and vim.api.nvim_buf_get_option(term_buf_id, "buftype") == "terminal" then
500500
if term_instance.win and vim.api.nvim_win_is_valid(term_instance.win) then
501+
-- Notify terminal of window dimensions to fix cursor position after session switch
502+
local chan = vim.bo[term_buf_id].channel
503+
if chan and chan > 0 then
504+
local width = vim.api.nvim_win_get_width(term_instance.win)
505+
local height = vim.api.nvim_win_get_height(term_instance.win)
506+
pcall(vim.fn.jobresize, chan, width, height)
507+
end
508+
501509
vim.api.nvim_win_call(term_instance.win, function()
502510
vim.cmd("startinsert")
503511
end)

0 commit comments

Comments
 (0)