Skip to content

Commit c4de23a

Browse files
committed
diff
1 parent d34aa0f commit c4de23a

File tree

1 file changed

+114
-22
lines changed

1 file changed

+114
-22
lines changed

chatgpt.el

Lines changed: 114 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
:type 'number
6060
:group 'chatgpt)
6161

62+
(defcustom chatgpt-input-method 'window
63+
"The method receive input."
64+
:type '(choice (const :tag "Read from minibuffer" minibuffer)
65+
(const :tag "Read inside new window" window))
66+
:group 'chatgpt)
67+
6268
(defconst chatgpt-buffer-name-format "*ChatGPT: <%s>*"
6369
"Name of the buffer to use for the `chatgpt' instance.")
6470

@@ -88,6 +94,12 @@
8894
;;
8995
;;; Util
9096

97+
(defun chatgpt--kill-buffer (buffer-or-name)
98+
"Like function `kill-buffer' but in the safe way."
99+
(when-let ((buffer (get-buffer chatgpt-input-buffer-name)))
100+
(when (buffer-live-p buffer)
101+
(kill-buffer buffer))))
102+
91103
(defun chatgpt--pop-to-buffer (buffer-or-name)
92104
"Wrapper to function `pop-to-buffer'.
93105
@@ -234,33 +246,108 @@ The data is consist of ROLE and CONTENT."
234246
(chatgpt--fill-region start (point)))))
235247
(cl-incf chatgpt--display-pointer)))
236248

