-
Notifications
You must be signed in to change notification settings - Fork 0
/
chatgpt-repl.el
103 lines (89 loc) · 3.18 KB
/
chatgpt-repl.el
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
;;; chatgpt-repl.el --- -*- lexical-binding: t; -*-
;; Keywords: tools
(require 'dash)
(defvar chatgpt-bin "chatgpt")
(defvar chatgpt-buffer-name "*chatgpt-repl*")
(defvar chatgpt-err-buffer-name "*chatgpt-repl-err*")
(defun chatgpt-repl-insert-prompt ()
(save-excursion
(goto-char (point-max))
(insert "\n> ")
(comint-set-process-mark)))
(defun chatgpt-bin-eval (input buffer)
(make-process :name "chatgpt-repl-bin"
:command (list chatgpt-bin input)
:stderr (get-buffer-create chatgpt-err-buffer-name)
:filter (lambda (proc string)
(with-current-buffer buffer
(save-excursion
(goto-char (point-max))
(insert string))))
:sentinel (lambda (proc event)
(when (not (process-live-p proc))
(with-current-buffer buffer
(chatgpt-repl-insert-prompt)))))
nil)
(defun chatgpt-repl-rep (input buffer)
(chatgpt-bin-eval input buffer))
(defun chatgpt-repl-send-input ()
(interactive)
(let ((input (buffer-substring
(process-mark (get-buffer-process (current-buffer)))
(point-max))))
(if (string-empty-p (string-trim input))
(chatgpt-repl-insert-prompt)
(progn
(comint-send-input)
(chatgpt-repl-rep input (current-buffer))))))
(defun chatgpt-repl-move-beginning-of-line ()
(interactive)
(let ((pos (comint-line-beginning-position)))
(if (= (point) pos)
(call-interactively #'back-to-indentation)
(goto-char pos))))
(defvar chatgpt-repl-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") #'chatgpt-repl-send-input)
(define-key map (kbd "C-a") #'chatgpt-repl-move-beginning-of-line)
(define-key map (kbd "C-k") #'kill-line)
map))
(define-derived-mode chatgpt-repl-mode comint-mode "chatgpt-repl"
""
(setq comint-prompt-regexp "^> ")
(setq comint-input-sender (lambda (proc s) nil))
(setq comint-process-echoes nil)
(setq comint-use-prompt-regexp t)
(unless (comint-check-proc (current-buffer))
(let ((process (start-process "chatgpt-repl" (current-buffer) "hexl")))
(set-process-query-on-exit-flag process nil)
(insert "ChatGPT-REPL\n")
(insert "make sure (get-env \"OPENAI_API_KEY\") and (executable-find \"chatgpt\") exist,\n")
(insert "install chatgpt bin: npm install chatgpt -g\n")
(insert "set env: M-x set-env")
(chatgpt-repl-insert-prompt))))
;;;###autoload
(defun chatgpt-repl ()
(interactive)
(let ((buffer (get-buffer-create chatgpt-buffer-name)))
(pop-to-buffer buffer)
(chatgpt-repl-mode)))
;;;###autoload
(defun chatgpt-repl-send (string)
(interactive "s")
(let ((buffer (get-buffer chatgpt-buffer-name)))
(when (not buffer)
(call-interactively 'chatgpt-repl))
(with-current-buffer chatgpt-buffer-name
(save-excursion
(goto-char (point-max))
(insert string))
(call-interactively 'chatgpt-repl-send-input))
(pop-to-buffer chatgpt-buffer-name)))
;;;###autoload
(defun chatgpt-translate-region ()
(interactive)
(when (not (region-active-p))
(user-error "no region active"))
(let ((s (buffer-substring-no-properties (region-beginning) (region-end))))
(chatgpt-repl-send (format "translate into english or chinese: %s" s))))
(provide 'chatgpt-repl)