Skip to content
Type and doc on hover for OCaml and Reason in emacs
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
CHANGES.org
LICENSE.md
README.org
demo.gif
full-demo.gif
merlin-eldoc.el

README.org

Merlin backend for eldoc

https://melpa.org/packages/merlin-eldoc-badge.svg

This package provides a merlin backend for eldoc. Its goal is to automatically (without using keybindings) provide information for the value under point in OCaml and ReasonML files. It also provides hints when calling a function. This information is obtained from merlin.

Please see the changelog for recent improvements and list of changes between versions.

Features

  • display type
  • display documentation
  • highlight occurrences
  • jump to other occurrences
  • provide the list of expected arguments (and their types) when calling a function

Installation

use-package

Add this code to init.el

(use-package merlin-eldoc
  :ensure t
  :hook ((reason-mode tuareg-mode caml-mode) . merlin-eldoc-setup))

Quelpa

With quelpa already installed and configured:

(quelpa '(merlin-eldoc :fetcher github :repo "Khady/merlin-eldoc"))
;; Add a hook to start the mode automatically for OCaml and Reason
(add-hook 'tuareg-mode-hook 'merlin-eldoc-setup)
(add-hook 'reason-mode-hook 'merlin-eldoc-setup)

The more manual way

First the package has to be installed:

M-x package-install RET merlin-eldoc RET

Then this code should be added to init.el

(require 'merlin-eldoc)
(add-hook 'tuareg-mode-hook 'merlin-eldoc-setup)
(add-hook 'reason-mode-hook 'merlin-eldoc-setup)

Usage

If a hook has been configured, then there is nothing to do. The eldoc mode should be launched automatically when an OCaml file is visited. And merlin will provide type information when available.

Otherwise, it can be launched by executing M-x merlin-eldoc-setup.

Once this is done, as soon as the point is on a word which is not a keyword, a type should be displayed in the echo area when the cursor doesn’t move for some time.

It is possible to configure the shape of the results using both eldoc and merlin-eldoc configurations. It allows to choose on how many lines the result will fit, if the documentation can be truncated, how to concatenate type and documentation…

For eldoc, the value to configure is eldoc-echo-area-use-multiline-p.

For merlin-eldoc, the easiest way it so use the customize interface to get access to all the possible values and the corresponding documentation.

M-x merlin-eldoc-customize RET

The main values are:

  • merlin-eldoc-doc to enable or disable the display of the documentation.
  • merlin-eldoc-type to enable or disable the display of the type.
  • merlin-eldoc-type-verbosity to control verbosity of the type. if ~’max~, it is equivalent to calling multiple times merlin-type-enclosing.
  • merlin-eldoc-occurrences to enable or disable the highlighting of all the occurrences of the identifier at point.
  • merlin-eldoc-function-arguments to enable or disable the hints when applying arguments to a function.
  • merlin-eldoc-max-lines to set on how many lines should fit the message printed in the minibuffer.

If highlighting of occurrences is enabled, two functions are povided to jump to the previous or next occurrence of value under the point:

  • merlin-eldoc-jump-to-prev-occurrence
  • merlin-eldoc-jump-to-next-occurrence

They can be binded to keys for more convenient usage.

Configuration examples

use-package

(use-package merlin-eldoc
  :after merlin
  :ensure t
  :custom
  (eldoc-echo-area-use-multiline-p t) ; use multiple lines when necessary
  (merlin-eldoc-max-lines 8)          ; but not more than 8
  (merlin-eldoc-type-verbosity 'min)  ; don't display verbose types
  (merlin-eldoc-function-arguments nil) ; don't show function arguments
  (merlin-eldoc-doc nil)                ; don't show the documentation
  :bind (:map merlin-mode-map
              ("C-c m p" . merlin-eldoc-jump-to-prev-occurrence)
              ("C-c m n" . merlin-eldoc-jump-to-next-occurrence))
  :hook ((tuareg-mode reason-mode) . merlin-eldoc-setup))

Quelpa

(quelpa '(merlin-eldoc :repo "Khady/merlin-eldoc" :fetcher github))

;; use multiple lines when necessary
(setq eldoc-echo-area-use-multiline-p t)

;; but not more than 10
(setq merlin-eldoc-max-lines 10)

;; don't dedicate a line to the documentation
(setq merlin-eldoc-max-lines-doc 'fit)

;; start merlin-eldoc when editing ocaml and reason files
(add-hook 'tuareg-mode-hook #'merlin-eldoc-setup)
(add-hook 'reason-mode-hook #'merlin-eldoc-setup)

Examples

In the following examples, the cursor is at <-!->. After the requisite idle time, eldoc will fire and show the corresponding information in the minibuffer.

  1. Type of a function
    let my<-!->add ~f ~i =
      f +. (float i)
        

    The information in the minibuffer will be:

    f:float -> i:int -> float
        
  2. Type and documentation of a function
    (** [myadd f i] add f and i *)
    let my<-!->add ~f ~i =
      f +. (float i)
        

    With type and doc enabled, it shows:

    f:float -> i:int -> float     (* [myadd f i] add f and i *)
        
  3. Type and documentation of List.map limited to one line
    List.map<-!->
        

    The exact result will depend on the width of the Emacs frame.

    ('a -> 'b) -> 'a list -> 'b list (* [List.map f [a1; ...; an]] applies function [f] to [a1, ..., an], and builds... *)
        
  4. Type and documentation of List.map on multiple lines
    List.map<-!->
        

    If at least 4 lines are allowed:

    (* [List.map f [a1; ...; an]] applies function [f] to [a1, ..., an],
       and builds the list [[f a1; ...; f an]]
       with the results returned by [f].  Not tail-recursive. *)
    ('a -> 'b) -> 'a list -> 'b list
        
  5. Function application and argument types
    let apply ~f ~i op =
      op @@ f +. (float i)
    
    let v = apply <-!->
        
    (* expected type: *) float -> 'a
    (* labels: *) ~f:float -> ~i:int
        

    Depending on the value of merlin-eldoc-max-lines-function-arguments it can also be displayed on one line.

    (* expected type: *) float -> 'a (* labels: *) ~f:float -> ~i:int
        
  6. Function application and argument types, with some arguments already given
    let apply ~f ~i op =
      op @@ f +. (float i)
    
    let v = apply ~i:3 <-!->
        
    (* expected type: *) float -> 'a (* labels: *) ~f:float
        
  7. Type expected by a label
    let apply ~f ~i op =
      op @@ f +. (float i)
    
    let v = apply ~i:<-!->
        
    (* expected type: *) int
        

Two videos are played bellow for a more visual demonstration.

Demo

Video showing the following features provided by this package:

  • Type of value at point
  • Highlight other occurrences of the identifier
  • Type hints while calling function
  • Documentation of function/value at point

All those operations are automatically called by eldoc when the cursor is idle for 0.5s.

full-demo.gif

Short video of demonstration with only type and documentation enabled:

demo.gif

Note that merlin is never called explicitly in this video. The only action is to move the pointer from one place to another.

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

You can’t perform that action at this time.