1. Overview

vim-iced logo

vim-iced is a Vim8 / Neovim plugin to provide a Clojure interactive development environment.

This project is heavily inspired by CIDER, and the goal of this project is to provide a Clojure development environment to Vim that is comparable(or more) to CIDER.

The assumption of "comparable to CIDER" varies from person to person. Although it is subjective, I assume "comparable to CIDER" is that there is no obstacle to development at work.

2. Getting Started

2.1. Installation

vim-iced itself and vim-sexp are the minimul requirements.

In addition, if there is one of follows, you can use interactive UI for selecting one from multiple candidates (e.g. selecting a ns which you’d like to add)

If anything is okay, ctrlp.vim is easy to install and stable.

2.1.1. Installing plugins

At first, if you don’t have a plugin manager, please install vim-plug.

vim
$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
neovim
$ curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

Next, add a vim-plug section to your ~/.vimrc (or ~/.config/nvim/init.vim for Neovim)

" Specify a directory for plugins
call plug#begin('~/.vim/plugged')

" One of following
Plug 'ctrlpvim/ctrlp.vim'
Plug 'junegunn/fzf'
Plug 'liuchengxu/vim-clap'

" Requires
Plug 'guns/vim-sexp',    {'for': 'clojure'}
Plug 'liquidz/vim-iced', {'for': 'clojure'}

call plug#end()

" Enable vim-iced's default key mapping
" This is recommended for newbies
let g:iced_enable_default_key_mappings = v:true

Then start Vim/Neovim, and execute the following command to install dependent plugins.

:PlugInstall

2.1.2. iced command

iced is a a utility command to make you easy to use vim-iced, and it comes with vim-iced. Setup is easy, just add the bin directory under the installed vim-iced directory to $PATH environmental variable. With above vim-plug setting, ~/.vim/plugged/vim-iced/bin is the directory to add to $PATH.

$ export PATH=$PATH:/path/to/repo/vim-iced/bin

To confirm setup, run the following command.

$ iced version

See iced command for more information.

2.2. Quick start

Let’s create a sample project for quick start. Here Leiningen is used to create a project template.

$ lein new hello-iced
$ cd hello-iced

We use iced command to launch REPL instead of lein command. This allows iced command to take care of all the additional libraries and REPL settings you need.

$ iced repl

Open vim and execute IcedConnect command.

$ vim src/hello_iced/core.clj

You succeeded to connect REPL if you see "Connected" message, so let’s execute the next command.

:IcedEval (+ 1 2 3 4 5)

Do you see 15 as a result? If so, your vim has started working with Clojure’s REPL finally!

3. Evaluation

The evaluation of S-expression is the most important element in REPL driven development.

3.1. Ranges

There are 3 main ranges to evaluation in vim-iced.

  • inner element

  • outer list

  • outer top list

See the following figure for the concrete ranges.

Evaluation range

If you enable default key mappings, following key mappings are available.

Table 1. Default key mappings

inner element

<Leader>ei

outer list

<Leader>ee

outer top list

<Leader>et

See help file for other default key mappings.

3.2. Results

The evaluation result is echoed on command-line and displayed in a popup at the end of line. However, the displayed result is only the returned value, so for example, the contents output by println are not diplayed.

The contents output to standard output are displayed on the Stdout buffer.

3.3. Marks

vim-iced also provides ways to evaluate forms by Vim’s mark. This feature is implemented by Conjure originally.

Command Default key mapping Description

IcedEvalAtMark

<Leader>ea

Evaluate the outer list (not outer top list) on the specified mark.

Type a key to specify the mark after executing this command.

IcedEvalLastOuterTopList

<Leader>el

Re-evaluate the outer top list which is evaluated last.
Last evaluated list is marked to g:iced#eval#mark_at_last.

For example, when you have a mark m on any position, <Leader>eam will evaluate the outer list on the mark m from any position.

4. Completion

4.1. Omni completion

vim-iced provides only omni completion. It is set to omnifunc for clojure filetype automatically by default.

Vim has a <C-x><C-o> key mapping for omni completion.

Example (📍 means cursor position)
(prin📍)    ;; Type `<C-x><C-o>` to show omni completion

4.2. Auto completion

vim-iced itself does not provide any auto completion methods.

However, the following completion plugins are supported as external plugins.

4.2.1. asyncomplete.vim

asyncomplete.vim is a async completion plugin in pure vim script for Vim8 and Neovim, and vim-iced-asyncomplete is a vim-iced plugin to work with this plugin.

To use vim-iced-asyncomplete, add followings to vim-plug section in your ~/.vimrc (or ~/.config/nvim/init.vim for Neovim)

Plug 'prabirshrestha/asyncomplete.vim'
Plug 'liquidz/vim-iced', {'for': 'clojure'}
Plug 'liquidz/vim-iced-asyncomplete', {'for': 'clojure'}

4.2.2. coc.nvim

coc.nvim is a intellisense engine for Vim8 and Neovim, and vim-iced-coc-source is a vim-iced plugin to work this plugin.

To use vim-iced-coc-source, do following installation steps.

  • Install coc.nvim (here is the installation step)

  • Add followings to vim-plug section in your ~/.vimrc (or ~/.config/nvim/init.vim for Neovim)

Plug 'liquidz/vim-iced', {'for': 'clojure'}
Plug 'liquidz/vim-iced-coc-source', {'for': 'clojure'}
  • Add the following definition to your coc-settings.json

