Emacs


GNU Emacs

"What is an Emac, anyway?"
"And why do you need several of them to edit text?"
        -- as seen on Slashdot.Org

[image]

Emacs is an acronym for Editor MACroS. Most often it refers to GNU Emacs, an editor with a built-in Lisp interpreter that understands a particular dialect of Lisp called Emacs-Lisp?. This editor is one of the best editors (some would say _the_ best) for editing Lisp code.

Most dialects of Lisp are supported, and Emacs can be extended to support those that aren't. Functionality can be extended by writing elisp, to be executed by Emacs' interpreter. Everything from Tetris (a game of falling blocks) to an IRC client (ERC) have been written in Emacs Lisp. It's available for many, many platforms and operating systems. More details can be found on its webpage: http://www.gnu.org/software/emacs/

Stallman's paper on Emacs is at http://www.gnu.org/software/emacs/emacs-paper.html.


Could someone post some good .emacs settings for scheme?

Some example .emacs settings

;;; The basic settings
(setq scheme-program-name "scheme48"
      scheme-mit-dialect nil)

;;; Tell emacs about your special interpreters. This is from the #!
;;; line.
(add-to-list 'interpreter-mode-alist '("scsh" . scheme-mode))

;;; You want quack. Really.
(require 'quack)

;;; Can you please explain what I `really want' from Quack?

(setq quack-fontify-style 'emacs
      quack-default-program "scheme48"
      quack-newline-behavior 'newline)

;;; Examples for quick documentation access. Quack does similar stuff.
;;; (So does <http://twb.ath.cx/~twb/canon/scheme-lookup/>,
;;; without the extra baggage of Quack.)

(defun s48-doc ()
  "Browse the Scheme48 documentation."
  (interactive)
  (browse-url "file:///usr/share/doc/scheme48/html/s48manual.html"))

(defun scsh-doc ()
  "Browse the scsh documentation."
  (interactive)
  (browse-url "file:///usr/share/doc/scsh-doc/scsh-manual/html/man-Z-H-1.html"))

;;; Tell emacs about the indentation of some not-so-well-known
;;; procedures.

;; If you are running scheme48 download scheme48.el from 
;; http://www.emacswiki.org/cgi-bin/wiki/Scheme48Mode
;; And add this provide 
(require 'scheme48)

;; gauche
(put 'with-error-handler 'scheme-indent-function 1)     ; 'defun)
(put 'with-exception-handler 'scheme-indent-function 1)
(put 'with-exit-exception-handler 'scheme-indent-function 1)
(put 'with-exit-exception-handler* 'scheme-indent-function 2)
(put 'my-with-exception-handler 'scheme-indent-function 2)
(put 'for-debug 'scheme-indent-function 'defun)
(put 'test-expected 'scheme-indent-function 'defun)
(put 'call-with-input-string 'scheme-indent-function 1)
(put 'with-port-locking 'scheme-indent-function 1)

Indenting receive

;; A customized indentation function for receive.
;; It is adapted from lisp-indent-specform.

;; This will indent RECEIVE as follows:
;; (receive params
;;          producer
;;   receiver)
;; instead of the `put' form above, which will indent as follows:
;; (receive params
;;     producer
;;   receiver)

;; Note: This could be made into a generalized function
;;   if it would be useful for other scheme functions.

(defun scheme-indent-receive (state indent-point normal-indent)
  (let ((containing-form-start (nth 1 state))
        (i 0)
        containing-form-column)
    ;; <snip documentation>
    (goto-char containing-form-start)
    (setq containing-form-column (current-column))
    (forward-char 1)
    (forward-sexp 1)
    ;; Now find the start of the last form.
    (parse-partial-sexp (point) indent-point 1 t)
    (while (and (< (point) indent-point)
                (condition-case ()
                    (progn
                      (setq i (1+ i))
                      (forward-sexp 1)
                      (parse-partial-sexp (point) indent-point 1 t))
                  (error nil))))
    ;; Point is sitting on first character of last (or count) sexp.
    (cond ((= i 0)
           (+ containing-form-column (* 2 lisp-body-indent)))
          ((= i 1) normal-indent)
          (t (+ containing-form-column lisp-body-indent)))))

;; tell emacs to use this function for indenting receive
(put 'receive 'scheme-indent-function 'scheme-indent-receive)

Indenting with-... and call-with-...

This snippet indents arguments to any operator named with-... or call-with-... (for any value of the ellipsis) such that the last argument is indented with two spaces, while the other arguments are indented with four. (Actually, it's value of lisp-indent-body versus twice the value of lisp-indent-body; that variable's value is, however, usually 2.) For example,

 (call-with-frobnicator frob grovel 
     (full-lexical mumble) 
   (lambda (frobnicator) 
     ...)) 

This hack relies on the usage of paredit.el, an Emacs minor mode for always editing valid structure in code, rather than working only with individual characters; this hack needs paredit in order to ensure that the way it tests the last versus other arguments to with-... & call-with-... forms, walking backward from the end of the expression, is valid.

(eval-after-load "scheme"
  ;; Ensure that this is run after scheme.el, so it won't be clobbered,
  ;; since we're redefining `scheme-indent-function'.
  '(progn

;;; This is a *slightly* modified version of what is in scheme.el,
;;; which is itself a slight modification of `lisp-indent-function'
;;; from lisp-mode.el.  Gee, you'd think that someone would think of
;;; the notion of 'abstraction' here...

(defun scheme-indent-function (indent-point state)
  (let ((normal-indent (current-column)))
    (goto-char (1+ (elt state 1)))
    (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
    (if (and (elt state 2)
             (not (looking-at "\\sw\\|\\s_")))
        ;; car of form doesn't seem to be a symbol
        (progn
          (if (not (> (save-excursion (forward-line 1) (point))
                      calculate-lisp-indent-last-sexp))
              (progn (goto-char calculate-lisp-indent-last-sexp)
                     (beginning-of-line)
                     (parse-partial-sexp (point)
                                         calculate-lisp-indent-last-sexp 0 t)))
          ;; Indent under the list or under the first sexp on the same
          ;; line as calculate-lisp-indent-last-sexp.  Note that first
          ;; thing on that line has to be complete sexp since we are
          ;; inside the innermost containing sexp.
          (backward-prefix-chars)
          (current-column))
      (let ((function (downcase         ;** downcasage added by TRC
                       (buffer-substring (point)
                                         (progn (forward-sexp 1) (point)))))
            method)
        (setq method (or (get (intern-soft function) 'scheme-indent-function)
                         (get (intern-soft function) 'scheme-indent-hook)))
        (cond ((or (eq method 'defun)
                   (and (null method)
                        (> (length function) 3)
                        (string-match "\\`def" function)))
               (lisp-indent-defform state indent-point))
              ;** WITH-... & CALL-WITH-... forms added by TRC
              ((or (eq method 'with-...)
                   (eq method 'call-with-...)
                   (and (null method)
                        (or (and (> (length function) 5)
                                 (string-match "\\`with-" function))
                            (and (> (length function) 9)
                                 (string-match "\\`call-with-" function)))))
               (lisp-indent-withform state indent-point))
              ((integerp method)
               (lisp-indent-specform method state
                                     indent-point normal-indent))
              (method
               (funcall method state indent-point normal-indent)))))))

