Reputation: 221
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))))
Upvotes: 2
Views: 1590
Reputation: 74430
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)))))))
Upvotes: 2