{
    "coc.source.iced.enable": true
}

5. Reference

5.1. Docstring

There are two ways (explicit and implicit) to refer var’s docstring.

The explicit way is executing commands such as follows.

Command Default key mapping Description

IcedDocumentPopupOpen

K

Show docstring for the var under the cursor in popup window

IcedDocumentOpen

Open a Document buffer, and show docstring in it.

The implicit way is a Auto Document feature. This feature enable automatic displaying one-line document at right of cursor line. This will be done by CursorHold and CursorHoldI auto command.

g:iced_enable_auto_document is a configuration to enable auto document feature.

5.2. ClojureDocs

ClojureDocs is a community-powered documentation and examples repository for the Clojure programming language. vim-iced provides the way to refer documents in ClojureDocs like docstring.

Command Default key mapping Description

IcedClojureDocsOpen

<Leader>hc

Open a window, and show documents for the symbol under the cursor.

IcedClojureDocsRefresh

IcedClojureDocsOpen will create a cache file in your local machine.
If you get a outdated result, you can refresh cache file by this command.

5.2.1. ClojureDocs on ClojureScript

ClojureDocs does not have docs for ClojureScript currently.

But if you would like to use Clojure documents instead of ClojureScript, you can use it by enabling g:iced#clojuredocs#use_clj_docs_on_cljs.

5.3. Source codes

IcedSourceShow or IcedSourcePopupShow is useful when you would like to refer the source code itself.

Command Default key mapping Description

IcedSourcePopupShow

<Leader>hs

Show source codes in a popup window.

IcedSourceShow

<Leader>hS

Open a separeted buffer(Document buffer) and show source codes in it.

5.3.1. Enhanced source extraction

If g:iced_enable_enhanced_definition_extraction is true, vim-iced enable enhanced source extraction. This feature is enabled by default.

The difference from normal extraction is to extract source by not only def and defn but also let form.

borkdude/jet is required currently.
vim-iced can download jet automatically if you want.

5.4. Use cases

Sometimes, it is useful to know how a function is used elsewhere. IcedUseCaseOpen command is for that.

IcedUseCaseOpen will open a separated buffer, and show the first usecase if it is found. When there are several usecases, IcedNextUseCase and IcedPrevUseCase commands switch the shown usecase.

5.5. clojure.spec

vim-iced provides following commands to integrate with clojure.spec.

Command Default key mapping Description

IcedBrowseSpec

<Leader>bs

Browse specs, and show spec form in Document buffer.

IcedSpecForm

Open a Document buffer, and show the spec form for specified keyword.
If no arguments are passed, the keyword under the cursor is used.

IcedSpecExample

Open a Document buffer, and show the example of the spec.
If no arguments are passed, the keyword under the cursor is used.

IcedTestSpecCheck

<Leader>ts

See Checking spec for more information

6.1. Jump to definition

vim-iced provides IcedDefJump command for jumping to definition.

If you jumped to a definition with above command, vim-iced add the current cursor position to Vim’s tag stack. So you can go back easily with <C-t>.

6.2. Other navigations

IcedCycleSrcAndTest will cycle source file and test file for current namespace.

For example, when you are in foo.core, IcedCycleSrcAndTest command will open the file which has foo.core-test namespace. If there is no corresponding file, vim-iced suggests pseudo file path to create new namespace.

6.2.2. Cross reference

To browse positions referencing/depending on the form under cursor, following commands are useful.

Command Default key mapping

IcedBrowseReferences

<Leader>br

IcedBrowseVarDependencies

<Leader>bd

Such as foo.handler.home and foo.view.home, there are likely to have related namespaces in web applications.

IcedBrowseRelatedNamespace is useful to jump in these related namespaces.

6.2.4. Test cases

Sometimes you may want to jump to the test code that corresponds to a specific var.

IcedBrowseTestUnderCursor command will search test functions that contains the var name in its test name.

6.2.5. let form

IcedJumpToLet allows you to jump cursor to the nearest let form.

If let form is not found in current top list, cursor is not moved. Default key is mapped to <Leader>jl.

7. Macro

Expanding macro is important for writing/debugging macros. vim-iced provides following two commands.

Command Default key mapping

IcedMacroExpand1OuterList

<Leader>em

IcedMacroExpandOuterList

<Leader>eM

These commands will open a separated buffer, and show expanded result in it. IcedMacroExpand1OuterList will show the result of expanding once, while IcedMacroExpandOuterList will show the all expanded result.

7.1. Expand expanded macro

As you know, IcedMacroExpand1OuterList will show the result of expanding once.

In the separated buffer for expanding macro, you can use IcedMacroExpand1OuterList command and its <Leader>em key mapping again. This means you can expand the expanded macro additionally.

8. Testing

vim-iced can integrate with clojure.test, and provides following test commands.

Command Default key mapping Description

IcedTestAll

<Leader>tp

Run all tests in current project

IcedTestNs

<Leader>tn

Run tests in current namespace

IcedTestUnderCursor

<Leader>tt

Run a test under cursor
See also Related tests

IcedTestRedo

<Leader>tr

Re run failed tests

IcedTestRerunLast

<Leader>tl

Run the last test again

8.1. Test result

When tests are failed, vim-iced show error messages in Test buffer, and IcedTestBufferOpen command open the buffer.

vim-iced also set error positions to quickfix, and :cwindow command enables you to show this information. This is useful to jump each failed tests.

IcedTestUnderCursor is not just running a test under cursor.

If the var under cursor does not contain :test metadata and current namespace doesn’t end with "-test", vim-iced searches test vars in corresponding test namespace (c.f. Source and test) and run them. Target test vars should include original var name in its name.

8.3. Checking spec

There is also checking spec as one of the tests.

IcedTestSpecCheck command is useful to run clojure.spec.test.alpha/check for the function under cursor.

Adding test.check dependency is required.

You can specify the number of tests as a command argument, or g:iced#test#spec_num_tests variable.

9. Formatting

vim-iced’s code formatting is powered by cljfmt. There are following two commands to format codes.

Command Default key mapping Description

IcedFormat

==

Reformat current form.

IcedFormatAll

=G

Reformat current buffer.

vim-sexp also provides formatting codes function. If you want to use vim-iced’s formatting function, you should define g:sexp_mappings as follows.

let g:sexp_mappings = {'sexp_indent': '', 'sexp_indent_top': ''}

9.1. Customize formatter

vim-iced also supports following (GraalVM powered) code formatting tools.

If you change g:iced_formatter option, vim-iced will use the tool to format codes and calculate indent level.

These tools can be downloaded automatically if you want.

10. Debugging

vim-iced supports CIDER’s #dbg and #break reader literals. The easiest way is to put #dbg to your code, and evaluate it.

(defn fib [n]
  #dbg (loop [a 0 b 1 n n]
         (if (<= n 0)
           a
           (recur b (+ a b) (dec n)))))

Once you evaluate (fib 10), debugger will launched something like follows.

debugging screenshot

10.1. Tracing function calls

vim-iced provides 2 commands for tracing function calls.

Command Description

IcedToggleTraceVar

Toggle tracing the specified var in current namespace.
If any symbol is not passed, the symbol under cursor is used.

IcedToggleTraceNs

Toggle tracing the specified namespace.
If any namespace is not passed, the current buffer’s namespace name is used.

Traced result will be displayed in Stdout buffer.

10.2. Browsing tapped values

If you have a big data structure and want to dig into it, browsing tapped values is useful.

When you evaluate (tap> YOUR_DATA), IcedBrowseTapped shows tapped values. Select the value you want to dig into, then browsing value start.

To use tap>, Clojure 1.10.0 or later is required.

All tapped values are stored in memory. So if you would like to delete them, execute IcedClearTapped command.

10.2.1. Browsing keys

For example, when there are following tapped values:

  • 1st tapped value: {:foo [{:dummy "bar"} {:bar "baz"}]}

  • 2nd tapped value: {:hello "world"}

The key to browse "baz" is 0 :foo 1 :bar.

  • The first 0 means "browse 1st tapped value"

  • :foo and :bar means the key for hash-map

  • 1 means the index of list/vector Back to top

11. Refactoring

11.1. Namespace

Following commands are available.

Command Default key mapping Description

IcedCleanNs

<Leader>rcn

Cleanup ns form.

IcedAddNs

<Leader>ran

Add require to ns form.

IcedAddMissing

<Leader>ram

Add missing libspec.

11.1.1. Cache

Namespaces and its aliases are cached for performance. IcedClearNsCache will clear this cache.

11.2. Function

Following commands are available.

Command Default key mapping Description

IcedExtractFunction

<Leader>ref

Extract the form under cursor as a function.

IcedAddArity

<Leader>raa

Add an arity to defn, fn, defmacro, or defmethod.

11.2.1. Examples

IcedExtractFunction (📍 means cursor position, and "bar" is inputed by user)
;; before
(defn foo [x]
  (inc (📍* x 2)))

;; after
(defn- bar [x]
  (* x 2))

(defn foo [x]
  (inc (bar x)))
IcedAddArity (📍 means cursor position)
;; before
(defn foo [x]
  (📍inc x))
;; after
(defn foo
  ([])
  ([x]
   (inc x)))

11.3. Form

Following commands are available.

Command Default key mapping Description

IcedThreadFirst

<Leader>rtf

Convert current outer form to use threading macro.

IcedThreadLast

<Leader>rtl

Convert current outer form to use →> threading macro.

IcedMoveToLet

<Leader>rml

Move the form under cursor to nearest let binding.
If there is no let form in current top list, wrap the form with let.

11.3.1. Examples

IcedThreadFirst
;; before
(foo (bar (baz "hello")))
;; after
(-> "hello" baz bar foo)
IcedThreadLast
;; before
(foo yy (bar xx "hello"))
;; after
(->> "hello" (bar xx) (foo yy))
IcedMoveToLet (📍 means cursor position, and "bar" is inputed by user)
;; before
(let [foo 1]
  (📍inc foo))
;; after
(let [foo 1
      bar (inc foo)]
  bar)

12. Sideloader

base64 command is required to use sideloader.

Sideloader is a new feature from nREPL 0.7, and enables injecting code remotely in a running server on demand.

vim-iced provides following commands for sideloader:

When nREPL requires to look up some codes, vim-iced will search in g:iced#source_root.

It is assumed that sources under g:iced#source_root is managed by tools such as ghq.

vim-iced will use find or fd as a searching file program.

12.1. Starting sideloader

There are following ways to start sideloader:

Sideloader cannot be stopped basically.
If you want, please reconnect(IcedReconnect) or restart REPL

There is IcedToggleSideloaderLookup command as a provisional method.

12.2. Example

First, prepare the following code.

(ns foo.core)

