How to remove namespace name from sublimeREPL (clojure) prompt? - clojure

I'm using clojure sublimeREPL and I would like to know if I can remove the namespace name from the prompt
Currently my prompt looks like this:
foo.core=>
More often for some reason it is doubled:
foo.core=>foo.core=>
I would like to be able to have just this:
>
I can't find the place where this behavior is defined in the sublimeREPL package
Any help welcome

As far as I can tell,lein repl recognizes no argument for setting the prompt. Furthermore, the standard tools.nrepl, as used by lein repl, has the ability to set the prompt, but it is hidden inside a private function in cmdline.clj and it is not exposed to any public function. So exposing this functionality would mean modifying both Leiningent and tools.nrepl.
Alternatively, the currently accessible way to set the prompt is as an argument to the function clojure.main/repl. Sublime is not set up to interact directly with this, because it is set up to use the nrepl protocol to communicate with Clojure.
So, unless I am missing something, your options are:
accept that you cannot change the prompt
change Leiningen and tools.nrepl so both expose a prompt option
change Sublime so that it can use clojure.main/repl directly

I know this is an old question, but there is a better answer than the accepted one. In your project.clj file, you can set :repl-options like so:
(defproject my-stuff "0.1.0"
:description "Leiningen Tutorial Project"
:url "http://example.com/FIXME"
:license {:name "MIT"
:url "http://opensource.org/licenses/MIT"}
:dependencies [[org.clojure/clojure "1.8.0"]]
:main ^:skip-aot my-stuff.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}}
:repl-options {
;; custom prompt
prompt (fn [ns] (str "> " ))
}
)
In your case, replace prompt (fn [ns] (str "> " )) with prompt (str "> " ) and you should be all set.

Related

Using imported Java libs in Clojure REPL

Twilio docs for Java lib
MVN for this lib
I'm trying to use Twilio from Clojure. Pretty new to Clojure dev, so I'm trying to get to grips with importing libs, in general.
My project.clj looks like this:
(defproject magical-new-project "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [[org.clojure/clojure "1.10.0"]
[com.twilio.sdk/twilio "7.47.5"]]
:repl-options {:init-ns magical-new-project.core})
I think I'm correctly importing the Twilio Java lib, but I'm not sure.
My core.clj looks like:
(ns magical-new-project.core
(:import [com.twilio Twilio]
;[com.twilio.http Request Response]
[com.twilio.rest.api.v2010.account Message]
[com.twilio.rest.api.v2010.account Call]
[com.twilio.type PhoneNumber]))
(defn foo
"I don't do a whole lot."
[x]
(println x "Peacefully disengage, World!"))
As far as I can tell, this should be correctly importing the Twilio class shown here.
So then I try (from REPL) to initialize the Twilio object that I hope I have successfully imported, but it fails.
$ lein repl
nREPL server started on port 62356 on host 127.0.0.1 - nrepl://127.0.0.1:62356
REPL-y 0.4.3, nREPL 0.6.0
Clojure 1.10.0
OpenJDK 64-Bit Server VM 12.0.1+12
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
magical-new-project.core=> (Twilio. "My API or Account SID goes here" "My AUTH_TOKEN or API secret goes here")
Syntax error (IllegalArgumentException) compiling new at (form-init14687807219308370487.clj:1:1).
No matching ctor found for class com.twilio.Twilio
As far as I can tell, the No matching ctor thing means there is no constructor function that accepts the arguments I'm presenting, but line 39 of the Twilio.java file seems to take two strings, and then if you look here, you'll see that I'm sending the right arguments (the ACCOUNT_SID and the AUTH_TOKEN).
At the moment, I'm not sure whether I'm (1) correctly importing the Twilio class, (2) adding the dependencies to the project correctly, (2) correctly using the REPL, or (4) correctly using the Twilio SDK. Maybe I'm doing all of these incorrectly.
I would really appreciate any help or advice that you could afford me.
the function you linked to is not a constructor but a static function on the class. You call a static function on a class in clojure like (Twilio/init "foo" "bar"). Your syntax is correct if it were actually a constructor.
Thanks #juraj. I wasn't sure if this actually qualified as an answer :-)

What's the correct way of providing a default value for *print-length* in profiles.clj?

