-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpel-commonlisp.el
230 lines (203 loc) · 8.09 KB
/
pel-commonlisp.el
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
;;; pel-commonlisp.el --- PEL Common Lisp Support -*-lexical-binding: t-*-
;; Copyright (C) 2020, 2021, 2024 Pierre Rouleau
;; Author: Pierre Rouleau <[email protected]>
;; This file is part of the PEL package
;; This file is not part of GNU Emacs.
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;;---------------------------------------------------------------------------
;;; Commentary:
;;
;; Environment Agnostic Commands
;; -----------------------------
;;
;; - The `pel-cl-repl' command opens a Common Lisp REPL, or switch to one
;; already running, using the available technology based on the user-option
;; selection: SLY, Slime or the bare-bone inferior Lisp mode REPL.
;;
;; - The `pel-cl-hyperspec-lookup' command which invokes the slime or sly
;; documentation lookup command depending of which is available.
;;
;; Code hierarchy:
;;
;; * `pel-cl-repl'
;; - `pel-switch-to-window'
;; * `pel-cl-hyperspec-lookup'
;; - `pel-symbol-at-point'
;;
;;
;; iMenu Extension
;; ---------------
;;
;; The file also provide the `pel-cl-add-symbol-to-imenu' command.
;; The `pel-cl-add-symbol-to-imenu' command adds the Common Lisp symbol at
;; point to the iMenu section allowing that symbol to be detected and show in
;; the iMenu index list under a specified section title.
;;
;; There's not that many programming languages where a defining construct can
;; be defined by user's code. Common Lisp is one of them. These will not
;; always be defined ahead of time in a Emacs file or dir-local setting
;; of the `lisp-imenu-generic-expression'. Therefore it will be useful to
;; have the ability to dynamically add such a symbol when browsing Common Lisp
;; source code that use a DSL where form defining macros are used.
;;
;; It's code hierarchy is:
;;
;; * `pel-cl-add-symbol-to-imenu'
;; - `pel-symbol-at-point'
;; - `pel-cl-add-to-imenu'
;; Credit: Drew Adams for nth-elt
;; https://emacs.stackexchange.com/questions/10492/how-to-get-element-number-in-a-list
;;; --------------------------------------------------------------------------
;;; Dependencies:
;;
(require 'pel--base) ; use: pel-symbol-at-point
;; ; pel-add-imenu-sections-to
(require 'pel--options)
(require 'pel-prompt) ; use: pel-prompt
(require 'pel-window) ; use: pel-switch-to-window
;;;---------------------------------------------------------------------------
;;; Code:
;; ---------------------------------------------------------------------------
;; pel-cl-repl
;; -----------
;;-pel-autoload
(defun pel-cl-repl (&optional n)
"Open or switch to Common-Lisp REPL buffer window.
Use the Common Lisp REPL selected by the PEL user-options:
- SLY when `pel-used-sly' is on and `pel-clisp-ide' is set to sly,
- Slime when `pel-use-slime'is on and `pel-clisp-ide' is set to slime,
- the inferior Lisp mode otherwise.
The behaviour of the command is affected by the optional argument N:
- with no buffers running REPL:
> N is nil or absent: - open REPL in current window
> N is positive: - open REPL in other window
> N is negative: - create new REPL in current window
- with 1 or more REPL already running:
- with 1 buffer already running it:
- use REPL buffer as target
- with multiple buffers already running it:
- prompt user to select the target REPL buffer
- if selected buffer is inside an opened window: switch to that window
- if selected buffer is not in an opened window:
> N is nil or absent: - open REPL in current window
> N is positive: - open REPL in other window
> N is negative: - create new REPL in current window."
(interactive "P")
(let* ((n (prefix-numeric-value n))
(in-other-window (and n (> n 0)))
(new-repl (and n (< n 0))))
(cond
;;
;; Use Slime
((and pel-use-slime
(eq pel-clisp-ide 'slime))
(if (fboundp 'slime)
(when (or new-repl
(not (pel-switch-to-window 'slime-repl-mode in-other-window)))
(slime))
(user-error "Function slime is unbound")))
;;
;; Use SLY
((and pel-use-sly
(eq pel-clisp-ide 'sly))
(if (fboundp 'sly)
(when (or new-repl
(not (pel-switch-to-window 'sly-mrepl-mode in-other-window)))
(sly))
(user-error "Function sly is unbound")))
;;
;; No IDE: use default Common Lisp REPL
(t
(if (fboundp 'run-lisp)
(when (or new-repl
(not (pel-switch-to-window 'inferior-lisp-mode in-other-window)))
(run-lisp nil))
(user-error "Function run-lisp is unbound"))))))
;; ---------------------------------------------------------------------------
;;-pel-autoload
(defun pel-cl-hyperspec-lookup ()
"Open Hyperspec documentation for symbol at point.
Use the Slime, SLY or PEL mechanism, whatever is available."
(interactive)
(cond
;;
;; Use Slime
((and pel-use-slime
(eq pel-clisp-ide 'slime))
(if (fboundp 'slime-documentation-lookup)
(slime-documentation-lookup)
(user-error "Function slime-documentation-lookup is unbound")))
;;
;; Use SLY
((and pel-use-sly
(eq pel-clisp-ide 'sly))
(if (fboundp 'sly-documentation-lookup)
(sly-documentation-lookup)
(user-error "Function sly is unbound")))
;;
;; No IDE: implement it.
(t
(if (and (require 'hyperspec nil :no-error)
(fboundp 'common-lisp-hyperspec))
(let ((symbol (or (pel-symbol-at-point)
(pel-prompt "Symbol: "
'hyperspec-search))))
(common-lisp-hyperspec symbol))
(user-error "Function common-lisp-hyperspec not available!")))))
;; ---------------------------------------------------------------------------
;; Add Common Lisp define macro symbols to iMenu section
;; -----------------------------------------------------
;;
(defun pel-cl-add-to-imenu (symbol-string title)
"Add SYMBOL-STRING to the imenu under specified TITLE."
(pel-add-imenu-sections-to
(list
(list title
'lisp-mode-symbol-regexp
(list symbol-string)))
'imenu-generic-expression))
;;-pel-autoload
(defun pel-cl-add-symbol-to-imenu ()
"Add symbol at point to imenu.
Common Lisp macro can define code definition forms similar to
`defun' and friends, effectively creating a Domain Specific
Language. The DSL symbols may not currently be know to `imenu'
parsing.
You can add new symbols to `imenu' by placing the point over such
a symbol and executing this command.
For example, if the file's code uses a `define-rule' macro like
this:
(define-rule rule1
(do-this)
(do-that)
(ensure this and that))
(define-rule secondary
(ensure something-else))
Place point over `define-rule' and execute the command.
You will be prompt for a title for `define-rule', where
you could enter \"rules\".
Then the `imenu' list will be able to show the \"rule\" and
\"secondary\" under the \"Rules\" iMenu section."
(interactive)
(let ((symbol (pel-symbol-at-point)))
(if symbol
(let ((title (pel-prompt (format "iMenu section for %s" symbol)
'imenu-section
:capitalize)))
(when title
(pel-cl-add-to-imenu symbol title)))
(user-error "No symbol at point"))))
;;;---------------------------------------------------------------------------
(provide 'pel-commonlisp)
;;; pel-commonlisp.el ends here