Permalink
Browse files

Merge branch 'master' into fix-macroexpand

  • Loading branch information...
2 parents 32f9bcc + 0af258a commit 663fb5fd2a6931a8427d3c27a386838eedda9140 @swannodette swannodette committed May 31, 2010
Showing with 221 additions and 155 deletions.
  1. +31 −0 NEWS
  2. +78 −131 README.md
  3. +1 −1 project.clj
  4. +14 −0 src/leiningen/swank.clj
  5. +30 −15 src/swank/commands/basic.clj
  6. +51 −0 src/swank/commands/xref.clj
  7. +1 −1 src/swank/core.clj
  8. +6 −7 src/swank/swank.clj
  9. +5 −0 src/swank/util.clj
  10. +4 −0 swank-clojure.el
View
31 NEWS
@@ -0,0 +1,31 @@
+Swank Clojure NEWS -- history of user-visible changes
+
+= 1.2.0 / 2010-05-15
+
+* Move lein-swank plugin to be bundled with swank-clojure.
+
+* Support M-x slime-who-calls. List all the callers of a given function.
+
+* Add swank.core/break.
+
+* Support slime-pprint-eval-last-expression.
+
+* Improve support for trunk slime.
+
+* Completion for static Java members.
+
+* Show causes of exceptions in debugger.
+
+* Preserve line numbers when compiling a region/defn.
+
+* Relicense to the EPL (same as Clojure).
+
+* Better compatibility with Clojure 1.2.
+
+= 1.1.0 / 2010-01-01
+
+* A whole mess of stuff!
+
+= 1.0.0 / 2009-11-10
+
+* First versioned release.
View
209 README.md
@@ -1,73 +1,64 @@
# Swank Clojure
-[Swank-clojure](http://github.com/technomancy/swank-clojure) is an
-adapter that lets you use SLIME (the Superior Lisp Interaction Mode
-for Emacs) with Clojure. It's designed to work with GNU Emacs 23 and
-higher. It may work with forks like XEmacs/Aquamacs or earlier
-versions of GNU Emacs, but those are not as well supported.
+[Swank Clojure](http://github.com/technomancy/swank-clojure) is a
+server that allows [SLIME](http://common-lisp.net/project/slime/) (the
+Superior Lisp Interaction Mode for Emacs) to connect to Clojure
+projects. To use it you must launch a swank server, then connect to it
+from within Emacs.
## Usage
-There are two main ways to launch Swank Clojure:
-
-* Standalone Session: If you just hit M-x slime, swank-clojure will
- download the jars for the latest stable releases of Clojure,
- Contrib, and Swank Clojure, launch an instance, and connect to
- it. If you just want to try out Clojure, this is all you need. Just
- get Swank Clojure through [ELPA](http://tromey.com/elpa) and stop
- reading here. =) But this is intended for experimentation; for real
- work in the context of a project you will probably want the other
- option.
-
-* Project: Users of Leiningen or Maven can [start a session from a
- shell](http://wiki.github.com/technomancy/leiningen/emacs-integration)
- with "lein swank" or "mvn -o clojure:swank" and connect to it from
- within Emacs using M-x slime-connect.
-
-Because the JVM classpath can't be modified at runtime, you can't
-start a session with plain M-x slime and then decide to work on your
-project; you'll need to start a new session.
-
-## Installation
-
-Install [from ELPA](http://tromey.com/elpa) using package.el[1].
-
-When you perform the installation, you will see warnings related to
-the byte-compilation of the packages. This is **normal**; the packages
-will work just fine even if there are problems byte-compiling it upon
-installation.
-
-If you're going to use Leiningen or Maven to initiate your sessions
-(#2 above), you'll only need the "slime-repl" package. Otherwise get
-the "swank-clojure" package.
-
-While it's possible to install swank-clojure manually, it's not
-recommended. package.el will be included in the next version of Emacs and
-has been a standard piece of the Emacs ecosystem for a while
-now. See the "Installing from Source" section below if you wish to
-hack on a development version that hasn't been released yet.
-
-Be sure you don't have old versions of SLIME either manually installed
-or installed using a system-wide package manager like apt-get. If you
-do have any manual configuration of SLIME, be sure to either remove it
-or place it after package.el is initialized.
+Add Swank Clojure to your project as a development dependency to your
+project. If you are using Leiningen, add it to your project.clj file
+under :dev-dependencies:
-## Embedding
+ :dev-dependencies [[swank-clojure "1.2.1"]]
-You can embed swank in your project, start the server from within your
-own code, and connect via Emacs to that instance:
+Once you run "lein deps" you can launch a swank server from the
+command line:
- (ns my-app
- (:use [swank.swank :as swank]))
- (swank/start-repl) ;; optionally takes a port argument
+ $ lein swank [PORT=4005] [HOST=localhost]
-Then use M-x slime-connect to connect from within Emacs.
+Note that the lein-swank plugin now comes with Swank Clojure; it does
+not need to be specified as a separate dependency any more.
-You can also start the server directly from the "java" command-line
-launcher if you AOT-compile it and specify "swank.swank" as your main
-class.
+If you're using Maven, add this to your pom.xml under the
+\<dependencies\> section:
+
+ <dependency>
+ <groupId>swank-clojure</groupId>
+ <artifactId>swank-clojure</artifactId>
+ <version>1.2.1</version>
+ </dependency>
+
+Then you can launch a swank server like so:
+
+ $ mvn -o clojure:swank
-## Commands
+Note that due to a bug in clojure-maven-plugin, you currently cannot
+include it as a test-scoped dependency; it must be compile-scoped. You
+also cannot change the port from Maven; it's hard-coded to 4005.
+
+## Connecting with SLIME
+
+Install the "slime-repl" package [from ELPA](http://tromey.com/elpa)
+using package.el. When you perform the installation, you will see
+warnings related to the byte-compilation of the packages. This is
+**normal**; the packages will work just fine even if there are
+problems byte-compiling it upon installation.
+
+Then you should be able to connect to the swank server you launched:
+
+ M-x slime-connect
+
+It will prompt you for your host (usually localhost) and port. It may
+also warn you that your SLIME version doesn't match your Swank
+version; this should be OK.
+
+Having old versions of SLIME either manually installed or installed
+using a system-wide package manager like apt-get may cause issues.
+
+## SLIME Commands
Commonly-used SLIME commands:
@@ -80,65 +71,48 @@ Commonly-used SLIME commands:
* **C-c C-d C-d**: Look up documentation for a var
* **C-c C-z**: Switch from a Clojure buffer to the repl buffer
* **C-c M-p**: Switch the repl namespace to match the current buffer
+* **C-c C-w c**: List all callers of a given function
Pressing "v" on a stack trace a debug buffer will jump to the file and
line referenced by that frame if possible.
-Note that Slime was designed to work with Common Lisp, which has a
+Note that SLIME was designed to work with Common Lisp, which has a
distinction between interpreted code and compiled code. Clojure has no
-such distinction, but many of the Slime commands retain parallel
+such distinction, but many of the SLIME commands retain parallel
load/compile commands that have the same effect in the context of
Clojure.
-## Debug Repl
-
-For now, see [Hugo Duncan's
-blog](http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml)
-for an explanation of this excellent feature. Further documentation to come.
-
-## Alternate Usage
-
-There are a couple other ways to launch a session for special cases:
+## Embedding
-* Custom classpath: If you want to hack on Clojure or Contrib or want
- to provide your own copy of the jars for some other reason, set
- swank-clojure-classpath to a list of paths to the jars you want to
- use and then hit M-x slime. If you have a ~/.clojure or
- ~/.swank-clojure directory full of jars you want to use, you don't
- need to set swank-clojure-classpath.
+You can embed Swank Clojure in your project, start the server from
+within your own code, and connect via Emacs to that instance:
-* Project Session from Emacs: Put your project's dependencies in the
- lib/ directory, (either manually or using
- [Leiningen](http://github.com/technomancy/leiningen) or Maven) then
- launch M-x swank-clojure-project. Note that you must have
- swank-clojure.jar in the lib/ directory, it will not automatically
- add itself to the classpath as it did in past versions that had to
- run from a checkout.
+ (ns my-app
+ (:use [swank.swank :as swank]))
+ (swank/start-repl) ;; optionally takes a port argument
-If you intend to use M-x swank-clojure-project, it will prompt for a
-project dir and set up the classpath for that structure based on some
-existing Clojure conventions:
+Then use M-x slime-connect to connect from within Emacs.
-* src/, classes/, test/, and resources/ - added to the classpath
-* lib/ - all .jars in here are added to the classpath
-* src/main/clojure, src/test/, target/classes,
- target/dependency - added if pom.xml exists (maven-style)
- All jars in target/dependency will be added as well.
+You can also start the server directly from the "java" command-line
+launcher if you AOT-compile it and specify "swank.swank" as your main
+class.
-Your project should include *all* its dependent jars (including
-Clojure and Swank-Clojure) in either lib/ or target/dependency. If it
-depends on more than just Clojure, Contrib, and Swank, it's
-recommended that you use a dependency manager such as Leiningen to
-manage these.
+## Debug Repl
-## Keeping Common Lisp
+For now, see [Hugo Duncan's
+blog](http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml)
+for an explanation of this excellent feature. Further documentation to come.
-If you want to use SLIME with Common Lisp or another Lisp
-implementation, add this to your Emacs config:
+## swank-clojure.el
- (add-to-list 'slime-lisp-implementations '(sbcl ("sbcl")))
+Previous versions of Swank Clojure bundled an Elisp library called
+swank-clojure.el that provided ways to launch your swank server from
+within your Emacs process. While swank-clojure is still distributed
+with the project, it's a much more error-prone way of doing things
+than the method outlined above.
-Then launch Slime with M-- M-x slime $LISP instead of just M-x slime.
+If you have configured your Emacs to use M-x swank-clojure-project
+then it should still work, but it's not recommended for new users.
## Community
@@ -154,36 +128,9 @@ tips. If you've got some time on your hands, reading this [style
guide](http://mumble.net/~campbell/scheme/style.txt) wouldn't hurt
either.
-## Installing from Source
-
-Swank-clojure is really two pieces: a server written in Clojure and a
-launcher written in Elisp. The elisp parts are installed with:
-
- $ git clone git://github.com/technomancy/slime.git
- $ git clone git://github.com/technomancy/clojure-mode.git
-
-Open slime/slime.el, slime/contrib/slime-repl.el,
-clojure-mode/clojure-mode.el, and swank-clojure.el and hit
-M-x package-install-from-buffer in each buffer in order. You will get
-compiler warnings, but they should not be fatal. Restart Emacs, and
-you should be able to use M-x slime.
-
-The Clojure-side server is managed with
-[Leiningen](http://github.com/technomancy/leiningen). Use the "lein
-install" task to place it in your local repository.
-
-Note that using Slime from CVS trunk is not recommended; changes have
-been introduced which are incompatible with the current implementation
-of the Clojure server. Using the versions in git from above will
-ensure that you have a compatible version.
-
## License
-Copyright (C) 2008-2010 Jeffrey Chu, Phil Hagelberg, Hugo Duncan, and contributors
-
-The Clojure server is licensed under the EPL. (See the file COPYING.)
-The Emacs code is licensed under the GNU General Public License
-version 3, which should have been distributed with your copy of Emacs.
+Copyright (C) 2008-2010 Jeffrey Chu, Phil Hagelberg, Hugo Duncan, and
+contributors
-[1] - [ELPA](http://tromey.com/elpa/install.html) is the Emacs Lisp
- Package Archive. It brings a real package manager to Emacs.
+Licensed under the EPL. (See the file COPYING.)
View
2 project.clj
@@ -1,4 +1,4 @@
-(defproject swank-clojure "1.2.0-SNAPSHOT"
+(defproject swank-clojure "1.2.1"
:description "Swank server connecting Clojure to Emacs SLIME"
:url "http://github.com/technomancy/swank-clojure"
:dev-dependencies [[org.clojure/clojure "1.2.0-master-SNAPSHOT"]])
View
14 src/leiningen/swank.clj
@@ -0,0 +1,14 @@
+(ns leiningen.swank
+ (:use [leiningen.compile :only [eval-in-project]]))
+
+(defn swank
+ "Launch swank server for Emacs to connect. Optionally takes PORT and HOST."
+ ([project port host & opts]
+ (eval-in-project project
+ `(do (require '~'swank.swank)
+ (@(ns-resolve '~'swank.swank '~'start-repl)
+ (Integer. ~port)
+ ~@(concat (map read-string opts)
+ [:host host])))))
+ ([project port] (swank project port "localhost"))
+ ([project] (swank project 4005)))
View
45 src/swank/commands/basic.clj
@@ -4,7 +4,8 @@
(swank.util.concurrent thread)
(swank.util string clojure)
(swank.clj-contrib pprint macroexpand))
- (:require (swank.util [sys :as sys]))
+ (:require (swank.util [sys :as sys])
+ (swank.commands [xref :as xref]))
(:import (java.io StringReader File)
(java.util.zip ZipFile)
(clojure.lang LineNumberingPushbackReader)))
@@ -398,29 +399,43 @@ that symbols accessible in the current namespace go first."
(defn who-specializes [class]
(letfn [(xref-lisp [sym] ; see find-definitions-for-emacs
- (if-let [meta (and sym (meta sym))]
+ (if-let [meta (and sym (meta sym))]
+ (if-let [path (slime-find-file (:file meta))]
+ `((~(str "(method " (:name meta) ")")
+ (:location
+ ~path
+ (:line ~(:line meta))
+ nil)))
+ `((~(str (:name meta))
+ (:error "Source definition not found."))))
+ `((~(str "(method " (.getName sym) ")")
+ (:error ~(format "%s - definition not found." sym))))))]
+ (let [methods (try (. class getMethods)
+ (catch java.lang.IllegalArgumentException e nil)
+ (catch java.lang.NullPointerException e nil))]
+ (map xref-lisp methods))))
+
+(defn who-calls [name]
+ (letfn [(xref-lisp [sym-var] ; see find-definitions-for-emacs
+ (when-let [meta (and sym-var (meta sym-var))]
(if-let [path (slime-find-file (:file meta))]
- `((~(str "(method " (:name meta) ")")
+ `((~(str (:name meta))
(:location
~path
(:line ~(:line meta))
nil)))
`((~(str (:name meta))
- (:error "Source definition not found."))))
- `((~(str "(method " (.getName sym) ")")
- (:error ~(format "%s - definition not found."
- sym))))))]
- (let [methods (try (. class getMethods)
- (catch java.lang.IllegalArgumentException e nil)
- (catch java.lang.NullPointerException e nil))]
- (map xref-lisp methods))))
+ (:error "Source definition not found."))))))]
+ (let [callers (xref/all-vars-who-call name) ]
+ (map first (map xref-lisp callers)))))
(defslimefn xref [type name]
(let [sexp (ns-resolve (maybe-ns *current-package*) (symbol name))]
- (condp = type
- :specializes (who-specializes sexp)
- :callers nil
- :not-implemented)))
+ (condp = type
+ :specializes (who-specializes sexp)
+ :calls (who-calls (symbol name))
+ :callers nil
+ :not-implemented)))
(defslimefn throw-to-toplevel []
(throw *debug-quit-exception*))
View
51 src/swank/commands/xref.clj
@@ -0,0 +1,51 @@
+(ns swank.commands.xref
+ (:use clojure.walk swank.util)
+ (:import (clojure.lang RT)
+ (java.io LineNumberReader InputStreamReader PushbackReader)))
+
+;; Yoinked and modified from clojure.contrib.repl-utils.
+;; Now takes a var instead of a sym in the current ns
+(defn- get-source-from-var
+ "Returns a string of the source code for the given symbol, if it can
+find it. This requires that the symbol resolve to a Var defined in
+a namespace for which the .clj is in the classpath. Returns nil if
+it can't find the source.
+Example: (get-source-from-var 'filter)"
+ [v] (when-let [filepath (:file (meta v))]
+ (when-let [strm (.getResourceAsStream (RT/baseLoader) filepath)]
+ (with-open [rdr (LineNumberReader. (InputStreamReader. strm))]
+ (dotimes [_ (dec (:line (meta v)))] (.readLine rdr))
+ (let [text (StringBuilder.)
+ pbr (proxy [PushbackReader] [rdr]
+ (read [] (let [i (proxy-super read)]
+ (.append text (char i))
+ i)))]
+ (read (PushbackReader. pbr))
+ (str text))))))
+
+(defn- recursive-contains? [coll obj]
+ "True if coll contains obj. Obj can't be a seq"
+ (not (empty? (filter #(= obj %) (flatten coll)))))
+
+(defn- does-var-call-fn [var fn]
+ "Checks if a var calls a function named 'fn"
+ (if-let [source (get-source-from-var var)]
+ (let [node (read-string source)]
+ (if (recursive-contains? node fn)
+ var
+ false))))
+
+(defn- does-ns-refer-to-var? [ns var]
+ (ns-resolve ns var))
+
+(defn all-vars-who-call [sym]
+ (filter
+ ifn?
+ (filter
+ #(identity %)
+ (map #(does-var-call-fn % sym)
+ (flatten
+ (map vals
+ (map ns-interns
+ (filter #(does-ns-refer-to-var? % sym)
+ (all-ns)))))))))
View
2 src/swank/core.clj
@@ -6,7 +6,7 @@
(:require (swank.util.concurrent [mbox :as mb])))
;; Protocol version
-(defonce *protocol-version* (ref nil))
+(defonce *protocol-version* (atom "20100404"))
;; Emacs packages
(def *current-package*)
View
13 src/swank/swank.clj
@@ -21,7 +21,7 @@
(:gen-class))
(defn ignore-protocol-version [version]
- (dosync (ref-set *protocol-version* version)))
+ (reset! *protocol-version* version))
(defn- connection-serve [conn]
(let [control
@@ -69,12 +69,11 @@
(repl :read (fn [rprompt rexit]
(if @stop rexit
(do (reset! stop true)
- `(do (ignore-protocol-version nil)
- (start-server (-> "java.io.tmpdir"
- (System/getProperty)
- (File. "slime-port.txt")
- (.getCanonicalPath))
- ~@(apply concat opts))))))
+ `(start-server (-> "java.io.tmpdir"
+ (System/getProperty)
+ (File. "slime-port.txt")
+ (.getCanonicalPath))
+ ~@(apply concat opts)))))
:need-prompt #(identity false))))
([] (start-repl 4005)))
View
5 src/swank/util.clj
@@ -39,6 +39,11 @@
(assoc ret k (conj (get ret k []) x))))
{})))))
+(when-not (ns-resolve 'clojure.core 'flatten)
+ (eval '(defn flatten [x]
+ (filter (complement sequential?)
+ (rest (tree-seq sequential? seq x))))))
+
(defmacro returning [[var ret] & body]
`(let [~var ~ret]
~@body
View
4 swank-clojure.el
@@ -15,6 +15,10 @@
;;
;;; Commentary:
;;
+;; NOTE: swank-clojure.el is currently unmaintained. Please see the
+;; swank-clojure readme for examples of how to start a swank server
+;; from your build tool and connect to it via SLIME.
+;;
;; The purpose of this file is to set up `slime-lisp-implementations'
;; to allow SLIME to communicate with the Swank server implemented in
;; Clojure. There are four ways to launch a session:

0 comments on commit 663fb5f

Please sign in to comment.