[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/drepl e8d9eb96b2 1/5: Refactoring
From: |
ELPA Syncer |
Subject: |
[elpa] externals/drepl e8d9eb96b2 1/5: Refactoring |
Date: |
Sun, 12 Nov 2023 12:57:57 -0500 (EST) |
branch: externals/drepl
commit e8d9eb96b2f472fc3e6c9c5286043c6552d3092a
Author: Augusto Stoffel <arstoffel@gmail.com>
Commit: Augusto Stoffel <arstoffel@gmail.com>
Refactoring
---
drepl-lua.el | 6 +-
drepl.el | 207 +++++++++++++++++++++++++++++++++--------------------------
2 files changed, 122 insertions(+), 91 deletions(-)
diff --git a/drepl-lua.el b/drepl-lua.el
index 42c8ec9c0b..4511d47365 100644
--- a/drepl-lua.el
+++ b/drepl-lua.el
@@ -35,6 +35,10 @@
:group 'lua
:link '(url-link "https://github.com/astoff/drepl"))
+(defcustom drepl-lua-program "lua"
+ "Name of the Lua executable."
+ :type 'string)
+
(defvar drepl-lua--start-file
(expand-file-name "drepl-lua.lua"
(if load-file-name
@@ -52,7 +56,7 @@
(drepl--run 'drepl-lua t))
(cl-defmethod drepl--command ((_ drepl-lua))
- '("lua" "-v" "-e" "loadfile()():main()"))
+ `(,drepl-lua-program "-v" "-e" "loadfile()():main()"))
(cl-defmethod drepl--init ((_ drepl-lua))
(drepl-mode)
diff --git a/drepl.el b/drepl.el
index 1c6bd71f88..5261dbcc55 100644
--- a/drepl.el
+++ b/drepl.el
@@ -62,17 +62,18 @@ which determines whether to ask or return nil when in
doubt."
(defvar-local drepl--current nil
"The dREPL associated to the current buffer.
In dREPL buffers, this is the dREPL object itself. In all other
-buffers, this is the dREPL buffer or nil.")
+buffers, this is a dREPL buffer or nil.")
-(defvar drepl--verbose nil)
+(defvar drepl--log-buffer nil
+ "Name of the event log buffer, or nil to disable logging.")
;;; Basic definitions
(defclass drepl-base ()
((buffer :initarg :buffer :reader drepl--buffer)
(status :initform nil :accessor drepl--status)
- (last-request-id :initform 0)
- (requests :initform nil)
+ (last-id :initform 0)
+ (callbacks :initform nil)
(pending :initform nil))
:abstract t
:documentation "Base dREPL class.")
@@ -81,18 +82,20 @@ buffers, this is the dREPL buffer or nil.")
"The underlying process of dREPL object REPL."
(get-buffer-process (drepl--buffer repl)))
-(defmacro drepl--message (fmtstring &rest args)
- "Write a message to *drepl-log* buffer if `drepl--verbose' is non-nil.
-The message is formed by calling `format' with FMTSTRING and ARGS."
- (let ((msg (lambda (&rest args)
- (with-current-buffer (get-buffer-create "*drepl-log*")
- (goto-char (point-max))
- (when-let ((w (get-buffer-window)))
- (set-window-point w (point)))
- (insert (propertize (format-time-string "[%T] ") 'face 'error)
- (apply #'format args)
- ?\n)))))
- `(when drepl--verbose (funcall ,msg ,fmtstring ,@args))))
+(defun drepl--log-message-1 (&rest args)
+ "Helper function for `drepl--log-message'."
+ (with-current-buffer (get-buffer-create drepl--log-buffer)
+ (goto-char (point-max))
+ (when-let ((w (get-buffer-window)))
+ (set-window-point w (point)))
+ (insert (propertize (format-time-string "[%T] ") 'face 'error)
+ (apply #'format args)
+ ?\n)))
+
+(defmacro drepl--log-message (string &rest args)
+ "Write a message to buffer pointed by `drepl--log-buffer', if non-nil.
+The message is formed by calling `format' with STRING and ARGS."
+ `(when drepl--log-buffer (drepl--log-message-1 ,string ,@args)))
;;; Communication protocol
@@ -114,11 +117,23 @@ DATA is a plist containing the request arguments, as well
as :op
and :id entries."
(setf (drepl--status repl) 'busy)
(let ((encoded (drepl--json-encode data)))
- (drepl--message "send %s" encoded)
+ (drepl--log-message "send %s" encoded)
(process-send-string (drepl--process repl)
(format "\e%%%s\n" encoded))))
-(cl-defgeneric drepl--communicate (repl callback op &rest args)
+(defun drepl--communicate (repl callback op &rest args)
+ "Send a request to REPL.
+
+OP is the operation name as as symbol and ARGS is a plist of
+arguments for that operation.
+
+When REPL responds, CALLBACK is called with one argument, the
+response data. This functions returns immediately with the id
+number of the request.
+
+CALLBACK may also be the symbol `sync' to make a synchronous
+request. In this case, the REPL must be in the state `ready',
+and this function returns the response data directly."
(if (eq callback 'sync)
(progn (unless (eq (drepl--status repl) 'ready)
(user-error "%s is busy" repl))
@@ -127,35 +142,26 @@ and :id entries."
(apply #'drepl--communicate repl cb op args)
(while (eq result :pending) (accept-process-output))
result))
- (let* ((id (cl-incf (oref repl last-request-id)))
+ (let* ((id (cl-incf (oref repl last-id)))
(data `(:id ,id :op ,(symbol-name op) ,@args)))
- (push (cons id callback) (if-let ((reqs (oref repl requests)))
+ (push (cons id callback) (if-let ((reqs (oref repl callbacks)))
(cdr reqs)
- (oref repl requests)))
+ (oref repl callbacks)))
(if (eq 'ready (drepl--status repl))
(drepl--send-request repl data)
(push (cons id data) (oref repl pending)))
id)))
-(cl-defgeneric drepl--handle-notification (repl data)
- (pcase (alist-get 'op data)
- ("status" (setf (drepl--status repl)
- (intern (alist-get 'status data))))
- ("getoptions"
- (setf (drepl--status repl) 'ready)
- (drepl--set-options repl data))
- ("log" (drepl--message "log:%s: %s"
- (buffer-name)
- (alist-get 'text data)))))
-
(defun drepl--osc-handler (_cmd text)
- (drepl--message "read %s" text)
+ "Function intended for use as an entry of `ansi-osc-handlers'.
+TEXT is a still unparsed message received from the interpreter."
+ (drepl--log-message "read %s" text)
(let* ((data (drepl--json-decode text))
(id (alist-get 'id data))
(callback (if id
(prog1
- (alist-get id (oref drepl--current requests))
- (setf (alist-get id (oref drepl--current requests)
+ (alist-get id (oref drepl--current callbacks))
+ (setf (alist-get id (oref drepl--current callbacks)
nil 'remove)
nil))
(apply-partially #'drepl--handle-notification
@@ -166,6 +172,19 @@ and :id entries."
(when callback
(funcall callback data))))
+(cl-defgeneric drepl--handle-notification (repl data)
+ "Method called when REPL sends a notification.
+DATA is the content of the message."
+ (pcase (alist-get 'op data)
+ ("status" (setf (drepl--status repl)
+ (intern (alist-get 'status data))))
+ ("getoptions"
+ (setf (drepl--status repl) 'ready)
+ (drepl--set-options repl data))
+ ("log" (drepl--log-message "log:%s: %s"
+ (buffer-name)
+ (alist-get 'text data)))))
+
;;; Buffer association
(defun drepl--get-repl (&optional status ensure)
@@ -181,7 +200,7 @@ and has the given status.
If ENSURE is non-nil, produce an error if there is no REPL
associated to the current buffer."
(let ((repl (cond
- ((recordp drepl--current) drepl--current)
+ ((drepl-base-p drepl--current) drepl--current)
((buffer-live-p drepl--current)
(buffer-local-value 'drepl--current drepl--current))
(t (let* ((dir default-directory)
@@ -196,7 +215,7 @@ associated to the current buffer."
(buffer-local-value 'drepl--current (car buffers))))))))
(when (and ensure (not repl))
(user-error (substitute-command-keys
- "No REPL, use \\[drepl-associate] to choose one")))
+ "No default REPL, use \\[drepl-associate] to choose one")))
(when (or (not status)
(and repl
(memq (process-status (drepl--process repl))
@@ -249,9 +268,11 @@ interactively."
(get-text-property 0 'drepl--annot cand))
(cl-defgeneric drepl--completion-bounds (_repl)
+ "Return the start and end of completion region as a cons cell."
(bounds-of-thing-at-point 'symbol))
-(cl-defgeneric drepl--completion-cadidates (repl code offset)
+(defun drepl--completion-cadidates (repl code offset)
+ "Ask REPL for possible completions of CODE with point at OFFSET."
(let ((response (while-no-input
(drepl--communicate repl 'sync 'complete
:code code
@@ -262,6 +283,7 @@ interactively."
(alist-get 'candidates response))))
(defun drepl--complete ()
+ "Function intended for use as a member of `completion-at-point-functions'."
(when-let ((repl (when (derived-mode-p 'drepl-mode)
(drepl--get-repl 'ready)))
(bounds (drepl--completion-bounds repl))
@@ -283,6 +305,7 @@ interactively."
;;; Eval operation
(cl-defgeneric drepl--eval (repl code)
+ "Send an eval request to REPL with CODE as argument."
(drepl--communicate repl #'ignore 'eval :code code))
(defun drepl--send-string (proc string)
@@ -294,7 +317,7 @@ STRING to the process."
(drepl--get-repl 'ready))))
(if repl
(drepl--eval repl string)
- (drepl--message "send %s" string)
+ (drepl--log-message "send %s" string)
(comint-simple-send proc string))))
(defun drepl-eval (code)
@@ -347,17 +370,10 @@ insert start a continuation line instead."
;;; Describe operation
-(cl-defgeneric drepl--call-eldoc (repl callback)
- "Compute help on thing at point and pass it to Eldoc's CALLBACK function."
- (when-let ((offset (- (point) (cdr comint-last-prompt)))
- (code (when (>= offset 0)
- (buffer-substring-no-properties
- (cdr comint-last-prompt)
- (point-max))))
- (cb (lambda (data) (apply callback (drepl--format-eldoc repl
data)))))
- (drepl--communicate repl cb 'describe :code code :offset offset)))
-
(cl-defgeneric drepl--format-eldoc (repl data)
+ "Format REPL response DATA to a `describe' operation.
+The return value is passed directly to an Eldoc callback. See
+`eldoc-documentation-functions' for details."
(ignore repl)
(let-alist data
(list
@@ -377,17 +393,47 @@ insert start a continuation line instead."
:thing .name)))
(defun drepl--eldoc-function (callback &rest _)
- "Function intended to be a member of `eldoc-documentation-functions'."
- (when-let ((repl (drepl--get-repl 'ready)))
- (drepl--call-eldoc repl callback)))
+ "Function intended for use as a member of `eldoc-documentation-functions'.
+See that variable's docstring for a description of CALLBACK."
+ (when-let ((repl (when (derived-mode-p 'drepl-mode)
+ (drepl--get-repl 'ready)))
+ (offset (- (point) (cdr comint-last-prompt)))
+ (code (when (>= offset 0)
+ (buffer-substring-no-properties
+ (cdr comint-last-prompt)
+ (point-max))))
+ (cb (lambda (data)
+ (apply callback (drepl--format-eldoc repl data)))))
+ (drepl--communicate repl cb 'describe :code code :offset offset)))
+
+;;; REPL restart
+
+(cl-defgeneric drepl--restart (repl hard)
+ "Generic method to restart a REPL.
+HARD should be as described in `drepl-restart', but it not used
+in the default implementation."
+ (ignore hard)
+ (with-current-buffer (drepl--buffer repl)
+ (kill-process (drepl--process repl))
+ (while (accept-process-output (drepl--process repl)))
+ (drepl--run (type-of repl) nil)))
-;;; Initialization and restart
+(defun drepl-restart (&optional hard)
+ "Restart the current REPL.
+Some REPLs by default perform a soft reset by deleting all user
+variables without killing the interpreter. In those cases, a
+prefix argument or non-nil HARD argument can be used to force a
+hard reset."
+ (interactive "P")
+ (drepl--restart (drepl--get-repl nil t) hard))
-(defun drepl--project-directory (ask)
+;;; REPL initialization
+
+(defun drepl--project-directory (may-prompt)
"Return the current project root directory.
-If it can be determined and ASK is non-nil, ask for a project;
-otherwise fall back to `default-directory'."
- (if-let ((proj (project-current ask)))
+If it can be determined and MAY-PROMPT is non-nil, ask for a
+project; otherwise fall back to `default-directory'."
+ (if-let ((proj (project-current may-prompt)))
(project-root proj)
default-directory))
@@ -398,59 +444,40 @@ otherwise fall back to `default-directory'."
(directory-file-name directory))
(or (get class 'drepl--buffer-name) class)))
-(defun drepl--get-buffer-create (class ask)
+(defun drepl--get-buffer-create (class may-prompt)
"Get or create a dREPL buffer of the given CLASS.
-The directory of the buffer is determined by
-`drepl-directory'. If ASK is non-nil, allow an interactive query
-if needed."
+The directory of the buffer is determined by `drepl-directory'.
+If MAY-PROMPT is non-nil, allow an interactive query if needed."
(if (eq (type-of drepl--current) class)
(drepl--buffer drepl--current)
(let ((default-directory (if (stringp drepl-directory)
drepl-directory
- (funcall drepl-directory ask))))
+ (funcall drepl-directory may-prompt))))
(get-buffer-create (drepl--buffer-name class default-directory)))))
(cl-defgeneric drepl--command (repl)
- "The command to start the REPL interpreter as a list of strings."
- (ignore repl)
- (error "This needs an implementation"))
+ "The command to start the REPL interpreter, as a list of strings.")
(cl-defgeneric drepl--init (repl)
"Initialization code for REPL.
This function is called in the REPL buffer after a Comint has
been started in it. It should call `drepl-mode' or a derived
-mode and perform all other desired initialization procedures."
- (ignore repl)
- (error "This needs an implementation"))
+mode and perform all other desired initialization procedures.")
(cl-defgeneric drepl--set-options (repl data)
"Implementation of the `setoptions' operation.
This method is called when the REPL sends a `getoptions'
notification. The REPL is in `ready' state when this happens.
-The notification message is passed as DATA."
- (ignore repl data)
- (error "This needs an implementation"))
+The notification message is passed as DATA.")
-(cl-defgeneric drepl--restart (repl hard)
- "Generic method to restart a REPL.
-HARD should be as described in `drepl-restart', but it not used
-in the default implementation."
- (ignore hard)
- (with-current-buffer (drepl--buffer repl)
- (kill-process (drepl--process repl))
- (while (accept-process-output (drepl--process repl)))
- (drepl--run (type-of repl) nil)))
+(defun drepl--run (class may-prompt)
+ "Pop to a REPL of the given CLASS or start a new one.
-(defun drepl-restart (&optional hard)
- "Restart the current REPL.
-Some REPLs by default perform a soft reset by deleting all user
-variables without killing the interpreter. In those cases, a
-prefix argument or non-nil HARD argument can be used to force a
-hard reset."
- (interactive "P")
- (drepl--restart (drepl--get-repl nil t) hard))
+If MAY-PROMPT is non-nil, prompt for a project in which to run
+it, if necessary.
-(defun drepl--run (class may-prompt)
+This function is intended to be wrapped in an interactive command
+for each new REPL type."
(let ((buffer (drepl--get-buffer-create class may-prompt)))
(unless (comint-check-proc buffer)
(cl-letf* (((default-value 'process-environment) process-environment)
@@ -458,7 +485,7 @@ hard reset."
(repl (make-instance class :buffer buffer))
(command (drepl--command repl)))
(with-current-buffer buffer
- (drepl--message "starting %s" buffer)
+ (drepl--log-message "starting %s" buffer)
(apply #'make-comint-in-buffer
(buffer-name buffer) buffer
(car command) nil