Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Basic interaction with a Clojure subprocess from Emacs

NotificationsYou must be signed in to change notification settings

clojure-emacs/inf-clojure

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Circle CIMELPAMELPA StableNonGNU ELPALicense GPL 3

inf-clojure

This package provides basic interaction with a Clojure subprocess (REPL).It's based on ideas from the popularinferior-lisp package.

inf-clojure has two components - a nice REPL buffer (inf-clojure-mode) and a REPLinteraction minor mode (inf-clojure-minor-mode), which extendsclojure-modewith commands to evaluate forms directly in the REPL.

Important

This documentation tracks themaster branch ofinf-clojure. Some ofthe features and settings discussed here might not be available inolder releases (including the current stable release). Please, consultthe relevant git tag (e.g. 2.2.0) if you need documentation for aspecificinf-clojure release.

Overview

inf-clojure aims to expose the extensive self-documenting features of ClojureREPLs via an Emacs package.inf-clojure is extremely simple and does not require special tooling.It supports the following REPLs:

inf-clojure provides a set of essential features for interactiveClojure/ClojureScript/ClojureCLR development:

  • Enhanced REPL
  • Interactive code evaluation
  • Code completion
  • Definition lookup
  • Documentation lookup
  • ElDoc
  • Apropos
  • Macroexpansion
  • Reloading a namespace (viarequire :reload/require :reload-all)
  • Connecting to socket REPLs

For a more powerful/full-featured solution seeCIDER.

Rationale

inf-clojure's goal is to provide the simplest possible way to interact with aClojure REPL. In Emacs terminology "inferior" process is a subprocess startedby Emacs (it being the "superior" process, of course).

inf-clojure doesn't require much of setup, as at its core it simply runs aterminal REPL process, pipes input to it, and processes its output. As theClojure socket REPL works in exactly the same mannerinf-clojure can alsointeract with it.

Functionality like code completion and eldoc is powered by evaluation ofpredefined code snippets that provide the necessary results. As differentClojure REPLs have different capabilities,inf-clojure tracks the type of aREPL and invokes the right code for each REPL type.

inf-clojure is built on top of Emacs'scomint. Unfortunatelycomint is pretty light on official documentation, but there is a goodoverview/tutorialhere.

Installation

Important

inf-clojure requires Emacs 28 or newer.

inf-clojure is available on the officialNonGNU ELPApackage.el repo and on the community-maintainedMELPA Stable andMELPA repos.

NonGNU ELPA and MELPA Stable are recommended as they have the latest stable version.MELPA has a development snapshot for users who don't mind breakage butdon't want to runinf-clojure from a git checkout.

You can installinf-clojure using the following command:

M-x package-install [RET] inf-clojure [RET]

or if you'd rather keep it in your Emacs config:

(unless (package-installed-p'inf-clojure)  (package-refresh-contents)  (package-install'inf-clojure))

If the installation doesn't work try refreshing the package list:

M-x package-refresh-contents

inf-clojure-minor-mode will be auto-enabled for Clojure source buffers after you doM-x inf-clojure. You can disable this behavior by settinginf-clojure-auto-mode tonil.

You can also add the following to your Emacs config to enableinf-clojure-minor-mode for Clojure source buffers, regardless of whetherthere's aninf-clojure REPL running:

(add-hook'clojure-mode-hook#'inf-clojure-minor-mode);; or if you're a`clojure-ts-mode' user:(add-hook'clojure-ts-mode-hook#'inf-clojure-minor-mode)

Warning

Don't enableinf-clojure-minor-mode andcider-mode at the same time. Theyhave overlapping functionality and keybindings and the result will be nothingshort of havoc.

Basic Usage

Just invokeM-x inf-clojure or pressC-c C-z within a Clojuresource file. You should get a prompt with the supported REPL types andcommon startup forms. You can select one of these or type in your owncustom startup. This will start a REPL process for the current projectand you can start interacting with it.

