diff --git a/src/lineedit.cpp b/src/lineedit.cpp index 9d9d0a9..d08d481 100644 --- a/src/lineedit.cpp +++ b/src/lineedit.cpp @@ -400,13 +400,28 @@ Result read_dumb(const char* prompt) { const size_t bufsize = 256; char buf[bufsize]; bool endstr = false; + bool in_paste = false; while (!endstr) { size_t i = 0; - while (i < sizeof(buf) - 1) { + while (i < sizeof(buf) - 10) { if (read(input_fd, buf + i, 1) != 1) break; - if (buf[i] == '\n') { + if (buf[i] == '\n' && !in_paste) { endstr = true; 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++; } diff --git a/valeri-mode.el b/valeri-mode.el index 0fe66e0..298d87d 100644 --- a/valeri-mode.el +++ b/valeri-mode.el @@ -14,7 +14,7 @@ Should be a list of strings." :type '(repeat string) :group 'valeri) -(defcustom valeri-prompt-regexp "[^\n]*\\(valeri>[\t ]+\\)+$" +(defcustom valeri-prompt-regexp "\\(valeri>[\t ]+\\)+" "Regexp which matches the Valeri program's prompt." :type 'regexp :group 'valeri) @@ -43,18 +43,30 @@ Should be a list of strings." "Buffer-local flag saying if this is a Valeri REPL buffer.") (make-variable-buffer-local 'valeri--repl-buffer-p) +(defvar valeri-eoe-indicator "valeri-eoe") + (defun valeri-get-create-process () "Return active Valeri process creating one if necessary." (valeri-start-process) valeri-process) -(defun valeri-send-string (str) - "Send STR plus a newline to the Valeri process. - -If `valeri-process' is nil or dead, start a new process first." - (unless (string-equal (substring str -1) "\n") - (setq str (concat str "\n"))) - (process-send-string (valeri-get-create-process) str)) +(defun valeri-send-string (buffer body) + "Pass BODY to the Valeri process in BUFFER." + (let ((escaped-body (format "\x1b[200~%s\x1b[201~" body)) + (eoe-string (format "\n(println \"%s\")\n" valeri-eoe-indicator))) + (mapconcat + #'identity + (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 (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) (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)