Skip to content

Commit 701c27b

Browse files
committed
Merge pull request #22 from otijhuis/eldoc
Аdd eldoc support
2 parents 6f4e792 + 8247c43 commit 701c27b

File tree

2 files changed

+122
-5
lines changed

2 files changed

+122
-5
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ result will be nothing short of havoc.**
5454

5555
`M-x inf-clojure` or `C-c C-z` within a Clojure source file.
5656

57+
## ElDoc
58+
59+
`eldoc-mode` is supported in Clojure source buffers and `*inferior-clojure*`
60+
buffers which are running a Clojure REPL.
61+
62+
When ElDoc is enabled and there is an active REPL, it will show the
63+
argument list of the function call you are currently editing in the
64+
echo area.
65+
66+
You can activate ElDoc with `M-x eldoc-mode` or by adding the
67+
following to you Emacs config:
68+
69+
```el
70+
(add-hook 'clojure-mode-hook #'eldoc-mode)
71+
(add-hook 'inf-clojure-mode-hook #'eldoc-mode)
72+
```
73+
74+
ElDoc currently doesn't work with ClojureScript buffers and REPL's.
75+
You can leave it enabled, it just won't show anything in the echo area.
76+
5777
## Troubleshooting
5878

5979
### REPL not responsive in Windows OS

inf-clojure.el

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040

