The following works for me: *DISCLAIMER: Use at own risk. Exercise care. Make backups of anything you change.* On linux, you need to have built your clisp with the "--with-modules=bindings/linuxlibc6" option, and you should *not* have compiled it without readline. See the build instructions and Makefile. STEP 1 Put /usr/bin/clisp in /etc/shells so it looks (something like) this: # /etc/shells: valid login shells #/bin/ash /bin/bash /bin/sh /usr/bin/clisp STEP 2 You can set up your $PATH In /etc/login.defs by modifying the entry for ENV_PATH to look (something) like this: ENV_PATH PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin This is so you can run X. [Once you have your clisp shell set up, you can control the environment variables (on Linux) via the linuxlibc6 bindings (see $clisp-src/modules/bindings/linuxlibc6/linux.lisp): setenv, putenv, getenv, etc] STEP 3 The "startx" command is a shell script, so we can't use it. As a temporary fix, I have defunned thus: (defun startx () (execute "/usr/X11R6/bin/xinit")) Which works for me. Although I haven't investigated all the consequences of not going via shell's startx. Also I *don't* use GNOME or KDE which may complicate things for you if you do. I use fvwm2 and have this in my .xinitrc: exec fvwm2 STEP 4 (some guru will probably shoot this down in flames) For conveniently running external programs (ie, I don't want to have to type (run-program "ls" :arguments '("-lh")) every time, I have set up a read macro. Put the following in somefile.lisp. (set-macro-character #\] (get-macro-character #\))) (set-dispatch-macro-character #\# #\[ #'(lambda (stream char1 char2) (setf (readtable-case *readtable*) :preserve) (UNWIND-PROTECT (LET* ((OUTPUT-STREAM (MAKE-STRING-OUTPUT-STREAM :ELEMENT-TYPE 'BASE-CHAR)) (STEP1 (FORMAT OUTPUT-STREAM "(RUN-PROGRAM ")) (COMMAND-LINE (READ-DELIMITED-LIST #\] STREAM T)) (COMMAND (FIRST COMMAND-LINE)) (STEP2 (FORMAT OUTPUT-STREAM "\"~A\" :ARGUMENTS " COMMAND)) (PARAMETERS (REST COMMAND-LINE)) (STEP3 (FORMAT OUTPUT-STREAM "'("))) (DOLIST (X PARAMETERS (PROGN (FORMAT OUTPUT-STREAM "))") (LET ((CLEAN (GET-OUTPUT-STREAM-STRING OUTPUT-STREAM))) (CLOSE OUTPUT-STREAM) (VALUES (READ-FROM-STRING CLEAN))))) (FORMAT OUTPUT-STREAM "\"~A\" " X))) (SETF (READTABLE-CASE *READTABLE*) :UPCASE)))) You will get (harmless) warnings from the compiler about unused variables STEP*, if you compile this file. You must keep the upper case stuff as is. (It could also be all upcase). STEP 5 It's also a PITA to have to type "#[" and "]" everytime you want to run a command, so add the following in your $HOME/.inputrc #for clash: prints the square brackets to run an external command "\ec": "#\C-b" When you type ESC-c (or META-c) readline will print "#" to the console and put the cursor inside the brackets. If you are running clisp as your shell, and do this, you will then be able to run programs (more or less) normally. You will need to escape the dot in any filenames with a dot in them: #[cat \.xinitrc] STEP 6 Now try it out-- *Don't* modify your /etc/passwd yet! -- Start up a clisp with "clisp -k full", and load somefile.lisp (the read-macro) into a CLISP which has readline compiled in. Hit "ESC c", type "ls -l", and see if it works. You *don't* have command line completion for external programs inside the read-macro. So hitting tab will just give you a list of all clisp's possibilties, which is not much use here. However, "run-program" does search your path for executables so you don't have to do #[/bin/ls -l] Also, I haven't (yet) written lisp versions of "cd" and the other bash builtins. But this is easy with the libc6 bindings, (chdir etc). Another convenience thing you can do is stuff like this for often used commands: (defmacro ls-lh () `#[ls -lh]) Now (ls-lh) reads as (run-program "ls" :arguments '("-lh")) STEP 7 If you are happy, and think you can live with this setup then you must do the following: -Dump a memory image from a clisp with the read macro and any convenience stuff loaded: (saveinitmem "lispinit.mem" :quiet t) The :quiet t suppresses clisp's start up message, which I find annoying. If you have some function you want to run every time clisp starts, you can also specify this (see impnotes.html). -Make a backup of /usr/[local]/lib/clisp. (wherever your's is installed) -Rename the "base" directory in /usr/lib/clisp to "orig-base". -Now rename the "full" directory to "base". -Replace the memory image in your *new* "base" directory with the one you dumped. STEP 8 Change your /etc/passwd to reflect your new shell. Light 13 candles in a circle round your Linux box, sacrifice a white rooster, invoke Saint IGNUcious and ... Login again. If you start pining for Bash, you can run: #[bash] And explicitly source all your configuration files (.profile etc) -------------------------------------------------------------------- It works for me. Now I just need to work out how to: get indentation on the command line. do command redirection. get name completion for arguments which are filenames. Piece of cake! (But don't hold your breath)
I've changed the macro a little so you don't have to type built-ins like cd a different way. I'll work on making this portable and nice next. I'm only a newbie so if this is ugly please tell me. Still don't have the other stuff to make this a nice swap for bash.
(defun command-line-command-equal (command-line command) (if (string-equal command (car command-line)) (list command (string-downcase (string (second command-line)))) nil)) (set-macro-character #\] (get-macro-character #\))) (set-dispatch-macro-character #\# #\[ (lambda (stream char1 char2) (declare (ignore char1 char2)) (setf (readtable-case *readtable*) :preserve) (unwind-protect (let ((command-line (read-delimited-list #\] stream t))) (cond ((command-line-command-equal command-line 'cd)) (t (list 'ext:run-program (princ-to-string (car command-line)) :arguments `',(mapcar #'princ-to-string (rest command-line)))))) (setf (readtable-case *readtable*) :upcase))))