249+
(defun chatgpt-send-response (response)
250+
"Send RESPONSE to ChatGPT."
251+
(let ((user (chatgpt-user))
252+
(instance chatgpt-instance))
253+
(when (string-empty-p response)
254+
(user-error "[INFO] Invalid response or instruction: %s" response))
255+
(chatgpt--add-message user response) ; add user's response
256+
(chatgpt-with-instance instance
257+
(chatgpt--display-messages)) ; display it
258+
(setq chatgpt-requesting-p t)
259+
(openai-chat chatgpt-chat-history
260+
(lambda (data)
261+
(chatgpt-with-instance instance
262+
(setq chatgpt-requesting-p nil)
263+
(chatgpt--add-tokens data)
264+
(chatgpt--add-response-messages data)
265+
(chatgpt--display-messages)))
266+
:model chatgpt-model
267+
:max-tokens chatgpt-max-tokens
268+
:temperature chatgpt-temperature
269+
:user user)))
270+
237271
(defun chatgpt-type-response ()
238272
"Type response to OpenAI."
239273
(interactive)
240274
(cond
241275
(chatgpt-requesting-p
242276
(message "[BUSY] Waiting for OpanAI to response..."))
243277
(t
244-
(let ((response (read-string "Type response: "))
245-
(user (chatgpt-user))
246-
(instance chatgpt-instance))
247-
(when (string-empty-p response)
248-
(user-error "[INFO] Invalid response or instruction: %s" response))
249-
(chatgpt--add-message user response) ; add user's response
250-
(chatgpt-with-instance instance
251-
(chatgpt--display-messages)) ; display it
252-
(setq chatgpt-requesting-p t)
253-
(openai-chat chatgpt-chat-history
254-
(lambda (data)
255-
(chatgpt-with-instance instance
256-
(setq chatgpt-requesting-p nil)
257-
(chatgpt--add-tokens data)
258-
(chatgpt--add-response-messages data)
259-
(chatgpt--display-messages)))
260-
:model chatgpt-model
261-
:max-tokens chatgpt-max-tokens
262-
:temperature chatgpt-temperature
263-
:user user)))))
278+
(cl-case chatgpt-input-method
279+
(`minibuffer
280+
(chatgpt-send-response (read-string "Type response: ")))
281+
(`window
282+
(chatgpt--start-input chatgpt-instance))
283+
(t
284+
(user-error "Invalid input method: %s" chatgpt-input-method))))))
285+
286+
;;
287+
;;; Input
288+
289+
(defconst chatgpt-input-buffer-name "*ChatGPT-Input*"
290+
"Buffer name to receive input.")
291+
292+
(defvar chatgpt-input-instance nil
293+
"The current instance; there is only one instance at a time.")
294+
295+
(defun chatgpt--start-input (instance)
296+
"Start input from INSTANCE."
297+
(chatgpt--kill-buffer chatgpt-input-buffer-name) ; singleton
298+
(let ((dir (if (window-parameter nil 'window-side)
299+
'bottom 'down))
300+
(buffer (get-buffer-create chatgpt-input-buffer-name)))
301+
(with-current-buffer buffer
302+
(chatgpt-input-mode)
303+
(setq chatgpt-input-instance instance)
304+
(erase-buffer)
305+
(insert "Type response here...")
306+
(mark-whole-buffer)) ; waiting for deletion
307+
(pop-to-buffer buffer `((display-buffer-in-direction)
308+
(direction . ,dir)
309+
(dedicated . t)
310+
(window-height . fit-window-to-buffer)))))
311+
312+
(defun chatgpt-input-send ()
313+
"Send the input."
314+
(interactive)
315+
(cond
316+
((not (eq major-mode #'chatgpt-input-mode)) ) ; does nothing
317+
(chatgpt-requesting-p
318+
(message "[BUSY] Waiting for OpanAI to response..."))
319+
(t
320+
(if (use-region-p)
321+
(delete-region (region-beginning) (region-end))
322+
(let ((response (buffer-string)))
323+
(chatgpt-with-instance chatgpt-input-instance
324+
(chatgpt-send-response response))
325+
(erase-buffer))))))
326+
327+
(defun chatgpt-input--post-command ()
328+
"Execution after input."
329+
(let ((max-lines (line-number-at-pos (point-max))))
330+
(fit-window-to-buffer)
331+
(enlarge-window (- max-lines (window-text-height)))))
332+
333+
(defun chatgpt-input-header-line ()
334+
"The display for input header line."
335+
(format "Session: %s" (cdr chatgpt-input-instance)))
336+
337+
(defvar chatgpt-input-mode-map
338+
(let ((map (make-sparse-keymap)))
339+
(define-key map (kbd "S-<return>") #'newline)
340+
(define-key map (kbd "RET") #'chatgpt-input-send)
341+
map)
342+
"Keymap for `chatgpt-mode'.")
343+
344+
;;;###autoload
345+
(define-derived-mode chatgpt-input-mode fundamental-mode "ChatGPT Input"
346+
"Major mode for `chatgpt-input-mode'.
347+
348+
\\<chatgpt-input-mode-map>"
349+
(setq-local header-line-format `((:eval (chatgpt-input-header-line))))
350+
(add-hook 'post-command-hook #'chatgpt-input--post-command nil t))
264351

265352
;;
266353
;;; Info
@@ -282,7 +369,7 @@ The data is consist of ROLE and CONTENT."
282369
(defun chatgpt-info ()
283370
"Show session information."
284371
(interactive)
285-
(when (eq major-mode 'chatgpt-mode)
372+
(when (eq major-mode #'chatgpt-mode)
286373
(lv-message
287374
(concat
288375
(format "session: %s" (cdr chatgpt-instance)) "\n"
@@ -303,6 +390,10 @@ The data is consist of ROLE and CONTENT."
303390
;;
304391
;;; Entry
305392

393+
(defun chatgpt-mode-kill-buffer ()
394+
""
395+
)
396+
306397
(defvar chatgpt-mode-map
307398
(let ((map (make-sparse-keymap)))
308399
(define-key map (kbd "RET") #'chatgpt-type-response)
@@ -315,7 +406,8 @@ The data is consist of ROLE and CONTENT."
315406
316407
\\<chatgpt-mode-map>"
317408
(setq-local buffer-read-only t)
318-
(font-lock-mode -1))
409+
(font-lock-mode -1)
410+
(add-hook 'kill-buffer-hook #'chatgpt-mode-kill-buffer nil t))
319411

320412
(defun chatgpt-register-instance (index buffer-or-name)
321413
"Register BUFFER-OR-NAME with INDEX as an instance.

0 commit comments

Comments
 (0)