Skip to content

Commit 96dbc3e

Browse files
committed
v2.0 release, updated README, added comments to all fns, added gifs for locals
and java completion, and made it so in cljs buffers we don't auto-complete Java since it doesn't make sense.
1 parent 57c0413 commit 96dbc3e

File tree

4 files changed

+78
-16
lines changed

4 files changed

+78
-16
lines changed

README.org

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,24 @@
66

77
This package makes use of clj-kondo's analysis data to provide code editing facilities related to Clojure, ClojureScript and cljc source. This means you get advanced editing features like auto-complete without the need for a connected REPL, because clj-kondo performs its magic using static source code analysis.
88

9-
Currently, it gives you contextual auto-completion using completion-at-point, which works without a REPL connected, since it relies on clj-kondo's static source analysis. It will list out all available Vars, Ns and Aliases in a given buffer.
9+
Current Features:
1010

11-
It supports the notion of projects, using projectile and Clojure's tools.deps. This means it'll pick up the buffer's current project root using projectile, and it will use Clojure's tools.deps to get the project's classpath. If it can't find either, it'll only auto-complete within the buffer, it won't be able to show candidates from the required dependencies.
11+
+ It gives you contextual auto-completion using completion-at-point, which works without a REPL connected, since it relies on clj-kondo's static source analysis. It will list out all available Vars, Ns and Aliases in a given buffer.
12+
+ It can also perform locals completion, using an Emacs implemented heuristic completion based on dabbrev that works really well in practice and can handle unbalanced code.
13+
+ It can also complete Java classes and their static methods and fields. It does so by relying on jar and javap JDK command line binaries.
14+
+ It supports the notion of projects, using projectile and Clojure's tools.deps. This means it'll pick up the buffer's current project root using projectile, and it will use Clojure's tools.deps to get the project's classpath. If it can't find either, it'll only auto-complete within the buffer, it won't be able to show candidates from the required dependencies.
1215

1316
* Screenshots
1417

15-
#+CAPTION: Example completion using anakondo
18+
#+CAPTION: Example Clojure global Vars and namespace completion using anakondo
1619
[[./screenshots/anakondo-auto-completion-no-repl-demo.gif]]
1720

21+
#+CAPTION: Example Clojure local binding completion using anakondo
22+
[[./screenshots/anakondo-locals-auto-completion-no-repl-demo.gif]]
23+
24+
#+CAPTION: Example Java classes and static methods and fields completion using anakondo
25+
[[./screenshots/anakondo-java-auto-completion-no-repl-demo.gif]]
26+
1827
* Contents :noexport:
1928
:PROPERTIES:
2029
:TOC: :include siblings
@@ -35,17 +44,38 @@ It supports the notion of projects, using projectile and Clojure's tools.deps. T
3544

3645
** Prerequisites
3746

38-
Anakondo needs the Clojure CLI tools.deps and clj-kondo to be installed and accessible from Emacs in order to run properly. To do so:
47+
For Clojure[Script] completion, Anakondo needs the Clojure CLI tools.deps and clj-kondo to be installed and accessible from Emacs in order to run properly. To do so:
3948

