1

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.

  • Are you extracting the variables/functions/macros from Lisp files that are already in 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 using grep to extract the list of results? Perhaps providing a little more details about the extraction method might generate other potential solutions . . . – lawlist Jul 9 '16 at 23:14
  • Hi lawlist, interesting viewpoint. No, I'm not using grep. I just use a 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 like occur does. – Kevin Jul 10 '16 at 2:04
  • 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 as buffer-line-contents as far as I am aware. You can just use a plain old buffer and add things like a special-mode-map to quit the buffer with q and so forth. – lawlist Jul 10 '16 at 3:21
  • And here is another option for you. Gather your results with 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. – lawlist Jul 10 '16 at 3:37
  • Thank you for your continued comments. As you requested, I updated the original question with more coding details, and with my test results. I think you're right that I'll end up using a normal buffer (vs a help buffer), and rebinding the q key. I think I'll go have a look at the occur source code now, to see if I can figure out how he does it. – Kevin Jul 10 '16 at 5:31
1

Here's the code that I am using for now. It displays the output lines in normal font-lock colors for Lisp-mode. Note that I had to add a trailing paren ) to each extracted (defun foo (..) line (see the extraction function above), to make it valid Lisp code for the (lisp-mode) call in the sample code below.

  (let (title alldefuns)
    ;; get a list of matches
    (setq alldefuns (ct-u-buffer-defuns-list))
    (switch-to-buffer (get-buffer-create "Defun-output"))
    (lisp-mode)
    (local-set-key "q" (lambda () (interactive) (kill-buffer)))
    (setq title "List of results:\n")
    (insert alldefuns))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.