(comment
  (require '[clojure.data.json :as json])
  (json/write-str {:foo "bar"}))

When you evaluate comment form, you will see the following error.

class java.io.FileNotFoundException
Execution error (FileNotFoundException) at foo.core/eval13426 (form-init6273881382280324078.clj:7).
Could not locate clojure/data/json__init.class, clojure/data/json.clj or clojure/data/json.cljc on classpath.

Then, execute IcedStartSideloader command, and you can see Sideloader has started. message is shown.

So let’s evaluate again! You’ll see the expected result such as "{\"foo\":\"bar\"}".

You can also confirm that sideloader works clearly in :message command results.

Provided clojure/data/json.clj as resource to sideloader.
Provided clojure/data/json.clj as resource to sideloader.
Provided clojure/data/json_compat_0_1.clj as resource to sideloader.
Provided clojure/data/json_compat_0_1.clj as resource to sideloader.

13. iced command

vim-iced provides iced command to use vim-iced easily. Main purpose of this command is launching REPL with all features for vim-iced.

13.1. Supports

iced command currently supports following tools.

shadow-cljs is not supported by iced command. To work with shadow-cljs, see vim-iced-shadow-cljs section in help.

13.2. Usage

$ iced repl [options]

13.2.1. Options

Following options are specially treated by iced command.

Option Description

--with-cljs

Enables ClojureScript features.
This option is enabled automatically when project configuration
file(eg. project.clj) contains 'org.clojure/clojurescript' dependency.

--with-kaocha

Enables features for testing with kaocha.

--force-boot

Force to use Boot.

--force-clojure-cli

Force to use Clojure CLI.

--dependency=VALUE

Adds extra dependency.
VALUE format is 'PACKAGE_NAME:VERSION'.
For example: --dependency=iced-nrepl:0.4.3

--middleware=VALUE

Adds extra nrepl middleware.
For example: --middleware=iced.nrepl/wrap-iced

--instant

Launch instant REPL via Clojure CLI.
Instant REPL requires no project/config file.

Other options are passed to each program as below.

13.2.2. Arguments

Leiningen profile
$ iced repl with-profile +foo
Clojure CLI alias
$ iced repl -A:foo
Combinating several options
$ iced repl --with-cljs --force-clojure-cli -A:foo

13.3. Advanced

13.3.1. Clojure CLI project

iced command use clj command for Clojure CLI project by default.

If you would like to use clojure command instead, you can overwrite the command by ICED_REPL_CLOJURE_CLI_CMD environmental variable.

$ ICED_REPL_CLOJURE_CLI_CMD=clojure iced repl

For example, this is useful when you’d like to use rebel-readline in the REPL which is started by iced repl.

14. ClojureScript

vim-iced supports following environments currently.

vim-iced provides following commands for ClojureScript.

Command Description

IcedStartCljsRepl

Start CLJS REPL with specified environment.
REPL session changes to 'cljs.user' namespace.
If no environment is passed, g:iced#cljs#default_env is used.

IcedQuitCljsRepl

Quit CLJS REPL.
REPL session changes to initial namespace.

IcedCycleSession

Cycle clj/cljs session.
Error occurs when CLJS session does not exist.

IcedCljsRepl

Start CLJS REPL via user specified code.
This can be used to start any CLJS REPLs.
The code will be passed to cider.piggieback/cljs-repl.

14.1. Figwheel-main

To start CLJS REPL with Figwheel main, you need to specify build-id.

via IcedCljsRepl command
:IcedCljsRepl (figwheel.main.api/repl-env "build-id")
via IcedStartCljsRepl command
:IcedStartCljsRepl figwheel-main build-id

14.2. GraalJS

ClojureScript 1.10.439 or later is required.

GraalVM is also required, and you must add GraalVM /bin to your PATH. Otherwise you can set PATH temporarily when you execute iced command.

PATH=/path/to/graalvm/bin:$PATH iced repl

Once you launch REPL with GraalJS, you can start CLJS REPL with the following command.

via IcedStartCljsRepl command
:IcedStartCljsRepl graaljs

14.3. shadow-cljs

iced command does not support shadow-cljs currently.
So you need to launch REPL manually.

To start CLJS REPL with shadow-cljs, you need 3 steps.

  1. Add definitions to shadow-cljs.edn

  2. Start to watch

    • $ shadow-cljs watch {YOUR-BUILD-ID}

  3. Connect and start cljs-repl

    • Execute IcedConnect command to connect to REPL

    • Execute IcedStartCljsRepl command like follows

      • :IcedStartCljsRepl shadow-cljs {YOUR-BUILD-ID}

If you would like to start CLJS REPL by hand, you can do it as follows.

:IcedEvalRepl (shadow.cljs.devtools.api/repl :YOUR-BUILD-ID)

14.3.1. shadow-cljs.edn

You need to modify :dependencies and :nrepl setting in shadow-cljs.edn as below.

shadow-cljs.edn
{
 :dependencies [[refactor-nrepl "2.5.0"]
                [cider/cider-nrepl "0.24.0"]
                [iced-nrepl "1.0.1"]]

 :nrepl {:cider false
         :middleware [cider.nrepl/wrap-classpath
                      cider.nrepl/wrap-clojuredocs
                      cider.nrepl/wrap-complete
                      cider.nrepl/wrap-debug
                      cider.nrepl/wrap-format
                      cider.nrepl/wrap-info
                      cider.nrepl/wrap-macroexpand
                      cider.nrepl/wrap-ns
                      cider.nrepl/wrap-out
                      cider.nrepl/wrap-spec
                      cider.nrepl/wrap-test
                      cider.nrepl/wrap-trace
                      cider.nrepl/wrap-undef
                      cider.nrepl/wrap-xref
                      refactor-nrepl.middleware/wrap-refactor
                      iced.nrepl/wrap-iced]}
}

15. Skeleton

vim-iced provides code skeleton when you open new clojure files. Concretely "when you open new" means the time when BufNewFile autocmd is fired.

Currently, following extensions are supported.

  • *.clj

  • *.cljs

  • *.cljc

15.1. Source file

For example, the skeleton when you open src/foo/bar.clj is as follows.

(ns foo.bar)

15.2. Test file

A skeleton for test file depends on the file extension.

15.2.1. *.clj

For example, the skeleton when you open test/foo/bar_test.clj is as follows.

(ns foo.bar-test
  (:require [clojure.test :as t]
            [foo.bar :as sut]))

15.2.2. *.cljs

For example, the skeleton when you open test/foo/bar_test.cljs is as follows.

(ns foo.bar-test
  (:require [cljs.test :as t :include-macros true]
            [foo.bar :as sut]))

15.2.3. *.cljc

For example, the skeleton when you open test/foo/bar_test.cljc is as follows.

(ns foo.bar-test
  (:require #?@(:clj  [[clojure.test :as t]
                       [foo.bar :as sut]]
                :cljs [[cljs.test :as t :include-macros true]
                       [foo.bar :as sut]])))