For those that do not know what *print-length* stands for:
If you (set! *print-length* 200), and you evaluate (range) in a REPL, which normally causes an infinite list of numbers to get printed, only the first 200 numbers will get printed.
I'm trying to set this as a default for all my REPLs in profiles.clj.
Right now I got this, but it doesn't work:
{:user {:plugins [[lein-swank "1.4.4"]
[lein-catnip "0.5.0"]]
:repl-options {*print-length* 200}}
:dev {:dependencies [[clj-ns-browser "1.2.0"]
[org.clojure/tools.trace "0.7.5"]]}}
What's wrong with this?
Update. Tnx Michal for answering this. My fixed profiles.clj now looks like this. Note that it only works inside a project.
{:user {:plugins [[lein-swank "1.4.4"]
[lein-catnip "0.5.0"]]
:repl-options {:init (set! *print-length* 200)}}
:dev {:dependencies [[clj-ns-browser "1.2.0"]
[org.clojure/tools.trace "0.7.5"]]}}
:repl-options needs to be a map of options supported by Leiningen's repl task; anything else will be ignored. *print-length* is not a valid option (and neither is nil; I'd have to check to be sure if the keys are evaluated here, but this won't work either way).
Instead you should use something like
:repl-options {:init (set! *print-length* 200)}
See sample.project.clj in the root of Leiningen's repository for a description of the available options (including :init).
This is now also supported in project.clj:
:global-vars {*print-length* 20}

How to exclude from project stax-utils dependency for tagsoup?

