Skip to content

Commit

Permalink
Added README.md and licensing info.
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan4th committed Nov 28, 2010
1 parent 8abc9e6 commit 93866d9
Show file tree
Hide file tree
Showing 14 changed files with 628 additions and 12 deletions.
45 changes: 42 additions & 3 deletions LICENSE
@@ -1,9 +1,48 @@
Copyright (c) 2010 Ivan Shvedunov. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Client file serving code was adapted from socket.io: Client file serving code was adapted from socket.io:


Copyright (c) 2010 LearnBoost <dev@learnboost.com> Copyright (c) 2010 LearnBoost <dev@learnboost.com>


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:


The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.


THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
263 changes: 263 additions & 0 deletions README.md
@@ -0,0 +1,263 @@
swank-js
========

swank-js provides [SLIME](http://common-lisp.net/project/slime/) REPL
and other development tools for in-browser JavaScript and
[Node.JS](http://nodejs.org). It consists of SWANK backend and
accompanying SLIME contrib. [Socket.IO](http://socket.io/) is used to
communicate with wide range of web browsers.

Motivation
----------

From my experience an ability to use REPL for JavaScript debugging and
interactive development is very helpful when developing Web
applications. Previously I was using a heavily patched
[MozRepl](https://github.com/bard/mozrepl/wiki/) version that was
adapted for in-browser JavaScript. Primary downsides of that approach
were extreme instability of communication between Emacs and the
browser, the lack of cross-browser support and the lack of good RPC
between Emacs and JS that can be used to develop some handy
extensions.

I knew there exists [slime-proxy](https://github.com/3b/slime-proxy)
project that provides such functionality for
[Parenscript](http://common-lisp.net/project/parenscript/). The
problem is that most of us including myself can't use Lisp all the
time and a lot of code needs to be developed using languages like
plain JavaScript (as opposed to Parenscript), Python and so on. My
first thought was to adapt slime-proxy for use with plain JS, but then
I decided to roll my own SWANK backend using Node.JS. I wanted to find
out what this buzz around Node.JS is about and perhaps steal an
idea or two from there for use in my Lisp projects. Another reason was
availability of [Socket.IO](http://socket.io/) and an example of
[tiny http server proxy](http://www.catonmat.net/http-proxy-in-nodejs).

Some people may prefer Firebug or built-in browser development tools
to Emacs-based development, but for example in case of mobile browsers
you don't have much choice. At some point I did try swank-js with an
colleague's iPhone and it worked, which is not too unexpected given
that Socket.IO has good cross-browser support.

Status
------

As of now swank-js provides REPL with an ability to work with multiple
browser connections, supports dynamic updates of JavaScript code using
C-c C-c / C-M-x, provides debug output function and an ability to
reload web pages in the browser or refresh their CSS using Emacs
commands.

Many aspects of full-fledged SWANK backends aren't implemented yet,
there's no debugger/completion/autodoc and so on, but as I plan to use
swank-js a lot in future there's a good chance many of these features
will be eventually added.

Installation
------------

1. Install [Node.JS](http://nodejs.org), [npm](http://npmjs.org/) and
then [Socket.IO](http://socket.io/):

npm install socket.io
2. Get recent [SLIME](http://common-lisp.net/project/slime/) from its CVS
or the [git mirror](http://git.boinkor.net/gitweb/slime.git).
3. Make sure you have latest [js2-mode](http://code.google.com/p/js2-mode/).
Add it to your .emacs:

(add-to-list 'load-path "/path/to/js2-mode/directory")
(autoload 'js2-mode "js2-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
3. Create symbolic link to slime-js.el in the contrib subdirectory of
SLIME project.
4. In your .emacs, add the following lines (you may use other key for
slime-js-reload; also, if you're already using SLIME, just add slime-js
to the list of contribs, otherwise adjust the load-path item):

(add-to-list 'load-path "/path/to/slime/installation")
(require 'slime)
(slime-setup '(slime-repl slime-js))

(global-set-key [f5] 'slime-js-reload)
(add-hook 'js2-mode-hook
(lambda ()
(slime-js-minor-mode 1)))
5. If you're using CSS mode, you may want to add the following lines too:

(add-hook 'css-mode-hook
(lambda ()
(define-key css-mode-map "\M-\C-x" 'slime-js-refresh-css)))

Usage
-----

Start swank-js with the following command in the project directory:

node swank.js

Make SLIME connect to the backend using M-x slime-connect and
specifying localhost and port 4005. You will see REPL buffer with the
following prompt:

NODE>

This means that you're currently talking to Node.JS. You may play
around with it by running some JavaScript expressions.

If you get warning about SLIME version mismatch, you may make it
disappear until the next SLIME upgrade by typing *,js-slime-version*
at the REPL and entering your SLIME version (e.g. 2010-11-13).

Point your web browser to

http://localhost:8009/swank-js/test.html
You will see the following message appear in the REPL (browser name
and version may differ):

Remote attached: (browser) Firefox3.6:127.0.0.1

This means that the browser is now connected. Several browsers can
connect simultaneously and you can switch between them and Node.JS
REPL using *,select-remote* REPL shortcut. To use it, press ','
(comma) and type *select-remote* (completion is supported). You will
see "Remote:" prompt. Press TAB to see completions. Select your
browser in the list by typing its name or clicking on the
completion. The following message will appear:

Remote selected: (browser) Firefox3.6:127.0.0.1
NODE>
FIREFOX-3.6>

After that, you can interactively evaluate expressions in your
browser. To go back to Node.JS repl, switch back to node.js/direct
remote. (Note that output always goes before consecutive REPL prompts,
I'll try to fix it in following versions).

FIREFOX-3.6> document.body.nodeName
BODY
FIREFOX-3.6> alert("test!")
FIREFOX-3.6>

When working with browser, you may use F5 to reload the page. swank-js
connection with browser is lost in this case, but to solve this
problem you may use *,sticky-select-remote* instead of
*,select-remote*. This way swank-js will remember your selection and
automagically attach to the browser whenever it connects. If you press
F5 after using *,sticky-select-remote*, you will see that browser
briefly disconnects but then connects again:

Remote detached: (browser) Firefox3.6:127.0.0.1
Remote selected (auto): (direct) node.js
Remote attached: (browser) Firefox3.6:127.0.0.1
Remote selected (auto): (browser) Firefox3.6:127.0.0.1
FIREFOX-3.6>
NODE>
FIREFOX-3.6>

The sticky remote selection is saved in the config file, ~/.swankjsrc,
so you don't need to do *,sticky-select-remote* after restarting the
browser.

Now, let's try to make it work with an actual site. swank-js acts as a
proxy between your browser and the site so it can inject necessary
script tags into HTML pages and avoid cross-domain HTTP request
problems. Let's point it to [reddit](http://www.reddit.com). Type
*,target-url* and then *http://www.reddit.com* (www. part is
important, otherwise it will redirect to www.reddit.com skipping the
proxy). Point your browser to http://localhost:8009, you'll see reddit
frontpage load. If you didn't do *,select-remote* or
*,sticky-select-remote* yet do it now and select your browser from the
list of remotes. Now you can execute JavaScript in the context of
reddit:

FIREFOX-3.6> $(".sitetable a.title").map(function(n) { return (n + 1) + ". " + $(this).text(); }).get().join("\n")
1. Wikileaks currently under a mass DDOS attack
2. Munich University - Jealous
...

Let's make a function from it. Create a file test.js somewhere and
make sure it uses js2-mode (if it doesn't, switch it to js2-mode using
M-x js2-mode). Type the following there:

function listRedditTitles () {
$(".sitetable a.title").map(
function (n) {
SwankJS.output((n + 1) + ". " + $(this).text() + "\n");
}).get().join("\n");
}

Note SwankJS.output() function being used there. It allows you to send
debug print to SLIME REPL.

Move the point somewhere into the middle of the listRedditTitles() function
and press C-M-x. Now you may try it out in the REPL:

FIREFOX-3.6> listRedditTitles()
1. Wikileaks currently under a mass DDOS attack
2. Munich University - Jealous
...

You may edit the function definition and update it using C-M-x any
number of times.

Now let's try some CSS hacking. Create a directory named zzz and start
a Web server in it from your command prompt:

$ mkdir zzz && cd zzz && python -mSimpleHTTPServer

Create a file named a.css there and make sure it uses css-mode (like
with js2-mode, you can force it with M-x css-mode). Add some CSS rules
to this file:

body {
background: green;
}

Now let's add the stylesheet to the reddit page:

FIREFOX-3.6> $('head').append('<link rel="stylesheet" href="http://localhost:8000/a.css" type="text/css" />');
[object Object]

You will see some parts of the page become green. Now, change green to
blue in the CSS file and press C-M-x (it will save the file
automatically):

body {
background: blue;
}

You will see the page become blue, maybe after some flickering as all
CSS used on the page is reloaded. This way you may update CSS in an
AJAX application without reloading the page, which is often rather
handy. Unlike editing CSS in Firebug in case when you're editing CSS
of your own application changes will not disappear upon page reload
(with reddit page you'll have to readd the stylesheet).

Troubleshooting
---------------

I've noticed that flashsocket Socket.IO transport does exhibit some
instability. You may want to try other transports by changing the
socketio cookie, e.g.:

document.cookie = "socketio=xhr-polling"

Be careful not to lose connection to the browser though especially in
case of REPL-less browser like IE6/7 or you'll have to type something
like

javascript:void(document.cookie = "socketio=flashsocket")

in the address bar.

In case of IE, increasing the maximum number of HTTP connections may
help with non-Flash transports, although I didn't try it yet. To do it
add DWORD value MaxConnectionsPer1_0Server to the following registry
key:

HKEY\_CURRENT\_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings

License
-------

swank-js is distributed under X11-style license. See LICENSE file.
27 changes: 27 additions & 0 deletions client/swank-js.js
@@ -1,3 +1,30 @@
//
// Copyright (c) 2010 Ivan Shvedunov. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var SwankJS = { socket: null, connected: false, bufferedOutput: [] }; var SwankJS = { socket: null, connected: false, bufferedOutput: [] };


// TBD: check message contents // TBD: check message contents
Expand Down
27 changes: 27 additions & 0 deletions config.js
@@ -1,4 +1,31 @@
// -*- mode: js2 -*- // -*- mode: js2 -*-
//
// Copyright (c) 2010 Ivan Shvedunov. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var path = require("path"), fs = require("fs"); var path = require("path"), fs = require("fs");


function Config (fileName) { function Config (fileName) {
Expand Down

0 comments on commit 93866d9

Please sign in to comment.