;;; Load Emacs-Lisp files into Common Lisp ;;; ;;; Copyright (C) 1999-2000 by Sam Steingold ;;; This is Free Software, covered by the GNU GPL (v2) ;;; See http://www.gnu.org/copyleft/gpl.html ;;; ;;; $Id: elisp.lisp,v 2.10 2002/03/18 20:40:22 sds Exp $ ;;; $Source: /cvsroot/clocc/clocc/src/cllib/elisp.lisp,v $ (eval-when (compile load eval) (require :cllib-base (translate-logical-pathname "clocc:src;cllib;base")) ;; `make-clos-readtable' (require :cllib-closio (translate-logical-pathname "cllib:closio")) ;; `from-list' (require :cllib-list (translate-logical-pathname "cllib:list"))) (in-package :cllib) (defpackage emacs-lisp #-allegro (:documentation "The package for loading Emacs-Lisp code into Common Lisp") (:nicknames "ELISP" "EL") (:use "CL" "CLLIB" "PORT") (:shadow let let* if member delete load require provide ignore format / defcustom defconst autoload)) (defconst +elisp-pack+ package (find-package :el) "The Emacs-Lisp package.") ;;; ;;; Emacs-Lisp-specific special forms ;;; (defmacro el::if (ii tt &rest ee) "Emacs-Lisp version of `if' (multiple `else' clauses)." (if ee `(if ,ii ,tt (progn ,@ee)) `(if ,ii ,tt))) (defmacro el::let ((&rest vars) &rest forms) "Emacs-Lisp version of `let' (everything special)." `(let ,vars (declare (special ,@(mapcar #'from-list vars))) ,@forms)) (defmacro el::let* ((&rest vars) &rest forms) "Emacs-Lisp version of `let*' (everything special)." `(let* ,vars (declare (special ,@(mapcar #'from-list vars))) ,@forms)) (defmacro el::while (cc &body forms) "Emacs-Lisp `while'." `(do () ((not ,cc)) ,@forms)) ;;; ;;; Read Emacs-Lisp objects ;;; (eval-when (compile load eval) ; CMUCL for `+elisp-readtable+' (defun el::read-elisp-special (stream char) (declare (stream stream) (character char)) (ecase char (#\[ (coerce (read-delimited-list #\] stream t) 'vector)) (#\" (coerce (loop :with char-to-add :and next-char :for this-char = (read-char stream t nil t) :until (char= this-char #\") :if (char= this-char #\\) :do (setq char-to-add (case (setq next-char (read-char stream t nil t)) (#\n #\Newline) (#\r #\Return) (#\f #\Page) (#\t #\Tab) (#\v #\Linefeed) (t next-char))) :else :do (setq char-to-add this-char) :collect char-to-add) 'string)) (#\? (loop :for cc :of-type character = (read-char stream t nil t) :collect (if (char/= cc #\\) cc (ecase (read-char stream t nil t) (#\C (read-char stream t nil t) :control) (#\^ :control) (#\S (read-char stream t nil t) :shift) (#\M (read-char stream t nil t) :meta) (#\s (read-char stream t nil t) :super) (#\H (read-char stream t nil t) :hyper) (#\n (setq cc #\Null) #\Newline) (#\t (setq cc #\Null) #\Tab) (#\r (setq cc #\Null) #\Return))) :into res :finally (return (if (characterp (car res)) (car res) res)) :while (char= cc #\\))))) (defun el::make-elisp-readtable () "Make the readtable for Emacs-Lisp parsing." (let ((rt (make-clos-readtable))) (set-macro-character #\? #'el::read-elisp-special nil rt) (set-macro-character #\[ #'el::read-elisp-special nil rt) (set-macro-character #\" #'el::read-elisp-special nil rt) ;; (setf (readtable-case rt) :downcase) rt)) ) (defconst +elisp-readtable+ readtable (el::make-elisp-readtable) "The readtable for Emacs-Lisp parsing.") ;;; bug in ACL and CMUCL #+nil (progn (defun read-vector (stream char) (coerce (read-delimited-list #\] stream t) 'vector)) (set-syntax-from-char #\[ #\() (set-syntax-from-char #\] #\)) (set-macro-character #\[ #'read-vector nil) (set-macro-character #\] (get-macro-character #\)) nil) (read-from-string "[1 2 3]") (read-from-string "#\\x") (read-from-string "[#\\x]") ) ;;; ;;; Emacs-Lisp-specific functions ;;; (defun el::memq (elt list) (member elt list :test #'eq)) (defun el::delq (elt list) (delete elt list :test #'eq)) (defun el::member (elt list) (member elt list :test #'equal)) (defun el::delete (elt list) (delete elt list :test #'equal)) (defun el::concat (&rest args) (apply #'concatenate 'string args)) (defun el::message (&rest args) (apply #'format t args)) (defun el::format (&rest args) (apply #'format nil args)) (defun el::put (symbol propname value) (setf (get symbol propname) value)) (defun el::fset (symbol def) (if (null def) (fmakunbound symbol) (setf (fdefinition symbol) (if (functionp def) def (fdefinition def))))) (defun el::setcar (cons obj) (setf (car cons) obj)) (defun el::setcdr (cons obj) (setf (cdr cons) obj)) (defun el::ignore (&rest ignore) (declare (ignore ignore)) nil) (defun el::sit-for (sec &optional (ms 0) nodisp) (declare (real sec ms) (ignore nodisp)) (sleep (+ sec (/ ms 1000)))) (defun el::string-to-number (string &optional (base 10)) (if (= base 10) (read-from-string string) (parse-integer string :radix base))) (defun el::/ (&rest args) (if (every #'integerp args) (reduce #'floor (cdr args) :initial-value (car args)) (apply #'/ args))) (defun el::decode-time (&optional (time (get-universal-time))) (unless (numberp time) (setq time (+ (ash (car time) 16) (if (numberp (cdr time)) (cdr time) (cadr time))))) (multiple-value-bind (sec minute hour day month year dow dst zone) (decode-universal-time time) (list sec minute hour day month year (mod (1+ dow) 7) dst (* 3600 zone)))) (defun el::encode-time (second minute hour day month year &rest zone) (encode-universal-time second minute hour day month year (car (last zone)))) ;; defalias is a function in Emacs, cannot use defmacro ;; a simple (setf fdefinition) is no good ;; since Emacs defalias works on macros too (defun el::defalias (symbol def) (eval `(defmacro ,symbol (&body body) (list* ',def body)))) (defmacro el::defgroup (&rest args) (declare (ignore args))) (defmacro el::defcustom (var val doc &key (type t) &allow-other-keys) (let ((type (if (and (consp type) (eq 'quote (car type))) (cadr type) type))) `(progn (declaim (type ,type ,var)) (defvar ,var ,val ,doc)))) (defmacro el::defface (name val doc &rest args) (declare (ignore args)) `(defvar ,name ,val ,doc)) (defmacro el::defconst (name val doc) `(defconstant ,name ,val ,doc)) (defmacro el::eval-when-compile (&rest body) `(eval-when (compile load) ,@body)) (defmacro el::setq-default (&rest body) `(setq ,@body)) (defmacro el::save-window-excursion (&rest body) `(progn ,@body)) (defmacro el::save-excursion (&rest body) `(progn ,@body)) (defmacro el::with-output-to-temp-buffer (&rest body) `(progn ,@body)) (defsubst el::number-to-string (number) (write-to-string number :radix 10)) (defsubst el::int-to-string (number) (el::number-to-string number)) (defsubst el::char-to-string (char) (string char)) (defsubst el::string-to-int (&rest args) (apply #'el::string-to-number args)) (defsubst el::file-truename (file) (truename file)) (defsubst el::file-exists-p (file) (probe-file file)) (defsubst el::substring (seq from &optional to) (subseq seq from to)) (defsubst el::% (x y) (rem x y)) (defsubst el::file-directory-p (ff) (probe-directory ff)) (defsubst el::sref (ar ix) (aref ar ix)) (defsubst el::set-default (sy va) (set sy va)) (defsubst el::default-value (sy) (symbol-value sy)) (defun el::run-hooks (&rest hooks) (labels ((rh (hook) (etypecase hook (list (dolist (hk hook) (rh hk))) ((or symbol function) (funcall hook))))) (dolist (hk hooks) (when (boundp hk) (rh (symbol-value hk)))))) (defun el::add-hook (hook function &optional append local) (declare (ignore local)) (let ((val (if (boundp hook) (symbol-value hook) nil))) (when (or (functionp val) (symbolp val)) (setq val (list val))) (unless (member function val :test #'equal) (setf (symbol-value hook) (if append (append val (list function)) (cons function val)))))) (defun el::remove-hook (hook function &optional local) (declare (ignore local)) (when (and (boundp hook) (symbol-value hook) function) (let ((val (symbol-value hook))) (if (or (functionp val) (symbolp val)) (when (eq val function) (setf val nil)) (setf (symbol-value hook) (remove function val :test #'equal)))))) (defun el::add-to-list (list el) (unless (boundp list) (setf (symbol-value list) nil)) (pushnew el (symbol-value list) :test #'equal)) ;;; tmp hacks (defmacro defun-fake (func) `(defun ,func (&rest args) (warn "~s [~{~s~^ ~}]: not implemented yet" ',func args) (values-list args))) (defun-fake el::define-key) (defun-fake el::make-sparse-keymap) (defun-fake el::substitute-key-definition) (defun-fake el::interactive) (defun-fake el::make-help-screen) (defun-fake el::help-for-help) (defun-fake el::start-kbd-macro) (defun-fake el::substitute-command-keys) (defun-fake el::display-color-p) (defun-fake el::propertize) (defun-fake el::make-mode-line-mouse-map) (defvar el::global-map (el::make-sparse-keymap)) (defvar el::help-char (code-char 8)) (defvar el::help-form nil) (defvar el::window-system nil) (defvar el::mode-line-format nil) (defvar el::buffer-read-only nil) (defvar el::indent-tabs-mode nil) (deftype el::sexp () 'list) (deftype el::file () 'string) (deftype el::hook () '(or list symbol)) (defun el::mapconcat (function sequence separator) ;; (el::mapconcat #'identity '("a" "b" "c") " ") ==> "a b c" (apply #'concatenate 'string (cdr (mapcan (lambda (el) (list separator el)) (map 'list function sequence))))) (defun to-directory (path) (if (char= #\/ (schar path (1- (length path)))) path (concatenate 'string path "/"))) (defun el::directory-files (directory &optional full match nosort) ;; incomplete (declare (ignore full nosort)) (let ((dir (to-directory directory))) (directory (if match (merge-pathnames match dir) dir)))) (defun el::expand-file-name (name &optional (default-dir (default-directory))) (namestring (merge-pathnames (to-directory default-dir) name))) (defun el::autoload (function file &optional docstring interactive type) (declare (symbol function) (type (or simple-string null) docstring) (ignore interactive type)) (unless (fboundp function) (setf (fdefinition function) (lambda (&rest args) (setf (documentation function 'function) nil) (fmakunbound function) (format t "; ~s is being autoloaded from `~a'~%" function file) (el::load file) (apply function args)) (documentation function 'function) (format nil "Autoloaded (from ~a)~@[:~%~a~]" file docstring)))) ;;; ;;; Load Emacs-Lisp files ;;; (defvar el::emacs-home #+(or mswindows win32) "d:/gnu/emacs/" #-(or mswindows win32) "/usr/local/src/emacs/") (defvar el::site-lisp-dir #+(or mswindows win32) "c:/gnu/sitelisp/" #-(or mswindows win32) "/usr/local/share/emacs/site-lisp/") (defvar el::load-path (list (concatenate 'string el::emacs-home "lisp/") (concatenate 'string el::emacs-home "leim/") el::site-lisp-dir)) (defvar el::features nil) (defun el::featurep (feature) (el::memq feature el::features)) #+allegro (pushnew "el" sys:*source-file-types* :test #'equal) #+cmu (pushnew "el" ext::*load-source-types* :test #'equal) #+clisp (pushnew "el" custom:*source-file-types* :test #'equalp) #+lispworks (pushnew "el" system:*text-file-types* :test #'equal) #+gcl (error 'not-implemented :proc 'file-types) (defun locate-file (file &optional source-only) (flet ((file-here (dir) ;; search the local files (let ((ff (merge-pathnames file dir))) (when (and (ignore-errors (probe-file ff)) (not (probe-directory ff))) (return-from locate-file ff))) (unless source-only (let ((ff (merge-pathnames (compile-file-pathname file) dir))) (when (probe-file ff) (return-from locate-file ff)))) (let ((ff (merge-pathnames (concatenate 'string file ".el") dir))) (when (probe-file ff) (return-from locate-file ff))))) (dolist (path el::load-path) (let ((dir (to-directory path))) (file-here dir) ;; search the subdirectories (dolist (sub-dir (directory (concatenate 'string dir "*/"))) (file-here sub-dir)))))) (defun el::load (file &optional noerror nomessage nosuffix must-suffix) "Emacs-Lisp load. The suffix stuff is ignored." (declare (ignore nosuffix must-suffix)) (let ((*readtable* +elisp-readtable+) (*package* +elisp-pack+) (ff (locate-file file))) (if ff (load ff :verbose (not nomessage)) (unless noerror (error "file `~a' not found" file))))) (defun el::require (feature &optional file-name noerror) "Emacs-Lisp require" (unless (el::featurep feature) (let ((file (or file-name (string-downcase (string feature))))) (el::load file noerror) (assert (el::featurep feature) () "loading `~a' failed to provide `~a'" file feature))) feature) (defun compile-el-file (file) (let ((*readtable* +elisp-readtable+) (*package* +elisp-pack+) (ff (or (locate-file file t) file))) (compile-file ff))) (defun el::provide (feature) (pushnew feature el::features)) ;; (in-package :cl-user) ;; (in-package :emacs-lisp) ;; (el::load "backquote") ;; (el::load "calendar") ;; (el::load "cal-hebrew") ;; (el::load "subr") ;; (el::load "help") ;; (cllib::locate-file "calendar") ;; (cllib::compile-el-file "backquote") ;; (cllib::compile-el-file "calendar") ;; (cllib::compile-el-file "cal-hebrew") ;; (el::calendar-hebrew-date-string) (provide :cllib-elisp) ;;; file elisp.lisp ends here