-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpel-emacs.el
245 lines (219 loc) · 9.29 KB
/
pel-emacs.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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
;;; pel-emacs.el --- Emacs stats utilities -*- lexical-binding: t -*-
;; Copyright (C) 2020, 2021, 2022, 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:
;;
;; A set of of utilities related to Emacs itself.
;;
;; - `pel-emacs-executable' identifies the Emacs executable path and prints it
;; on the echo area.
;; - `pel-open-emacs-refcard' prompts for the name of an Emacs reference card
;; and opens the PDF file if it can locate it. It attempts to locate the
;; directory unless the `pel-emacs-refcard-dirpath' user option identify the
;; directory where the reference card files are stored.
;; - It uses the `pel-emacs-refcard-dirpath' utility to identify the
;; location of the directory and topic specific PDF files.
;; - `pel-emacs-load-stats' print Emacs Lisp load statistics in the echo area.
;; - `pel-emacs-mem-stats' print Emacs Lisp memory statistics in a buffer.
;; Those might be useful when developing Emacs Lisp code.
;;
;; The function call hierarchy:
;;
;; * `pel-emacs-executable'
;; * `pel-open-emacs-refcard'
;; - `pel-emacs-refcard-dirpath'
;; * `pel-emacs-load-stats'
;; * `pel-emacs-mem-stats'
;; * `pel-emacs-command-stats'
;; - `pel--emacs-command-count'
;; - `pel--emacs-command-binding'
;;; --------------------------------------------------------------------------
;;; Dependencies:
;;
(require 'pel--base) ; use: pel-print-in-buffer
(require 'pel--options)
;;; --------------------------------------------------------------------------
;;; Code:
;;
;;-pel-autoload
(defun pel-emacs-executable ()
"Display Emacs executable path in echo area."
(interactive)
(message "Emacs := %s"
(file-truename
(expand-file-name invocation-name invocation-directory))))
;; ---------------------------------------------------------------------------
;; pel-open-emacs-refcard
(defvar pel--prompt-history-for-emacs-refcard nil
"History list for function `pel-open-emacs-refcard'.")
(defun pel-emacs-refcard-dirpath (&optional topic)
"Compute and return the path of Emacs refcard directory.
If TOPIC is non-nil, return the full path of the specified topic PDF file."
(let ((refcard-dirpath (or pel-emacs-refcard-dirpath
(expand-file-name
(format "../../share/emacs/%s/etc/refcards"
emacs-version)
(file-truename
(expand-file-name
invocation-name
invocation-directory))))))
(unless (file-exists-p refcard-dirpath)
(user-error
(if pel-emacs-refcard-dirpath
"Directory identified by pel-emacs-refcard-dirpath is invalid!\
Please fix it!"
"Cannot locate Emacs refcard directory!
Please identify a directory with PDF refcard files in the \
pel-emacs-refcard-dirpath user option!")))
(if topic
(expand-file-name (format "%s.pdf" topic) refcard-dirpath)
refcard-dirpath)))
;;-pel-autoload
(defun pel-open-emacs-refcard ()
"Prompt for an Emacs REFCARD and open it.
Attempts to find the directory where the Emacs PDF reference card
files are stored. Failing to detect them it uses the directory identified by
the variable `pel-emacs-refcard-dirpath' user option."
(interactive)
(let* ((topics (mapcar
(lambda (fn)
(substring fn 0 -4))
(directory-files
(pel-emacs-refcard-dirpath) nil "\\.pdf\\'")))
(topic (completing-read
"Refcard: "
topics
nil ; predicate
t ; require-match
nil ; initial
'pel--prompt-history-for-emacs-refcard)))
(browse-url (format "file:%s" (pel-emacs-refcard-dirpath topic)))))
;; ---------------------------------------------------------------------------
;; pel-emacs-load-stats
;;-pel-autoload
(defun pel-emacs-load-stats (&optional with-details)
"Display number of loaded files & features.
If WITH-DETAILS, print details in the *emacs-load-stats* buffer.
With \\[universal-argument] \\[universal-argument] prefix, also print content of load-history."
(interactive "P")
(if (and (require 'package nil :no-error)
(boundp 'package-selected-packages)
(boundp 'package-alist)
(boundp 'package-activated-list))
(let ((numeric-arg (prefix-numeric-value with-details))
(overview-msg (format "\
# loaded files : %d
# load-path length : %d
# features : %d
# package-alist : %d
# packages activated: %d
# packages selected : %d"
(length load-history)
(length load-path)
(length features)
(length package-alist)
(length package-activated-list)
(length package-selected-packages))))
(if with-details
(pel-print-in-buffer
"*emacs-load-stats*"
"Emacs Load Statistics"
(lambda ()
"Print stats in buffer."
(insert overview-msg "\n\n")
(when (>= numeric-arg 16)
(pel-insert-list-content 'load-history))
(pel-insert-list-content 'features)
(pel-insert-list-content 'package-activated-list)
(pel-insert-list-content 'package-selected-packages)))
(message overview-msg)
))
(user-error "The package file is not loaded!")))
;; ---------------------------------------------------------------------------
;; pel-emacs-mem-stats
;; Prevent byte-compiler warning by declaring variables that are
;; always available.
(defvar cons-cell-consed)
(defvar float-consed)
(defvar vector-cells-consed)
(defvar string-chars-consed)
;; (defvar misc-objects-consed)
(defvar intervals-consed)
(defvar strings-consed)
;;-pel-autoload
(defun pel-emacs-mem-stats ()
"Display Emacs memory statistics inside an *emacs-mem-stats* buffer."
(interactive)
(pel-print-in-buffer "*emacs-mem-stats*"
"Emacs Memory"
(format "\
On %s:
- cons-cells-consed : %19d
- floats-consed : %19d
- vector-cells-consed: %19d
- symbols-consed : %19d
- string-chars-consed: %19d
- intervals-consed : %19d
- strings-consed : %19d%s"
(format-time-string "%A, %B %d, %Y @ %T")
cons-cells-consed
floats-consed
vector-cells-consed
symbols-consed
string-chars-consed
intervals-consed
strings-consed
(if (boundp 'misc-objects-consed)
(format "
- misc-objects-consed: %19d" misc-objects-consed)
""))))
;; ---------------------------------------------------------------------------
;; pel-emacs-command-stats
(defun pel--emacs-command-binding (command)
"Return the first key bound to the COMMAND.
COMMAND must be a symbol.
Return a key binding string if there is a binding.
Return nil if there is no binding."
(let ((key-description (substitute-command-keys (format "\\[%s]" command)))
(m-x-sequence (format "M-x %s" command)))
(unless (string= key-description m-x-sequence)
key-description)))
(defun pel--emacs-command-count (&optional predicate)
"Return number of available commands that meet the (optional predicate)."
(let ((command-count 0))
(mapatoms
(lambda (symbol)
(when (and (commandp symbol)
(or (null predicate)
(funcall predicate symbol)))
(setq command-count (1+ command-count)))))
command-count))
;;-pel-autoload
(defun pel-emacs-command-stats ()
"Display number of available commands and command with key bindings."
(interactive)
(message "\
Number of currently available commands : %4d
Number of those commands with key bindings: %4d
Number of global keys (and key prefixes) : %4d"
(pel--emacs-command-count)
(pel--emacs-command-count (function pel--emacs-command-binding))
(length global-map)))
;;; --------------------------------------------------------------------------
(provide 'pel-emacs)
;;; pel-emacs.el ends here