Giter VIP home page Giter VIP logo

nrepl's Introduction

nREPL Logo


CircleCI Spell-check Status Clojars Project cljdoc badge downloads badge Backers on Open Collective Sponsors on Open Collective Discord

nREPL is a Clojure network REPL that provides a REPL server and client, along with some common APIs of use to IDEs and other tools that may need to evaluate Clojure code in remote environments.

nREPL powers many well-known development tools.

Usage

  • Start an nREPL server (e.g. with lein repl)
  • Connect to the server using any nREPL client (e.g. CIDER, Calva, vim-fireplace)
  • Start hacking!

See the documentation for way information on the subject.

API Documentation

You can find nREPL's API documentation on cljdoc.

Status

Extremely stable. nREPL's protocol and API are rock-solid and battle tested. nREPL's team pledges to evolve them only in backwards-compatible ways.

That being said, there were a few organizational changes related to the transition out of clojure-contrib that everyone has to keep in mind:

  • [nrepl "0.3.1"] is a drop-in replacement for [org.clojure/tools.nrepl "0.2.13"] (notice the different artifact coordinates).
  • [nrepl "0.4.0"] changes the namespaces from clojure.tools.nrepl.* to nrepl.*.

Future releases will focus on supporting the needs of the essential tools of the Clojure(Script) ecosystem (e.g. Leiningen, CIDER, Cursive).

FAQ

How is this different from the "contrib" tools.nrepl project?

Check the brief history of nREPL, available here.

How does nREPL compare to other REPL servers (e.g. prepl)?

Check out this detailed comparison.

Does nREPL support ClojureScript?

Yes and no. The reference nREPL implementation is Clojure-specific, but it can be extended with ClojureScript support via the Piggieback middleware. In the future there may be implementations of nREPL that target ClojureScript directly.

Does nREPL support other programming languages besides Clojure?

The nREPL protocol is language-agnostic and implementations of nREPL servers exist for several programming languages. Implementing new nREPL servers is pretty simple.

Testing and Hacking around

See Hacking on nREPL.

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! πŸ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

License

Copyright Β© 2010-2023 Chas Emerick, Bozhidar Batsov and contributors.

Licensed under the EPL. (See the file epl.html.)

nrepl's People

Contributors

alexander-yakushev avatar bbatsov avatar cemerick avatar cgrand avatar chancerussell avatar cichli avatar dotemacs avatar ericdallo avatar gfredericks avatar ikappaki avatar ivarref avatar kotarak avatar mallt avatar martinklepsch avatar nicolas-graves avatar p4v4n avatar pfeodrippe avatar plexus avatar rlbdv avatar seancorfield avatar severeoverfl0w avatar shen-tian avatar slipset avatar solar05 avatar sudorock avatar technomancy avatar th994 avatar tonsky avatar trptcolin avatar vemv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nrepl's Issues

Make it possible to specify the transport used by the server via the CLI

It'd be really nice if it was possible to start a server via the CLI using different transport, as right now bencode is hardcoded there. I guess we can simply add a --transport flag for this which can be the transport to use (a var that we can require and resolve perhaps). Maybe we can add some special handling for built-in transports, so those are easier to use. Here's some example usage:

nrepl --transport tty

nrepl --transport nrepl.transport/tty

