Merge pull request #124 from mads379/refactor-major-mode-use

Refactor major mode use
This commit is contained in:
Jérémie Dimino 2015-01-12 09:36:07 +00:00
commit 0d606f6dae
2 changed files with 108 additions and 93 deletions

View File

@ -135,21 +135,35 @@ you can copy-paste this code into you `~/.emacs` file:
Then you can execute utop inside emacs with: `M-x utop`. Then you can execute utop inside emacs with: `M-x utop`.
Integration with the tuareg/typerex mode utop also ships with a minor mode that has the following key-bindings
----------------------------------------
You can replace the default toplevel used by the tuareg or typerex | key-binding | function | Description |
mode by utop, for that add the following lines to your `~/.emacs` file: |-------------|-------------------|------------------------------|
| C-c C-s | utop | Start a utop buffer |
| C-x C-e | utop-eval-phrase | Evaluate the current phrase |
| C-x C-r | utop-eval-region | Evaluate the selected region |
| C-c C-b | utop-eval-buffer | Evaluate the current buffer |
| C-c C-k | utop-kill | Kill a running utop process |
You can enable the minor mode using `M-x utop-minor-mode`, or you can
have it enabled by default with the following configuration
```scheme ```scheme
(autoload 'utop-setup-ocaml-buffer "utop" "Toplevel for OCaml" t) (autoload 'utop-minor-mode "utop" "Minor mode for utop" t)
(add-hook 'tuareg-mode-hook 'utop-setup-ocaml-buffer) (add-hook 'tuareg-mode-hook 'utop-minor-mode)
(add-hook 'typerex-mode-hook 'utop-setup-ocaml-buffer)
``` ```
You can also complete text in a tuareg or typerex buffer using the If you plan to use utop with another major-mode than tuareg,
environment of the toplevel. For that bind the function e.g. typerex, then you will need the following configuration instead
`utop-edit-complete` to the key you want.
```scheme
(autoload 'utop-minor-mode "utop" "Minor mode for utop" t)
(add-hook 'typerex-mode-hook 'utop-minor-mode)
```
You can also complete text in a buffer using the environment of the
toplevel. For that bind the function `utop-edit-complete` to the key
you want.
Common error Common error
------------ ------------

View File

