Add support for executing multiline code blocks via comint mode
This commit is contained in:
parent
9e45485053
commit
ad4f0a43d4
2 changed files with 51 additions and 10 deletions
|
@ -400,13 +400,28 @@ Result<String> read_dumb(const char* prompt) {
|
||||||
const size_t bufsize = 256;
|
const size_t bufsize = 256;
|
||||||
char buf[bufsize];
|
char buf[bufsize];
|
||||||
bool endstr = false;
|
bool endstr = false;
|
||||||
|
bool in_paste = false;
|
||||||
while (!endstr) {
|
while (!endstr) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < sizeof(buf) - 1) {
|
while (i < sizeof(buf) - 10) {
|
||||||
if (read(input_fd, buf + i, 1) != 1) break;
|
if (read(input_fd, buf + i, 1) != 1) break;
|
||||||
if (buf[i] == '\n') {
|
if (buf[i] == '\n' && !in_paste) {
|
||||||
endstr = true;
|
endstr = true;
|
||||||
break;
|
break;
|
||||||
|
} else if (buf[i] == '\x1b') {
|
||||||
|
// TODO: this implementation has a bug with processing weird escape
|
||||||
|
// sequences, but fixing it will require a proper state machine.
|
||||||
|
// Example of input where this will break: "\x1b\n"
|
||||||
|
for (size_t j = 1; j <= 5; ++j) {
|
||||||
|
if (read(input_fd, buf + i + j, 1) != 1) break;
|
||||||
|
}
|
||||||
|
if (strncmp(buf + i, "\x1b[200~", 5) == 0) {
|
||||||
|
in_paste = true;
|
||||||
|
}
|
||||||
|
if (strncmp(buf + i, "\x1b[201~", 5) == 0) {
|
||||||
|
in_paste = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ Should be a list of strings."
|
||||||
:type '(repeat string)
|
:type '(repeat string)
|
||||||
:group 'valeri)
|
:group 'valeri)
|
||||||
|
|
||||||
(defcustom valeri-prompt-regexp "[^\n]*\\(valeri>[\t ]+\\)+$"
|
(defcustom valeri-prompt-regexp "\\(valeri>[\t ]+\\)+"
|
||||||
"Regexp which matches the Valeri program's prompt."
|
"Regexp which matches the Valeri program's prompt."
|
||||||
:type 'regexp
|
:type 'regexp
|
||||||
:group 'valeri)
|
:group 'valeri)
|
||||||
|
@ -43,18 +43,30 @@ Should be a list of strings."
|
||||||
"Buffer-local flag saying if this is a Valeri REPL buffer.")
|
"Buffer-local flag saying if this is a Valeri REPL buffer.")
|
||||||
(make-variable-buffer-local 'valeri--repl-buffer-p)
|
(make-variable-buffer-local 'valeri--repl-buffer-p)
|
||||||
|
|
||||||
|
(defvar valeri-eoe-indicator "valeri-eoe")
|
||||||
|
|
||||||
(defun valeri-get-create-process ()
|
(defun valeri-get-create-process ()
|
||||||
"Return active Valeri process creating one if necessary."
|
"Return active Valeri process creating one if necessary."
|
||||||
(valeri-start-process)
|
(valeri-start-process)
|
||||||
valeri-process)
|
valeri-process)
|
||||||
|
|
||||||
(defun valeri-send-string (str)
|
(defun valeri-send-string (buffer body)
|
||||||
"Send STR plus a newline to the Valeri process.
|
"Pass BODY to the Valeri process in BUFFER."
|
||||||
|
(let ((escaped-body (format "\x1b[200~%s\x1b[201~" body))
|
||||||
If `valeri-process' is nil or dead, start a new process first."
|
(eoe-string (format "\n(println \"%s\")\n" valeri-eoe-indicator)))
|
||||||
(unless (string-equal (substring str -1) "\n")
|
(mapconcat
|
||||||
(setq str (concat str "\n")))
|
#'identity
|
||||||
(process-send-string (valeri-get-create-process) str))
|
(butlast
|
||||||
|
(split-string
|
||||||
|
(mapconcat
|
||||||
|
#'org-trim
|
||||||
|
(org-babel-comint-with-output
|
||||||
|
(buffer valeri-eoe-indicator t escaped-body)
|
||||||
|
(insert (org-babel-chomp escaped-body) eoe-string)
|
||||||
|
(comint-send-input nil t))
|
||||||
|
"\n") "[\r\n]")) "\n")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-derived-mode valeri-mode lisp-mode "Valeri"
|
(define-derived-mode valeri-mode lisp-mode "Valeri"
|
||||||
|
@ -109,6 +121,20 @@ When called interactively, switch to the process buffer."
|
||||||
(if (looking-at comint-prompt-regexp)
|
(if (looking-at comint-prompt-regexp)
|
||||||
(match-end 0)))))
|
(match-end 0)))))
|
||||||
|
|
||||||
|
(defun valeri-comint-end-of-output-p (output)
|
||||||
|
"Return non-nil if OUTPUT ends with input prompt."
|
||||||
|
(string-match
|
||||||
|
;; XXX: It seems on macOS an extra carriage return is attached
|
||||||
|
;; at the end of output, this handles that too.
|
||||||
|
(concat
|
||||||
|
"\r?\n?"
|
||||||
|
;; Remove initial caret from calculated regexp
|
||||||
|
(replace-regexp-in-string
|
||||||
|
(rx string-start ?^) ""
|
||||||
|
valeri-prompt-regexp)
|
||||||
|
(rx eos))
|
||||||
|
output))
|
||||||
|
|
||||||
|
|
||||||
(provide 'valeri-mode)
|
(provide 'valeri-mode)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue