diff options
| author | Stefan Monnier | 2003-03-13 18:15:07 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2003-03-13 18:15:07 +0000 |
| commit | 21a3d3e7c97da660fd5c45b9d0d2c5a969b2e3b7 (patch) | |
| tree | 9de02d72b366996402a5e0fb77af33565fc3b0d1 /lisp/textmodes | |
| parent | df380962210bb5f655f9ad80b38e88a8254b6b61 (diff) | |
| download | emacs-21a3d3e7c97da660fd5c45b9d0d2c5a969b2e3b7.tar.gz emacs-21a3d3e7c97da660fd5c45b9d0d2c5a969b2e3b7.zip | |
(outline-mode-menu-bar-map): Add entries.
(outline-mode-prefix-map): Match new bindings to those of allout.
(outline-map-region): New fun.
(outline-map-tree): Remove.
(outline-promote, outline-demote): Apply to region if active.
Change the default to apply to the subtree.
(outline-move-subtree-up, outline-move-subtree-down): New funs.
(outline-invisible-p): Add optional `pos' argument.
(outline-next-visible-heading, outline-toggle-children): Use it.
(outline-get-next-sibling): Don't call outline-level at eob.
Diffstat (limited to 'lisp/textmodes')
| -rw-r--r-- | lisp/textmodes/outline.el | 226 |
1 files changed, 152 insertions, 74 deletions
diff --git a/lisp/textmodes/outline.el b/lisp/textmodes/outline.el index ffb9c3bd881..fe8f747cb99 100644 --- a/lisp/textmodes/outline.el +++ b/lisp/textmodes/outline.el | |||
| @@ -80,9 +80,12 @@ in the file it applies to." | |||
| 80 | (define-key map "\C-k" 'show-branches) | 80 | (define-key map "\C-k" 'show-branches) |
| 81 | (define-key map "\C-q" 'hide-sublevels) | 81 | (define-key map "\C-q" 'hide-sublevels) |
| 82 | (define-key map "\C-o" 'hide-other) | 82 | (define-key map "\C-o" 'hide-other) |
| 83 | (define-key map "\C-^" 'outline-promote) | 83 | (define-key map "\C-^" 'outline-move-subtree-up) |
| 84 | (define-key map "\C-v" 'outline-demote) | 84 | (define-key map "\C-v" 'outline-move-subtree-down) |
| 85 | ;; Where to bind toggle and insert-heading ? | 85 | (define-key map [(control ?<)] 'outline-promote) |
| 86 | (define-key map [(control ?>)] 'outline-demote) | ||
| 87 | (define-key map "\C-m" 'outline-insert-heading) | ||
| 88 | ;; Where to bind outline-cycle ? | ||
| 86 | map)) | 89 | map)) |
| 87 | 90 | ||
| 88 | (defvar outline-mode-menu-bar-map | 91 | (defvar outline-mode-menu-bar-map |
| @@ -108,9 +111,19 @@ in the file it applies to." | |||
| 108 | (define-key map [headings] | 111 | (define-key map [headings] |
| 109 | (cons "Headings" (make-sparse-keymap "Headings"))) | 112 | (cons "Headings" (make-sparse-keymap "Headings"))) |
| 110 | 113 | ||
| 114 | (define-key map [headings demote-subtree] | ||
| 115 | '(menu-item "Demote subtree" outline-demote)) | ||
| 116 | (define-key map [headings promote-subtree] | ||
| 117 | '(menu-item "Promote subtree" outline-promote)) | ||
| 118 | (define-key map [headings move-subtree-down] | ||
| 119 | '(menu-item "Move subtree down" outline-move-subtree-down)) | ||
| 120 | (define-key map [headings move-subtree-up] | ||
| 121 | '(menu-item "Move subtree up" outline-move-subtree-up)) | ||
| 111 | (define-key map [headings copy] | 122 | (define-key map [headings copy] |
| 112 | '(menu-item "Copy to kill ring" outline-headers-as-kill | 123 | '(menu-item "Copy to kill ring" outline-headers-as-kill |
| 113 | :enable mark-active)) | 124 | :enable mark-active)) |
| 125 | (define-key map [headings outline-insert-heading] | ||
| 126 | '("New heading" . outline-insert-heading)) | ||
| 114 | (define-key map [headings outline-backward-same-level] | 127 | (define-key map [headings outline-backward-same-level] |
| 115 | '("Previous Same Level" . outline-backward-same-level)) | 128 | '("Previous Same Level" . outline-backward-same-level)) |
| 116 | (define-key map [headings outline-forward-same-level] | 129 | (define-key map [headings outline-forward-same-level] |
| @@ -139,7 +152,7 @@ in the file it applies to." | |||
| 139 | (cons '(--- "---") (cdr x)))) | 152 | (cons '(--- "---") (cdr x)))) |
| 140 | outline-mode-menu-bar-map)))))) | 153 | outline-mode-menu-bar-map)))))) |
| 141 | map)) | 154 | map)) |
| 142 | 155 | ||
| 143 | 156 | ||
| 144 | (defvar outline-mode-map | 157 | (defvar outline-mode-map |
| 145 | (let ((map (make-sparse-keymap))) | 158 | (let ((map (make-sparse-keymap))) |
| @@ -339,9 +352,9 @@ at the end of the buffer." | |||
| 339 | (re-search-backward (concat "^\\(?:" outline-regexp "\\)") | 352 | (re-search-backward (concat "^\\(?:" outline-regexp "\\)") |
| 340 | nil 'move)) | 353 | nil 'move)) |
| 341 | 354 | ||
| 342 | (defsubst outline-invisible-p () | 355 | (defsubst outline-invisible-p (&optional pos) |
| 343 | "Non-nil if the character after point is invisible." | 356 | "Non-nil if the character after point is invisible." |
| 344 | (get-char-property (point) 'invisible)) | 357 | (get-char-property (or pos (point)) 'invisible)) |
| 345 | 358 | ||
| 346 | (defun outline-visible () | 359 | (defun outline-visible () |
| 347 | (not (outline-invisible-p))) | 360 | (not (outline-invisible-p))) |
| @@ -391,75 +404,144 @@ If INVISIBLE-OK is non-nil, an invisible heading line is ok too." | |||
| 391 | (run-hooks 'outline-insert-heading-hook))) | 404 | (run-hooks 'outline-insert-heading-hook))) |
| 392 | 405 | ||
| 393 | (defun outline-promote (&optional children) | 406 | (defun outline-promote (&optional children) |
| 394 | "Promote the current heading higher up the tree. | 407 | "Promote headings higher up the tree. |
| 395 | If prefix argument CHILDREN is given, promote also all the children." | 408 | If prefix argument CHILDREN is given, promote also all the children. |
| 396 | (interactive "P") | 409 | If the region is active in `transient-mark-mode', promote all headings |
| 397 | (outline-back-to-heading) | 410 | in the region." |
| 398 | (let* ((head (match-string 0)) | 411 | (interactive |
| 399 | (level (save-match-data (funcall outline-level))) | 412 | (list (if (and transient-mark-mode mark-active) 'region |
| 400 | (up-head (or (car (rassoc (1- level) outline-heading-alist)) | 413 | (outline-back-to-heading) |
| 401 | (save-excursion | 414 | (if current-prefix-arg nil 'subtree)))) |
| 402 | (save-match-data | 415 | (cond |
| 403 | (outline-up-heading 1 t) | 416 | ((eq children 'region) |
| 404 | (match-string 0)))))) | 417 | (outline-map-region 'outline-promote (region-beginning) (region-end))) |
| 405 | 418 | (children | |
| 406 | (unless (rassoc level outline-heading-alist) | 419 | (outline-map-region 'outline-promote |
| 407 | (push (cons head level) outline-heading-alist)) | 420 | (point) |
| 408 | 421 | (save-excursion (outline-get-next-sibling) (point)))) | |
| 409 | (replace-match up-head nil t) | 422 | (t |
| 410 | (when children | 423 | (outline-back-to-heading t) |
| 411 | (outline-map-tree 'outline-promote level)))) | 424 | (let* ((head (match-string 0)) |
| 425 | (level (save-match-data (funcall outline-level))) | ||
| 426 | (up-head (or (car (rassoc (1- level) outline-heading-alist)) | ||
| 427 | (save-excursion | ||
| 428 | (save-match-data | ||
| 429 | (outline-up-heading 1 t) | ||
| 430 | (match-string 0)))))) | ||
| 431 | |||
| 432 | (unless (rassoc level outline-heading-alist) | ||
| 433 | (push (cons head level) outline-heading-alist)) | ||
| 434 | |||
| 435 | (replace-match up-head nil t))))) | ||
| 412 | 436 | ||
| 413 | (defun outline-demote (&optional children) | 437 | (defun outline-demote (&optional children) |
| 414 | "Demote the current heading lower down the tree. | 438 | "Demote headings lower down the tree. |
| 415 | If prefix argument CHILDREN is given, demote also all the children." | 439 | If prefix argument CHILDREN is given, demote also all the children. |
| 416 | (interactive "P") | 440 | If the region is active in `transient-mark-mode', demote all headings |
| 417 | (outline-back-to-heading) | 441 | in the region." |
| 418 | (let* ((head (match-string 0)) | 442 | (interactive |
| 419 | (level (save-match-data (funcall outline-level))) | 443 | (list (if (and transient-mark-mode mark-active) 'region |
| 420 | (down-head | 444 | (outline-back-to-heading) |
| 421 | (or (car (rassoc (1+ level) outline-heading-alist)) | 445 | (if current-prefix-arg nil 'subtree)))) |
| 422 | (save-excursion | 446 | (cond |
| 423 | (save-match-data | 447 | ((eq children 'region) |
| 424 | (while (and (not (eobp)) | 448 | (outline-map-region 'outline-demote (region-beginning) (region-end))) |
| 425 | (progn | 449 | (children |
| 426 | (outline-next-heading) | 450 | (outline-map-region 'outline-demote |
| 427 | (<= (funcall outline-level) level)))) | 451 | (point) |
| 428 | (when (eobp) | 452 | (save-excursion (outline-get-next-sibling) (point)))) |
| 429 | ;; Try again from the beginning of the buffer. | 453 | (t |
| 430 | (goto-char (point-min)) | 454 | (let* ((head (match-string 0)) |
| 455 | (level (save-match-data (funcall outline-level))) | ||
| 456 | (down-head | ||
| 457 | (or (car (rassoc (1+ level) outline-heading-alist)) | ||
| 458 | (save-excursion | ||
| 459 | (save-match-data | ||
| 431 | (while (and (not (eobp)) | 460 | (while (and (not (eobp)) |
| 432 | (progn | 461 | (progn |
| 433 | (outline-next-heading) | 462 | (outline-next-heading) |
| 434 | (<= (funcall outline-level) level))))) | 463 | (<= (funcall outline-level) level)))) |
| 435 | (unless (eobp) | 464 | (when (eobp) |
| 436 | (looking-at outline-regexp) | 465 | ;; Try again from the beginning of the buffer. |
| 437 | (match-string 0)))) | 466 | (goto-char (point-min)) |
| 438 | (save-match-data | 467 | (while (and (not (eobp)) |
| 439 | ;; Bummer!! There is no lower heading in the buffer. | 468 | (progn |
| 440 | ;; Let's try to invent one by repeating the first char. | 469 | (outline-next-heading) |
| 441 | (let ((new-head (concat (substring head 0 1) head))) | 470 | (<= (funcall outline-level) level))))) |
| 442 | (if (string-match (concat "\\`" outline-regexp) new-head) | 471 | (unless (eobp) |
| 443 | ;; Why bother checking that it is indeed of lower level ? | 472 | (looking-at outline-regexp) |
| 444 | new-head | 473 | (match-string 0)))) |
| 445 | ;; Didn't work: keep it as is so it's still a heading. | 474 | (save-match-data |
| 446 | head)))))) | 475 | ;; Bummer!! There is no lower heading in the buffer. |
| 476 | ;; Let's try to invent one by repeating the first char. | ||
| 477 | (let ((new-head (concat (substring head 0 1) head))) | ||
| 478 | (if (string-match (concat "\\`" outline-regexp) new-head) | ||
| 479 | ;; Why bother checking that it is indeed lower level ? | ||
| 480 | new-head | ||
| 481 | ;; Didn't work: keep it as is so it's still a heading. | ||
| 482 | head)))))) | ||
| 447 | 483 | ||
| 448 | (unless (rassoc level outline-heading-alist) | 484 | (unless (rassoc level outline-heading-alist) |
| 449 | (push (cons head level) outline-heading-alist)) | 485 | (push (cons head level) outline-heading-alist)) |
| 486 | (replace-match down-head nil t))))) | ||
| 450 | 487 | ||
| 451 | (replace-match down-head nil t) | 488 | (defun outline-map-region (fun beg end) |
| 452 | (when children | 489 | "Call FUN for every heading between BEG and END. |
| 453 | (outline-map-tree 'outline-demote level)))) | 490 | When FUN is called, point is at the beginning of the heading and |
| 454 | 491 | the match data is set appropriately." | |
| 455 | (defun outline-map-tree (fun level) | ||
| 456 | "Call FUN for every heading underneath the current one." | ||
| 457 | (save-excursion | 492 | (save-excursion |
| 458 | (while (and (progn | 493 | (setq end (copy-marker end)) |
| 459 | (outline-next-heading) | 494 | (goto-char beg) |
| 460 | (> (funcall outline-level) level)) | 495 | (when (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t) |
| 461 | (not (eobp))) | 496 | (goto-char (match-beginning 0)) |
| 462 | (funcall fun)))) | 497 | (funcall fun) |
| 498 | (while (and (progn | ||
| 499 | (outline-next-heading) | ||
| 500 | (< (point) end)) | ||
| 501 | (not (eobp))) | ||
| 502 | (funcall fun))))) | ||
| 503 | |||
| 504 | ;; Vertical tree motion | ||
| 505 | |||
| 506 | (defun outline-move-subtree-up (&optional arg) | ||
| 507 | "Move the currrent subtree up past ARG headlines of the same level." | ||
| 508 | (interactive "p") | ||
| 509 | (outline-move-subtree-down (- arg))) | ||
| 510 | |||
| 511 | (defun outline-move-subtree-down (&optional arg) | ||
| 512 | "Move the currrent subtree down past ARG headlines of the same level." | ||
| 513 | (interactive "p") | ||
| 514 | (let ((re (concat "^" outline-regexp)) | ||
| 515 | (movfunc (if (> arg 0) 'outline-get-next-sibling | ||
| 516 | 'outline-get-last-sibling)) | ||
| 517 | (ins-point (make-marker)) | ||
| 518 | (cnt (abs arg)) | ||
| 519 | beg end txt folded) | ||
| 520 | ;; Select the tree | ||
| 521 | (outline-back-to-heading) | ||
| 522 | (setq beg (point)) | ||
| 523 | (save-match-data | ||
| 524 | (save-excursion (outline-end-of-heading) | ||
| 525 | (setq folded (outline-invisible-p))) | ||
| 526 | (outline-end-of-subtree)) | ||
| 527 | (if (= (char-after) ?\n) (forward-char 1)) | ||
| 528 | (setq end (point)) | ||
| 529 | ;; Find insertion point, with error handling | ||
| 530 | (goto-char beg) | ||
| 531 | (while (> cnt 0) | ||
| 532 | (or (funcall movfunc) | ||
| 533 | (progn (goto-char beg) | ||
| 534 | (error "Cannot move past superior level"))) | ||
| 535 | (setq cnt (1- cnt))) | ||
| 536 | (if (> arg 0) | ||
| 537 | ;; Moving forward - still need to move over subtree | ||
| 538 | (progn (outline-end-of-subtree) | ||
| 539 | (if (= (char-after) ?\n) (forward-char 1)))) | ||
| 540 | (move-marker ins-point (point)) | ||
| 541 | (insert (delete-and-extract-region beg end)) | ||
| 542 | (goto-char ins-point) | ||
| 543 | (if folded (hide-subtree)) | ||
| 544 | (move-marker ins-point nil))) | ||
| 463 | 545 | ||
| 464 | (defun outline-end-of-heading () | 546 | (defun outline-end-of-heading () |
| 465 | (if (re-search-forward outline-heading-end-regexp nil 'move) | 547 | (if (re-search-forward outline-heading-end-regexp nil 'move) |
| @@ -484,9 +566,7 @@ A heading line is one that starts with a `*' (or that | |||
| 484 | (while (and (not (eobp)) | 566 | (while (and (not (eobp)) |
| 485 | (re-search-forward (concat "^\\(?:" outline-regexp "\\)") | 567 | (re-search-forward (concat "^\\(?:" outline-regexp "\\)") |
| 486 | nil 'move) | 568 | nil 'move) |
| 487 | (save-excursion | 569 | (outline-invisible-p (match-beginning 0)))) |
| 488 | (goto-char (match-beginning 0)) | ||
| 489 | (outline-invisible-p)))) | ||
| 490 | (setq arg (1- arg))) | 570 | (setq arg (1- arg))) |
| 491 | (beginning-of-line)) | 571 | (beginning-of-line)) |
| 492 | 572 | ||
| @@ -534,7 +614,7 @@ If FLAG is nil then text is shown, while if FLAG is t the text is hidden." | |||
| 534 | ;; reveal do the rest, by simply doing: | 614 | ;; reveal do the rest, by simply doing: |
| 535 | ;; (remove-overlays (overlay-start o) (overlay-end o) | 615 | ;; (remove-overlays (overlay-start o) (overlay-end o) |
| 536 | ;; 'invisible 'outline) | 616 | ;; 'invisible 'outline) |
| 537 | ;; | 617 | ;; |
| 538 | ;; That works fine as long as everything is in sync, but if the | 618 | ;; That works fine as long as everything is in sync, but if the |
| 539 | ;; structure of the document is changed while revealing parts of it, | 619 | ;; structure of the document is changed while revealing parts of it, |
| 540 | ;; the resulting behavior can be ugly. I.e. we need to make | 620 | ;; the resulting behavior can be ugly. I.e. we need to make |
| @@ -681,9 +761,7 @@ Show the heading too, if it is currently invisible." | |||
| 681 | "Show or hide the current subtree depending on its current state." | 761 | "Show or hide the current subtree depending on its current state." |
| 682 | (interactive) | 762 | (interactive) |
| 683 | (outline-back-to-heading) | 763 | (outline-back-to-heading) |
| 684 | (if (save-excursion | 764 | (if (not (outline-invisible-p (line-end-position))) |
| 685 | (end-of-line) | ||
| 686 | (not (outline-invisible-p))) | ||
| 687 | (hide-subtree) | 765 | (hide-subtree) |
| 688 | (show-children) | 766 | (show-children) |
| 689 | (show-entry))) | 767 | (show-entry))) |
| @@ -754,7 +832,7 @@ Default is enough to cause the following heading to appear." | |||
| 754 | (point)) | 832 | (point)) |
| 755 | (progn (outline-end-of-heading) (point)) | 833 | (progn (outline-end-of-heading) (point)) |
| 756 | nil))))))) | 834 | nil))))))) |
| 757 | (run-hooks 'outline-view-change-hook)) | 835 | (run-hooks 'outline-view-change-hook)) |
| 758 | 836 | ||
| 759 | 837 | ||
| 760 | 838 | ||
| @@ -801,7 +879,7 @@ Stop at the first and last subheadings of a superior heading." | |||
| 801 | (while (and (> (funcall outline-level) level) | 879 | (while (and (> (funcall outline-level) level) |
| 802 | (not (eobp))) | 880 | (not (eobp))) |
| 803 | (outline-next-visible-heading 1)) | 881 | (outline-next-visible-heading 1)) |
| 804 | (if (< (funcall outline-level) level) | 882 | (if (or (eobp) (< (funcall outline-level) level)) |
| 805 | nil | 883 | nil |
| 806 | (point)))) | 884 | (point)))) |
| 807 | 885 | ||