Skip to content

Commit 04f588e

Browse files
authored
Merge pull request #1785 from cskksc/feature/multiline-eldoc
Add support for multiline eldoc
2 parents 0f8df59 + 1554a48 commit 04f588e

File tree

5 files changed

+166
-28
lines changed

5 files changed

+166
-28
lines changed

cider-browse-ns.el

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ If the first line of the DOC string contains multiple sentences, only
120120
the first sentence is returned. If the DOC string is nil, a Not documented
121121
string is returned."
122122
(if doc
123-
(let* ((split-newline (split-string (read doc) "\n"))
123+
(let* ((split-newline (split-string doc "\n"))
124124
(first-line (car split-newline)))
125125
(cond
126126
((string-match "\\. " first-line) (substring first-line 0 (match-end 0)))
@@ -135,6 +135,9 @@ Each item consists of a ns-var and the first line of its docstring."
135135
(propertized-ns-vars (nrepl-dict-map #'cider-browse-ns--properties ns-vars-with-meta)))
136136
(mapcar (lambda (ns-var)
137137
(let* ((doc (nrepl-dict-get-in ns-vars-with-meta (list ns-var "doc")))
138+
;; to avoid (read nil)
139+
;; it prompts the user for a Lisp expression
140+
(doc (when doc (read doc)))
138141
(first-doc-line (cider-browse-ns--first-doc-line doc)))
139142
(concat ns-var " " (propertize first-doc-line 'font-lock-face 'font-lock-doc-face))))
140143
propertized-ns-vars)))

cider-eldoc.el

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,73 @@ is non-nil. Else format it as a variable."
138138
;; in case ns-or-class is nil
139139
propertized-method-name))
140140

141+
(defun cider-eldoc-format-sym-doc (var ns docstring)
142+
"Return the formatted eldoc string for VAR and DOCSTRING.
143+
144+
Consider the value of `eldoc-echo-area-use-multiline-p' while formatting.
145+
If the entire line cannot fit in the echo area, the var name may be
146+
truncated or eliminated entirely from the output to make room for the
147+
description.
148+
149+
Try to truncate the var with various strategies, so that the var and
150+
the docstring can be displayed in the minibuffer without resizing the window.
151+
We start with `cider-abbreviate-ns' and `cider-last-ns-segment'.
152+
Next, if the var is in current namespace, we remove NS from the eldoc string.
153+
Otherwise, only the docstring is returned."
154+
(let* ((ea-multi eldoc-echo-area-use-multiline-p)
155+
;; Subtract 1 from window width since emacs will not write
156+
;; any chars to the last column, or in later versions, will
157+
;; cause a wraparound and resize of the echo area.
158+
(ea-width (1- (window-width (minibuffer-window))))
159+
(strip (- (+ (length var) (length docstring)) ea-width))
160+
(newline (string-match-p "\n" docstring))
161+
;; Truncated var can be ea-var long
162+
;; Subtract 2 to account for the : and / added when including
163+
;; the namespace prefixed form in eldoc string
164+
(ea-var (- (- ea-width (length docstring)) 2)))
165+
(cond
166+
((or (eq ea-multi t)
167+
(and (<= strip 0) (null newline))
168+
(and ea-multi (or (> (length docstring) ea-width) newline)))
169+
(format "%s: %s" var docstring))
170+
171+
;; Now we have to truncate either the docstring or the var
172+
(newline (cider-eldoc-format-sym-doc var ns (substring docstring 0 newline)))
173+
174+
;; Only return the truncated docstring
175+
((> (length docstring) ea-width)
176+
(substring docstring 0 ea-width))
177+
178+
;; Try to truncate the var with cider-abbreviate-ns
179+
((<= (length (cider-abbreviate-ns var)) ea-var)
180+
(format "%s: %s" (cider-abbreviate-ns var) docstring))
181+
182+
;; Try to truncate var with cider-last-ns-segment
183+
((<= (length (cider-last-ns-segment var)) ea-var)
184+
(format "%s: %s" (cider-last-ns-segment var) docstring))
185+
186+
;; If the var is in current namespace, we try to truncate the var by
187+
;; skipping the namespace from the returned eldoc string
188+
((and (string-equal ns (cider-current-ns))
189+
(<= (- (length var) (length ns)) ea-var))
190+
(format "%s: %s"
191+
(replace-regexp-in-string (format "%s/" ns) "" var)
192+
docstring))
193+
194+
;; We couldn't fit the var and docstring in the available space,
195+
;; so we just display the docstring
196+
(t docstring))))
197+
141198
(defun cider-eldoc-format-variable (thing pos eldoc-info)
142199
"Return the formatted eldoc string for a variable.
143200
THING is the variable name. POS will always be 0 here.
144201
ELDOC-INFO is a p-list containing the eldoc information."
145-
(let ((ns (lax-plist-get eldoc-info "ns"))
146-
(symbol (lax-plist-get eldoc-info "symbol"))
147-
(docstring (lax-plist-get eldoc-info "docstring")))
202+
(let* ((ns (lax-plist-get eldoc-info "ns"))
203+
(symbol (lax-plist-get eldoc-info "symbol"))
204+
(docstring (lax-plist-get eldoc-info "docstring"))
205+
(formatted-var (cider-eldoc-format-thing ns symbol thing 'var)))
148206
(when docstring
149-
(format "%s: %s" (cider-eldoc-format-thing ns symbol thing 'var)
150-
docstring))))
207+
(cider-eldoc-format-sym-doc formatted-var ns docstring))))
151208

152209
(defun cider-eldoc-format-function (thing pos eldoc-info)
153210
"Return the formatted eldoc string for a function.

doc/configuration.md

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,6 @@ experience.
44

55
## Basic configuration
66

7-
* Enable `eldoc` in Clojure buffers:
8-
9-
```el
10-
(add-hook 'cider-mode-hook #'eldoc-mode)
11-
```
12-
13-
![Eldoc](images/eldoc.png)
14-
15-
CIDER also would show the eldoc for the symbol at point. So in (map inc ...)
16-
when the cursor is over inc its eldoc would be displayed. You can turn off this
17-
behaviour by:
18-
19-
```el
20-
(setq cider-eldoc-display-for-symbol-at-point nil)
21-
```
22-
237
* Suppress auto-enabling of `cider-mode` in `clojure-mode` buffers, when starting
248
CIDER:
259

@@ -140,6 +124,34 @@ More details can be found [here](https://github.com/clojure-emacs/cider/issues/9
140124
(setq cider-filter-regexps '(".*nrepl"))
141125
```
142126

127+
## Configuring eldoc
128+
129+
* Enable `eldoc` in Clojure buffers:
130+
131+
```el
132+
(add-hook 'cider-mode-hook #'eldoc-mode)
133+
```
134+
135+
![Eldoc](images/eldoc.png)
136+
137+
* CIDER also would show the eldoc for the symbol at point. So in (map inc ...)
138+
when the cursor is over inc its eldoc would be displayed. You can turn off this
139+
behaviour by:
140+
141+
```el
142+
(setq cider-eldoc-display-for-symbol-at-point nil)
143+
```
144+
145+
* CIDER respects the value of `eldoc-echo-area-use-multiline-p` when
146+
displaying documentation in the minibuffer. You can customize this variable to change
147+
its behaviour.
148+
149+
| eldoc-echo-area-use-multiline-p | Behaviour |
150+
| ------------- | ------------- |
151+
| `t` | Never attempt to truncate messages. Complete symbol name and function arglist or variable documentation will be displayed even if echo area must be resized to fit.|
152+
| `nil` | Messages are always truncated to fit in a single line of display in the echo area. |
153+
| `truncate-sym-name-if-fit` or anything non-nil | Symbol name may be truncated if it will enable the function arglist or documentation string to fit on a single line. Otherwise, behavior is just like `t` case. |
154+
143155
## Overlays
144156

145157
When you evaluate code in Clojure files, the result is displayed in the buffer

test/cider-browse-ns-tests.el

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@
6767
:to-equal "Not documented."))
6868

6969
(it "returns the first line of the doc string"
70-
(expect (cider-browse-ns--first-doc-line "\"True if s is nil, empty, or contains only whitespace.\"")
71-
:to-equal "True if s is nil, empty, or contains only whitespace."))
70+
(expect (cider-browse-ns--first-doc-line "True if s is nil, empty, or contains only whitespace.")
71+
:to-equal "True if s is nil, empty, or contains only whitespace."))
7272

7373
(it "returns the first sentence of the doc string if the first line contains multiple sentences"
74-
(expect (cider-browse-ns--first-doc-line "\"First sentence. Second sentence.\"")
75-
:to-equal "First sentence. "))
74+
(expect (cider-browse-ns--first-doc-line "First sentence. Second sentence.")
75+
:to-equal "First sentence. "))
7676

7777
(it "returns the first line of the doc string if the first sentence spans multiple lines"
78-
(expect (cider-browse-ns--first-doc-line "\"True if s is nil, empty, or\n contains only whitespace.\"")
79-
:to-equal "True if s is nil, empty, or...")))
78+
(expect (cider-browse-ns--first-doc-line "True if s is nil, empty, or\n contains only whitespace.")
79+
:to-equal "True if s is nil, empty, or...")))

test/cider-eldoc-tests.el

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,69 @@
234234
(search-forward ".length")
235235
(expect (cider-eldoc-info-in-current-sexp) :to-equal
236236
'("eldoc-info" (("java.lang.String") ".length" (("this"))) "thing" "java.lang.String/.length" "pos" 0)))))))
237+
238+
(describe "cider-eldoc-format-sym-doc"
239+
:var (eldoc-echo-area-use-multiline-p)
240+
(before-all
241+
(spy-on 'window-width :and-return-value 177))
242+
243+
(it "returns the formated eldoc string"
244+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Simple docstring.")
245+
:to-equal "kubaru.core/plane: Simple docstring."))
246+
247+
248+
(describe "specifications for eldoc-echo-area-use-multiline-p"
249+
(describe "when its value is t"
250+
(before-each
251+
(setq eldoc-echo-area-use-multiline-p t))
252+
(it "does not truncate anything"
253+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
254+
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
255+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
256+
:to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3.")))
257+
258+
259+
(describe "when its value is truncate-sym-name-if-fit"
260+
(before-each
261+
(setq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit))
262+
(it "doesn't truncate anything if docstring doesn't fit"
263+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
264+
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
265+
266+
(it "truncates the symbol name with cider-abbreviate-ns"
267+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
268+
:to-equal "k.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
269+
270+
(it "truncates the symbol name with cider-last-ns-segment"
271+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
272+
:to-equal "core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
273+
274+
(it "leaves out the namespace if the var is in current namespace"
275+
(spy-on 'cider-current-ns :and-return-value "kubaru.core")
276+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
277+
:to-equal "plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
278+
279+
;; this case would be different when it is nil
280+
(it "returns as is if truncating the symbol doesn't make it fit"
281+
;; notice that the T is not deleted
282+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT")
283+
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT"))
284+
285+
(describe "when the docstring spans multiple lines"
286+
(it "returns it as is"
287+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
288+
:to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3."))))
289+
290+
291+
(describe "when its value is nil"
292+
(before-each
293+
(setq eldoc-echo-area-use-multiline-p nil))
294+
(it "leaves out the symbol name and truncates the docstring"
295+
;; notice the missing T from the result
296+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT")
297+
:to-equal "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
298+
299+
(describe "when the docstring spans multiple lines"
300+
(it "returns tries to display the var with the first line"
301+
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
302+
:to-equal "kubaru.core/plane: Line 1."))))))

0 commit comments

Comments
 (0)