Skip to content

Commit ece16ff

Browse files
rrudakovbbatsov
authored andcommitted
Add clojure-ts-mode support
1 parent 9aea501 commit ece16ff

File tree

3 files changed

+115
-54
lines changed

3 files changed

+115
-54
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Changelog
22

33
## master (unreleased)
4+
45
* Improve support for multiple forms in the same line by replacing beginning-of-defun fn.
56
* [#202](https://github.com/clojure-emacs/inf-clojure/issues/202): Add ClojureCLR support.
67
* [#204](https://github.com/clojure-emacs/inf-clojure/issues/204): Scroll repl buffer on insert commands
78
* [#208](https://github.com/clojure-emacs/inf-clojure/pull/208) Display message after setting repl.
8-
* [#210](https://github.com/clojure-emacs/inf-clojure/pull/210) Include `inf-clojure-socket-repl` to create a socket REPL and connect to it from inside Emacs.
9-
9+
* [#210](https://github.com/clojure-emacs/inf-clojure/pull/210) Include `inf-clojure-socket-repl` to create a socket REPL and connect to it from inside Emacs.
10+
- [#217](https://github.com/clojure-emacs/inf-clojure/pull/217): Add `clojure-ts-mode` support.
1011

1112
## 3.2.1 (2022-07-22)
1213

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ You can also add the following to your Emacs config to enable
103103

104104
```emacs-lisp
105105
(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode)
106+
107+
;; or if you're a `clojure-ts-mode' user:
108+
109+
(add-hook 'clojure-ts-mode-hook #'inf-clojure-minor-mode)
106110
```
107111

108112
**Warning:** Don't enable `inf-clojure-minor-mode` and `cider-mode` at the same time. They
@@ -217,6 +221,18 @@ If you want to update a specific form there is a function
217221
(inf-clojure-update-feature 'clojure 'completion "(incomplete.core/completions \"%s\")")
218222
```
219223

224+
### `clojure-ts-mode` support
225+
226+
`inf-clojure` will try to use `clojure-ts-mode` by default if it's
227+
available with fallback to `clojure-mode`.
228+
229+
If you want to use `inf-clojure` with `clojure-mode` exclusively, you
230+
can set it to:
231+
232+
```emacs-lisp
233+
(setopt inf-clojure-source-modes '(clojure-mode))
234+
```
235+
220236
#### Caveats
221237

222238
As `inf-clojure` is built on top of `comint` it has all the usual comint limitations -

inf-clojure.el

Lines changed: 96 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@
6565

6666
(require 'comint)
6767
(require 'clojure-mode)
68+
(require 'clojure-ts-mode nil :no-error)
6869
(require 'eldoc)
6970
(require 'thingatpt)
7071
(require 'ansi-color)
7172
(require 'cl-lib)
7273
(require 'subr-x)
74+
(require 'project)
7375

7476
(defvar inf-clojure-startup-forms '((lein . "lein repl")
7577
(boot . "boot repl")
@@ -193,10 +195,10 @@ either `setq-local` or an entry in `.dir-locals.el`." )
193195
MULTIPLE PROCESS SUPPORT
194196
===========================================================================
195197
To run multiple Clojure processes, you start the first up
196-
with \\[inf-clojure]. It will be in a buffer named `*inf-clojure*'.
198+
with \\[inf-clojure]. It will be in a buffer named *inf-clojure*.
197199
Rename this buffer with \\[rename-buffer]. You may now start up a new
198200
process with another \\[inf-clojure]. It will be in a new buffer,
199-
named `*inf-clojure*'. You can switch between the different process
201+
named *inf-clojure*. You can switch between the different process
200202
buffers with \\[switch-to-buffer].
201203
202204
Commands that send text from source buffers to Clojure processes --
@@ -205,7 +207,7 @@ process to send to, when you have more than one Clojure process around. This
205207
is determined by the global variable `inf-clojure-buffer'. Suppose you
206208
have three inferior Clojures running:
207209
Buffer Process
208-
foo inf-clojure
210+
foo `inf-clojure'
209211
bar inf-clojure<2>
210212
*inf-clojure* inf-clojure<3>
211213
If you do a \\[inf-clojure-eval-defun] command on some Clojure source code,
@@ -269,7 +271,7 @@ has been found. See also variable `inf-clojure-buffer'."
269271
(error "No Clojure subprocess; see variable `inf-clojure-buffer'"))))
270272

271273
(defun inf-clojure-repl-p (&optional buf)
272-
"Indicates if BUF is an inf-clojure REPL.
274+
"Indicates if BUF is an `inf-clojure' REPL.
273275
If BUF is nil then defaults to the current buffer.
274276
Checks the mode and that there is a live process."
275277
(let ((buf (or buf (current-buffer))))
@@ -278,35 +280,35 @@ Checks the mode and that there is a live process."
278280
(process-live-p (get-buffer-process buf)))))
279281

280282
(defun inf-clojure-repls ()
281-
"Return a list of all inf-clojure REPL buffers."
283+
"Return a list of all `inf-clojure' REPL buffers."
282284
(let (repl-buffers)
283285
(dolist (b (buffer-list))
284286
(when (inf-clojure-repl-p b)
285287
(push (buffer-name b) repl-buffers)))
286288
repl-buffers))
287289

288290
(defun inf-clojure--prompt-repl-buffer (prompt)
289-
"Prompt the user to select an inf-clojure repl buffer.
291+
"Prompt the user to select an `inf-clojure' repl buffer.
290292
PROMPT is a string to prompt the user.
291293
Returns nil when no buffer is selected."
292294
(let ((repl-buffers (inf-clojure-repls)))
293295
(if (> (length repl-buffers) 0)
294-
(when-let ((repl-buffer (completing-read prompt repl-buffers nil t)))
296+
(when-let* ((repl-buffer (completing-read prompt repl-buffers nil t)))
295297
(get-buffer repl-buffer))
296298
(user-error "No buffers have an inf-clojure process"))))
297299

298300
(defun inf-clojure-set-repl (always-ask)
299-
"Set an inf-clojure buffer as the active (default) REPL.
301+
"Set an `inf-clojure' buffer as the active (default) REPL.
300302
If in a REPL buffer already, use that unless a prefix is used (or
301-
ALWAYS-ASK). Otherwise get a list of all active inf-clojure
303+
ALWAYS-ASK). Otherwise get a list of all active `inf-clojure'
302304
REPLS and offer a choice. It's recommended to rename REPL
303305
buffers after they are created with `rename-buffer'."
304306
(interactive "P")
305-
(when-let ((new-repl-buffer
306-
(if (or always-ask
307-
(not (inf-clojure-repl-p)))
308-
(inf-clojure--prompt-repl-buffer "Select default REPL: ")
309-
(current-buffer))))
307+
(when-let* ((new-repl-buffer
308+
(if (or always-ask
309+
(not (inf-clojure-repl-p)))
310+
(inf-clojure--prompt-repl-buffer "Select default REPL: ")
311+
(current-buffer))))
310312
(setq inf-clojure-buffer new-repl-buffer)
311313
(message "Current inf-clojure REPL set to %s" new-repl-buffer)))
312314

@@ -349,6 +351,14 @@ mode. Default is whitespace followed by 0 or 1 single-letter colon-keyword
349351
\(as in :a, :c, etc.)"
350352
:type 'regexp)
351353

354+
(defcustom inf-clojure-source-modes '(clojure-ts-mode clojure-mode)
355+
"Used to determine if a buffer contains Clojure source code.
356+
357+
Any buffer with one of these major modes, it's considered a Clojure
358+
source file by all `inf-clojure' commands."
359+
:type '(repeat symbol)
360+
:safe #'symbolp)
361+
352362
(defun inf-clojure--modeline-info ()
353363
"Return modeline info for `inf-clojure-minor-mode'.
354364
Either \"no process\" or \"buffer-name(repl-type)\""
@@ -453,7 +463,7 @@ The value of this variable is a mode line template as in
453463
`mode-line-format'. See Info Node `(elisp)Mode Line Format' for details
454464
about mode line templates.
455465
456-
Customize this variable to change how inf-clojure-minor-mode
466+
Customize this variable to change how `inf-clojure-minor-mode'
457467
displays its status in the mode line. The default value displays
458468
the current REPL. Set this variable to nil to disable the
459469
mode line entirely."
@@ -609,24 +619,35 @@ This should usually be a combination of `inf-clojure-prompt' and
609619
:package-version '(inf-clojure . "2.0.0"))
610620

611621
(defcustom inf-clojure-auto-mode t
612-
"Automatically enable inf-clojure-minor-mode.
622+
"Automatically enable `inf-clojure-minor-mode'.
613623
All buffers in `clojure-mode' will automatically be in
614624
`inf-clojure-minor-mode' unless set to nil."
615625
:type 'boolean
616626
:safe #'booleanp
617627
:package-version '(inf-clojure . "3.1.0"))
618628

629+
(defun inf-clojure--get-preferred-major-modes ()
630+
"Return list of preferred major modes that are actually available."
631+
(cl-remove-if-not (lambda (mode) (featurep mode))
632+
inf-clojure-source-modes))
633+
634+
(defun inf-clojure--clojure-buffer-p ()
635+
"Return TRUE if the current buffer is a Clojure buffer."
636+
(derived-mode-p (inf-clojure--get-preferred-major-modes)))
637+
619638
(defun inf-clojure--clojure-buffers ()
620639
"Return a list of all existing `clojure-mode' buffers."
621-
(cl-remove-if-not
622-
(lambda (buffer) (with-current-buffer buffer (derived-mode-p 'clojure-mode)))
623-
(buffer-list)))
640+
(cl-remove-if-not (lambda (buffer)
641+
(with-current-buffer buffer
642+
(inf-clojure--clojure-buffer-p)))
643+
(buffer-list)))
624644

625645
(defun inf-clojure-enable-on-existing-clojure-buffers ()
626646
"Enable inf-clojure's minor mode on existing Clojure buffers.
627647
See command `inf-clojure-minor-mode'."
628648
(interactive)
629-
(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode)
649+
(dolist (mode (inf-clojure--get-preferred-major-modes))
650+
(add-hook (derived-mode-hook-name mode) #'inf-clojure-minor-mode))
630651
(dolist (buffer (inf-clojure--clojure-buffers))
631652
(with-current-buffer buffer
632653
(inf-clojure-minor-mode +1))))
@@ -688,6 +709,8 @@ If `comint-use-prompt-regexp' is nil (the default), \\[comint-insert-input] on
688709
(setq comint-input-sender 'inf-clojure--send-string)
689710
(setq comint-prompt-regexp inf-clojure-comint-prompt-regexp)
690711
(setq mode-line-process '(":%s"))
712+
;; NOTE: Using Tree-sitter based syntax highlighting in comint
713+
;; buffer is currently not possible.
691714
(clojure-mode-variables)
692715
(clojure-font-lock-setup)
693716
(when inf-clojure-enable-eldoc
@@ -799,10 +822,24 @@ to suppress the usage of the target buffer discovery logic."
799822
The name is simply the final segment of the path."
800823
(file-name-nondirectory (directory-file-name dir)))
801824

825+
(defun inf-clojure--project-dir ()
826+
"Return current Clojure project root."
827+
(let ((project-vc-extra-root-markers '("project.clj" ; Leiningen
828+
"build.boot" ; Boot
829+
"build.gradle" ; Gradle
830+
"build.gradle.kts" ; Gradle
831+
"deps.edn" ; Clojure CLI (a.k.a. tools.deps)
832+
"shadow-cljs.edn" ; shadow-cljs
833+
"bb.edn" ; babashka
834+
"nbb.edn" ; nbb
835+
"basilisp.edn" ; Basilisp (Python)
836+
)))
837+
(project-root (project-current))))
838+
802839
;;;###autoload
803840
(defun inf-clojure (cmd &optional suppress-message)
804-
"Run an inferior Clojure process, input and output via buffer `*inf-clojure*'.
805-
If there is a process already running in `*inf-clojure*', just
841+
"Run an inferior Clojure process, input and output via buffer *inf-clojure*.
842+
If there is a process already running in *inf-clojure*, just
806843
switch to that buffer.
807844
808845
CMD is a string which serves as the startup command or a cons of
@@ -826,7 +863,7 @@ process buffer for a list of commands.)"
826863
(mapcar #'cdr inf-clojure-startup-forms)
827864
nil
828865
'confirm-after-completion))))
829-
(let* ((project-dir (clojure-project-dir))
866+
(let* ((project-dir (inf-clojure--project-dir))
830867
(process-buffer-name (or
831868
inf-clojure-custom-repl-name
832869
(if project-dir
@@ -850,7 +887,9 @@ process buffer for a list of commands.)"
850887
(with-current-buffer (apply #'make-comint
851888
process-buffer-name (car cmdlist) nil (cdr cmdlist))
852889
(inf-clojure-mode)
853-
(set-syntax-table clojure-mode-syntax-table)
890+
(set-syntax-table (pcase (car (inf-clojure--get-preferred-major-modes))
891+
('clojure-ts-mode clojure-ts-mode-syntax-table)
892+
(_ clojure-mode-syntax-table)))
854893
(setq-local inf-clojure-repl-type repl-type)
855894
(hack-dir-local-variables-non-file-buffer))))
856895
;; update the default comint buffer and switch to it
@@ -940,7 +979,7 @@ defaults provided in `inf-clojure-socket-repl-startup-forms'."
940979
'confirm-after-completion))))
941980
(let* ((host "localhost")
942981
(port (or inf-clojure-socket-repl-port (+ 5500 (random 500))))
943-
(project-dir (clojure-project-dir))
982+
(project-dir (inf-clojure--project-dir))
944983
(repl-type (or (unless prefix-arg
945984
inf-clojure-custom-repl-type)
946985
(car (rassoc cmd inf-clojure-socket-repl-startup-forms))
@@ -978,16 +1017,19 @@ of forms."
9781017
(condition-case nil
9791018
(with-temp-buffer
9801019
(progn
981-
(clojurec-mode)
1020+
;; Activate preferred major mode.
1021+
(funcall (car (inf-clojure--get-preferred-major-modes)))
9821022
(insert str)
9831023
(whitespace-cleanup)
9841024
(goto-char (point-min))
9851025
(while (not (eobp))
9861026
(while (looking-at "\n")
9871027
(delete-char 1))
9881028
(unless (eobp)
989-
(clojure-forward-logical-sexp))
990-
(unless (eobp)
1029+
;; NOTE: There is no special API for that in
1030+
;; `clojure-ts-mode', so probably for now lets keep this
1031+
;; `clojure-mode' function.
1032+
(clojure-forward-logical-sexp)
9911033
(forward-char)))
9921034
(buffer-substring-no-properties (point-min) (point-max))))
9931035
(scan-error str)))
@@ -1105,13 +1147,6 @@ START and END are the beginning and end positions in the buffer to send."
11051147
This holds a cons cell of the form `(DIRECTORY . FILE)'
11061148
describing the last `inf-clojure-load-file' command.")
11071149

1108-
(defcustom inf-clojure-source-modes '(clojure-mode)
1109-
"Used to determine if a buffer contains Clojure source code.
1110-
If it's loaded into a buffer that is in one of these major modes, it's
1111-
considered a Clojure source file by `inf-clojure-load-file'.
1112-
Used by this command to determine defaults."
1113-
:type '(repeat symbol))
1114-
11151150
(defun inf-clojure-load-file (&optional switch-to-repl file-name)
11161151
"Load a Clojure file into the inferior Clojure process.
11171152
@@ -1123,7 +1158,7 @@ is present it will be used instead of the current file."
11231158
(file-name (or file-name
11241159
(car (comint-get-source "Load Clojure file: " inf-clojure-prev-l/c-dir/file
11251160
;; nil because doesn't need an exact name
1126-
inf-clojure-source-modes nil))))
1161+
(inf-clojure--get-preferred-major-modes) nil))))
11271162
(load-form (inf-clojure-get-feature proc 'load)))
11281163
(comint-check-source file-name) ; Check to see if buffer needs saved.
11291164
(setq inf-clojure-prev-l/c-dir/file (cons (file-name-directory file-name)
@@ -1132,23 +1167,32 @@ is present it will be used instead of the current file."
11321167
(when switch-to-repl
11331168
(inf-clojure-switch-to-repl t))))
11341169

1170+
(defun inf-clojure--find-ns ()
1171+
"Return the namespace of the current Clojure buffer.
1172+
1173+
This function delegates its job to an appropritate function, considering
1174+
`inf-clojure-source-modes'."
1175+
(pcase (car (inf-clojure--get-preferred-major-modes))
1176+
('clojure-ts-mode (clojure-ts-find-ns))
1177+
(_ (clojure-find-ns))))
1178+
11351179
(defun inf-clojure-reload (arg)
11361180
"Send a query to the inferior Clojure for reloading the namespace.
1137-
See variable `inf-clojure-reload-form' and
1181+
See variable `inf-clojure-reload-form' and variable
11381182
`inf-clojure-reload-all-form'.
11391183
11401184
The prefix argument ARG can change the behavior of the command:
11411185
1142-
- C-u M-x `inf-clojure-reload': prompts for a namespace name.
1143-
- M-- M-x `inf-clojure-reload': executes (require ... :reload-all).
1144-
- M-- C-u M-x `inf-clojure-reload': reloads all AND prompts."
1186+
- \\`C-u' \\[inf-clojure-reload]: prompts for a namespace name.
1187+
- \\`M--' \\[inf-clojure-reload]: executes (require ... :reload-all).
1188+
- \\`M--' \\`C-u' \\[inf-clojure-reload]: reloads all AND prompts."
11451189
(interactive "P")
11461190
(let* ((proc (inf-clojure-proc))
11471191
(reload-all-p (or (equal arg '-) (equal arg '(-4))))
11481192
(prompt-p (or (equal arg '(4)) (equal arg '(-4))))
11491193
(ns (if prompt-p
1150-
(car (inf-clojure-symprompt "Namespace" (clojure-find-ns)))
1151-
(clojure-find-ns)))
1194+
(car (inf-clojure-symprompt "Namespace" (inf-clojure--find-ns)))
1195+
(inf-clojure--find-ns)))
11521196
(form (if (not reload-all-p)
11531197
(inf-clojure-reload-form proc)
11541198
(inf-clojure-reload-all-form proc))))
@@ -1249,7 +1293,7 @@ STRING if present."
12491293
(prin1-to-string (substring-no-properties string))))
12501294
nil
12511295
(expand-file-name inf-clojure--log-file-name
1252-
(clojure-project-dir))
1296+
(inf-clojure--project-dir))
12531297
'append
12541298
'no-annoying-write-file-in-minibuffer)))
12551299

@@ -1357,11 +1401,11 @@ for evaluation, therefore FORM should not include it."
13571401
(defun inf-clojure-arglists (fn)
13581402
"Send a query to the inferior Clojure for the arglists for function FN.
13591403
See variable `inf-clojure-arglists-form'."
1360-
(when-let ((proc (inf-clojure-proc 'no-error)))
1361-
(when-let ((arglists-form (inf-clojure-get-feature proc 'arglists)))
1362-
(thread-first (format arglists-form fn)
1363-
(inf-clojure--process-response proc "(" ")")
1364-
(inf-clojure--some)))))
1404+
(when-let* ((proc (inf-clojure-proc 'no-error))
1405+
(arglists-form (inf-clojure-get-feature proc 'arglists)))
1406+
(thread-first (format arglists-form fn)
1407+
(inf-clojure--process-response proc "(" ")")
1408+
(inf-clojure--some))))
13651409

13661410
(defun inf-clojure-show-arglists (prompt-for-symbol)
13671411
"Show the arglists for function FN in the mini-buffer.
@@ -1383,8 +1427,8 @@ prefix argument PROMPT-FOR-NS, it prompts for a namespace name."
13831427
(interactive "P")
13841428
(let* ((proc (inf-clojure-proc))
13851429
(ns (if prompt-for-ns
1386-
(car (inf-clojure-symprompt "Ns vars" (clojure-find-ns)))
1387-
(clojure-find-ns)))
1430+
(car (inf-clojure-symprompt "Ns vars" (inf-clojure--find-ns)))
1431+
(inf-clojure--find-ns)))
13881432
(ns-vars-form (inf-clojure-get-feature proc 'ns-vars)))
13891433
(inf-clojure--send-string proc (format ns-vars-form ns))))
13901434

@@ -1396,8 +1440,8 @@ PROMPT-FOR-NS, it prompts for a namespace name."
13961440
(interactive "P")
13971441
(let* ((proc (inf-clojure-proc))
13981442
(ns (if prompt-for-ns
1399-
(car (inf-clojure-symprompt "Set ns to" (clojure-find-ns)))
1400-
(clojure-find-ns)))
1443+
(car (inf-clojure-symprompt "Set ns to" (inf-clojure--find-ns)))
1444+
(inf-clojure--find-ns)))
14011445
(set-ns-form (inf-clojure-get-feature proc 'set-ns)))
14021446
(when (or (not ns) (equal ns ""))
14031447
(user-error "No namespace selected"))

0 commit comments

Comments
 (0)