tags:

views:

111

answers:

1

Im making a DSL in lisp (basically what i think is a nicer syntax), its the same thing as lisp except with different 'primitives', no instead of not, 'as' instead of let.Thus i need to change both indentation and color only in files which end in .goby (it should not effect ones which end in .lisp) So i would like to create files with extension of .goby, and have my new, minor/major mode enabled (but with everything else besides syntax inherited from lisp).

However, whatever i do it also effects .lisp files! Anyone?

For example, I tried to make a local variable for unique lisp indentation which would indent 'hi' by 10 spaces. but it effected all .lisp files also

;;in goby.el
(define-derived-mode
  goby-mode lisp-mode "Goby"
  "Major mode"
  (let ((func #'lisp-indent-function))
    (set (make-local-variable 'lisp-indent-function) func)
    (put 'hi 'lisp-indent-function 10)))


(provide 'goby)

;;in .emacs
(setq auto-mode-alist
      (append auto-mode-alist
          '(("\\.gy\\'" . goby-mode))))
+2  A: 

There's probably a cleaner way, but a way that works is to rewrite 'lisp-indent-function to be 'goby-indent-function and use your own table of offsets like so:

(define-derived-mode
  goby-mode lisp-mode "Goby"
  "Major mode"
  (set (make-local-variable 'lisp-indent-function) 'goby-indent-function))

;; goby specific offsets here
(put 'hi 'goby-indent-function 10)
(put 'if 'goby-indent-function 4)

(defun goby-indent-function (indent-point state)
  "Same as 'lisp-indent-function but uses 'goby-indent-function symbol

This function is the normal value of the variable `goby-indent-function'.
It is used when indenting a line within a function call, to see if the
called function says anything special about how to indent the line.

INDENT-POINT is the position where the user typed TAB, or equivalent.
Point is located at the point to indent under (for default indentation);
STATE is the `parse-partial-sexp' state for that position.

If the current line is in a call to a Lisp function
which has a non-nil property `goby-indent-function',
that specifies how to do the indentation.  The property value can be
* `defun', meaning indent `defun'-style;
* an integer N, meaning indent the first N arguments specially
  like ordinary function arguments and then indent any further
  arguments like a body;
* a function to call just as this function was called.
  If that function returns nil, that means it doesn't specify
  the indentation.

This function also returns nil meaning don't specify the indentation."
  (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 (buffer-substring (point)
                                        (progn (forward-sexp 1) (point))))
            method)
        (setq method (or (get (intern-soft function) 'goby-indent-function)
                         (get (intern-soft function) 'lisp-indent-hook)))
        (cond ((or (eq method 'defun)
                   (and (null method)
                        (> (length function) 3)
                        (string-match "\\`def" function)))
               (lisp-indent-defform state indent-point))
              ((integerp method)
               (lisp-indent-specform method state
                                     indent-point normal-indent))
              (method
               (funcall method indent-point state)))))))
Trey Jackson
Perfect ! I assume i do something similar for coloring?
josh
For some reason this doesn't work if i do this in .emacs(require 'slime)(slime-setup '(slime-repl slime-fancy)) - so slime must change some lisp mode functions?
josh
@josh Yes, coloring would be done similarly. Check http://www.emacswiki.org/emacs/FontLockKeywords and http://stackoverflow.com/questions/1063115/a-hello-world-example-for-a-major-mode-in-emacs
Trey Jackson
@josh Regarding interaction with `slime`, that'd require some debugging, not sure how it interacts with the lisp functions.
Trey Jackson