Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ Unreleased
- Simplify `on-interface` to avoid redundant extension check ([#90](https://github.com/tarides/ocaml-eglot/pull/90))
- Avoid re-initializing major mode on every type display update ([#90](https://github.com/tarides/ocaml-eglot/pull/90))
- Remove `ocaml-eglot-objinfo` in favor to `neocaml-objinfo` ([#92](https://github.com/tarides/ocaml-eglot/pull/92))
- Rename minor mode from `ocaml-eglot` to `ocaml-eglot-mode` (old name kept as alias)
- Rename minor mode from `ocaml-eglot` to `ocaml-eglot-mode` (old name kept as alias) ([#93](https://github.com/tarides/ocaml-eglot/pull/93))
- Add `M-w` as a shortcut for copying types in the kill-ring ([#96](https://github.com/tarides/ocaml-eglot/pull/96))
- Add `q` as a shortcut for closing ocaml-eglot-temporary buffer ([#96](https://github.com/tarides/ocaml-eglot/pull/96))
Add `ocaml-eglot-refactor-extract` to extract region a local definition and attach the feature to `type-enclosing` ([#96](https://github.com/tarides/ocaml-eglot/pull/96))

ocaml-eglot 1.3.0
======================
Expand Down
100 changes: 59 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ user experience as close as possible to that offered by the Emacs mode
- [Configure `flymake`](#configure-flymake)
- [Using `flycheck` instead of `flymake`](#using-flycheck-instead-of-flymake)
- [Using Merlin-configuration](#using-merlin-configuration)
- [`merlin.el` window behavior](#merlinel-window-behavior)
- [Recommended minimal configuration](#recommended-minimal-configuration)
- [Usage with `dune pkg`](#usage-with-dune-pkg)
- [Features](#features)
Expand All @@ -43,17 +44,18 @@ user experience as close as possible to that offered by the Emacs mode
- [Jump to definition/declaration](#jump-to-definitiondeclaration)
- [Definition and Declaration](#definition-and-declaration)
- [Find identifier definition/declaration](#find-identifier-definitiondeclaration)
- [Jump to type definition of an expression](#jump-to-type-definition--of-an-expression)
- [Jump to type definition of an expression](#jump-to-type-definition-of-an-expression)
- [Find occurrences](#find-occurrences)
- [Renaming](#renaming)
- [Infer Interface](#infer-interface)
- [Find Alternate file](#find-alternate-file)
- [Get Documentation](#get-documentation)
- [Construct Expression](#construct-expression)
- [Destruct (or case-analysis)](#destruct-or-case-analysis)
- [Source Browsing](#source-browsing)
- [Search for values](#search-for-values)
- [Opening up build artefacts](#opening-up-build-artefacts)
- [Refactoring](#refactoring)
- [Renaming](#renaming)
- [Extract expression as toplevel expression ](#extract-expression-as-toplevel-expression)
- [Comparison of Merlin and OCaml-eglot commands](#comparison-of-merlin-and-ocaml-eglot-commands)

<!-- markdown-toc end -->
Expand Down Expand Up @@ -429,16 +431,16 @@ During a "type enclosing" session the following commands are available:
expression
- `ocaml-eglot-type-enclosing-shrink` (<kbd>C-↓</kbd>): to shrink the
expression
- `ocaml-eglot-type-enclosing-copy` (<kbd>C-w</kbd>): to copy the
- `ocaml-eglot-type-enclosing-copy` (<kbd>C-w</kbd> or <kbd>M-w</kbd>): to copy the
type expression to the _kill-ring_ (clipboard)
- `ocaml-eglot-type-enclosing-annotate` (<kbd>C-;</kbd>): to annotate
(with type) the current enclosing
- `ocaml-eglot-type-enclosing-refactor-extract-at-toplevel` (<kbd>C-x</kbd>): to extract the enclosing inside a toplevel definition

You can also enter an expression in the mini-buffer for which you want
to display the type:

- `ocaml-eglot-type-expression` (<kbd>C-u</kbd> <kbd>C-c</kbd> <kbd>C-t</kbd>)
- `ocaml-eglot-type-annotate` Add type annotation under the cursor


![Type Enclosings example](media/type-enclosing.gif)
Expand Down Expand Up @@ -499,14 +501,6 @@ project, it requires an index. This index can be created by running

![Occurrences example](media/occurences.gif)

### Renaming

Use `ocaml-eglot-rename` to rename the symbol under the
cursor. Starting with OCaml 5.3 it is possible to rename a symbol
across multiple files after building an up-to-date index with `dune
build @ocaml-index`.

![Rename example](media/rename.gif)

### Infer Interface

Expand Down Expand Up @@ -620,34 +614,58 @@ Alternatively, you can search for a definition or declaration:

![Search Definition or Declaration Example](media/search-def.gif)

### Refactoring

#### Renaming

Use `ocaml-eglot-rename` to rename the symbol under the
cursor. Starting with OCaml 5.3 it is possible to rename a symbol
across multiple files after building an up-to-date index with `dune
build @ocaml-index`.

![Rename example](media/rename.gif)

#### Extract expression as toplevel expression

Extract the selected region into a top-level variable. If a prefix is
provided, the command allows entering a name and passing free
variables (_after extraction_) as arguments:

![Extract Example](media/refactor-1.gif)

It can be used through **type-enclosing**:

![Extract Example with enclosings](media/refactor-2.gif)


## Comparison of Merlin and OCaml-eglot commands

| `merlin` | `ocaml-eglot` | Note |
|-----------------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------|
| `merlin-error-check` | — | The functionality is supported by `eglot` diagnostics (via LSP). |
| `merlin-error-next` | `ocaml-eglot-error-next` | |
| `merlin-error-prev` | `ocaml-eglot-error-prev` | |
| `merlin-type-enclosing` | `ocaml-eglot-type-enclosing` | |
| `merlin-type-expr` | `ocaml-eglot-type-expression` | |
| ❌ | `ocaml-eglot-type-annotate` | |
| `merlin-locate` | `ocaml-eglot-find-declaration` | |
| — | `ocaml-eglot-find-definition` | Available in Merlin by configuration |
| ❌ | `ocaml-eglot-find-type-definition` | |
| ❌ | `ocaml-eglot-find-identifier-in-alternate-file` | |
| `merlin-locate-ident` | `ocaml-eglot-find-identifier-definition`, `ocaml-eglot-find-identifier-declaration` | |
| `merlin-occurences` | `ocaml-eglot-occurrences` | |
| `merlin-project-occurences` | — | Handled by `ocaml-eglot-occurrences` (if `ocaml-version >= 5.2` and need an index, `dune build @ocaml-index`) |
| `merlin-iedit-occurrences` | `ocaml-eglot-rename` | |
| `merlin-document` | `ocaml-eglot-document` | also `ocaml-eglot-document-identifier` |
| `merlin-phrase-next` | `ocaml-eglot-phrase-next` | |
| `merlin-phrase-prev` | `ocaml-eglot-phrase-prev` | |
| `merlin-switch-to-ml` | `ocaml-eglot-alternate-file` | |
| `merlin-switch-to-mli` | `ocaml-eglot-alternate-file` | |
| ❌ | `ocaml-eglot-infer-interface` | It was supported by `Tuareg` (and a bit ad-hoc) |
| `merlin-jump` | `ocaml-eglot-jump` | |
| `merlin-destruct` | `ocaml-eglot-destruct` | |
| `merlin-construct` | `ocaml-eglot-construct` | |
| `merlin-next-hole` | `ocaml-eglot-hole-next` | |
| `merlin-previous-hole` | `ocaml-eglot-hole-prev` | |
| `merlin-toggle-view-errors` | — | An `eglot` configuration |
| `merlin` | `ocaml-eglot` | Note |
|-----------------------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
| `merlin-error-check` | — | The functionality is supported by `eglot` diagnostics (via LSP). |
| `merlin-error-next` | `ocaml-eglot-error-next` | |
| `merlin-error-prev` | `ocaml-eglot-error-prev` | |
| `merlin-type-enclosing` | `ocaml-eglot-type-enclosing` | |
| `merlin-type-expr` | `ocaml-eglot-type-expression` | |
| ❌ | `ocaml-eglot-type-annotate` | |
| `merlin-locate` | `ocaml-eglot-find-declaration` | |
| — | `ocaml-eglot-find-definition` | Available in Merlin by configuration |
| ❌ | `ocaml-eglot-find-type-definition` | |
| ❌ | `ocaml-eglot-find-identifier-in-alternate-file` | |
| `merlin-locate-ident` | `ocaml-eglot-find-identifier-definition`, `ocaml-eglot-find-identifier-declaration` | |
| `merlin-occurences` | `ocaml-eglot-occurrences` | |
| `merlin-project-occurences` | — | Handled by `ocaml-eglot-occurrences` (if `ocaml-version >= 5.2` and need an index, `dune build @ocaml-index`) |
| `merlin-iedit-occurrences` | `ocaml-eglot-rename` | |
| `merlin-document` | `ocaml-eglot-document` | also `ocaml-eglot-document-identifier` |
| `merlin-phrase-next` | `ocaml-eglot-phrase-next` | |
| `merlin-phrase-prev` | `ocaml-eglot-phrase-prev` | |
| `merlin-switch-to-ml` | `ocaml-eglot-alternate-file` | |
| `merlin-switch-to-mli` | `ocaml-eglot-alternate-file` | |
| ❌ | `ocaml-eglot-infer-interface` | It was supported by `Tuareg` (and a bit ad-hoc) |
| `merlin-jump` | `ocaml-eglot-jump` | |
| `merlin-destruct` | `ocaml-eglot-destruct` | |
| `merlin-construct` | `ocaml-eglot-construct` | |
| `merlin-next-hole` | `ocaml-eglot-hole-next` | |
| `merlin-previous-hole` | `ocaml-eglot-hole-prev` | |
| `merlin-toggle-view-errors` | — | An `eglot` configuration |
| ❌ | `ocaml-eglot-refactor-extract-at-toplevel` | |
Binary file added media/refactor-1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/refactor-2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 10 additions & 13 deletions ocaml-eglot-req.el
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ under the cursor. The MARKUP-KIND can also be configured."
markup-kind)))
(ocaml-eglot-req--send :ocamllsp/getDocumentation params)))

(defun ocaml-eglot-req--locate-fallback (err)
(defun ocaml-eglot-req--err-fallback (err)
"A fallback for printing ERR from locate queries."
(let ((error-data (alist-get 'jsonrpc-error-data err)))
(eglot--error "%s" error-data)))
Expand All @@ -190,7 +190,7 @@ under the cursor. The MARKUP-KIND can also be configured."
"Execute the `textDocument/typeDefinition' request for the current point."
(let ((params (ocaml-eglot-req--TextDocumentPositionParams)))
(ocaml-eglot-req--send :textDocument/typeDefinition params
:fallback 'ocaml-eglot-req--locate-fallback)))
:fallback 'ocaml-eglot-req--err-fallback)))

(defun ocaml-eglot-req--type-enclosings (at index verbosity)
"Execute the `ocamllsp/typeEnclosing' request for the current point.
Expand Down Expand Up @@ -244,17 +244,14 @@ ARGV is the list of arguments."
`(:expression, expression))))
(ocaml-eglot-req--send :ocamllsp/typeExpression params)))

(defun ocaml-eglot-req--locate-ident (ident look-for)
"Locate an identifier (IDENT) using `merlin-locate'.
LOOK-FOR is used to define if it should find the interface
or the implementation."
;; TODO: use a dedicated custom request instead of tunneling
(let ((argv (vector "-position" (ocaml-eglot-util-point-as-arg (point-max))
"-prefix" ident
"-look-for" (pcase look-for
('interface "interface")
(_ "implementation")))))
(ocaml-eglot-req--merlin-call "locate" argv)))
(defun ocaml-eglot-req--refactor-extract (range &optional name)
"Extract the given RANGE as a toplevel expression named NAME.
If NAME is empty, it will be computed."
(let ((params (append (ocaml-eglot-req--TextDocumentIdentifier)
`(:range, range)
`(:extract_name, name))))
(ocaml-eglot-req--send :ocamllsp/refactorExtract params
:fallback 'ocaml-eglot-req--err-fallback)))

(provide 'ocaml-eglot-req)
;;; ocaml-eglot-req.el ends here
Loading
Loading