123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406 |
- ;; allout-widgets.el --- Visually highlight allout outline structure.
- ;; Copyright (C) 2005-2017 Free Software Foundation, Inc.
- ;; Author: Ken Manheimer <ken dot manheimer at gmail...>
- ;; Maintainer: Ken Manheimer <ken dot manheimer at gmail...>
- ;; Version: 1.0
- ;; Created: Dec 2005
- ;; Keywords: outlines
- ;; Website: http://myriadicity.net/software-and-systems/craft/emacs-allout
- ;; This file is part of GNU Emacs.
- ;; GNU Emacs is free software: you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, either version 3 of the License, or
- ;; (at your option) any later version.
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
- ;;; Commentary:
- ;; This is an allout outline-mode add-on that highlights outline structure
- ;; with graphical widgets.
- ;;
- ;; To activate, customize `allout-widgets-auto-activation'. You can also
- ;; invoke allout-widgets-mode in a particular allout buffer. When
- ;; auto-enabled, you can inhibit widget operation in particular allout
- ;; buffers by setting the variable `allout-widgets-mode-inhibit' non-nil in
- ;; that file's buffer. Use emacs *file local variables* to generally
- ;; inhibit for a file.
- ;;
- ;; See the `allout-widgets-mode' docstring for more details.
- ;;
- ;; Info about allout and allout-widgets development are available at
- ;; http://myriadicity.net/Sundry/EmacsAllout
- ;;
- ;; The graphics include:
- ;;
- ;; - icons for item bullets, varying to distinguish whether the item either
- ;; lacks any subitems, the subitems are currently collapsed within the
- ;; item, or the item is currently expanded.
- ;;
- ;; - guide lines connecting item bullet-icons with those of their subitems.
- ;;
- ;; - cue area between the bullet-icon and the start of the body headline,
- ;; for item numbering, encryption indicator, and distinctive bullets.
- ;;
- ;; The bullet-icon and guide line graphics provide keybindings and mouse
- ;; bindings for easy outline navigation and exposure control, extending
- ;; outline hot-spot navigation (see `allout-mode' docstring for details).
- ;;
- ;; Developers note: Our use of emacs widgets is unconventional. We
- ;; decorate existing text rather than substituting for it, to
- ;; piggy-back on existing allout operation. This employs the C-coded
- ;; efficiencies of widget-apply, widget-get, and widget-put, along
- ;; with the basic object-oriented organization of widget-create, to
- ;; systematically couple overlays, graphics, and other features with
- ;; allout-governed text.
- ;;; Code:
- ;;;_ : General Environment
- (require 'allout)
- (require 'widget)
- (require 'wid-edit)
- (eval-when-compile
- (progn
- (require 'overlay)
- (require 'cl)
- ))
- ;;;_ : internal variables needed before user-customization variables
- ;;; In order to enable activation of allout-widgets-mode via customization,
- ;;; allout-widgets-auto-activation uses a setting function. That function
- ;;; is invoked when the customization variable definition is evaluated,
- ;;; during file load, so the involved code must reside above that
- ;;; definition in the file.
- ;;;_ = allout-widgets-mode
- (defvar allout-widgets-mode nil
- "Allout mode enhanced with graphical widgets.")
- (make-variable-buffer-local 'allout-widgets-mode)
- ;;;_ : USER CUSTOMIZATION VARIABLES and incidental functions:
- ;;;_ > defgroup allout-widgets
- (defgroup allout-widgets nil
- "Allout extension that highlights outline structure graphically.
- Customize `allout-widgets-auto-activation' to activate allout-widgets
- with allout-mode."
- :group 'allout)
- ;;;_ > defgroup allout-widgets-developer
- (defgroup allout-widgets-developer nil
- "Settings for development of allout widgets extension."
- :group 'allout-widgets)
- ;;;_ ; some functions a bit early, for allout-auto-activation dependency:
- ;;;_ > allout-widgets-mode-enable
- (defun allout-widgets-mode-enable ()
- "Enable allout-widgets-mode in allout-mode buffers.
- See `allout-widgets-mode-inhibit' for per-file/per-buffer
- inhibition of allout-widgets-mode."
- (add-hook 'allout-mode-off-hook 'allout-widgets-mode-off)
- (add-hook 'allout-mode-on-hook 'allout-widgets-mode-on)
- t)
- ;;;_ > allout-widgets-mode-disable
- (defun allout-widgets-mode-disable ()
- "Disable allout-widgets-mode in allout-mode buffers.
- See `allout-widgets-mode-inhibit' for per-file/per-buffer
- inhibition of allout-widgets-mode."
- (remove-hook 'allout-mode-off-hook 'allout-widgets-mode-off)
- (remove-hook 'allout-mode-on-hook 'allout-widgets-mode-on)
- t)
- ;;;_ > allout-widgets-setup (varname value)
- ;;;###autoload
- (defun allout-widgets-setup (varname value)
- "Commission or decommission allout-widgets-mode along with allout-mode.
- Meant to be used by customization of `allout-widgets-auto-activation'."
- (set-default varname value)
- (if allout-widgets-auto-activation
- (allout-widgets-mode-enable)
- (allout-widgets-mode-disable)))
- ;;;_ = allout-widgets-auto-activation
- ;;;###autoload
- (defcustom allout-widgets-auto-activation nil
- "Activate to enable allout icon graphics wherever allout mode is active.
- Also enable `allout-auto-activation' for this to take effect upon
- visiting an outline.
- When this is set you can disable allout widgets in select files
- by setting `allout-widgets-mode-inhibit'
- Instead of setting `allout-widgets-auto-activation' you can
- explicitly invoke `allout-widgets-mode' in allout buffers where
- you want allout widgets operation.
- See `allout-widgets-mode' for allout widgets mode features."
- :version "24.1"
- :type 'boolean
- :group 'allout-widgets
- :set 'allout-widgets-setup
- )
- ;; ;;;_ = allout-widgets-allow-unruly-edits
- ;; (defcustom allout-widgets-allow-unruly-edits nil
- ;; "Control whether manual edits are restricted to maintain outline integrity.
- ;; When nil, manual edits must either be within an item's body or encompass
- ;; one or more items completely - eg, killing topics as entities, rather than
- ;; deleting from the middle of one to the middle of another.
- ;; If you only occasionally need to make unrestricted change, you can set this
- ;; variable in the specific buffer using set-variable, or just deactivate
- ;; `allout-mode' temporarily. You can customize this to always allow unruly
- ;; edits, but you will be able to create outlines that are unnavigable in
- ;; principle, and not just for allout's navigation and exposure mechanisms."
- ;; :type 'boolean
- ;; :group allout-widgets)
- ;; (make-variable-buffer-local 'allout-widgets-allow-unruly-edits)
- ;;;_ = allout-widgets-auto-activation - below, for eval-order dependencies
- ;;;_ = allout-widgets-icons-dark-subdir
- (defcustom allout-widgets-icons-dark-subdir "icons/allout-widgets/dark-bg/"
- "Directory on `image-load-path' holding allout icons for dark backgrounds."
- :version "24.1"
- :type 'string
- :group 'allout-widgets)
- ;;;_ = allout-widgets-icons-light-subdir
- (defcustom allout-widgets-icons-light-subdir "icons/allout-widgets/light-bg/"
- "Directory on `image-load-path' holding allout icons for light backgrounds."
- :version "24.1"
- :type 'string
- :group 'allout-widgets)
- ;;;_ = allout-widgets-icon-types
- (defcustom allout-widgets-icon-types '(xpm png)
- "File extensions for the icon graphic format types, in order of preference."
- :version "24.1"
- :type '(repeat symbol)
- :group 'allout-widgets)
- ;;;_ . Decoration format
- ;;;_ = allout-widgets-theme-dark-background
- (defcustom allout-widgets-theme-dark-background "allout-dark-bg"
- "Identify the outline's icon theme to use with a dark background."
- :version "24.1"
- :type '(string)
- :group 'allout-widgets)
- ;;;_ = allout-widgets-theme-light-background
- (defcustom allout-widgets-theme-light-background "allout-light-bg"
- "Identify the outline's icon theme to use with a light background."
- :version "24.1"
- :type '(string)
- :group 'allout-widgets)
- ;;;_ = allout-widgets-item-image-properties-emacs
- (defcustom allout-widgets-item-image-properties-emacs
- '(:ascent center :mask (heuristic t))
- "Default properties item widget images in mainline Emacs."
- :version "24.1"
- :type 'plist
- :group 'allout-widgets)
- ;;;_ = allout-widgets-item-image-properties-xemacs
- (defcustom allout-widgets-item-image-properties-xemacs
- nil
- "Default properties item widget images in XEmacs."
- :version "24.1"
- :type 'plist
- :group 'allout-widgets)
- ;;;_ . Developer
- ;;;_ = allout-widgets-run-unit-tests-on-load
- (defcustom allout-widgets-run-unit-tests-on-load nil
- "When non-nil, unit tests will be run at end of loading allout-widgets.
- Generally, allout widgets code developers are the only ones who'll want to
- set this.
- \(If set, this makes it an even better practice to exercise changes by
- doing byte-compilation with a repeat count, so the file is loaded after
- compilation.)
- See `allout-widgets-run-unit-tests' to see what's run."
- :version "24.1"
- :type 'boolean
- :group 'allout-widgets-developer)
- ;;;_ = allout-widgets-time-decoration-activity
- (defcustom allout-widgets-time-decoration-activity nil
- "Retain timing info of the last cooperative redecoration.
- The details are retained as the value of
- `allout-widgets-last-decoration-timing'.
- Generally, allout widgets code developers are the only ones who'll want to
- set this."
- :version "24.1"
- :type 'boolean
- :group 'allout-widgets-developer)
- ;;;_ = allout-widgets-hook-error-post-time 0
- (defcustom allout-widgets-hook-error-post-time 0
- "Amount of time to sit showing hook error messages.
- 0 is minimal, or nil to not post to the message area.
- This is for debugging purposes."
- :version "24.1"
- :type 'integer
- :group 'allout-widgets-developer)
- ;;;_ = allout-widgets-maintain-tally nil
- (defcustom allout-widgets-maintain-tally nil
- "If non-nil, maintain a collection of widgets, `allout-widgets-tally'.
- This is for debugging purposes.
- The tally shows the total number of item widgets in the current
- buffer, and tracking increases as new widgets are added and
- decreases as obsolete widgets are garbage collected."
- :version "24.1"
- :type 'boolean
- :group 'allout-widgets-developer)
- (defvar allout-widgets-tally nil
- "Hash-table of existing allout widgets, for debugging.
- Table is maintained only if `allout-widgets-maintain-tally' is non-nil.
- The table contents will be out of sync if any widgets are created
- or deleted while this variable is nil.")
- (make-variable-buffer-local 'allout-widgets-tally)
- (defvar allout-widgets-mode-inhibit) ; defined below
- ;;;_ > allout-widgets-tally-string
- (defun allout-widgets-tally-string ()
- "Return a string giving the number of tracked widgets, or empty string if not tracking.
- The string is formed for appending to the allout-mode mode-line lighter.
- An empty string is also returned if tracking is inhibited or
- widgets are locally inhibited.
- The number varies according to the evanescence of objects on a
- hash table with weak keys, so tracking of widget erasures is often delayed."
- (when (and allout-widgets-maintain-tally
- (not allout-widgets-mode-inhibit)
- allout-widgets-tally)
- (format ":%s" (hash-table-count allout-widgets-tally))))
- ;;;_ = allout-widgets-track-decoration nil
- (defcustom allout-widgets-track-decoration nil
- "If non-nil, show cursor position of each item decoration.
- This is for debugging purposes, and generally set at need in a
- buffer rather than as a prevailing configuration (but it's handy
- to publicize it by making it a customization variable)."
- :version "24.1"
- :type 'boolean
- :group 'allout-widgets-developer)
- (make-variable-buffer-local 'allout-widgets-track-decoration)
- ;;;_ : Mode context - variables, hookup, and hooks
- ;;;_ . internal mode variables
- ;;;_ , Mode activation and environment
- ;;;_ = allout-widgets-version
- (defvar allout-widgets-version "1.0"
- "Version of currently loaded allout-widgets extension.")
- ;;;_ > allout-widgets-version
- (defun allout-widgets-version (&optional here)
- "Return string describing the loaded outline version."
- (interactive "P")
- (let ((msg (concat "Allout Outline Widgets Extension v "
- allout-widgets-version)))
- (if here (insert msg))
- (message "%s" msg)
- msg))
- ;;;_ = allout-widgets-mode-inhibit
- (defvar allout-widgets-mode-inhibit nil
- "Inhibit `allout-widgets-mode' from activating widgets.
- This also inhibits automatic adjustment of widgets to track allout outline
- changes.
- You can use this as a file local variable setting to disable
- allout widgets enhancements in selected buffers while generally
- enabling widgets by customizing `allout-widgets-auto-activation'.
- In addition, you can invoked `allout-widgets-mode' allout-mode
- buffers where this is set to enable and disable widget
- enhancements, directly.")
- ;;;###autoload
- (put 'allout-widgets-mode-inhibit 'safe-local-variable
- (if (fboundp 'booleanp) 'booleanp (lambda (x) (member x '(t nil)))))
- (make-variable-buffer-local 'allout-widgets-mode-inhibit)
- ;;;_ = allout-inhibit-body-modification-hook
- (defvar allout-inhibit-body-modification-hook nil
- "Override de-escaping of text-prefixes in item bodies during specific changes.
- This is used by `allout-buffer-modification-handler' to signal such changes
- to `allout-body-modification-handler', and is always reset by
- `allout-post-command-business'.")
- (make-variable-buffer-local 'allout-inhibit-body-modification-hook)
- ;;;_ = allout-widgets-icons-cache
- (defvar allout-widgets-icons-cache nil
- "Cache allout icon images, as an association list.
- `allout-fetch-icon-image' uses this cache transparently, keying
- images with lists containing the name of the icon directory (as
- found on the `load-path') and the icon name.
- Set this variable to nil to empty the cache, and have it replenish from the
- filesystem.")
- ;;;_ = allout-widgets-unset-inhibit-read-only
- (defvar allout-widgets-unset-inhibit-read-only nil
- "Tell `allout-widgets-post-command-business' to unset `inhibit-read-only'.
- Used by `allout-graphics-modification-handler'")
- ;;;_ = allout-widgets-reenable-before-change-handler
- (defvar allout-widgets-reenable-before-change-handler nil
- "Tell `allout-widgets-post-command-business' to reequip the handler.
- Necessary because the handler sometimes deliberately raises an
- error, causing it to be disabled.")
- ;;;_ , State for hooks
- ;;;_ = allout-unresolved-body-mod-workroster
- (defvar allout-unresolved-body-mod-workroster (make-hash-table :size 16)
- "List of body-overlays that did before-change business but not after-change.
- See `allout-post-command-business' and `allout-body-modification-handler'.")
- ;;;_ = allout-structure-unruly-deletion-message
- (defvar allout-structure-unruly-deletion-message
- "Unruly edit prevented --
- To change the bullet character: \\[allout-rebullet-current-heading]
- To promote this item: \\[allout-shift-out]
- To demote it: \\[allout-shift-in]
- To delete it and offspring: \\[allout-kill-topic]
- See \\[describe-mode] for many more options."
- "Informative message presented on improper editing of outline structure.
- The structure includes the guides lines, bullet, and bullet cue.")
- ;;;_ = allout-widgets-changes-record
- (defvar allout-widgets-changes-record nil
- "Record outline changes for processing by post-command hook.
- Entries on the list are lists whose first element is a symbol indicating
- the change type and subsequent elements are data specific to that change
- type. For example:
- (exposure ALLOUT-EXPOSURE-FROM ALLOUT-EXPOSURE-TO ALLOUT-EXPOSURE-FLAG)
- The changes are recorded in reverse order, with new values pushed
- onto the front.")
- (make-variable-buffer-local 'allout-widgets-changes-record)
- ;;;_ = allout-widgets-undo-exposure-record
- (defvar allout-widgets-undo-exposure-record nil
- "Record outline undo traces for processing by post-command hook.
- The changes are recorded in reverse order, with new values pushed
- onto the front.")
- (make-variable-buffer-local 'allout-widgets-undo-exposure-record)
- ;;;_ = allout-widgets-last-hook-error
- (defvar allout-widgets-last-hook-error nil
- "String holding last error string, for debugging purposes.")
- ;;;_ = allout-widgets-adjust-message-length-threshold 100
- (defvar allout-widgets-adjust-message-length-threshold 100
- "Display \"Adjusting widgets\" message above this number of pending changes."
- )
- ;;;_ = allout-widgets-adjust-message-size-threshold 10000
- (defvar allout-widgets-adjust-message-size-threshold 10000
- "Display \"Adjusting widgets\" message above this size of pending changes."
- )
- ;;;_ = allout-doing-exposure-undo-processor nil
- (defvar allout-undo-exposure-in-progress nil
- "Maintained true during `allout-widgets-exposure-undo-processor'")
- ;;;_ , Widget-specific outline text format
- ;;;_ = allout-escaped-prefix-regexp
- (defvar allout-escaped-prefix-regexp ""
- "Regular expression for body text that would look like an item prefix if
- not altered with an escape sequence.")
- (make-variable-buffer-local 'allout-escaped-prefix-regexp)
- ;;;_ , Widget element formatting
- ;;;_ = allout-item-icon-keymap
- (defvar allout-item-icon-keymap
- (let ((km (make-sparse-keymap)))
- (dolist (digit '("0" "1" "2" "3"
- "4" "5" "6" "7" "8" "9"))
- (define-key km digit 'digit-argument))
- (define-key km "-" 'negative-argument)
- ;; (define-key km [(return)] 'allout-tree-expand-command)
- ;; (define-key km [(meta return)] 'allout-toggle-torso-command)
- ;; (define-key km [(down-mouse-1)] 'allout-item-button-click)
- ;; (define-key km [(down-mouse-2)] 'allout-toggle-torso-event-command)
- ;; Override underlying mouse-1 and mouse-2 bindings in icon territory:
- (define-key km [(mouse-1)] (lambda () (interactive) nil))
- (define-key km [(mouse-2)] (lambda () (interactive) nil))
- ;; Catchall, handles actual keybindings, dynamically doing keymap lookups:
- (define-key km [t] 'allout-item-icon-key-handler)
- km)
- "General tree-node key bindings.")
- ;;;_ = allout-item-body-keymap
- (defvar allout-item-body-keymap
- (let ((km (make-sparse-keymap))
- (local-map (current-local-map)))
- ;; (define-key km [(control return)] 'allout-tree-expand-command)
- ;; (define-key km [(meta return)] 'allout-toggle-torso-command)
- ;; XXX We need to reset this per buffer's mode; we do so in
- ;; allout-widgets-mode.
- (if local-map
- (set-keymap-parent km local-map))
- km)
- "General key bindings for the text content of outline items.")
- (make-variable-buffer-local 'allout-item-body-keymap)
- ;;;_ = allout-body-span-category
- (defvar allout-body-span-category nil
- "Symbol carrying allout body-text overlay properties.")
- ;;;_ = allout-cue-span-keymap
- (defvar allout-cue-span-keymap
- (let ((km (make-sparse-keymap)))
- (set-keymap-parent km allout-item-icon-keymap)
- km)
- "Keymap used in the item cue area - the space between the icon and headline.")
- ;;;_ = allout-escapes-category
- (defvar allout-escapes-category nil
- "Symbol for category of text property used to hide escapes of prefix-like
- text in allout item bodies.")
- ;;;_ = allout-guides-category
- (defvar allout-guides-category nil
- "Symbol carrying allout icon-guides overlay properties.")
- ;;;_ = allout-guides-span-category
- (defvar allout-guides-span-category nil
- "Symbol carrying allout icon and guide lines overlay properties.")
- ;;;_ = allout-icon-span-category
- (defvar allout-icon-span-category nil
- "Symbol carrying allout icon and guide lines overlay properties.")
- ;;;_ = allout-cue-span-category
- (defvar allout-cue-span-category nil
- "Symbol carrying common properties of the space following the outline icon.
- \(That space is used to convey selected cues indicating body qualities,
- including things like:
- - encryption `~'
- - numbering `#'
- - indirect reference `@'
- - distinctive bullets - see `allout-distinctive-bullets-string'.)")
- ;;;_ = allout-span-to-category
- (defvar allout-span-to-category
- '((:guides-span . allout-guides-span-category)
- (:cue-span . allout-cue-span-category)
- (:icon-span . allout-icon-span-category)
- (:body-span . allout-body-span-category))
- "Association list mapping span identifier to category identifier.")
- ;;;_ = allout-trailing-category
- (defvar allout-trailing-category nil
- "Symbol carrying common properties of an overlay's trailing newline.")
- ;;;_ , Developer
- (defvar allout-widgets-last-decoration-timing nil
- "Timing details for the last cooperative decoration action.
- This is maintained when `allout-widgets-time-decoration-activity' is set.
- The value is a list containing two elements:
- - the elapsed time as a number of seconds
- - the list of changes processed, a la `allout-widgets-changes-record'.
- When active, the value is revised each time automatic decoration activity
- happens in the buffer.")
- (make-variable-buffer-local 'allout-widgets-last-decoration-timing)
- ;;;_ . mode hookup
- ;;;_ > define-minor-mode allout-widgets-mode (arg)
- ;;;###autoload
- (define-minor-mode allout-widgets-mode
- "Toggle Allout Widgets mode.
- With a prefix argument ARG, enable Allout Widgets mode if ARG is
- positive, and disable it otherwise. If called from Lisp, enable
- the mode if ARG is omitted or nil.
- Allout Widgets mode is an extension of Allout mode that provides
- graphical decoration of outline structure. It is meant to
- operate along with `allout-mode', via `allout-mode-hook'.
- The graphics include:
- - guide lines connecting item bullet-icons with those of their subitems.
- - icons for item bullets, varying to indicate whether or not the item
- has subitems, and if so, whether or not the item is expanded.
- - cue area between the bullet-icon and the start of the body headline,
- for item numbering, encryption indicator, and distinctive bullets.
- The bullet-icon and guide line graphics provide keybindings and mouse
- bindings for easy outline navigation and exposure control, extending
- outline hot-spot navigation (see `allout-mode')."
- :lighter nil
- :keymap nil
- ;; define-minor-mode handles any provided argument according to emacs
- ;; minor-mode conventions - '(elisp) Minor Mode Conventions' - and sets
- ;; allout-widgets-mode accordingly *before* running the body code, so we
- ;; cue on that.
- (if allout-widgets-mode
- ;; Activating:
- (progn
- (allout-add-resumptions
- ;; XXX user may need say in line-truncation/hscrolling - an option
- ;; that abstracts mode.
- ;; truncate text lines to keep guide lines intact:
- '(truncate-lines t)
- ;; and enable autoscrolling to ease view of text
- '(auto-hscroll-mode t)
- '(line-move-ignore-fields t)
- '(widget-push-button-prefix "")
- '(widget-push-button-suffix "")
- ;; allout-escaped-prefix-regexp depends on allout-regexp:
- (list 'allout-escaped-prefix-regexp (concat "\\(\\\\\\)"
- "\\(" allout-regexp "\\)")))
- (allout-add-resumptions
- (list 'allout-widgets-tally allout-widgets-tally)
- (list 'allout-widgets-escapes-sanitization-regexp-pair
- (list (concat "\\(\n\\|\\`\\)"
- allout-escaped-prefix-regexp
- )
- ;; Include everything but the escape symbol.
- "\\1\\3"))
- )
- (add-hook 'after-change-functions 'allout-widgets-after-change-handler
- nil t)
- (allout-setup-text-properties)
- (add-to-invisibility-spec '(allout-torso . t))
- (add-to-invisibility-spec 'allout-escapes)
- (if (current-local-map)
- (set-keymap-parent allout-item-body-keymap (current-local-map)))
- (add-hook 'allout-exposure-change-functions
- 'allout-widgets-exposure-change-recorder nil 'local)
- (add-hook 'allout-structure-added-functions
- 'allout-widgets-additions-recorder nil 'local)
- (add-hook 'allout-structure-deleted-functions
- 'allout-widgets-deletions-recorder nil 'local)
- (add-hook 'allout-structure-shifted-functions
- 'allout-widgets-shifts-recorder nil 'local)
- (add-hook 'allout-after-copy-or-kill-hook
- 'allout-widgets-after-copy-or-kill-function nil 'local)
- (add-hook 'allout-post-undo-hook
- 'allout-widgets-after-undo-function nil 'local)
- (add-hook 'before-change-functions 'allout-widgets-before-change-handler
- nil 'local)
- (add-hook 'post-command-hook 'allout-widgets-post-command-business
- nil 'local)
- (add-hook 'pre-command-hook 'allout-widgets-pre-command-business
- nil 'local)
- ;; init the widgets tally for debugging:
- (if (not allout-widgets-tally)
- (setq allout-widgets-tally (make-hash-table
- :test 'eq :weakness 'key)))
- ;; add tally count display on minor-mode-alist just after
- ;; allout-mode entry.
- ;; (we use ternary condition form to keep condition simple for deletion.)
- (let* ((mode-line-entry '(allout-widgets-mode-inhibit ""
- (:eval (allout-widgets-tally-string))))
- (associated (assoc (car mode-line-entry) minor-mode-alist))
- ;; need location for it only if not already present:
- (after (and (not associated)
- (memq (assq 'allout-mode minor-mode-alist) minor-mode-alist))))
- (if after
- (rplacd after (cons mode-line-entry (cdr after)))))
- (allout-widgets-prepopulate-buffer)
- t)
- ;; Deactivating:
- (let ((inhibit-read-only t)
- (was-modified (buffer-modified-p)))
- (allout-widgets-undecorate-region (point-min)(point-max))
- (remove-from-invisibility-spec '(allout-torso . t))
- (remove-from-invisibility-spec 'allout-escapes)
- (remove-hook 'after-change-functions
- 'allout-widgets-after-change-handler 'local)
- (remove-hook 'allout-exposure-change-functions
- 'allout-widgets-exposure-change-recorder 'local)
- (remove-hook 'allout-structure-added-functions
- 'allout-widgets-additions-recorder 'local)
- (remove-hook 'allout-structure-deleted-functions
- 'allout-widgets-deletions-recorder 'local)
- (remove-hook 'allout-structure-shifted-functions
- 'allout-widgets-shifts-recorder 'local)
- (remove-hook 'allout-after-copy-or-kill-hook
- 'allout-widgets-after-copy-or-kill-function 'local)
- (remove-hook 'before-change-functions
- 'allout-widgets-before-change-handler 'local)
- (remove-hook 'post-command-hook
- 'allout-widgets-post-command-business 'local)
- (remove-hook 'pre-command-hook
- 'allout-widgets-pre-command-business 'local)
- (assq-delete-all 'allout-widgets-mode-inhibit minor-mode-alist)
- (set-buffer-modified-p was-modified))))
- ;;;_ > allout-widgets-mode-off
- (defun allout-widgets-mode-off ()
- "Explicitly disable `allout-widgets-mode'."
- (allout-widgets-mode -1))
- ;;;_ > allout-widgets-mode-off
- (defun allout-widgets-mode-on ()
- "Explicitly enable `allout-widgets-mode'."
- (allout-widgets-mode 1))
- ;;;_ > allout-setup-text-properties ()
- (defun allout-setup-text-properties ()
- "Configure category and literal text properties."
- ;; XXX body - before-change, entry, keymap
- (setplist 'allout-guides-span-category nil)
- (put 'allout-guides-span-category
- 'modification-hooks '(allout-graphics-modification-handler))
- (put 'allout-guides-span-category 'local-map allout-item-icon-keymap)
- (put 'allout-guides-span-category 'mouse-face widget-button-face)
- (put 'allout-guides-span-category 'field 'structure)
- ;; (put 'allout-guides-span-category 'face 'widget-button)
- (setplist 'allout-icon-span-category
- (allout-widgets-copy-list (symbol-plist
- 'allout-guides-span-category)))
- (put 'allout-icon-span-category 'field 'structure)
- ;; XXX for body text we're instead going to use the buffer-wide
- ;; resources, like before/after-change-functions hooks and the
- ;; buffer's key map. that way we won't have to do painful provisions
- ;; to fixup things after edits, catch outlier interstitial
- ;; characters, like newline and empty lines after hidden subitems,
- ;; etc.
- (setplist 'allout-body-span-category nil)
- (put 'allout-body-span-category 'evaporate t)
- (put 'allout-body-span-category 'local-map allout-item-body-keymap)
- ;;(put 'allout-body-span-category
- ;; 'modification-hooks '(allout-body-modification-handler))
- ;;(put 'allout-body-span-category 'field 'body)
- (setplist 'allout-cue-span-category nil)
- (put 'allout-cue-span-category 'evaporate t)
- (put 'allout-cue-span-category
- 'modification-hooks '(allout-body-modification-handler))
- (put 'allout-cue-span-category 'local-map allout-cue-span-keymap)
- (put 'allout-cue-span-category 'mouse-face widget-button-face)
- (put 'allout-cue-span-category 'pointer 'arrow)
- (put 'allout-cue-span-category 'field 'structure)
- (setplist 'allout-trailing-category nil)
- (put 'allout-trailing-category 'evaporate t)
- (put 'allout-trailing-category 'local-map allout-item-body-keymap)
- (setplist 'allout-escapes-category nil)
- (put 'allout-escapes-category 'invisible 'allout-escapes)
- (put 'allout-escapes-category 'evaporate t))
- ;;;_ > allout-widgets-prepopulate-buffer ()
- (defun allout-widgets-prepopulate-buffer ()
- "Step over the current buffers exposed items to do initial widgetizing."
- (if (not allout-widgets-mode-inhibit)
- (save-excursion
- (goto-char (point-min))
- (while (allout-next-visible-heading 1)
- (when (not (widget-at (point)))
- (allout-get-or-create-item-widget))))))
- ;;;_ . settings context
- ;;;_ = allout-container-item
- (defvar allout-container-item-widget nil
- "A widget for the current outline's overarching container as an item.
- The item has settings (of the file/connection) and maybe a body, but no
- icon/bullet.")
- (make-variable-buffer-local 'allout-container-item-widget)
- ;;;_ . Hooks and hook helpers
- ;;;_ , major command-loop business:
- ;;;_ > allout-widgets-pre-command-business (&optional recursing)
- (defun allout-widgets-pre-command-business (&optional _recursing)
- "Handle actions pending before `allout-mode' activity."
- )
- ;;;_ > allout-widgets-post-command-business (&optional recursing)
- (defun allout-widgets-post-command-business (&optional _recursing)
- "Handle actions pending after any `allout-mode' commands.
- Optional RECURSING is for internal use, to limit recursion."
- ;; - check changed text for nesting discontinuities and escape anything
- ;; that's: (1) asterisks at bol or (2) excessively nested.
- (condition-case nil
- (when (and (boundp 'allout-mode) allout-mode)
- (if allout-widgets-unset-inhibit-read-only
- (setq inhibit-read-only nil
- allout-widgets-unset-inhibit-read-only nil))
- (when allout-widgets-reenable-before-change-handler
- (add-hook 'before-change-functions
- 'allout-widgets-before-change-handler
- nil 'local)
- (setq allout-widgets-reenable-before-change-handler nil))
- (when (or allout-widgets-undo-exposure-record
- allout-widgets-changes-record)
- (let* ((debug-on-signal t)
- (debug-on-error t)
- ;; inhibit recording new undo records when processing
- ;; effects of undo-exposure:
- (debugger 'allout-widgets-hook-error-handler)
- (adjusting-message " Adjusting widgets...")
- (replaced-message (allout-widgets-adjusting-message
- adjusting-message))
- (start-time (current-time)))
- (if allout-widgets-undo-exposure-record
- ;; inhibit undo recording iff undoing exposure stuff.
- ;; XXX we might need to inhibit per respective
- ;; change-record, rather than assuming that some undo
- ;; activity during a command is all undo activity.
- (let ((buffer-undo-list t))
- (allout-widgets-exposure-undo-processor)
- (allout-widgets-changes-dispatcher))
- (allout-widgets-exposure-undo-processor)
- (allout-widgets-changes-dispatcher))
- (if allout-widgets-time-decoration-activity
- (setq allout-widgets-last-decoration-timing
- (list (allout-elapsed-time-seconds (current-time)
- start-time)
- allout-widgets-changes-record)))
- (setq allout-widgets-changes-record nil)
- (if replaced-message
- (if (stringp replaced-message)
- (message replaced-message)
- (message "")))))
- ;; alas, decorated intermediate matches are not easily undecorated
- ;; when they're automatically rehidden by isearch, so we're
- ;; dropping this nicety.
- ;; ;; Detect undecorated items, eg during isearch into previously
- ;; ;; unexposed topics, and decorate "economically". Some
- ;; ;; undecorated stuff is often exposed, to reduce lag, but the
- ;; ;; item containing the cursor is decorated. We constrain
- ;; ;; recursion to avoid being trapped by unexpectedly undecoratable
- ;; ;; items.
- ;; (when (and (not recursing)
- ;; (not (allout-current-decorated-p))
- ;; (or (not (equal (allout-depth) 0))
- ;; (not allout-container-item-widget)))
- ;; (let ((buffer-undo-list t))
- ;; (allout-widgets-exposure-change-recorder
- ;; allout-recent-prefix-beginning allout-recent-prefix-end nil)
- ;; (allout-widgets-post-command-business 'recursing)))
- ;; Detect and rectify fouled outline structure - decorated item
- ;; not at beginning of line.
- (let ((this-widget (or (widget-at (point))
- ;; XXX we really should be checking across
- ;; edited span, not just point and point+1
- (and (not (eq (point) (point-max)))
- (widget-at (1+ (point))))))
- inserted-at)
- (save-excursion
- (if (and this-widget
- (goto-char (widget-get this-widget :from))
- (not (bolp)))
- (if (not
- (condition-case nil
- (yes-or-no-p
- (concat "Misplaced item won't be recognizable "
- " as part of outline - rectify? "))
- (quit nil)))
- (progn
- (if (allout-hidden-p (max (1- (point)) 1))
- (save-excursion
- (goto-char (max (1- (point)) 1))
- (allout-show-to-offshoot)))
- (allout-widgets-undecorate-item this-widget))
- ;; expose any hidden intervening items, so resulting
- ;; position is clear:
- (setq inserted-at (point))
- (allout-unprotected (insert-before-markers "\n"))
- (forward-char -1)
- ;; ensure the inserted newline is visible:
- (allout-flag-region inserted-at (1+ inserted-at) nil)
- (allout-widgets-post-command-business 'recursing)
- (message (concat "outline structure corrected - item"
- " moved to beginning of new line"))
- ;; preserve cursor position in some cases:
- (if (and inserted-at
- (> (point) inserted-at))
- (forward-char -1)))))))
- (error
- ;; zero work list so we don't get stuck futilely retrying.
- ;; error recording done by allout-widgets-hook-error-handler.
- (setq allout-widgets-changes-record nil))))
- ;;;_ , major change handlers:
- ;;;_ > allout-widgets-before-change-handler
- (defun allout-widgets-before-change-handler (beg end)
- "Business to be done before changes in a widgetized allout outline."
- ;; protect against unruly edits to structure:
- (cond
- (undo-in-progress (when (eq (get-text-property beg 'category)
- 'allout-icon-span-category)
- (save-excursion
- (goto-char beg)
- (let* ((item-widget (allout-get-item-widget)))
- (if item-widget
- (allout-widgets-exposure-undo-recorder
- item-widget))))))
- (inhibit-read-only t)
- ((not (and (boundp 'allout-mode) allout-mode)) t)
- ((equal this-command 'quoted-insert) t)
- ((not (text-property-any beg (if (equal end beg)
- (min (1+ beg) (point-max))
- end)
- 'field 'structure))
- t)
- ((yes-or-no-p "Unruly edit of outline structure - allow? ")
- (setq allout-widgets-unset-inhibit-read-only (not inhibit-read-only)
- inhibit-read-only t))
- (t
- ;; tell the allout-widgets-post-command-business to reestablish the hook:
- (setq allout-widgets-reenable-before-change-handler t)
- ;; and raise an error to prevent the edit (and disable the hook):
- (error "%s"
- (substitute-command-keys allout-structure-unruly-deletion-message)))))
- ;;;_ > allout-widgets-after-change-handler
- (defun allout-widgets-after-change-handler (_beg _end _prelength)
- "Reconcile what needs to be reconciled for allout widgets after edits."
- )
- ;;;_ > allout-current-decorated-p ()
- (defun allout-current-decorated-p ()
- "True if the current item is not decorated"
- (save-excursion
- (if (allout-back-to-current-heading)
- (if (> allout-recent-depth 0)
- (and (allout-get-item-widget) t)
- allout-container-item-widget))))
- ;;;_ > allout-widgets-hook-error-handler
- (defun allout-widgets-hook-error-handler (mode args)
- "Process errors which occurred in the course of command hook operation.
- We store a backtrace of the error information in the variable,
- `allout-widgets-last-hook-error', unset the error handlers, and
- reraise the error, so that processing continues to the
- encompassing condition-case."
- ;; first deconstruct special error environment so errors here propagate
- ;; to encompassing condition-case:
- (setq debugger 'debug
- debug-on-error nil
- debug-on-signal nil)
- (let* ((bt (with-output-to-string (backtrace)))
- (this "allout-widgets-hook-error-handler")
- (header
- (format "allout-widgets-last-hook-error stored, %s/%s %s %s"
- this mode args
- (format-time-string "%e-%b-%Y %r"))))
- ;; post to *Messages* then immediately replace with more compact notice:
- (message "%s" (setq allout-widgets-last-hook-error
- (format "%s:\n%s" header bt)))
- (message header) (sit-for allout-widgets-hook-error-post-time)
- ;; reraise the error, or one concerning this function if unexpected:
- (if (equal mode 'error)
- (apply 'signal args)
- (error "%s: unexpected mode, %s %s" this mode args))))
- ;;;_ > allout-widgets-changes-exceed-threshold-p ()
- (defun allout-widgets-adjusting-message (message)
- "Post MESSAGE when pending are likely to make a big enough delay.
- If posting of the MESSAGE is warranted and there already is a
- `current-message' in the minibuffer, the MESSAGE is appended to
- the current one, and the previously pending `current-message' is
- returned for later posting on completion.
- If posting of the MESSAGE is warranted, but no `current-message'
- is pending, then t is returned to indicate that case.
- If posting of the MESSAGE is not warranted, then nil is returned.
- See `allout-widgets-adjust-message-length-threshold',
- `allout-widgets-adjust-message-size-threshold' for message
- posting threshold criteria."
- (if (or (> (length allout-widgets-changes-record)
- allout-widgets-adjust-message-length-threshold)
- ;; for size, use distance from start of first to end of last:
- (let ((min (point-max))
- (max 0)
- first second)
- (mapc (function (lambda (entry)
- (if (eq :undone-exposure (car entry))
- nil
- (setq first (cadr entry)
- second (caddr entry))
- (if (< (min first second) min)
- (setq min (min first second)))
- (if (> (max first second) max)
- (setq max (max first second))))))
- allout-widgets-changes-record)
- (> (- max min) allout-widgets-adjust-message-size-threshold)))
- (let ((prior (current-message)))
- (message (if prior (concat prior " - " message) message))
- (or prior t))))
- ;;;_ > allout-widgets-changes-dispatcher ()
- (defun allout-widgets-changes-dispatcher ()
- "Dispatch CHANGES-RECORD items to respective widgets change processors."
- (if (not allout-widgets-mode-inhibit)
- (let* ((changes-record allout-widgets-changes-record)
- (changes-pending (and changes-record t))
- entry
- exposures
- additions
- deletions
- shifts)
- (when changes-pending
- (while changes-record
- (setq entry (pop changes-record))
- (case (car entry)
- (:exposed (push entry exposures))
- (:added (push entry additions))
- (:deleted (push entry deletions))
- (:shifted (push entry shifts))))
- (if exposures
- (allout-widgets-exposure-change-processor exposures))
- (if additions
- (allout-widgets-additions-processor additions))
- (if deletions
- (allout-widgets-deletions-processor deletions))
- (if shifts
- (allout-widgets-shifts-processor shifts))))
- (when (not (equal allout-widgets-mode-inhibit 'undecorated))
- (allout-widgets-undecorate-region (point-min)(point-max))
- (setq allout-widgets-mode-inhibit 'undecorated))))
- ;;;_ > allout-widgets-exposure-change-recorder (from to flag)
- (defun allout-widgets-exposure-change-recorder (from to flag)
- "Record allout exposure changes for tracking during post-command processing.
- Records changes in `allout-widgets-changes-record'."
- (push (list :exposed from to flag) allout-widgets-changes-record))
- ;;;_ > allout-widgets-exposure-change-processor (changes)
- (defun allout-widgets-exposure-change-processor (changes)
- "Widgetize and adjust item widgets tracking allout outline exposure changes.
- Generally invoked via `allout-exposure-change-functions'."
- (let ((changes (sort changes (function (lambda (this next)
- (< (cadr this) (cadr next))))))
- ;; have to distinguish between concealing and exposing so that, eg,
- ;; `allout-expose-topic's mix is handled properly.
- handled-expose
- covered
- deactivate-mark)
- (dolist (change changes)
- (let (handling
- (from (cadr change))
- bucket got
- (to (caddr change))
- (flag (cadddr change))
- parent)
- ;; swap from and to:
- (if (< to from) (setq bucket to
- to from
- from bucket))
- ;; have we already handled exposure changes in this region?
- (setq handling (if flag 'handled-conceal 'handled-expose)
- got (allout-range-overlaps from to (symbol-value handling))
- covered (car got))
- (set handling (cadr got))
- (when (not covered)
- (save-excursion
- (goto-char from)
- (cond
- ;; collapsing:
- (flag
- (allout-widgets-undecorate-region from to)
- (allout-beginning-of-current-line)
- (let ((widget (allout-get-item-widget)))
- (if (not widget)
- (allout-get-or-create-item-widget)
- (widget-apply widget :redecorate))))
- ;; expanding:
- (t
- (while (< (point) to)
- (allout-beginning-of-current-line)
- (setq parent (allout-get-item-widget))
- (if (not parent)
- (setq parent (allout-get-or-create-item-widget))
- (widget-apply parent :redecorate))
- (allout-next-visible-heading 1)
- (if (widget-get parent :has-subitems)
- (allout-redecorate-visible-subtree parent))
- (if (> (point) to)
- ;; subtree may be well beyond to - incorporate in ranges:
- (setq handled-expose
- (allout-range-overlaps from (point) handled-expose)
- covered (car handled-expose)
- handled-expose (cadr handled-expose)))
- (allout-next-visible-heading 1))))))))))
- ;;;_ > allout-widgets-additions-recorder (from to)
- (defun allout-widgets-additions-recorder (from to)
- "Record allout item additions for tracking during post-command processing.
- Intended for use on `allout-structure-added-functions'.
- FROM point at the start of the first new item and TO is point at the start
- of the last one.
- Records changes in `allout-widgets-changes-record'."
- (push (list :added from to) allout-widgets-changes-record))
- ;;;_ > allout-widgets-additions-processor (changes)
- (defun allout-widgets-additions-processor (changes)
- "Widgetize and adjust items tracking allout outline structure additions.
- Dispatched by `allout-widgets-post-command-business' in response to
- :added entries recorded by `allout-widgets-additions-recorder'."
- (save-excursion
- (let (handled
- covered)
- (dolist (change changes)
- (let ((from (cadr change))
- bucket
- (to (caddr change)))
- (if (< to from) (setq bucket to to from from bucket))
- ;; have we already handled exposure changes in this region?
- (setq handled (allout-range-overlaps from to handled)
- covered (car handled)
- handled (cadr handled))
- (when (not covered)
- (goto-char from)
- ;; Prior sibling and parent can both be affected.
- (if (allout-ascend)
- (allout-redecorate-visible-subtree
- (allout-get-or-create-item-widget 'redecorate)))
- (if (< (point) from)
- (goto-char from))
- (while (and (< (point) to) (not (eobp)))
- (allout-beginning-of-current-line)
- (allout-redecorate-visible-subtree
- (allout-get-or-create-item-widget))
- (allout-next-visible-heading 1))
- (if (> (point) to)
- ;; subtree may be well beyond to - incorporate in ranges:
- (setq handled (allout-range-overlaps from (point) handled)
- covered (car handled)
- handled (cadr handled)))))))))
- ;;;_ > allout-widgets-deletions-recorder (depth from)
- (defun allout-widgets-deletions-recorder (depth from)
- "Record allout item deletions for tracking during post-command processing.
- Intended for use on `allout-structure-deleted-functions'.
- DEPTH is the depth of the deleted subtree, and FROM is the point from which
- the subtree was deleted.
- Records changes in `allout-widgets-changes-record'."
- (push (list :deleted depth from) allout-widgets-changes-record))
- ;;;_ > allout-widgets-deletions-processor (changes)
- (defun allout-widgets-deletions-processor (changes)
- "Adjust items tracking allout outline structure deletions.
- Dispatched by `allout-widgets-post-command-business' in response to
- :deleted entries recorded by `allout-widgets-deletions-recorder'."
- (save-excursion
- (dolist (change changes)
- (let ((depth (cadr change))
- (from (caddr change)))
- (goto-char from)
- (when (allout-previous-visible-heading 1)
- (if (> depth 1)
- (allout-ascend-to-depth (1- depth)))
- (allout-redecorate-visible-subtree
- (allout-get-or-create-item-widget 'redecorate)))))))
- ;;;_ > allout-widgets-shifts-recorder (shifted-amount at)
- (defun allout-widgets-shifts-recorder (shifted-amount at)
- "Record outline subtree shifts for tracking during post-command processing.
- Intended for use on `allout-structure-shifted-functions'.
- SHIFTED-AMOUNT is the depth change and AT is the point at the start of the
- subtree that's been shifted.
- Records changes in `allout-widgets-changes-record'."
- (push (list :shifted shifted-amount at) allout-widgets-changes-record))
- ;;;_ > allout-widgets-shifts-processor (changes)
- (defun allout-widgets-shifts-processor (changes)
- "Widgetize and adjust items tracking allout outline structure additions.
- Dispatched by `allout-widgets-post-command-business' in response to
- :shifted entries recorded by `allout-widgets-shifts-recorder'."
- (save-excursion
- (dolist (change changes)
- (goto-char (caddr change))
- (allout-ascend)
- (allout-redecorate-visible-subtree))))
- ;;;_ > allout-widgets-after-copy-or-kill-function ()
- (defun allout-widgets-after-copy-or-kill-function ()
- "Do allout-widgets processing of text just placed in the kill ring.
- Intended for use on `allout-after-copy-or-kill-hook'."
- (if (car kill-ring)
- (setcar kill-ring (allout-widgets-undecorate-text (car kill-ring)))))
- ;;;_ > allout-widgets-after-undo-function ()
- (defun allout-widgets-after-undo-function ()
- "Do allout-widgets processing of text after an undo.
- Intended for use on `allout-post-undo-hook'."
- (save-excursion
- (if (allout-goto-prefix)
- (allout-redecorate-item (allout-get-or-create-item-widget)))))
- ;;;_ > allout-widgets-exposure-undo-recorder (widget from-state)
- (defun allout-widgets-exposure-undo-recorder (widget)
- "Record outline exposure undo for tracking during post-command processing.
- Intended for use by `allout-graphics-modification-handler'.
- WIDGET is the widget being changed.
- Records changes in `allout-widgets-changes-record'."
- ;; disregard the events if we're currently processing them.
- (if (not allout-undo-exposure-in-progress)
- (push widget allout-widgets-undo-exposure-record)))
- ;;;_ > allout-widgets-exposure-undo-processor ()
- (defun allout-widgets-exposure-undo-processor ()
- "Adjust items tracking undo of allout outline structure exposure.
- Dispatched by `allout-widgets-post-command-business' in response to
- :undone-exposure entries recorded by `allout-widgets-exposure-undo-recorder'."
- (let* ((allout-undo-exposure-in-progress t)
- ;; inhibit undo recording while twiddling exposure to track undo:
- (widgets allout-widgets-undo-exposure-record)
- widget-start-marker widget-end-marker
- from-state icon-start-point to-state
- handled covered)
- (setq allout-widgets-undo-exposure-record nil)
- (save-excursion
- (dolist (widget widgets)
- (setq widget-start-marker (widget-get widget :from)
- widget-end-marker (widget-get widget :to)
- from-state (widget-get widget :icon-state)
- icon-start-point (widget-apply widget :actual-position
- :icon-start)
- to-state (get-text-property icon-start-point
- :icon-state))
- (setq handled (allout-range-overlaps widget-start-marker
- widget-end-marker
- handled)
- covered (car handled)
- handled (cadr handled))
- (when (not covered)
- (goto-char (widget-get widget :from))
- (when (not (allout-hidden-p))
- ;; adjust actual exposure to that of to-state viz from-state
- (cond ((and (eq to-state 'closed) (eq from-state 'opened))
- (allout-hide-current-subtree)
- (allout-decorate-item-and-context widget))
- ((and (eq to-state 'opened) (eq from-state 'closed))
- (save-excursion
- (dolist
- (expose-to (allout-chart-exposure-contour-by-icon))
- (goto-char expose-to)
- (allout-show-to-offshoot)))))))))))
- ;;;_ > allout-chart-exposure-contour-by-icon (&optional from-depth)
- (defun allout-chart-exposure-contour-by-icon (&optional from-depth)
- "Return points of subtree items to which exposure should be extended.
- The qualifying items are ones with a widget icon that is in the closed or
- empty state, or items with undecorated subitems.
- The resulting list of points is in reverse order.
- Optional FROM-DEPTH is for internal use."
- ;; During internal recursion, we return a pair: (at-end . result)
- ;; Otherwise we just return the result.
- (let ((from-depth from-depth)
- start-point
- at-end level-depth
- this-widget
- got subgot)
- (if from-depth
- (setq level-depth (allout-depth))
- ;; at containing item:
- (setq start-point (point))
- (setq from-depth (allout-depth))
- (setq at-end (not (allout-next-heading))
- level-depth allout-recent-depth))
- ;; traverse the level, recursing on deeper levels:
- (while (and (not at-end)
- (> allout-recent-depth from-depth)
- (setq this-widget (allout-get-item-widget)))
- (if (< level-depth allout-recent-depth)
- ;; recurse:
- (progn
- (setq subgot (allout-chart-exposure-contour-by-icon level-depth)
- at-end (car subgot)
- subgot (cdr subgot))
- (if subgot (setq got (append subgot got))))
- ;; progress at this level:
- (when (memq (widget-get this-widget :icon-state) '(closed empty))
- (push (point) got)
- (allout-end-of-subtree))
- (setq at-end (not (allout-next-heading)))))
- ;; tailor result depending on whether or not we're a recursion:
- (if (not start-point)
- (cons at-end got)
- (goto-char start-point)
- got)))
- ;;;_ > allout-range-overlaps (from to ranges)
- (defun allout-range-overlaps (from to ranges)
- "Return a pair indicating overlap of FROM and TO subtree range in RANGES.
- First element of result indicates whether candidate range FROM, TO
- overlapped any of the existing ranges.
- Second element of result is a new version of RANGES incorporating the
- candidate range with overlaps consolidated.
- FROM and TO must be in increasing order, as must be the pairs in RANGES."
- ;; to append to the end: (rplacd next-to-last-cdr (list 'f))
- (let (new-ranges
- entry
- ;; the start of the range that includes the candidate from:
- included-from
- ;; the end of the range that includes the candidate to:
- included-to
- ;; the candidates were inserted:
- done)
- (while (and ranges (not done))
- (setq entry (car ranges)
- ranges (cdr ranges))
- (cond
- (included-from
- ;; some entry included the candidate from.
- (cond ((> (car entry) to)
- ;; current entry exceeds end of candidate range - done.
- (push (list included-from to) new-ranges)
- (push entry new-ranges)
- (setq included-to to
- done t))
- ((>= (cadr entry) to)
- ;; current entry includes end of candidate range - done.
- (push (list included-from (cadr entry)) new-ranges)
- (setq included-to (cadr entry)
- done t))
- ;; current entry contained in candidate range - ditch, continue:
- (t nil)))
- ((> (car entry) to)
- ;; current entry start exceeds candidate end - done, placed as new entry
- (push (list from to) new-ranges)
- (push entry new-ranges)
- (setq included-to to
- done t))
- ((>= (car entry) from)
- ;; current entry start is above candidate start, but not above
- ;; candidate end (by prior case).
- (setq included-from from)
- ;; now we have to check on whether this entry contains to, or continue:
- (when (>= (cadr entry) to)
- ;; current entry contains only candidate end - done:
- (push (list included-from (cadr entry)) new-ranges)
- (setq included-to (cadr entry)
- done t))
- ;; otherwise, we will continue to look for placement of candidate end.
- )
- ((>= (cadr entry) to)
- ;; current entry properly contains candidate range.
- (push entry new-ranges)
- (setq included-from (car entry)
- included-to (cadr entry)
- done t))
- ((>= (cadr entry) from)
- ;; current entry contains start of candidate range.
- (setq included-from (car entry)))
- (t
- ;; current entry is below the candidate range.
- (push entry new-ranges))))
- (cond ((and included-from included-to)
- ;; candidates placed.
- nil)
- ((not (or included-from included-to))
- ;; candidates found no place, must be at the end:
- (push (list from to) new-ranges))
- (included-from
- ;; candidate start placed but end not:
- (push (list included-from to) new-ranges))
- ;; might be included-to and not included-from, indicating new entry.
- )
- (setq new-ranges (nreverse new-ranges))
- (if ranges (setq new-ranges (append new-ranges ranges)))
- (list (if included-from t) new-ranges)))
- ;;;_ > allout-test-range-overlaps ()
- (defun allout-test-range-overlaps ()
- "`allout-range-overlaps' unit tests."
- (let* (ranges
- got
- (try (lambda (from to)
- (setq got (allout-range-overlaps from to ranges))
- (setq ranges (cadr got))
- got)))
- ;; ;; biggie:
- ;; (setq ranges nil)
- ;; ;; ~ .02 to .1 seconds for just repeated listing args instead of funcall
- ;; ;; ~ 13 seconds for doing repeated funcall
- ;; (message "time-trial: %s, resulting size %s"
- ;; (time-trial
- ;; '(let ((size 10000)
- ;; doing)
- ;; (dotimes (count size)
- ;; (setq doing (random size))
- ;; (funcall try doing (+ doing (random 5)))
- ;; ;;(list doing (+ doing (random 5)))
- ;; )))
- ;; (length ranges))
- ;; (sit-for 2)
- ;; fresh:
- (setq ranges nil)
- (assert (equal (funcall try 3 5) '(nil ((3 5)))))
- ;; add range at end:
- (assert (equal (funcall try 10 12) '(nil ((3 5) (10 12)))))
- ;; add range at beginning:
- (assert (equal (funcall try 1 2) '(nil ((1 2) (3 5) (10 12)))))
- ;; insert range somewhere in the middle:
- (assert (equal (funcall try 7 9) '(nil ((1 2) (3 5) (7 9) (10 12)))))
- ;; consolidate some:
- (assert (equal (funcall try 5 8) '(t ((1 2) (3 9) (10 12)))))
- ;; add more:
- (assert (equal (funcall try 15 17) '(nil ((1 2) (3 9) (10 12) (15 17)))))
- ;; add more:
- (assert (equal (funcall try 20 22)
- '(nil ((1 2) (3 9) (10 12) (15 17) (20 22)))))
- ;; encompass more:
- (assert (equal (funcall try 4 11) '(t ((1 2) (3 12) (15 17) (20 22)))))
- ;; encompass all:
- (assert (equal (funcall try 2 25) '(t ((1 25)))))
- ;; fresh slate:
- (setq ranges nil)
- (assert (equal (funcall try 20 25) '(nil ((20 25)))))
- (assert (equal (funcall try 30 35) '(nil ((20 25) (30 35)))))
- (assert (equal (funcall try 26 28) '(nil ((20 25) (26 28) (30 35)))))
- (assert (equal (funcall try 15 20) '(t ((15 25) (26 28) (30 35)))))
- (assert (equal (funcall try 10 30) '(t ((10 35)))))
- (assert (equal (funcall try 5 6) '(nil ((5 6) (10 35)))))
- (assert (equal (funcall try 2 100) '(t ((2 100)))))
- (setq ranges nil)
- ))
- ;;;_ > allout-widgetize-buffer (&optional doing)
- (defun allout-widgetize-buffer (&optional doing)
- "EXAMPLE FUNCTION. Widgetize items in buffer using allout-chart-subtree.
- We economize by just focusing on the first of local-maximum depth siblings.
- Optional DOING is for internal use - a chart of the current level, for
- recursive operation."
- (interactive)
- (if (not doing)
- (save-excursion
- (goto-char (point-min))
- ;; Construct the chart by scanning the siblings:
- (dolist (top-level-sibling (allout-chart-siblings))
- (goto-char top-level-sibling)
- (let ((subchart (allout-chart-subtree)))
- (if subchart
- (allout-widgetize-buffer subchart)))))
- ;; save-excursion was done on recursion entry, not necessary here.
- (let (have-sublists)
- (dolist (sibling doing)
- (when (listp sibling)
- (setq have-sublists t)
- (allout-widgetize-buffer sibling)))
- (when (and (not have-sublists) (not (widget-at (car doing))))
- (goto-char (car doing))
- (allout-get-or-create-item-widget)))))
- ;;;_ : Item widget and constructors
- ;;;_ $ allout-item-widget
- (define-widget 'allout-item-widget 'default
- "A widget presenting an allout outline item."
- 'button nil
- ;; widget-field-at respects this to get item if 'field is unused.
- ;; we don't use field to avoid collision with end-of-line, etc, on which
- ;; allout depends.
- 'real-field nil
- ;; data fields:
- ;; tailor the widget for a specific item
- :create 'allout-decorate-item-and-context
- :value-delete 'allout-widgets-undecorate-item
- ;; Not Yet Converted (from original, tree-widget stab)
- :expander 'allout-tree-event-dispatcher ; get children when nil :args
- :expander-p 'identity ; always engage the :expander
- :action 'allout-tree-widget-action
- ;; :notify "when item changes"
- ;; force decoration of item but not context, unless already done this tick:
- :redecorate 'allout-redecorate-item
- :last-decorated-tick nil
- ;; recognize the actual situation of the item's text:
- :parse-item 'allout-parse-item-at-point
- ;; decorate the entirety of the item, sans offspring:
- :decorate-item-span 'allout-decorate-item-span
- ;; decorate the various item elements:
- :decorate-guides 'allout-decorate-item-guides
- :decorate-icon 'allout-decorate-item-icon
- :decorate-cue 'allout-decorate-item-cue
- :decorate-body 'allout-decorate-item-body
- :actual-position 'allout-item-actual-position
- ;; Layout parameters:
- :is-container nil ; is this actually the encompassing file/connection?
- :from nil ; item beginning - marker
- :to nil ; item end - marker
- :span-overlay nil ; overlay by which actual position is determined
- ;; also serves as guide-end:
- :icon-start nil
- :icon-end nil
- :distinctive-start nil
- ;; also serves as cue-start:
- :distinctive-end nil
- ;; also serves as cue-end:
- :body-start nil
- :body-end nil
- :depth nil
- :has-subitems nil
- :was-has-subitems 'init
- :expanded nil
- :was-expanded 'init
- :brief nil
- :was-brief 'init
- :does-encrypt nil ; pending encryption when :is-encrypted false.
- :is-encrypted nil
- ;; the actual location of the item text:
- :location 'allout-item-location
- :button-keymap allout-item-icon-keymap ; XEmacs
- :keymap allout-item-icon-keymap ; Emacs
- ;; Element regions:
- :guides-span nil
- :icon-span nil
- :cue-span nil
- :bullet nil
- :was-bullet nil
- :body-span nil
- :body-brevity-p 'allout-body-brevity-p
- ;; :guide-column-flags indicate (in reverse order) whether or not the
- ;; item's ancestor at the depth corresponding to the column has a
- ;; subsequent sibling - ie, whether or not the corresponding column needs
- ;; a descender line to connect that ancestor with its sibling.
- :guide-column-flags nil
- :was-guide-column-flags 'init
- ;; ie, has subitems:
- :populous-p 'allout-item-populous-p
- :help-echo 'allout-tree-widget-help-echo
- )
- ;;;_ > allout-new-item-widget ()
- (defsubst allout-new-item-widget ()
- "create a new item widget, not yet situated anywhere."
- (if allout-widgets-maintain-tally
- ;; all the extra overhead is incurred only when doing the
- ;; maintenance, except the condition, which can't be avoided.
- (let ((widget (widget-convert 'allout-item-widget)))
- (puthash widget nil allout-widgets-tally)
- widget)
- (widget-convert 'allout-item-widget)))
- ;;;_ : Item decoration
- ;;;_ > allout-decorate-item-and-context (item-widget &optional redecorate
- ;;; blank-container parent)
- (defun allout-decorate-item-and-context (item-widget &optional redecorate
- blank-container _parent)
- "Create or adjust widget decorations for ITEM-WIDGET and neighbors at point.
- The neighbors include its siblings and parent.
- ITEM-WIDGET can be a created or converted `allout-item-widget'.
- If you're only trying to get or create a widget for an item, use
- `allout-get-or-create-item-widget'. If you have the item-widget, applying
- :redecorate will do the right thing.
- Optional BLANK-CONTAINER is for internal use. It is used to fabricate a
- container widget for an empty-bodied container, in the course of decorating
- a proper (non-container) item which starts at the beginning of the file.
- Optional REDECORATE causes redecoration of the item-widget and
- its siblings, even if already decorated in this cycle of the command loop.
- Optional PARENT, when provided, bypasses some navigation and computation
- necessary to obtain the parent of the items being processed.
- We return the item-widget corresponding to the item at point."
- (when (or redecorate
- (not (equal (widget-get item-widget :last-decorated-tick)
- allout-command-counter)))
- (let* ((allout-inhibit-body-modification-hook t)
- (was-modified (buffer-modified-p))
- (was-point (point))
- prefix-start
- (is-container (or blank-container
- (not (setq prefix-start (allout-goto-prefix)))
- (< was-point prefix-start)))
- ;; steady-point (set in two steps) is reliable across parent
- ;; widget-creation.
- (steady-point (progn (if is-container (goto-char 1))
- (point-marker)))
- (steady-point (progn (set-marker-insertion-type steady-point t)
- steady-point))
- (parent (and (not is-container)
- (allout-get-or-create-parent-widget)))
- successor-sibling
- doing-item
- reverse-siblings-chart
- (buffer-undo-list t))
- ;; At this point the parent is decorated and parent-flags indicate
- ;; its guide lines. We will iterate over the siblings according to a
- ;; chart we create at the start, and going from last to first so we
- ;; don't have to worry about text displacement caused by widgetizing.
- (if is-container
- (progn (widget-put item-widget :is-container t)
- (setq reverse-siblings-chart (list 1)))
- (goto-char (widget-apply parent :actual-position :from))
- (if (widget-get parent :is-container)
- ;; `allout-goto-prefix' will go to first non-container item:
- (allout-goto-prefix)
- (allout-next-heading))
- (setq reverse-siblings-chart (list allout-recent-prefix-beginning))
- (while (allout-next-sibling)
- (push allout-recent-prefix-beginning reverse-siblings-chart)))
- (dolist (doing-at reverse-siblings-chart)
- (goto-char doing-at)
- (when allout-widgets-track-decoration
- (sit-for 0))
- (setq doing-item (if (= doing-at steady-point)
- item-widget
- (or (allout-get-item-widget)
- (allout-new-item-widget))))
- (when (or redecorate (not (equal (widget-get doing-item
- :last-decorated-tick)
- allout-command-counter)))
- (widget-apply doing-item :parse-item t blank-container)
- (widget-apply doing-item :decorate-item-span)
- (widget-apply doing-item :decorate-guides
- parent (and successor-sibling t))
- (widget-apply doing-item :decorate-icon)
- (widget-apply doing-item :decorate-cue)
- (widget-apply doing-item :decorate-body)
- (widget-put doing-item :last-decorated-tick allout-command-counter))
- (setq successor-sibling doing-at))
- (set-buffer-modified-p was-modified)
- (goto-char steady-point)
- ;; must null the marker or the buffer gets clogged with impedance:
- (set-marker steady-point nil)
- item-widget)))
- ;;;_ > allout-redecorate-item (item)
- (defun allout-redecorate-item (item-widget)
- "Resituate ITEM-WIDGET decorations, disregarding context.
- Use this to redecorate only the item, when you know that its
- situation with respect to siblings, parent, and offspring is
- unchanged from its last decoration. Use
- `allout-decorate-item-and-context' instead to reassess and adjust
- relevant context, when suitable."
- (if (not (equal (widget-get item-widget :last-decorated-tick)
- allout-command-counter))
- (let ((was-modified (buffer-modified-p))
- (buffer-undo-list t))
- (widget-apply item-widget :parse-item)
- (widget-apply item-widget :decorate-guides)
- (widget-apply item-widget :decorate-icon)
- (widget-apply item-widget :decorate-cue)
- (widget-apply item-widget :decorate-body)
- (set-buffer-modified-p was-modified))))
- ;;;_ > allout-redecorate-visible-subtree (&optional parent-widget
- ;;; depth chart)
- (defun allout-redecorate-visible-subtree (&optional parent-widget depth chart)
- "Redecorate all visible items in subtree at point.
- Optional PARENT-WIDGET is for optimization, when the parent
- widget is already available.
- Optional DEPTH restricts the excursion depth of covered.
- Optional CHART is for internal recursion, to carry a chart of the
- target items.
- Point is left at the last sibling in the visible subtree."
- ;; using a treatment that takes care of all the siblings on a level, we
- ;; only need apply it to the first sibling on the level, and we can
- ;; collect and pass the parent of the lower levels to recursive calls as
- ;; we go.
- (let ((parent-widget
- (if (and parent-widget (widget-apply parent-widget
- :actual-position :from))
- (progn (goto-char (widget-apply parent-widget
- :actual-position :from))
- parent-widget)
- (let ((got (allout-get-item-widget)))
- (if got
- (allout-decorate-item-and-context got 'redecorate)
- (allout-get-or-create-item-widget 'redecorate)))))
- (pending-chart (or chart (allout-chart-subtree nil 'visible)))
- item-widget
- previous-sibling-point
- recent-sibling-point)
- (setq pending-chart (nreverse pending-chart))
- (dolist (sibling-point pending-chart)
- (cond ((integerp sibling-point)
- (when (not previous-sibling-point)
- (goto-char sibling-point)
- (if (setq item-widget (allout-get-item-widget nil))
- (allout-decorate-item-and-context item-widget 'redecorate
- nil parent-widget)
- (allout-get-or-create-item-widget)))
- (setq previous-sibling-point sibling-point
- recent-sibling-point sibling-point))
- ((listp sibling-point)
- (if (or (not depth)
- (> depth 1))
- (allout-redecorate-visible-subtree
- (if (not previous-sibling-point)
- ;; containment discontinuity - sigh
- parent-widget
- (allout-get-or-create-item-widget 'redecorate))
- (if depth (1- depth))
- sibling-point)))))
- (if (and recent-sibling-point (< (point) recent-sibling-point))
- (goto-char recent-sibling-point))))
- ;;;_ > allout-parse-item-at-point (item-widget &optional at-beginning
- ;;; blank-container)
- (defun allout-parse-item-at-point (item-widget &optional at-beginning
- blank-container)
- "Set widget ITEM-WIDGET layout parameters per item-at-point's actual layout.
- If optional AT-BEGINNING is t, then point is assumed to be at the start of
- the item prefix.
- If optional BLANK-CONTAINER is true, then the parameters of a container
- which has an empty body are set. (Though the body is blank, the object
- may have subitems.)"
- ;; Uncomment this sit-for to notice where decoration is happening:
- ;; (sit-for .1)
- (let* ((depth (allout-depth))
- (depth (if blank-container 0 depth))
- (is-container (or blank-container (zerop depth)))
- (does-encrypt (and (not is-container)
- (allout-encrypted-type-prefix)))
- (is-encrypted (and does-encrypt (allout-encrypted-topic-p)))
- (icon-end allout-recent-prefix-end)
- (icon-start (1- icon-end))
- body-start
- body-end
- has-subitems
- )
- (widget-put item-widget :depth depth)
- (if is-container
- (progn
- (widget-put item-widget :from (allout-set-boundary-marker
- :from (point-min)
- (widget-get item-widget :from)))
- (widget-put item-widget :icon-end nil)
- (widget-put item-widget :icon-start nil)
- (setq body-start (widget-put item-widget :body-start 1)))
- ;; not container:
- (widget-put item-widget :from (allout-set-boundary-marker
- :from (if at-beginning
- (point)
- allout-recent-prefix-beginning)
- (widget-get item-widget :from)))
- (widget-put item-widget :icon-start icon-start)
- (widget-put item-widget :icon-end icon-end)
- (when does-encrypt
- (widget-put item-widget :does-encrypt t)
- (widget-put item-widget :is-encrypted is-encrypted))
- ;; cue area:
- (setq body-start icon-end)
- (widget-put item-widget :bullet (allout-get-bullet))
- (if (equal (char-after body-start) ? )
- (setq body-start (1+ body-start)))
- (widget-put item-widget :body-start body-start)
- )
- ;; Both container and regular items:
- ;; :body-end (doesn't include a trailing blank line, if any) -
- (widget-put item-widget :body-end (setq body-end
- (if blank-container
- 1
- (allout-end-of-entry))))
- (widget-put item-widget :to (allout-set-boundary-marker
- :to (if blank-container
- (point-min)
- (or (allout-pre-next-prefix)
- (goto-char (point-max))))
- (widget-get item-widget :to)))
- (widget-put item-widget :has-subitems
- (setq has-subitems
- (and
- ;; has a subsequent item:
- (not (= body-end (point-max)))
- ;; subsequent item is deeper:
- (< depth (allout-recent-depth)))))
- ;; note :expanded - true if widget item's content is currently visible?
- (widget-put item-widget :expanded
- (and has-subitems
- ;; subsequent item is or isn't visible:
- (save-excursion
- (goto-char allout-recent-prefix-beginning)
- (not (allout-hidden-p)))))))
- ;;;_ > allout-set-boundary-marker (boundary position &optional current-marker)
- (defun allout-set-boundary-marker (_boundary position &optional current-marker)
- "Set or create item widget BOUNDARY type marker at POSITION.
- Optional CURRENT-MARKER is the marker currently being used for
- the boundary, if any.
- BOUNDARY type is either :from or :to, determining the marker insertion type."
- (if (not position) (setq position (point)))
- (if current-marker
- (set-marker current-marker position)
- (let ((marker (make-marker)))
- ;; XXX dang - would like for :from boundary to advance after inserted
- ;; text, but that would omit new header prefixes when allout
- ;; relevels, etc. this competes with ad-hoc edits, which would
- ;; better be omitted
- (set-marker-insertion-type marker nil)
- (set-marker marker position))))
- ;;;_ > allout-decorate-item-span (item-widget)
- (defun allout-decorate-item-span (item-widget)
- "Equip the item with a span, as an entirety.
- This span is implemented so it can be used to detect displacement
- of the widget in absolute terms, and provides an offset bias for
- the various element spans."
- (if (and (widget-get item-widget :is-container)
- ;; the only case where the span could be empty.
- (eq (widget-get item-widget :from)
- (widget-get item-widget :to)))
- nil
- (allout-item-span item-widget
- (widget-get item-widget :from)
- (widget-get item-widget :to))))
- ;;;_ > allout-decorate-item-guides (item-widget
- ;;; &optional parent-widget has-successor)
- (defun allout-decorate-item-guides (item-widget
- &optional parent-widget has-successor)
- "Add ITEM-WIDGET guide icon-prefix descender and connector text properties.
- Optional arguments provide context for deriving the guides.
- In their absence, the current guide column flags are used.
- Optional PARENT-WIDGET is the widget for the item's parent item.
- Optional HAS-SUCCESSOR is true if the item is followed by a sibling.
- We also hide the header-prefix string.
- Guides are established according to the item-widget's :guide-column-flags,
- when different than :was-guide-column-flags. Changing that property and
- reapplying this method will rectify the glyphs."
- (when (not (widget-get item-widget :is-container))
- (let* ((depth (widget-get item-widget :depth))
- ;; (parent-depth (and parent-widget
- ;; (widget-get parent-widget :depth)))
- (parent-flags (and parent-widget
- (widget-get parent-widget :guide-column-flags)))
- (parent-flags-depth (length parent-flags))
- (extender-length (- depth (+ parent-flags-depth 2)))
- (flags (or (and (> depth 1)
- parent-widget
- (widget-put item-widget :guide-column-flags
- (append (list has-successor)
- (if (< 0 extender-length)
- (make-list extender-length
- '-))
- parent-flags)))
- (widget-get item-widget :guide-column-flags)))
- (was-flags (widget-get item-widget :was-guide-column-flags))
- (guides-start (widget-get item-widget :from))
- (guides-end (widget-get item-widget :icon-start))
- (position guides-start)
- (increment (length allout-header-prefix))
- reverse-flags
- guide-name
- extenders
- (inhibit-read-only t))
- (when (not (equal was-flags flags))
- (setq reverse-flags (reverse flags))
- (while reverse-flags
- (setq guide-name
- (cond ((null (cdr reverse-flags))
- (if (car reverse-flags)
- 'mid-connector
- 'end-connector))
- ((eq (car reverse-flags) '-)
- ;; accumulate extenders tally, to be painted on next
- ;; non-extender flag, according to the flag type.
- (setq extenders (1+ (or extenders 0)))
- nil)
- ((car reverse-flags)
- 'through-descender)
- (t 'skip-descender)))
- (when guide-name
- (put-text-property position (setq position (+ position increment))
- 'display (allout-fetch-icon-image guide-name))
- (if (> increment 1) (setq increment 1))
- (when extenders
- ;; paint extenders after a connector, else leave spaces.
- (dotimes (i extenders)
- (put-text-property
- position (setq position (1+ position))
- 'display (allout-fetch-icon-image
- (if (memq guide-name '(mid-connector end-connector))
- 'extender-connector
- 'skip-descender))))
- (setq extenders nil)))
- (setq reverse-flags (cdr reverse-flags)))
- (widget-put item-widget :was-guide-column-flags flags))
- (allout-item-element-span-is item-widget :guides-span
- guides-start guides-end))))
- ;;;_ > allout-decorate-item-icon (item-widget)
- (defun allout-decorate-item-icon (item-widget)
- "Add item icon glyph and distinctive bullet text properties to ITEM-WIDGET."
- (when (not (widget-get item-widget :is-container))
- (let* ((icon-start (widget-get item-widget :icon-start))
- (icon-end (widget-get item-widget :icon-end))
- (bullet (widget-get item-widget :bullet))
- (use-bullet bullet)
- (was-bullet (widget-get item-widget :was-bullet))
- (distinctive (allout-distinctive-bullet bullet))
- (distinctive-start (widget-get item-widget :distinctive-start))
- (distinctive-end (widget-get item-widget :distinctive-end))
- (does-encrypt (widget-get item-widget :does-encrypt))
- (is-encrypted (and does-encrypt (widget-get item-widget
- :is-encrypted)))
- (expanded (widget-get item-widget :expanded))
- (has-subitems (widget-get item-widget :has-subitems))
- (inhibit-read-only t)
- icon-state)
- (when (not (and (equal (widget-get item-widget :was-expanded) expanded)
- (equal (widget-get item-widget :was-has-subitems)
- has-subitems)
- (equal (widget-get item-widget :was-does-encrypt)
- does-encrypt)
- (equal (widget-get item-widget :was-is-encrypted)
- is-encrypted)))
- (setq icon-state
- (cond (does-encrypt (if is-encrypted
- 'locked-encrypted
- 'unlocked-encrypted))
- (expanded 'opened)
- (has-subitems 'closed)
- (t 'empty)))
- (put-text-property icon-start (1+ icon-start)
- 'display (allout-fetch-icon-image icon-state))
- (widget-put item-widget :was-expanded expanded)
- (widget-put item-widget :was-has-subitems has-subitems)
- (widget-put item-widget :was-does-encrypt does-encrypt)
- (widget-put item-widget :was-is-encrypted is-encrypted)
- ;; preserve as a widget property to track last known:
- (widget-put item-widget :icon-state icon-state)
- ;; preserve as a text property to track undo:
- (put-text-property icon-start icon-end :icon-state icon-state))
- (allout-item-element-span-is item-widget :icon-span
- icon-start icon-end)
- (when (not (string= was-bullet bullet))
- (cond ((not distinctive)
- ;; XXX we strip the prior properties without even checking if
- ;; the prior bullet was distinctive, because the widget
- ;; provisions to convey that info is disappearing, sigh.
- (remove-text-properties icon-end (1+ icon-end) '(display))
- (setq distinctive-start icon-end distinctive-end icon-end)
- (widget-put item-widget :distinctive-start distinctive-start)
- (widget-put item-widget :distinctive-end distinctive-end))
- ((not (string= bullet allout-numbered-bullet))
- (setq distinctive-start icon-end distinctive-end (+ icon-end 1)))
- (does-encrypt
- (setq distinctive-start icon-end distinctive-end (+ icon-end 1)))
- (t
- (goto-char icon-end)
- (looking-at "[0-9]+")
- (setq use-bullet (buffer-substring icon-end (match-end 0)))
- (setq distinctive-start icon-end
- distinctive-end (match-end 0))))
- (put-text-property distinctive-start distinctive-end 'display
- use-bullet)
- (widget-put item-widget :was-bullet bullet)
- (widget-put item-widget :distinctive-start distinctive-start)
- (widget-put item-widget :distinctive-end distinctive-end)))))
- ;;;_ > allout-decorate-item-cue (item-widget)
- (defun allout-decorate-item-cue (item-widget)
- "Incorporate space between bullet icon and body to the ITEM-WIDGET."
- ;; NOTE: most of the cue-area
- (when (not (widget-get item-widget :is-container))
- (let* ((cue-start (or (widget-get item-widget :distinctive-end)
- (widget-get item-widget :icon-end)))
- (body-start (widget-get item-widget :body-start))
- ;(expanded (widget-get item-widget :expanded))
- ;(has-subitems (widget-get item-widget :has-subitems))
- (inhibit-read-only t))
- (allout-item-element-span-is item-widget :cue-span cue-start body-start)
- (put-text-property (1- body-start) body-start 'rear-nonsticky t))))
- ;;;_ > allout-decorate-item-body (item-widget &optional force)
- (defun allout-decorate-item-body (item-widget &optional force)
- "Incorporate item body text as part the ITEM-WIDGET.
- Optional FORCE means force reassignment of the region property."
- (let* ((allout-inhibit-body-modification-hook t)
- (body-start (widget-get item-widget :body-start))
- (body-end (widget-get item-widget :body-end))
- (inhibit-read-only t))
- (allout-item-element-span-is item-widget :body-span
- body-start (min (1+ body-end) (point-max))
- force)))
- ;;;_ > allout-item-actual-position (item-widget field)
- (defun allout-item-actual-position (item-widget field)
- "Return ITEM-WIDGET FIELD position taking item displacement into account."
- ;; The item's sub-element positions (:icon-end, :body-start, etc) are
- ;; accurate when the item is parsed, but some offsets from the start
- ;; drift with text added in the body.
- ;;
- ;; Rather than reparse an item with every change (inefficient), or derive
- ;; every position from a distinct field marker/overlay (prohibitive as
- ;; the number of items grows), we use the displacement tracking of the
- ;; :span-overlay's markers, against the registered :from or :body-end
- ;; (depending on whether the requested field value is before or after the
- ;; item body), to bias the registered values.
- ;;
- ;; This is not necessary/useful when the item is being decorated, because
- ;; that always must be preceded by a fresh item parse.
- (if (not (eq field :body-end))
- (widget-get item-widget :from)
- (let* ((span-overlay (widget-get item-widget :span-overlay))
- (body-end-position (widget-get item-widget :body-end))
- (ref-marker-position (and span-overlay
- (overlay-end span-overlay)))
- (offset (and body-end-position span-overlay
- (- (or ref-marker-position 0)
- body-end-position))))
- (+ (widget-get item-widget field) (or offset 0)))))
- ;;;_ : Item undecoration
- ;;;_ > allout-widgets-undecorate-region (start end)
- (defun allout-widgets-undecorate-region (start end)
- "Eliminate widgets and decorations for all items in region from START to END."
- (let ((next start)
- widget)
- (save-excursion
- (goto-char start)
- (while (< (setq next (next-single-char-property-change next
- 'display
- (current-buffer)
- end))
- end)
- (goto-char next)
- (when (setq widget (allout-get-item-widget))
- ;; if the next-property/overly progression got us to a widget:
- (allout-widgets-undecorate-item widget t))))))
- ;;;_ > allout-widgets-undecorate-text (text)
- (defun allout-widgets-undecorate-text (text)
- "Eliminate widgets and decorations for all items in TEXT."
- (remove-text-properties 0 (length text)
- '(display nil :icon-state nil rear-nonsticky nil
- category nil button nil field nil)
- text)
- text)
- ;;;_ > allout-widgets-undecorate-item (item-widget &optional no-expose)
- (defun allout-widgets-undecorate-item (item-widget &optional no-expose)
- "Remove widget decorations from ITEM-WIDGET.
- Any concealed content head lines and item body is exposed, unless
- optional NO-EXPOSE is non-nil."
- (let ((from (widget-get item-widget :from))
- (to (widget-get item-widget :to))
- (text-properties-to-remove '(display nil
- :icon-state nil
- rear-nonsticky nil
- category nil
- button nil
- field nil))
- (span-overlay (widget-get item-widget :span-overlay))
- (button-overlay (widget-get item-widget :button))
- (was-modified (buffer-modified-p))
- (buffer-undo-list t)
- (inhibit-read-only t))
- (if (not no-expose)
- (allout-flag-region from to nil))
- (allout-unprotected
- (remove-text-properties from to text-properties-to-remove))
- (when span-overlay
- (delete-overlay span-overlay) (widget-put item-widget :span-overlay nil))
- (when button-overlay
- (delete-overlay button-overlay) (widget-put item-widget :button nil))
- (set-marker from nil)
- (set-marker to nil)
- (if (not was-modified)
- (set-buffer-modified-p nil))))
- ;;;_ : Item decoration support
- ;;;_ > allout-item-span (item-widget &optional start end)
- (defun allout-item-span (item-widget &optional start end)
- "Return or register the location of an ITEM-WIDGET's actual START and END.
- If START and END are not passed in, return either a dotted pair
- of the current span, if established, or nil if not yet set.
- When the START and END are passed, return the distance that the
- start of the item moved. We return 0 if the span was not
- previously established or is not moved."
- (let ((overlay (widget-get item-widget :span-overlay)))
- (cond ((not overlay) (when start
- (setq overlay (make-overlay start end nil t nil))
- (overlay-put overlay 'button item-widget)
- (overlay-put overlay 'evaporate t)
- (widget-put item-widget :span-overlay overlay)
- t))
- ;; report:
- ((not start) (cons (overlay-start overlay) (overlay-end overlay)))
- ;; move:
- ((or (not (equal (overlay-start overlay) start))
- (not (equal (overlay-end overlay) end)))
- (move-overlay overlay start end)
- t)
- ;; specified span already set:
- (t nil))))
- ;;;_ > allout-item-element-span-is (item-widget element
- ;;; &optional start end force)
- (defun allout-item-element-span-is (item-widget element
- &optional start end force)
- "Return or register the location of the indicated ITEM-WIDGET ELEMENT.
- ELEMENT is one of :guides-span, :icon-span, :cue-span, or :body-span.
- When optional START is specified, optional END must also be.
- START and END are the actual bounds of the region, if provided.
- If START and END are not passed in, we return either a dotted
- pair of the current span, if established, or nil if not yet set.
- When the START and END are passed, we return t if the region
- changed or nil if not.
- Optional FORCE means force assignment of the region's text
- property, even if it's already set."
- (let ((span (widget-get item-widget element)))
- (cond ((or (not span) force)
- (when start
- (widget-put item-widget element (cons start end))
- (put-text-property start end 'category
- (cdr (assoc element
- allout-span-to-category)))
- t))
- ;; report:
- ((not start) span)
- ;; move if necessary:
- ((not (and (eq (car span) start)
- (eq (cdr span) end)))
- (widget-put item-widget element span)
- t)
- ;; specified span already set:
- (t nil))))
- ;;;_ : Item widget retrieval (/ high-level creation):
- ;;;_ > allout-get-item-widget (&optional container)
- (defun allout-get-item-widget (&optional container)
- "Return the widget for the item at point, or nil if no widget yet exists.
- Point must be situated *before* the start of the target item's
- body, so we don't get an existing containing item when we're in
- the process of creating an item in the middle of another.
- Optional CONTAINER is used to obtain the container item."
- (if (or container (zerop (allout-depth)))
- allout-container-item-widget
- ;; allout-recent-* are calibrated by (allout-depth) if we got here.
- (let ((got (widget-at allout-recent-prefix-beginning)))
- (if (and got (listp got))
- (if (marker-position (widget-get got :from))
- (and
- (>= (point) (widget-apply got :actual-position :from))
- (<= (point) (widget-apply got :actual-position :body-start))
- got)
- ;; a wacky residual item - undecorate and disregard:
- (allout-widgets-undecorate-item got)
- nil)))))
- ;;;_ > allout-get-or-create-item-widget (&optional redecorate blank-container)
- (defun allout-get-or-create-item-widget (&optional redecorate blank-container)
- "Return a widget for the item at point, creating the widget if necessary.
- When creating a widget, we assume there has been a context change
- and decorate its siblings and parent, as well.
- Optional BLANK-CONTAINER is for internal use, to fabricate a
- meta-container item with an empty body when the first proper
- \(non-container) item starts at the beginning of the file.
- Optional REDECORATE, if non-nil, means to redecorate the widget
- if it already exists."
- (let ((widget (allout-get-item-widget blank-container))
- (buffer-undo-list t))
- (cond (widget (if redecorate
- (allout-redecorate-item widget))
- widget)
- ((or blank-container (zerop (allout-depth)))
- (or allout-container-item-widget
- (setq allout-container-item-widget
- (allout-decorate-item-and-context
- (widget-convert 'allout-item-widget)
- nil blank-container))))
- ;; create a widget for a regular/non-container item:
- (t (allout-decorate-item-and-context (widget-convert
- 'allout-item-widget))))))
- ;;;_ > allout-get-or-create-parent-widget (&optional redecorate)
- (defun allout-get-or-create-parent-widget (&optional redecorate)
- "Return widget for parent of item at point, decorating it if necessary.
- We return the container widget if we're above the first proper item in the
- file.
- Optional REDECORATE, if non-nil, means to redecorate the widget if it
- already exists.
- Point will wind up positioned on the beginning of the parent or beginning
- of the buffer."
- ;; use existing widget, if there, else establish it
- (if (or (bobp) (and (not (allout-ascend))
- (looking-at-p allout-regexp)))
- (allout-get-or-create-item-widget redecorate 'blank-container)
- (allout-get-or-create-item-widget redecorate)))
- ;;;_ : X- Item ancillaries
- ;;;_ >X allout-body-modification-handler (beg end)
- (defun allout-body-modification-handler (_beg _end)
- "Do routine processing of body text before and after modification.
- Operation is inhibited by `allout-inhibit-body-modification-handler'."
- ;; The primary duties are:
- ;;
- ;; - marking of escaped prefix-like text for delayed cleanup of escapes
- ;; - removal and replacement of the settings
- ;; - maintenance of beginning-of-line guide lines
- ;;
- ;; ?? Escapes removal (before changes) is not done when edits span multiple
- ;; items, recognizing that item structure is being preserved, including
- ;; escaping of item-prefix-like text within bodies. See
- ;; `allout-before-modification-handler' and
- ;; `allout-inhibit-body-modification-handler'.
- ;;
- ;; Adds the overlay to the `allout-unresolved-body-mod-workhash' during
- ;; before-change operation, and removes from that list during after-change
- ;; operation.
- (cond (allout-inhibit-body-modification-hook nil)))
- ;;;_ >X allout-graphics-modification-handler (beg end)
- (defun allout-graphics-modification-handler (beg _end)
- "Protect against incoherent deletion of decoration graphics.
- Deletes allowed only when `inhibit-read-only' is t."
- (cond
- (undo-in-progress (when (eq (get-text-property beg 'category)
- 'allout-icon-span-category)
- (save-excursion
- (goto-char beg)
- (let* ((item-widget (allout-get-item-widget)))
- (if item-widget
- (allout-widgets-exposure-undo-recorder
- item-widget))))))
- (inhibit-read-only t)
- ((not (and (boundp 'allout-mode) allout-mode)) t)
- ((equal this-command 'quoted-insert) t)
- ((yes-or-no-p "Unruly edit of outline structure - allow? ")
- (setq allout-widgets-unset-inhibit-read-only (not inhibit-read-only)
- inhibit-read-only t))
- (t (error "%s"
- (substitute-command-keys allout-structure-unruly-deletion-message)))))
- ;;;_ > allout-item-icon-key-handler ()
- (defun allout-item-icon-key-handler ()
- "Catchall handling of key bindings in item icon/cue hot-spots.
- Applies `allout-hotspot-key-handler' and calls the result, if any, as an
- interactive command."
- (interactive)
- (let* ((mapped-binding (allout-hotspot-key-handler)))
- (when mapped-binding
- (call-interactively mapped-binding))))
- ;;;_ : Status
- ;;;_ . allout-item-location (item-widget)
- (defun allout-item-location (item-widget)
- "Location of the start of the item's text."
- (overlay-start (widget-get item-widget :span-overlay)))
- ;;;_ : Icon management
- ;;;_ > allout-fetch-icon-image (name)
- (defun allout-fetch-icon-image (name)
- "Fetch allout icon for symbol NAME.
- We use a caching strategy, so the caller doesn't need to do so."
- (let* ((types allout-widgets-icon-types)
- (use-dir (if (equal (allout-frame-property nil 'background-mode)
- 'light)
- allout-widgets-icons-light-subdir
- allout-widgets-icons-dark-subdir))
- (key (list name use-dir))
- (got (assoc key allout-widgets-icons-cache)))
- (if got
- ;; display system shows only first of subsequent adjacent
- ;; `eq'-identical repeats - use copies to avoid this problem.
- (allout-widgets-copy-list (cadr got))
- (while (and types (not got))
- (setq got
- (allout-find-image
- (list (append (list :type (car types)
- :file (concat use-dir
- (symbol-name name)
- "." (symbol-name
- (car types))))
- (if (featurep 'xemacs)
- allout-widgets-item-image-properties-xemacs
- allout-widgets-item-image-properties-emacs)
- ))))
- (setq types (cdr types)))
- (if got
- (push (list key got) allout-widgets-icons-cache))
- got)))
- ;;;_ : Miscellaneous
- ;;;_ > allout-elapsed-time-seconds (time-value time-value)
- (defun allout-elapsed-time-seconds (end start)
- "Return seconds between START/END time values."
- (let ((elapsed (time-subtract end start)))
- (float-time elapsed)))
- ;;;_ > allout-frame-property (frame property)
- (defalias 'allout-frame-property
- (cond ((fboundp 'frame-parameter)
- 'frame-parameter)
- ((fboundp 'frame-property)
- 'frame-property)
- (t nil)))
- ;;;_ > allout-find-image (specs)
- (defalias 'allout-find-image
- (if (fboundp 'find-image)
- 'find-image
- nil) ; aka, not-yet-implemented for xemacs.
- )
- ;;;_ > allout-widgets-copy-list (list)
- (defun allout-widgets-copy-list (list)
- ;; duplicated from cl.el 'copy-list' as of 2008-08-17
- "Return a copy of LIST, which may be a dotted list.
- The elements of LIST are not copied, just the list structure itself."
- (if (consp list)
- (let ((res nil))
- (while (consp list) (push (pop list) res))
- (prog1 (nreverse res) (setcdr res list)))
- (car list)))
- ;;;_ . allout-widgets-count-buttons-in-region (start end)
- (defun allout-widgets-count-buttons-in-region (start end)
- "Debugging/diagnostic tool - count overlays with `button' property in region."
- (interactive "r")
- (setq start (or start (point-min))
- end (or end (point-max)))
- (if (> start end) (let ((interim start)) (setq start end end interim)))
- (let ((button-overlays (delq nil
- (mapcar (function (lambda (o)
- (if (overlay-get o 'button)
- o)))
- (overlays-in start end)))))
- (length button-overlays)))
- ;;;_ : Run unit tests:
- (defun allout-widgets-run-unit-tests ()
- (message "Running allout-widget tests...")
- (allout-test-range-overlaps)
- (message "Running allout-widget tests... Done.")
- (sit-for .5))
- (when allout-widgets-run-unit-tests-on-load
- (allout-widgets-run-unit-tests))
- ;;;_ : provide
- (provide 'allout-widgets)
- ;;;_. Local emacs vars.
- ;;;_ , Local variables:
- ;;;_ , allout-layout: (-1 : 0)
- ;;;_ , End:
|