Skip to content

Commit af4e391

Browse files
committed
provide option to index all blocks, and more...
1. handle some cases where the buffer has readonly text 2. advise xref-find-definitions to use this library to generate tags 3. advise org-babel-load-file to point to the right places.
1 parent d94fd0f commit af4e391

File tree

1 file changed

+99
-33
lines changed

1 file changed

+99
-33
lines changed

scimax-literate-programming.el

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@
5858
;; auto
5959
;; none
6060

61-
61+
(defvar scimax-lp-consider-all nil
62+
"If non-nil consider all src blocks when making tags.")
6263

6364
(defvar scimax-lp-etags-language-map
6465
'(("emacs-lisp" . "lisp")
@@ -70,12 +71,13 @@ Each cons cell is (src-block lang . etags language)")
7071

7172

7273
(defun scimax-lp-tangle-p ()
73-
"Return t if the block should be tangled.
74+
"Return absolute tangle filename if the block should be tangled.
7475
That means :tangle is not no."
75-
(and (org-in-src-block-p)
76-
(not (string= "no"
77-
(cdr (assq :tangle
78-
(nth 2 (org-babel-get-src-block-info 'light))))))))
76+
(when (org-in-src-block-p)
77+
(let ((tangle (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 'light))))))
78+
;; Note this might be a "yes"
79+
(when (not (string= "no" tangle))
80+
(expand-file-name tangle)))))
7981

8082

8183
(defun scimax-lp-update-lang-tags (org-file lang)
@@ -93,7 +95,9 @@ should make this a safe operation."
9395
(let ((open (find-buffer-visiting org-file)))
9496
(with-current-buffer (find-file-noselect org-file)
9597
(save-buffer)
96-
(let* ((content (buffer-string)))
98+
99+
(let* ((content (buffer-string))
100+
(inhibit-read-only t))
97101
;; This has potential for disaster since it deletes the buffer! I think
98102
;; this is pretty safe, but you should be prepared for disaster. If
99103
;; there is any error in this, I think it undoes the buffer damage.
@@ -102,7 +106,7 @@ should make this a safe operation."
102106
(while (and (not (eobp)))
103107
(if (and (org-in-src-block-p)
104108
(string= lang (car (org-babel-get-src-block-info 'light)))
105-
(scimax-lp-tangle-p))
109+
(or (scimax-lp-tangle-p) scimax-lp-consider-all))
106110
(let* ((src (org-element-context))
107111
(end (org-element-property :end src))
108112
(len (length (buffer-substring
@@ -138,44 +142,62 @@ should make this a safe operation."
138142
(unless open (kill-buffer (find-buffer-visiting org-file))))))
139143

140144

141-
(defun scimax-lp-generate-tags ()
145+
(defvar scimax-lp-update-tags-always t
146+
"If non-nil, update TAGS file whenever the org file is newer.")
147+
148+
149+
(defun scimax-lp-generate-tags (&optional refresh)
142150
"Generate a list of tags from org-files and visit the tag-file.
143151
This will attempt to get tags for every language defined in
144152
`scimax-lp-etags-language-map'."
145-
(interactive)
146-
(save-buffer)
147-
(when (file-exists-p "TAGS") (delete-file "TAGS"))
148-
(let* ((current-point (point))
149-
(org-files (f-entries
150-
"."
151-
(lambda (f) (f-ext? f "org")) t))
152-
langs)
153-
(loop for org-file in org-files do
154-
(setq langs '())
155-
(org-babel-map-src-blocks org-file
156-
(pushnew lang langs :test 'string=))
157-
(loop for lang in langs do
158-
(scimax-lp-update-lang-tags org-file lang)))
159-
(goto-char current-point)
160-
(let ((tag-buffer (or (find-buffer-visiting "TAGS")
161-
(find-file-noselect "TAGS"))))
153+
(interactive "P")
154+
(when (and (eq major-mode 'org-mode)
155+
(or scimax-lp-update-tags-always refresh))
156+
(save-buffer)
157+
;; (when (file-exists-p "TAGS") (delete-file "TAGS"))
158+
(let* ((current-point (point))
159+
(org-files (f-entries
160+
"."
161+
(lambda (f) (f-ext? f "org")) t))
162+
langs)
163+
(loop for org-file in org-files do
164+
(setq langs '())
165+
(org-babel-map-src-blocks org-file
166+
(pushnew lang langs :test 'string=))
167+
(loop for lang in langs do
168+
(scimax-lp-update-lang-tags org-file lang)))
169+
(goto-char current-point)))
170+
(let ((tag-buffer (or (find-buffer-visiting "TAGS")
171+
(find-file-noselect "TAGS"))))
172+
(when tag-buffer
162173
(with-current-buffer tag-buffer
163174
(revert-buffer :ignore-auto :noconfirm)
164175
(visit-tags-table "TAGS")))))
165176

166177

178+
;; I had to make this small function for a reason I don't understand. I could
179+
;; not use the `scimax-lp-generate-tags' function directly without an error
180+
;; related to number of arguments.
181+
(defun scimax-lp-xref-advice (arg)
182+
":before advice for xref-find-definitions to automatically make tags."
183+
(scimax-lp-generate-tags))
184+
185+
(advice-add 'xref-find-definitions :before #'scimax-lp-xref-advice)
186+
167187
(defun scimax-lp-signature-doc ()
168188
"Get signature and docstring for thing at point.
169189
For emacs-lisp this should work for defun and defvar. For other
170190
languages you will get see the definition line."
171191
(interactive)
172192
(when (org-in-src-block-p)
173193
;; This is a weird issue. It seems like read moves the point inside the
174-
;; save-window-excursion, so I save the point here to move back later.
194+
;; save-window-excursion and doesn't restore it, so I save the point here to
195+
;; move back later.
175196
(let ((current-point (point)))
176197
(save-window-excursion
177-
(let* ((fname (symbol-name (symbol-at-point)))
178-
(p (xref-find-definitions fname)))
198+
(let* ((sname (symbol-name (symbol-at-point)))
199+
(p (condition-case nil (xref-find-definitions sname)
200+
(error nil))))
179201
(cond
180202
((string= (get-char-property (point) 'lang) 'emacs-lisp)
181203
(cond
@@ -184,22 +206,66 @@ languages you will get see the definition line."
184206
(args (nth 2 def))
185207
(n3 (nth 3 def))
186208
(docstring (if (stringp n3) n3 "")))
187-
(message "%s: (%s) \"%s\"" fname args docstring)))
209+
(message "%s: (%s) \"%s\"" sname args docstring)))
188210
((looking-at "(defvar")
189211
(let* ((def (read (current-buffer)))
190212
(var (nth 1 def))
191213
(val (nth 2 def))
192214
(ds (nth 3 def)))
193215
(message "%s=%s \"%s\"" var val ds)))))
194216
(t
195-
;; This assumes that xref-find-definitions moved the point. I don't
196-
;; know any better way to get reasonable information about the
197-
;; definition. You need parsing to get it in general.
217+
;; if p is nil it means nothing was found, so we try searching
218+
;; instead. this is not a very sophisticated search yet, we should
219+
;; search until we are in the right kind of code block. This will
220+
;; fail on things not defined in the current file, e.g. variable
221+
;; names that are imported.
222+
(unless p
223+
(goto-char (point-min))
224+
(re-search-forward sname))
225+
;; Then, we show the context
198226
(message (buffer-substring
199227
(line-beginning-position)
200228
(line-end-position)))))))
201229
(goto-char current-point))))
202230

231+
;; * Advice on org-babel-load-file
232+
233+
;; The idea here is to replace all definitions of the tangled files with the
234+
;; org-file in `load-history' so that describe-function/variable points to them
235+
;; instead.
236+
237+
(defun scimax-lp-modify-load-history (&rest args)
238+
"Modify the load-history to point all tangled files to compile."
239+
(interactive)
240+
(let* ((file (nth 0 args))
241+
(compile (nth 1 args))
242+
(open (find-buffer-visiting file))
243+
tf
244+
(tangle-files '()))
245+
(org-babel-map-src-blocks file
246+
;; I am not sure if it matters if the
247+
(setq tf (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 'light)))))
248+
(cond
249+
((string= "yes" tf)
250+
(setq tf (concat (file-name-sans-extension (buffer-file-name)) ".el")))
251+
((not (string= "no" tf))
252+
(setq tf (expand-file-name tf)))
253+
(t
254+
(setq tf nil)))
255+
(when tf
256+
(setq tf (concat tf (if compile "c" "")))
257+
(pushnew (expand-file-name tf) tangle-files :test #'string=)))
258+
;; now modify the load-history
259+
(mapc (lambda (tf)
260+
(when (car (assoc tf load-history))
261+
(setf (car (assoc tf load-history)) (expand-file-name file))))
262+
tangle-files)
263+
(unless open (kill-buffer open))))
264+
265+
(advice-add 'org-babel-load-file :after #'scimax-lp-modify-load-history)
266+
267+
;; (advice-remove 'org-babel-load-file 'scimax-lp-modify-load-history)
268+
203269

204270
(provide 'scimax-literate-programming)
205271

0 commit comments

Comments
 (0)