I wrote a function to show me a list of all defuns in the current buffer. The output is syntactically incorrect Lisp code (if you can even call it Lisp code, being syntactically a mess). Here's what the output looks like in the help window:
List of results:
(defvar var-one nil "Var one doc")
(defvar var-two nil "Var two doc")
(defun foobar (one two)
(defmacro mymacro (body)
If possible, I would like to fontify the display a bit, to color the defun words and the function names in some way.
I tried to do what org-mode does (suggested on another thread on SO). That is, copy my results to a temp buffer, enable Lisp mode, run font-lock-fontify-buffer
in Lisp mode on the temp buffer, and copy the fontified results back. But that didn't work, for two reasons. First, Lisp mode tried to indent my results like a mess of cascaded, nested defuns (ugh).
The main problem seems to be that with-help-window
loses or blocks all font locking. Maybe it's because of the princ
statements used to generate output into the help window?
Here's my display code (which does not work for keeping font info):
(with-help-window (help-buffer)
(princ (concat title "\n\n"))
(princ alldefuns)
(lisp-mode) ; doesn't help, in or out
(font-lock-fontify-buffer))
My questions are:
Is it possible to display fontified text using with-help-window
?
Or is there an alternate route that I should try? (I suppose I could go study the occur
source, which displays the same kind of results in a normal buffer. But I'd like to stick with with-help-window
approach if I could...)
Update for @lawlist comments below:
Here is the code that generates the list of defuns from the current buffer. The code looks like it should correctly collect and preserve font-lock info from the current buffer because it uses buffer-substring
to extract the lines.
(defun ct-u-buffer-defuns-list ()
"Return a stringlist of defuns in current buffer."
(let (result buf-contents tmp regex)
(setq buf-contents (buffer-string))
(with-temp-buffer
(insert buf-contents)
(goto-char (point-min))
(setq regex "^(defun")
(while (re-search-forward regex nil t)
(let (bol eol)
(setq bol (line-beginning-position))
(setq eol (line-end-position))
(setq tmp (buffer-substring bol eol))
(setq result (concat result tmp "\n")))))
result))
But on a 20 line display displayed in a normal buffer using the code below executed in the scratch buffer, only the first 10 lines retain their font-lock info. Or sometimes it's another 5 or 10 lines in a 30 line display. I don't know why.
(let (alldefuns)
(switch-to-buffer "ct-utils.el")
(setq alldefuns (ct-u-buffer-defuns-list))
(switch-to-buffer (get-buffer-create "foobar"))
(insert "List of results:\n")
(insert alldefuns))
So it seems that at least part of the font-lock properties are collected and preserved by the extraction (search) code, and at least part of the font-lock properties are preserved by inserting the collected string into a temp buffer (Fundamental mode is active in the temporary buffer).
Further, when I try the following bits of code in the *scratch*
buffer as suggested in the comments (alldefuns
is a variable that contains the lines extracted from the code buffer), I get the following results:
(defun foo ()
"Insert a string of defun lines in the current buffer."
(insert alldefuns))
;;works perfectly in Lisp mode scratch buffer
(foo)
;; only displays 10 of 30 lines with font lock info
(let ((temp-buffer-window-setup-hook 'foo))
(help-window-full-frame (help-buffer)
(princ "This title appears last in output.\n")))
It's a puzzle why displaying in (1) a temporary help buffer, or (2) in a temporary Fundamental mode buffer, only shows 1 chunk of 10 lines or so of font-lock info.
emacs-lisp-mode
such that they might already contain the correct highlighting? Perhaps it is just a matter of adjusting the extraction method to preserve the highlighting . . . Or, are you actually usinggrep
to extract the list of results? Perhaps providing a little more details about the extraction method might generate other potential solutions . . .while (string-match "(defun")
loop to walk the current buffer, and(setq string (concat string (buffer-line-contents) "\n"))
to build up the string that is displayed. The main problem is that the help window method strips the font lock info. I can get some font-lock colors by copying and fonting in a temp buffer, and bringing back the fontified string. But then it's lost in the help window process. My guess is that I'll end up using a normal buffer likeoccur
does.buffer-substring
preserves the text-properties, so if you use that function when gathering the results, then it won't be necessary to fontify anything afterwords and there would be no need to use a help-buffer. There is no such animal asbuffer-line-contents
as far as I am aware. You can just use a plain old buffer and add things like aspecial-mode-map
to quit the buffer withq
and so forth.buffer-substring
and save it in a variable -- e.g.,my-variable
, and use a simple function like(defun foo () (insert my-variable))
Then, use this:(let ((temp-buffer-window-setup-hook 'foo)) (help-window-full-frame (help-buffer)))
in conjunction with the macro that we wrote together a couple of weeks ago: emacs.stackexchange.com/a/24037/2287 Of course, you can use a list to store the information and populate your help buffer accordingly.occur
source code now, to see if I can figure out how he does it.