0

When using hideshow (specifically hs-hide-initial-comment-block), I often run into the problem where the very first comment is a license block, followed by a more detailed comment on the purpose of the file.

For example:

/*
 * 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 2
 * 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, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**

  • This file contains functions that solve problem W, part of API X.
  • Take care not to do Y because it can cause issues with Z.

*/

As you might guess, I would like to fold only the first comment, but keep all other comments expanded since it's not part of the boiler plate license header.

Is there a way to tread blank lines as delimiters when hiding comments to avoid hiding multiple, unrelated comments at once?

ideasman42
  • 8,786
  • 1
  • 32
  • 114

1 Answers1

0

This can be done using advice, although it's not trivial, the following code only collapses the first comment block.

(defmacro my-with-advice (fn-orig where fn-advice &rest body)
  "Execute BODY with WHERE advice on FN-ORIG temporarily enabled."
  `
  (let ((fn-advice-var ,fn-advice))
    (unwind-protect
      (progn
        (advice-add ,fn-orig ,where fn-advice-var)
        ,@body)
      (advice-remove ,fn-orig fn-advice-var))))

(defun my-c-comment-end-skip-backward (pos) (cond ;; Check for "/*". ((and (eq (char-before pos) ?/) (eq (char-before (- pos 1)) 42)) (- pos 2)) (t pos)))

(defun my-comment-bounds () (interactive) (let ((state (syntax-ppss)) (point-init (point)))

;; We may be at the comment start, which isn't considered a comment.
(unless (nth 4 state)
  (save-excursion
    (skip-syntax-forward "^-")
    (let ((state-test (syntax-ppss)))
      (when (and (nth 4 state-test) (<= point-init (nth 8 state-test)))
        (setq state state-test)))))

(when (nth 4 state)
  (let ((start (nth 8 state)))
    (save-excursion
      (goto-char start)
      (forward-comment 1)
      (skip-syntax-backward ">")
      (cons start (point)))))))

(defun my-hs-hide-initial-comment-block (orig-fun &rest args) (my-with-advice 'hs-inside-comment-p :around (lambda (fn) (save-excursion (save-restriction (goto-char (point-min)) (skip-chars-forward " \t\n\f") (let ((bounds (my-comment-bounds))) (when bounds (narrow-to-region (car bounds) (cdr bounds)))) (funcall fn)))) (apply orig-fun args)))

(with-eval-after-load 'hideshow (advice-add 'hs-hide-initial-comment-block :around #'my-hs-hide-initial-comment-block))

ideasman42
  • 8,786
  • 1
  • 32
  • 114