16. Operator

vim-iced provides following operators.

Operator Description

<Plug>(iced_eval)

Evaluate codes

<Plug>(iced_eval_and_print)

Evaluate code and print result to stdout buffer

<Plug>(iced_eval_and_tap)

Evaluate code and tap result by clojure.core/tap>

<Plug>(iced_eval_and_replace)

Evaluate code and replace it by the evaluation result

It is useful to combinate these operators with vim-sexp's motions like follows. (Change the mapping key as you like)

Example
aug MyClojureSetting
  au!
  au FileType clojure nmap <buffer> <Leader>epe
      \ <Plug>(iced_eval_and_print)<Plug>(sexp_outer_list)``
  au FileType clojure nmap <buffer> <Leader>ept
      \ <Plug>(iced_eval_and_print)<Plug>(sexp_outer_top_list)``

  au FileType clojure nmap <buffer> <Leader>eae
      \ <Plug>(iced_eval_and_tap)<Plug>(sexp_outer_list)``
  au FileType clojure nmap <buffer> <Leader>eat
      \ <Plug>(iced_eval_and_tap)<Plug>(sexp_outer_top_list)``

  au FileType clojure nmap <buffer> <Leader>ere
      \ <Plug>(iced_eval_and_replace)<Plug>(sexp_outer_list)``
  au FileType clojure nmap <buffer> <Leader>ert
      \ <Plug>(iced_eval_and_replace)<Plug>(sexp_outer_top_list)``
aug END

17. Editing S-expression

vim-iced is depending on vim-sexp, and most features for editing S-expression are provided by vim-sexp.

In vim-iced, only the following functionalities which is extended from vim-sexp are provided.

Command Description

IcedSlurp

Slurp the next element.
If no elements in current form, search next form and slurp.
For searching next form, g:iced#paredit#slurp_max_depth is used.

IcedBarf

Barf the last element in current form.

These commands are so useful when combined with vim-submode.
See Tips for more information.

18. Docker

When you are connecting to nREPL in docker container, various paths will be paths in the docker container.

Because some features such as jumping to definition does not work properly as it is, vim-iced provides g:iced#nrepl#path_translation option to translate these paths.

See Docker in Configuration section.

18.1. Example

At first, build a simple docker image for vim-iced.

Minimum dockerfile for vim-iced
FROM clojure:openjdk-14-lein-alpine
RUN apk add --no-cache --virtual .builddeps git && \
    git clone --depth 1 --single-branch https://github.com/liquidz/vim-iced /usr/local/src/vim-iced && \
    apk del .builddeps
ENV PATH $PATH:/usr/local/src/vim-iced/bin
ENTRYPOINT ["iced", "repl"]
$ docker build -t vim-iced .

Second, launch nREPL with a fixed port number.

project.clj
(defproject foo "0.1.0-SNAPSHOT"
  ;; ...

  ;; Change port number as you like
  :repl-options {:host "0.0.0.0" :port 55555}

  ;; ...
  )
$ docker run --rm -it --expose 55555 -p 55555:55555 -v $(pwd):/tmp vim-iced

Finally just connect with IcedConnect as usual.

19. Command palette

It is hard to remember all commands by vim-iced since there are many commands.

But most commands can be filtered/selected from the command palette even if you don’t remember them.

Command Default key mapping Description

IcedCommandPalette

<Leader>hh

Select a command from the palette.

If you’d like to customize the command palette(e.g. adding new command), g:iced#palette option is useful.

See Command palette in Configuration section for more information.

20. Buffer

20.1. Stdout buffer

Standard outputs will be outputted to dedicated buffer.

vim-iced provides following commands to control stdout buffer.

Command Default key mapping Description

IcedStdoutBufferOpen

<Leader>ss

Open stdout buffer.

IcedStdoutBufferClear

<Leader>sl

Clear all lines in stdout buffer.

IcedStdoutBufferClose

<Leader>sq

Close stdout buffer window.

20.2. Test buffer

