tag: 1.2
commit 01ec85ff9dd18824625ebddc92df1509c4cecd25
Author: Michał K <[email protected]>
Commit: João Távora <[email protected]>
Implement TextDocument/rangeFormatting
* eglot.el (eglot-format): New command.
(eglot-format-buffer): Use it as implementation.
(eglot-client-capabilities): Add :rangeFormatting.
* eglot-tests.el (formatting): Also test range formatting.
* README.md (Commands and keybindings): Mention eglot-format.
(Language features): Tick textDocument/rangeFormatting.
---
README.md | 6 +++---
eglot-tests.el | 34 +++++++++++++++++++++-------------
eglot.el | 41 ++++++++++++++++++++++++++++++-----------
3 files changed, 54 insertions(+), 27 deletions(-)
diff --git a/README.md b/README.md
index f32f478..860dda8 100644
--- a/README.md
+++ b/README.md
@@ -96,8 +96,8 @@ Here's a summary of available commands:
- `M-x eglot-rename` ask the server to rename the symbol at point;
-- `M-x eglot-format-buffer` ask the server to reformat the current
- buffer;
+- `M-x eglot-format` asks the server to format buffer or the active
+ region;
- `M-x eglot-code-actions` asks the server for any code actions at
point. These may tipically be simple fixes, like deleting an unused
@@ -206,7 +206,7 @@ eglot-shutdown`.
- [ ] textDocument/documentColor
- [ ] textDocument/colorPresentation (3.6.0)
- [x] textDocument/formatting
-- [ ] textDocument/rangeFormatting
+- [x] textDocument/rangeFormatting
- [ ] textDocument/onTypeFormatting
- [x] textDocument/rename
diff --git a/eglot-tests.el b/eglot-tests.el
index 3932769..6940fcd 100644
--- a/eglot-tests.el
+++ b/eglot-tests.el
@@ -376,23 +376,31 @@ Pass TIMEOUT to `eglot--with-timeout'."
(should (string-match "^exit" eldoc-last-message)))))
(ert-deftest formatting ()
- "Test document formatting in a python LSP"
+ "Test formatting in a python LSP"
(skip-unless (and (executable-find "pyls")
(or (executable-find "yapf")
(executable-find "autopep8"))))
(eglot--with-dirs-and-files
- '(("project" . (("something.py" . "def foo():pass"))))
- (with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
- (search-forward ":pa")
- (eglot-format-buffer)
- (should (looking-at "ss"))
- (should (or
- ;; yapf
- (string= (buffer-string) "def foo():\n pass\n")
- ;; autopep8
- (string= (buffer-string) "def foo(): pass\n"))))))
+ '(("project" . (("something.py" . "def a():pass\ndef b():pass"))))
+ (with-current-buffer
+ (eglot--find-file-noselect "project/something.py")
+ (should (eglot--tests-connect))
+ (search-forward "b():pa")
+ (eglot-format (point-at-bol) (point-at-eol))
+ (should (looking-at "ss"))
+ (should
+ (or
+ ;; yapf
+ (string= (buffer-string) "def a():pass\n\n\ndef b():\n pass\n")
+ ;; autopep8
+ (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n")))
+ (eglot-format-buffer)
+ (should
+ (or
+ ;; yapf
+ (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n")
+ ;; autopep8
+ (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n"))))))
(ert-deftest javascript-basic ()
"Test basic autocompletion in a python LSP"
diff --git a/eglot.el b/eglot.el
index fbc6a53..f0a4b71 100644
--- a/eglot.el
+++ b/eglot.el
@@ -183,6 +183,7 @@ lasted more than that many seconds."
:documentHighlight `(:dynamicRegistration :json-false)
:codeAction `(:dynamicRegistration :json-false)
:formatting `(:dynamicRegistration :json-false)
+ :rangeFormatting `(:dynamicRegistration :json-false)
:rename `(:dynamicRegistration :json-false)
:publishDiagnostics `(:relatedInformation :json-false))
:experimental (list))))
@@ -1227,17 +1228,35 @@ DUMMY is ignored."
(defun eglot-format-buffer ()
"Format contents of current buffer."
(interactive)
- (unless (eglot--server-capable :documentFormattingProvider)
- (eglot--error "Server can't format!"))
- (eglot--apply-text-edits
- (jsonrpc-request
- (eglot--current-server-or-lose)
- :textDocument/formatting
- (list :textDocument (eglot--TextDocumentIdentifier)
- :options (list :tabSize tab-width
- :insertSpaces
- (if indent-tabs-mode :json-false t)))
- :deferred :textDocument/formatting)))
+ (eglot-format nil nil))
+
+(defun eglot-format (&optional beg end)
+ "Format region BEG END.
+If either BEG or END is nil, format entire buffer.
+Interactively, format active region, or entire buffer if region
+is not active."
+ (interactive (and (region-active-p) (list (region-beginning) (region-end))))
+ (pcase-let ((`(,method ,cap ,args)
+ (cond
+ ((and beg end)
+ `(:textDocument/rangeFormatting
+ :documentRangeFormattingProvider
+ (:range ,(list :start (eglot--pos-to-lsp-position beg)
+ :end (eglot--pos-to-lsp-position end)))))
+ (t
+ '(:textDocument/formatting :documentFormattingProvider
nil)))))
+ (unless (eglot--server-capable cap)
+ (eglot--error "Server can't format!"))
+ (eglot--apply-text-edits
+ (jsonrpc-request
+ (eglot--current-server-or-lose)
+ method
+ (cl-list*
+ :textDocument (eglot--TextDocumentIdentifier)
+ :options (list :tabSize tab-width
+ :insertSpaces (if indent-tabs-mode :json-false t))
+ args)
+ :deferred method))))
(defun eglot-completion-at-point ()
"EGLOT's `completion-at-point' function."