4141
(require 'comint)
4242
(require 'clojure-mode)
43+
(require 'eldoc)
44+
(require 'thingatpt)
4345

4446

4547
(defgroup inf-clojure nil
@@ -131,6 +133,7 @@ The following commands are available:
131133
132134
\\{inf-clojure-minor-mode-map}"
133135
:lighter "" :keymap inf-clojure-minor-mode-map
136+
(inf-clojure-eldoc-setup)
134137
(make-local-variable 'completion-at-point-functions)
135138
(add-to-list 'completion-at-point-functions
136139
#'inf-clojure-completion-at-point))
@@ -247,6 +250,7 @@ to continue it."
247250
(setq comint-prompt-regexp inf-clojure-prompt)
248251
(setq mode-line-process '(":%s"))
249252
(clojure-mode-variables)
253+
(inf-clojure-eldoc-setup)
250254
(setq comint-get-old-input #'inf-clojure-get-old-input)
251255
(setq comint-input-filter #'inf-clojure-input-filter)
252256
(set (make-local-variable 'comint-prompt-read-only) inf-clojure-prompt-read-only)
@@ -429,11 +433,15 @@ Used by this command to determine defaults."
429433
; doesn't need an exact name
430434
(comint-check-source file-name) ; Check to see if buffer needs saved.
431435
(setq inf-clojure-prev-l/c-dir/file (cons (file-name-directory file-name)
432-
(file-name-nondirectory file-name)))
436+
(file-name-nondirectory file-name)))
433437
(comint-send-string (inf-clojure-proc)
434438
(format inf-clojure-load-command file-name))
435439
(inf-clojure-switch-to-repl t))
436440

441+
(defun inf-clojure-connected-p ()
442+
"Return t if inferior Clojure is currently connected, nil otherwise."
443+
(not (null inf-clojure-buffer)))
444+
437445

438446
;;; Documentation functions: function doc, var doc, arglist, and
439447
;;; describe symbol.
@@ -519,6 +527,9 @@ The value is nil if it can't find one."
519527
(and (symbolp obj) obj)))
520528
(error nil)))
521529

530+
(defun inf-clojure-symbol-at-point ()
531+
"Return the name of the symbol at point, otherwise nil."
532+
(or (thing-at-point 'symbol) ""))
522533

523534
;;; Documentation functions: var doc and arglist.
524535
;;; ======================================================================
@@ -535,7 +546,7 @@ See variable `inf-clojure-var-source-command'."
535546
(interactive (inf-clojure-symprompt "Var source" (inf-clojure-var-at-pt)))
536547
(comint-proc-query (inf-clojure-proc) (format inf-clojure-var-source-command var)))
537548

538-
(defun inf-clojure-show-arglist (fn)
549+
(defun inf-clojure-arglist (fn)
539550
"Send a query to the inferior Clojure for the arglist for function FN.
540551
See variable `inf-clojure-arglist-command'."
541552
(interactive (inf-clojure-symprompt "Arglist" (inf-clojure-fn-called-at-pt)))
@@ -549,12 +560,16 @@ See variable `inf-clojure-arglist-command'."
549560
(process-send-string proc eldoc-snippet)
550561
(while (and (not (string-match inf-clojure-prompt kept))
551562
(accept-process-output proc 2)))
552-
; some nasty #_=> garbage appears in the output
553563
(setq eldoc (and (string-match "(.+)" kept) (match-string 0 kept)))
554564
)
555565
(set-process-filter proc comint-filt))
556-
(when eldoc
557-
(message "%s: %s" fn eldoc))))
566+
eldoc))
567+
568+
(defun inf-clojure-show-arglist (fn)
569+
"Show the arglist for function FN in the mini-buffer."
570+
(interactive (inf-clojure-symprompt "Arglist" (inf-clojure-fn-called-at-pt)))
571+
(if-let ((eldoc (inf-clojure-arglist fn)))
572+
(message "%s: %s" fn eldoc)))
558573

559574
(defun inf-clojure-show-ns-vars (ns)
560575
"Send a query to the inferior Clojure for the public vars in NS.
@@ -644,6 +659,88 @@ Returns the selected completion or nil."
644659
(completion-table-with-cache #'inf-clojure-completions)
645660
(completion-table-dynamic #'inf-clojure-completions))))))
646661

662+
;;;; ElDoc
663+
;;;; =====
664+
665+
(defvar inf-clojure-extra-eldoc-commands '("yas-expand")
666+
"Extra commands to be added to eldoc's safe commands list.")
667+
668+
(defvar-local inf-clojure-eldoc-last-symbol nil
669+
"The eldoc information for the last symbol we checked.")
670+
671+
(defun inf-clojure-eldoc-format-thing (thing)
672+
"Format the eldoc THING."
673+
(propertize thing 'face 'font-lock-function-name-face))
674+
675+
(defun inf-clojure-eldoc-beginning-of-sexp ()
676+
"Move to the beginning of current sexp.
677+
678+
Return the number of nested sexp the point was over or after. "
679+
(let ((parse-sexp-ignore-comments t)
680+
(num-skipped-sexps 0))
681+
(condition-case _
682+
(progn
683+
;; First account for the case the point is directly over a
684+
;; beginning of a nested sexp.
685+
(condition-case _
686+
(let ((p (point)))
687+
(forward-sexp -1)
688+
(forward-sexp 1)
689+
(when (< (point) p)
690+
(setq num-skipped-sexps 1)))
691+
(error))
692+
(while
693+
(let ((p (point)))
694+
(forward-sexp -1)
695+
(when (< (point) p)
696+
(setq num-skipped-sexps (1+ num-skipped-sexps))))))
697+
(error))
698+
num-skipped-sexps))
699+
700+
(defun inf-clojure-eldoc-info-in-current-sexp ()
701+
"Return a list of the current sexp and the current argument index."
702+
(save-excursion
703+
(let ((argument-index (1- (inf-clojure-eldoc-beginning-of-sexp))))
704+
;; If we are at the beginning of function name, this will be -1.
705+
(when (< argument-index 0)
706+
(setq argument-index 0))
707+
;; Don't do anything if current word is inside a string, vector,
708+
;; hash or set literal.
709+
(if (member (or (char-after (1- (point))) 0) '(?\" ?\{ ?\[))
710+
nil
711+
(list (inf-clojure-symbol-at-point) argument-index)))))
712+
713+
(defun inf-clojure-eldoc-arglist (thing)
714+
"Return the arglist for THING."
715+
(when (and thing
716+
(not (string= thing ""))
717+
(not (string-prefix-p ":" thing)))
718+
;; check if we can used the cached eldoc info
719+
(if (string= thing (car inf-clojure-eldoc-last-symbol))
720+
(cdr inf-clojure-eldoc-last-symbol)
721+
(let ((arglist (inf-clojure-arglist (substring-no-properties thing))))
722+
(when arglist
723+
(setq inf-clojure-eldoc-last-symbol (cons thing arglist))
724+
arglist)))))
725+
726+
(defun inf-clojure-eldoc ()
727+
"Backend function for eldoc to show argument list in the echo area."
728+
(when (and (inf-clojure-connected-p)
729+
;; don't clobber an error message in the minibuffer
730+
(not (member last-command '(next-error previous-error))))
731+
(let* ((info (inf-clojure-eldoc-info-in-current-sexp))
732+
(thing (car info))
733+
(value (inf-clojure-eldoc-arglist thing)))
734+
(when value
735+
(format "%s: %s"
736+
(inf-clojure-eldoc-format-thing thing)
737+
value)))))
738+
739+
(defun inf-clojure-eldoc-setup ()
740+
"Turn on eldoc mode in the current buffer."
741+
(setq-local eldoc-documentation-function #'inf-clojure-eldoc)
742+
(apply #'eldoc-add-command inf-clojure-extra-eldoc-commands))
743+
647744
(provide 'inf-clojure)
648745

649746
;;; inf-clojure.el ends here

0 commit comments

Comments
 (0)