1
2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3;;
4;; MODULE      : generic-edit.scm
5;; DESCRIPTION : Generic editing routines
6;; COPYRIGHT   : (C) 2001  Joris van der Hoeven
7;;
8;; This software falls under the GNU general public license version 3 or later.
9;; It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
10;; in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
11;;
12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13
14(texmacs-module (generic generic-edit)
15  (:use (utils library tree)
16	(utils library cursor)
17	(utils edit variants)
18        (bibtex bib-complete)
19	(source macro-search)))
20
21(tm-define (generic-context? t) #t) ;; overridden in, e.g., graphics mode
22
23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24;; Basic cursor movements via the keyboard
25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26
27(tm-define (kbd-horizontal t forwards?)
28  (and-with p (tree-outer t)
29    (kbd-horizontal p forwards?)))
30
31(tm-define (kbd-vertical t downwards?)
32  (and-with p (tree-outer t)
33    (kbd-vertical p downwards?)))
34
35(tm-define (kbd-extremal t forwards?)
36  (and-with p (tree-outer t)
37    (kbd-extremal p forwards?)))
38
39(tm-define (kbd-incremental t downwards?)
40  (and-with p (tree-outer t)
41    (kbd-incremental p downwards?)))
42
43(tm-define (kbd-horizontal t forwards?)
44  (:require (tree-is-buffer? t))
45  (with move (lambda () (if forwards? (go-right) (go-left)))
46    (go-to-next-such-that move generic-context?)))
47
48(tm-define (kbd-vertical t downwards?)
49  (:require (tree-is-buffer? t))
50  (with move (lambda () (if downwards? (go-down) (go-up)))
51    (go-to-next-such-that move generic-context?)))
52
53(tm-define (kbd-extremal t forwards?)
54  (:require (tree-is-buffer? t))
55  (with move (lambda () (if forwards? (go-end-line) (go-start-line)))
56    (go-to-next-such-that move generic-context?)))
57
58(tm-define (kbd-incremental t downwards?)
59  (:require (tree-is-buffer? t))
60  (with move (lambda () (if downwards? (go-page-down) (go-page-up)))
61    (go-to-next-such-that move generic-context?)))
62
63(tm-define (kbd-left)
64  (kbd-horizontal (focus-tree) #f))
65(tm-define (kbd-right)
66  (kbd-horizontal (focus-tree) #t))
67(tm-define (kbd-up)
68  (kbd-vertical (focus-tree) #f))
69(tm-define (kbd-down)
70  (kbd-vertical (focus-tree) #t))
71(tm-define (kbd-start-line)
72  (kbd-extremal (focus-tree) #f))
73(tm-define (kbd-end-line)
74  (kbd-extremal (focus-tree) #t))
75(tm-define (kbd-page-up)
76  (kbd-incremental (focus-tree) #f))
77(tm-define (kbd-page-down)
78  (kbd-incremental (focus-tree) #t))
79
80(tm-define (kbd-select r)
81  (select-from-shift-keyboard)
82  (r)
83  (select-from-cursor))
84
85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86;; Basic editing via the keyboard
87;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
88
89(tm-define (insert-return) (insert-raw-return))
90
91(tm-define (kbd-space-bar t shift?)
92  (and-with p (tree-outer t)
93    (kbd-space-bar p shift?)))
94
95(tm-define (kbd-enter t shift?)
96  (and-with p (tree-outer t)
97    (kbd-enter p shift?)))
98
99(tm-define (kbd-control-enter t shift?)
100  (and-with p (tree-outer t)
101    (kbd-control-enter p shift?)))
102
103(tm-define (kbd-alternate-enter t shift?)
104  (and-with p (tree-outer t)
105    (kbd-alternate-enter p shift?)))
106
107(tm-define (kbd-remove t forwards?)
108  (and-with p (tree-outer t)
109    (kbd-remove p forwards?)))
110
111(tm-define (kbd-variant t forwards?)
112  (and-with p (tree-outer t)
113    (kbd-variant p forwards?)))
114
115(tm-define (kbd-space-bar t shift?)
116  (:require (tree-is-buffer? t))
117  (insert " "))
118
119(tm-define (kbd-enter t shift?)
120  (:require (tree-is-buffer? t))
121  (insert-return))
122
123(tm-define (kbd-control-enter t shift?)
124  (:require (tree-is-buffer? t))
125  (noop))
126
127(tm-define (kbd-alternate-enter t shift?)
128  (:require (tree-is-buffer? t))
129  (noop))
130
131(tm-define (kbd-remove t forwards?)
132  (:require (tree-is-buffer? t))
133  (remove-text forwards?))
134
135(tm-define (kbd-remove t forwards?)
136  (:require (and (tree-is-buffer? t) (with-any-selection?)))
137  (clipboard-cut "nowhere")
138  (clipboard-clear "nowhere"))
139
140(tm-define (kbd-variant t forwards?)
141  (:require (tree-is-buffer? t))
142  (if (and (not (complete-try?)) forwards?)
143      (with sh (kbd-system-rewrite (kbd-find-inv-binding '(kbd-alternate-tab)))
144        (set-message `(concat "Use " ,sh " in order to insert a tab")
145                     "tab"))))
146
147(tm-define (kbd-variant t forwards?)
148  (:require (and (tree-in? t '(label reference pageref)) (cursor-inside? t)))
149  (if (complete-try?) (noop)))
150
151(tm-define (bib-cite-context? t)
152  (and (tree-in? t '(cite nocite cite-detail))
153       (cursor-inside? t)
154       (or (not (tree-is? t 'cite-detail))
155           (== (tree-index (tree-down t)) 0))))
156
157(tm-define (kbd-variant t forwards?)
158  (:require (and (not (supports-db?)) (bib-cite-context? t)))
159  (with u (current-bib-file #t)
160    (with ttxt (tree-ref t (cADr (cursor-path)))
161      (if (or (url-none? u) (not ttxt))
162          (set-message "No completions" "You must add a bibliography file")
163          (custom-complete (tm->tree (citekey-completions u ttxt)))))))
164
165(tm-define (kbd-alternate-variant t forwards?)
166  (and-with p (tree-outer t)
167    (kbd-alternate-variant p forwards?)))
168
169(tm-define (kbd-alternate-variant t forwards?)
170  (:require (tree-is-buffer? t))
171  (make-htab "5mm"))
172
173(tm-define (kbd-space)
174  (kbd-space-bar (focus-tree) #f))
175(tm-define (kbd-shift-space)
176  (kbd-space-bar (focus-tree) #t))
177(tm-define (kbd-return)
178  (kbd-enter (focus-tree) #f))
179(tm-define (kbd-shift-return)
180  (kbd-enter (focus-tree) #t))
181(tm-define (kbd-control-return)
182  (kbd-control-enter (focus-tree) #f))
183(tm-define (kbd-shift-control-return)
184  (kbd-control-enter (focus-tree) #t))
185(tm-define (kbd-alternate-return)
186  (kbd-alternate-enter (focus-tree) #f))
187(tm-define (kbd-shift-alternate-return)
188  (kbd-alternate-enter (focus-tree) #t))
189(tm-define (kbd-backspace)
190  (kbd-remove (focus-tree) #f))
191(tm-define (kbd-delete)
192  (kbd-remove (focus-tree) #t))
193(tm-define (kbd-tab)
194  (kbd-variant (focus-tree) #t))
195(tm-define (kbd-shift-tab)
196  (kbd-variant (focus-tree) #f))
197(tm-define (kbd-alternate-tab)
198  (kbd-alternate-variant (focus-tree) #t))
199(tm-define (kbd-shift-alternate-tab)
200  (kbd-alternate-variant (focus-tree) #f))
201
202(tm-define (notify-activated t) (noop))
203(tm-define (notify-disactivated t) (noop))
204
205;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
206;; Basic predicates
207;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208
209(tm-define (simple-tags)
210  '(concat document tformat table row cell shown hidden))
211
212(tm-define (complex-context? t)
213  (and (nleaf? t)
214       (nin? (tree-label t) (simple-tags))))
215
216(tm-define (simple-context? t)
217  (or (leaf? t)
218      (and (tree-in? t (simple-tags))
219           (simple-context? (tree-down t)))))
220
221(tm-define (document-context? t)
222  (tree-is? t 'document))
223
224(tm-define (table-markup-context? t)
225  (or (tree-in? t '(table tformat))
226      (and (== (tree-arity t) 1)
227           (or (tree-in? (tree-ref t 0) '(table tformat))
228               (and (tm-func? (tree-ref t 0) 'document 1)
229                    (tree-in? (tree-ref t 0 0) '(table tformat)))))))
230
231(tm-define (structured-horizontal? t)
232  (or (tree-is-dynamic? t)
233      (table-markup-context? t)))
234
235(tm-define (structured-vertical? t)
236  (or (tree-in? t '(tree))
237      (table-markup-context? t)))
238
239;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
240;; Tree traversal
241;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
242
243(tm-define (traverse-horizontal t forwards?)
244  (if forwards? (go-to-next-word) (go-to-previous-word)))
245
246(tm-define (traverse-vertical t downwards?)
247  (and-with p (tree-outer t)
248    (traverse-vertical p downwards?)))
249
250(tm-define (traverse-vertical t downwards?)
251  (:require (document-context? t))
252  (with move (if downwards? go-to-next-tag go-to-previous-tag)
253    (move 'document)))
254
255(define (find-similar-upwards t l)
256  (cond ((in? (tree-label t) l) t)
257        ((and (not (tree-is-buffer? t)) (tree-up t))
258         (find-similar-upwards (tree-up t) l))
259        (else #f)))
260
261(define-macro (with-focus-in l . body)
262  `(begin
263     ,@body
264     (selection-cancel)
265     (and-with t (find-similar-upwards (focus-tree) ,l)
266       (tree-focus t))))
267
268(tm-define (traverse-incremental t forwards?)
269  (let* ((l (similar-to (tree-label t)))
270         (fun (if forwards? go-to-next-tag go-to-previous-tag)))
271    (with-focus-in l (fun l))))
272
273(tm-define (traverse-extremal t forwards?)
274  (let* ((l (similar-to (tree-label t)))
275         (fun (if forwards? go-to-next-tag go-to-previous-tag))
276         (inc (lambda () (fun l))))
277    (with-focus-in l
278      (go-to-repeat inc)
279      (structured-inner-extremal t forwards?))))
280
281(tm-define (traverse-previous)
282  (traverse-incremental (focus-tree) #f))
283(tm-define (traverse-next)
284  (traverse-incremental (focus-tree) #t))
285(tm-define (traverse-first)
286  (traverse-extremal (focus-tree) #f))
287(tm-define (traverse-last)
288  (traverse-extremal (focus-tree) #t))
289(tm-define (traverse-left)
290  (traverse-horizontal (focus-tree) #f))
291(tm-define (traverse-right)
292  (traverse-horizontal (focus-tree) #t))
293(tm-define (traverse-up)
294  (traverse-vertical (focus-tree) #f))
295(tm-define (traverse-down)
296  (traverse-vertical (focus-tree) #t))
297(tm-define (traverse-previous-section-title)
298  (go-to-previous-tag (similar-to 'section)))
299
300;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
301;; Structured insert and remove
302;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303
304(tm-define (structured-insert-horizontal t forwards?)
305  (and-with p (tree-outer t)
306    (structured-insert-horizontal p forwards?)))
307
308(tm-define (structured-insert-vertical t downwards?)
309  (and-with p (tree-outer t)
310    (structured-insert-vertical p downwards?)))
311
312(tm-define (structured-remove-horizontal t forwards?)
313  (and-with p (tree-outer t)
314    (structured-remove-horizontal p forwards?)))
315
316(tm-define (structured-remove-vertical t downwards?)
317  (and-with p (tree-outer t)
318    (structured-remove-vertical p downwards?)))
319
320(tm-define (structured-insert-horizontal t forwards?)
321  (:require (structured-horizontal? t))
322  (when (tree->path t :down)
323    (insert-argument-at (tree->path t :down) forwards?)))
324
325(tm-define (structured-remove-horizontal t forwards?)
326  (:require (structured-horizontal? t))
327  (when (tree->path t :down)
328    (remove-argument-at (tree->path t :down) forwards?)))
329
330(tm-define (structured-insert-extremal t forwards?)
331  (structured-extremal t forwards?)
332  (structured-insert-horizontal t forwards?))
333
334(tm-define (structured-insert-incremental t downwards?)
335  (structured-incremental t downwards?)
336  (structured-insert-vertical t downwards?))
337
338(tm-define (structured-insert-left)
339  (structured-insert-horizontal (focus-tree) #f))
340(tm-define (structured-insert-right)
341  (structured-insert-horizontal (focus-tree) #t))
342(tm-define (structured-remove-left)
343  (structured-remove-horizontal (focus-tree) #f))
344(tm-define (structured-remove-right)
345  (structured-remove-horizontal (focus-tree) #t))
346(tm-define (structured-insert-up)
347  (structured-insert-vertical (focus-tree) #f))
348(tm-define (structured-insert-down)
349  (structured-insert-vertical (focus-tree) #t))
350(tm-define (structured-remove-up)
351  (structured-remove-vertical (focus-tree) #f))
352(tm-define (structured-remove-down)
353  (structured-remove-vertical (focus-tree) #t))
354(tm-define (structured-insert-start)
355  (structured-insert-extremal (focus-tree) #f))
356(tm-define (structured-insert-end)
357  (structured-insert-extremal (focus-tree) #t))
358(tm-define (structured-insert-top)
359  (structured-insert-incremental (focus-tree) #f))
360(tm-define (structured-insert-bottom)
361  (structured-insert-incremental (focus-tree) #t))
362
363;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
364;; Structured movements
365;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
366
367(tm-define (structured-horizontal t forwards?)
368  (and-with p (tree-outer t)
369    (structured-horizontal p forwards?)))
370
371(tm-define (structured-horizontal t forwards?)
372  (:require (structured-horizontal? t))
373  (with-focus-after t
374    (with move (if forwards? path-next-argument path-previous-argument)
375      (with p (move (root-tree) (tree->path (tree-down t)))
376        (if (nnull? p) (go-to p))))))
377
378(tm-define (structured-vertical t downwards?)
379  (and-with p (tree-outer t)
380    (structured-vertical p downwards?)))
381
382(tm-define (structured-inner-extremal t forwards?)
383  (and-with p (tree-outer t)
384    (structured-inner-extremal p forwards?)))
385
386(tm-define (structured-inner-extremal t forwards?)
387  (:require (structured-horizontal? t))
388  (with-focus-after t
389    (tree-go-to t :down (if forwards? :end :start))))
390
391(tm-define (structured-extremal t forwards?)
392  (go-to-repeat (lambda () (structured-horizontal t forwards?)))
393  (structured-inner-extremal t forwards?))
394
395(tm-define (structured-incremental t downwards?)
396  (go-to-repeat (lambda () (structured-vertical t downwards?)))
397  (structured-inner-extremal t downwards?))
398
399(tm-define (structured-exit t forwards?)
400  (when (complex-context? t)
401    (tree-go-to t (if forwards? :end :start))))
402
403(tm-define (structured-left)
404  (structured-horizontal (focus-tree) #f))
405(tm-define (structured-right)
406  (structured-horizontal (focus-tree) #t))
407(tm-define (structured-up)
408  (structured-vertical (focus-tree) #f))
409(tm-define (structured-down)
410  (structured-vertical (focus-tree) #t))
411(tm-define (structured-start)
412  (structured-extremal (focus-tree) #f))
413(tm-define (structured-end)
414  (structured-extremal (focus-tree) #t))
415(tm-define (structured-top)
416  (structured-incremental (focus-tree) #f))
417(tm-define (structured-bottom)
418  (structured-incremental (focus-tree) #t))
419(tm-define (structured-exit-left)
420  (structured-exit (focus-tree) #f))
421(tm-define (structured-exit-right)
422  (structured-exit (focus-tree) #t))
423
424;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
425;; Multi-purpose alignment
426;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
427
428(tm-define (geometry-speed t down?)
429  (and-with p (tree-outer t)
430    (geometry-speed p down?)))
431
432(tm-define (geometry-variant t forwards?)
433  (and-with p (tree-outer t)
434    (geometry-variant p forwards?)))
435
436(tm-define (geometry-default t)
437  (and-with p (tree-outer t)
438    (geometry-default p)))
439
440(tm-define (geometry-horizontal t forwards?)
441  (and-with p (tree-outer t)
442    (geometry-horizontal p forwards?)))
443
444(tm-define (geometry-vertical t down?)
445  (and-with p (tree-outer t)
446    (geometry-vertical p down?)))
447
448(tm-define (geometry-extremal t forwards?)
449  (and-with p (tree-outer t)
450    (geometry-extremal p forwards?)))
451
452(tm-define (geometry-incremental t down?)
453  (and-with p (tree-outer t)
454    (geometry-incremental p down?)))
455
456(tm-define (geometry-slower)
457  (geometry-speed (focus-tree) #f))
458(tm-define (geometry-faster)
459  (geometry-speed (focus-tree) #t))
460(tm-define (geometry-circulate forwards?)
461  (geometry-variant (focus-tree) forwards?))
462(tm-define (geometry-reset)
463  (geometry-default (focus-tree)))
464(tm-define (geometry-left)
465  (geometry-horizontal (focus-tree) #f))
466(tm-define (geometry-right)
467  (geometry-horizontal (focus-tree) #t))
468(tm-define (geometry-up)
469  (geometry-vertical (focus-tree) #f))
470(tm-define (geometry-down)
471  (geometry-vertical (focus-tree) #t))
472(tm-define (geometry-start)
473  (geometry-extremal (focus-tree) #f))
474(tm-define (geometry-end)
475  (geometry-extremal (focus-tree) #t))
476(tm-define (geometry-top)
477  (geometry-incremental (focus-tree) #f))
478(tm-define (geometry-bottom)
479  (geometry-incremental (focus-tree) #t))
480
481;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
482;; Tree editing
483;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484
485(tm-define (structured-insert-horizontal t forwards?)
486  (:require (tree-is? t 'tree))
487  (if (== (tree-down-index t) 0) (set! t (tree-up t)))
488  (if (== (tm-car t) 'tree)
489      (with pos (tree-down-index t)
490        (if forwards? (set! pos (1+ pos)))
491        (tree-insert! t pos '(""))
492        (tree-go-to t pos 0))))
493
494(tm-define (structured-remove-horizontal t forwards?)
495  (:require (tree-is? t 'tree))
496  (if (== (tree-down-index t) 0) (set! t (tree-up t)))
497  (if (== (tm-car t) 'tree)
498      (with pos (tree-down-index t)
499        (cond (forwards?
500               (tree-remove! t pos 1)
501               (if (== pos (tree-arity t))
502                   (tree-go-to t :end)
503                   (tree-go-to t pos :start)))
504              ((== pos 1) (tree-go-to t 0 :end))
505              (else (tree-remove! t (- pos 1) 1))))))
506
507(tm-define (structured-insert-vertical t downwards?)
508  (:require (tree-is? t 'tree))
509  (if downwards?
510      (if (== (tree-down-index t) 0)
511          (with pos (tree-arity t)
512            (tree-insert! t pos '(""))
513            (tree-go-to t pos 0))
514          (begin
515            (set! t (tree-down t))
516            (tree-set! t `(tree ,t ""))
517            (tree-go-to t 1 0)))
518      (begin
519        (if (!= (tree-down-index t) 0) (set! t (tree-down t)))
520        (tree-set! t `(tree "" ,t))
521        (tree-go-to t 0 0))))
522
523(define (branch-active t)
524  (with i (tree-down-index t)
525    (if (and (= i 0) (tree-is? t :up 'tree))
526        (tree-up t)
527        t)))
528
529(define (branch-go-to . l)
530  (apply tree-go-to l)
531  (if (tree-is? (cursor-tree) 'tree)
532      (with last (cAr l)
533        (if (nin? last '(:start :end)) (set! last :start))
534        (tree-go-to (cursor-tree) 0 last))))
535
536(tm-define (structured-horizontal t* forwards?)
537  (:require (tree-is? t* 'tree))
538  (let* ((t (branch-active t*))
539         (i (tree-down-index t)))
540    (cond ((and (not forwards?) (> i 1))
541           (branch-go-to t (- i 1) :end))
542          ((and forwards? (!= i 0) (< i (- (tree-arity t) 1)))
543           (branch-go-to t (+ i 1) :start)))))
544
545(tm-define (structured-vertical t* downwards?)
546  (:require (tree-is? t* 'tree))
547  (let* ((t (branch-active t*))
548         (i (tree-down-index t)))
549    (cond ((and (not downwards?) (!= i 0))
550           (tree-go-to t 0 :end))
551          ((and downwards? (== (tree-down-index t*) 0))
552           (branch-go-to t* (quotient (tree-arity t*) 2) :start)))))
553
554(tm-define (structured-extremal t* forwards?)
555  (:require (tree-is? t* 'tree))
556  (let* ((t (branch-active t*))
557         (i (tree-down-index t)))
558    (cond ((not forwards?)
559           (branch-go-to t 1 :start))
560          (forwards?
561           (branch-go-to t :last :end)))))
562
563(tm-define (structured-incremental t downwards?)
564  (:require (tree-is? t 'tree))
565  (go-to-repeat (if downwards? structured-down structured-up)))
566
567;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
568;; Extra editing functions
569;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
570
571(tm-define (kill-paragraph)
572  (selection-set-start)
573  (go-end-paragraph)
574  (selection-set-end)
575  (clipboard-cut "primary"))
576
577(tm-define (yank-paragraph)
578  (selection-set-start)
579  (go-end-paragraph)
580  (selection-set-end)
581  (clipboard-copy "primary"))
582
583(tm-define (select-all)
584  (tree-select (buffer-tree)))
585
586(tm-define (go-to-line n . opt-from)
587  (if (nnull? opt-from) (cursor-history-add (car opt-from)))
588  (with-innermost t 'document
589    (tree-go-to t n 0)))
590
591(tm-define (go-to-column c . opt-from)
592  (if (nnull? opt-from) (cursor-history-add (car opt-from)))
593  (with-innermost t 'document
594    (with p (tree-cursor-path t)
595      (tree-go-to t (cADr p) c))))
596
597(tm-define (select-word w t col)
598  (:synopsis "Selects word @w in tree @t, more or less around column @col.")
599  (let* ((st (tree->string t))
600         (pos (- col (string-length w)))
601         (beg (string-contains st w (max 0 pos)))) ; returns index of w in st
602    (if beg
603        (with p (tree->path t)
604          (go-to (rcons p beg))
605          (selection-set-start)
606          (go-to (rcons p (+ beg (string-length w))))
607          (selection-set-end)))
608    beg))
609
610;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
611;; Standard environment parameters for primitives
612;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
613
614(tm-define (standard-parameters l)
615  (:require (== l "action"))
616  (list "locus-color"))
617
618(tm-define (standard-parameters l)
619  (:require (== l "locus"))
620  (list "locus-color" "visited-color"))
621
622(tm-define (standard-parameters l)
623  (:require (== l "ornament"))
624  (list "ornament-shape" "ornament-title-style" "ornament-border"
625	"ornament-hpadding" "ornament-vpadding"
626	"ornament-color" "ornament-extra-color"
627	"ornament-sunny-color" "ornament-shadow-color"))
628
629(tm-define (standard-parameters l)
630  (:require (in? l '("reference" "pageref" "label" "tag")))
631  (list))
632
633(tm-define (search-parameters l)
634  (:require (in? (if (string? l) l (symbol->string l))
635                 '("reference" "pageref" "hlink")))
636  (standard-parameters "locus"))
637
638(tm-define (parameter-choice-list l)
639  (:require (== l "ornament-shape"))
640  (list "classic" "rounded" "angular" "cartoon"
641        ;;"ring"
642        ))
643
644(tm-define (parameter-choice-list l)
645  (:require (== l "ornament-title-style"))
646  (list "classic"
647        "top left" "top center" "top right"
648        "bottom left" "bottom center" "bottom right"))
649
650;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
651;; Inserting various kinds of content
652;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
653
654(tm-define (label-insert t)
655  (and-with p (tree-outer t)
656    (label-insert p)))
657
658(tm-define (label-insert t)
659  (:require (tree-is-buffer? t))
660  (make 'label))
661
662(tm-define (make-label)
663  (label-insert (focus-tree)))
664
665(tm-define (make-specific s)
666  (if (or (== s "texmacs") (in-source?))
667      (insert-go-to `(specific ,s "") '(1 0))
668      (insert-go-to `(inactive (specific ,s "")) '(0 1 0))))
669
670(define (url->delta-unix u)
671  (if (url-rooted? u) (set! u (url-delta (current-buffer) u)))
672  (url->unix u))
673
674(tm-define (make-include u)
675  (insert `(include ,(url->delta-unix u))))
676
677(tm-define (make-inline-image l)
678  (apply make-image (cons* (url->delta-unix (car l)) #f (cdr l))))
679
680(tm-define (make-link-image l)
681  (apply make-image (cons* (url->delta-unix (car l)) #t (cdr l))))
682
683(tm-define (make-graphics-over-selection)
684  (if (selection-active-any?)
685  (with selection (selection-tree)
686    (clipboard-cut "graphics background")
687    (insert-go-to `(draw-over ,selection (graphics)) '(1 1)))))
688
689;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
690;; Thumbnails facility
691;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
692
693(define (thumbnail-suffixes)
694  (list->url
695    (map url-wildcard
696         '("*.gif" "*.jpg" "*.jpeg" "*.JPG" "*.JPEG" "*.png" "*.PNG"))))
697
698(define (fill-row l nr)
699  (cond ((= nr 0) '())
700        ((nnull? l) (cons (car l) (fill-row (cdr l) (- nr 1))))
701        (else (cons "" (fill-row l (- nr 1))))))
702
703(define (make-rows l nr)
704  (if (> (length l) nr)
705      (cons (list-head l nr) (make-rows (list-tail l nr) nr))
706      (list (fill-row l nr))))
707
708(define (make-thumbnails-sub l)
709  (define (mapper x)
710    `(image ,(url->delta-unix x) "0.22par" "" "" ""))
711  (let* ((l1 (map mapper l))
712         (l2 (make-rows l1 4))
713         (l3 (map (lambda (r) `(row ,@(map (lambda (c) `(cell ,c)) r))) l2)))
714    (insert `(tabular* (tformat (twith "table-width" "1par")
715                                (twith "table-hyphen" "yes")
716                                (table ,@l3))))))
717
718(tm-define (make-thumbnails)
719  (:interactive #t)
720  (user-url "Picture directory" "directory"
721   (lambda (dir)
722     (let* ((find (url-append dir (thumbnail-suffixes)))
723                  (files (url->list (url-expand (url-complete find "r"))))
724                  (base (buffer-master))
725                  (rel-files (map (lambda (x) (url-delta base x)) files)))
726           (if (nnull? rel-files) (make-thumbnails-sub rel-files))))))
727
728;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
729;; Routines for floats
730;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
731
732(tm-define (make-marginal-note)
733  (:synopsis "Insert a marginal note.")
734  (wrap-selection-small
735    (insert-go-to `(inactive (marginal-note "normal" "c" "")) '(0 2 0))))
736
737(tm-define (test-marginal-note-hpos? hp)
738  (and-with t (tree-innermost 'marginal-note #t)
739    (tm-equal? (tree-ref t 0) hp)))
740(tm-define (set-marginal-note-hpos hp)
741  (:synopsis "Set the horizontal position of the marginal note to @hp.")
742  (:check-mark "v" test-marginal-note-hpos?)
743  (and-with t (tree-innermost 'marginal-note #t)
744    (tree-set t 0 hp)))
745
746(tm-define (test-marginal-note-valign? va)
747  (and-with t (tree-innermost 'marginal-note #t)
748    (tm-equal? (tree-ref t 1) va)))
749(tm-define (set-marginal-note-valign va)
750  (:synopsis "Set the vertical alignment of the marginal note to @va.")
751  (:check-mark "v" test-marginal-note-valign?)
752  (and-with t (tree-innermost 'marginal-note #t)
753    (tree-set t 1 va)))
754
755(tm-define (make-insertion s)
756  (:synopsis "Make an insertion of type @s.")
757  (with pos (if (== s "float") "tbh" "")
758    (insert-go-to (list 'float s pos (list 'document ""))
759                  (list 2 0 0))))
760
761(tm-define (insertion-positioning what flag)
762  (:synopsis "Allow/disallow the position @what for innermost float.")
763  (with-innermost t 'float
764    (let ((op (if flag string-union string-minus))
765          (st (tree-ref t 1)))
766      (tree-set! st (op (tree->string st) what)))))
767
768(define (test-insertion-positioning? what)
769  (with-innermost t 'float
770    (with c (string-ref what 0)
771      (char-in-string? c (tree->string (tree-ref t 1))))))
772
773(define (not-test-insertion-positioning? s)
774  (not (test-insertion-positioning? s)))
775
776(tm-define (toggle-insertion-positioning what)
777  (:check-mark "v" test-insertion-positioning?)
778  (insertion-positioning what (not-test-insertion-positioning? what)))
779
780(tm-define (toggle-insertion-positioning-not s)
781  (:check-mark "v" not-test-insertion-positioning?)
782  (toggle-insertion-positioning s))
783
784;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
785;; Balloons
786;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
787
788(tm-define (balloon-context? t)
789  (tree-in? t (balloon-tag-list)))
790
791(define (integer-floor x)
792  (inexact->exact (floor x)))
793
794(tm-define (display-balloon body balloon halign valign extents)
795  (:secure #t)
796  (with (x1 y1 x2 y2) (tree-bounding-rectangle body)
797    (let* ((zf (get-window-zoom-factor))
798           (sf (/ 5.0 zf))
799           (balloon* `(with "magnification" ,(number->string zf) ,balloon))
800           (w (widget-texmacs-output balloon* '(style "generic")))
801           (ww (integer-floor (/ (tree->number (tree-ref extents 0)) sf)))
802           (wh (integer-floor (/ (tree->number (tree-ref extents 1)) sf)))
803           (ha (tree->stree halign))
804           (va (tree->stree valign))
805           (x (cond ((== ha "Left") (- (- x1 ww) (* 3 256)))
806                    ((== ha "left") x1)
807                    ((== ha "center") (quotient (+ x1 x2 (- ww)) 2))
808                    ((== ha "right") (- (- x2 ww) (* 3 256)))
809                    ((== ha "Right") x2)
810                    (else x1)))
811           (y (cond ((== va "Bottom") (- y1 (* 5 256)))
812                    ((== va "bottom") (+ y1 wh))
813                    ((== va "center") (quotient (+ y1 y2 wh) 2))
814                    ((== va "top") y2)
815                    ((== va "Top") (+ y2 wh (* 5 256)))
816                    (else (- y1 (* 5 256))))))
817      ;;(display* "size= " (widget-size w) "\n")
818      (show-balloon w x y))))
819
820(tm-define (display-balloon* body balloon halign valign extents)
821  (:secure #t)
822  (with (mx my) (get-mouse-position)
823    (let* ((zf (get-window-zoom-factor))
824           (sf (/ 5.0 zf))
825           (balloon* `(with "magnification" ,(number->string zf) ,balloon))
826           (w (widget-texmacs-output balloon* '(style "generic")))
827           (ww (integer-floor (/ (tree->number (tree-ref extents 0)) sf)))
828           (wh (integer-floor (/ (tree->number (tree-ref extents 1)) sf)))
829           (ha (tree->stree halign))
830           (va (tree->stree valign))
831           (x (cond ((in? ha (list "Left" "left")) (- (- mx ww) (* 3 256)))
832                    ((== ha "center") (+ (- mx (quotient ww 2)) (* 5 256)))
833                    ((in? ha (list "right" "Right")) (+ mx (* 10 256)))
834                    (else (+ mx (* 3 256)))))
835           (y (cond ((in? va (list "Bottom" "bottom")) (- my (* 16 256)))
836                    ((== va "center") (- (+ my (quotient wh 2)) (* 8 256)))
837                    ((in? va (list "top" "Top")) (+ my wh (* 5 256)))
838                    (else (- my (* 5 256))))))
839      (show-balloon w x y))))
840
841(tm-define (make-balloon)
842  (:synopsis "Insert a balloon.")
843  (wrap-selection-small
844    (insert-go-to `(inactive (mouse-over-balloon "" "" "left" "Bottom"))
845                  '(0 0 0))))
846
847(tm-define (test-balloon-halign? ha)
848  (and-with t (tree-innermost balloon-context? #t)
849    (tm-equal? (tree-ref t 2) ha)))
850(tm-define (set-balloon-halign ha)
851  (:synopsis "Set the horizontal alignment of the marginal note to @ha.")
852  (:check-mark "v" test-balloon-halign?)
853  (and-with t (tree-innermost balloon-context? #t)
854    (tree-set t 2 ha)))
855
856(tm-define (test-balloon-valign? va)
857  (and-with t (tree-innermost balloon-context? #t)
858    (tm-equal? (tree-ref t 3) va)))
859(tm-define (set-balloon-valign va)
860  (:synopsis "Set the vertical alignment of the marginal note to @va.")
861  (:check-mark "v" test-balloon-valign?)
862  (and-with t (tree-innermost balloon-context? #t)
863    (tree-set t 3 va)))
864
865;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
866;; Sound and video
867;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
868
869(tm-define (make-sound u)
870  (if (not (url-none? u))
871      (insert `(sound ,(url->delta-unix u)))))
872
873(tm-define (make-animation u)
874  (interactive
875      (lambda (w h len rep)
876        (if (== rep "no") (set! rep "false"))
877        (insert `(video ,(url->delta-unix u) ,w ,h ,len ,rep)))
878    "Width" "Height" "Length" "Repeat?"))
879
880;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
881;; Search, replace, spell and tab-completion
882;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
883
884(tm-define (key-press-command key)
885  ;; FIXME: this routine should do exactly the same as key-press,
886  ;; without modification of the internal state and without executing
887  ;; the actual shortcut. It should rather return a command which
888  ;; does all this, or #f
889  (and-with p (kbd-find-key-binding key)
890    (car p)))
891
892(tm-define (keyboard-press key time)
893  (:mode search-mode?)
894  (with cmd (key-press-command (string-append "search " key))
895    (cond (cmd (cmd))
896          ((key-press-search key) (noop))
897          (else (key-press key)))))
898
899(tm-define (search-next)
900  (key-press-search "next"))
901
902(tm-define (search-previous)
903  (key-press-search "previous"))
904
905(tm-define (keyboard-press key time)
906  (:mode replace-mode?)
907  (with cmd (key-press-command (string-append "replace " key))
908    (cond (cmd (cmd))
909          ((key-press-replace key) (noop))
910          (else (key-press key)))))
911
912(tm-define (keyboard-press key time)
913  (:mode spell-mode?)
914  (with cmd (key-press-command (string-append "spell " key))
915    (cond (cmd (cmd))
916          ((key-press-spell key) (noop))
917          (else (key-press key)))))
918
919(tm-define (keyboard-press key time)
920  (:mode complete-mode?)
921  (with cmd (key-press-command (string-append "complete " key))
922    (cond (cmd (cmd))
923          ((key-press-complete key) (noop))
924          (else (key-press key)))))
925
926(tm-define (keyboard-press key time)
927  (:mode remote-control-mode?)
928  ;;(display* "Press " key "\n")
929  (if (ahash-ref remote-control-remap key)
930      (begin
931        ;;(display* "Remap " (ahash-ref remote-control-remap key) "\n")
932        (key-press (ahash-ref remote-control-remap key)))
933      (key-press key)))
934
935(tm-define (focus-open-search-tool t)
936  (:interactive #t)
937  (noop))
938