Add a simple emacs mode for editing valeri code

This commit is contained in:
Konstantin Nazarov 2024-10-09 00:54:56 +01:00
parent f4660b6bc1
commit 908df85c63
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
2 changed files with 117 additions and 0 deletions

View file

@ -19,6 +19,7 @@ enum class TtyEscape {
CtrlF = 6, CtrlF = 6,
CtrlH = 8, CtrlH = 8,
Tab = 9, Tab = 9,
LF = 10,
CtrlK = 11, CtrlK = 11,
CtrlL = 12, CtrlL = 12,
Enter = 13, Enter = 13,
@ -244,6 +245,7 @@ class LineEdit {
if (nread <= 0) return false; if (nread <= 0) return false;
switch (TtyEscape(c)) { switch (TtyEscape(c)) {
case TtyEscape::LF:
case TtyEscape::Enter: case TtyEscape::Enter:
return false; return false;
break; break;

115
valeri-mode.el Normal file
View file

@ -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