Skip to content

Commit

Permalink
[#1782] Customizable appearance of a multiline docstring
Browse files Browse the repository at this point in the history
  • Loading branch information
cskksc committed Jun 23, 2016
1 parent 4d915c3 commit 1554a48
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 21 deletions.
67 changes: 62 additions & 5 deletions cider-eldoc.el
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,73 @@ is non-nil. Else format it as a variable."
;; in case ns-or-class is nil
propertized-method-name))

(defun cider-eldoc-format-sym-doc (var ns docstring)
"Return the formatted eldoc string for VAR and DOCSTRING.
Consider the value of `eldoc-echo-area-use-multiline-p' while formatting.
If the entire line cannot fit in the echo area, the var name may be
truncated or eliminated entirely from the output to make room for the
description.
Try to truncate the var with various strategies, so that the var and
the docstring can be displayed in the minibuffer without resizing the window.
We start with `cider-abbreviate-ns' and `cider-last-ns-segment'.
Next, if the var is in current namespace, we remove NS from the eldoc string.
Otherwise, only the docstring is returned."
(let* ((ea-multi eldoc-echo-area-use-multiline-p)
;; Subtract 1 from window width since emacs will not write
;; any chars to the last column, or in later versions, will
;; cause a wraparound and resize of the echo area.
(ea-width (1- (window-width (minibuffer-window))))
(strip (- (+ (length var) (length docstring)) ea-width))
(newline (string-match-p "\n" docstring))
;; Truncated var can be ea-var long
;; Subtract 2 to account for the : and / added when including
;; the namespace prefixed form in eldoc string
(ea-var (- (- ea-width (length docstring)) 2)))
(cond
((or (eq ea-multi t)
(and (<= strip 0) (null newline))
(and ea-multi (or (> (length docstring) ea-width) newline)))
(format "%s: %s" var docstring))

;; Now we have to truncate either the docstring or the var
(newline (cider-eldoc-format-sym-doc var ns (substring docstring 0 newline)))

;; Only return the truncated docstring
((> (length docstring) ea-width)
(substring docstring 0 ea-width))

;; Try to truncate the var with cider-abbreviate-ns
((<= (length (cider-abbreviate-ns var)) ea-var)
(format "%s: %s" (cider-abbreviate-ns var) docstring))

;; Try to truncate var with cider-last-ns-segment
((<= (length (cider-last-ns-segment var)) ea-var)
(format "%s: %s" (cider-last-ns-segment var) docstring))

;; If the var is in current namespace, we try to truncate the var by
;; skipping the namespace from the returned eldoc string
((and (string-equal ns (cider-current-ns))
(<= (- (length var) (length ns)) ea-var))
(format "%s: %s"
(replace-regexp-in-string (format "%s/" ns) "" var)
docstring))

;; We couldn't fit the var and docstring in the available space,
;; so we just display the docstring
(t docstring))))

(defun cider-eldoc-format-variable (thing pos eldoc-info)
"Return the formatted eldoc string for a variable.
THING is the variable name. POS will always be 0 here.
ELDOC-INFO is a p-list containing the eldoc information."
(let ((ns (lax-plist-get eldoc-info "ns"))
(symbol (lax-plist-get eldoc-info "symbol"))
(docstring (lax-plist-get eldoc-info "docstring")))
(let* ((ns (lax-plist-get eldoc-info "ns"))
(symbol (lax-plist-get eldoc-info "symbol"))
(docstring (lax-plist-get eldoc-info "docstring"))
(formatted-var (cider-eldoc-format-thing ns symbol thing 'var)))
(when docstring
(format "%s: %s" (cider-eldoc-format-thing ns symbol thing 'var)
docstring))))
(cider-eldoc-format-sym-doc formatted-var ns docstring))))

(defun cider-eldoc-format-function (thing pos eldoc-info)
"Return the formatted eldoc string for a function.
Expand Down
44 changes: 28 additions & 16 deletions doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,6 @@ experience.

## Basic configuration

* Enable `eldoc` in Clojure buffers:

```el
(add-hook 'cider-mode-hook #'eldoc-mode)
```

![Eldoc](images/eldoc.png)

CIDER also would show the eldoc for the symbol at point. So in (map inc ...)
when the cursor is over inc its eldoc would be displayed. You can turn off this
behaviour by:

```el
(setq cider-eldoc-display-for-symbol-at-point nil)
```

* Suppress auto-enabling of `cider-mode` in `clojure-mode` buffers, when starting
CIDER:

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

## Configuring eldoc

* Enable `eldoc` in Clojure buffers:

```el
(add-hook 'cider-mode-hook #'eldoc-mode)
```

![Eldoc](images/eldoc.png)

* CIDER also would show the eldoc for the symbol at point. So in (map inc ...)
when the cursor is over inc its eldoc would be displayed. You can turn off this
behaviour by:

```el
(setq cider-eldoc-display-for-symbol-at-point nil)
```

* CIDER respects the value of `eldoc-echo-area-use-multiline-p` when
displaying documentation in the minibuffer. You can customize this variable to change
its behaviour.

| eldoc-echo-area-use-multiline-p | Behaviour |
| ------------- | ------------- |
| `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.|
| `nil` | Messages are always truncated to fit in a single line of display in the echo area. |
| `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. |

## Overlays

When you evaluate code in Clojure files, the result is displayed in the buffer
Expand Down
66 changes: 66 additions & 0 deletions test/cider-eldoc-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,69 @@
(search-forward ".length")
(expect (cider-eldoc-info-in-current-sexp) :to-equal
'("eldoc-info" (("java.lang.String") ".length" (("this"))) "thing" "java.lang.String/.length" "pos" 0)))))))

(describe "cider-eldoc-format-sym-doc"
:var (eldoc-echo-area-use-multiline-p)
(before-all
(spy-on 'window-width :and-return-value 177))

(it "returns the formated eldoc string"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Simple docstring.")
:to-equal "kubaru.core/plane: Simple docstring."))


(describe "specifications for eldoc-echo-area-use-multiline-p"
(describe "when its value is t"
(before-each
(setq eldoc-echo-area-use-multiline-p t))
(it "does not truncate anything"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
:to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3.")))


(describe "when its value is truncate-sym-name-if-fit"
(before-each
(setq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit))
(it "doesn't truncate anything if docstring doesn't fit"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

(it "truncates the symbol name with cider-abbreviate-ns"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
:to-equal "k.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

(it "truncates the symbol name with cider-last-ns-segment"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
:to-equal "core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

(it "leaves out the namespace if the var is in current namespace"
(spy-on 'cider-current-ns :and-return-value "kubaru.core")
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
:to-equal "plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

;; this case would be different when it is nil
(it "returns as is if truncating the symbol doesn't make it fit"
;; notice that the T is not deleted
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT")
:to-equal "kubaru.core/plane: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT"))

(describe "when the docstring spans multiple lines"
(it "returns it as is"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
:to-equal "kubaru.core/plane: Line 1.\nLine 2.\nLine 3."))))


(describe "when its value is nil"
(before-each
(setq eldoc-echo-area-use-multiline-p nil))
(it "leaves out the symbol name and truncates the docstring"
;; notice the missing T from the result
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaT")
:to-equal "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

(describe "when the docstring spans multiple lines"
(it "returns tries to display the var with the first line"
(expect (cider-eldoc-format-sym-doc "kubaru.core/plane" "kubaru.core" "Line 1.\nLine 2.\nLine 3.")
:to-equal "kubaru.core/plane: Line 1."))))))

0 comments on commit 1554a48

Please sign in to comment.