(comment-style(s)): Replaces comment-extra-lines (and comment-multi-line).
[emacs.git] / lisp / progmodes / hideshow.el
blob85c917cdae72169d77f9019bb05048e0c9cc1baf
1 ;;; hideshow.el --- minor mode cmds to selectively display blocks of code
3 ;; Copyright (C) 1994, 95, 96, 97, 98 Free Software Foundation
5 ;; Author: Thien-Thi Nguyen <ttn@netcom.com>
6 ;; Dan Nicolaescu <dann@ics.uci.edu>
7 ;; Keywords: C C++ java lisp tools editing comments blocks hiding outlines
8 ;; Maintainer-Version: 4.22
9 ;; Time-of-Day-Author-Most-Likely-to-be-Recalcitrant: early morning
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
28 ;;; Commentary:
30 ;; - Commands provided
32 ;; This file provides `hs-minor-mode'. When active, seven commands:
34 ;; hs-{hide,show}-{all,block}, hs-show-region,
35 ;; hs-hide-level and hs-minor-mode
37 ;; are available, implementing block hiding and showing. Blocks are
38 ;; defined per mode. In c-mode or c++-mode, they are simply curly braces,
39 ;; while in Lisp-ish modes they are parens. Multi-line comments can also
40 ;; be hidden. The command `M-x hs-minor-mode' toggles the minor mode or
41 ;; sets it (similar to outline minor mode).
43 ;; - Customization
45 ;; Variables control things thusly:
47 ;; hs-hide-comments-when-hiding-all -- self-explanatory!
48 ;; hs-show-hidden-short-form -- whether or not the last line in a form
49 ;; is omitted (saving screen space)
50 ;; hs-isearch-open -- what kind of hidden blocks to open when
51 ;; doing isearch
52 ;; hs-special-modes-alist -- keeps at bay hideshow's heuristics with
53 ;; respect to block definitions
55 ;; Hooks are run after some commands:
57 ;; hs-hide-hook in hs-hide-block, hs-hide-all, hs-hide-level
58 ;; hs-show-hook hs-show-block, hs-show-all, hs-show-region
60 ;; See docs for each variable or hook for more info.
62 ;; - Suggested usage
64 ;; (load-library "hideshow")
65 ;; (add-hook 'X-mode-hook 'hs-minor-mode) ; other modes similarly
67 ;; where X = {emacs-lisp,c,c++,perl,...}. See the doc for the variable
68 ;; `hs-special-modes-alist' if you'd like to use hideshow w/ other modes.
70 ;; - Bugs / caveats
72 ;; 1. Hideshow does not work w/ emacs 18 because emacs 18 lacks the
73 ;; function `forward-comment' (among other things). If someone writes
74 ;; this, please send me a copy.
76 ;; 2. Users of cc-mode.el should not hook hideshow into
77 ;; c-mode-common-hook since at that stage of the call sequence, the
78 ;; variables `comment-start' and `comment-end' are not yet provided.
79 ;; Instead, use c-mode-hook and c++-mode-hook as suggested above.
81 ;; - Thanks and feedback
83 ;; Thanks go to the following people for valuable ideas, code and bug
84 ;; reports.
85 ;; adahome@ix.netcom.com Dean Andrews
86 ;; alfh@ifi.uio.no Alf-Ivar Holm
87 ;; gael@gnlab030.grenoble.hp.com Gael Marziou
88 ;; jan.djarv@sa.erisoft.se Jan Djarv
89 ;; preston.f.crow@dartmouth.edu Preston F. Crow
90 ;; qhslali@aom.ericsson.se Lars Lindberg
91 ;; sheff@edcsgw2.cr.usgs.gov Keith Sheffield
92 ;; ware@cis.ohio-state.edu Pete Ware
93 ;; d.love@dl.ac.uk Dave Love
95 ;; Special thanks go to Dan Nicolaescu <dann@ics.uci.edu>, who
96 ;; reimplemented hideshow using overlays (rather than selective display),
97 ;; added isearch magic, folded in custom.el compatibility, generalized
98 ;; comment handling, incorporated mouse support, and maintained the code
99 ;; in general. Version 4.0 is largely due to his efforts.
101 ;; Correspondance welcome; please indicate version number.
103 ;;; Code:
105 (require 'easymenu)
107 ;;;----------------------------------------------------------------------------
108 ;;; user-configurable variables
110 (defgroup hideshow nil
111 "Minor mode for hiding and showing program and comment blocks."
112 :prefix "hs-"
113 :group 'languages)
115 ;;;###autoload
116 (defcustom hs-hide-comments-when-hiding-all t
117 "Hide the comments too when you do an `hs-hide-all'."
118 :type 'boolean
119 :group 'hideshow)
121 ;;;###autoload
122 (defcustom hs-show-hidden-short-form t
123 "Leave only the first line visible in a hidden block.
124 If non-nil only the first line is visible when a block is in the
125 hidden state, else both the first line and the last line are shown.
126 A nil value disables `hs-adjust-block-beginning', which see.
128 An example of how this works: (in C mode)
129 original:
131 /* My function main
132 some more stuff about main
135 main(void)
137 int x=0;
138 return 0;
142 hidden and `hs-show-hidden-short-form' is nil
143 /* My function main...
146 main(void)
147 {...
150 hidden and `hs-show-hidden-short-form' is t
151 /* My function main...
153 main(void)...
155 For the last case you have to be on the line containing the
156 ellipsis when you do `hs-show-block'."
157 :type 'boolean
158 :group 'hideshow)
160 (defcustom hs-minor-mode-hook 'hs-hide-initial-comment-block
161 "Hook called when `hs-minor-mode' is installed.
162 A good value for this would be `hs-hide-initial-comment-block' to
163 hide all the comments at the beginning of the file."
164 :type 'hook
165 :group 'hideshow)
167 (defcustom hs-isearch-open 'block
168 "What kind of hidden blocks to open when doing `isearch'.
169 One of the following values:
171 block -- open only blocks
172 comment -- open only comments
173 t -- open both blocks and comments
174 nil -- open neither blocks nor comments
176 This has effect iff `search-invisible' is set to `open'."
177 :type '(choice (const :tag "open only blocks" block)
178 (const :tag "open only comments" comment)
179 (const :tag "open both blocks and comments" t)
180 (const :tag "don't open any of them" nil))
181 :group 'hideshow)
183 ;;;###autoload
184 (defvar hs-special-modes-alist
185 '((c-mode "{" "}" nil nil hs-c-like-adjust-block-beginning)
186 (c++-mode "{" "}" "/[*/]" nil hs-c-like-adjust-block-beginning)
187 (java-mode "\\(\\(\\([ \t]*\\(\\(abstract\\|final\\|native\\|p\\(r\\(ivate\\|otected\\)\\|ublic\\)\\|s\\(tatic\\|ynchronized\\)\\)[ \t\n]+\\)*[.a-zA-Z0-9_:]+[ \t\n]*\\(\\[[ \t\n]*\\][ \t\n]*\\)?\\([a-zA-Z0-9_:]+[ \t\n]*\\)([^)]*)\\([ \n\t]+throws[ \t\n][^{]+\\)?\\)\\|\\([ \t]*static[^{]*\\)\\)[ \t\n]*{\\)" "}" "/[*/]" java-hs-forward-sexp hs-c-like-adjust-block-beginning))
188 ; I tested the java regexp using the following:
189 ;(defvar hsj-public)
190 ;(defvar hsj-type)
191 ;(defvar hsj-fname)
192 ;(defvar hsj-par)
193 ;(defvar hsj-throws)
194 ;(defvar hsj-static)
196 ;(setq hsj-public
197 ; (concat "[ \t]*\\("
198 ; (regexp-opt '("public" "private" "protected" "abstract"
199 ; "synchronized" "static" "final" "native") 1)
200 ; "[ \t\n]+\\)*"))
202 ;(setq hsj-type "[.a-zA-Z0-9_:]+[ \t\n]*\\(\\[[ \t\n]*\\][ \t\n]*\\)?")
203 ;(setq hsj-fname "\\([a-zA-Z0-9_:]+[ \t\n]*\\)")
204 ;(setq hsj-par "([^)]*)")
205 ;(setq hsj-throws "\\([ \n\t]+throws[ \t\n][^{]+\\)?")
207 ;(setq hsj-static "[ \t]*static[^{]*")
210 ;(setq hs-block-start-regexp (concat
211 ; "\\("
212 ; "\\("
213 ; "\\("
214 ; hsj-public
215 ; hsj-type
216 ; hsj-fname
217 ; hsj-par
218 ; hsj-throws
219 ; "\\)"
220 ; "\\|"
221 ; "\\("
222 ; hsj-static
223 ; "\\)"
224 ; "\\)"
225 ; "[ \t\n]*{"
226 ; "\\)"
227 ; ))
229 "*Alist for initializing the hideshow variables for different modes.
230 It has the form
231 (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC).
232 If present, hideshow will use these values as regexps for start, end
233 and comment-start, respectively. Since Algol-ish languages do not have
234 single-character block delimiters, the function `forward-sexp' used
235 by hideshow doesn't work. In this case, if a similar function is
236 available, you can register it and have hideshow use it instead of
237 `forward-sexp'. See the documentation for `hs-adjust-block-beginning'
238 to see what is the use of ADJUST-BEG-FUNC.
240 If any of those is left nil, hideshow will try to guess some values
241 using function `hs-grok-mode-type'.
243 Note that the regexps should not contain leading or trailing whitespace.")
245 (defvar hs-hide-hook nil
246 "*Hooks called at the end of commands to hide text.
247 These commands include `hs-hide-all', `hs-hide-block' and `hs-hide-level'.")
249 (defvar hs-show-hook nil
250 "*Hooks called at the end of commands to show text.
251 These commands include `hs-show-all', `hs-show-block' and `hs-show-region'.")
253 (defvar hs-minor-mode-prefix "\C-c"
254 "*Prefix key to use for hideshow commands in hideshow minor mode.")
256 ;;;----------------------------------------------------------------------------
257 ;;; internal variables
259 (defvar hs-minor-mode nil
260 "Non-nil if using hideshow mode as a minor mode of some other mode.
261 Use the command `hs-minor-mode' to toggle this variable.")
263 (defvar hs-minor-mode-map nil
264 "Mode map for hideshow minor mode.")
266 ;(defvar hs-menu-bar nil
267 ; "Menu bar for hideshow minor mode (Xemacs only).")
269 (defvar hs-c-start-regexp nil
270 "Regexp for beginning of comments.
271 Differs from mode-specific comment regexps in that
272 surrounding whitespace is stripped.")
274 (defvar hs-block-start-regexp nil
275 "Regexp for beginning of block.")
277 (defvar hs-block-end-regexp nil
278 "Regexp for end of block.")
280 (defvar hs-forward-sexp-func 'forward-sexp
281 "Function used to do a `forward-sexp'.
282 Should change for Algol-ish modes. For single-character block
283 delimiters -- ie, the syntax table regexp for the character is
284 either `(' or `)' -- `hs-forward-sexp-func' would just be
285 `forward-sexp'. For other modes such as simula, a more specialized
286 function is necessary.")
288 (defvar hs-adjust-block-beginning nil
289 "Function used to tweak the block beginning.
290 It has effect only if `hs-show-hidden-short-form' is non-nil.
291 The block it is hidden from the point returned by this function,
292 as opposed to hiding it from the point returned when searching
293 `hs-block-start-regexp'. In c-like modes, if we wish to also hide the
294 curly braces (if you think they occupy too much space on the screen),
295 this function should return the starting point (at the end of line) of
296 the hidden region.
298 It is called with a single argument ARG which is the the position in
299 buffer after the block beginning.
301 It should return the position from where we should start hiding.
303 It should not move the point.
305 See `hs-c-like-adjust-block-beginning' for an example of using this.")
307 ;(defvar hs-emacs-type 'fsf
308 ; "Used to support both Emacs and Xemacs.")
310 ;(eval-when-compile
311 ; (if (string-match "xemacs\\|lucid" emacs-version)
312 ; (progn
313 ; (defvar current-menubar nil "")
314 ; (defun set-buffer-menubar (arg1))
315 ; (defun add-menu (arg1 arg2 arg3)))))
317 ;;;----------------------------------------------------------------------------
318 ;;; support funcs
320 ;; snarfed from outline.el;
321 (defun hs-flag-region (from to flag)
322 "Hide or show lines from FROM to TO, according to FLAG.
323 If FLAG is nil then text is shown, while if FLAG is non-nil the text
324 is hidden. Actually flag is really either `comment' or `block'
325 depending on what kind of block it is suppose to hide."
326 (save-excursion
327 (goto-char from)
328 (end-of-line)
329 (hs-discard-overlays (point) to 'invisible 'hs)
330 (if flag
331 (let ((overlay (make-overlay (point) to)))
332 ;; Make overlay hidden and intangible.
333 (overlay-put overlay 'invisible 'hs)
334 (overlay-put overlay 'hs t)
335 (when (or (eq hs-isearch-open t) (eq hs-isearch-open flag))
336 (overlay-put overlay 'isearch-open-invisible
337 'hs-isearch-open-invisible))
338 (overlay-put overlay 'intangible t)))))
340 ;; This is set as an `isearch-open-invisible' property to hidden
341 ;; overlays.
342 (defun hs-isearch-open-invisible (ov)
343 (save-excursion
344 (goto-char (overlay-start ov))
345 (hs-show-block)))
347 ;; Remove from the region BEG ... END all overlays
348 ;; with a PROP property equal to VALUE.
349 ;; Overlays with a PROP property different from VALUE are not touched.
350 (defun hs-discard-overlays (beg end prop value)
351 (if (< end beg)
352 (setq beg (prog1 end (setq end beg))))
353 (save-excursion
354 (goto-char beg)
355 (let ((overlays (overlays-in beg end))
357 (while overlays
358 (setq o (car overlays))
359 (if (eq (overlay-get o prop) value)
360 (delete-overlay o))
361 (setq overlays (cdr overlays))))))
363 (defun hs-hide-block-at-point (&optional end comment-reg)
364 "Hide block iff on block beginning.
365 Optional arg END means reposition at end.
366 Optional arg COMMENT-REG is a list of the form (BEGIN . END) and
367 specifies the limits of the comment, or nil if the block is not
368 a comment."
369 (if comment-reg
370 (progn
371 ;; goto the end of line at the end of the comment
372 (goto-char (nth 1 comment-reg))
373 (unless hs-show-hidden-short-form (forward-line -1))
374 (end-of-line)
375 (hs-flag-region (car comment-reg) (point) 'comment)
376 (goto-char (if end (nth 1 comment-reg) (car comment-reg))))
377 (if (looking-at hs-block-start-regexp)
378 (let* ((p ;; p is the point at the end of the block beginning
379 (if (and hs-show-hidden-short-form
380 hs-adjust-block-beginning)
381 ;; we need to adjust the block beginning
382 (funcall hs-adjust-block-beginning (match-end 0))
383 (match-end 0)))
384 ;; q is the point at the end of the block
385 (q (progn (funcall hs-forward-sexp-func 1) (point))))
386 ;; position the point so we can call `hs-flag-region'
387 (unless hs-show-hidden-short-form (forward-line -1))
388 (end-of-line)
389 (if (and (< p (point)) (> (count-lines p q)
390 (if hs-show-hidden-short-form 1 2)))
391 (hs-flag-region p (point) 'block))
392 (goto-char (if end q p))))))
394 (defun hs-show-block-at-point (&optional end comment-reg)
395 "Show block iff on block beginning.
396 Optional arg END means reposition at end.
397 Optional arg COMMENT-REG is a list of the forme (BEGIN . END) and
398 specifies the limits of the comment. It should be nil when hiding
399 a block."
400 (if comment-reg
401 (when (car comment-reg)
402 (hs-flag-region (car comment-reg) (nth 1 comment-reg) nil)
403 (goto-char (if end (nth 1 comment-reg) (car comment-reg))))
404 (if (looking-at hs-block-start-regexp)
405 (let* ((p (point))
407 (condition-case error ; probably unbalanced paren
408 (progn
409 (funcall hs-forward-sexp-func 1)
410 (point))
411 (error
412 ;; try to get out of rat's nest and expose the whole func
413 (if (/= (current-column) 0) (beginning-of-defun))
414 (setq p (point))
415 (re-search-forward (concat "^" hs-block-start-regexp)
416 (point-max) t 2)
417 (point)))))
418 (hs-flag-region p q nil)
419 (goto-char (if end (1+ (point)) p))))))
421 (defun hs-safety-is-job-n ()
422 "Warn if `buffer-invisibility-spec' does not contain hs."
423 (if (or buffer-invisibility-spec (assq 'hs buffer-invisibility-spec) )
425 (message "Warning: `buffer-invisibility-spec' does not contain hs!!")
426 (sit-for 2)))
428 (defun hs-hide-initial-comment-block ()
429 (interactive)
430 "Hide the first block of comments in a file.
431 This is useful when a part of `hs-minor-mode-hook', especially with
432 huge header-comment RCS logs."
433 (let ((p (point))
434 c-reg)
435 (goto-char (point-min))
436 (skip-chars-forward " \t\n^L")
437 (setq c-reg (hs-inside-comment-p))
438 ;; see if we have enough comment lines to hide
439 (if (and c-reg (> (count-lines (car c-reg) (nth 1 c-reg))
440 (if hs-show-hidden-short-form 1 2)))
441 (hs-hide-block)
442 (goto-char p))))
444 (defun hs-inside-comment-p ()
445 "Return non-nil if point is inside a comment, otherwise nil.
446 Actually, returns a list containing the buffer position of the start
447 and the end of the comment. A comment block can be hidden only if on
448 its starting line there is only whitespace preceding the actual comment
449 beginning. If we are inside of a comment but this condition is not met,
450 we return a list having a nil as its car and the end of comment position
451 as cdr."
452 (save-excursion
453 ;; the idea is to look backwards for a comment start regexp, do a
454 ;; forward comment, and see if we are inside, then extend extend
455 ;; forward and backward as long as we have comments
456 (let ((q (point)))
457 (when (or (looking-at hs-c-start-regexp)
458 (re-search-backward hs-c-start-regexp (point-min) t))
459 (forward-comment (- (buffer-size)))
460 (skip-chars-forward " \t\n\f")
461 (let ((p (point))
462 (not-hidable nil))
463 (beginning-of-line)
464 (unless (looking-at (concat "[ \t]*" hs-c-start-regexp))
465 ;; we are in this situation: (example)
466 ;; (defun bar ()
467 ;; (foo)
468 ;; ) ; comment
469 ;; ^
470 ;; the point was here before doing (beginning-of-line)
471 ;; here we should advance till the next comment which
472 ;; eventually has only white spaces preceding it on the same
473 ;; line
474 (goto-char p)
475 (forward-comment 1)
476 (skip-chars-forward " \t\n\f")
477 (setq p (point))
478 (while (and (< (point) q)
479 (> (point) p)
480 (not (looking-at hs-c-start-regexp)))
481 (setq p (point)) ;; use this to avoid an infinit cycle.
482 (forward-comment 1)
483 (skip-chars-forward " \t\n\f"))
484 (if (or (not (looking-at hs-c-start-regexp))
485 (> (point) q))
486 ;; we cannot hide this comment block
487 (setq not-hidable t)))
488 ;; goto the end of the comment
489 (forward-comment (buffer-size))
490 (skip-chars-backward " \t\n\f")
491 (end-of-line)
492 (if (>= (point) q)
493 (list (if not-hidable nil p) (point))))))))
495 (defun hs-grok-mode-type ()
496 "Set up hideshow variables for new buffers.
497 If `hs-special-modes-alist' has information associated with the
498 current buffer's major mode, use that.
499 Otherwise, guess start, end and comment-start regexps; forward-sexp
500 function; and adjust-block-beginning function."
501 (if (and (boundp 'comment-start)
502 (boundp 'comment-end)
503 comment-start comment-end)
504 (let ((lookup (assoc major-mode hs-special-modes-alist)))
505 (setq hs-block-start-regexp (or (nth 1 lookup) "\\s\(")
506 hs-block-end-regexp (or (nth 2 lookup) "\\s\)")
507 hs-c-start-regexp (or (nth 3 lookup)
508 (let ((c-start-regexp
509 (regexp-quote comment-start)))
510 (if (string-match " +$" c-start-regexp)
511 (substring c-start-regexp 0 (1- (match-end 0)))
512 c-start-regexp)))
513 hs-forward-sexp-func (or (nth 4 lookup) 'forward-sexp)
514 hs-adjust-block-beginning (nth 5 lookup)))
515 (error "%s Mode doesn't support Hideshow Mode" mode-name)))
517 (defun hs-find-block-beginning ()
518 "Reposition point at block-start.
519 Return point, or nil if top-level."
520 (let (done
521 (try-again t)
522 (here (point))
523 (both-regexps (concat "\\(" hs-block-start-regexp "\\)\\|\\("
524 hs-block-end-regexp "\\)"))
525 (buf-size (buffer-size)))
526 (beginning-of-line)
527 ;; A block beginning can span on multiple lines, if the point
528 ;; is on one of those lines, trying a regexp search from
529 ;; that point would fail to find the block beginning, so we look
530 ;; backwards for the block beginning, or a block end.
531 (while try-again
532 (setq try-again nil)
533 (if (and (re-search-backward both-regexps (point-min) t)
534 (match-beginning 1)) ; found a block beginning
535 (if (save-match-data (hs-inside-comment-p))
536 ;;but it was inside a comment, so we have to look for
537 ;;it again
538 (setq try-again t)
539 ;; that's what we were looking for
540 (setq done (match-beginning 0)))
541 ;; we found a block end, or we reached the beginning of the
542 ;; buffer look to see if we were on a block beginning when we
543 ;; started
544 (if (and
545 (re-search-forward hs-block-start-regexp (point-max) t)
547 (and (>= here (match-beginning 0)) (< here (match-end 0)))
548 (and hs-show-hidden-short-form hs-adjust-block-beginning
549 (save-match-data
550 (= 1 (count-lines
551 (funcall hs-adjust-block-beginning
552 (match-end 0)) here))))))
553 (setq done (match-beginning 0)))))
554 (goto-char here)
555 (while (and (not done)
556 ;; This had problems because the regexp can match something
557 ;; inside of a comment!
558 ;; Since inside a comment we can have incomplete sexps
559 ;; this would have signaled an error.
560 (or (forward-comment (- buf-size)) t); `or' is a hack to
561 ; make it return t
562 (re-search-backward both-regexps (point-min) t))
563 (if (match-beginning 1) ; start of start-regexp
564 (setq done (match-beginning 0))
565 (goto-char (match-end 0)) ; end of end-regexp
566 (funcall hs-forward-sexp-func -1)))
567 (goto-char (or done here))
568 done))
570 (defun hs-hide-level-recursive (arg minp maxp)
571 "Hide blocks ARG levels below this block recursively."
572 (when (hs-find-block-beginning)
573 (setq minp (1+ (point)))
574 (forward-sexp)
575 (setq maxp (1- (point))))
576 (hs-flag-region minp maxp ?\n) ; eliminate weirdness
577 (goto-char minp)
578 (while (progn
579 (forward-comment (buffer-size))
580 (re-search-forward hs-block-start-regexp maxp t))
581 (if (> arg 1)
582 (hs-hide-level-recursive (1- arg) minp maxp)
583 (goto-char (match-beginning 0))
584 (hs-hide-block-at-point t)))
585 (hs-safety-is-job-n)
586 (goto-char maxp))
588 (defmacro hs-life-goes-on (&rest body)
589 "Execute optional BODY iff variable `hs-minor-mode' is non-nil."
590 `(let ((inhibit-point-motion-hooks t))
591 (when hs-minor-mode
592 ,@body)))
594 (put 'hs-life-goes-on 'edebug-form-spec '(&rest form))
596 (defun hs-already-hidden-p ()
597 "Return non-nil if point is in an already-hidden block, otherwise nil."
598 (save-excursion
599 (let ((c-reg (hs-inside-comment-p)))
600 (if (and c-reg (nth 0 c-reg))
601 ;; point is inside a comment, and that comment is hidable
602 (goto-char (nth 0 c-reg))
603 (if (and (not c-reg) (hs-find-block-beginning)
604 (looking-at hs-block-start-regexp))
605 ;; point is inside a block
606 (goto-char (match-end 0)))))
607 (end-of-line)
608 (let ((overlays (overlays-at (point)))
609 (found nil))
610 (while (and (not found) (overlayp (car overlays)))
611 (setq found (overlay-get (car overlays) 'hs)
612 overlays (cdr overlays)))
613 found)))
615 (defun java-hs-forward-sexp (arg)
616 "Function used by `hs-minor-mode' for `forward-sexp' in Java mode."
617 (if (< arg 0)
618 (backward-sexp 1)
619 (if (looking-at hs-block-start-regexp)
620 (progn
621 (goto-char (match-end 0))
622 (forward-char -1)
623 (forward-sexp 1))
624 (forward-sexp 1))))
626 (defun hs-c-like-adjust-block-beginning (arg)
627 "Function to be assigned to `hs-adjust-block-beginning' for C-like modes.
628 Arg is a position in buffer just after {. This goes back to the end of
629 the function header. The purpose is to save some space on the screen
630 when displaying hidden blocks."
631 (save-excursion
632 (goto-char arg)
633 (forward-char -1)
634 (forward-comment (- (buffer-size)))
635 (point)))
637 ;;;----------------------------------------------------------------------------
638 ;;; commands
640 ;;;###autoload
641 (defun hs-hide-all ()
642 "Hide all top-level blocks, displaying only first and last lines.
643 Move point to the beginning of the line, and it run the normal hook
644 `hs-hide-hook'. See documentation for `run-hooks'.
645 If `hs-hide-comments-when-hiding-all' is t, also hide the comments."
646 (interactive)
647 (hs-life-goes-on
648 (message "Hiding all blocks ...")
649 (save-excursion
650 (hs-flag-region (point-min) (point-max) nil) ; eliminate weirdness
651 (goto-char (point-min))
652 (if hs-hide-comments-when-hiding-all
653 (let (c-reg
654 (count 0)
655 (block-and-comment-re ;; this should match
656 (concat "\\(^" ;; the block beginning and comment start
657 hs-block-start-regexp
658 "\\)\\|\\(" hs-c-start-regexp "\\)")))
659 (while (re-search-forward block-and-comment-re (point-max) t)
660 (if (match-beginning 1) ;; we have found a block beginning
661 (progn
662 (goto-char (match-beginning 1))
663 (hs-hide-block-at-point t)
664 (message "Hiding ... %d" (setq count (1+ count))))
665 ;;found a comment
666 (setq c-reg (hs-inside-comment-p))
667 (if (and c-reg (car c-reg))
668 (if (> (count-lines (car c-reg) (nth 1 c-reg))
669 (if hs-show-hidden-short-form 1 2))
670 (progn
671 (hs-hide-block-at-point t c-reg)
672 (message "Hiding ... %d" (setq count (1+ count))))
673 (goto-char (nth 1 c-reg)))))))
674 (let ((count 0)
675 (top-level-re (concat "^" hs-block-start-regexp))
676 (buf-size (buffer-size)))
677 (while
678 (progn
679 (forward-comment buf-size)
680 (re-search-forward top-level-re (point-max) t))
681 (goto-char (match-beginning 0))
682 (hs-hide-block-at-point t)
683 (message "Hiding ... %d" (setq count (1+ count))))))
684 (hs-safety-is-job-n))
685 (beginning-of-line)
686 (message "Hiding all blocks ... done")
687 (run-hooks 'hs-hide-hook)))
689 (defun hs-show-all ()
690 "Show all top-level blocks.
691 Point is unchanged; run the normal hook `hs-show-hook'.
692 See documentation for `run-hooks'."
693 (interactive)
694 (hs-life-goes-on
695 (message "Showing all blocks ...")
696 (hs-flag-region (point-min) (point-max) nil)
697 (message "Showing all blocks ... done")
698 (run-hooks 'hs-show-hook)))
700 (defun hs-hide-block (&optional end)
701 "Select a block and hide it.
702 With prefix arg, reposition at end. Block is defined as a sexp for
703 Lispish modes, mode-specific otherwise. Comments are blocks, too.
704 Upon completion, point is repositioned and the normal hook
705 `hs-hide-hook' is run. See documentation for `run-hooks'."
706 (interactive "P")
707 (hs-life-goes-on
708 (let ((c-reg (hs-inside-comment-p)))
709 (cond
710 ((and c-reg (or (null (nth 0 c-reg))
711 (<= (count-lines (car c-reg) (nth 1 c-reg))
712 (if hs-show-hidden-short-form 1 2))))
713 (message "Not enough comment lines to hide!"))
714 ((or c-reg (looking-at hs-block-start-regexp)
715 (hs-find-block-beginning))
716 (hs-hide-block-at-point end c-reg)
717 (hs-safety-is-job-n)
718 (run-hooks 'hs-hide-hook))))))
720 (defun hs-show-block (&optional end)
721 "Select a block and show it.
722 With prefix arg, reposition at end. Upon completion, point is
723 repositioned and the normal hook `hs-show-hook' is run.
724 See documentation for `hs-hide-block' and `run-hooks'."
725 (interactive "P")
726 (hs-life-goes-on
727 (let ((c-reg (hs-inside-comment-p)))
728 (if (or c-reg
729 (looking-at hs-block-start-regexp)
730 (hs-find-block-beginning))
731 (progn
732 (hs-show-block-at-point end c-reg)
733 (hs-safety-is-job-n)
734 (run-hooks 'hs-show-hook))))))
736 (defun hs-show-region (beg end)
737 "Show all lines from BEG to END, without doing any block analysis.
738 Note: `hs-show-region' is intended for use when `hs-show-block' signals
739 \"unbalanced parentheses\" and so is an emergency measure only. You may
740 become very confused if you use this command indiscriminately."
741 (interactive "r")
742 (hs-life-goes-on
743 (hs-flag-region beg end nil)
744 (hs-safety-is-job-n)
745 (run-hooks 'hs-show-hook)))
747 (defun hs-hide-level (arg)
748 "Hide all blocks ARG levels below this block."
749 (interactive "p")
750 (hs-life-goes-on
751 (save-excursion
752 (message "Hiding blocks ...")
753 (hs-hide-level-recursive arg (point-min) (point-max))
754 (message "Hiding blocks ... done"))
755 (hs-safety-is-job-n)
756 (run-hooks 'hs-hide-hook)))
758 ;;;###autoload
759 (defun hs-mouse-toggle-hiding (e)
760 "Toggle hiding/showing of a block.
761 Should be bound to a mouse key."
762 (interactive "@e")
763 (mouse-set-point e)
764 (if (hs-already-hidden-p)
765 (hs-show-block)
766 (hs-hide-block)))
768 ;;;###autoload
769 (defun hs-minor-mode (&optional arg)
770 "Toggle hideshow minor mode.
771 With ARG, turn hideshow minor mode on if ARG is positive, off otherwise.
772 When hideshow minor mode is on, the menu bar is augmented with hideshow
773 commands and the hideshow commands are enabled.
774 The value '(hs . t) is added to `buffer-invisibility-spec'.
775 Last, the normal hook `hs-minor-mode-hook' is run; see the doc
776 for `run-hooks'.
778 The main commands are: `hs-hide-all', `hs-show-all', `hs-hide-block',
779 `hs-show-block', `hs-hide-level' and `hs-show-region'.
780 Also see the documentation for the variable `hs-show-hidden-short-form'.
782 Turning hideshow minor mode off reverts the menu bar and the
783 variables to default values and disables the hideshow commands.
785 Key bindings:
786 \\{hs-minor-mode-map}"
788 (interactive "P")
789 (setq hs-minor-mode
790 (if (null arg)
791 (not hs-minor-mode)
792 (> (prefix-numeric-value arg) 0)))
793 (if hs-minor-mode
794 (progn
795 ; (if (eq hs-emacs-type 'lucid)
796 ; (progn
797 ; (set-buffer-menubar (copy-sequence current-menubar))
798 ; (add-menu nil (car hs-menu-bar) (cdr hs-menu-bar))))
799 (make-local-variable 'line-move-ignore-invisible)
800 (setq line-move-ignore-invisible t)
801 (add-to-invisibility-spec '(hs . t)) ;;hs invisible
802 (hs-grok-mode-type)
803 (run-hooks 'hs-minor-mode-hook))
804 ; (if (eq hs-emacs-type 'lucid)
805 ; (set-buffer-menubar (delete hs-menu-bar current-menubar)))
806 (remove-from-invisibility-spec '(hs . t))))
809 ;;;----------------------------------------------------------------------------
810 ;;; load-time setup routines
812 ;; which emacs being used?
813 ;(setq hs-emacs-type
814 ; (if (string-match "xemacs\\|lucid" emacs-version)
815 ; 'lucid
816 ; 'fsf))
818 ;; keymaps and menus
819 (if hs-minor-mode-map
821 (setq hs-minor-mode-map (make-sparse-keymap))
822 (easy-menu-define hs-minor-mode-menu
823 hs-minor-mode-map
824 "Menu used when hideshow minor mode is active."
825 (cons "Hide/Show"
826 (mapcar
827 ;; populate keymap then massage entry for easymenu
828 (lambda (ent)
829 (define-key hs-minor-mode-map (aref ent 2) (aref ent 1))
830 (aset ent 2 (not (vectorp (aref ent 2)))) ; disable mousy stuff
831 ent)
832 ;; I believe there is nothing bound on these keys
833 ;; menu entry command key
834 '(["Hide Block" hs-hide-block "\C-ch"]
835 ["Show Block" hs-show-block "\C-cs"]
836 ["Hide All" hs-hide-all "\C-cH"]
837 ["Show All" hs-show-all "\C-cS"]
838 ["Hide Level" hs-hide-level "\C-cL"]
839 ["Show Region" hs-show-region "\C-cR"]
840 ["Toggle Hiding" hs-mouse-toggle-hiding [S-mouse-2]]
841 )))))
843 ;; some housekeeping
844 (or (assq 'hs-minor-mode minor-mode-map-alist)
845 (setq minor-mode-map-alist
846 (cons (cons 'hs-minor-mode hs-minor-mode-map)
847 minor-mode-map-alist)))
848 (or (assq 'hs-minor-mode minor-mode-alist)
849 (setq minor-mode-alist (append minor-mode-alist
850 (list '(hs-minor-mode " hs")))))
852 ;; make some variables permanently buffer-local
853 (mapcar (lambda (var)
854 (make-variable-buffer-local var)
855 (put var 'permanent-local t))
856 '(hs-minor-mode
857 hs-c-start-regexp
858 hs-block-start-regexp
859 hs-block-end-regexp
860 hs-forward-sexp-func
861 hs-adjust-block-beginning))
863 ;;;----------------------------------------------------------------------------
864 ;;; that's it
866 (provide 'hideshow)
868 ;;; hideshow.el ends here