If you want to use a socket REPL server, useM-x inf-clojure-socket-replwhich will start a socket server and connect to it for you.

If you've already started a socket REPL server, useM-x inf-clojure-connectand enter its host and port numbers.

Inf-clojure aims to be very simple and offer tooling that the REPLitself exposes. A few commands are:

  • eval last sexp (C-x C-e)
  • show arglists for function (C-c C-a)
  • show var documentation (C-c C-v)
  • show source (C-c C-s)
  • insert top level form into REPL (C-c C-j d)

For a list of all available commands ininf-clojure-mode (a.k.a. theREPL) andinf-clojure-minor-mode you can either invokeC-h f RET inf-clojure-mode andC-h f RET inf-clojure-minor-mode or simplybrowse their menus.

Manyinf-clojure-minor-mode commands by default act on the symbol atpoint. You can, however, change this behaviour by invoking suchcommands with a prefix argument. For instance:C-u C-c C-v will askfor the symbol you want to show the docstring for.

Configuration

In the time-honoured Emacs traditioninf-clojure's behaviour is extremelyconfigurable.

You can set custom values toinf-clojure variables on aper-project basis usingdirectoryvariablesor by setting them in in yourinit file.

You can see all the configuration options available using the commandM-x customize-group RET inf-clojure.

Startup

Whileinf-clojure is capable of starting many common REPLs out of the box, it'sfairly likely you will want to set some custom REPL startup command(e.g. because you need to include sometools.deps profile) and the REPL typethat goes with it. This is most easily achieved with the following.dir-locals.el:

((nil  (inf-clojure-custom-startup."clojure -A:compliment")  (inf-clojure-custom-repl-type. clojure)))

Important

This file has to be in the directory in which you're invokinginf-clojure or a parent directory.

There are two important configuration variables here:

  1. inf-clojure-custom-startup: Which startup command to use soinf-clojure can run the inferior Clojure process (REPL).
  2. inf-clojure-custom-repl-type: The type of the REPL started by the above command (e.g.planck).

If these are set and you wish to prevent inf-clojure from using them,use a prefix arg when invokinginf-clojure (C-u M-x inf-clojure).

REPL Features

The supported REPL-features are in an alist calledinf-clojure-repl-features and it has the following shape:

'((cljs. ((doc."(cljs.repl/doc %s)")           (source."(cljs.repl/source %s)")           (arglists."(try (->> '%s cljs.core/resolve cljs.core/meta :arglists) (catch :default _ nil))")           (apropos."(cljs.repl/apropos\"%s\")")           (ns-vars."(cljs.repl/dir %s)")           (set-ns."(in-ns '%s)")           (macroexpand."(cljs.core/macroexpand '%s)")           (macroexpand-1."(cljs.core/macroexpand-1 '%s)"))))

If you want to add a new REPL type, just do something like:

(add-to-list'inf-clojure-repl-features             (cons new-repl-type '((doc."(myrepl/doc-command %s")                                   (source."...")                                   ...)))

Theinf-clojure-repl-features data structure is just analist of alists, so you can manipulate it in numerous ways.

If you want to update a specific form there is a functioninf-clojure-update-repl-feature which can be used like so:

(inf-clojure-update-feature'clojure'completion"(incomplete.core/completions\"%s\")")

clojure-ts-mode support

inf-clojure will try to useclojure-ts-mode by default if it'savailable with fallback toclojure-mode.

If you want to useinf-clojure withclojure-mode exclusively, youcan set it to:

(setopt inf-clojure-source-modes '(clojure-mode))

Caveats

Asinf-clojure is built on top ofcomint it has all the usual comint limitations -namely it can't handle well some fancy terminal features (e.g. ANSI colours).In general the "dumber" your terminal REPL is, the better (e.g.clojure vsclj).Connecting to a socket REPL is one simple way to avoid dealing with this type ofproblems.

If you decidenot to use the socket REPL, it is highly recommendedyou disable output coloring and/orreadline facilities:inf-clojure does notfilter out ASCII escape characters at the moment and will not behave correctly.

ForLeiningen, there are no command-line switches and you need to adda customproject.cljoption:

...:repl-options {:colorfalse}...

Clojure Command Line Socket REPL

If you have the newClojure CLI tools installed you can use theclojure command:

Important

Do not useclj because it adds readline support.

clojure -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"

Then eitherC-c M-c RET localhost RET 5555 from within Emacs or add the following to your.dir-locals.el:

((nil. ((inf-clojure-custom-startup. ("localhost".5555)))))

Leiningen Socket REPL

For Leiningen, add the following option to your~/.lein/profiles.clj or yourproject.clj:

:jvm-opts ["-Dclojure.server.repl={:port 5555 :accept clojure.core.server/repl}"]

Then runlein repl from within your project directory to start theREPL. To connect, you can eitherm-x inf-clojure-connect [RET] localhost [RET] 5555 or you can put in a dir local file theinformation on how connect:

((nil (inf-clojure-custom-startup"localhost".5555)))

The socket server REPL configuration options are describedhere.

Multiple Process Support

To run multiple Clojure processes, you start the first upwithinf-clojure. It will be in a buffer named*inf-clojure*.Rename this buffer withrename-buffer. You may now start up a newprocess with anotherinf-clojure. It will be in a new buffer,named*inf-clojure*. You can switch between the different processbuffers withswitch-to-buffer.

Note

If you're startinginf-clojure within a Clojure project directory the nameof the project will be incorporated into the name of the REPL buffer -e.g.*inf-clojure my-project*.

Commands that send text from source buffers to Clojure processes (likeinf-clojure-eval-defunorinf-clojure-show-arglists) have to choose a process to send to, when you have more thanone Clojure process around. This is determined by the global variableinf-clojure-buffer.

Suppose you have three inferior Clojures running:

Buffer              Process------              -------foo                 inf-clojurebar                 inf-clojure<2>*inf-clojure*       inf-clojure<3>

If you do ainf-clojure-eval-defun command on some Clojure source code,what process do you send it to?

  • If you're in a process buffer (foo, bar, or*inf-clojure*),you send it to that process.
  • If you're in some other buffer (e.g., a source file), yousend it to the process attached to bufferinf-clojure-buffer.

This process selection is performed by functioninf-clojure-proc.Wheneverinf-clojure fires up a new process, it resetsinf-clojure-buffer to be the new process's buffer. If you only runone process, this does the right thing. If you run multipleprocesses, you might need to changeinf-clojure-buffer towhichever process buffer you want to use.

You can use the helpful functioninf-clojure-set-repl. If called inaninf-clojure REPL buffer, it will assign that buffer as the currentREPL ((setq inf-clojure-buffer (current-buffer)). If you arenot in aninf-clojure REPL buffer, it will offer a choice ofacceptable buffers to set as the REPL buffer. If called with a prefix,it will always give the list even if you are currently in anacceptable REPL buffer.

Tip

Renaming buffers will greatly improve thefunctionality of this list; the list "project-1: clojure repl","project-2: cljs repl" is far more understandable than "inf-clojure","inf-clojure<2>".

REPL Type

Aninf-clojure REPL has an associated type. The available types can beobtained frominf-clojure-repl-features:

(mapcar'car inf-clojure-repl-features);; => (cljs planck joker clojure babashka)

What does it mean that a REPL type is supported? Well, it means thatinf-clojure would use the proper Clojure(Script) code internally to powercommands like definition lookup and friends. Those differ from REPL to REPL andcan't be implemented in a REPL-independent way. The REPL type is inferred onstartup when using theinf-clojure command or is specified manually when usinginf-clojure-connect.

ElDoc

eldoc-mode is supported in Clojure source buffers and*inferior-clojure*buffers which are running a Clojure REPL.

When ElDoc is enabled and there is an active REPL, it will show the argumentlist of the function call you are currently editing in the echo area. Itaccomplishes this by evaluating forms to get the metadata for the vars underyour cursor. One side effect of this is that it can mess with repl vars like*1 and*2. You can disable inf-clojure's Eldoc functionality with(setq inf-clojure-enable-eldoc nil).

ElDoc should be enabled by default in Emacs 26.1+. If it is not active bydefault, you can activate ElDoc withM-x eldoc-mode or by adding the followingto you Emacs config:

(add-hook'clojure-mode-hook#'eldoc-mode)(add-hook'inf-clojure-mode-hook#'eldoc-mode)

ElDoc currently doesn't work with ClojureScript buffers and REPL's.You can leave it enabled, it just won't show anything in the echo area.

Code Completion

Code completion is a tricky aspect if you are trying to be as close toa generic REPL as possible. Some runtimes (e.g. Planck)explicitly provide completion functions in their REPL namespaces. Forclojure, you will need to have a library on your classpath. If you areusing a recent version of Leiningen, you already haveincomplete. Youcould alternatively usecompliment {:mvn/version "0.3.10"}.

;; for incomplete(inf-clojure-update-feature'clojure'completion"(incomplete.core/completions\"%s\")");; or;; for compliment(inf-clojure-update-feature'clojure'completion"(compliment.core/completions\"%s\")")

If you give a form for the completion form, it is your responsibilityto ensure that this namespace is on the classpath and required. Ifusing Leiningen, this is done for you withincomplete. If addingcompliment, the following sampledeps.edn can conveniently add the depto your program:

{:aliases {:compliment {:extra-deps {compliment {:mvn/version"0.3.10"}}}}}

Use the startup command:clojure -A:compliment. Then require the nsonce so that the completion machinery will work:(require 'compliment.core). Now tab completion should work.

For more advanced customization, code completion is particularly opento customization. Not only you cansetq the customaryinf-clojure-completion-form,inf-clojure-completion-form-planck andinf-clojure-completion-form-joker - the form to send to the REPL -but you can also useinf-clojure-completions-fn for specifying afunction that given the REPL response should return Elisp datacompatible withcompletion-at-point-functions.

For more info runM-x describe-variable RET inf-clojure-completions-fn. Another option is to have a look athowCIDER doesit.

Troubleshooting

Things seem broken

Inf-clojure is intentionally quite simple and just sends commands to aREPL on your behalf to provide features. In order to do thisinf-clojure largely needs to know the REPL type so it can format thecorrect calls. Most end up in(planck.repl/doc [symbol]) or(cljs.repl/doc ...) so its important that the REPL type is setcorrectly. This REPL type exists in the process buffer (REPL) and thesource buffers as a cache. If you have problems, runM-x inf-clojure-set-repl-type from the source buffer to set the REPL typein both buffers. To see how simple inf-clojure is, look atinf-clojure-repl-features to see largely how things are laid out.

REPL not responsive in Windows OS

In Windows, the REPL is not returning anything. For example, type(+ 1 1) and pressENTER, the cursor just drops to a new line andnothing is shown.

The explanation of this problem and solution can be foundhere.

The solution is to create a file named.jline.rc in your$HOMEdirectory and add this line to that file:

jline.terminal=unsupported

Log process activity

Standard Emacs debugging turns out to be difficult when an asynchronous process is involved. In this case try to enable logging:

(setq inf-clojure-log-activityt)

This creates.inf-clojure.log in the project directory so that you cantail -f on it.

License

Copyright © 2014-2025 Bozhidar Batsov andcontributors.

Distributed under the GNU General Public License; typeC-h C-c to view it.

About

Basic interaction with a Clojure subprocess from Emacs

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors32


[8]ページ先頭

©2009-2025 Movatter.jp