;++ This is an approximation.  It fails for something like:
;++   (with-foo bar
;++     baz (quux))
;++ It could be generalized to negative special form indent methods; e.g.,
;++   (put 'with-frobbotzim 'scheme-indent-function -2)
;++ and then
;++   (with-frobbotzim frob grovel
;++       full lexical
;++       mumble chumble
;++       spuzz
;++    (lambda (foo) ...)
;++    (lambda (bar) ...))
;++ That is, the last two subforms would be indented two spaces, whereas all
;++ preceding subforms would get four spaces.

(defun lisp-indent-withform (state indent-point)
  (if (not (and (boundp 'paredit-mode)
                paredit-mode))
      ;; If we're not in paredit mode, it's not really safe to go backwards
      ;; from the end and to try to indent based on that, since there may not
      ;; be an end to work backwards from (i.e. the structure not be valid).
      (lisp-indent-defform state indent-point)
    (goto-char (nth 1 state))
    (let ((body-column (+ (current-column)
                          lisp-body-indent)))
      (forward-sexp 1)
      (backward-char 1)
      (backward-sexp 1)
      (skip-chars-backward " \t" (point-at-bol))
      (if (= (point) indent-point)
          body-column
          ;; If it's not the last argument, then we must specify not only the
          ;; column to indent to but also the start of the containing sexp,
          ;; which implies (don't ask me how) that any *following* subforms
          ;; must be indented separately, and not just on this column.  This
          ;; allows C-M-q to know to indent the penultimate arguments with four
          ;; spaces, but to keep recomputing the indentation so that it doesn't
          ;; assume the last one will go to the same column, which is a wrong
          ;; assumption.
          (list (+ body-column lisp-body-indent)
                (nth 1 state))))))

))    ;end `eval-after-load'

Indentation Crash Tutorial

The following information was provided by Riastradh in #scheme-on-freenode. Thanks Riastradh!

(put 'name 'scheme-indent-function n)

Will make forms with name in the operator position indent with the first n subforms using four spaces, and the remaining using two spaces.

So, for instance, we have (put 'do 'scheme-indent-function 2), (put 'lambda 'scheme-indent-function 1), (put 'if 'scheme-indent-function 3), and so on.

(put 'name 'scheme-indent-function 'defun)

Having defun instead of a number means that all of the subforms will be indented with two spaces, regardless of how many there are on the first line.

By contrast, with a value of 0, if there is a subform on the first line (i.e. the same line as the opening bracket and the operator name), all of the subsequent forms will be aligned with it, like in procedure calls.

So we have (put 'define 'scheme-indent-function 'defun), but (put 'begin 'scheme-indent-function 0)

(define (foo bar)
  (baz bar))

(begin (foo)
       (bar))                                                                                                                                                        

Put with a function

You can also put a symbol whose function to use to indent the form, so, because let is special -- it has two different forms, one of which should be indented with one subform (the binding list) and the other of which with two subforms (the name and the initial binding list) --, we have (put 'let 'scheme-indent-function 'scheme-let-indent).

Quack and pretty-lambda on OS X

Quack's pretty-lambda fontification may work out the the box with Carbon Emacs, but when it doesn't it can be a pain to configure. There are two main stumbling blocks you may encounter.

Quack's pretty-lambda works out of the box with http://www.aquamacs.org.

Gotchas

First, you'll want to use a recent CVS version such as 2005-12-11. Version 2005-04-28 does not like the iso10646-1 font encoding, which limits your font options greatly. Additionally, version 2006-03-25 crashed frequently for me. Once you have a version with iso10646-1 support, lambda display generally works out of the box, and the dreaded 'hollow box' issue rarely rears its head.

Second, Quack uses composition to replace the word lambda with the Greek letter, but for whatever reason, composition does not work correctly with bitmapped fonts. Included in bitmapped fonts here are fonts that are not anti-aliased at small sizes, such as Monaco 10 and Symbol 10.

Default fontsets

Using a recent version of Carbon Emacs, the default fontset fontset-default (Monaco 12) will display the letter lambda correctly. This is because this fontset maps all the Emacs charsets (such as greek-iso8859-7, containing lambda) to iso10646-1 (Unicode) versions of Monaco, and because Monaco 12 is anti-aliased.

Furthermore, fontset-mac (ETL 14) works as well; it has a large number of special cases for various characters, including Symbol 12 for the Greek lambda.

A smaller version of Monaco

Most likely you'll have your own font preference, and you may have created a fontset for it. Quack uses the lambda character from greek-iso8859-7, so your fontset must a) be able to display this character and b) display it anti-aliased. Here is a simple example using Monaco 10:

; Create a fontset called fontset-monaco
(create-fontset-from-fontset-spec 
 (concat
  "-apple-monaco-medium-r-normal--10-*-*-*-*-*-fontset-monaco,"
  "ascii:-apple-monaco-medium-r-normal--10-100-*-*-m-100-mac-roman,"
  "latin-iso8859-1:-apple-monaco-medium-r-normal--10-100-*-*-m-100-mac-roman"))

; Use fontset-monaco in all frames
(setq initial-frame-alist `((width . 103) (height . 67) 
                            (font . "fontset-monaco")))
