diff --git a/src/lineedit.cpp b/src/lineedit.cpp index efb552a..254cbfe 100644 --- a/src/lineedit.cpp +++ b/src/lineedit.cpp @@ -19,6 +19,7 @@ enum class TtyEscape { CtrlF = 6, CtrlH = 8, Tab = 9, + LF = 10, CtrlK = 11, CtrlL = 12, Enter = 13, @@ -244,6 +245,7 @@ class LineEdit { if (nread <= 0) return false; switch (TtyEscape(c)) { + case TtyEscape::LF: case TtyEscape::Enter: return false; break; diff --git a/valeri-mode.el b/valeri-mode.el new file mode 100644 index 0000000..0fe66e0 --- /dev/null +++ b/valeri-mode.el @@ -0,0 +1,115 @@ +;;; valeri-mode.el --- a major-mode for editing Valeri programs -*- lexical-binding: t -*- + + +(require 'comint) + +(defcustom valeri-default-application "valeri" + "Default application to run in Valeri process." + :type 'string + :group 'valeri) + +(defcustom valeri-default-command-switches (list) + "Command switches for `valeri-default-application'. +Should be a list of strings." + :type '(repeat string) + :group 'valeri) + +(defcustom valeri-prompt-regexp "[^\n]*\\(valeri>[\t ]+\\)+$" + "Regexp which matches the Valeri program's prompt." + :type 'regexp + :group 'valeri) + +(defcustom valeri-traceback-line-re + ;; This regexp skips prompt and meaningless "stdin:N:" prefix when looking + ;; for actual file-line locations. + "^\\(?:[\t ]*\\|.*>[\t ]+\\)\\(?:[^\n\t ]+:[0-9]+:[\t ]*\\)*\\(?:\\([^\n\t ]+\\):\\([0-9]+\\):\\)" + "Regular expression that describes tracebacks and errors." + :type 'regexp + :group 'valeri) + +(defvar valeri-process-init-code + (mapconcat + 'identity + '("") + " ")) + +(defvar valeri-process nil + "The active Valeri process") + +(defvar valeri-process-buffer nil + "Buffer used for communication with the Valeri process.") + +(defvar valeri--repl-buffer-p nil + "Buffer-local flag saying if this is a Valeri REPL buffer.") +(make-variable-buffer-local 'valeri--repl-buffer-p) + +(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)) + +;;;###autoload +(define-derived-mode valeri-mode lisp-mode "Valeri" + "Major mode for editing Valeri code." + :group 'valeri + ) + +;;;###autoload +(defalias 'run-valeri #'valeri-start-process) + +;;;###autoload +(defun valeri-start-process (&optional name program startfile &rest switches) + "Start a Valeri process named NAME, running PROGRAM. +PROGRAM defaults to NAME, which defaults to `valeri-default-application'. +When called interactively, switch to the process buffer." + (interactive) + (setq name (or name valeri-default-application)) + (setq program (or program valeri-default-application)) + ;; don't re-initialize if there already is a Valeri process + (unless (comint-check-proc (format "*%s*" name)) + (setq valeri-process-buffer (apply #'make-comint name program startfile + (or switches valeri-default-command-switches))) + (setq valeri-process (get-buffer-process valeri-process-buffer)) + (set-process-query-on-exit-flag valeri-process nil) + (with-current-buffer valeri-process-buffer + ;; enable error highlighting in stack traces + (require 'compile) + (setq valeri--repl-buffer-p t) + (make-local-variable 'compilation-error-regexp-alist) + (setq compilation-error-regexp-alist + (cons (list valeri-traceback-line-re 1 2) + compilation-error-regexp-alist)) + (compilation-shell-minor-mode 1) + (setq-local comint-prompt-regexp valeri-prompt-regexp) + + ;; Don't send initialization code until seeing the prompt to ensure that + ;; the interpreter is ready. + ;; (while (not (valeri-prompt-line)) + ;; (accept-process-output (get-buffer-process (current-buffer))) + ;; (goto-char (point-max))) + ;; (valeri-send-string valeri-process-init-code) + )) + + ;; when called interactively, switch to process buffer + (if (called-interactively-p 'any) + (switch-to-buffer valeri-process-buffer))) + +(defun valeri-prompt-line () + (save-excursion + (save-match-data + (forward-line 0) + (if (looking-at comint-prompt-regexp) + (match-end 0))))) + + +(provide 'valeri-mode) + +;;; valeri-mode.el ends here