(replace nrepl in your minds with the long clj invocation that's really needed for this)

That might become even more important if we end up having more useful transports like #60 and #61.

*print-namespace-maps* is always true

Expected behavior, actual behavior and steps to reproduce the problem

Evaluating a map with namespaced keys like
{:person/name "Fred" :person/age 50}
in the cider repl prints the following return value
#:person{:name "Fred", :age 50}
This is due to *print-namespace-maps* defaulting to true.
Normally, it should be possible to change the value of this var permanently with set! thusly:

user> (set! *print-namespace-maps* false)
false
user> *print-namespace-maps*
false

However, the actual behavior is thus:

user> (set! *print-namespace-maps* false)
false
user> *print-namespace-maps*
true

Similarly, it should be possible to temporarily change the var with binding:

user> (binding [*print-namespace-maps* false]
        [*print-namespace-maps* {:person/name "Fred" :person/age 50}])
[false {:person/name "Fred" :person/age 50}]

But, although the var seems to change, the desired behavior remains to be seen;

user> (binding [*print-namespace-maps* false]
        [*print-namespace-maps* {:person/name "Fred" :person/age 50}])
[false #:person{:name "Fred", :age 50}]

I first posted this problem as an issue at the CIDER repo: clojure-emacs/cider#2280
@bbatsov pointed out that it must be a problem in nrepl, so I reposted the issue here and closed the original issue.
Some of the discussion in the thread underneath the original issue might prove useful.

Following the issue instructions there, I included information about my CIDER version, emacs version and operating system. I'll include them here, as well;

CIDER version information

;; CIDER 0.15.0 (London), nREPL 0.2.13
;; Clojure 1.9.0, Java 1.8.0_92

Emacs version

GNU Emacs 24.5.1 (x86_64-apple-darwin15.3.0, NS apple-appkit-1404.34) of 2016-06-01

Operating system

OSX El Capitan, Version 10.11.6

Error: SocketException: Protocol family unavailable

The description in NREPL-83 suggests "start-server" will try "::" first and then fall back to "localhost". However, running in Alpine Linux, the attempt to bind "::" throws an exception and the fallback to "localhost" never occurs.

AFAIK, Alpine is different in more ways than one... ipv6 disabled by default, and also musl-libc has its own resolver, so multiple factors could be adding up here. The result however is an exception and behavior that doesn't match the expectation established in NREPL-83.

Obviously the caller can workaround this problem by explicitly passing a :bind argument, like (start-server :port p :bind "localhost"), and for that reason I can consider this a minor issue. If nothing else perhaps the documentation can be clarified.

Here' a transcript to show what I mean:
https://gist.github.com/gonewest818/ae5c5caf49380f81c5a2667408da6d4f

lines 1-74 documents launching alpine, installing lein, and creating a project with nrepl 0.2.13

lines 75-76 shows the exception when no :bind is specified

lines 78-79 proves the obvious workaround

lines 90-91 duplicates the exception by replicating what's happening inside tools.repl

(from https://dev.clojure.org/jira/browse/NREPL-87)

Some messages to an nREPL server never result in a response that includes status :done

According to the documentation:

"Once a handler has completely processed a message, a response
containing a :status of :done must be sent."

I am assuming this includes messages that have resulted in an error. Some messages to an nREPL server never respond with such a status possibly leaving some clients waiting for follow up messages forever.

So far I have found two instances of this problem.

  1. The interruptible-eval middleware may result in a :no-code error that does not include the :done status.

  2. The session middleware may result in a :unknown-session error that does not include the :done status.

I'm including a patch for the above two which are just one word fixes. There might be other situations in which the problem arises.

(from https://dev.clojure.org/jira/browse/NREPL-76)

Add initial authentication support and simple default

The first of these two patches adds authentication to the server, and
the second trivially adjusts the message function to use it (as an
example).

I could easily imagine the current approach might not be acceptable,
but I'd be happy to try to make adjustments.

If this turns out to be interesting, then presumably tools like
leiningen and cider might want to provide more interesting strategies
via their own :auth-wrapper.

I haven't added automated tests for the authentication yet, but you can
run all of the existing tests like this:

NREPL_AUTH=none mvn package

and if we pursue the changes, I can see about adding authorization to
relevant parts of the test suite, if that's helpful.

If you'd like to try it out:

(umask 077 && dd bs=1 count=256 if=/dev/random | base64 > nrepl-token)
NREPL_AUTH=file:nrepl-token lein repl :headless

and then from another process in the same working directory:

(repl/message {:op :eval :code "(+ 1 1)" :auth (slurp "nrepl-token")})

(I also have a patch that adds NREPL_AUTH support to cider.)

(from https://dev.clojure.org/jira/browse/NREPL-85)

Expose function to connect to an existing nREPL session

It may be useful to expose the function to connect to an existing nREPL session, especially from the command-line (at least for the sake of a symmetric API - i.e. create/connect nREPL session).

Sean Corfield put this snippet together to connect to an existing nREPL session. Note it uses a private function:

clj -Sdeps '{:deps {nrepl {:mvn/version "0.4.4"}}}' -e "(require,'[nrepl.cmdline,:as,c]),(#'c/run-repl,\"localhost\",7888)"

Connecting to a manually started nREPL server raises `ClassNotFoundException: clojure.tools.nrepl`

I encountered a strange error when starting an nREPL server programmatically and then connecting to it via lein repl :connect <port>. A CompilerException java.lang.ClassNotFoundException: clojure.tools.nrepl is thrown, i.e., it refers to the old namespace.

I'm not sure where the error lies, nREPL or Leiningen, but I'm posting here first πŸ˜‰

Steps to reproduce the problem

Here's a (somewhat) minimal example that I've cooked down from the Luminus template project:

;;; core.clj
(ns nrepl-minimal.core
  (:require [nrepl.server :as nrepl]
            [mount.core :as mount]
            [clojure.tools.logging :as log])
  (:gen-class))

(mount/defstate ^{:on-reload :noop} repl-server
  :start
  (try
    (log/info "starting nREPL server on port 7000")
    (nrepl/start-server :port 7000)
    (catch Throwable t
      (log/error t "failed to start nREPL")
      (throw t)))
  :stop
  (nrepl/stop-server repl-server))

(defn -main
  [& args]
  (mount/start-with-args nil))

Project file:

;;; project.clj
(defproject nrepl-minimal "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [mount "0.1.14"]
                 [nrepl "0.4.5"]]
  :main ^:skip-aot nrepl-minimal.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

With this configuration, I can reproduce the error:

Terminal 1:

nrepl-minimal$ lein run
Nov 04, 2018 9:10:39 PM clojure.tools.logging$eval493$fn__496 invoke
INFO: starting nREPL server on port 7000

Terminal 2:

nrepl-minimal$ lein repl :connect 7000
Connecting to nREPL at 127.0.0.1:7000
WARNING: cat already refers to: #'clojure.core/cat in namespace: net.cgrand.regex, being replaced by: #'net.cgrand.regex/cat
CompilerException java.lang.ClassNotFoundException: clojure.tools.nrepl, compiling:(/tmp/form-init1590356727115022318.clj:1:82) 
#object[clojure.lang.Namespace 0x7632d7e9 "user"]
Error loading namespace; falling back to user
nil
user=>

Environment & Version information

  • Clojure: 1.9.0

  • Java:

    $ java -version
    openjdk version "1.8.0_181"
    OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-1ubuntu0.18.04.1-b13)
    OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
  • OS:

    $ uname -a
    Linux pop-os 4.15.0-36-generic #39-Ubuntu SMP Mon Sep 24 16:19:09 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
  • Leiningen

    lein -version
    Leiningen 2.8.1 on Java 1.8.0_181 OpenJDK 64-Bit Server VM

Test transports-fail-on-disconnects fails during test-all

Expected behavior

All tests in lein test-all should pass.

Actual behavior

Test transports-fail-on-disconnects fails on clojure v1.8 and v1.9 with message:

expected: (thrown? SocketException (transport/send transport {"op" "eval", "code" "(+ 5 1)"}))
  actual: nil

Full test-all output at https://gist.github.com/benjaminran/c2880f10fc2dad5378b01f7a64a72e57.

Note: the test doesn't fail when I run it directly:

bnran at dca90496b22a in ~/dev/clj/nREPL on master*
$ lein with-profile base,system,user,provided,dev,1.8 test :only nrepl.core-test/transports-fail-on-disconnects

lein test nrepl.core-test

Ran 1 tests containing 3 assertions.
0 failures, 0 errors.
bnran at dca90496b22a in ~/dev/clj/nREPL on master*
$ lein with-profile base,system,user,provided,dev,1.9 test :only nrepl.core-test/transports-fail-on-disconnects

lein test nrepl.core-test

Ran 1 tests containing 3 assertions.
0 failures, 0 errors.

Why does the test fail during test-all but not when run directly? Am I missing something?

Steps to reproduce the problem

Run lein test-all.

Environment & Version information

Clojure version

1.8 and 1.9

Java version

bnran at dca90496b22a in ~/dev/clj/nREPL on master*
$ lein --version
Leiningen 2.8.1 on Java 1.8.0_181 Java HotSpot(TM) 64-Bit Server VM
bnran at dca90496b22a in ~/dev/clj/nREPL on master*
$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

Operating system

macOS Sierra 10.12.6 (16G1510)

Start an nREPL using JVM Opts (Like socket REPL)

It's not possible to start the clj tools in jack-in with a main or additional -e options.

Starting the nREPL should be similar to starting a socket REPL. If it was a JVM opt it can be placed as the first parameter, always, as CLJ doesn't distinguish on order.

Using JVM opts in this way would also benefit production systems which wish to add nREPL. Currently it requires being able to evaluate code early, or altering the component/integrant/mount system in order to load nREPL in production (but not in dev, because leiningen does that!). This would also open up nREPL for easier use with general java software systems, such as Datomic.

Thread used to evaluate forms changes over time

See this thread for reference: https://groups.google.com/forum/#!topic/clojure/UfTQvYNf1-s

When a session is left idle for a little bit of time, the thread id evaluating forms changes. This causes any thread local variables in use to reset to their initial values. This causes strange behavior when doing interactive programming that involves use of thread locals.

The solution is for the same thread to always be used for a given session for as long as the session is open.

(from https://dev.clojure.org/jira/browse/NREPL-80)

Interrupt of load-file generates java.lang.ThreadDeath exception

At lein prompt (load-file "src/test/core.clj") where core.clj contains (Thread/sleep 10000) then C-c to interrupt.

CompilerException java.lang.ThreadDeath, compiling/home/vitoshka/tmp/cidertest/src/blabla/core.clj:1:17)
clojure.lang.Compiler.load (Compiler.java:7142)
clojure.lang.Compiler.loadFile (Compiler.java:7086)
clojure.lang.RT$3.invoke (RT.java:318)
user/eval3418 (form-init8959987907704530559.clj:1)
clojure.lang.Compiler.eval (Compiler.java:6703)
clojure.lang.Compiler.eval (Compiler.java:6666)
clojure.core/eval (core.clj:2927)
clojure.main/repl/read-eval-print-6625/fn-6628 (main.clj:239)
clojure.main/repl/read-eval-print--6625 (main.clj:239)
clojure.main/repl/fn--6634 (main.clj:257)
clojure.main/repl (main.clj:257)
clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn--594 (interruptible_eval.clj:67)
Caused by:
ThreadDeath
java.lang.Thread.stop (Thread.java:836)
clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn--636 (interruptible_eval.clj:204)
clojure.tools.nrepl.middleware/wrap-conj-descriptor/fn--408 (middleware.clj:17)
clojure.tools.nrepl.middleware.pr-values/pr-values/fn--573 (pr_values.clj:17)
clojure.tools.nrepl.middleware/wrap-conj-descriptor/fn--408 (middleware.clj:17)
clojure.tools.nrepl.middleware.load-file/wrap-load-file/fn--751 (load_file.clj:77)
clojure.tools.nrepl.middleware/wrap-conj-descriptor/fn--408 (middleware.clj:17)
clojure.tools.nrepl.middleware.session/add-stdin/fn--710 (session.clj:235)
clojure.tools.nrepl.middleware/wrap-conj-descriptor/fn--408 (middleware.clj:17)
cider.nrepl.middleware.test/wrap-test/fn--3003 (test.clj:199)
clojure.tools.nrepl.middleware/wrap-conj-descriptor/fn--408 (middleware.clj:17)
cider.nrepl.middleware.stacktrace/wrap-stacktrace/fn--2909 (stacktrace.clj:146)

In CIDER, eval the buffer with C-c C-k which uses load-file op and then C-c C-b to interrupt. The relevant CIDER issue is here.

(from https://dev.clojure.org/jira/browse/NREPL-69)

Too many DynamicClassLoaders created

Not sure whether this ticket belongs here or in the Clojure-proper JIRA, so feel free to close if this is an inappropriate location. clojure.main/repl creates a new DynamicClassLoader on every execution, so it looks like the stack of classloaders grows without bounds. Seems a bit similar to http://dev.clojure.org/jira/browse/NREPL-31 in that clojure.main/repl has another assumption about when clojure.main/repl will run.

See https://groups.google.com/forum/?fromgroups=#!topic/clojure/firG9zTVecU%5B1-25%5D for the original report.

(from https://dev.clojure.org/jira/browse/NREPL-36)

Migration out of Clojure Contrib

As discussed on the Clojure google group, maintenance of nREPL is moving out of the Clojure Contrib umbrella. To restate the rationale from that thread:

  1. nREPL is an essential bit of infrastructure in Clojure tooling
  2. On balance, I have neglected the project in recent years, to the detriment of all of the users of the aforementioned tooling.
  3. On balance, contributors and potential contributors have been less involved (or turned away entirely) because of the well-known friction that comes with the contrib process and requirements. (tbh, this is a factor in #2, though not the majority)
  4. No one (least of all me) would object to nREPL having its contribution process managed through github or gitlab.

So basically everyone wants nREPL to be a "regular" project, and subject to and beneficiary of the same expectations as 99.9% of all of the other OSS projects we all interact with daily.

To move forward, I've decided to "reboot" the project; i.e. to reconstitute it as a standalone effort without any legacy tying it to its time within the Contrib system. Simply forking back to my repo here would be far easier in the short term, but I prefer a reboot at this point because, as I state later on in the aforementioned Google Groups thread:

Do I want to maintain explanations of the answers to [questions regarding the heritage and lingering impact of the Contrib process and Contributor's Agreement] for a (fork of a) project that's no longer within contrib? Most definitely not.

The vast majority of the commits in the history at tools.nrepl are mine, and the project's license will remain EPL, so this should a pretty straightforward task. I will solicit agreement from all material contributors to the tools.nrepl project in a subtask listed below, which will simply establish that their contributions are available under EPL (whereas to date, they are only available in a "CA-encumbered" state since they were provided via the Contrib process).

Migration TODOs

  • Obtain agreement from material contributors to tools.nrepl that their work is available under EPL-only terms (#2)
  • Reconstruct commit history to include only those contributors' work (this will drop things like minor build process changes, commits by the build.clojure.org buildbots, etc)
  • Change maven coordinates (back) to com.cemerick/nrepl
  • Tweak up build process to deploy to Maven central without using the Contrib parent POM, etc
  • Cut a release matching [org.clojure/tools.nrepl "0.2.13"] in every material way
  • Grant commit to additional key contributors
  • πŸŽ‰ ❗️
  • Make more sweet REPLs and other tools πŸ˜„

Exception when using Ctrl-D in interactive mode

Expected behavior

Entering Ctrl-D in an interactive nREPL session makes it immediately exit.

Actual behavior

Entering Ctrl-D throws an exception and hangs the process.

Steps to reproduce the problem

$ clj -Sdeps '{:deps {nrepl {:mvn/version "0.4.5"}}}' -m nrepl.cmdline --interactive
nREPL server started on port 54732 on host 0:0:0:0:0:0:0:0 - nrepl://0:0:0:0:0:0:0:0:54732
nREPL 0.4.5
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 10.0.2+13
user=> ^D
Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.RuntimeException: EOF while reading
	at clojure.lang.LispReader.read(LispReader.java:304)
	at clojure.lang.LispReader.read(LispReader.java:206)
	at clojure.lang.LispReader.read(LispReader.java:200)
	at clojure.core$read.invokeStatic(core.clj:3758)
	at clojure.core$read.invokeStatic(core.clj:3733)
	at clojure.core$read.invokeStatic(core.clj:3733)
	at clojure.core$read.invokeStatic(core.clj:3733)
	at clojure.core$read.invoke(core.clj:3733)
	at nrepl.cmdline$run_repl.invokeStatic(cmdline.clj:42)
	at nrepl.cmdline$run_repl.invoke(cmdline.clj:24)
	at nrepl.cmdline$_main.invokeStatic(cmdline.clj:179)
	at nrepl.cmdline$_main.doInvoke(cmdline.clj:138)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:702)
	at clojure.core$apply.invokeStatic(core.clj:657)
	at clojure.main$main_opt.invokeStatic(main.clj:317)
	at clojure.main$main_opt.invoke(main.clj:313)
	at clojure.main$main.invokeStatic(main.clj:424)
	at clojure.main$main.doInvoke(main.clj:387)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:702)
	at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: EOF while reading
	at clojure.lang.Util.runtimeException(Util.java:221)
	at clojure.lang.LispReader.read(LispReader.java:258)
	... 21 more

Consider transfering the repo

Hey Chas!

I don't mean to be pushy or something, but I was really looking forward to nREPL 0.3 (and mostly to what would follow afterwards). I also see you probably didn't have time for nREPL 0.3 recently. Would be open to just transferring the repo to clojure-emacs so we can maintain it there, as we did with piggieback? I think it'd be in the project's best interest if we have more people sharing its maintenance.

Bind clojure.spec.alpha/*explain-out* by default

From a Slack discussion in #cursive over a Clojurians: a user.clj file like the following:

(ns user
  (:require
    [clojure.spec.alpha :as s]
    [expound.alpha :as expound]))

(set! s/*explain-out* expound/printer)

causes an error: "java.lang.IllegalStateException: Can't change/establish root binding of: explain-out with set"

@puredanger explains:

s/*explain-out* is a dynamic variable. to be able to set! it, it must have been bound in a binding somewhere higher on the stack. The clojure.main repl does this, nrepl does not.

Obviously this is a bit tricky to maintain support for Clojure < 1.9, but this is probably a common thing to want to do.

Command line - compose middleware in deps.edn

Hello folks!

I think that, not nRepl's fault for sure, one thing that does not compose well is the --middleware option at the moment. Say I have a :cider-clj entry in deps.edn with:

:main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.piggieback/wrap-cljs-repl]"]

In theory I would like to add just one thing, the piggieback middleware, without changing anything else. Instead we have to add a :cider-cljs entry with:

:main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware,cider.piggieback/wrap-cljs-repl]"]

Maybe we could allow many --middleware options and drop the vector format. If deps.edn conjoins vectors (will verify), probably we can just append things at the tail or :main-opts.

Make it possible to limit the size of returned values and output

Some clients (e.g. Emacs) can't handle very well huge strings in their REPL buffers. It's also questionable how good UX this constitutes as well.

Ideally we should be able to specify some value/output limit in eval ops, so that we can trim the result accordingly. We can either return the full and trimmed results in the same message or just have clients request to eval the same code again without any size limits if they happen to need the big result.

See clojure-emacs/cider#1115 and clojure-emacs/cider#2507 for more details. @gonewest818 started working on something very similar a while back (clojure-emacs/cider#1115 (comment)), so someone might pick up his work if they want to, even though a simpler approach with no caching of the results/output will be fine as well.

Implement a Transit transport

That's a pretty similar issue to #60.

Having a Transit transport would simplify the lives of people using Clojure/ClojureScript/Java clients for nREPL. It's main advantage over an EDN transport would be that Transit defines a more flexible format that's also JSON friendly.

It should be pretty easy to create a transport based on the default bencode transport that simply uses Transit instead of bencode. Here's the implementation of the bencode transport as a reference:

(defn bencode
  "Returns a Transport implementation that serializes messages
   over the given Socket or InputStream/OutputStream using bencode."
  ([^Socket s] (bencode s s s))
  ([in out & [^Socket s]]
   (let [in (PushbackInputStream. (io/input-stream in))
         out (io/output-stream out)]
     (fn-transport
      #(let [payload (rethrow-on-disconnection s (bencode/read-bencode in))
             unencoded (<bytes (payload "-unencoded"))
             to-decode (apply dissoc payload "-unencoded" unencoded)]
         (merge (dissoc payload "-unencoded")
                (when unencoded {"-unencoded" unencoded})
                (<bytes to-decode)))
      #(rethrow-on-disconnection s
                                 (locking out
                                   (doto out
                                     (bencode/write-bencode %)
                                     .flush)))
      (fn []
        (if s
          (.close s)
          (do
            (.close in)
            (.close out))))))))

As this transport will require an extra dep it'd be best to implement it as a tiny separate library in the nREPL org.

0.3.0 java classes are incompatible with Java 8 and 9

Using nREPL in Java 8, I get the following error. It appears the Java classes in 0.3.0 were compiled for Java 10. Is this intentional or should it still be compatible with 8?

java.lang.UnsupportedClassVersionError: clojure/tools/nrepl/StdOutBuffer has been compiled by a more recent version of the Java Runtime (class file version 54.0), this version of the Java Runtime only recognizes class file versions up to 52.0, compiling:(clojure/tools/nrepl/middleware/session.clj:31:13)

Expose JMX MBean to provide list of available nREPL endpoints

In a development environment, one often has many nREPL servers running, sometimes more than one per project. This means that it's sometimes difficult to keep track of which ports are associated with which projects / processes, and existing per-project REPL tracking mechanisms (e.g. Leiningen/reply's repl-port file) are generally not up the job.

It would be great if nREPL exposed a JMX MBean that provided information on each active nREPL server, what URL(s) they'll respond to, and perhaps other details (what middleware is installed on each, etc). Clients could then use JMX to discover all of the nREPL servers on a given host, and present that information in tool-appropriate 'connect' dialogs, etc.

(from https://dev.clojure.org/jira/browse/NREPL-44)

Transport/send hangs when sending non-bencodable information outside of :value slot

Situation: Writing a CIDER middleware, trying to transport/send a response message via the standard bencode transport. The response message has a non-bencodable item outside of the :value slot.

Expected behavior: transport/send will bubble up the IllegalArgumentException thrown in c.t.n.bencode/write-bencode due to the non-bencodable item.

Actual behavior: transport/send silently fails and hangs. No response is sent over the wire (verified by monitoring communication going across nREPL's port). No exception is bubbled up to the CIDER middleware. Subsequent calls to nREPL (to evaluate code for example) do not return. Once an interrupt is sent, the subsequent calls do return correct values, but the non-bencodable response never appears.

I'm guessing there's some relationship to NREPL-30 (http://dev.clojure.org/jira/browse/NREPL-30)? Please see clojure-emacs/cider-nrepl#332 for further info as well. Let me know if there's anything I can do to debug this issue better.

Thanks for your help,
Sanjay

(from https://dev.clojure.org/jira/browse/NREPL-81)

Implement message logging functionality

Is your feature request related to a problem? Please describe.

Often when people encounter an issue with nREPL the best way to debug the issues is to expect the message exchange between their client and nREPL, so we/they can check whether the request and response messages are what we're expecting them to be (both in their encoded and decoded form).

Describe the solution you'd like

Ideally we'll need some way to log all messages as Clojure maps and in their encoded format (e.g. bencode) to a file. Perhaps we can have a logging middleware that checks for some :verbose key in messages and would log those. Clients can easily implement a toggle turning on/off message logging. We can probably have different options for showing the messages encoded or decoded. Likely we should have one log file per each server that goes to .nrepl/ or the current directory, so logs for different servers don't get interleaved (or we can have one log file and just prefix messages accordingly there).

Describe alternatives you've considered

CIDER has some client-side message logging functionality, but there's no easy way to inspect what happens with the message on the server's end.

This doesn't really have to be a middleware - it can also be some server config (e.g. we can add a verbose flag to start-server and just check for it on the transport level), but I think a middleware will be a more flexible solution.

Looking at #79 it seems that @pfeodrippe should be able to easy handle this. Given his work on #84 he should also immediately appreciate the importance of having this. :D

Support custom value rendering middleware

Currently, nREPL's interruptible-eval middleware hardcodes a dependency on pr-values. It would be nicer if the user could either specify alternate rendering middleware or if nREPL's built-in middleware accepted an arbitrary function to render values with. Specifically, this would enable pretty-printing REPL output.

I've set up a middleware to demonstrate this, in combination with the Puget printing library:
https://github.com/greglook/whidbey

Currently it is possible to replace the default middleware, but it involves some ugly runtime metadata manipulation which reaches into the nREPL internals. Addressing this would be another step towards simplifying pretty-printing/color integration in the REPL.

(from https://dev.clojure.org/jira/browse/NREPL-55)

Adopt default port

7888 is "free", at least in IANA.

Most users want to put an nREPL port on their app, and that should always be on a typical port. Auto-selection of a port is only desirable in tooling scenarios, and tooling authors can pass an argument to start-server.

This will change the behaviour of (start-server).

(from https://dev.clojure.org/jira/browse/NREPL-3)

Setup some basic home page using GH pages

@arrdem Recently bought nrepl.org and I guess we should host a simple GH page there (at least initially). The easiest thing we can do is just upload the readme as a homepage via the GH admin UI. I guess this will only require a bit of config on the DNS side.

Eliminate illegal access warnings

When we start the server today on JDK 9+ we get:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by nrepl.middleware.interruptible_eval$set_line_BANG_ to field java.io.FilterReader.in
WARNING: Please consider reporting this to the maintainers of nrepl.middleware.interruptible_eval$set_line_BANG_
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

There we're setting some protected fields, which was never really a great approach, but now it seems this might be blocked down the road. We need to see how we can set the metadata without breaking data encapsulation. Maybe we can get some inspiration from clojure.main?

@mallt Would like to tackle this? I assume it'd be pretty straight-forward.

Namespace migration

As a consequence of #1, it seems necessary to eventually move nREPL out of the clojure.tools.nrepl.* namespaces associated with Clojure Contrib. After all, tools.nrepl may yet be maintained separately from this effort, and no one benefits from same-named namespaces floating around in multiple artifacts.

I see two options:

  1. Cut over to cemerick.nrepl.* namespaces, and stop distributing clojure.tools.nrepl.*-namespaced code from here ASAP.
  2. Move the actual code to cemerick.nrepl.* namespaces, replacing the clojure.tools.nrepl.* namespaces with stubs that use immigrate or similar to ensure API compatibility for downstream tools and libraries. This arrangement can persist for some period of time, eventually moving those stubs into a separate "nrepl-compat" library, that can be added in downstream as needed to provide those clojure.tools.nrepl.* namespaces.

Thoughts?

Implement an EDN transport

Having an EDN transport would simplify the lives of people using Clojure/ClojureScript/Java clients for nREPL. It should be pretty easy to create a transport based on the default bencode transport that simply uses EDN instead of bencode. Here's the implementation of the bencode transport as a reference:

(defn bencode
  "Returns a Transport implementation that serializes messages
   over the given Socket or InputStream/OutputStream using bencode."
  ([^Socket s] (bencode s s s))
  ([in out & [^Socket s]]
   (let [in (PushbackInputStream. (io/input-stream in))
         out (io/output-stream out)]
     (fn-transport
      #(let [payload (rethrow-on-disconnection s (bencode/read-bencode in))
             unencoded (<bytes (payload "-unencoded"))
             to-decode (apply dissoc payload "-unencoded" unencoded)]
         (merge (dissoc payload "-unencoded")
                (when unencoded {"-unencoded" unencoded})
                (<bytes to-decode)))
      #(rethrow-on-disconnection s
                                 (locking out
                                   (doto out
                                     (bencode/write-bencode %)
                                     .flush)))
      (fn []
        (if s
          (.close s)
          (do
            (.close in)
            (.close out))))))))

The best thing about this transport is that it requires no extra deps, so it can be easily bundled with nREPL itself.

Licensing your nREPL contributions under EPL

For background, please see #1.

Your contributions to nREPL over the years are greatly appreciated. To better serve all of the users of nREPL, and to simplify things for those that are most impacted by the project, I am pulling development here (where the project began some 8 years ago).

Note that the license is not changing from EPL, the license that has always governed nREPL contributions. However, your commits were submitted through the Clojure Contrib process, which carries additional terms. Since I am seeking to excise the Contrib/CA heritage from the project, and IANAL, I'm now asking to reaffirm your licensing of your nREPL commits under "regular" EPL terms, so they may be included here.

Once all contributors indicate their assent here, I will reconstruct the nREPL commit history to include only your work, which will drop things like minor build process changes, commits by the build.clojure.org buildbot, etc. My hope is that the result will be a place where people invested in nREPL and the tools that depend upon it can collaborate using familiar practices and a set of enthusiastically shared expectations.

tl;dr

If you agree to license your contributions to tools.nrepl under the Eclipse Public License, please respond here with "OK" or similar. This will unambiguously allow those contributions to be used in other EPL-licensed contexts (including this project) without consideration of the Clojure Contribution Agreement (CA), under which those contributions were made originally.

If you do not agree, please indicate this in a comment as well, or contact me directly by email.

The roster of contributors with material commits in the tools.nrepl history are as follows:

Thank you again for your work. β™₯️

Make using subrepls seamless

This is written from the perspective of CIDER - I assume this still belongs here and not in CIDER

If you call (clojure.main/repl) in nREPL, the reading and printing is not done via nREPL magic anymore but by the implementation of clojure.main/repl.
The stdin reading triggers an outgoing nREPL message with status ("need-input"), which CIDER handles completely different than the normal input prompt in the REPL buffer.

This currently prevents using a break macro (https://gist.github.com/leobm/6061734) in CIDER
and causes clojure-emacs/cider#2017.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.