-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmode.lisp
88 lines (76 loc) · 2.78 KB
/
mode.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
(in-package #:neomacs)
(sera:export-always
'(mode define-mode))
(defvar *modes* nil)
(defclass mode (defaultable-class)
((commands :initform nil :accessor commands)
(keymap :accessor keymap)
(lighter
:accessor lighter :type string
:documentation
"String displayed in header to indicate this mode is enabled.")
(hooks
:initform nil :accessor hooks :initarg :hooks
:documentation
"Other modes to enable or disable when enable or disabling this mode."))
(:documentation "Metaclass for modes."))
(macrolet ((define-symbol-accessors (accessor)
`(progn
(defmethod ,accessor ((object t)))
(defmethod ,accessor ((name null)))
(defmethod ,accessor ((name symbol))
(,accessor (find-class name)))
(defmethod (setf ,accessor)
(new-val (name symbol))
(setf (,accessor (find-class name)) new-val)))))
(define-symbol-accessors commands)
(define-symbol-accessors lighter)
(define-symbol-accessors keymap)
(define-symbol-accessors hooks))
(defmethod keymap ((mode-name (eql :global)))
*global-keymap*)
(defmethod sb-mop:validate-superclass
((class mode) (super standard-class))
t)
(defun default-lighter (class)
"Compute the default lighter string for CLASS."
(let ((name (symbol-name (class-name class))))
(when (sera:string-suffix-p "-MODE" name)
(setf name (subseq name 0 (- (length name) 5))))
(string-capitalize name)))
(defmethod shared-initialize :after
((class mode) slot-names
&key toggler lighter documentation)
(declare (ignore slot-names))
(pushnew (class-name class) *modes*)
(flet ((safe-car (form)
(when form
(if (cdr form)
(error "~a has more than one element."
form)
(car form)))))
(when (safe-car toggler)
(let ((name (string-downcase (symbol-name
(class-name class)))))
(eval `(define-command ,(class-name class) ()
,documentation
(message "~a ~:[disabled~;enabled~]"
,name
(toggle ',(class-name class)))))))
(setf (lighter class)
(or (safe-car lighter)
(default-lighter class))
(keymap class)
(make-keymap (class-name class)))))
(defmacro define-mode
(name super-modes slots &rest options)
"Define a mode with NAME.
Like `define-class' besides supporting extra OPTIONS:
(:toggler TOGGLER-P): If TOGGLER-P is t, generate a toggler command
with NAME.
(:lighter LIGHTER): Set the mode's lighter to LIGHTER."
`(progn
(sera:export-always ',name)
(define-class ,name ,super-modes ,slots
(:metaclass mode)
,@options)))