Merge pull request #216 from rgrinberg/dev

Emacs mode renovation
This commit is contained in:
Rudi Grinberg 2018-02-26 22:29:27 +07:00 committed by GitHub
commit 730a8aeac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 148 additions and 207 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
_build/ _build/
.merlin .merlin
*.install *.install
*.elc

View File

@ -1,4 +1,4 @@
;;; utop.el --- Universal toplevel for OCaml ;;; utop.el --- Universal toplevel for OCaml -*- lexical-binding: t -*-
;; Copyright: (c) 2011, Jeremie Dimino <jeremie@dimino.org> ;; Copyright: (c) 2011, Jeremie Dimino <jeremie@dimino.org>
;; Author: Jeremie Dimino <jeremie@dimino.org> ;; Author: Jeremie Dimino <jeremie@dimino.org>
@ -18,9 +18,8 @@
;;; Code: ;;; Code:
(require 'easymenu) (require 'easymenu)
(require 'pcase)
;; tabulated-list is a part of Emacs 24 (require 'tabulated-list)
(require 'tabulated-list nil t)
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | License | ;; | License |
@ -238,19 +237,20 @@ Caml toplevel")
(defun utop-compat-resolve (choices) (defun utop-compat-resolve (choices)
"Resolve a symbol based on the current major mode. CHOICES is a "Resolve a symbol based on the current major mode. CHOICES is a
list of 3 function symbols: (tuareg-symbol typerex-symbol caml-symbol)." list of 3 function symbols: (tuareg-symbol typerex-symbol caml-symbol)."
(cond (nth
((eq major-mode 'tuareg-mode ) (nth 0 choices)) (pcase major-mode
((eq major-mode 'typerex-mode ) (nth 1 choices)) ('tuareg-mode 0)
((eq major-mode 'caml-mode ) (nth 2 choices)) ('typerex-mode 1)
((eq major-mode 'reason-mode ) (nth 3 choices)) ('caml-mode 2)
(t (error (format "utop doesn't support the major mode \"%s\". It ('reason-mode 3)
supports caml, tuareg and typerex modes by default. For other (major-mode (error (format "utop doesn't support the major mode \"%s\". It
supports caml, tuareg, typerex and reason modes by default. For other
modes you need to set these variables: modes you need to set these variables:
- `utop-next-phrase-beginning' - `utop-next-phrase-beginning'
- `utop-discover-phrase' - `utop-discover-phrase'
" " major-mode))))
(symbol-name major-mode)))))) choices))
(defun utop-compat-next-phrase-beginning () (defun utop-compat-next-phrase-beginning ()
(funcall (funcall
@ -266,54 +266,6 @@ modes you need to set these variables:
caml-find-phrase caml-find-phrase
reason-discover-phrase)))) reason-discover-phrase))))
;; +-----------------------------------------------------------------+
;; | Compability with previous emacs version |
;; +-----------------------------------------------------------------+
(unless (featurep 'tabulated-list)
;; tabulated-list.el is part of Emacs 24
;; This is a thin layer building compability with previous versions
(defvar tabulated-list-format nil)
(defvar tabulated-list-sort-key nil)
(defvar tabulated-list-printer nil)
(defvar tabulated-list-revert-hook nil)
(defvar tabulated-list-entries nil)
(define-derived-mode tabulated-list-mode special-mode "Mini-tabulated list mode"
"Tabulated list"
(make-local-variable 'tabulated-list-format)
(make-local-variable 'tabulated-list-sort-key)
(make-local-variable 'tabulated-list-printer)
(set (make-local-variable 'revert-buffer-function) 'tabulated-list-revert)
(defun tabulated-list-init-header ()
(save-excursion
(let ((inhibit-read-only t))
(mapc
(lambda (entry)
(let* ((name (nth 0 entry))
(size (length name))
(padding (- (nth 1 entry) size)))
(insert name)
(insert-char ?\s padding)
)) tabulated-list-format)
(insert "\n"))))
(defun tabulated-list-print (dummy)
(save-excursion
(let ((inhibit-read-only t))
(mapc (lambda (entry)
(goto-char (point-max))
(apply tabulated-list-printer entry))
tabulated-list-entries))
t))
(defun tabulated-list-revert (ignore-auto noconfirm)
(let ((inhibit-read-only t))
(delete-region (point-min) (point-max))
(tabulated-list-init-header)
(tabulated-list-print t))))
)
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | Utils | ;; | Utils |
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
@ -356,34 +308,25 @@ it is started."
"Change the utop state and mode-line-process." "Change the utop state and mode-line-process."
(setq utop-state state) (setq utop-state state)
(setq mode-line-process (setq mode-line-process
(cond (pcase state
((eq state 'edit) ('edit ": idle")
": idle") ('comp ": completion")
((eq state 'comp) ('hist ": history")
": completion") ('wait ": running")
((eq state 'hist) ('copy ": copying")
": history") ('done
((eq state 'wait) (let ((status (process-status utop-process))
": running") (code (process-exit-status utop-process)))
((eq state 'copy)
": copying")
((eq state 'done)
(let ((status (process-status utop-process)) (code (process-exit-status utop-process)))
(cond (cond
((and (eq status 'exit) (= code 0)) ((and (eq status 'exit) (= code 0))
": exited[0]") ": exited[0]")
((eq status 'exit) ((or (eq status 'exit) (eq status 'signal))
(let ((msg (concat ": exited[" (int-to-string code) "]"))) (let* ((status-name (pcase status ('exit "exited") ('signal "killed")))
(msg (concat ": " status-name "[" (int-to-string code) "]")))
(add-text-properties 0 (length msg) '(face bold) msg) (add-text-properties 0 (length msg) '(face bold) msg)
msg)) msg))
((eq status 'signal) (t ": unknown"))))
(let ((msg (concat ": killed[" (int-to-string code) "]"))) (_ ": unknown"))))
(add-text-properties 0 (length msg) '(face bold) msg)
msg))
(t
": unknown"))))
(t
": unknown"))))
(defun utop-send-data (cmd) (defun utop-send-data (cmd)
"Send current input to utop" "Send current input to utop"
@ -434,33 +377,30 @@ it is started."
(end-pos (utop-ident-looking nil))) (end-pos (utop-ident-looking nil)))
(buffer-substring-no-properties start-pos end-pos))) (buffer-substring-no-properties start-pos end-pos)))
; Currently not working - the communication is asynchronous so how to ;; Currently not working - the communication is asynchronous so how to
; make sure without implementing another state that the type ;; make sure without implementing another state that the type
; information has been already printed? ;; information has been already printed?
(defun utop-type-at-point () (defun utop-type-at-point ()
"Find type of an identifier at point from uTop" "Find type of an identifier at point from uTop"
(utop-eval-string (utop-ident-at-point)) (utop-eval-string (utop-ident-at-point)))
; (utop-last-type) ;; (utop-last-type)
)
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | Edition control | ;; | Edition control |
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
(defun utop-cannot-edit () (defun utop-cannot-edit ()
(cond (signal
((eq utop-state 'wait) 'text-read-only
(signal 'text-read-only '("You cannot edit the buffer while ocaml is evaluating a phrase"))) (pcase utop-state
((eq utop-state 'done) ('wait "You cannot edit the buffer while ocaml is evaluating a phrase")
(signal 'text-read-only '("You cannot edit the buffer when ocaml is not running"))) ('done "You cannot edit the buffer when ocaml is not running")
((eq utop-state 'comp) ('comp "You cannot edit the buffer while waiting for completion")
(signal 'text-read-only '("You cannot edit the buffer while waiting for completion"))) ('copy "You cannot edit the buffer while waiting for copy of last input")
((eq utop-state 'copy) ('hist "You cannot edit the buffer while waiting for history"))))
(signal 'text-read-only '("You cannot edit the buffer while waiting for copy of last input")))
((eq utop-state 'hist)
(signal 'text-read-only '("You cannot edit the buffer while waiting for history")))))
(defun utop-before-change (start stop) (defun utop-before-change (_start stop)
(unless utop-inhibit-check (unless utop-inhibit-check
(cond (cond
((not (eq utop-state 'edit)) ((not (eq utop-state 'edit))
@ -585,18 +525,18 @@ it is started."
;; Extract the command and its argument ;; Extract the command and its argument
(string-match "\\`\\([a-z-]*\\):\\(.*\\)\\'" line) (string-match "\\`\\([a-z-]*\\):\\(.*\\)\\'" line)
(let ((command (match-string 1 line)) (argument (match-string 2 line))) (let ((command (match-string 1 line)) (argument (match-string 2 line)))
(cond (pcase command
;; Output on stdout ;; Output on stdout
((string= command "stdout") ("stdout"
(utop-insert-output argument 'utop-stdout)) (utop-insert-output argument 'utop-stdout))
;; Output on stderr ;; Output on stderr
((string= command "stderr") ("stderr"
(utop-insert-output argument 'utop-stderr)) (utop-insert-output argument 'utop-stderr))
;; Synchronisation of the phrase terminator ;; Synchronisation of the phrase terminator
((string= command "phrase-terminator") ("phrase-terminator"
(setq utop-phrase-terminator argument)) (setq utop-phrase-terminator argument))
;; A new prompt ;; A new prompt
((string= command "prompt") ("prompt"
(let ((prompt (apply utop-prompt ()))) (let ((prompt (apply utop-prompt ())))
;; Insert the new prompt ;; Insert the new prompt
(utop-insert-prompt prompt) (utop-insert-prompt prompt)
@ -610,7 +550,7 @@ it is started."
(utop-eval-input nil t nil utop-initial-mode) (utop-eval-input nil t nil utop-initial-mode)
(setq utop-initial-mode nil)))) (setq utop-initial-mode nil))))
;; Input has been accepted ;; Input has been accepted
((string= command "accept") ("accept"
;; Add a newline character at the end of the buffer ;; Add a newline character at the end of the buffer
(goto-char (point-max)) (goto-char (point-max))
(insert "\n") (insert "\n")
@ -631,7 +571,7 @@ it is started."
(setq utop-prompt-min (point-max)) (setq utop-prompt-min (point-max))
(setq utop-prompt-max (point-max))) (setq utop-prompt-max (point-max)))
;; Continue editiong ;; Continue editiong
((string= command "continue") ("continue"
;; Add a newline character at the position where the user ;; Add a newline character at the position where the user
;; pressed enter ;; pressed enter
(when utop-pending-position (when utop-pending-position
@ -640,14 +580,14 @@ it is started."
;; Reset the state ;; Reset the state
(utop-set-state 'edit)) (utop-set-state 'edit))
;; Part of a history entry ;; Part of a history entry
((string= command "history-data") ("history-data"
(cond (cond
(utop-pending-entry (utop-pending-entry
(setq utop-pending-entry (concat utop-pending-entry "\n" argument))) (setq utop-pending-entry (concat utop-pending-entry "\n" argument)))
(t (t
(setq utop-pending-entry argument)))) (setq utop-pending-entry argument))))
;; End of history data ;; End of history data
((string= command "history-end") ("history-end"
(progn (progn
(cond (cond
((eq utop-state 'copy) ((eq utop-state 'copy)
@ -661,23 +601,23 @@ it is started."
;; Resume edition ;; Resume edition
(utop-set-state 'edit))) (utop-set-state 'edit)))
;; We are at a bound of history ;; We are at a bound of history
((string= command "history-bound") ("history-bound"
;; Just resume edition ;; Just resume edition
(utop-set-state 'edit)) (utop-set-state 'edit))
;; Complete with a word ;; Complete with a word
((string= command "completion-word") ("completion-word"
(utop-set-state 'edit) (utop-set-state 'edit)
(with-current-buffer utop-complete-buffer (insert argument)) (with-current-buffer utop-complete-buffer (insert argument))
;; Hide completion ;; Hide completion
(minibuffer-hide-completions)) (minibuffer-hide-completions))
;; Start of completion ;; Start of completion
((string= command "completion-start") ("completion-start"
(setq utop-completion nil)) (setq utop-completion nil))
;; A new possible completion ;; A new possible completion
((string= command "completion") ("completion"
(push argument utop-completion)) (push argument utop-completion))
;; End of completion ;; End of completion
((string= command "completion-stop") ("completion-stop"
(utop-set-state 'edit) (utop-set-state 'edit)
(if (> (length utop-completion) 1) (if (> (length utop-completion) 1)
(with-current-buffer utop-complete-buffer (with-current-buffer utop-complete-buffer
@ -686,7 +626,7 @@ it is started."
(minibuffer-hide-completions)) (minibuffer-hide-completions))
(setq utop-completion nil))))) (setq utop-completion nil)))))
(defun utop-process-output (process output) (defun utop-process-output (_process output)
"Process the output of utop" "Process the output of utop"
(with-current-buffer utop-buffer-name (with-current-buffer utop-buffer-name
(utop-perform (utop-perform
@ -931,7 +871,7 @@ defaults to 0."
(unless (eq utop-state 'done) (unless (eq utop-state 'done)
(utop-send-string (format "exit:%d\n" (or exit-code 0)))))) (utop-send-string (format "exit:%d\n" (or exit-code 0))))))
(defun utop-sentinel (process msg) (defun utop-sentinel (_process _msg)
"Callback for process' state change." "Callback for process' state change."
(let ((buffer (get-buffer utop-buffer-name))) (let ((buffer (get-buffer utop-buffer-name)))
;; Do nothing if the buffer does not exist anymore ;; Do nothing if the buffer does not exist anymore
@ -1008,7 +948,7 @@ defaults to 0."
(setq packages (cdr packages)))) (setq packages (cdr packages))))
(setq tabulated-list-entries (nreverse tabulated-list-entries))) (setq tabulated-list-entries (nreverse tabulated-list-entries)))
(defun utop-package-printer (id cols) (defun utop-package-printer (_id cols)
"Print one findlib package entry." "Print one findlib package entry."
(let ((width (cadr (elt tabulated-list-format 0)))) (let ((width (cadr (elt tabulated-list-format 0))))
(insert-text-button (elt cols 0) (insert-text-button (elt cols 0)