|
6 | 6 | ;; Maintainer: Shen, Jen-Chieh <[email protected]> |
7 | 7 | ;; URL: https://github.com/emacs-openai/chatgpt |
8 | 8 | ;; Version: 0.1.0 |
9 | | -;; Package-Requires: ((emacs "26.1") (openai "0.1.0")) |
| 9 | +;; Package-Requires: ((emacs "26.1") (openai "0.1.0") (ht "2.0")) |
10 | 10 | ;; Keywords: comm openai |
11 | 11 |
|
12 | 12 | ;; This file is not part of GNU Emacs. |
|
31 | 31 |
|
32 | 32 | ;;; Code: |
33 | 33 |
|
| 34 | +(require 'comint) |
| 35 | + |
34 | 36 | (require 'openai) |
| 37 | +(require 'ht) |
35 | 38 |
|
36 | 39 | (defgroup chatgpt nil |
37 | 40 | "Use ChatGPT inside Emacs." |
38 | 41 | :prefix "chatgpt-" |
39 | 42 | :group 'comm |
40 | 43 | :link '(url-link :tag "Repository" "https://github.com/emacs-openai/chatgpt")) |
41 | 44 |
|
| 45 | +(defconst chatgpt-buffer-name-format "*ChatGPT: <%s>*" |
| 46 | + "Name of the buffer to use for the `chatgpt' comint instance.") |
| 47 | + |
| 48 | +(defvar chatgpt-instances (ht-create) |
| 49 | + "List of instances, each pair is consist of (index . buffer).") |
| 50 | + |
| 51 | +;; |
| 52 | +;;; Util |
| 53 | + |
| 54 | +(defun chatgpt--pop-to-buffer (buffer-or-name) |
| 55 | + "" |
| 56 | + (pop-to-buffer buffer-or-name `((display-buffer-in-direction) |
| 57 | + (dedicated . t)))) |
| 58 | + |
| 59 | +;; |
| 60 | +;;; Core |
| 61 | + |
| 62 | +(defun chatgpt--live-instances () |
| 63 | + "Return a list of live instances." |
| 64 | + (let ((live-instances)) |
| 65 | + (ht-map (lambda (index buffer) |
| 66 | + (when (get-buffer buffer) |
| 67 | + (push buffer live-instances))) |
| 68 | + chatgpt-instances) |
| 69 | + (reverse live-instances))) |
| 70 | + |
| 71 | +(defun chatgpt--shown-instances () |
| 72 | + "Return a list of live instances that are displayed on the screen." |
| 73 | + (let ((live-instances (chatgpt--live-instances)) |
| 74 | + (shown-instances)) |
| 75 | + (dolist (instance shown-instances) |
| 76 | + (when (get-buffer-window instance) |
| 77 | + (push instance shown-instances))) |
| 78 | + (reverse shown-instances))) |
| 79 | + |
| 80 | +(defun chatgpt--new-index () |
| 81 | + "Find killed instance before giving new index." |
| 82 | + (let ((target)) |
| 83 | + (cl-some (lambda (index) |
| 84 | + (let ((buffer (ht-get chatgpt-instances index))) |
| 85 | + (unless (get-buffer buffer) ; if buffer is killed |
| 86 | + (setq target index) |
| 87 | + t))) |
| 88 | + (ht-keys chatgpt-instances)) |
| 89 | + (unless target ; No killed instance? |
| 90 | + (setq target (ht-size chatgpt-instances))) ; Create a new one! |
| 91 | + target)) |
| 92 | + |
| 93 | +;;;###autoload |
| 94 | +(define-derived-mode chatgpt-mode comint-mode "ChatGPT" |
| 95 | + "Major mode for `chatgpt-mode'. |
| 96 | +
|
| 97 | +\\<chatgpt-mode-map>" |
| 98 | + (setq comint-prompt-regexp cassandra-prompt-regexp |
| 99 | + comint-prompt-read-only t)) |
| 100 | + |
| 101 | +;;;###autoload |
| 102 | +(defun chatgpt-new () |
| 103 | + "Run a new instance of ChatGPT." |
| 104 | + (interactive) |
| 105 | + (let* ((new-index (chatgpt--new-index)) |
| 106 | + (new-buffer-name (format chatgpt-buffer-name-format new-index))) |
| 107 | + (when (get-buffer new-buffer-name) |
| 108 | + (user-error "Internal Error: creating instance that already exists")) |
| 109 | + (ht-set chatgpt-instances new-index (get-buffer-create new-buffer-name)) |
| 110 | + (with-current-buffer new-buffer-name |
| 111 | + (chatgpt-mode 1)) |
| 112 | + (chatgpt--pop-to-buffer new-buffer-name))) |
| 113 | + |
| 114 | +;;;###autoload |
| 115 | +(defun chatgpt () |
| 116 | + "Start ChatGPT with existing instance, else create a new instance." |
| 117 | + (interactive) |
| 118 | + (let ((live-instances (chatgpt--live-instances)) |
| 119 | + (shown-instances (chatgpt--shown-instances))) |
| 120 | + (cond (shown-instances |
| 121 | + (chatgpt--pop-to-buffer (nth 0 shown-instances))) |
| 122 | + (live-instances |
| 123 | + (chatgpt--pop-to-buffer (nth 0 shown-instances))) |
| 124 | + (t |
| 125 | + (chatgpt-new))))) |
| 126 | + |
42 | 127 | (provide 'chatgpt) |
43 | 128 | ;;; chatgpt.el ends here |
0 commit comments