GithubHelp home page GithubHelp logo

swannodette / replicant Goto Github PK

View Code? Open in Web Editor NEW

This project forked from puredanger/replicant

0.0 3.0 1.0 140 KB

Sketching use of clojure socket server for tooling use

License: Eclipse Public License 1.0

Clojure 100.00%

replicant's Introduction

replicant

A sketch of using the Clojure socket server facility to create a repl suitable for tooling use. This is not a published library that you should use directly - feel free to steal and modify any code you see here.

Usage

The goal here is for a tool (IDE) to create a REPL for a user where the tool is able to snoop on the user's REPL context (for example, dynamic vars like ns).

Start the JVM with a data tooling REPL server

First, we need to start a JVM - this should use the project's classpath and settings but may also need to include access to any extra code needed by the tooling repl (like the stuff in this project). You will also need to instruct the Clojure runtime to start a socket server that the tool will connect to as a client with a system property:

-Dclojure.server.datarepl="{:port 5555 :accept 'replicant.util/data-repl}"

The data-repl accept function will be called in this JVM when you connect as a client on port 5555 to this JVM. The data-repl is just a normal repl with modifications to capture *out* and *err* and to turn off the REPL prompt.

The response from any expression sent to the data-repl will be a map that contains the keys :result (if successful), :exception (if thrown, in map form), :out, and :err.

Start user REPL server

The tool must then connect to the running JVM on the specified port (5555). The tool is then connected as a client to the user's application. From within this connection we need to set up a state container for the user's environment bindings. It can then evaulate arbitrary expressions in the context of the user's environment.

  (let [bindings (atom {})          ;; shared atom to stash user's bindings
        repl-name (gensym "repl")   ;; generate repl server name
        server ^SocketServer (server/start-server
                                {:name   repl-name
                                 :port   0   ;; pick a free port
                                 :accept 'replicant.util/repl
                                 :args   [:eval (partial user-eval bindings)]})
        repl-port (.getLocalPort server)]

    ;; do stuff below in this context
  )

This code creates an atom to stash user bindings, then starts a new repl server with a special eval function, user-eval, which looks like this:

(defn user-eval
  [binding-atom form]
  (let [result (eval form)]
    (swap! binding-atom (get-thread-bindings))
    result))

user-eval does one special thing - after you evaluate a form, it stashes the user's current bindings in the specified atom. In our case, this will be an atom that the tooling repl has access to.

Connect user REPL connection

The tool should then create a normal socket REPL connection to the repl-port retrieved above. When they do so they will be using user-eval and their bindings will be saved off after every REPL evaluation in the binding-atom.

Evaluate in user's environment

Now that the user's state is being saved off, the tooling repl (the first connection) can evaluate arbitrary expressions (like *ns*) in the context of the first tooling REPL connection using something like with-user-bindings:

(defmacro with-user-bindings
  [binding-atom & body]
  `(with-bindings ~@binding-atom body))

License

Copyright © 2015 Alex Miller

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

replicant's People

Contributors

puredanger avatar

Watchers

 avatar  avatar  avatar

Forkers

anthrax3

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.