Gauche Devlog

< ERR5RS Records and beyond | Enhanced queue >

2010/04/26

Better REPL?

Gosh's default REPL provides bare minimum features. I almost always run gosh inside Emacs and usually it's fine, but sometimes I do feel it can be better.

So I'm experimenting ideas here: http://gauche.svn.sourceforge.net/viewvc/gauche/Gauche-scripts/trunk/xrepl/

Here are some stuff I have. I'll use it for a while to see if it's worth to be included into gosh or not. Other ideas and feedbacks are welcome.

Prettyprinting the result

It has rudimental pretty printer (which is a bit dumb; it may take exponential time for large S-expr that I need to fix). Ideally pretty printer should be a part of Gauche, integrated with built-in format etc.

gosh> (call-with-input-string
          (values-ref (http-get "blog.practical-scheme.net" "/gauche") 2)
        (cut ssax:xml->sxml <> '()))
(*TOP*
 (html
  (head
   (title "Gauche Devlog")
   (base (|@| (href "http://blog.practical-scheme.net/gauche")))
   (link
    (|@| (type "application/rss+xml") (title "RSS") (rel "alternate")
     (href "http://blog.practical-scheme.net/gauche?c=rss")))
   (link (|@| (type "text/css") (rel "stylesheet") (href "blog.css")))
   (link (|@| (type "text/css") (rel "stylesheet") (href "gauche-devlog.css"))))
  (body
...

History

Accessing recent evaluation results. This feature has been sitting long in my wishlist, but I couldn't make up my mind of what symbols I would use; CL uses *, **, ***, ... but in Scheme * would conflict with the built-in function. I finally decided to adapt Clojure's convention; *1 refers to the last evaluated result, *2 for the second last, etc.

gosh> *1
(*TOP*
 (html
  (head
   (title "Gauche Devlog")
...
gosh> (length (cadr *1))
3

The procedure *history prints the list of history.

*1, *2, ... only keeps the first value of the result(s). In case if we have more than one values, *1+, *2+, ... keeps the list of values.

If the last evaluation ends as an error, the condition object is bound to *e.

gosh> (car 3)
*** ERROR: pair required, but got 3
Stack Trace:
_______________________________________
  0  (with-error-handler (lambda (e) (let ((e e)) (%guard-rec e e (else ...
        [unknown location]
gosh> *e
#<error "pair required, but got 3">

Shell-like commands

You can type shell commands by leading it with a comma:

gosh> ,cd ~/src/Gauche
/home/shiro/src/Gauche
gosh> ,ls
AUTHORS       README          configure.ac       ltmain.sh
COPYING       VERSION         configure.ac.orig  m4/
ChangeLog     acinclude.m4    doc/               missing*
DIST*         aclocal.m4      examples/          mkinstalldirs*
DIST_EXCLUDE  config.guess*   ext/               rpmfiles-common.txt
Gauche.spec   config.log      framework.sh*      rpmfiles-encoding.txt
HACKING       config.rpath*   gc/                rpmfiles-gdbm.txt
INSTALL.in    config.status*  gc.diff            src/
Makefile      config.sub*     install-sh*        test/
Makefile.in   config.threads  lib/               test.record
NEWS          configure*      libsrc/            winnt/
gosh> ,make -j
for d in gc src lib ext doc; do (cd $d; make all); done
make[1]: Entering directory `/home/shiro/src/Gauche/gc'
...

Sometimes I'm too lazy to switch from *scheme* buffer to *shell* buffer (or, more like that I forget to switch and am annoyed by getting 'unbound variable: ls').

It would be nicer if I can easily grab the shell output into Scheme variable, and feed the content of Scheme variable into shell commands.

Smarter (or verbose) error handling

I'm not sure I'll keep this one, but giving a try.

"." isn't in *load-path* by default, for the obvious security reasons. But sometimes I forget to type "./foo.scm" and being annoyed, for I know foo.scm in the current dir is safe. So, here's a little help...

gosh> (load "t.scm")
*** REPL: Cannot load file "t.scm" in *load-path* ("../lib" "../libsrc" "../src" "/usr/share/gauche/site/lib" "/usr/share/gauche/0.9.1_pre1/lib" "/usr/share/gauche/0.9/lib" "/home/shiro/src/Gauche-scripts/xrepl/")
But you have the file under the current directory.
Do you want to add "." in *load-path*? (y/n): 

This is actually implemented in more general "error filter" framework. When REPL gets an error, a series of registered tests are run, and if there's a match, an associated action is invoked.

This kind of thing may be too annoying (in fact, I don't even like CL implementations entering the debugger on error by default.) But I'll see.

Tag: repl

Post a comment

Name: