diff --git a/org/channel-tui-view.org b/org/channel-tui-view.org index 555c5fe..97548c7 100644 --- a/org/channel-tui-view.org +++ b/org/channel-tui-view.org @@ -218,7 +218,7 @@ and current sidebar mode (:auto/:visible/:hidden)." ;; Speaker lines for all input rows (dotimes (r panel-rows) (cl-tty.backend:draw-text fb hpad (+ panel-top r) "│" (theme-color :input-prompt) nil)) - ;; Draw each wrapped input line + ;; Draw each wrapped input line, tracking display position of cursor (let ((accum 0) (cl 0) (cc 0)) (dotimes (i n-lines) (let* ((line (nth i lines)) @@ -226,9 +226,9 @@ and current sidebar mode (:auto/:visible/:hidden)." (len (length line))) (when (>= row (- h 4)) (return)) (cl-tty.backend:draw-text fb (+ hpad 2) row line input-fg nil) - (when (and (>= pos accum) (<= pos (+ accum len))) + (when (and (>= pos accum) (or (< pos (+ accum len)) (= i (1- n-lines)))) (setf cl i cc (- pos accum))) - (incf accum (1+ len)))) + (incf accum len))) (setf (st :cursor-line) cl (st :cursor-col) cc)) ;; Hint bar at h-2: F:/MCP: on left, token gauge + keybindings on right (let* ((focal (or (st :foveal-id) "-")) @@ -343,35 +343,26 @@ and current sidebar mode (:auto/:visible/:hidden)." (setf (st :dirty) (list nil nil nil)))) (defun position-cursor (fb w h) - "Draw cursor at the input insertion point using reverse video (Emacs-style)." - (let* ((sw (if (sidebar-visible-p w) (or (st :sidebar-width) 42) 0)) - (cw (- w sw)) - (hpad 2) - (text (input-string)) + "Draw cursor at the input insertion point using reverse video (Emacs-style). +Uses cursor-line/cursor-col stored by view-input to stay aligned with rendering." + (let* ((text (input-string)) (text-len (length text)) (pos (or (st :cursor-pos) 0)) - (prompt-w (- cw (* 2 hpad) 2)) + (cl (or (st :cursor-line) 0)) + (cc (or (st :cursor-col) 0)) + (hpad 2) + (sw (if (sidebar-visible-p w) (or (st :sidebar-width) 42) 0)) + (cw (- w sw)) + (inner-w (- cw (* 2 hpad))) + (prompt-w (- inner-w 2)) (lines (cl-tty.box:word-wrap text prompt-w)) (n-lines (max 1 (length lines))) - (cl 0) (cc 0) (accum 0)) - ;; Find which wrapped line the cursor falls on - (dotimes (i n-lines) - (let ((len (length (nth i lines)))) - (when (and (>= pos accum) (or (<= pos (+ accum len)) - (= i (1- n-lines)))) - (setf cl i cc (- pos accum))) - (incf accum (1+ len)))) - ;; If text exists but pos is 0, move cursor to end (recovery for pos reset) - (when (and (plusp text-len) (zerop pos)) - (setf pos text-len - cl (1- n-lines) - cc (length (car (last lines))))) - (let* ((panel-rows (max 4 (+ n-lines 2))) - (panel-top (- h 4 panel-rows -1)) - (cx (+ hpad 2 cc)) - (cy (+ panel-top 1 cl)) - (bg-i (theme-color :bg-input)) - (input-fg (theme-color :input-fg))) + (panel-rows (max 4 (+ n-lines 2))) + (panel-top (- h 4 panel-rows -1)) + (bg-i (theme-color :bg-input)) + (input-fg (theme-color :input-fg))) + (let ((cx (+ hpad 2 cc)) + (cy (+ panel-top 1 cl))) (if (< pos text-len) (let ((ch (char text pos))) (cl-tty.backend:draw-text fb cx cy (string ch) bg-i input-fg))