Mercurial > emacs
changeset 72873:b42e98d06749
* allout.el (allout-regexp, allout-line-boundary-regexp)
(allout-bob-regexp): Correct grouping and boundaries to fix
backwards traversal.
(allout-depth-specific-regexp, allout-depth-one-regexp): New
versions that exploit \\{M\\} regexp syntax, to avoid geometric or
worse time in allout-ascend.
(allout-doublecheck-at-and-shallower): Identify depth threshold
below which topics are checked for and disqualified by containment
discontinuities.
(allout-hotspot-key-handler): Correctly handle multiple-key
strokes. Remove some unused variables.
(allout-mode-leaders): Clarify that mode-specific comment-start
will be used
(set-allout-regexp): Correctly regexp-quote allout regexps to
properly accept alternative header-leads and primary bullets with
regexp-specific characters (eg, C "/*", mathematica "(*").
Include new regular expressions among those configured.
(allout-infer-header-lead-and-primary-bullet): Rename
allout-infer-header-lead.
(allout-recent-depth): Manifest as a variable as well as a function.
(allout-prefix-data): Simplify into an inline instead of a macro,
assuming current match data rather than being explicitly passed it.
Establish allout-recent-depth value as well as
allout-recent-prefix-beginning and allout-recent-prefix-end.
(allout-aberrant-container-p): True when an item's immediate
offspring discontinuously contained. Useful for disqualifying
unintended topic prefixes, likely at low depths.
(allout-goto-prefix-doublechecked): Elaborated version of
allout-goto-prefix which disqualifies aberrant pseudo-items.
(allout-end-of-prefix, allout-pre-next-prefix)
(allout-end-of-subtree): Disqualify aberrant containers.
(allout-beginning-of-current-entry): Position at start of buffer
when in container (depth 0) entry.
(nullify-allout-prefix-data): Invalidate allout-recent-* prefix data.
(allout-current-bullet): Strip text properties.
(allout-get-prefix-bullet): Use right match groups.
(allout-beginning-of-line, allout-next-heading): Disqualify
aberrant containers.
(allout-previous-heading): Disqualify aberrant containers.
(allout-get-invisibility-overlay): Increment so progress is made
when the first overlay is not the sought one.
(allout-end-of-prefix): Disqualify aberrant containers.
(allout-end-of-line): Cycle something like allout-beginning-of-line.
(allout-mode): Make allout-old-style-prefixes (ie, enabling use with
outline.el outlines) functional again. Change the primary bullet
along with the header-lead - level 1 new-style bullets now work.
Engage allout-before-change-handler in mainline emacs, not just
xemacs, to do undo handling.
(allout-before-change-handler): Expose undo changes occurring in
hidden regions. Use allout-get-invisibility-overlay instead of
reimplementing it inline.
(allout-chart-subtree): Use start rather than end of prefix in
charts. Use allout-recent-depth variable.
(allout-chart-siblings): Disqualify aberrant topics.
(allout-beginning-of-current-entry): Position correctly.
(allout-ascend): Use new allout-depth-specific-regexp and
allout-depth-one-regexp for linear instead of O(N^2) or worse behavior.
(allout-ascend-to-depth, allout-up-current-level): Depend on
allout-ascend, rather than reimplementing an algorithm.
(allout-descend-to-depth): Use allout-recent-depth var instead of fun.
(allout-next-sibling): On traversal of numerous intervening
topics, resort to economical allout-next-sibling-leap.
(allout-next-sibling-leap): Specialized version of
allout-next-sibling that uses allout-ascend cleverly, to depend on
a regexp search to leap large numbers of contained topics, rather
than arbitrarily many one-by-one traversals.
(allout-next-visible-heading): Disqualify aberrant topics.
(allout-previous-visible-heading): Position consistently when interactive.
(allout-forward-current-level): Base on allout-previous-sibling
rather than reimplmenting the algorithm. Remove unused vars.
(allout-solicit-alternate-bullet): Present default choice stripped
of text properties.
(allout-rebullet-heading): Use bullet stripped of text properties.
Register changes using allout-exposure-change-hook. Disregard
aberrant topics.
(allout-shift-in): With universal-argument, make topic a peer of
it's former offspring. Simplify the code by separating out
allout-shift-out functionality.
(allout-shift-out): With universal-argument, make offspring peers
of their former container, and its siblings. Implement the
functionality here, rather than inappropriately muddling the
implementation of allout-shift-in.
(allout-rebullet-topic): Respect additional argument for new
parent-child separation function.
(allout-yank-processing): Use allout-ascend directly.
(allout-show-entry): Disqualify aberrant topics.
(allout-show-children): Handle discontinuous children gracefully,
extending the depth being revealed to expose them and posting a
message indicating the situation.
(allout-show-to-offshoot): Remove obsolete and incorrect comment.
Leave cursor in correct position.
(allout-hide-current-subtree): Use allout-ascend directly.
Disqualify aberrant topics.
(allout-kill-line, allout-kill-topic): Preserve exposure layout in
a way that the yanks can restore it, as used to happen.
(allout-yank-processing): Restore exposure layout as recorded by
allout-kill-*, as used to happen.
(allout-annotate-hidden, allout-hide-by-annotation): New routines
for preseving and restoring exposure layout across kills.
(allout-toggle-subtree-encryption): Run allout-exposure-change-hook.
(allout-encrypt-string): Strip text properties.
Rearranged order and outline-headings for some of the
miscellaneous functions.
(allout-resolve-xref): No need to quote the error name in the
condition-case handler section.
(allout-flatten): Classic recursive (and recursively intensive,
without tail-recursion) list-flattener, needed by allout-shift-out
when confronted with discontinuous children.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Thu, 14 Sep 2006 17:52:07 +0000 |
parents | 193325efd854 |
children | 6b510f400416 |
files | lisp/ChangeLog lisp/allout.el |
diffstat | 2 files changed, 951 insertions(+), 445 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Thu Sep 14 17:49:52 2006 +0000 +++ b/lisp/ChangeLog Thu Sep 14 17:52:07 2006 +0000 @@ -1,3 +1,114 @@ +2006-09-005 Ken Manheimer <address@hidden> + + * allout.el (allout-regexp, allout-line-boundary-regexp) + (allout-bob-regexp): Correct grouping and boundaries to fix + backwards traversal. + (allout-depth-specific-regexp, allout-depth-one-regexp): New + versions that exploit \\{M\\} regexp syntax, to avoid geometric or + worse time in allout-ascend. + (allout-doublecheck-at-and-shallower): Identify depth threshold + below which topics are checked for and disqualified by containment + discontinuities. + (allout-hotspot-key-handler): Correctly handle multiple-key + strokes. Remove some unused variables. + (allout-mode-leaders): Clarify that mode-specific comment-start + will be used + (set-allout-regexp): Correctly regexp-quote allout regexps to + properly accept alternative header-leads and primary bullets with + regexp-specific characters (eg, C "/*", mathematica "(*"). + Include new regular expressions among those configured. + (allout-infer-header-lead-and-primary-bullet): Rename + allout-infer-header-lead. + (allout-recent-depth): Manifest as a variable as well as a function. + (allout-prefix-data): Simplify into an inline instead of a macro, + assuming current match data rather than being explicitly passed it. + Establish allout-recent-depth value as well as + allout-recent-prefix-beginning and allout-recent-prefix-end. + (allout-aberrant-container-p): True when an item's immediate + offspring discontinuously contained. Useful for disqualifying + unintended topic prefixes, likely at low depths. + (allout-goto-prefix-doublechecked): Elaborated version of + allout-goto-prefix which disqualifies aberrant pseudo-items. + (allout-end-of-prefix, allout-pre-next-prefix) + (allout-end-of-subtree): Disqualify aberrant containers. + (allout-beginning-of-current-entry): Position at start of buffer + when in container (depth 0) entry. + (nullify-allout-prefix-data): Invalidate allout-recent-* prefix data. + (allout-current-bullet): Strip text properties. + (allout-get-prefix-bullet): Use right match groups. + (allout-beginning-of-line, allout-next-heading): Disqualify + aberrant containers. + (allout-previous-heading): Disqualify aberrant containers. + (allout-get-invisibility-overlay): Increment so progress is made + when the first overlay is not the sought one. + (allout-end-of-prefix): Disqualify aberrant containers. + (allout-end-of-line): Cycle something like allout-beginning-of-line. + (allout-mode): Make allout-old-style-prefixes (ie, enabling use with + outline.el outlines) functional again. Change the primary bullet + along with the header-lead - level 1 new-style bullets now work. + Engage allout-before-change-handler in mainline emacs, not just + xemacs, to do undo handling. + (allout-before-change-handler): Expose undo changes occurring in + hidden regions. Use allout-get-invisibility-overlay instead of + reimplementing it inline. + (allout-chart-subtree): Use start rather than end of prefix in + charts. Use allout-recent-depth variable. + (allout-chart-siblings): Disqualify aberrant topics. + (allout-beginning-of-current-entry): Position correctly. + (allout-ascend): Use new allout-depth-specific-regexp and + allout-depth-one-regexp for linear instead of O(N^2) or worse behavior. + (allout-ascend-to-depth, allout-up-current-level): Depend on + allout-ascend, rather than reimplementing an algorithm. + (allout-descend-to-depth): Use allout-recent-depth var instead of fun. + (allout-next-sibling): On traversal of numerous intervening + topics, resort to economical allout-next-sibling-leap. + (allout-next-sibling-leap): Specialized version of + allout-next-sibling that uses allout-ascend cleverly, to depend on + a regexp search to leap large numbers of contained topics, rather + than arbitrarily many one-by-one traversals. + (allout-next-visible-heading): Disqualify aberrant topics. + (allout-previous-visible-heading): Position consistently when interactive. + (allout-forward-current-level): Base on allout-previous-sibling + rather than reimplmenting the algorithm. Remove unused vars. + (allout-solicit-alternate-bullet): Present default choice stripped + of text properties. + (allout-rebullet-heading): Use bullet stripped of text properties. + Register changes using allout-exposure-change-hook. Disregard + aberrant topics. + (allout-shift-in): With universal-argument, make topic a peer of + it's former offspring. Simplify the code by separating out + allout-shift-out functionality. + (allout-shift-out): With universal-argument, make offspring peers + of their former container, and its siblings. Implement the + functionality here, rather than inappropriately muddling the + implementation of allout-shift-in. + (allout-rebullet-topic): Respect additional argument for new + parent-child separation function. + (allout-yank-processing): Use allout-ascend directly. + (allout-show-entry): Disqualify aberrant topics. + (allout-show-children): Handle discontinuous children gracefully, + extending the depth being revealed to expose them and posting a + message indicating the situation. + (allout-show-to-offshoot): Remove obsolete and incorrect comment. + Leave cursor in correct position. + (allout-hide-current-subtree): Use allout-ascend directly. + Disqualify aberrant topics. + (allout-kill-line, allout-kill-topic): Preserve exposure layout in + a way that the yanks can restore it, as used to happen. + (allout-yank-processing): Restore exposure layout as recorded by + allout-kill-*, as used to happen. + (allout-annotate-hidden, allout-hide-by-annotation): New routines + for preseving and restoring exposure layout across kills. + (allout-toggle-subtree-encryption): Run allout-exposure-change-hook. + (allout-encrypt-string): Strip text properties. + Rearranged order and outline-headings for some of the + miscellaneous functions. + (allout-resolve-xref): No need to quote the error name in the + condition-case handler section. + (allout-flatten): Classic recursive (and recursively intensive, + without tail-recursion) list-flattener, needed by allout-shift-out + when confronted with discontinuous children. + 2006-09-14 Chong Yidong <cyd@stupidchicken.com> * startup.el (fancy-splash-text): Move editing instructions to
--- a/lisp/allout.el Thu Sep 14 17:49:52 2006 +0000 +++ b/lisp/allout.el Thu Sep 14 17:52:07 2006 +0000 @@ -847,18 +847,37 @@ (defvar allout-bullets-string-len 0 "Length of current buffers' `allout-plain-bullets-string'.") (make-variable-buffer-local 'allout-bullets-string-len) +;;;_ = allout-depth-specific-regexp +(defvar allout-depth-specific-regexp "" + "*Regular expression to match a heading line prefix for a particular depth. + +This expression is used to search for depth-specific topic +headers at depth 2 and greater. Use `allout-depth-one-regexp' +for to seek topics at depth one. + +This var is set according to the user configuration vars by +`set-allout-regexp'. It is prepared with format strings for two +decimal numbers, which should each be one less than the depth of the +topic prefix to be matched.") +(make-variable-buffer-local 'allout-depth-specific-regexp) +;;;_ = allout-depth-one-regexp +(defvar allout-depth-one-regexp "" + "*Regular expression to match a heading line prefix for depth one. + +This var is set according to the user configuration vars by +`set-allout-regexp'. It is prepared with format strings for two +decimal numbers, which should each be one less than the depth of the +topic prefix to be matched.") +(make-variable-buffer-local 'allout-depth-one-regexp) ;;;_ = allout-line-boundary-regexp (defvar allout-line-boundary-regexp () "`allout-regexp' with outline style beginning-of-line anchor. -This is properly set when `allout-regexp' is produced by -`set-allout-regexp', so that (match-beginning 2) and (match-end -2) delimit the prefix.") +This is properly set by `set-allout-regexp'.") (make-variable-buffer-local 'allout-line-boundary-regexp) ;;;_ = allout-bob-regexp (defvar allout-bob-regexp () - "Like `allout-line-boundary-regexp', for headers at beginning of buffer. -\(match-beginning 2) and \(match-end 2) delimit the prefix.") + "Like `allout-line-boundary-regexp', for headers at beginning of buffer.") (make-variable-buffer-local 'allout-bob-regexp) ;;;_ = allout-header-subtraction (defvar allout-header-subtraction (1- (length allout-header-prefix)) @@ -869,7 +888,14 @@ "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.") (make-variable-buffer-local 'allout-plain-bullets-string-len) - +;;;_ = allout-doublecheck-at-and-shallower +(defconst allout-doublecheck-at-and-shallower 3 + "Verify apparent topics of this depth and shallower as being non-aberrant. + +Verified with `allout-aberrant-container-p'. This check's usefulness is +limited to shallow prospects, because the determination of aberrance +depends on the mistaken item being followed by a legitimate item of +excessively greater depth.") ;;;_ X allout-reset-header-lead (header-lead) (defun allout-reset-header-lead (header-lead) "*Reset the leading string used to identify topic headers." @@ -961,7 +987,9 @@ "Generate proper topic-header regexp form for outline functions. Works with respect to `allout-plain-bullets-string' and -`allout-distinctive-bullets-string'." +`allout-distinctive-bullets-string'. + +Also refresh various data structures that hinge on the regexp." (interactive) ;; Derive allout-bullets-string from user configured components: @@ -996,19 +1024,84 @@ ;; Derive next for repeated use in allout-pending-bullet: (setq allout-plain-bullets-string-len (length allout-plain-bullets-string)) (setq allout-header-subtraction (1- (length allout-header-prefix))) - ;; Produce the new allout-regexp: - (setq allout-regexp (concat "\\(" - (regexp-quote allout-header-prefix) - "[ \t]*[" - allout-bullets-string - "]\\)\\|" - (regexp-quote allout-primary-bullet) - "+\\|\^l")) - (setq allout-line-boundary-regexp - (concat "\\(\n\\)\\(" allout-regexp "\\)")) - (setq allout-bob-regexp - (concat "\\(\\`\\)\\(" allout-regexp "\\)")) - ) + + (let (new-part old-part) + (setq new-part (concat "\\(" + (regexp-quote allout-header-prefix) + "[ \t]*" + ;; already regexp-quoted in a custom way: + "[" allout-bullets-string "]" + "\\)") + old-part (concat "\\(" + (regexp-quote allout-primary-bullet) + "\\|" + (regexp-quote allout-header-prefix) + "\\)" + "+" + " ?[^" allout-primary-bullet "]") + allout-regexp (concat new-part + "\\|" + old-part + "\\|\^l") + + allout-line-boundary-regexp (concat "\n" new-part + "\\|" + "\n" old-part) + + allout-bob-regexp (concat "\\`" new-part + "\\|" + "\\`" old-part)) + + (setq allout-depth-specific-regexp + (concat "\\(^\\|\\`\\)" + "\\(" + + ;; new-style spacers-then-bullet string: + "\\(" + (allout-format-quote (regexp-quote allout-header-prefix)) + " \\{%s\\}" + "[" (allout-format-quote allout-bullets-string) "]" + "\\)" + + ;; old-style all-bullets string, if primary not multi-char: + (if (< 0 allout-header-subtraction) + "" + (concat "\\|\\(" + (allout-format-quote + (regexp-quote allout-primary-bullet)) + (allout-format-quote + (regexp-quote allout-primary-bullet)) + (allout-format-quote + (regexp-quote allout-primary-bullet)) + "\\{%s\\}" + ;; disqualify greater depths: + "[^" + (allout-format-quote allout-primary-bullet) + "]\\)" + )) + "\\)" + )) + (setq allout-depth-one-regexp + (concat "\\(^\\|\\`\\)" + "\\(" + + "\\(" + (regexp-quote allout-header-prefix) + ;; disqualify any bullet char following any amount of + ;; intervening whitespace: + " *" + (concat "[^ " allout-bullets-string "]") + "\\)" + (if (< 0 allout-header-subtraction) + ;; Need not support anything like the old + ;; bullet style if the prefix is multi-char. + "" + (concat "\\|" + (regexp-quote allout-primary-bullet) + ;; disqualify deeper primary-bullet sequences: + "[^" allout-primary-bullet "]")) + "\\)" + )))) ;;;_ : Key bindings ;;;_ = allout-mode-map (defvar allout-mode-map nil "Keybindings for (allout) outline minor mode.") @@ -1142,7 +1235,7 @@ (if (not (symbolp name)) (error "Pair's name, %S, must be a symbol, not %s" name (type-of name))) - (setq prior-value (condition-case err + (setq prior-value (condition-case nil (symbol-value name) (void-variable nil))) (when (not (assoc name allout-mode-prior-settings)) @@ -1792,8 +1885,7 @@ (remove-from-invisibility-spec '(allout . t)) (remove-hook 'pre-command-hook 'allout-pre-command-business t) (remove-hook 'post-command-hook 'allout-post-command-business t) - (when (featurep 'xemacs) - (remove-hook 'before-change-functions 'allout-before-change-handler t)) + (remove-hook 'before-change-functions 'allout-before-change-handler t) (remove-hook 'isearch-mode-end-hook 'allout-isearch-end-handler t) (remove-hook write-file-hook-var-name 'allout-write-file-hook-handler t) (remove-hook 'auto-save-hook 'allout-auto-save-hook-handler t) @@ -1813,7 +1905,7 @@ (allout-overlay-preparations) ; Doesn't hurt to redo this. - (allout-infer-header-lead) + (allout-infer-header-lead-and-primary-bullet) (allout-infer-body-reindent) (set-allout-regexp) @@ -1854,9 +1946,8 @@ (allout-add-resumptions '(line-move-ignore-invisible t)) (add-hook 'pre-command-hook 'allout-pre-command-business nil t) (add-hook 'post-command-hook 'allout-post-command-business nil t) - (when (featurep 'xemacs) - (add-hook 'before-change-functions 'allout-before-change-handler - nil t)) + (add-hook 'before-change-functions 'allout-before-change-handler + nil t) (add-hook 'isearch-mode-end-hook 'allout-isearch-end-handler nil t) (add-hook write-file-hook-var-name 'allout-write-file-hook-handler nil t) @@ -2000,14 +2091,19 @@ This before-change handler is used only where modification-hooks overlay property is not supported." + + (if (and (allout-mode-p) undo-in-progress (allout-hidden-p)) + (allout-show-to-offshoot)) + ;; allout-overlay-interior-modification-handler on an overlay handles ;; this in other emacs, via `allout-exposure-category's 'modification-hooks. (when (and (featurep 'xemacs) (allout-mode-p)) ;; process all of the pending overlays: - (dolist (overlay (overlays-in beg end)) - (if (eq (overlay-get ol 'invisible) 'allout) - (allout-overlay-interior-modification-handler - overlay nil beg end nil))))) + (save-excursion + (got-char beg) + (let ((overlay (allout-get-invisibility-overlay))) + (allout-overlay-interior-modification-handler + overlay nil beg end nil))))) ;;;_ > allout-isearch-end-handler (&optional overlay) (defun allout-isearch-end-handler (&optional overlay) "Reconcile allout outline exposure on arriving in hidden text after isearch. @@ -2035,19 +2131,35 @@ (defvar allout-recent-prefix-end 0 "Buffer point of the end of the last topic prefix encountered.") (make-variable-buffer-local 'allout-recent-prefix-end) +;;;_ = allout-recent-depth +(defvar allout-recent-depth 0 + "Depth of the last topic prefix encountered.") +(make-variable-buffer-local 'allout-recent-depth) ;;;_ = allout-recent-end-of-subtree (defvar allout-recent-end-of-subtree 0 "Buffer point last returned by `allout-end-of-current-subtree'.") (make-variable-buffer-local 'allout-recent-end-of-subtree) -;;;_ > allout-prefix-data (beg end) -(defmacro allout-prefix-data (beg end) - "Register allout-prefix state data - BEGINNING and END of prefix. +;;;_ > allout-prefix-data () +(defsubst allout-prefix-data () + "Register allout-prefix state data. For reference by `allout-recent' funcs. Returns BEGINNING." - `(setq allout-recent-prefix-end ,end - allout-recent-prefix-beginning ,beg)) + (setq allout-recent-prefix-end (or (match-end 1) (match-end 2)) + allout-recent-prefix-beginning (or (match-beginning 1) + (match-beginning 2)) + allout-recent-depth (max 1 (- allout-recent-prefix-end + allout-recent-prefix-beginning + allout-header-subtraction))) + allout-recent-prefix-beginning) +;;;_ > nullify-allout-prefix-data () +(defsubst nullify-allout-prefix-data () + "Mark allout prefix data as being uninformative." + (setq allout-recent-prefix-end (point) + allout-recent-prefix-beginning (point) + allout-recent-depth 0) + allout-recent-prefix-beginning) ;;;_ > allout-recent-depth () -(defmacro allout-recent-depth () +(defsubst allout-recent-depth () "Return depth of last heading encountered by an outline maneuvering function. All outline functions which directly do string matches to assess @@ -2055,19 +2167,17 @@ `allout-recent-prefix-end' if successful. This function uses those settings to return the current depth." - '(max 1 (- allout-recent-prefix-end - allout-recent-prefix-beginning - allout-header-subtraction))) + allout-recent-depth) ;;;_ > allout-recent-prefix () -(defmacro allout-recent-prefix () +(defsubst allout-recent-prefix () "Like `allout-recent-depth', but returns text of last encountered prefix. All outline functions which directly do string matches to assess headings set the variables `allout-recent-prefix-beginning' and `allout-recent-prefix-end' if successful. This function uses those settings -to return the current depth." - '(buffer-substring allout-recent-prefix-beginning - allout-recent-prefix-end)) +to return the current prefix." + (buffer-substring-no-properties allout-recent-prefix-beginning + allout-recent-prefix-end)) ;;;_ > allout-recent-bullet () (defmacro allout-recent-bullet () "Like allout-recent-prefix, but returns bullet of last encountered prefix. @@ -2076,8 +2186,8 @@ headings set the variables `allout-recent-prefix-beginning' and `allout-recent-prefix-end' if successful. This function uses those settings to return the current depth of the most recently matched topic." - '(buffer-substring (1- allout-recent-prefix-end) - allout-recent-prefix-end)) + '(buffer-substring-no-properties (1- allout-recent-prefix-end) + allout-recent-prefix-end)) ;;;_ #4 Navigation @@ -2091,7 +2201,8 @@ (save-excursion (allout-beginning-of-current-line) (and (looking-at allout-regexp) - (allout-prefix-data (match-beginning 0) (match-end 0))))) + (not (allout-aberrant-container-p)) + (allout-prefix-data)))) ;;;_ > allout-on-heading-p () (defalias 'allout-on-heading-p 'allout-on-current-heading-p) ;;;_ > allout-e-o-prefix-p () @@ -2101,6 +2212,51 @@ (beginning-of-line)) (looking-at allout-regexp)) (= (point)(save-excursion (allout-end-of-prefix)(point))))) +;;;_ > allout-aberrant-container-p () +(defun allout-aberrant-container-p () + "True if topic, or next sibling with children, contains them discontinuously. + +Discontinuous means an immediate offspring that is nested more +than one level deeper than the topic. + +If topic has no offspring, then the next sibling with offspring will +determine whether or not this one is determined to be aberrant. + +If true, then the allout-recent-* settings are calibrated on the +offspring that qaulifies it as aberrant, ie with depth that +exceeds the topic by more than one." + + ;; This is most clearly understood when considering standard-prefix-leader + ;; low-level topics, which can all too easily match text not intended as + ;; headers. For example, any line with a leading '.' or '*' and lacking a + ;; following bullet qualifies without this protection. (A sequence of + ;; them can occur naturally, eg a typical textual bullet list.) We + ;; disqualify such low-level sequences when they are followed by a + ;; discontinuously contained child, inferring that the sequences are not + ;; actually connected with their prospective context. + + (let ((depth (allout-depth)) + (start-point (point)) + done aberrant) + (save-excursion + (while (and (not done) + (re-search-forward allout-line-boundary-regexp nil 0)) + (allout-prefix-data) + (goto-char allout-recent-prefix-beginning) + (cond + ;; sibling - continue: + ((eq allout-recent-depth depth)) + ;; first offspring is excessive - aberrant: + ((> allout-recent-depth (1+ depth)) + (setq done t aberrant t)) + ;; next non-sibling is lower-depth - not aberrant: + (t (setq done t))))) + (if aberrant + aberrant + (goto-char start-point) + ;; recalibrate allout-recent-* + (allout-depth) + nil))) ;;;_ : Location attributes ;;;_ > allout-depth () (defun allout-depth () @@ -2113,10 +2269,10 @@ (let ((start-point (point))) (if (and (allout-goto-prefix) (not (< start-point (point)))) - (allout-recent-depth) + allout-recent-depth (progn - ;; Oops, no prefix, zero prefix data: - (allout-prefix-data (point)(point)) + ;; Oops, no prefix, nullify it: + (nullify-allout-prefix-data) ;; ... and return 0: 0))))) ;;;_ > allout-current-depth () @@ -2149,10 +2305,10 @@ (condition-case nil (save-excursion (allout-back-to-current-heading) - (buffer-substring (- allout-recent-prefix-end 1) - allout-recent-prefix-end)) + (buffer-substring-no-properties (- allout-recent-prefix-end 1) + allout-recent-prefix-end)) ;; Quick and dirty provision, ostensibly for missing bullet: - ('args-out-of-range nil)) + (args-out-of-range nil)) ) ;;;_ > allout-get-prefix-bullet (prefix) (defun allout-get-prefix-bullet (prefix) @@ -2160,7 +2316,7 @@ ;; Doesn't make sense if we're old-style prefixes, but this just ;; oughtn't be called then, so forget about it... (if (string-match allout-regexp prefix) - (substring prefix (1- (match-end 0)) (match-end 0)))) + (substring prefix (1- (match-end 2)) (match-end 2)))) ;;;_ > allout-sibling-index (&optional depth) (defun allout-sibling-index (&optional depth) "Item number of this prospective topic among its siblings. @@ -2174,10 +2330,10 @@ (cond ((and depth (<= depth 0) 0)) ((or (not depth) (= depth (allout-depth))) (let ((index 1)) - (while (allout-previous-sibling (allout-recent-depth) nil) + (while (allout-previous-sibling allout-recent-depth nil) (setq index (1+ index))) index)) - ((< depth (allout-recent-depth)) + ((< depth allout-recent-depth) (allout-ascend-to-depth depth) (allout-sibling-index)) (0)))) @@ -2229,11 +2385,17 @@ (if (or (not allout-beginning-of-line-cycles) (not (equal last-command this-command))) (move-beginning-of-line 1) - (let ((beginning-of-body (save-excursion - (allout-beginning-of-current-entry) - (point)))) + (allout-depth) + (let ((beginning-of-body + (save-excursion + (while (and (<= allout-recent-depth + allout-doublecheck-at-and-shallower) + (allout-aberrant-container-p) + (allout-previous-visible-heading 1))) + (allout-beginning-of-current-entry) + (point)))) (cond ((= (current-column) 0) - (allout-beginning-of-current-entry)) + (goto-char beginning-of-body)) ((< (point) beginning-of-body) (allout-beginning-of-current-line)) ((= (point) beginning-of-body) @@ -2241,7 +2403,7 @@ (t (allout-beginning-of-current-line) (if (< (point) beginning-of-body) ;; we were on the headline after its start: - (allout-beginning-of-current-entry))))))) + (goto-char beginning-of-body))))))) ;;;_ > allout-end-of-line () (defun allout-end-of-line () "End-of-line with `allout-end-of-line-cycles' behavior, if set." @@ -2261,6 +2423,7 @@ (allout-hidden-p))) (allout-back-to-current-heading) (allout-show-current-entry) + (allout-show-children) (allout-end-of-entry)) ((>= (point) end-of-entry) (allout-back-to-current-heading) @@ -2270,40 +2433,47 @@ (defsubst allout-next-heading () "Move to the heading for the topic \(possibly invisible) after this one. -Returns the location of the heading, or nil if none found." - - (if (and (bobp) (not (eobp)) (looking-at allout-regexp)) +Returns the location of the heading, or nil if none found. + +We skip anomolous low-level topics, a la `allout-aberrant-container-p'." + (if (looking-at allout-regexp) (forward-char 1)) - (if (re-search-forward allout-line-boundary-regexp nil 0) - (allout-prefix-data ; Got valid location state - set vars: - (goto-char (or (match-beginning 2) - allout-recent-prefix-beginning)) - (or (match-end 2) allout-recent-prefix-end)))) + (when (re-search-forward allout-line-boundary-regexp nil 0) + (allout-prefix-data) + (and (<= allout-recent-depth allout-doublecheck-at-and-shallower) + ;; register non-aberrant or disqualifying offspring as allout-recent-* + (allout-aberrant-container-p)) + (goto-char allout-recent-prefix-beginning))) ;;;_ > allout-this-or-next-heading (defun allout-this-or-next-heading () "Position cursor on current or next heading." ;; A throwaway non-macro that is defined after allout-next-heading ;; and usable by allout-mode. - (if (not (allout-goto-prefix)) (allout-next-heading))) + (if (not (allout-goto-prefix-doublechecked)) (allout-next-heading))) ;;;_ > allout-previous-heading () -(defmacro allout-previous-heading () +(defsubst allout-previous-heading () "Move to the prior \(possibly invisible) heading line. -Return the location of the beginning of the heading, or nil if not found." - - '(if (bobp) - nil - (allout-goto-prefix) - (if - ;; searches are unbounded and return nil if failed: - (or (re-search-backward allout-line-boundary-regexp nil 0) - (looking-at allout-bob-regexp)) - (progn ; Got valid location state - set vars: - (allout-prefix-data - (goto-char (or (match-beginning 2) - allout-recent-prefix-beginning)) - (or (match-end 2) allout-recent-prefix-end)))))) +Return the location of the beginning of the heading, or nil if not found. + +We skip anomolous low-level topics, a la `allout-aberrant-container-p'." + + (if (bobp) + nil + ;; allout-goto-prefix-doublechecked calls us, so we can't use it here. + (let ((start-point (point))) + (allout-goto-prefix) + (when (or (re-search-backward allout-line-boundary-regexp nil 0) + (looking-at allout-bob-regexp)) + (goto-char (allout-prefix-data)) + (if (and (<= allout-recent-depth allout-doublecheck-at-and-shallower) + (allout-aberrant-container-p)) + (or (allout-previous-heading) + (goto-char start-point) + ;; recalibrate allout-recent-*: + (allout-depth))) + (point))))) ;;;_ > allout-get-invisibility-overlay () (defun allout-get-invisibility-overlay () "Return the overlay at point that dictates allout invisibility." @@ -2311,7 +2481,8 @@ got) (while (and overlays (not got)) (if (equal (overlay-get (car overlays) 'invisible) 'allout) - (setq got (car overlays)))) + (setq got (car overlays)) + (pop overlays))) got)) ;;;_ > allout-back-to-visible-text () (defun allout-back-to-visible-text () @@ -2324,11 +2495,8 @@ ;;;_ " These routines either produce or assess charts, which are ;;; nested lists of the locations of topics within a subtree. ;;; -;;; Use of charts enables efficient navigation of subtrees, by -;;; requiring only a single regexp-search based traversal, to scope -;;; out the subtopic locations. The chart then serves as the basis -;;; for assessment or adjustment of the subtree, without redundant -;;; traversal of the structure. +;;; Charts enable efficient subtree navigation by providing a reusable basis +;;; for elaborate, compound assessment and adjustment of a subtree. ;;;_ > allout-chart-subtree (&optional levels visible orig-depth prev-depth) (defun allout-chart-subtree (&optional levels visible orig-depth prev-depth) @@ -2348,12 +2516,12 @@ routines need assess the structure only once, and then use the chart for their elaborate manipulations. -Topics are entered in the chart so the last one is at the car. -The entry for each topic consists of an integer indicating the point -at the beginning of the topic. Charts for offspring consists of a -list containing, recursively, the charts for the respective subtopics. -The chart for a topics' offspring precedes the entry for the topic -itself. +The chart entries for the topics are in reverse order, so the +last topic is listed first. The entry for each topic consists of +an integer indicating the point at the beginning of the topic +prefix. Charts for offspring consists of a list containing, +recursively, the charts for the respective subtopics. The chart +for a topics' offspring precedes the entry for the topic itself. The other function parameters are for internal recursion, and should not be specified by external callers. ORIG-DEPTH is depth of topic at @@ -2380,17 +2548,17 @@ (while (and (not (eobp)) ; Still within original topic? - (< orig-depth (setq curr-depth (allout-recent-depth))) + (< orig-depth (setq curr-depth allout-recent-depth)) (cond ((= prev-depth curr-depth) ;; Register this one and move on: - (setq chart (cons (point) chart)) + (setq chart (cons allout-recent-prefix-beginning chart)) (if (and levels (<= levels 1)) ;; At depth limit - skip sublevels: (or (allout-next-sibling curr-depth) ;; or no more siblings - proceed to ;; next heading at lesser depth: (while (and (<= curr-depth - (allout-recent-depth)) + allout-recent-depth) (if visible (allout-next-visible-heading 1) (allout-next-heading))))) @@ -2437,11 +2605,11 @@ Effectively a top-level chart of siblings. See `allout-chart-subtree' for an explanation of charts." (save-excursion - (if (allout-goto-prefix) - (let ((chart (list (point)))) - (while (allout-next-sibling) - (setq chart (cons (point) chart))) - (if chart (setq chart (nreverse chart))))))) + (when (allout-goto-prefix-doublechecked) + (let ((chart (list (point)))) + (while (allout-next-sibling) + (setq chart (cons (point) chart))) + (if chart (setq chart (nreverse chart))))))) ;;;_ > allout-chart-to-reveal (chart depth) (defun allout-chart-to-reveal (chart depth) @@ -2514,15 +2682,25 @@ (search-backward "\n" nil 1)) (forward-char 1) (if (looking-at allout-regexp) - (setq done (allout-prefix-data (match-beginning 0) - (match-end 0))) + (setq done (allout-prefix-data)) (forward-char -1))) (if (bobp) (cond ((looking-at allout-regexp) - (allout-prefix-data (match-beginning 0)(match-end 0))) + (allout-prefix-data)) ((allout-next-heading)) (done)) done))) +;;;_ > allout-goto-prefix-doublechecked () +(defun allout-goto-prefix-doublechecked () + "Put point at beginning of immediately containing outline topic. + +Like `allout-goto-prefix', but shallow topics \(according to `allout-doublecheck-at-and-shallower') are checked and disqualified for child containment discontinuity, according to `allout-aberrant-container-p'." + (allout-goto-prefix) + (if (and (<= allout-recent-depth allout-doublecheck-at-and-shallower) + (allout-aberrant-container-p)) + (allout-previous-heading) + (point))) + ;;;_ > allout-end-of-prefix () (defun allout-end-of-prefix (&optional ignore-decorations) "Position cursor at beginning of header text. @@ -2530,15 +2708,13 @@ If optional IGNORE-DECORATIONS is non-nil, put just after bullet, otherwise skip white space between bullet and ensuing text." - (if (not (allout-goto-prefix)) + (if (not (allout-goto-prefix-doublechecked)) nil - (let ((match-data (match-data))) - (goto-char (match-end 0)) - (if ignore-decorations - t - (while (looking-at "[0-9]") (forward-char 1)) - (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1))) - (store-match-data match-data)) + (goto-char allout-recent-prefix-end) + (if ignore-decorations + t + (while (looking-at "[0-9]") (forward-char 1)) + (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1))) ;; Reestablish where we are: (allout-current-depth))) ;;;_ > allout-current-bullet-pos () @@ -2547,7 +2723,7 @@ (if (not (allout-current-depth)) nil - (1- (match-end 0)))) + (1- allout-recent-prefix-end))) ;;;_ > allout-back-to-current-heading () (defun allout-back-to-current-heading () "Move to heading line of current topic, or beginning if already on the line. @@ -2562,11 +2738,9 @@ (progn (while (allout-hidden-p) (allout-beginning-of-current-line) (if (not (looking-at allout-regexp)) - (re-search-backward (concat - "^\\(" allout-regexp "\\)") + (re-search-backward allout-regexp nil 'move))) - (allout-prefix-data (match-beginning 1) - (match-end 1))))) + (allout-prefix-data)))) (if (interactive-p) (allout-end-of-prefix) (point)))) @@ -2579,8 +2753,7 @@ Returns that character position." (if (re-search-forward allout-line-boundary-regexp nil 'move) - (prog1 (goto-char (match-beginning 0)) - (allout-prefix-data (match-beginning 2)(match-end 2))))) + (goto-char (1- (allout-prefix-data))))) ;;;_ > allout-end-of-subtree (&optional current include-trailing-blank) (defun allout-end-of-subtree (&optional current include-trailing-blank) "Put point at the end of the last leaf in the containing topic. @@ -2596,11 +2769,11 @@ (interactive "P") (if current (allout-back-to-current-heading) - (allout-goto-prefix)) - (let ((level (allout-recent-depth))) + (allout-goto-prefix-doublechecked)) + (let ((level allout-recent-depth)) (allout-next-heading) (while (and (not (eobp)) - (> (allout-recent-depth) level)) + (> allout-recent-depth level)) (allout-next-heading)) (if (eobp) (allout-end-of-entry) @@ -2629,6 +2802,9 @@ (interactive) (let ((start-point (point))) (move-beginning-of-line 1) + (if (< 0 (allout-current-depth)) + (goto-char allout-recent-prefix-end) + (goto-char (point-min))) (allout-end-of-prefix) (if (and (interactive-p) (= (point) start-point)) @@ -2676,17 +2852,12 @@ (defun allout-ascend-to-depth (depth) "Ascend to depth DEPTH, returning depth if successful, nil if not." (if (and (> depth 0)(<= depth (allout-depth))) - (let ((last-good (point))) - (while (and (< depth (allout-depth)) - (setq last-good (point)) - (allout-beginning-of-level) - (allout-previous-heading))) - (if (= (allout-recent-depth) depth) - (progn (goto-char allout-recent-prefix-beginning) - depth) - (goto-char last-good) - nil)) - (if (interactive-p) (allout-end-of-prefix)))) + (let (last-ascended) + (while (and (< depth allout-recent-depth) + (setq last-ascended (allout-ascend)))) + (goto-char allout-recent-prefix-beginning) + (if (interactive-p) (allout-end-of-prefix)) + (and last-ascended allout-recent-depth)))) ;;;_ > allout-ascend () (defun allout-ascend () "Ascend one level, returning t if successful, nil if not." @@ -2703,49 +2874,24 @@ (start-depth (allout-depth))) (while (and (> (allout-depth) 0) - (not (= depth (allout-recent-depth))) ; ... not there yet + (not (= depth allout-recent-depth)) ; ... not there yet (allout-next-heading) ; ... go further - (< start-depth (allout-recent-depth)))) ; ... still in topic + (< start-depth allout-recent-depth))) ; ... still in topic (if (and (> (allout-depth) 0) - (= (allout-recent-depth) depth)) + (= allout-recent-depth depth)) depth (goto-char start-point) nil)) ) -;;;_ > allout-up-current-level (arg &optional dont-complain) -(defun allout-up-current-level (arg &optional dont-complain) - "Move out ARG levels from current visible topic. - -Positions on heading line of containing topic. Error if unable to -ascend that far, or nil if unable to ascend but optional arg -DONT-COMPLAIN is non-nil." +;;;_ > allout-up-current-level (arg) +(defun allout-up-current-level (arg) + "Move out ARG levels from current visible topic." (interactive "p") (allout-back-to-current-heading) - (let ((present-level (allout-recent-depth)) - (last-good (point)) - failed) - ;; Loop for iterating arg: - (while (and (> (allout-recent-depth) 1) - (> arg 0) - (not (bobp)) - (not failed)) - (setq last-good (point)) - ;; Loop for going back over current or greater depth: - (while (and (not (< (allout-recent-depth) present-level)) - (or (allout-previous-visible-heading 1) - (not (setq failed present-level))))) - (setq present-level (allout-current-depth)) - (setq arg (- arg 1))) - (if (or failed - (> arg 0)) - (progn (goto-char last-good) - (if (interactive-p) (allout-end-of-prefix)) - (if (not dont-complain) - (error "Can't ascend past outermost level") - (if (interactive-p) (allout-end-of-prefix)) - nil)) - (if (interactive-p) (allout-end-of-prefix)) - allout-recent-prefix-beginning))) + (if (not (allout-ascend)) + (error "Can't ascend past outermost level") + (if (interactive-p) (allout-end-of-prefix)) + allout-recent-prefix-beginning)) ;;;_ - Linear ;;;_ > allout-next-sibling (&optional depth backward) @@ -2756,24 +2902,101 @@ Go backward if optional arg BACKWARD is non-nil. -Return depth if successful, nil otherwise." - - (if (and backward (bobp)) +Return the start point of the new topic if successful, nil otherwise." + + (if (if backward (bobp) (eobp)) nil - (let ((start-depth (or depth (allout-depth))) + (let ((target-depth (or depth (allout-depth))) (start-point (point)) + (count 0) + leaping last-depth) - (while (and (not (if backward (bobp) (eobp))) - (if backward (allout-previous-heading) - (allout-next-heading)) - (> (setq last-depth (allout-recent-depth)) start-depth))) - (if (and (not (eobp)) - (and (> (or last-depth (allout-depth)) 0) - (= (allout-recent-depth) start-depth))) - allout-recent-prefix-beginning - (goto-char start-point) - (if depth (allout-depth) start-depth) - nil)))) + (while (and + ;; done too few single steps to resort to the leap routine: + (not leaping) + ;; not at limit: + (not (if backward (bobp) (eobp))) + ;; still traversable: + (if backward (allout-previous-heading) (allout-next-heading)) + ;; we're below the target depth + (> (setq last-depth allout-recent-depth) target-depth)) + (setq count (1+ count)) + (if (> count 7) ; lists are commonly 7 +- 2, right?-) + (setq leaping t))) + (cond (leaping + (or (allout-next-sibling-leap target-depth backward) + (progn + (goto-char start-point) + (if depth (allout-depth) target-depth) + nil))) + ((and (not (eobp)) + (and (> (or last-depth (allout-depth)) 0) + (= allout-recent-depth target-depth))) + allout-recent-prefix-beginning) + (t + (goto-char start-point) + (if depth (allout-depth) target-depth) + nil))))) +;;;_ > allout-next-sibling-leap (&optional depth backward) +(defun allout-next-sibling-leap (&optional depth backward) + "Like `allout-next-sibling', but by direct search for topic at depth. + +Traverse at optional DEPTH, or current depth if none specified. + +Go backward if optional arg BACKWARD is non-nil. + +Return the start point of the new topic if successful, nil otherwise. + +Costs more than regular `allout-next-sibling' for short traversals: + + - we have to check the prior \(next, if travelling backwards) + item to confirm connectivity with the prior topic, and + - if confirmed, we have to reestablish the allout-recent-* settings with + some extra navigation + - if confirmation fails, we have to do more work to recover + +It is an increasingly big win when there are many intervening +offspring before the next sibling, however, so +`allout-next-sibling' resorts to this if it finds itself in that +situation." + + (if (if backward (bobp) (eobp)) + nil + (let* ((start-point (point)) + (target-depth (or depth (allout-depth))) + (search-whitespace-regexp nil) + (depth-biased (- target-depth 2)) + (expression (if (<= target-depth 1) + allout-depth-one-regexp + (format allout-depth-specific-regexp + depth-biased depth-biased))) + found + done) + (while (not done) + (setq found (if backward + (re-search-backward expression nil 'to-limit) + (forward-char 1) + (re-search-forward expression nil 'to-limit))) + (if (and found (allout-aberrant-container-p)) + (setq found nil)) + (setq done (or found (if backward (bobp) (eobp))))) + (if (not found) + (progn (goto-char start-point) + nil) + ;; rationale: if any intervening items were at a lower depth, we + ;; would now be on the first offspring at the target depth - ie, + ;; the preceeding item (per the search direction) must be at a + ;; lesser depth. that's all we need to check. + (if backward (allout-next-heading) (allout-previous-heading)) + (if (< allout-recent-depth target-depth) + ;; return to start and reestablish allout-recent-*: + (progn + (goto-char start-point) + (allout-depth) + nil) + (goto-char found) + ;; locate cursor and set allout-recent-*: + (allout-goto-prefix)))))) ;;;_ > allout-previous-sibling (&optional depth backward) (defun allout-previous-sibling (&optional depth backward) "Like `allout-forward-current-level' backwards, respecting invisible topics. @@ -2807,7 +3030,7 @@ (let ((depth (allout-depth))) (while (allout-previous-sibling depth nil)) - (prog1 (allout-recent-depth) + (prog1 allout-recent-depth (if (interactive-p) (allout-end-of-prefix))))) ;;;_ > allout-next-visible-heading (arg) (defun allout-next-visible-heading (arg) @@ -2821,21 +3044,36 @@ (step (if backward -1 1)) prev got) - (while (> arg 0) ; limit condition - (while (and (not (if backward (bobp)(eobp))) ; boundary condition - ;; Move, skipping over all those concealed lines: - (prog1 (condition-case nil (or (line-move step) t) - (error nil)) - (allout-beginning-of-current-line)) - (not (setq got (looking-at allout-regexp))))) + (while (> arg 0) + (while (and + ;; Boundary condition: + (not (if backward (bobp)(eobp))) + ;; Move, skipping over all concealed lines in one fell swoop: + (prog1 (condition-case nil (or (line-move step) t) + (error nil)) + (allout-beginning-of-current-line)) + ;; Deal with apparent header line: + (if (not (looking-at allout-regexp)) + ;; not a header line, keep looking: + t + (allout-prefix-data) + (if (and (<= allout-recent-depth + allout-doublecheck-at-and-shallower) + (allout-aberrant-container-p)) + ;; skip this aberrant prospective header line: + t + ;; this prospective headerline qualifies - register: + (setq got allout-recent-prefix-beginning) + ;; and break the loop: + nil)))) ;; Register this got, it may be the last: (if got (setq prev got)) (setq arg (1- arg))) (cond (got ; Last move was to a prefix: - (allout-prefix-data (match-beginning 0) (match-end 0)) - (allout-end-of-prefix)) + (allout-end-of-prefix)) (prev ; Last move wasn't, but prev was: - (allout-prefix-data (match-beginning 0) (match-end 0))) + (goto-char prev) + (allout-end-of-prefix)) ((not backward) (end-of-line) nil)))) ;;;_ > allout-previous-visible-heading (arg) (defun allout-previous-visible-heading (arg) @@ -2845,7 +3083,8 @@ A heading line is one that starts with a `*' (or that `allout-regexp' matches)." (interactive "p") - (allout-next-visible-heading (- arg))) + (prog1 (allout-next-visible-heading (- arg)) + (if (interactive-p) (allout-end-of-prefix)))) ;;;_ > allout-forward-current-level (arg) (defun allout-forward-current-level (arg) "Position point at the next heading of the same level. @@ -2856,38 +3095,25 @@ (interactive "p") (let ((start-depth (allout-current-depth)) (start-arg arg) - (backward (> 0 arg)) - last-depth - (last-good (point)) - at-boundary) + (backward (> 0 arg))) (if (= 0 start-depth) (error "No siblings, not in a topic...")) (if backward (setq arg (* -1 arg))) - (while (not (or (zerop arg) - at-boundary)) - (while (and (not (if backward (bobp) (eobp))) - (if backward (allout-previous-visible-heading 1) - (allout-next-visible-heading 1)) - (> (setq last-depth (allout-recent-depth)) start-depth))) - (if (and last-depth (= last-depth start-depth) - (not (if backward (bobp) (eobp)))) - (setq last-good (point) - arg (1- arg)) - (setq at-boundary t))) - (if (and (not (eobp)) - (= arg 0) - (and (> (or last-depth (allout-depth)) 0) - (= (allout-recent-depth) start-depth))) - allout-recent-prefix-beginning - (goto-char last-good) - (if (not (interactive-p)) - nil - (allout-end-of-prefix) - (error "Hit %s level %d topic, traversed %d of %d requested" - (if backward "first" "last") - (allout-recent-depth) - (- (abs start-arg) arg) - (abs start-arg)))))) + (allout-back-to-current-heading) + (while (and (not (zerop arg)) + (if backward + (allout-previous-sibling) + (allout-next-sibling))) + (setq arg (1- arg))) + (if (not (interactive-p)) + nil + (allout-end-of-prefix) + (if (not (zerop arg)) + (error "Hit %s level %d topic, traversed %d of %d requested" + (if backward "first" "last") + allout-recent-depth + (- (abs start-arg) arg) + (abs start-arg)))))) ;;;_ > allout-backward-current-level (arg) (defun allout-backward-current-level (arg) "Inverse of `allout-forward-current-level'." @@ -2977,34 +3203,41 @@ Returns the qualifying command, if any, else nil." (interactive) - (let* ((key-num (cond ((numberp last-command-char) last-command-char) + (let* ((key-string (if (numberp last-command-char) + (char-to-string last-command-char))) + (key-num (cond ((numberp last-command-char) last-command-char) ;; for XEmacs character type: ((and (fboundp 'characterp) (apply 'characterp (list last-command-char))) (apply 'char-to-int (list last-command-char))) (t 0))) - mapped-binding - (on-bullet (eq (point) (allout-current-bullet-pos)))) + mapped-binding) (if (zerop key-num) nil - (if (and (<= 33 key-num) - (setq mapped-binding + (if (and + ;; exclude control chars and escape: + (<= 33 key-num) + (setq mapped-binding + (or (and (assoc key-string allout-keybindings-list) + ;; translate literal membership on list: + (cadr (assoc key-string allout-keybindings-list))) + ;; translate as a keybinding: (key-binding (concat allout-command-prefix (char-to-string - (if (and (<= 97 key-num) ; "a" + (if (and (<= 97 key-num) ; "a" (>= 122 key-num)) ; "z" (- key-num 96) key-num))) - t))) - ;; Qualified with the allout prefix - do hot-spot operation. + t)))) + ;; Qualified as an allout command - do hot-spot operation. (setq allout-post-goto-bullet t) ;; accept-defaults nil, or else we'll get allout-item-icon-key-handler. (setq mapped-binding (key-binding (char-to-string key-num)))) (while (keymapp mapped-binding) (setq mapped-binding - (lookup-key mapped-binding (read-key-sequence-vector nil t)))) + (lookup-key mapped-binding (vector (read-char))))) (if mapped-binding (setq this-command mapped-binding))))) @@ -3036,7 +3269,7 @@ (setq choice (solicit-char-in-string (format "Select bullet: %s ('%s' default): " sans-escapes - default-bullet) + (substring-no-properties default-bullet)) sans-escapes t))) (message "") @@ -3275,7 +3508,7 @@ (allout-ascend-to-depth depth)) ((>= relative-depth 1) nil) (t (allout-back-to-current-heading))) - (setq ref-depth (allout-recent-depth)) + (setq ref-depth allout-recent-depth) (setq ref-bullet (if (> allout-recent-prefix-end 1) (allout-recent-bullet) @@ -3363,7 +3596,7 @@ (setq dbl-space t)) (if (save-excursion (allout-next-heading) - (when (> (allout-recent-depth) ref-depth) + (when (> allout-recent-depth ref-depth) ;; This is an offspring. (forward-line -1) (looking-at "^\\s-*$"))) @@ -3388,7 +3621,13 @@ (if (and dbl-space (not (> relative-depth 0))) (newline 1)) (if (and (not (eobp)) - (not (bolp))) + (or (not (bolp)) + (and (not (bobp)) + ;; bolp doesnt detect concealed + ;; trailing newlines, compensate: + (save-excursion + (forward-char -1) + (allout-hidden-p))))) (forward-char 1)))) )) (setq start (point)) @@ -3507,23 +3746,28 @@ (interactive "p") (let ((initial-col (current-column)) (on-bullet (eq (point)(allout-current-bullet-pos))) + from to (backwards (if (< arg 0) (setq arg (* arg -1))))) (while (> arg 0) (save-excursion (allout-back-to-current-heading) (allout-end-of-prefix) + (setq from allout-recent-prefix-beginning + to allout-recent-prefix-end) (allout-rebullet-heading t ;;; solicit nil ;;; depth nil ;;; number-control nil ;;; index - t)) ;;; do-successors + t) ;;; do-successors + (run-hook-with-args 'allout-exposure-change-hook + from to t)) (setq arg (1- arg)) (if (<= arg 0) nil (setq initial-col nil) ; Override positioning back to init col (if (not backwards) (allout-next-visible-heading 1) - (allout-goto-prefix) + (allout-goto-prefix-doublechecked) (allout-next-visible-heading -1)))) (message "Done.") (cond (on-bullet (goto-char (allout-current-bullet-pos))) @@ -3573,7 +3817,7 @@ (new-depth (or new-depth current-depth)) (mb allout-recent-prefix-beginning) (me allout-recent-prefix-end) - (current-bullet (buffer-substring (- me 1) me)) + (current-bullet (buffer-substring-no-properties (- me 1) me)) (new-prefix (allout-make-topic-prefix current-bullet nil new-depth @@ -3627,11 +3871,17 @@ ) ; let* ((current-depth (allout-depth))...) ) ; defun ;;;_ > allout-rebullet-topic (arg) -(defun allout-rebullet-topic (arg) +(defun allout-rebullet-topic (arg &optional sans-offspring) "Rebullet the visible topic containing point and all contained subtopics. Descends into invisible as well as visible topics, however. +When optional sans-offspring is non-nil, subtopics are not +shifted. \(Shifting a topic outwards without shifting its +offspring is disallowed, since this would create a \"containment +discontinuity\", where the depth difference between a topic and +its immediate offspring is greater than one.) + With repeat count, shift topic depth by that amount." (interactive "P") (let ((start-col (current-column))) @@ -3642,17 +3892,18 @@ ;; Fill the user in, in case we're shifting a big topic: (if (not (zerop arg)) (message "Shifting...")) (allout-back-to-current-heading) - (if (<= (+ (allout-recent-depth) arg) 0) + (if (<= (+ allout-recent-depth arg) 0) (error "Attempt to shift topic below level 1")) - (allout-rebullet-topic-grunt arg) + (allout-rebullet-topic-grunt arg nil nil nil nil sans-offspring) (if (not (zerop arg)) (message "Shifting... done."))) (move-to-column (max 0 (+ start-col arg))))) -;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...) +;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...) (defun allout-rebullet-topic-grunt (&optional relative-depth starting-depth starting-point index - do-successors) + do-successors + sans-offspring) "Like `allout-rebullet-topic', but on nearest containing topic \(visible or not). @@ -3663,8 +3914,23 @@ First arg RELATIVE-DEPTH means to shift the depth of the entire topic that amount. -The rest of the args are for internal recursive use by the function -itself. The are STARTING-DEPTH, STARTING-POINT, and INDEX." +Several subsequent args are for internal recursive use by the function +itself: STARTING-DEPTH, STARTING-POINT, and INDEX. + +Finally, if optional SANS-OFFSPRING is non-nil then the offspring +are not shifted. \(Shifting a topic outwards without shifting +its offspring is disallowed, since this would create a +\"containment discontinuity\", where the depth difference between +a topic and its immediate offspring is greater than one..)" + + ;; XXX the recursion here is peculiar, and in general the routine may + ;; need simplification with refactoring. + + (if (and sans-offspring + relative-depth + (< relative-depth 0)) + (error (concat "Attempt to shift topic outwards without offspring," + " would cause containment discontinuity."))) (let* ((relative-depth (or relative-depth 0)) (new-depth (allout-depth)) @@ -3676,44 +3942,57 @@ (and (or (zerop relative-depth) (not on-starting-call)) (allout-sibling-index)))) + (starting-index index) (moving-outwards (< 0 relative-depth)) - (starting-point (or starting-point (point)))) + (starting-point (or starting-point (point))) + (local-point (point))) ;; Sanity check for excessive promotion done only on starting call: (and on-starting-call moving-outwards (> 0 (+ starting-depth relative-depth)) - (error "Attempt to shift topic out beyond level 1")) ;;; ====> + (error "Attempt to shift topic out beyond level 1")) (cond ((= starting-depth new-depth) - ;; We're at depth to work on this one: - (allout-rebullet-heading nil ;;; solicit - (+ starting-depth ;;; starting-depth - relative-depth) - nil ;;; number - index ;;; index - ;; Every contained topic will get hit, - ;; and we have to get to outside ones - ;; deliberately: - nil) ;;; do-successors - ;; ... and work on subsequent ones which are at greater depth: - (setq index 0) - (allout-next-heading) - (while (and (not (eobp)) - (< starting-depth (allout-recent-depth))) - (setq index (1+ index)) - (allout-rebullet-topic-grunt relative-depth ;;; relative-depth - (1+ starting-depth);;;starting-depth - starting-point ;;; starting-point - index))) ;;; index + ;; We're at depth to work on this one. + + ;; When shifting out we work on the children before working on + ;; the parent to avoid interim `allout-aberrant-container-p' + ;; aberrancy, and vice-versa when shifting in: + (if (>= relative-depth 0) + (allout-rebullet-heading nil + (+ starting-depth relative-depth) + nil ;;; number + index + nil)) ;;; do-successors + (when (not sans-offspring) + ;; ... and work on subsequent ones which are at greater depth: + (setq index 0) + (allout-next-heading) + (while (and (not (eobp)) + (< starting-depth (allout-depth))) + (setq index (1+ index)) + (allout-rebullet-topic-grunt relative-depth + (1+ starting-depth) + starting-point + index))) + (when (< relative-depth 0) + (save-excursion + (goto-char local-point) + (allout-rebullet-heading nil ;;; solicit + (+ starting-depth relative-depth) + nil ;;; number + starting-index + nil)))) ;;; do-successors ((< starting-depth new-depth) ;; Rare case - subtopic more than one level deeper than parent. ;; Treat this one at an even deeper level: - (allout-rebullet-topic-grunt relative-depth ;;; relative-depth - new-depth ;;; starting-depth - starting-point ;;; starting-point - index))) ;;; index + (allout-rebullet-topic-grunt relative-depth + new-depth + starting-point + index + sans-offspring))) (if on-starting-call (progn @@ -3721,8 +4000,8 @@ ;; if topic has changed depth (if (or do-successors (and (not (zerop relative-depth)) - (or (= (allout-recent-depth) starting-depth) - (= (allout-recent-depth) (+ starting-depth + (or (= allout-recent-depth starting-depth) + (= allout-recent-depth (+ starting-depth relative-depth))))) (allout-rebullet-heading nil nil nil nil t)) ;; Now rectify numbering of new siblings of the adjusted topic, @@ -3747,24 +4026,24 @@ was-eobp) (while (and (not (eobp)) (allout-depth) - (>= (allout-recent-depth) depth) + (>= allout-recent-depth depth) (>= ascender depth)) ; Skip over all topics at ; lesser depths, which can not ; have been disturbed: (while (and (not (setq was-eobp (eobp))) - (> (allout-recent-depth) ascender)) + (> allout-recent-depth ascender)) (allout-next-heading)) ; Prime ascender for ascension: - (setq ascender (1- (allout-recent-depth))) - (if (>= (allout-recent-depth) depth) + (setq ascender (1- allout-recent-depth)) + (if (>= allout-recent-depth depth) (allout-rebullet-heading nil ;;; solicit nil ;;; depth nil ;;; number-control nil ;;; index t)) ;;; do-successors (if was-eobp (goto-char (point-max))))) - (allout-recent-depth)) + allout-recent-depth) ;;;_ > allout-number-siblings (&optional denumber) (defun allout-number-siblings (&optional denumber) "Assign numbered topic prefix to this topic and its siblings. @@ -3780,7 +4059,7 @@ (save-excursion (allout-back-to-current-heading) (allout-beginning-of-level) - (let ((depth (allout-recent-depth)) + (let ((depth allout-recent-depth) (index (if (not denumber) 1)) (use-bullet (equal '(16) denumber)) (more t)) @@ -3794,55 +4073,84 @@ (setq more (allout-next-sibling depth nil)))))) ;;;_ > allout-shift-in (arg) (defun allout-shift-in (arg) - "Increase depth of current heading and any topics collapsed within it. - -We disallow shifts that would result in the topic having a depth more than -one level greater than the immediately previous topic, to avoid containment -discontinuity. The first topic in the file can be adjusted to any positive -depth, however." + "Increase depth of current heading and any items collapsed within it. + +With a negative argument, the item is shifted out using +`allout-shift-out', instead. + +With an argument greater than one, shift-in the item but not its +offspring, making the item into a sibling of its former children, +and a child of sibling that formerly preceeded it. + +You are not allowed to shift the first offspring of a topic +inwards, because that would yield a \"containment +discontinuity\", where the depth difference between a topic and +its immediate offspring is greater than one. The first topic in +the file can be adjusted to any positive depth, however." + (interactive "p") - (if (> arg 0) - ;; refuse to create a containment discontinuity: - (save-excursion - (allout-back-to-current-heading) - (if (not (bobp)) - (let* ((current-depth (allout-recent-depth)) - (start-point (point)) - (predecessor-depth (progn - (forward-char -1) - (allout-goto-prefix) - (if (< (point) start-point) - (allout-recent-depth) - 0)))) - (if (and (> predecessor-depth 0) - (> (+ current-depth arg) - (1+ predecessor-depth))) - (error (concat "Disallowed shift deeper than" - " containing topic's children."))))))) - (let ((where (point)) - has-successor) - (if (and (< arg 0) - (allout-current-topic-collapsed-p) - (save-excursion (allout-next-sibling))) - (setq has-successor t)) - (allout-rebullet-topic arg) - (when (< arg 0) - (save-excursion - (if (allout-ascend) - (allout-show-children))) - (if has-successor - (allout-show-children))) - (run-hook-with-args 'allout-structure-shifted-hook arg where))) + (if (< arg 0) + (allout-shift-out (* arg -1)) + ;; refuse to create a containment discontinuity: + (save-excursion + (allout-back-to-current-heading) + (if (not (bobp)) + (let* ((current-depth allout-recent-depth) + (start-point (point)) + (predecessor-depth (progn + (forward-char -1) + (allout-goto-prefix-doublechecked) + (if (< (point) start-point) + allout-recent-depth + 0)))) + (if (and (> predecessor-depth 0) + (> (1+ current-depth) + (1+ predecessor-depth))) + (error (concat "Disallowed shift deeper than" + " containing topic's children.")))))) + (let ((where (point))) + (allout-rebullet-topic 1 (and (> arg 1) 'sans-offspring)) + (run-hook-with-args 'allout-structure-shifted-hook arg where)))) ;;;_ > allout-shift-out (arg) (defun allout-shift-out (arg) "Decrease depth of current heading and any topics collapsed within it. - -We disallow shifts that would result in the topic having a depth more than -one level greater than the immediately previous topic, to avoid containment -discontinuity. The first topic in the file can be adjusted to any positive -depth, however." +This will make the item a sibling of its former container. + +With a negative argument, the item is shifted in using +`allout-shift-in', instead. + +With an argument greater than one, shift-out the item's offspring +but not the item itself, making the former children siblings of +the item. + +With an argument greater than 1, the item's offspring are shifted +out without shifting the item. This will make the immediate +subtopics into siblings of the item." (interactive "p") - (allout-shift-in (* arg -1))) + (if (< arg 0) + (allout-shift-in (* arg -1)) + ;; Get proper exposure in this area: + (save-excursion (if (allout-ascend) + (allout-show-children))) + ;; Show collapsed children if there's a successor which will become + ;; their sibling: + (if (and (allout-current-topic-collapsed-p) + (save-excursion (allout-next-sibling))) + (allout-show-children)) + (let ((where (and (allout-depth) allout-recent-prefix-beginning))) + (save-excursion + (if (> arg 1) + ;; Shift the offspring but not the topic: + (let ((children-chart (allout-chart-subtree 1))) + (if (listp (car children-chart)) + ;; whoops: + (setq children-chart (allout-flatten children-chart))) + (save-excursion + (dolist (child-point children-chart) + (goto-char child-point) + (allout-shift-out 1)))) + (allout-rebullet-topic (* arg -1)))) + (run-hook-with-args 'allout-structure-shifted-hook (* arg -1) where)))) ;;;_ : Surgery (kill-ring) functions with special provisions for outlines: ;;;_ > allout-kill-line (&optional arg) (defun allout-kill-line (&optional arg) @@ -3857,21 +4165,18 @@ (kill-line arg) ;; Ah, have to watch out for adjustments: (let* ((beg (point)) + end (beg-hidden (allout-hidden-p)) (end-hidden (save-excursion (allout-end-of-current-line) + (setq end (point)) (allout-hidden-p))) - (depth (allout-depth)) - (collapsed (allout-current-topic-collapsed-p))) - - (if collapsed - (put-text-property beg (1+ beg) 'allout-was-collapsed t) - (remove-text-properties beg (1+ beg) '(allout-was-collapsed t))) + (depth (allout-depth))) + + (allout-annotate-hidden beg end) (if (and (not beg-hidden) (not end-hidden)) (allout-unprotected (kill-line arg)) (kill-line arg)) - ; Provide some feedback: - (sit-for 0) (if allout-numbered-bullet (save-excursion ; Renumber subsequent topics if needed: (if (not (looking-at allout-regexp)) @@ -3889,20 +4194,13 @@ - would not be added to whitespace already separating the topic from the previous one. -Completely collapsed topics are marked as such, for re-collapse -when yank with allout-yank into an outline as a heading." - - ;; Some finagling is done to make complex topic kills appear faster - ;; than they actually are. A redisplay is performed immediately - ;; after the region is deleted, though the renumbering process - ;; has yet to be performed. This means that there may appear to be - ;; a lag *after* a kill has been performed. +Topic exposure is marked with text-properties, to be used by +allout-yank-processing for exposure recovery." (interactive) (let* ((inhibit-field-text-motion t) - (collapsed (allout-current-topic-collapsed-p)) (beg (prog1 (allout-back-to-current-heading) (beginning-of-line))) - (depth (allout-recent-depth))) + (depth allout-recent-depth)) (allout-end-of-current-subtree) (if (and (/= (current-column) 0) (not (eobp))) (forward-char 1)) @@ -3910,21 +4208,88 @@ (if (and (looking-at "\n") (or (save-excursion (or (not (allout-next-heading)) - (= depth (allout-recent-depth)))) + (= depth allout-recent-depth))) (and (> (- beg (point-min)) 3) (string= (buffer-substring (- beg 2) beg) "\n\n")))) (forward-char 1))) - (if collapsed - (allout-unprotected - (put-text-property beg (1+ beg) 'allout-was-collapsed t)) - (allout-unprotected - (remove-text-properties beg (1+ beg) '(allout-was-collapsed t)))) + (allout-annotate-hidden beg (point)) + (allout-unprotected (kill-region beg (point))) - (sit-for 0) (save-excursion (allout-renumber-to-depth depth)) (run-hook-with-args 'allout-structure-deleted-hook depth (point)))) +;;;_ > allout-annotate-hidden (begin end) +(defun allout-annotate-hidden (begin end) + "Qualify text with properties to indicate exposure status." + + (let ((was-modified (buffer-modified-p))) + (allout-unprotected + (remove-text-properties begin end '(allout-was-hidden t))) + (save-excursion + (goto-char begin) + (let (done next prev overlay) + (while (not done) + ;; at or advance to start of next hidden region: + (if (not (allout-hidden-p)) + (setq next + (next-single-char-property-change (point) + 'invisible nil end))) + (if (or (not next) (eq prev next)) + ;; still not at start of hidden area - must not be any left. + (setq done t) + (goto-char next) + (setq prev next) + (if (not (allout-hidden-p)) + ;; still not at start of hidden area. + (setq done t) + (setq overlay (allout-get-invisibility-overlay)) + (setq next (overlay-end overlay) + prev next) + ;; advance to end of this hidden area: + (when next + (goto-char next) + (allout-unprotected + (put-text-property (overlay-start overlay) next + 'allout-was-hidden t)))))))) + (set-buffer-modified-p was-modified))) +;;;_ > allout-hide-by-annotation (begin end) +(defun allout-hide-by-annotation (begin end) + "Translate text properties indicating exposure status into actual exposure." + (save-excursion + (goto-char begin) + (let ((was-modified (buffer-modified-p)) + done next prev) + (while (not done) + ;; at or advance to start of next annotation: + (if (not (get-text-property (point) 'allout-was-hidden)) + (setq next (next-single-char-property-change (point) + 'allout-was-hidden + nil end))) + (if (or (not next) (eq prev next)) + ;; no more or not advancing - must not be any left. + (setq done t) + (goto-char next) + (setq prev next) + (if (not (get-text-property (point) 'allout-was-hidden)) + ;; still not at start of annotation. + (setq done t) + ;; advance to just after end of this annotation: + (setq next (next-single-char-property-change (point) + 'allout-was-hidden + nil end)) + (overlay-put (make-overlay prev next) + 'category 'allout-exposure-category) + (allout-unprotected + (remove-text-properties prev next '(allout-was-hidden t))) + (setq prev next) + (if next (goto-char next))))) + (set-buffer-modified-p was-modified)))) +;;;_ > allout-remove-exposure-annotation (begin end) +(defun allout-remove-exposure-annotation (begin end) + "Remove text properties indicating exposure status." + (remove-text-properties begin end '(allout-was-hidden t))) + ;;;_ > allout-yank-processing () (defun allout-yank-processing (&optional arg) @@ -3955,12 +4320,10 @@ (let* ((subj-beg (point)) (into-bol (bolp)) (subj-end (allout-mark-marker t)) - (was-collapsed (get-text-property subj-beg 'allout-was-collapsed)) ;; 'resituate' if yanking an entire topic into topic header: (resituate (and (allout-e-o-prefix-p) - (looking-at (concat "\\(" allout-regexp "\\)")) - (allout-prefix-data (match-beginning 1) - (match-end 1)))) + (looking-at allout-regexp) + (allout-prefix-data))) ;; `rectify-numbering' if resituating (where several topics may ;; be resituating) or yanking a topic into a topic slot (bol): (rectify-numbering (or resituate @@ -3968,7 +4331,7 @@ (if resituate ; The yanked stuff is a topic: (let* ((prefix-len (- (match-end 1) subj-beg)) - (subj-depth (allout-recent-depth)) + (subj-depth allout-recent-depth) (prefix-bullet (allout-recent-bullet)) (adjust-to-depth ;; Nil if adjustment unnecessary, otherwise depth to which @@ -3982,15 +4345,13 @@ (beginning-of-line) (not (= (point) subj-beg))) (looking-at allout-regexp) - (allout-prefix-data (match-beginning 0) - (match-end 0))) - (allout-recent-depth)))) + (allout-prefix-data)) + allout-recent-depth))) (more t)) (setq rectify-numbering allout-numbered-bullet) (if adjust-to-depth ; Do the adjustment: (progn - (message "... yanking") (sit-for 0) (save-restriction (narrow-to-region subj-beg subj-end) ; Trim off excessive blank @@ -4006,7 +4367,7 @@ (while more (allout-back-to-current-heading) ; go as high as we can in each bunch: - (while (allout-ascend-to-depth (1- (allout-depth)))) + (while (allout-ascend)) (save-excursion (allout-rebullet-topic-grunt (- adjust-to-depth subj-depth)) @@ -4015,7 +4376,6 @@ (progn (widen) (forward-char -1) (narrow-to-region subj-beg (point)))))) - (message "") ;; Preserve new bullet if it's a distinctive one, otherwise ;; use old one: (if (string-match (regexp-quote prefix-bullet) @@ -4042,19 +4402,19 @@ (progn (save-excursion ; Give some preliminary feedback: - (message "... reconciling numbers") (sit-for 0) + (message "... reconciling numbers") ; ... and renumber, in case necessary: (goto-char subj-beg) - (if (allout-goto-prefix) + (if (allout-goto-prefix-doublechecked) (allout-rebullet-heading nil ;;; solicit (allout-depth) ;;; depth nil ;;; number-control nil ;;; index t)) (message "")))) - (when (and (or into-bol resituate) was-collapsed) - (remove-text-properties subj-beg (1+ subj-beg) '(allout-was-collapsed)) - (allout-hide-current-subtree)) + (if (or into-bol resituate) + (allout-hide-by-annotation (point) (allout-mark-marker t)) + (allout-remove-exposure-annotation (allout-mark-marker t) (point))) (if (not resituate) (exchange-point-and-mark)) (run-hook-with-args 'allout-structure-added-hook subj-beg subj-end)))) @@ -4139,7 +4499,7 @@ (error "%s not found and can't be created" file-name))) (condition-case failure (find-file-other-window file-name) - ('error failure)) + (error failure)) (error "%s not found" file-name)) ) ) @@ -4198,7 +4558,7 @@ (interactive) (save-excursion (let (beg end) - (allout-goto-prefix) + (allout-goto-prefix-doublechecked) (setq beg (if (allout-hidden-p) (1- (point)) (point))) (setq end (allout-pre-next-prefix)) (allout-flag-region beg end nil) @@ -4235,8 +4595,27 @@ (save-excursion (allout-beginning-of-current-line) (save-restriction - (let* ((chart (allout-chart-subtree (or level 1))) - (to-reveal (allout-chart-to-reveal chart (or level 1)))) + (let* (depth + (chart (allout-chart-subtree (or level 1))) + (to-reveal (or (allout-chart-to-reveal chart (or level 1)) + ;; interactive, show discontinuous children: + (and chart + (interactive-p) + (save-excursion + (allout-back-to-current-heading) + (setq depth (allout-current-depth)) + (and (allout-next-heading) + (> allout-recent-depth + (1+ depth)))) + (message + "Discontinuous offspring; use `%s %s'%s." + (substitute-command-keys + "\\[universal-argument]") + (substitute-command-keys + "\\[allout-shift-out]") + " to elevate them.") + (allout-chart-to-reveal + chart (- allout-recent-depth depth)))))) (goto-char start-point) (when (and strict (allout-hidden-p)) ;; Concealed root would already have been taken care of, @@ -4267,14 +4646,12 @@ (save-excursion (let ((inhibit-field-text-motion t) (orig-pt (point)) - (orig-pref (allout-goto-prefix)) + (orig-pref (allout-goto-prefix-doublechecked)) (last-at (point)) bag-it) (while (or bag-it (allout-hidden-p)) (while (allout-hidden-p) - ;; XXX We would use `(move-beginning-of-line 1)', but it gets - ;; stuck on hidden newlines at column 80, as of GNU Emacs 22.0.50. - (beginning-of-line) + (move-beginning-of-line 1) (if (allout-hidden-p) (forward-char -1))) (if (= last-at (setq last-at (point))) ;; Oops, we're not making any progress! Show the current @@ -4286,9 +4663,9 @@ (beep) (message "%s: %s" "allout-show-to-offshoot: " - "Aberrant nesting encountered."))) - (allout-show-children) - (goto-char orig-pref)) + "Aberrant nesting encountered.")) + (allout-show-children) + (goto-char orig-pref))) (goto-char orig-pt))) (if (allout-hidden-p) (allout-show-entry))) @@ -4368,10 +4745,10 @@ (current-exposed (not (allout-current-topic-collapsed-p t)))) (cond (current-exposed (allout-flag-current-subtree t)) (just-close nil) - ((allout-up-current-level 1 t) (allout-hide-current-subtree)) + ((allout-ascend) (allout-hide-current-subtree)) (t (goto-char 0) (message sibs-msg) - (allout-goto-prefix) + (allout-goto-prefix-doublechecked) (allout-expose-topic '(0 :)) (message (concat sibs-msg " Done.")))) (goto-char from))) @@ -4636,7 +5013,7 @@ level, and expose children of subsequent topics at current level *except* for the last, which should be opened completely." (list 'save-excursion - '(if (not (or (allout-goto-prefix) + '(if (not (or (allout-goto-prefix-doublechecked) (allout-next-heading))) (error "allout-new-exposure: Can't find any outline topics")) (list 'allout-expose-topic (list 'quote spec)))) @@ -4758,20 +5135,20 @@ (goto-char start) (beginning-of-line) ;; Goto initial topic, and register preceeding stuff, if any: - (if (> (allout-goto-prefix) start) + (if (> (allout-goto-prefix-doublechecked) start) ;; First topic follows beginning point - register preliminary stuff: (setq result (list (list 0 "" nil (buffer-substring start (1- (point))))))) (while (and (not done) (not (eobp)) ; Loop until we've covered the region. (not (> (point) end))) - (setq depth (allout-recent-depth) ; Current topics depth, + (setq depth allout-recent-depth ; Current topics depth, bullet (allout-recent-bullet) ; ... bullet, prefix (allout-recent-prefix) beg (progn (allout-end-of-prefix t) (point))) ; and beginning. (setq done ; The boundary for the current topic: (not (allout-next-visible-heading 1))) - (setq new-depth (allout-recent-depth)) + (setq new-depth allout-recent-depth) (setq gone-out out out (< new-depth depth)) (beginning-of-line) @@ -5040,10 +5417,10 @@ ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#" end ; bounded by end-of-line 1) ; no matches, move to end & return nil - (goto-char (match-beginning 0)) + (goto-char (match-beginning 2)) (insert "\\") (setq end (1+ end)) - (goto-char (1+ (match-end 0))))))) + (goto-char (1+ (match-end 2))))))) ;;;_ > allout-insert-latex-header (buffer) (defun allout-insert-latex-header (buffer) "Insert initial LaTeX commands at point in BUFFER." @@ -5089,7 +5466,7 @@ (allout-latex-verb-quote (if allout-title (condition-case nil (eval allout-title) - ('error "<unnamed buffer>")) + (error "<unnamed buffer>")) "Unnamed Outline")) "}\n" "\\end{center}\n\n")) @@ -5228,7 +5605,7 @@ default to symmetric encryption - you must manually \(re)encrypt key-pair encrypted topics if you want them to continue to use the key-pair cipher. -Level-1 topics, with prefix consisting solely of an `*' asterisk, cannot be +Level-one topics, with prefix consisting solely of an `*' asterisk, cannot be encrypted. If you want to encrypt the contents of a top-level topic, use \\[allout-shift-in] to increase its depth. @@ -5291,12 +5668,13 @@ (save-excursion (allout-end-of-prefix t) - (if (= (allout-recent-depth) 1) + (if (= allout-recent-depth 1) (error (concat "Cannot encrypt or decrypt level 1 topics -" " shift it in to make it encryptable"))) (let* ((allout-buffer (current-buffer)) ;; Asses location: + (bullet-pos allout-recent-prefix-beginning) (after-bullet-pos (point)) (was-encrypted (progn (if (= (point-max) after-bullet-pos) @@ -5362,12 +5740,9 @@ (delete-char 1)) ;; Add the is-encrypted bullet qualifier: (goto-char after-bullet-pos) - (insert "*")) - ) - ) - ) - ) - ) + (insert "*")))) + (run-hook-with-args 'allout-exposure-changed-hook + bullet-pos subtree-end nil)))) ;;;_ > allout-encrypt-string (text decrypt allout-buffer key-type for-key ;;; fetch-pass &optional retried verifying ;;; passphrase) @@ -5512,7 +5887,8 @@ (error "decryption failed"))))) (setq result-text - (buffer-substring 1 (- (point-max) (if decrypt 0 1)))) + (buffer-substring-no-properties + 1 (- (point-max) (if decrypt 0 1)))) ) ;; validate result - non-empty @@ -5924,17 +6300,8 @@ ) ;;;_ #9 miscellaneous -;;;_ > allout-mark-topic () -(defun allout-mark-topic () - "Put the region around topic currently containing point." - (interactive) - (let ((inhibit-field-text-motion t)) - (beginning-of-line)) - (allout-goto-prefix) - (push-mark (point)) - (allout-end-of-current-subtree) - (exchange-point-and-mark)) -;;;_ > outlineify-sticky () +;;;_ : Mode: +;;;_ > outlineify-sticky () ;; outlinify-sticky is correct spelling; provide this alias for sticklers: ;;;###autoload (defalias 'outlinify-sticky 'outlineify-sticky) @@ -5958,7 +6325,7 @@ "`allout-mode' docstring: `^Hm'.")) (allout-adjust-file-variable "allout-layout" (or allout-layout '(-1 : 0)))))) -;;;_ > allout-file-vars-section-data () +;;;_ > allout-file-vars-section-data () (defun allout-file-vars-section-data () "Return data identifying the file-vars section, or nil if none. @@ -5986,7 +6353,7 @@ ) ) ) -;;;_ > allout-adjust-file-variable (varname value) +;;;_ > allout-adjust-file-variable (varname value) (defun allout-adjust-file-variable (varname value) "Adjust the setting of an emacs file variable named VARNAME to VALUE. @@ -6050,7 +6417,38 @@ ) ) ) -;;;_ > solicit-char-in-string (prompt string &optional do-defaulting) +;;;_ > allout-get-configvar-values (varname) +(defun allout-get-configvar-values (configvar-name) + "Return a list of values of the symbols in list bound to CONFIGVAR-NAME. + +The user is prompted for removal of symbols that are unbound, and they +otherwise are ignored. + +CONFIGVAR-NAME should be the name of the configuration variable, +not its value." + + (let ((configvar-value (symbol-value configvar-name)) + got) + (dolist (sym configvar-value) + (if (not (boundp sym)) + (if (yes-or-no-p (format "%s entry `%s' is unbound - remove it? " + configvar-name sym)) + (delq sym (symbol-value configvar-name))) + (push (symbol-value sym) got))) + (reverse got))) +;;;_ : Topics: +;;;_ > allout-mark-topic () +(defun allout-mark-topic () + "Put the region around topic currently containing point." + (interactive) + (let ((inhibit-field-text-motion t)) + (beginning-of-line)) + (allout-goto-prefix-doublechecked) + (push-mark (point)) + (allout-end-of-current-subtree) + (exchange-point-and-mark)) +;;;_ : UI: +;;;_ > solicit-char-in-string (prompt string &optional do-defaulting) (defun solicit-char-in-string (prompt string &optional do-defaulting) "Solicit (with first arg PROMPT) choice of a character from string STRING. @@ -6083,7 +6481,8 @@ ;; got something out of loop - return it: got) ) -;;;_ > regexp-sans-escapes (string) +;;;_ : Strings: +;;;_ > regexp-sans-escapes (string) (defun regexp-sans-escapes (regexp &optional successive-backslashes) "Return a copy of REGEXP with all character escapes stripped out. @@ -6106,7 +6505,7 @@ (regexp-sans-escapes (substring regexp 1))) ;; Exclude first char, but maintain count: (regexp-sans-escapes (substring regexp 1) successive-backslashes)))) -;;;_ > count-trailing-whitespace-region (beg end) +;;;_ > count-trailing-whitespace-region (beg end) (defun count-trailing-whitespace-region (beg end) "Return number of trailing whitespace chars between BEG and END. @@ -6117,29 +6516,25 @@ (goto-char beg) (let ((count 0)) (while (re-search-forward "[ ][ ]*$" end t) - (goto-char (1+ (match-beginning 0))) + (goto-char (1+ (match-beginning 2))) (setq count (1+ count))) count)))) -;;;_ > allout-get-configvar-values (varname) -(defun allout-get-configvar-values (configvar-name) - "Return a list of values of the symbols in list bound to CONFIGVAR-NAME. - -The user is prompted for removal of symbols that are unbound, and they -otherwise are ignored. - -CONFIGVAR-NAME should be the name of the configuration variable, -not its value." - - (let ((configvar-value (symbol-value configvar-name)) - got) - (dolist (sym configvar-value) - (if (not (boundp sym)) - (if (yes-or-no-p (format "%s entry `%s' is unbound - remove it? " - configvar-name sym)) - (delq sym (symbol-value configvar-name))) - (push (symbol-value sym) got))) - (reverse got))) -;;;_ > allout-mark-marker to accommodate divergent emacsen: +;;;_ > allout-format-quote (string) +(defun allout-format-quote (string) + "Return a copy of string with all \"%\" characters doubled." + (apply 'concat + (mapcar (lambda (char) (if (= char ?%) "%%" (char-to-string char))) + string))) +;;;_ : lists +;;;_ > allout-flatten (list) +(defun allout-flatten (list) + "Return a list of all atoms in list." + ;; classic. + (cond ((null list) nil) + ((atom (car list)) (cons (car list) (flatten (cdr list)))) + (t (append (flatten (car list)) (flatten (cdr list)))))) +;;;_ : Compatability: +;;;_ > allout-mark-marker to accommodate divergent emacsen: (defun allout-mark-marker (&optional force buffer) "Accommodate the different signature for `mark-marker' across Emacsen. @@ -6148,7 +6543,7 @@ (if (featurep 'xemacs) (apply 'mark-marker force buffer) (mark-marker))) -;;;_ > subst-char-in-string if necessary +;;;_ > subst-char-in-string if necessary (if (not (fboundp 'subst-char-in-string)) (defun subst-char-in-string (fromchar tochar string &optional inplace) "Replace FROMCHAR with TOCHAR in STRING each time it occurs. @@ -6160,10 +6555,10 @@ (if (eq (aref newstr i) fromchar) (aset newstr i tochar))) newstr))) -;;;_ > wholenump if necessary +;;;_ > wholenump if necessary (if (not (fboundp 'wholenump)) (defalias 'wholenump 'natnump)) -;;;_ > remove-overlays if necessary +;;;_ > remove-overlays if necessary (if (not (fboundp 'remove-overlays)) (defun remove-overlays (&optional beg end name val) "Clear BEG and END of overlays whose property NAME has value VAL. @@ -6190,7 +6585,7 @@ (move-overlay o end (overlay-end o)) (delete-overlay o))))))) ) -;;;_ > copy-overlay if necessary - xemacs ~ 21.4 +;;;_ > copy-overlay if necessary - xemacs ~ 21.4 (if (not (fboundp 'copy-overlay)) (defun copy-overlay (o) "Return a copy of overlay O." @@ -6202,7 +6597,7 @@ (while props (overlay-put o1 (pop props) (pop props))) o1))) -;;;_ > add-to-invisibility-spec if necessary - xemacs ~ 21.4 +;;;_ > add-to-invisibility-spec if necessary - xemacs ~ 21.4 (if (not (fboundp 'add-to-invisibility-spec)) (defun add-to-invisibility-spec (element) "Add ELEMENT to `buffer-invisibility-spec'. @@ -6212,14 +6607,14 @@ (setq buffer-invisibility-spec (list t))) (setq buffer-invisibility-spec (cons element buffer-invisibility-spec)))) -;;;_ > remove-from-invisibility-spec if necessary - xemacs ~ 21.4 +;;;_ > remove-from-invisibility-spec if necessary - xemacs ~ 21.4 (if (not (fboundp 'remove-from-invisibility-spec)) (defun remove-from-invisibility-spec (element) "Remove ELEMENT from `buffer-invisibility-spec'." (if (consp buffer-invisibility-spec) (setq buffer-invisibility-spec (delete element buffer-invisibility-spec))))) -;;;_ > move-beginning-of-line if necessary - older emacs, xemacs +;;;_ > move-beginning-of-line if necessary - older emacs, xemacs (if (not (fboundp 'move-beginning-of-line)) (defun move-beginning-of-line (arg) "Move point to beginning of current line as displayed. @@ -6243,7 +6638,7 @@ (skip-chars-backward "^\n")) (vertical-motion 0)) ) -;;;_ > move-end-of-line if necessary - older emacs, xemacs +;;;_ > move-end-of-line if necessary - older emacs, xemacs (if (not (fboundp 'move-end-of-line)) (defun move-end-of-line (arg) "Move point to end of current line as displayed. @@ -6283,7 +6678,7 @@ (setq arg 1) (setq done t))))))) ) -;;;_ > line-move-invisible-p if necessary +;;;_ > line-move-invisible-p if necessary (if (not (fboundp 'line-move-invisible-p)) (defun line-move-invisible-p (pos) "Return non-nil if the character after POS is currently invisible."