-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathai-code-backends-infra-ghostel.el
More file actions
137 lines (118 loc) · 5.85 KB
/
ai-code-backends-infra-ghostel.el
File metadata and controls
137 lines (118 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;;; ai-code-backends-infra-ghostel.el --- Ghostel support for AI Code terminals -*- lexical-binding: t; -*-
;; Author: Kang Tu, AI Agent
;; SPDX-License-Identifier: Apache-2.0
;;; Commentary:
;; Ghostel-specific support for `ai-code-backends-infra'.
;;; Code:
(require 'ai-code-session-link)
;; Prefer `ghostel-exec' for Ghostel backend startup when available, as
;; it simplifies process startup integration.
(declare-function ai-code-backends-infra--configure-session-input-shortcuts
"ai-code-backends-infra" ())
(declare-function ai-code-backends-infra--install-navigation-cursor-sync
"ai-code-backends-infra" ())
(declare-function ai-code-backends-infra--note-meaningful-output
"ai-code-backends-infra" ())
(declare-function ai-code-backends-infra--output-meaningful-p
"ai-code-backends-infra" (output))
(declare-function ai-code-backends-infra--set-session-directory
"ai-code-backends-infra" (buffer directory))
(declare-function ai-code-backends-infra--sync-terminal-cursor
"ai-code-backends-infra" ())
(declare-function ghostel-exec "ghostel" (buffer program &optional args))
(declare-function ghostel-send-key "ghostel" (key-name &optional mods))
(declare-function ghostel-send-string "ghostel" (string))
(declare-function ghostel--window-adjust-process-window-size
"ghostel" (process windows))
(defvar ai-code-backends-infra--session-terminal-backend)
(defvar ghostel--copy-mode-active nil)
(defvar ghostel--input-mode)
(defvar ghostel-kill-buffer-on-exit)
(defvar ghostel-set-title-function)
(defun ai-code-backends-infra-ghostel-ensure-backend ()
"Ensure the Ghostel backend is available."
(unless (featurep 'ghostel) (require 'ghostel nil t))
(unless (featurep 'ghostel)
(user-error "The package ghostel is not installed")))
(defun ai-code-backends-infra-ghostel-navigation-mode-p ()
"Return non-nil when the current Ghostel buffer is in copy mode."
(or (bound-and-true-p ghostel--copy-mode-active)
(eq ghostel--input-mode 'copy)))
(defun ai-code-backends-infra-ghostel-install-navigation-cursor-sync ()
"Install cursor synchronization for Ghostel navigation mode."
(add-hook 'post-command-hook
#'ai-code-backends-infra--sync-terminal-cursor nil t))
(defun ai-code-backends-infra-ghostel-send-string (string)
"Send STRING to the current Ghostel process."
(ghostel-send-string string))
(defun ai-code-backends-infra-ghostel-send-escape ()
"Send escape to the current Ghostel process."
(ghostel-send-key "escape"))
(defun ai-code-backends-infra-ghostel-send-return ()
"Send return to the current Ghostel process."
(ghostel-send-key "return"))
(defun ai-code-backends-infra-ghostel-send-backspace ()
"Send backspace to the current Ghostel process."
(ghostel-send-key "backspace"))
(defun ai-code-backends-infra-ghostel-resize-handler ()
"Return the Ghostel resize handler."
#'ghostel--window-adjust-process-window-size)
(defun ai-code-backends-infra--configure-ghostel-buffer ()
"Configure the current Ghostel buffer for AI Code sessions."
(setq-local ghostel-set-title-function nil)
(setq-local ghostel-kill-buffer-on-exit nil)
(ai-code-backends-infra--configure-session-input-shortcuts)
(ai-code-backends-infra--install-navigation-cursor-sync))
(defun ai-code-backends-infra--start-ghostel-process (buffer command)
"Start a Ghostel session in BUFFER for COMMAND."
(with-current-buffer buffer
(ai-code-backends-infra--configure-ghostel-buffer)
(let* ((argv (split-string-shell-command command))
(program (car argv))
(args (cdr argv)))
(cond
((not program) nil)
((fboundp 'ghostel-exec)
(let ((proc (ghostel-exec buffer program args)))
;; `ghostel-exec' enters `ghostel-mode', which resets local state.
(ai-code-backends-infra--configure-ghostel-buffer)
proc))
(t
(user-error
"Ghostel backend requires a Ghostel version that provides `ghostel-exec`"))))))
(defun ai-code-backends-infra-ghostel-create-session (buffer-name working-dir command env-vars)
"Create a Ghostel session named BUFFER-NAME in WORKING-DIR.
COMMAND is the shell command to run and ENV-VARS are extra environment
variables for the terminal process."
(let* ((working-dir (file-name-as-directory (expand-file-name working-dir)))
(buffer (get-buffer-create buffer-name))
(process-environment (append env-vars process-environment)))
(ai-code-backends-infra--set-session-directory buffer working-dir)
(with-current-buffer buffer
(setq-local default-directory working-dir)
(setq-local ai-code-backends-infra--session-terminal-backend 'ghostel)
(let ((default-directory working-dir)
(proc (ai-code-backends-infra--start-ghostel-process buffer command)))
(when (processp proc)
(ignore-errors
(set-process-query-on-exit-flag proc nil))
(when-let ((sentinel (ignore-errors (process-sentinel proc))))
(ignore-errors
(process-put proc
'ai-code-backends-infra--ghostel-sentinel
sentinel)))
(let ((orig-filter (process-filter proc)))
(set-process-filter
proc
(lambda (process output)
(when (buffer-live-p buffer)
(when orig-filter
(funcall orig-filter process output))
(when (buffer-live-p buffer)
(with-current-buffer buffer
(when (ai-code-backends-infra--output-meaningful-p output)
(ai-code-backends-infra--note-meaningful-output))
(ai-code-session-link--linkify-recent-output output))))))))
(cons buffer proc)))))
(provide 'ai-code-backends-infra-ghostel)
;;; ai-code-backends-infra-ghostel.el ends here