@ -207,16 +207,63 @@ before the end of prompt.")
"The position of the cursor in the phrase sent to OCaml (where "The position of the cursor in the phrase sent to OCaml (where
to add the newline character if it is not accepted).") to add the newline character if it is not accepted).")
(make-variable-buffer-local
(defvar utop-package-list nil (defvar utop-package-list nil
"List of packages to load when visiting OCaml buffer. "List of packages to load when visiting OCaml buffer.
Useful as file variable.") Useful as file variable."))
(make-variable-buffer-local
(defvar utop-ocaml-preprocessor nil (defvar utop-ocaml-preprocessor nil
"Name of preprocesor. Currently supported camlp4o, camlp4r. "Name of preprocesor. Currently supported camlp4o, camlp4r.
Useful as file variable.") Useful as file variable."))
(defvar utop-skip-blank-and-comments 'compat-skip-blank-and-comments
"The function used to skip blanks and comments.")
(defvar utop-skip-to-end-of-phrase 'compat-skip-to-end-of-phrase
"The function used to find the end of a phrase")
(defvar utop-discover-phrase 'compat-discover-phrase
"The function used to discover a phrase")
(defvar utop-skip-after-eval-phrase t
"Whether to skip to next phrase after evaluation.
Non-nil means skip to the end of the phrase after evaluation in the
Caml toplevel")
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | Compability | ;; | Compability with different ocaml major modes |
;; +-----------------------------------------------------------------+
(defun utop-compat-resolve (symbol)
"Resolve a symbol based on the current major mode."
(cond
((eq major-mode 'tuareg-mode)
(intern (concat "tuareg-" symbol)))
((eq major-mode 'typerex-mode)
(intern (concat "typerex-" symbol)))
((eq major-mode 'caml-mode)
(intern (concat "caml-" symbol)))
((require 'tuareg nil t)
(intern (concat "tuareg-" symbol)))
((require 'typerex nil t)
(intern (concat "typerex-" symbol)))
((require 'caml nil t)
(intern (concat "caml-" symbol)))
(error (concat "unsupported mode: " (symbol-name major-mode) ", utop support only caml, tuareg and typerex modes"))))
(defun compat-skip-blank-and-comments ()
(funcall (utop-compat-resolve "skip-blank-and-comments")))
(defun compat-skip-to-end-of-phrase ()
(funcall (utop-compat-resolve "skip-to-end-of-phrase")))
(defun compat-discover-phrase ()
(funcall (utop-compat-resolve "discover-phrase")))
;; +-----------------------------------------------------------------+
;; | Compability with previous emacs version |
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
(unless (featurep 'tabulated-list) (unless (featurep 'tabulated-list)
@ -740,36 +787,9 @@ If ADD-TO-HISTORY is t then the input will be added to history."
(buffer-substring-no-properties utop-prompt-max (point))))) (buffer-substring-no-properties utop-prompt-max (point)))))
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | Caml/Tuareg/Typerex integration | ;; | Eval |
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
(defun utop-choose (symbol)
"Be best at resolving caml, tuareg or typerex dependencies even
when byte-compiling."
(cond
((eq major-mode 'tuareg-mode)
(intern (concat "tuareg-" symbol)))
((eq major-mode 'typerex-mode)
(intern (concat "typerex-" symbol)))
((eq major-mode 'caml-mode)
(intern (concat "caml-" symbol)))
((require 'tuareg nil t)
(intern (concat "tuareg-" symbol)))
((require 'typerex nil t)
(intern (concat "typerex-" symbol)))
((require 'caml nil t)
(intern (concat "caml-" symbol)))
(error (concat "unsupported mode: " (symbol-name major-mode) ", utop support only caml, tuareg and typerex modes"))))
(defmacro utop-choose-symbol (symbol)
(utop-choose symbol))
(defmacro utop-choose-call (symbol &rest args)
`(,(utop-choose symbol) ,@args))
(defmacro utop-choose-defun (symbol &rest args)
`(defun ,(utop-choose symbol) ,@args))
(defun utop-prepare-for-eval () (defun utop-prepare-for-eval ()
"Prepare utop for evaluation." "Prepare utop for evaluation."
(save-excursion (save-excursion
@ -814,18 +834,15 @@ when byte-compiling."
(defun utop-eval (start end &optional mode) (defun utop-eval (start end &optional mode)
"Eval the given region in utop." "Eval the given region in utop."
;; From tuareg
(unless (eq major-mode 'caml-mode)
(set (utop-choose "interactive-last-phrase-pos-in-source") start))
;; Select the text of the region ;; Select the text of the region
(let ((text (let ((text
(save-excursion (save-excursion
;; Search the start and end of the current paragraph ;; Search the start and end of the current paragraph
(goto-char start) (goto-char start)
(utop-choose-call "skip-blank-and-comments") (funcall utop-skip-blank-and-comments)
(setq start (point)) (setq start (point))
(goto-char end) (goto-char end)
(utop-choose-call "skip-to-end-of-phrase") (funcall utop-skip-to-end-of-phrase)
(setq end (point)) (setq end (point))
(buffer-substring-no-properties start end)))) (buffer-substring-no-properties start end))))
(utop-eval-string text mode))) (utop-eval-string text mode)))
@ -842,10 +859,10 @@ when byte-compiling."
(utop-prepare-for-eval) (utop-prepare-for-eval)
(let ((end)) (let ((end))
(save-excursion (save-excursion
(let ((pair (utop-choose-call "discover-phrase"))) (let ((pair (funcall utop-discover-phrase)))
(setq end (nth 2 pair)) (setq end (nth 2 pair))
(utop-eval (nth 0 pair) (nth 1 pair)))) (utop-eval (nth 0 pair) (nth 1 pair))))
(if (utop-choose-symbol "skip-after-eval-phrase") (if utop-skip-after-eval-phrase
(goto-char end)))) (goto-char end))))
(defun utop-eval-buffer () (defun utop-eval-buffer ()
@ -860,7 +877,7 @@ when byte-compiling."
;; Find the start of the current phrase ;; Find the start of the current phrase
(save-excursion (save-excursion
(let* ((end (point)) (let* ((end (point))
(start (nth 0 (utop-choose-call "discover-phrase"))) (start (nth 0 (funcall utop-discover-phrase)))
(input (buffer-substring-no-properties start end)) (input (buffer-substring-no-properties start end))
(edit-buffer (current-buffer))) (edit-buffer (current-buffer)))
;; Start utop if needed ;; Start utop if needed
@ -881,42 +898,6 @@ when byte-compiling."
;; Send the phrase to complete ;; Send the phrase to complete
(utop-complete-input input))))))) (utop-complete-input input)))))))
(defun utop-setup-ocaml-buffer ()
"Override caml/tuareg/typerex interactive functions by utop ones.
You can call this function after loading the caml/tuareg/typerex
mode to let it use utop instead of its builtin support for
interactive toplevel.
To automatically do that just add these lines to your .emacs:
(autoload 'utop-setup-ocaml-buffer \"utop\" \"Toplevel for OCaml\" t)
(add-hook 'caml-mode-hook 'utop-setup-ocaml-buffer)
(add-hook 'tuareg-mode-hook 'utop-setup-ocaml-buffer)
(add-hook 'typerex-mode-hook 'utop-setup-ocaml-buffer)"
(interactive)
;; Redefine caml/tuareg/typerex functions
(utop-choose-defun "eval-phrase" () (interactive) (utop-eval-phrase))
(utop-choose-defun "eval-region" (start end) (interactive "r") (utop-eval-region start end))
(utop-choose-defun "eval-buffer" () (interactive) (utop-eval-buffer))
(utop-choose-defun "interrupt-caml" () (interactive) (utop-interrupt))
(utop-choose-defun "kill-caml" () (interactive) (utop-kill))
(utop-choose-defun "run-caml" () (interactive) (utop))
;; Redefine this variable so menu will work
(set (utop-choose "interactive-buffer-name") utop-buffer-name)
;; Package list for this file
(make-local-variable 'utop-package-list)
;; Preprocessor to use
(make-local-variable 'utop-ocaml-preprocessor)
;; Load local file variables
(add-hook 'hack-local-variables-hook 'utop-hack-local-variables)
nil)
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
;; | Edition functions | ;; | Edition functions |
;; +-----------------------------------------------------------------+ ;; +-----------------------------------------------------------------+
@ -1164,6 +1145,25 @@ defaults to 0."
(utop-insert "\nRestarting...\n\n") (utop-insert "\nRestarting...\n\n")
(utop-start arguments))) (utop-start arguments)))
(defun utop-setup-ocaml-buffer ()
"Deprecated"
(error "This function is deprecated. See https://github.com/diml/utop for configuration information."))
;;;###autoload
(define-minor-mode utop-minor-mode
"Minor mode for utop."
:lighter " utop"
:keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-s") 'utop)
(define-key map (kbd "C-x C-e") 'utop-eval-phrase)
(define-key map (kbd "C-x C-r") 'utop-eval-region)
(define-key map (kbd "C-c C-b") 'utop-eval-buffer)
(define-key map (kbd "C-c C-k") 'utop-kill)
map)
;; Load local file variables
(add-hook 'hack-local-variables-hook 'utop-hack-local-variables))
;;;###autoload
(define-derived-mode utop-mode fundamental-mode "utop" (define-derived-mode utop-mode fundamental-mode "utop"
"Set the buffer mode to utop." "Set the buffer mode to utop."
@ -1239,6 +1239,7 @@ Special keys for utop:
(with-current-buffer buf (utop-mode))))) (with-current-buffer buf (utop-mode)))))
buf)) buf))
(provide 'utop-minor-mode)
(provide 'utop) (provide 'utop)
;;; utop.el ends here ;;; utop.el ends here