Test results will be outputted to dedicated buffer.

vim-iced provides following commands to control test buffer.

Command Default key mapping Description

IcedTestBufferOpen

<Leader>to

Open test result buffer.

Test buffer is opened automatically when tests are failed. On the other hand, test buffer is closed automatically when test are succeeded.

So you don’t need to use the above command basically.

20.3. Document buffer

Documents will be shown to popup window by default. But you can show them to dedicated buffer to keep them displayed.

vim-iced provides following commands to control document buffer.

Command Default key mapping Description

IcedDocumentOpen

<Leader>hb

Open a window, and show documents for specified symbol.
If symbol is not passed, the symbol under the cursor is used.

IcedDocumentClose

<Leader>hq

Close document window.

21. Configuration

21.1. Evaluation

21.1.1. Eval inside comment

comment form is useful for checking behavior. You can use evaluating outer list range to evaluate codes inside comment form, but it is bored that some cursor movements are required.

g:iced#eval#inside_comment is a configuration that allow you to evaluate inside comment form with evaluating outer top list range, and it is enabled by default.

Example (📍 means cursor position)
(comment📍      ;; Execute `:IcedEvalOuterTopList`
  (+ 1 2 3))    ;; => 6

21.2. Formatting

21.2.1. Customizing indent rules

g:iced#format#rule is a configuration that allow you to define indentation rules for cljfmt.

For example, merr's let has a form like follows.

(merr/let +err+ [foo 1]
          (inc foo))

To format like clojure.core/let, you should define the following rule.

let g:iced#format#rule = {
      \ 'merr.core/let': '[[:block 2] [:inner 1]]',
      \ }

Then you can get the following result.

(merr/let +err+ [foo 1]
  (inc foo))

See cljfmt’s README for more information.

21.3. Hook

Some events on vim-iced can be hooked, and you can execute any processing.

21.3.1. Event

Following events can be hooked.

Event key Event parameters Description

connected

-

Hooked when vim-iced is connected to nREPL.

disconnected

-

Hooked when vim-iced is disconnected from nREPL.

test_finished

result: Test result ("succeeded" or "failed")
summary: Test summary string

Hooked when running test is finished.

ns_required

-

Hooked when :IcedRequire is finished.

ns_all_reloaded

-

Hooked when :IcedRequireAll is finished.

session_switched

session: Destination session type. "clj" or "cljs".

Hooked when current session is switched.

21.3.2. Reporter

Hooked events and event parameters are reported to reporters. You can define some kind of reporters as follows.

Reporter key Description

shell

Process a event by a shell command.
The shell command is executed in terminal.

eval

Process a event by IcedEval command.

function

Process a event by a user-defined function.

command

Process a event by a vim command.

21.3.3. Example

Here is a example to setting up hooks.

let g:iced#hook = {
    \ 'connected': {'type': 'function',
    \               'exec': {_ -> iced#message#info_str('foo')}},
    \ 'disconnected': {'type': 'command',
    \                  'exec': 'echom "bar"'},
    \ 'ns_required': {'type': 'eval',
    \                 'exec': '(println "baz")'},
    \ 'test_finished': {'type': 'shell',
    \                   'exec': {v -> printf('tmux display-message "%s"', v.summary)}}
    \ }

21.4. Docker

g:iced#nrepl#path_translation is a option to define path translation rules.

In actual use, it is recommended to define the option in the project-specific configuration file by vim-localrc like follows.

/path/to/your/project/root/.local.vimrc
let g:iced#nrepl#path_translation = {
      \ '/tmp': expand('<sfile>:p:h'),
      \ '/root': $HOME,
      \ }

21.5. Command palette

The g:iced#palette option allows you to customize the command palette.

In actual use, it is recommended to define the option in the project-specific configuration file by vim-localrc like follows.

/path/to/your/project/root/.local.vimrc
let g:iced#palette = {
      \ 'foo bar': ':IcedEval (+ 1 2 3 4 5)',
      \ }

21.6. Advanced settings

21.6.1. Stdout buffer

Option Default value Description

g:iced#buffer#stdout#mods

''

Buffer position definition.
Following values are supported.

  • vertical

  • leftabove

  • aboveleft

  • rightbelow

  • belowright

  • topleft

  • botright

g:iced#buffer#stdout#file

''

If not empty, vim-iced write stdout buffer content to the file path.

g:iced#buffer#stdout#file_buffer_size

256

Max line count to buffer for g:iced#buffer#stdout#filer.

g:iced#buffer#stdout#max_line

-1

Max line count to keep in stdout buffer.
If negative number is setted, it means no limit.

g:iced#buffer#stdout#deleting_line_delay

1000

Delay time for deleting excess lines in stdout buffer.
Unit is milli sec.
This option is enabled when g:iced#buffer#stdout#max_line is a positive number.

21.6.2. Document

Table 2. Document buffer
Option Default value Description

g:iced#buffer#document#height

'previewheight'

Document window height.

g:iced#buffer#document#does_update_automatically

v:false

If v:true and document buffer is visible, update document buffer with document for the form under cursor.

Table 3. Auto document
Option Default value Description

g:iced_enable_auto_document

'none'

Enable automatic displaying one-line document.
This will be done by CursorHold and CursorHoldI auto command.

The value should be one of 'normal', 'insert' or 'any'.
Otherwise, this option will be disabled.

  • 'normal': Enabled on only normal mode.

  • 'insert': Enabled on only insert mode.

  • 'every' : Enabled on normal and insert mode.

