changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / emacs/lib/sk.el

changeset 676: ca09f470abb3
parent: e052bac27cec
child: 585f14458a65
author: Richard Westhaver <ellis@rwest.io>
date: Tue, 24 Sep 2024 20:57:47 -0400
permissions: -rw-r--r--
description: rm dir-locals and makefile, added dir-locals hacks in sk.el
1 ;;; sk.el --- skel Emacs Mode -*- lexical-binding:t -*-
2 
3 ;; skel-mode, skel-minor-mode,skt-minor-mode, sk-classes
4 
5 ;; Copyright (C) 2023 The Compiler Company
6 
7 ;; Author: ellis <ellis@rwest.io>
8 ;; Keywords: languages, lisp
9 
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14 
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19 
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
22 
23 ;;; Commentary:
24 
25 ;;
26 
27 ;;; Code:
28 (eval-and-compile (require 'eieio)
29  (require 'cl-lib)
30  (require 'sxp (expand-file-name "sxp.el" (join-paths user-emacs-directory "lib/")))
31  (require 'skeleton)
32  (require 'org)
33  (require 'tempo)
34  (require 'autoinsert)
35  (defvar skel-debug nil)
36  (when skel-debug (require 'ede)))
37 
38 (defvar skel-version "0.1.0")
39 
40 (defgroup skel nil
41  "skel customization group."
42  :group 'local)
43 
44 (defcustom skel-minor-mode-map-prefix "C-c C-."
45  "Prefix for `skel-minor-mode' keymap."
46  :type 'string
47  :group 'skel)
48 
49 (defcustom skel-triggers nil
50  "Association of symbols to a specific condition which can be used
51 to trigger `skel-actions' based on the `skel-behavior' value."
52  :type '(list function)
53  :group 'skel)
54 
55 (defcustom skel-actions nil
56  "Array of actions which may be performed on skeletons."
57  :type 'obarray
58  :group 'skel)
59 
60 (defcustom skel-id-prefix "sk"
61  "Default prefix for `make-id'."
62  :type 'string
63  :group 'skel)
64 
65 (defvar-keymap skel-minor-mode-map
66  :doc "skel-minor-mode keymap."
67  :repeat (:enter)
68  :prefix 'skel-minor-mode-map)
69 
70 (define-minor-mode skel-minor-mode
71  "skel-minor-mode"
72  :global t
73  :lighter " Sk"
74  :group 'skel
75  :keymap skel-minor-mode-map
76  :version skel-version)
77 
78 ;; TODO 2023-09-06:
79 (define-derived-mode skel-mode lisp-mode "SKEL"
80  :group 'skel
81  (skel-minor-mode 1))
82 
83 (org-babel-make-language-alias "skel" "lisp")
84 
85 (defun maybe-skel-minor-mode ()
86  "Check the current environment and determine if `skel-minor-mode' should
87 be enabled. This function is added as a hook to
88 `lisp-data-mode-hook'.")
89 
90 (defvar skel-hashtable (make-hash-table :test #'equal)
91  "Internal table of available skeletons.")
92 
93 (defvar skel-stack nil "Internal stack of skeletons.")
94 
95 (defcustom skel-state 'passive
96  "State toggle for the `skel' system. Base states are passive and
97 active."
98  :type 'symbol
99  :group 'skel)
100 
101 (defvar skel-active-map nil
102  "List of cons cells of the form (SYM . BODY...) where SYM is a member of
103 `skel-triggers'.")
104 
105 (defvar skel-passive-map nil
106  "list of cons cells of the form (SYM . BODY...) where SYM is a member of
107 `skel-triggers'.")
108 
109 (defmacro make-id (&optional pre)
110  `(let ((pre ,(if-let (pre) (concat skel-id-prefix "-" pre "-") (concat skel-id-prefix "-")))
111  (current-time-list nil))
112  (symb pre (prog1 gensym-counter (setq gensym-counter (1+ gensym-counter))) (format "%x" (car (current-time))))))
113 
114 (defmacro defcmd (name &rest body) `(defun ,name nil (interactive) ,@body))
115 
116 (defclass sk (sxp)
117  ((id :initarg :id :initform (make-id)))
118  :documentation "Base class for skeleton objects. Inherits from `sxp'."
119  :abstract t)
120 
121 (defcmd sk-classes (eieio-class-children 'sk))
122 
123 (defmacro def-sk-class (name doc &optional slots superclasses)
124  "Define a new class with superclass of `skel'+SUPERCLASSES, SLOTS,
125 DOC, and NAME."
126  (declare (indent 1))
127  `(defclass ,(symb "sk-" name)
128  ,(if superclasses `(sk ,@superclasses) '(sk))
129  ,(if slots
130  `(,@slots
131  (:id :initarg :id :initform (make-id ,(symbol-name name)) :accessor id))
132  `((:id :initarg :id :initform (make-id ,(symbol-name name)) :accessor id)))
133  :documentation ,doc))
134 
135 (def-sk-class target "Target skeleton class.")
136 (def-sk-class source "Source skeleton class.")
137 (def-sk-class rule
138  "Config skeleton class."
139  ((target :initarg :target :initform nil :type (or null sk-target))
140  (rules :initarg :source :initform nil :type (or null sk-source))))
141 
142 (def-sk-class project
143  "Project skeleton class."
144  ((type :initarg :type :initform nil :accessor sk-project-type :type (or null symbol))
145  (rules :initarg :rules :initform nil :accessor sk-project-rules :type list)))
146 
147 (defun skel-init ()
148  "Initialize the skel library."
149  (interactive)
150  (add-to-list 'auto-mode-alist '("skelfile" . skel-mode))
151  (add-to-list 'auto-mode-alist '("\\.sk" . skel-mode)))
152 
153 (defun project-skelfile-path (&optional project)
154  "Find skelfile associated with PROJECT. Defaults to current
155 directory and returns name of skelfile. When PROJECT is T uses
156 `project-current'."
157  (let* ((dir (unless (eql t project) (expand-file-name (or project default-directory))))
158  (project-root (project-root (project-current nil dir))))
159  (or
160  (when dir
161  (cl-find-if
162  (lambda (x)
163  (when (string-match
164  (rx (or "skelfile" (and (* any) ".sk")))
165  (file-name-nondirectory x))
166  x))
167  (directory-files dir t)))
168  (when project
169  (cl-find-if (lambda (x)
170  (when (string-match (rx (or "skelfile" (and (* any) ".sk")))
171  (file-name-nondirectory x))
172  x))
173  (directory-files project-root t))))))
174 
175 (defun read-skelfile-bind (&optional project)
176  (let ((buffer (find-file-noselect (project-skelfile-path project))))
177  (with-current-buffer buffer
178  (goto-char (point-min))
179  (goto-char (search-forward-regexp (rx bol ":bind" (* space))))
180  (read buffer))))
181 
182 (defun project-skelfile-dir-locals (&optional project)
183  "Return a list of dir-local bindings from a skelfile."
184  (let ((form (read-skelfile-bind project)))
185  (cl-loop for f in form
186  do (cond
187  ((eql (car f) :dir-locals) (cl-return (cdr f)))
188  ;; when used as second element, the first is the name
189  ;; of the CL-local binding, here we discard it and
190  ;; just take the CDDR.
191  ((eql (cadr f) :dir-locals) (cl-return (cddr f)))))))
192 
193 (defun skel-dir-local--get-variables ()
194  "Compute and return the list of :DIR-LOCAL bindings found in the current
195 project's skelfile, if any. Typically added to
196 `hack-dir-local--get-variables'."
197  (let ((root (project-root (project-current))))
198  (cons (expand-file-name root) (project-skelfile-dir-locals root))))
199 
200 (defun %skel-dir-local--get-variables ()
201  (let ((root (expand-file-name (project-root (project-current)))))
202  (unless (assoc-string root dir-locals-class-alist)
203  (push (skel-dir-local--get-variables) dir-locals-class-alist))))
204 
205 (add-hook 'skel-minor-mode-hook '%skel-dir-local--get-variables)
206 
207 (provide 'skel)
208 (provide 'sk)
209 ;;; sk.el ends here