(setq default-frame-alist initial-frame-alist)

You haven't specified a font for greek-iso8859-7, so Emacs defaults it to -*-iso10646-1, which should map to the Unicode encoding for Monaco 10, and be displayed correctly.

(In an odd twist, any -iso10646-1 encoded font will be displayed with anti-aliasing, no matter the size or whether you have requested anti-aliasing be disabled. This is to our advantage due to the composition problem mentioned earlier, although it can be annoying when working with Unicode in general.)

Advanced: Using a font lacking lambda

You might like to use a font which does not contain a lambda character. For example, I use a font of my own design which covers only ASCII. In this case Emacs maps greek-iso-8859-7 to another font--Abadi MT on my system. To change to Monaco 10, which meshes better with the ASCII font, add a greek-iso8859-7 charset to the fontset:

   "greek-iso8859-7:-apple-monaco-medium-r-normal--10-*-*-*-m-*-iso10646-1,"

or alternatively, set a font for only one character:

(set-fontset-font "fontset-fixedr12" 
                  (make-char 'greek-iso8859-7 107)   ; lambda is code point 107
                  "-apple-monaco-medium-r-normal--10-100-*-*-m-100-iso10646-1")

Lack of iso10646-1 support

If you're stuck with an earlier version of Carbon Emacs that cannot display iso10646-1 encodings, you can use the Symbol font:

   "greek-iso8859-7:-apple-symbol-medium-r-normal--12-*-*-*-m-*-mac-symbol,"

I use Symbol 12 here because Symbol 10 is not anti-aliased and the lambda will not be composed correctly.


emacs-tutorial


category-software category-software-ide