From db1821a97ffac0d6fbffe99a366fc2d726054229 Mon Sep 17 00:00:00 2001 From: syl20bnr Date: Mon, 11 May 2015 23:45:26 -0400 Subject: [PATCH] ocaml: refactor layer to make it better for spacemacs idioms Fix activation of auto-complete Sort packages Improvement with hook usage Move opam init function in funcs.el and call it only in tuareg config Fix errors if opam is not installed, warn if it has not been found Small edition of the README Rename additional REPL functions with spacemacs prefix --- contrib/lang/ocaml/README.md | 23 ++-- contrib/lang/ocaml/extensions.el | 31 ----- contrib/lang/ocaml/funcs.el | 23 ++++ contrib/lang/ocaml/packages.el | 190 +++++++++++++++---------------- 4 files changed, 128 insertions(+), 139 deletions(-) delete mode 100644 contrib/lang/ocaml/extensions.el create mode 100644 contrib/lang/ocaml/funcs.el diff --git a/contrib/lang/ocaml/README.md b/contrib/lang/ocaml/README.md index b12b6484d934..3d28b53268f5 100644 --- a/contrib/lang/ocaml/README.md +++ b/contrib/lang/ocaml/README.md @@ -8,6 +8,7 @@ - [Ocaml contribution layer for Spacemacs](#ocaml-contribution-layer-for-spacemacs) - [Description](#description) - [Install](#install) + - [Layer](#layer) - [OPAM packages](#opam-packages) - [Key Bindings](#key-bindings) - [REPL (utop)](#repl-utop) @@ -19,26 +20,26 @@ This is a very basic layer for editing ocaml files. -- Syntax highlighting via `tuareg-mode` -- Error reporting, completion and type display via `merlin` +- Syntax highlighting (major-mode) via [tuareg-mode][] +- Error reporting, completion and type display via [merlin][] +- auto-completion with company mode via [merlin][] +- syntax-checking via [flycheck-ocaml][] ## Install +### Layer + To use this contribution add it to your `~/.spacemacs` ```elisp (setq-default dotspacemacs-configuration-layers '(ocaml)) ``` -Optional configuration layers supported: - * auto-completion (company mode via merlin) - * syntax-checking (flycheck-ocaml) - ### OPAM packages This layer requires some [opam](http://opam.ocaml.org) packages: -- `merlin` +- `merlin` for auto-completion - `utop` - `ocp-indent` @@ -66,11 +67,15 @@ opam install merlin utop ocp-indent SPC m s P | Send phrase to the REPL and switch to the REPL in `insert state` SPC m s r | Send region to the REPL SPC m s R | Send region to the REPL and switch to the REPL in `insert state` -C-j | next item in history -C-k | previous item in history +C-j | (in REPL) next item in history +C-k | (in REPL) previous item in history ## TODO - Add more proper spacemacs key-bindings for basic merlin tasks - Add proper keybindings for ocamldebug - Add more keybindings for tuareg-mode + +[tuareg-mode]: https://github.com/ocaml/tuareg +[merlin]: https://github.com/the-lambda-church/merlin +[flycheck-ocaml]: https://github.com/diml/utop diff --git a/contrib/lang/ocaml/extensions.el b/contrib/lang/ocaml/extensions.el deleted file mode 100644 index f4fbaf956f77..000000000000 --- a/contrib/lang/ocaml/extensions.el +++ /dev/null @@ -1,31 +0,0 @@ -;;; extensions.el --- ocaml Layer extensions File for Spacemacs -;; -;; Copyright (c) 2012-2014 Sylvain Benner -;; Copyright (c) 2014-2015 Sylvain Benner & Contributors -;; -;; Author: Sylvain Benner -;; URL: https://github.com/syl20bnr/spacemacs -;; -;; This file is not part of GNU Emacs. -;; -;;; License: GPLv3 - -(setq ocaml-pre-extensions - '( - ;; pre extension ocamls go here - )) - -(setq ocaml-post-extensions - '( - ;; post extension ocamls go here - )) - -;; For each extension, define a function ocaml/init- -;; -;; (defun ocaml/init-my-extension () -;; "Initialize my extension" -;; ) -;; -;; Often the body of an initialize function uses `use-package' -;; For more info on `use-package', see readme: -;; https://github.com/jwiegley/use-package diff --git a/contrib/lang/ocaml/funcs.el b/contrib/lang/ocaml/funcs.el new file mode 100644 index 000000000000..33714fd40c5d --- /dev/null +++ b/contrib/lang/ocaml/funcs.el @@ -0,0 +1,23 @@ +;;; funcs.el --- ocaml Layer functions File for Spacemacs +;; +;; Copyright (c) 2012-2014 Sylvain Benner +;; Copyright (c) 2014-2015 Sylvain Benner & Contributors +;; +;; Author: Sylvain Benner +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +(defun spacemacs//init-ocaml-opam () + (if (executable-find "opam") + (let ((share (substring (shell-command-to-string + "opam config var share 2> /dev/null") 0 -1))) + (when share + (setq opam-share share + opam-load-path (concat share "/emacs/site-lisp"))) + (add-to-list 'load-path opam-load-path)) + (spacemacs-buffer/warning + (concat "Cannot find \"opam\" executable. " + "The ocaml layer won't work properly.")))) diff --git a/contrib/lang/ocaml/packages.el b/contrib/lang/ocaml/packages.el index 100e02a05de1..83a10cfd2f4e 100644 --- a/contrib/lang/ocaml/packages.el +++ b/contrib/lang/ocaml/packages.el @@ -12,120 +12,112 @@ (setq ocaml-packages '( - tuareg - merlin - utop - ocp-indent company flycheck flycheck-ocaml - ;; package ocamls go here + merlin + ocp-indent + tuareg + utop )) -(defun ocaml/init-tuareg () - (add-hook 'tuareg-mode-hook #'merlin-mode) - (evil-leader/set-key-for-mode 'tuareg-mode - "mcc" 'compile - ) - ;; don't auto-close apostrophes (type 'a = foo) - (when (fboundp 'sp-local-pair) - (sp-local-pair 'tuareg-mode "'" nil :actions nil) - ) - ) +(defun ocaml/post-init-company () + (spacemacs|add-company-hook merlin-mode)) -(defun ocaml/opam () - (setq opam-share (substring (shell-command-to-string "opam config var share 2> /dev/null") 0 -1)) - (setq opam-load-path (concat opam-share "/emacs/site-lisp")) - (add-to-list 'load-path opam-load-path)) +(when (configuration-layer/layer-usedp 'syntax-checking) + (defun ocaml/init-flycheck-ocaml () + (use-package flycheck-ocaml + :if (configuration-layer/package-usedp 'flycheck) + :defer t + :init + (progn + (add-to-hook 'merlin-mode-hook '(flycheck-mode + flycheck-ocaml-setup)) + (eval-after-load 'merlin + (setq merlin-use-auto-complete-mode nil)))))) -(defun ocaml/init-utop () - (use-package utop +(defun ocaml/init-merlin () + (use-package merlin + :defer t :init - (autoload 'utop "utop" "Toplevel for OCaml" t) - (autoload 'utop-minor-mode "utop" "Minor mode for utop" t) - (add-hook 'tuareg-mode-hook 'utop-minor-mode) - :config - ;; Setup environment variables using opam - (dolist (var (car (read-from-string (shell-command-to-string "opam config env --sexp")))) - (setenv (car var) (cadr var))) - ;; Update the emacs path - (setq exec-path (append (parse-colon-path (getenv "PATH")) - (list exec-directory))) - (defun utop-eval-phrase-and-go () - (interactive) - (utop-eval-phrase) - (utop)) - (defun utop-eval-buffer-and-go () - (interactive) - (utop-eval-buffer) - (utop)) - (defun utop-eval-region-and-go (start end) - (interactive "r") - (utop-eval-region start end) - (utop)) - (evil-leader/set-key-for-mode 'tuareg-mode - "msb" 'utop-eval-buffer - "msB" 'utop-eval-buffer-and-go - "msi" 'utop - "msp" 'utop-eval-phrase - "msP" 'utop-eval-phrase-and-go - "msr" 'utop-eval-region - "msR" 'utop-eval-region-and-go - ) - ) - (define-key utop-mode-map (kbd "C-j") 'utop-history-goto-next) - (define-key utop-mode-map (kbd "C-k") 'utop-history-goto-prev) - ) + (progn + (add-hook 'tuareg-mode-hook 'merlin-mode) + ;; disable integration with auto-complete, we use flycheck + (set-default 'merlin-use-auto-complete-mode nil) + (push 'merlin-company-backend company-backends-merlin-mode) + (evil-leader/set-key-for-mode 'tuareg-mode + "met" 'merlin-type-enclosing + "mgg" 'merlin-locate + ;;"mhh" 'merlin-document + )))) (defun ocaml/init-ocp-indent () (use-package ocp-indent + :defer t :init - (ocaml/opam) - ) - ) + (add-hook 'tuareg-mode-hook 'ocp-indent-caml-mode-setup))) -(defun ocaml/init-merlin () - (use-package merlin +(defun ocaml/init-tuareg () + (use-package tuareg :defer t :init - (ocaml/opam) - (set-default 'merlin-use-auto-complete-mode 'easy) - (when (configuration-layer/package-usedp 'company) - (push 'merlin-company-backend company-backends-merlin-mode)) - ) - (evil-leader/set-key-for-mode 'tuareg-mode - "mgg" 'merlin-locate - "met" 'merlin-type-enclosing - ;; "mhh" 'merlin-document - ) - ) + (progn + (spacemacs//init-ocaml-opam) + (evil-leader/set-key-for-mode 'tuareg-mode + "mcc" 'compile)) + :config + (when (fboundp 'sp-local-pair) + ;; don't auto-close apostrophes (type 'a = foo) + (sp-local-pair 'tuareg-mode "'" nil :actions nil)))) -(when (configuration-layer/layer-usedp 'auto-completion) - ;; Hook company to merlin-mode - (defun ocaml/post-init-company () - (spacemacs|add-company-hook merlin-mode) - )) +(defun ocaml/init-utop () + (use-package utop + :defer t + :init (add-hook 'tuareg-mode-hook 'utop-minor-mode) + :config + (progn + ;; Setup environment variables using opam + (if (executable-find "opam") + (let ((vars (car (read-from-string + (shell-command-to-string "opam config env --sexp"))))) + (dolist (var vars) + (setenv (car var) (cadr var)))) + (spacemacs-buffer/warning "Cannot find \"opam\" executable.")) + ;; Update the emacs path + (setq exec-path (append (parse-colon-path (getenv "PATH")) + (list exec-directory))) -(when (configuration-layer/layer-usedp 'syntax-checking) - (defun ocaml/init-flycheck-ocaml () - (use-package flycheck-ocaml - :if (configuration-layer/package-usedp 'flycheck) - :defer t - :init - (add-hook 'merlin-mode-hook 'flycheck-mode) - (with-eval-after-load 'merlin - ;; Disable Merlin's own error checking - (setq merlin-error-after-save nil) - ;; Enable Flycheck checker - (flycheck-ocaml-setup)) - ))) + (defun spacemacs/utop-eval-phrase-and-go () + "Send phrase to REPL and evaluate it and switch to the REPL in +`insert state'" + (interactive) + (utop-eval-phrase) + (utop) + (evil-insert-state)) -;; For each package, define a function ocaml/init- -;; -;; (defun ocaml/init-my-package () -;; "Initialize my package" -;; ) -;; -;; Often the body of an initialize function uses `use-package' -;; For more info on `use-package', see readme: -;; https://github.com/jwiegley/use-package + (defun spacemas/utop-eval-buffer-and-go () + "Send buffer to REPL and evaluate it and switch to the REPL in +`insert state'" + (interactive) + (utop-eval-buffer) + (utop) + (evil-insert-state)) + + (defun spacemacs/utop-eval-region-and-go (start end) + "Send region to REPL and evaluate it and switch to the REPL in +`insert state'" + (interactive "r") + (utop-eval-region start end) + (utop) + (evil-insert-state)) + + (evil-leader/set-key-for-mode 'tuareg-mode + "msb" 'utop-eval-buffer + "msB" 'spacemas/utop-eval-buffer-and-go + "msi" 'utop + "msp" 'utop-eval-phrase + "msP" 'spacemacs/utop-eval-phrase-and-go + "msr" 'utop-eval-region + "msR" 'spacemacs/utop-eval-region-and-go)) + (define-key utop-mode-map (kbd "C-j") 'utop-history-goto-next) + (define-key utop-mode-map (kbd "C-k") 'utop-history-goto-prev)))