4049
1. Install clj-kondo by following its [[https://github.com/borkdude/clj-kondo/blob/master/doc/install.md][install instructions]].
4150
2. Make sure =clj-kondo= is in your shell's ~PATH~.
4251
3. Install the Clojure CLI tools.deps by following its [[https://clojure.org/guides/getting_started#_clojure_installer_and_cli_tools][install instruction]].
4352
4. Make sure the =clojure= CLI is in your shell's ~PATH~.
44-
5. Now proceed with one of the following strategies to install the anakondo package in your Emacs.
53+
54+
For Java completion, you also need to be sure that you have a JDK installed and that its ~/bin~ folder is on the environment PATH used by Emacs.
4555

4656
** MELPA
4757

48-
Not in MELPA yet, but should be coming soon.
58+
1. Run: ~M-x package-install anakondo~
59+
2. Now put this in your init file:
60+
+ If you want to pre-load it:
61+
#+BEGIN_SRC elisp
62+
;; Load anakondo to make available its minor mode in clojure buffers
63+
(require 'anakondo)
64+
#+END_SRC
65+
+ If you want to lazy load it:
66+
#+BEGIN_SRC elisp
67+
;; Delays loading of anakondo until a clojure buffer is used
68+
(autoload 'anakondo-minor-mode "anakondo")
69+
#+END_SRC
70+
71+
** use-package
72+
73+
Put this in your in your init file:
74+
#+begin_src emacs-lisp :tangle yes
75+
(use-package anakondo
76+
:ensure t
77+
:commands anakondo-minor-mode)
78+
#+end_src
4979

5080
** Manual
5181

@@ -94,7 +124,7 @@ If you are also using Cider, the order in which you add the hooks matters in the
94124
1. If you add anakondo to the Clojure mode hooks first, then completion will first try to use anakondo's, and only if it can't complete the form will it then try to use Cider's completion. This means if you try to complete a keyword for example, it'll fallback to Cider's, but for completing symbols it won't, even if it finds no candidates.
95125
2. Otherwise, if you add Cider to the Clojure mode hooks first, then completion will first try to use Cider's, and only if Cider completion is not available, because there is no connected REPL, will it then fallback to try anakondo's completion. If Cider completion is available (because you have a REPL connected), it will never fallback to trying anakondo's completion, even if Cider doesn't find any completion candidates.
96126

97-
*Currently, I recommend adding anakondo after Cider*. This will make it so when no REPL is connected, you have anakondo's clj-kondo based static analysis completion. While when a REPL is running, you have Cider's completion, which currently gives you more information and includes locals and java classes. If you do it the other way around, when a REPL is running, if anakondo find completions you will only see the ones it found, which would be missing local bindings and java classes. I'll be exploring options to have the completions merged in the future, so we get the best of both worlds.
127+
*Currently, I recommend adding anakondo after Cider*. This will make it so when no REPL is connected, you have anakondo's clj-kondo based static analysis completion. While when a REPL is running, you have Cider's completion. If you do it the other way around, when a REPL is running, if anakondo find completions you will only see the ones it found. I'll be exploring options to have the completions merged in the future, so we get the best of both worlds.
98128

99129
This also goes if you turn on/off the modes manually, except in that case, order and effect are reversed. The last mode you turn on will be the one who is in charge of completion first. While with the hooks, it is the first mode you add to the hook that will be in charge of completion first.
100130

@@ -105,6 +135,11 @@ This also goes if you turn on/off the modes manually, except in that case, order
105135
+ If dependency completion isn't working, remember that =anakondo= only supports =tools.deps= for now, if you don't have a =deps.edn= for your project, it will pick up your global =deps.edn= instead, it won't use your lein =project.clj= or boot =build.boot= dependencies.
106136
+ If you've disabled cider-mode, and somehow anakondo completion stopped working, this is because of a known bug in cider-mode, which removes all configured completion for the buffer, not just its own, I am trying to get this fixed in cider as well.
107137
+ If you've killed the REPL, and somehow anakondo completion doesn't seem to be starting back up, this is also due to a bug in cider, where it deletes all configured completion for the buffer on repl quit. I am trying to get this fixed in cider as well.
138+
+ For Java completions of the default imports, they are going to be the ones defined by Clojure 1.10. So if you use an older or newer version of Clojure, you'll still see the completion of the imports from Clojure 1.10. So don't take it as a source of truth.
139+
+ The list of Java classes you get completed comes from the boot classpath specified by the =java= command which is on your environment PATH, and the Java dependencies defined in your project's deps.edn. So if you use Java 8, you will see the Java 8 standard classes, if you use Java 11, you will see Java 11's standard classes, etc.
140+
+ Only Java classes coming from a Jar on your boot classpath and classpath will be completed. If you have =.class= files in your boot classpath or classpath they will not be completed for now. So if you depend on Java dependencies, make sure it is through a Jar, and not a folder containing =.class= files if you want completion for them.
141+
+ To auto-complete the static methods and fields of a Java class, type =/= after the class and call your completion function, such as completion-at-point or company-indent-or-complete-common, etc.
142+
+ Java static methods and fields completion doesn't work with custom imports for now, only fully qualified and default imports will get completion.
108143

109144
* Changelog
110145
:PROPERTIES:
@@ -116,7 +151,7 @@ This also goes if you turn on/off the modes manually, except in that case, order
116151
Additions
117152
+ Add support for locals auto-completion
118153
+ Add support for Java classes auto-completion (fully qualified + default imports only for now) (can only complete from jars on the classpath, no support for class files on the classpath for now)
119-
+ Add support for Java static methods and fields auto-completion on press of `/`
154+
+ Add support for Java static methods and fields auto-completion on press of =/=
120155

121156
Changes
122157
+ Much faster auto-completion when using "as you type" completion like company-mode
@@ -126,7 +161,7 @@ Fixes
126161

127162
Internal
128163
+ Added a buffer local cache of completion candidates which keeps track of the completion list for the last start positions of completions, makes "as you type" completions much faster
129-
+ Infers Java boot classpath by using the `java` command itself
164+
+ Infers Java boot classpath by using the =java= command itself
130165
+ Uses dabbrev with some custom heuristic to identify symbols and syntax-ppsp for locals completion
131166
+ Uses javap to find available static methods and fields for a given class
132167
+ Uses jar to find all classes in the classpath jars

anakondo.el

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ for completion, and messaging was excessive in that case."
429429
curr-ns))
430430

431431
(defun anakondo--jar-analize-sync (classpath-list)
432+
"Return the list of Java classes contained in the Jars from CLASSPATH-LIST."
432433
(let* ((jars (seq-filter
433434
(lambda (path)
434435
(string-match-p ".*\.jar$" path))
@@ -453,12 +454,19 @@ for completion, and messaging was excessive in that case."
453454
classes))))))))
454455

455456
(defun anakondo--make-class-map (class-name methods-and-fields)
457+
"Make a java class definition hash table map.
458+
459+
{:name CLASS-NAME
460+
:methods-and-fields METHODS-AND-FIELDS}"
456461
(let* ((class-map (make-hash-table)))
457462
(puthash :name class-name class-map)
458463
(puthash :methods-and-fields methods-and-fields class-map)
459464
class-map))
460465

461466
(defun anakondo--java-analyze-class-map (classpath class)
467+
"Return the class-map containing Java methods and fields for given CLASS.
468+
469+
CLASSPATH : The classpath where CLASS can be found in."
462470
(let* (methods-and-fields)
463471
(with-temp-buffer
464472
(shell-command (concat "javap -cp '" classpath "' -public '" class "'") t)
@@ -480,6 +488,7 @@ for completion, and messaging was excessive in that case."
480488
(anakondo--make-class-map class methods-and-fields)))
481489

482490
(defun anakondo--get-java-boot-classpath-list ()
491+
"Return the Java boot classpath as a list."
483492
(let* ((boot-classpath (with-temp-buffer
484493
(shell-command "java -XshowSettings:properties -version" t)
485494
(goto-char (point-min))
@@ -501,6 +510,11 @@ for completion, and messaging was excessive in that case."
501510
boot-classpath))
502511

503512
(defun anakondo--get-java-analysis-classpath (as)
513+
"Return classpath that contain both project classpath and boot classpath.
514+
515+
AS : can be 'list if you want classpath returned as a list
516+
or 'cp if you want classpath returned as a java style
517+
colon separated string classpath."
504518
(let* ((project-path (anakondo--get-project-path))
505519
(project-classpaths-list (split-string project-path ":" nil "[[:blank:]\n]*"))
506520
(java-boot-classpath-list (anakondo--get-java-boot-classpath-list))
@@ -510,7 +524,7 @@ for completion, and messaging was excessive in that case."
510524
('cp (string-join analysis-classpath-list ":")))))
511525

512526
(defun anakondo--java-projectile-analyse-sync (java-classes-cache)
513-
"Analyze synchronously the project for all Java classes and their methods and fields.
527+
"Analyze project for all Java classes and their methods and fields.
514528
515529
Updates JAVA-CLASSES-CACHE with the result."
516530
(let* ((analysis-classpath-list (anakondo--get-java-analysis-classpath 'list))
@@ -557,7 +571,7 @@ How it works:
557571
;; Fix clj-kondo issue: https://github.com/borkdude/clj-kondo/issues/866
558572
;; We need to send to clj-kondo the buffer with prefix that doesn't end in forward slash
559573
(prefix-end-in-forward-slash? (when (and (char-before) (= (char-before) ?/))
560-
(delete-backward-char 1)
574+
(delete-char -1)
561575
t))
562576
(curr-ns (anakondo--clj-kondo-buffer-analyse-sync var-def-cache ns-def-cache ns-usage-cache)))
563577
;; Restore deleted forward-slash
@@ -591,15 +605,18 @@ How it works:
591605
(anakondo--safe-hash-table-values (gethash curr-ns ns-usage-cache))))))
592606

593607
(defun anakondo--get-local-completion-candidates (prefix prefix-start)
594-
"Return a local candidate list compatible with completion-at-point for current symbol at point.
608+
"Return a local candidate list for current symbol at point.
595609
596-
Does not use clj-kondo, will perform a heuristic search for locals on best effort.
610+
Does not use clj-kondo, will perform a heuristic search for locals on
611+
best effort.
597612
598613
Heuristic:
599-
Uses dabbrev to find all symbols between the top level form up to prefix-start.
614+
Uses dabbrev to find all symbols between the top level form up to
615+
prefix-start.
600616
601617
PREFIX : string for which to find all candidates that can complete it.
602-
PREFIX-START : start point of PREFIX, candidates are found up to PREFIX-START."
618+
PREFIX-START : start point of PREFIX, candidates are found up to
619+
PREFIX-START."
603620
(let* ((all-expansions nil)
604621
expansion
605622
(syntax (syntax-ppss))
@@ -615,6 +632,11 @@ PREFIX-START : start point of PREFIX, candidates are found up to PREFIX-START."
615632
all-expansions))
616633

617634
(defun anakondo--get-java-completion-candidates (prefix)
635+
"Return the java completion candidates at point for given PREFIX.
636+
637+
PREFIX : Used to figure out when we should complete java classes
638+
versus completing java methods and fields by checking
639+
if prefix ends in a forward slash or not."
618640
(let* ((java-classes-cache (anakondo--get-projectile-java-classes-cache))
619641
(class-to-complete (when (string-match "^\\(?1:.*\\)/.*$" prefix)
620642
(match-string 1 prefix))))
@@ -674,13 +696,18 @@ Return a `completion-at-point' list for use with
674696
(anakondo--get-local-completion-candidates prefix start)))
675697
(let* ((candidates (append
676698
(anakondo--get-clj-kondo-completion-candidates)
677-
(anakondo--get-java-completion-candidates prefix))))
699+
(unless (equal (anakondo--get-buffer-lang) "cljs")
700+
(anakondo--get-java-completion-candidates prefix)))))
678701
(setq-local anakondo--completion-candidates-cache (cons start candidates))
679702
(append
680703
candidates
681704
(anakondo--get-local-completion-candidates prefix start))))))))))
682705

683706
(defun anakondo--projectile-analyse-sync (var-def-cache ns-def-cache ns-usage-cache java-classes-cache)
707+
"Analyze projectile project, updating caches with analysis result.
708+
709+
Caches which will be updated are VAR-DEF-CACHE, NS-DEF-CACHE, NS-USAGE-CACHE,
710+
JAVA-CLASSES-CACHE."
684711
(message "Analysing project for completion...")
685712
(anakondo--clj-kondo-projectile-analyse-sync var-def-cache ns-def-cache ns-usage-cache)
686713
(anakondo--java-projectile-analyse-sync java-classes-cache)
410 KB
Loading
837 KB
Loading

0 commit comments

Comments
 (0)