diff --git a/CHANGELOG.md b/CHANGELOG.md index 712a766..f125544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## main (unreleased) +## 0.5.0 (2026-11-05) + +CIDER in a terminal. + ### Features - [#45](https://github.com/nrepl/neorepl/pull/45): The REPL shows the delimiter that pairs with the one at the cursor, and a closer that pairs with nothing, or with the wrong kind, in red, rather than JLine moving the cursor to the opener for half a second. diff --git a/PLAN.md b/PLAN.md index 8b587b7..2346063 100644 --- a/PLAN.md +++ b/PLAN.md @@ -327,7 +327,6 @@ Upstream, alongside 0.4. The 0.1 announcement promised the first three. - Cross-references: `neorepl refs`, `,refs` and an MCP tool, on cider-nrepl's `fn-refs` and `fn-deps`. Done (2026-11-01, cider-nrepl 0.64.0): `neorepl refs SYM`, with `--deps` for what SYM uses, `,refs` and `,deps` in the REPL, and the MCP tool `refs` with `deps`. Both ops take the `:ns` to resolve `:sym` in, and answer with the functions' `:name`, `:file`, classpath-relative, `:file-url`, `:line` and `:column`; a var that isn't there gets `done` and nothing, the same as one nothing uses, so when there's nothing, neorepl asks `info` whether the var's there before saying nothing uses it, since an agent would take that for safe to change. They only see the project's code that's loaded, tests included, as orchard looks through the constants of the functions in the project's namespaces, the ones whose files aren't in jars, so not one defined at the REPL in a namespace without a file (orchard 0.48.0's `fn-refs`, checked 2026-11-04). bb's server has neither. - The namespace browser, full-screen on `neorepl.browser` like the inspector, which `,ns` without a name could open instead of printing the list. `features/namespaces` gives it the names and `features/enter-ns` the switch, and it can hand the namespace picked back through the `:ns` a command's output carries. It'll want every loaded namespace too, not only the project's, which `features/namespaces` needs an option for. Done (2026-11-03, cider-nrepl 0.64.0 and bb 1.13.229): `,ns` without a name opens it on a terminal, and prints the project's namespaces elsewhere. It starts at the project's, the namespace the REPL's in selected, `a` switches to every loaded one, but the nREPL tooling's own, which CIDER leaves out too, and `/` filters by name as it's typed. Enter switches to the namespace, → shows its public vars with the first line of each one's doc, from cider-nrepl's `ns-vars-with-meta`, or from `ns-publics` without it, as on bb, which has no such op, → again a var's whole doc, and `e` opens a namespace or var in `$EDITOR`, as `,edit` does. - A spec browser, as CIDER's `cider-browse-spec`: the specs in the registry, filtered as the name's typed, a spec's form with the specs it names to go to, and examples generated from it. Done (2026-11-03, cider-nrepl 0.64.0 and bb 1.13.229): `,spec`, or `,spec NAME` for a spec's form, or the specs with NAME in theirs. The list comes from cider-nrepl's `spec-list`, or from `s/registry` without it, and examples from its `spec-example`, or `clojure.spec.gen.alpha` without it, which both take test.check on the server; babashka has it, and spec. The form is evaluated, `s/form` pretty printed, as `spec-form` sends it as bencode lists, which can't tell a vector from a list, with `s/` for clojure.spec.alpha and clojure.core left out, as CIDER shows it. Specs it names, from the lexer's keywords and symbols that are in the list, are values to move to, each occurrence of its own, and → or Enter goes to one, ← back. Without a terminal, `,spec NAME` prints the form, and `,spec` the names. -- Left over from 0.2: the frames of ClojureScript errors, from the JS stack. - From clojure-cli.repl: evaluating the form at the cursor, and the last evaluation's outcome and time in the prompt. Done (2026-11-04, checked on bb 1.13.227 and 1.13.229 and JLine 4.4.7): C-x Enter, which JLine leaves unbound, with C-x C-e taken by `$EDITOR` as in bash, evaluates `lexer/form-at`: the innermost list, vector, map or set the cursor's in or right after, as clojure-cli.repl takes, or failing that, the symbol or literal there, with its prefixes, like `'` and `#?`, the cursor on them too, but not its metadata, nor `~`, `~@` and `#?@`, which only work inside another form. JLine's cursor counts code points, the lexer chars. Rather than print the value above the prompt, as clojure-cli.repl does, it puts only the form in the input and accepts it with history off, so it goes through the REPL loop like anything typed, with output, errors, `*in*`, Ctrl-C and autoreload, and the transcript says what gave the value. The next read starts with the input as it was, through `readLine`'s buffer, and the cursor where it was, through JLine's `callback-init` widget. History goes back to what it was after, so an inputrc's `set disable-history on` holds. The outcome and time go at the right of the input's first line, as zsh's `RPROMPT` with `TRANSIENT_RPROMPT`, so `ns=> ` stays as comint modes match it: a check mark or a cross, and the wall-clock time from Enter to the result, autoreload and waiting for `*in*` included, until a command runs, under the `outcome` setting. The highlighter draws it while the line's read and leaves it out of the last redisplay, since JLine's own right prompt stays in the scrollback, next to the next input, and bb reaches neither `setRightPrompt` nor the field to clear it. clojure-cli.repl's example prompt takes its time from middleware on the server, which neorepl can't count on. - What the line editor was meant to have from the start: indenting continuation lines, a way to pick the vi keymap, which JLine has but nothing selects, the candidates' namespaces in the completion menu, and paren matching. All done by 2026-11-01. Enter in an unfinished form starts a line indented for it, from `lexer/indentation`, the way cljfmt's defaults would: a body by two, for the heads cljfmt lists and anything starting with def, other lists' arguments lined up with the first one on the head's line, or else with the head, and the elements of vectors, maps and sets with the first. Nothing in a string, where the spaces would be part of it. It's a widget in place of JLine's `accept-line`, since JLine's own indenting goes by its `indentation` variable, so many spaces for each open bracket, and with that set, typing a closer deletes as many spaces before it, in strings too. A paste comes in whole, through bracketed paste, so it keeps its own indentation. Done: the vi keymap, and the rest of readline's settings JLine knows, from readline's inputrc, `$INPUTRC` or `~/.inputrc`, which JLine reads when the reader's made, `$if neorepl` holding what's for neorepl alone (2026-11-01, JLine 4.4.7, bb 1.13.226 and 1.13.229). JLine skips a line it can't make sense of without a word, and takes `set blink-matching-paren on`, which a bash user's inputrc might have, for 0, so its jump to the opener stays off. Done too: paren matching. JLine's moved the cursor to the opener for half a second after a closer was typed, counting brackets as it went, so one in a string, a comment or a `\(` threw it off. That's off, and the highlighter shows the delimiter that pairs with the closer before the cursor, or with the opener under it, reversed, from `lexer/delimiter-match`, which goes by the lexer's tokens. A closer that pairs with nothing, or with the wrong kind, shows red, and an opener that isn't closed doesn't, since that's only unfinished. JLine's last redraw of the line comes once it's done reading, after Enter or Ctrl-C, and goes without the pair, which would otherwise stay in the scrollback. The REPL tests leave colors out unless they ask for them, since that redraw puts the opener on the terminal again. The symbols it shows as special forms take in the ones macros expand into, `let*` and friends, and the defining, binding and threading macros, `deftest`, `->`, `doto`, `with-open`, `reify` and `extend-protocol` among them, but not the project's own macros, which would take asking the server. Done too: the candidates' namespaces, next to their types, as `(function, clojure.core)`, for candidates that don't name it already, as `str/join` does, the way CIDER annotates them. Only vars come with one from cider-nrepl 0.64.0: classes, namespaces, keywords and members have a type alone. - REPL commands highlighted as they're typed. Done: a command's comma and name in bold blue, as special forms are, and a name that's no command's, nor the start of one, which it is while it's typed, in red, like a closer that pairs with nothing. @@ -343,6 +342,7 @@ Upstream, alongside 0.4. The 0.1 announcement promised the first three. - Settings, and keys that toggle them, as rebel-readline's `:repl/toggle-*` commands do: a config file, `$XDG_CONFIG_HOME/neorepl/config.edn`, with what they start as, `,set` to list them and change them, and widgets the inputrc can bind. Done (2026-11-03): `eldoc`, `color`, `quiet`, `server-output`, `taps` and `autoreload`, each on or off, in one atom the line editor and the REPL loop read as they go. C-x C-h toggles eldoc and C-x C-q quiet, and every setting but autoreload, whose turning on reloads, has a `neorepl-toggle-` widget. The file's mistakes are warnings, and `NO_COLOR` wins over it. Turning `server-output` off only leaves out what comes, since nREPL can't stop forwarding ([nrepl#513](https://github.com/nrepl/nrepl/issues/513)), and the REPL asks for it only once it's on. Then (2026-11-04) `pretty`, on C-x C-p, and `print-length` and `print-level`, a number or off, which go to nREPL's printers as their options, `nrepl.util.print/pprint`'s or `pr`'s; off leaves the session's own vars. Still to come: a theme for the colors. 0.6, distribution and Windows +- Left over from 0.2, through 0.5: the frames of ClojureScript errors, from the JS stack. - Clojars, as `org.nrepl/neorepl`, which in-process mode and installing it as a Clojure tool need. An uberjar with `Enable-Native-Access: ALL-UNNAMED` in its manifest, and Homebrew. Native-image only if bb turns out not to be enough. - Windows: CIDER's quoting lessons in jack-in, and keeping Ctrl-C away from a server neorepl starts, which `sh -c 'trap "" INT; exec "$@"'` does elsewhere. - The docs site. diff --git a/src/neorepl/main.clj b/src/neorepl/main.clj index b7158c3..92a9eb8 100644 --- a/src/neorepl/main.clj +++ b/src/neorepl/main.clj @@ -26,7 +26,7 @@ (def version "neorepl's version, which every release bumps." - "0.5.0-snapshot") + "0.6.0-snapshot") (defn- warn [msg] (binding [*out* *err*]