I'm running Debian Wheezy, openjdk-7-jre, clojure 1.4.0 and leiningen-1.7.1, all installed from official repo.
I have a project.clj like this:
(defproject guess-film "1.0.0-SNAPSHOT"
:description "FIXME"
:dependencies [
[org.clojure/clojure "1.4.0"],
[clj-http "0.5.0"],
[clj-tagsoup "0.3.0" :exclusions [net.java.dev.stax-utils/stax-utils]]
]
:main guess-film.core
)
As you can see on that stage I excluded stax-utils, actually this is described on clj-tagsoup Github page.
Then I have this src/guess-film/core.clj:
ns guess-film.core
(:require
[clj-http.client :as client]
[pl.danieljanus.tagsoup :as parser :refer [parse parse-string]] :verbose
)
)
And when I try to
lein repl
it crashes, I presume because of unsatisfied stax-utils:
...
(clojure.core/load "/pl/danieljanus/tagsoup")
(clojure.core/load "/clojure/zip")
(clojure.core/in-ns 'pl.danieljanus.tagsoup)
(clojure.core/alias 'zip 'clojure.zip)
(clojure.core/load "/clojure/xml")
(clojure.core/in-ns 'pl.danieljanus.tagsoup)
(clojure.core/alias 'xml 'clojure.xml)
(clojure.core/load "/clojure/data/xml")
(clojure.core/in-ns 'clojure.data.xml)
(clojure.core/alias 'str 'clojure.string)
(clojure.core/in-ns 'pl.danieljanus.tagsoup)
(clojure.core/alias 'lazy-xml 'clojure.data.xml)
ClassNotFoundException javanet.staxutils.ContentHandlerToXMLEventWriter java.net.URLClassLoader$1.run (URLClassLoader.java:366)
I tried to evade loading of lazy-xml by using :refer, but that doesn't work I presume. Also I tried ":use ... :only [parse parse-string]" with no success either.
I just don't like to load what I am not going to use :)
Is it clj-tagsoup failure that it tries to load lazy-xml anyway?
If I can't escape from that dependency, will it be a perfomance hit?
It is clj-tagsoup the one that is importing the javanet.staxutils.Content... class, so I don't think there is much that you can do about it.
It won't be any performance hit, loading just another class it is not going to make much of a difference and it is not going to use much memory either.

Why does read-line not return after hitting ENTER (seems like a hang) using lein run, but works with lein repl?

The problem at hand is that when I run my program with lein run it gets to the (read-line) part and I can't get out of it, meaning: read-line never returns.
Here is the relevant code:
(def command (atom ""))
(defn print-prompt []
(print "prompt> ")
(flush)
)
(defn ask-for-input []
(print-prompt)
(let [x (str (read-line))]
(println (str "User input: " x))
(reset! command x)
)
)
I never see the "User input: " string on screen.
The strange part is, if I run lein repl and call (ask-for-input) then it works correctly :S
Try lein trampoline run, it works.
The following is from leiningen FAQ:
Q: I don't have access to stdin inside my project.
A: This is a limitation of the JVM's process-handling methods; none of them expose stdin correctly. This means that functions like read-line will not work as expected in most contexts, though the repl task necessarily includes a workaround. You can also use the trampoline task to launch your project's JVM after Leiningen's has exited rather than launching it as a subprocess.
I tried your source code, but omitted the flush. It worked without a problem. What version of Clojure are you using? I tried the following code with Clojure 1.3.
(def command (atom 0))
(defn print-prompt []
(print "prompt> ")
)
(defn ask-for-input
[]
(print-prompt)
(let [x (str (read-line))]
(println (str "User input: " x))
(reset! command x)
))
Edit:
I altered one of your functions that I copied and tested with, and it works now with standalone and lein run. You had (flush) in your original example.
(defn print-prompt []
(print "prompt> ")
(flush)
)
From what I can garner, println causes a flush, print doesn't, and you need a flush after print.
I am adding this information in case it might be of help. I have a Clojure project called repl-test. Here is my repl-test project's core.clj file header. Your source, already posted, is in this file with some other functions, not related to your post.
(ns repl-test.core
(:gen-class)
(:use clojure.contrib.command-line)
(:require [clojure.contrib.string :as cstr])
(:require [clojure.contrib.trace :as ctr])
(:require [clojure.string :as sstr])
(:use clojure-csv.core))
And here is the project.clj file:
(defproject repl-test "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[org.clojure/clojure "1.3.0"]
[org.clojure/clojure-contrib "1.2.0"]
[clojure-csv/clojure-csv "1.2.4"]
[org.clojure/tools.cli "0.1.0"]
[clj-http "0.1.3"]]
:aot [repl-test.core]
:main repl-test.core)

Compojure development without web server restarts

I've written a small Swing App before in Clojure and now I'd like to create an Ajax-style Web-App. Compojure looks like the best choice right now, so that's what I'm going to try out.
I'd like to have a real tiny edit/try feedback-loop, so I'd prefer not to restart the web server after each small change I do.
What's the best way to accomplish this? By default my Compojure setup (the standard stuff with ant deps/ant with Jetty) doesn't seem to reload any changes I do. I'll have to restart with run-server to see the changes. Because of the Java-heritage and the way the system is started etc. This is probably perfectly normal and the way it should be when I start the system from command-line.
Still, there must be a way to reload stuff dynamically while the server is running. Should I use Compojure from REPL to accomplish my goal? If I should, how do I reload my stuff there?
This is quite an old question, and there have been some recent changes that make this much easier.
There are two main things that you want:
Control should return to the REPL so you can keep interacting with your server. This is accomplished by adding {:join? false} to options when starting the Jetty server.
You'd like to automatically pick up changes in certain namespaces when the files change. This can be done with Ring's "wrap-reload" middleware.
A toy application would look like this:
(ns demo.core
(:use webui.nav
[clojure.java.io]
[compojure core response]
[ring.adapter.jetty :only [run-jetty]]
[ring.util.response]
[ring.middleware file file-info stacktrace reload])
(:require [compojure.route :as route] view)
(:gen-class))
; Some stuff using Fleet omitted.
(defroutes main-routes
(GET "/" [] (view/layout {:body (index-page)})
(route/not-found (file "public/404.html"))
)
(defn app
[]
(-> main-routes
(wrap-reload '(demo.core view))
(wrap-file "public")
(wrap-file-info)
(wrap-stacktrace)))
(defn start-server
[]
(run-jetty (app) {:port 8080 :join? false}))
(defn -main [& args]
(start-server))
The wrap-reload function decorates your app routes with a function that detects changes in the listed namespaces. When processing a request, if those namespaces have changed on disk, they are reloaded before further request processing. (My "view" namespace is dynamically created by Fleet, so this auto-reloads my templates whenever they change, too.)
I added a few other pieces of middleware that I've found consistently useful. wrap-file handles static assets. wrap-file-info sets the MIME type on those static assets. wrap-stacktrace helps in debugging.
From the REPL, you could start this app by using the namespace and calling start-server directly. The :gen-class keyword and -main function mean that the app can also be packaged as an uberjar for startup from outside the REPL, too. (There's a world outside the REPL? Well, some people have asked for it anyway...)
Here's an answer I got from James Reeves in the Compojure Google Group (the answer's here with his permission):
You can reload a namespace in Clojure using the :reload key on the use
or require commands. For example, let's say you have a file "demo.clj" that contains your routes:
(ns demo
(:use compojure))
(defroutes demo-routes
(GET "/"
"Hello World")
(ANY "*"
[404 "Page not found"]))
At the REPL, you can use this file and start a server:
user=> (use 'demo)
nil
user=> (use 'compojure)
nil
user=> (run-server {:port 8080} "/*" (servlet demo-routes))
...
You could also put the run-server command in another clojure file.
However, you don't want to put it in the same file as the stuff you want to reload.
Now make some changes to demo.clj. At the REPL type:
user=> (use 'demo :reload)
nil
And your changes should now show up on http://localhost:8080
I wanted to add an answer, since things have changed a bit since the newest answer and I had spent a bit of time looking for this myself.
Install leiningen (just follow the instructions there)
Create project
lein new compojure compojure-test
Edit the ring section of project.clj
:ring {:handler compojure-test.handler/app
:auto-reload? true
:auto-refresh? true}
Start the server on whatever port you want
lein ring server-headless 8080
Check that the server is running in your browser, the default base route should just say "Hello world". Next, go modify your handler (it's in src/project_name). Change the hello world text, save the file and reload the page in your browser. It should reflect the new text.
Following up on Timothy's link to Jim Downing's setup, I recently posted on a critical addition to that baseline that I found was necessary to enable automatic redeployment of compojure apps during development.
I have a shell script that looks like this:
#!/bin/sh
CLASSPATH=/home/me/install/compojure/compojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure/clojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure-contrib/clojure-contrib.jar
CLASSPATH=$CLASSPATH:/home/me/elisp/clojure/swank-clojure
for f in /home/me/install/compojure/deps/*.jar; do
CLASSPATH=$CLASSPATH:$f
done
java -server -cp $CLASSPATH clojure.lang.Repl /home/me/code/web/web.clj
web.clj looks like this
(use '[swank.swank])
(swank.swank/ignore-protocol-version "2009-03-09")
(start-server ".slime-socket" :port 4005 :encoding "utf-8")
Whenever I want to update the server I create an ssh tunnel from my local machine to the remote machine.
Enclojure and Emacs (running SLIME+swank-clojure) can connect to the remote REPL.
This is highly configuration dependent but works for me and I think you can adapt it:
Put compojure.jar and the jars under the compojure/deps directory are in your classpath. I use clojure-contrib/launchers/bash/clj-env-dir to do this, all you need to do is set the directory in CLOJURE_EXT and it will find the jars.
CLOJURE_EXT Colon-delimited list of paths to directories whose top-level
contents are (either directly or as symbolic links) jar
files and/or directories whose paths will be in Clojure's
classpath.
Launch clojure REPL
Paste in hello.clj example from compojure root directory
Check localhost:8080
Re-define the greeter
(defroutes greeter
(GET "/"
(html [:h1 "Goodbye World"])))
Check localhost:8080
There are also methods for attaching a REPL to an existing process, or you could keep a socket REPL embedded in your server or you could even define a POST call that will eval on the fly to allow you to redefine functions from the browser itself! There are lots of ways to approach this.
I'd like to follow up on mtnygard's answer and post the full project.clj file and core.clj file that got the given functionality working. A few modifications were made, and it's more barebones
pre-setup commands
lein new app test-web
cd test-web
mkdir resources
project.clj
(defproject test-web "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.5.1"]
[compojure "1.1.6"]
[ring "1.2.1"]]
:main ^:skip-aot test-web.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
core.clj
(ns test-web.core
(:use
[clojure.java.io]
[compojure core response]
[ring.adapter.jetty :only [run-jetty]]
[ring.util.response]
[ring.middleware file file-info stacktrace reload])
(:require [compojure.route :as route])
(:gen-class))
(defroutes main-routes
(GET "/" [] "Hello World!!")
(GET "/hello" [] (hello))
(route/not-found "NOT FOUND"))
(def app
(-> main-routes
(wrap-reload '(test-web.core))
(wrap-file "resources")
(wrap-file-info)
(wrap-stacktrace)))
(defn hello []
(str "Hello World!"))
(defn start-server
[]
(run-jetty #'app {:port 8081 :join? false}))
(defn -main [& args]
(start-server))
Pay Attention to the change from (defn app ...) to (def app ...)
This was crucial to getting the jetty server to work correctly
Compojure uses ring internally (by the same author), the ring web server options allow automatic realoading. So two alternatives would be :
lein ring server
lein ring server-headless
lein ring server 4000
lein ring server-headless 4000
Note that :
You need to have a line in your project.clj file that looks like:
:ring {:handler your.app/handler}