1 ;;; kvspec.el --- Koutline view specification.
3 ;; Copyright (C) 1995, 2006 Free Software Foundation, Inc.
4 ;; Developed with support from Motorola Inc.
6 ;; Author: Bob Weiner, Brown U.
7 ;; Maintainer: Mats Lidell <matsl@contactor.se>
8 ;; Keywords: outlines, wp
10 ;; This file is part of GNU Hyperbole.
12 ;; GNU Hyperbole is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 3, or (at
15 ;; your option) any later version.
17 ;; GNU Hyperbole is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
29 ;;; Koutliner view specs
30 ;; + means support code has been written already.
32 ;; + all: Show all lines of cells and all cells in the outline.
33 ;; + blank: Blank lines are on.
35 ;; + cutoff: Show only NUM lines per cell, 0 = all
36 ;; c - set default cutoff lines
37 ;; cNUM - set cutoff lines to NUM
38 ;; descend: Only entries below this entry
39 ;; + elide: Ellipses are on.
41 ;; filter: Regexp or filter program to select entries for view,
42 ;; off=select non-matching entries
43 ;; glue: Freeze any group of entries selected to stay at top of
44 ;; window, off=freeze those not-in-group.
45 ;; include: Include an entry referenced by a link.
46 ;; + level: Some levels are hidden.
47 ;; l - set default level clipping
48 ;; lNUM - set level clipping to NUM
49 ;; name: Display leading names within cells.
51 ;; + number: Cell numbers are on
52 ;; n - set default labels
53 ;; n0 - display idstamp labels
54 ;; n1 - display alpha labels
55 ;; n2 - display partial alpha labels
56 ;; n. - display legal labels
57 ;; n* - display star labels
58 ;; n~ - turn off labels
59 ;; rest: Only following cells.
60 ;; synthesize: Use a named generator function to generate entries for
62 ;; view: Turn koutliner view mode on. Standard insertion keys then
63 ;; can be used for browsing and view setting.
69 ;;; Other required Elisp libraries
78 (defvar kvspec:current nil
79 "String that represents the current view spec.
80 It is local to each koutline. Nil value means it has not been set yet.")
86 (defun kvspec:activate (&optional view-spec)
87 "Activate optional VIEW-SPEC or existing view spec in the current koutline.
88 VIEW-SPEC is a string or t, which means recompute the current view spec. See
89 <${hyperb:dir}/kotl/EXAMPLE.kotl, 2b17=048> for details on valid view specs."
90 (interactive (list (read-string "Set view spec: " kvspec:current)))
92 (if (or (equal view-spec "") (equal view-spec kvspec:current))
95 (kvspec:update view-spec)
98 (defun kvspec:initialize ()
99 "Ensure that view spec settings will be local to the current buffer."
100 (if (and (fboundp 'local-variable-p)
101 (local-variable-p 'kvspec:current (current-buffer)))
103 (make-local-variable 'kvspec:current)
104 (make-local-variable 'kvspec:string)))
106 (defun kvspec:levels-to-show (levels-to-keep)
107 "Hide all cells in outline at levels deeper than LEVELS-TO-KEEP (a number).
108 Shows any hidden cells within LEVELS-TO-KEEP. 1 is the first level. 0 means
109 display all levels of cells."
110 (if (null levels-to-keep)
112 (read-from-minibuffer "Show cells down to level (0 = show all levels): "
114 (setq levels-to-keep (prefix-numeric-value levels-to-keep))
115 (if (< levels-to-keep 0)
116 (error "(kvspec:levels-to-show): Must display at least one level."))
118 (function (lambda (kview)
119 (if (/= (kcell-view:level) levels-to-keep)
120 (kotl-mode:show-tree)
121 (kotl-mode:hide-subtree)
122 ;; Move to last cell in hidden subtree, to skip further
123 ;; processing of these cells.
124 (if (kcell-view:next t)
125 (kcell-view:previous)
126 (goto-char (point-max))))))
128 (kview:set-attr kview 'levels-to-show levels-to-keep))
130 (defun kvspec:show-lines-per-cell (num)
131 "Show NUM lines per cell."
132 (if (and (integerp num) (>= num 0))
134 (error "(kvspec:show-lines-per-cell): Invalid lines per cell, '%d'" num))
135 (kview:set-attr kview 'lines-to-show num)
136 (let (start end count)
138 ;; Show all lines in cells.
142 ;; Use free variable label-sep-len bound in kview:map-tree for
144 (setq start (goto-char (kcell-view:start nil label-sep-len))
145 end (kcell-view:end-contents))
146 ;; Show all lines in cell.
147 (subst-char-in-region start end ?\r ?\n t)))
149 ;; Show NUM lines in cells.
153 ;; Use free variable label-sep-len bound in kview:map-tree for speed.
154 (setq start (goto-char (kcell-view:start nil label-sep-len))
155 end (kcell-view:end-contents)
157 ;; Hide all lines in cell.
158 (subst-char-in-region start end ?\n ?\r t)
159 ;; Expand num - 1 newlines to show num lines.
160 (while (and (> count 0) (search-forward "\r" end t))
161 (replace-match "\n") (setq count (1- count)))))
164 (defun kvspec:toggle-blank-lines ()
165 "Toggle blank lines between cells on or off."
168 (if (string-match "b" kvspec:current)
169 (hypb:replace-match-string "b" kvspec:current "" t)
170 (concat "b" kvspec:current)))
172 (kvspec:update-modeline))
174 (defun kvspec:update (view-spec)
175 "Update current view spec according to VIEW-SPEC but don't change the view.
176 VIEW-SPEC is a string or t, which means recompute the current view spec. See
177 <${hyperb:dir}/kotl/EXAMPLE.kotl, 2b17=048> for details on valid view specs."
178 (cond ((stringp view-spec)
179 ;; Use given view-spec after removing extraneous characters.
181 (hypb:replace-match-string
182 "[^.*~0-9abcdefgilnrsv]+" view-spec "" t)))
183 ((or (eq view-spec t) (null kvspec:current))
184 (setq kvspec:current (kvspec:compute))))
185 ;; Update display using current specs.
186 (kvspec:update-modeline))
189 ;;; Private functions
192 (defun kvspec:blank-lines ()
193 "Turn blank lines on or off according to 'kvspec:current'."
194 (let ((modified-p (buffer-modified-p))
196 (if (string-match "b" kvspec:current)
198 (progn (kview:set-attr kview 'blank-lines t)
199 (kproperty:remove (point-min) (point-max) '(invisible t)))
201 (kview:set-attr kview 'blank-lines nil)
203 (goto-char (point-max))
204 (while (re-search-backward "[\n\r][\n\r]" nil t)
205 ;; Make blank lines invisible.
206 (kproperty:put (1+ (point)) (min (+ (point) 2) (point-max))
208 (set-buffer-modified-p modified-p)))
210 (defun kvspec:compute ()
211 "Compute and return current view spec string."
214 ;; a - Show all cells and cell lines.
215 ;; Never compute this setting (use it only within links) since it will
216 ;; expose all carefully hidden outline items if the user forgets to turn
217 ;; it off when he resets the view specs.
219 ;; b - blank separator lines
220 (if (kview:get-attr kview 'blank-lines) "b")
222 ;; c - cutoff lines per cell
223 (let ((lines (kview:get-attr kview 'lines-to-show)))
226 (concat "c" (int-to-string lines))))
229 (if selective-display-ellipses "e")
231 ;; l - hide some levels
232 (let ((levels (kview:get-attr kview 'levels-to-show)))
235 (concat "l" (int-to-string levels))))
237 ;; n - numbering type
238 (let ((type (kview:label-type kview)))
239 (cond ((eq type 'no) nil)
240 ((eq type kview:default-label-type) "n")
241 (t (concat "n" (char-to-string
242 (car (rassq (kview:label-type kview)
243 kvspec:label-type-alist)))))))))
245 (defun kvspec:elide ()
246 "Turn ellipses display following clipped cells on or off according to 'kvspec:current'."
247 (setq selective-display-ellipses
248 (if (string-match "e" kvspec:current) t)))
250 (defun kvspec:hide-levels ()
251 "Show a set number of cell levels according to 'kvspec:current'."
252 ;; "l" means use value of kview:default-levels-to-show.
253 ;; "l0" means show all levels.
255 (if (not (string-match "l\\([0-9]+\\)?" kvspec:current))
256 ;; Don't change the view if no view spec is given but note that
257 ;; all levels should be shown in the future.
258 (kview:set-attr kview 'levels-to-show 0)
259 (if (match-beginning 1)
260 (setq levels (string-to-number
261 (substring kvspec:current (match-beginning 1)
263 (setq levels kview:default-levels-to-show))
264 (kview:set-attr kview 'levels-to-show levels)
265 (kvspec:levels-to-show levels))))
267 (defun kvspec:lines-to-show ()
268 "Show a set number of lines per cell according to 'kvspec:current'."
269 ;; "c" means use value of kview:default-lines-to-show.
270 ;; "c0" means show all lines.
271 (cond ((not (string-match "c\\([0-9]+\\)?" kvspec:current))
272 ;; Don't change the view if no view spec is given but note that all
273 ;; lines should be shown in the future.
274 (kview:set-attr kview 'lines-to-show 0))
276 (kvspec:show-lines-per-cell
277 (string-to-number (substring kvspec:current (match-beginning 1)
279 (t (kvspec:show-lines-per-cell kview:default-lines-to-show))))
281 (defun kvspec:numbering ()
282 "Set the type of numbering (label) display according to 'kvspec:current'."
283 (if (not (string-match "n\\([.*~0-2]\\)?" kvspec:current))
285 ;; "n" means use value of kview:default-label-type.
286 ;; "n0" means display idstamps.
287 ;; "n1" means display alpha labels.
288 ;; "n2" means display partial alpha labels.
289 ;; "n." means display legal labels.
290 ;; "n*" means star labels.
291 ;; "n~" means no labels.
293 (if (match-beginning 1)
294 (setq spec (string-to-char
295 (substring kvspec:current
296 (match-beginning 1) (match-end 1)))
297 type (cdr (assq spec kvspec:label-type-alist)))
298 (setq type kview:default-label-type))
299 (kview:set-label-type kview type))))
301 (defun kvspec:update-modeline ()
302 "Setup or update display of the current kview spec in the modeline."
303 (if (stringp kvspec:current)
304 (setq kvspec:string (format kvspec:string-format kvspec:current)))
305 (if (memq 'kvspec:string mode-line-format)
307 (setq mode-line-format (copy-sequence mode-line-format))
308 (let ((elt (or (memq 'mode-line-buffer-identification mode-line-format)
309 (memq 'modeline-buffer-identification mode-line-format))))
311 (setcdr elt (cons 'kvspec:string (cdr elt)))
313 (let ((mf modeline-format)
317 (if (and (consp elt) (eq (cdr elt) 'modeline-buffer-identification))
318 (progn (setcdr mf (cons 'kvspec:string (cdr mf)))
320 (setq mf (cdr mf)))))))))
322 (defun kvspec:update-view ()
323 "Update view according to current setting of local 'kvspec:current' variable."
324 (let ((modified-p (buffer-modified-p))
328 (if (string-match "a" kvspec:current)
329 (kotl-mode:show-all))
331 (kvspec:blank-lines) ;; b
333 ;; This must come before kvspec:lines-to-show or else it could show
334 ;; lines that should be hidden.
335 (kvspec:hide-levels) ;; l
337 (kvspec:lines-to-show) ;; c
339 (if (string-match "d" kvspec:current)
344 (if (string-match "f" kvspec:current)
347 (if (string-match "g" kvspec:current)
350 (if (string-match "i" kvspec:current)
353 (if (string-match "r" kvspec:current)
356 (if (string-match "s" kvspec:current)
359 ;; Do this last since it can trigger an error if partial alpha is
361 (kvspec:numbering) ;; n
364 (set-buffer-modified-p modified-p)))
367 ;;; Private variables
370 (defvar kvspec:label-type-alist
371 '((?0 . idstamp) (?1 . alpha) (?2 . partial-alpha)
372 (?. . legal) (?* . star) (?~ . no))
373 "Alist of (view-spec-character . label-type) pairs.")
375 (defvar kvspec:string ""
376 "String displayed in koutline modelines to reflect the current view spec.
377 It is local to each koutline. Set this to nil to disable modeline display of
378 the view spec settings.")
380 (defvar kvspec:string-format " <|%s>"
381 "Format of the kview spec modeline display.
382 It must contain a '%s' which is replaced with the current set of view spec
383 characters at run-time.")
387 ;;; kvspec.el ends here