1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422 |
- ;; allout-widgets.el --- Visually highlight allout outline structure.
- ;; Copyright (C) 2005-2012 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
- ;;;###autoload
- (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 iff `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. Specifically:
- '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-hook
- 'allout-widgets-exposure-change-recorder nil 'local)
- (add-hook 'allout-structure-added-hook
- 'allout-widgets-additions-recorder nil 'local)
- (add-hook 'allout-structure-deleted-hook
- 'allout-widgets-deletions-recorder nil 'local)
- (add-hook 'allout-structure-shifted-hook
- '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-hook
- 'allout-widgets-exposure-change-recorder 'local)
- (remove-hook 'allout-structure-added-hook
- 'allout-widgets-additions-recorder 'local)
- (remove-hook 'allout-structure-deleted-hook
- 'allout-widgets-deletions-recorder 'local)
- (remove-hook 'allout-structure-shifted-hook
- '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 disable 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 failure
- (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 err
- (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
- (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" (current-time)))))
- ;; 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-hook'."
- (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
- handled-conceal
- 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-hook'.
- 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-hook'.
- 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-hook'.
- 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 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)
- ;; (random t)
- ;; (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)))
- parent-flags parent-depth
- successor-sibling
- body
- doing-item
- sub-item-widget
- depth
- 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 depth (allout-recent-depth))
- (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
- previous-sibling
- 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
- bullet
- has-subitems
- (contents-depth (1+ depth))
- )
- (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 (setq 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 (setq contents-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 iff 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 paint-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))
- (body-text-end 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))
- was-start was-end
- changed)
- (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 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
- (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 (triple)
- (defun allout-elapsed-time-seconds (end start)
- "Return seconds between `current-time' style time START/END triples."
- (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:
|