g:iced_enable_popup_document

'every'

Display documents on popup window.
The value should be one of follows.
Otherwise, this option will be disabled.

  • 'full' : Enabled on only full document. IcedDocumentOpen shows full document.

  • 'one-line': Enabled on only one-line document.

  • 'every' : Every enabled.

g:iced_max_distance_for_auto_document

2

Max line distance to display one-line document.
See also

21.6.3. ClojureScript

Option Default value Description

g:iced#nrepl#auto#does_switch_session

v:false

If v:true, enable automatic switching CLJ/CLJS session.
This will be done by WinEnter auto command.

g:iced_enable_enhanced_cljs_completion

v:true

If v:true, enable enhanced ClojureScript completion.

22. Tips

22.1. vim-submode

vim-submode is a Vim plugin to provide the way to define "submodes" to the built-in vim-modes.

vim-submode is useful to repeat some commands such as IcedSlurp or IcedBarf.

Repeat slurping and barfing
" Change key mappings as you like.
" In this case, type `<LocalLeader>kssss` to repeat slurping.
call submode#enter_with('slurp', 'n', '', '<LocalLeader>ks', ':<C-u>IcedSlurp<CR>')
call submode#enter_with('slurp', 'n', '', '<LocalLeader>kb', ':<C-u>IcedBarf<CR>')
call submode#leave_with('slurp', 'n', '', '<Esc>')
call submode#map('slurp', 'n', '', 's', ':<C-u>IcedSlurp<CR>')
call submode#map('slurp', 'n', '', 'b', ':<C-u>IcedBarf<CR>')
Repeat jumping errors
" Change key mappings as you like.
" In this case, type `<LocalLeader>nnnn` to repeat jumping next errors.
call submode#enter_with('sign_jump', 'n', '', '<LocalLeader>n', ':<C-u>IcedJumpToNextError<CR>')
call submode#enter_with('sign_jump', 'n', '', '<LocalLeader>N', ':<C-u>IcedJumpToPrevError<CR>')
call submode#leave_with('sign_jump', 'n', '', '<Esc>')
call submode#map('sign_jump', 'n', '', 'n', ':<C-u>IcedJumpToNextSign<CR>')
call submode#map('sign_jump', 'n', '', 'N', ':<C-u>IcedJumpToPrevSign<CR>')

22.2. Auto connection

If you’d like to connect to REPL automatically, define autocmd for VimEnter event.

It is recommended to define autocmd like follows in ftplugin directory.

Example: $HOME/.vim/ftplugin/clojure.vim
aug MyClojureSetting
  au!
  au VimEnter * IcedConnect
aug END

If you don’t want to connect to REPL for project.clj, *.edn, or etc, skip connecting as below.

Example: $HOME/.vim/ftplugin/clojure.vim
function! s:auto_connect() abort
  if expand('%:t') ==# 'project.clj' || expand('%:e') ==# 'edn'
    return
  endif
  IcedConnect
endfunction

aug MyClojureSetting
  au!
  au VimEnter * call s:auto_connect()
aug END

22.3. Overwriting mappings

vim-iced provides default key mappings. Since vim-iced will verify the mapping existence, if you would like to overwrite some key mappings, you could do as follows.

Example: $HOME/.vim/ftplugin/clojure.vim
nmap <Leader>em <Plug>(iced_eval_at_mark) (1)
nmap <Leader>eM <Plug>(iced_macroexpand_1_outer_list) (2)
nmap <Nop>(iced_macroexpand_outer_list) <Plug>(iced_macroexpand_outer_list) (3)
1 Use <Leader>em for iced_eval_at_mark instead of <Leader>ea.
2 Use <Leader>eM for iced_macroexpand_1_outer_list instead of <Leader>em.
3 Disable default mapping <Leader>eM for iced_macroexpand_outer_list.

22.4. Reloaded workflows

If you are managing lifecycle of components with Stuart Sierra’s component, integrant or etc, key mappings like follows are useful.

aug MyClojureSetting
  au!
  " Change key mappings and forms as you like
  au FileType clojure nnoremap <buffer> <Leader>go :<C-u>IcedEval (user/go)<CR>
  au FileType clojure nnoremap <buffer> <Leader>Go :<C-u>IcedEval (user/reset)<CR>
aug END

23. External integration

23.1. kaocha

kaocha is full featured next gen Clojure test runner.

vim-iced has a external plugin named vim-iced-kaocha to integrate with kaocha.

Command Description

:IcedKaochaTest

Run tests specified by {ids}.
{ids} must be an array of testable-id.
See kaocha document for testable-id.

:IcedKaochaTestUnderCursor

Run a test under cursor.

:IcedKaochaTestNs

Run tests in current namespace.

:IcedKaochaTestAll

Run all tests in current project.

:IcedKaochaTestRedo

Re run failed tests.

:IcedKaochaTestRerunLast

Run last test again.

23.1.1. Usage

First, add vim-iced-kaocha to your vim-plug section.

call plug#begin('~/.vim/plugged')

Plug 'liquidz/vim-iced', {'for': 'clojure'}
" Add this line >>>>>>>>>>>>>>
Plug 'liquidz/vim-iced-kaocha'
" <<<<<<<<<<<<<<<<<<<<<<<<<<<<

call plug#end()

Next, launch your REPL with --with-kaocha option.

$ iced repl --with-kaocha
Key mapping example
aug MyClojureSetting
  au!
  " Change key mappings as you like.
  au FileType clojure nmap <silent><buffer> <Leader>ktt <Plug>(iced_kaocha_test_under_cursor)
  au FileType clojure nmap <silent><buffer> <Leader>ktn <Plug>(iced_kaocha_test_ns)
  au FileType clojure nmap <silent><buffer> <Leader>ktr <Plug>(iced_kaocha_test_redo)
  au FileType clojure nmap <silent><buffer> <Leader>ktl <Plug>(iced_kaocha_test_rerun_last)
aug END

24. Socket REPL

vim-iced targets nREPL mainly, but now will also support minimal operations on socket REPL.

Table 4. Socket REPL supports
Feature Supports? Description

All ranges to evaluation are supported.

Only referring docstrings.

Etc…​

Any other features are not supported.

vim-iced provides following commands to connect socket REPL.

Command Description

IcedConnectSocketRepl

Make connection to socket REPL.

IcedConnectPrepl

Make connection to pREPL.
This connection is based on socket repl connection.

24.1. Connecting socket REPL

You can try socket REPL connection as follows.

Table 5. Launch socket REPL via babashka
Tool Command

$ bb --socket-repl 5555

$ joker --repl :5555

$ planck --socket-repl 5555

$ lumo --socket-repl 5555

Connect to socket REPL
:IcedConnectSocketRepl 5555

Another way, you can launch socket REPL with random empty port internally.

:IcedInstantConnect babashka

If you’d like to use nREPL server instead of Socket REPL, you use g:iced#repl#babashka_repl_type option.

24.2. Connecting pREPL

pREPL connection is based on socket REPL connection in vim-iced.

borkdude/jet is required currently.
vim-iced can download jet automatically if you want.

You can try pREPL connection as follows.

Launch pREPL
$ clj -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/io-prepl}"
Connect to pREPL
:IcedConnectPrepl 5555

25. Developer

25.1. Minimal configuration

Minimal configuration is useful for debugging. If you find an unexpected behavior, please try this configuration.

Setup
$ mkdir -p /tmp/vim-iced-test/pack/iced/start
$ git clone https://github.com/guns/vim-sexp \
    /tmp/vim-iced-test/pack/iced/start/vim-sexp
$ git clone https://github.com/liquidz/vim-iced \
    /tmp/vim-iced-test/pack/iced/start/vim-iced
test_config.vim
set nocompatible
set encoding=utf-8
scriptencoding utf-8
filetype plugin indent on

set runtimepath-=$HOME/.vim
set runtimepath-=$HOME/.vim/after
set runtimepath-=$HOME/.config/nvim
set runtimepath-=$HOME/.config/nvim/after
set runtimepath-=$HOME/.local/share/nvim/site
set runtimepath-=$HOME/.local/share/nvim/site/after

set packpath=/tmp/vim-iced-test
Lanuch Vim/Neovim
# Vim
$ vim -u /path/to/test_config.vim /path/to/your/project/code.clj

# Neovim
$ nvim -u /path/to/test_config.vim /path/to/your/project/code.clj

25.2. Testing vim-iced

vim-iced uses vim-themis as a test runner.

25.2.1. Run tests on docker

The easiest way to run tests is the way using docker.

# Run vimscript test for vim
$ make docker_themis

# Run vimscript test for neovim
$ make docker_neovim_themis

If you would like to filter test cases, use --target option for vim-themis. Please refer to the argument of themis#suite in the first line of each test for the string to be specified for --target.

For example, execute the following command to run test cases only for iced#nrepl#eval.

$ docker run --rm -v $(pwd):/root \
      --entrypoint './.vim-themis/bin/themis' uochan/vim:latest \
      --target 'iced\.nrepl\.eval '

25.2.2. Run tests locally

You can also run tests locally. The following make rule will clone vim-themis and run tests.

# Run vimscript test
$ make themis

# Run all tests
$ make test

# Once you clone vim-themis, you can specify `--target` like below
$ ./.vim-themis/bin/themis \
      --target 'iced\.nrepl\.eval '

26. Cheatsheet

Based on default key mappings.
See help file for whole default key mappings.

Connection

<Leader>'

Make connection to nREPL

==

Reformat the form under cursor

<Leader>ee

Evaluate outer list

<Leader>et

Evaluate outer top list

<Leader>eb

Require current namespace

<Leader>eq

Interrupt code evaluation

<Leader>em

Evaluate macroexpand-1 for outer list

<Leader>eM

Evaluate macroexpand for outer list

<Leader>tt

Run test under cursor

<Leader>tn

Run tests in current namespace

<Leader>tr

Re run failed tests

<Leader>tl

Re run last test

<Leader>tp

Run all tests

<C-]>

Jump cursor to the definition of symbol under cursor

<C-t>

Jump back cursor

<Leader>bn

Browse namespaces related to the current namespace

K

Show documents for the symbol under cursor

<Leader>hs

Show source for the symbol under cursor

<Leader>hq

Close document buffer

<Leader>bs

Browse specs

<Leader>rcn

Clean namespace

<Leader>ran

Add ns to require form

<Leader>ram

Add missing libspec

<Leader>ref

Extract the form under cursor as a function

<Leader>raa

Add another arity

<Leader>rtf

Convert form to use -> threading macro.

<Leader>rtl

Convert form to use ->> threading macro

<Leader>rml

Move the form under cursor to nearest let binding

Others

<Leader>hh

Show command palette