194
230
(define (navigation-list-sub type attrs nr source l)
196
232
(let* ((head (list type attrs nr source (car l)))
197
(tail (navigation-list-sub type attrs (+ nr 1) source (cdr l))))
198
(if (== source (vertex->id (car l))) tail
233
(tail (navigation-list-sub type attrs (+ nr 1) source (cdr l))))
234
(if (== source (vertex->id (car l))) tail
201
237
(tm-define (link-list->navigation-list l)
202
238
(:synopsis "Transforms the link list @t into a navigation list")
204
240
(let* ((item (car l))
205
(source (link-item-id item))
206
(type (link-item-type item))
207
(attrs (link-item-attributes item))
208
(vertices (link-item-vertices item))
209
(h (navigation-list-sub type attrs 0 source vertices))
210
(r (link-list->navigation-list (cdr l))))
211
(list-remove-duplicates (append h r)))))
241
(source (link-item-id item))
242
(type (link-item-type item))
243
(attrs (link-item-attributes item))
244
(vertices (link-item-vertices item))
245
(h (navigation-list-sub type attrs 0 source vertices))
246
(r (link-list->navigation-list (cdr l))))
247
(list-remove-duplicates (append h r)))))
213
249
(tm-define (upward-navigation-list t)
214
250
(link-list->navigation-list (upward-link-list t #t)))
216
252
(tm-define (navigation-list-filter l type nr jumpable?)
217
253
(cond ((null? l) l)
218
((and (or (== type #t) (== (navigation-type (car l)) type))
219
(or (== nr #t) (== (navigation-pos (car l)) nr))
221
(func? (navigation-target (car l)) 'id 1)
222
(func? (navigation-target (car l)) 'url 1)
223
(func? (navigation-target (car l)) 'script)))
224
(cons (car l) (navigation-list-filter (cdr l) type nr jumpable?)))
225
(else (navigation-list-filter (cdr l) type nr jumpable?))))
254
((and (or (== type #t) (== (navigation-type (car l)) type))
255
(or (== nr #t) (== (navigation-pos (car l)) nr))
257
(func? (navigation-target (car l)) 'id 1)
258
(func? (navigation-target (car l)) 'url 1)
259
(func? (navigation-target (car l)) 'script)))
260
(cons (car l) (navigation-list-filter (cdr l) type nr jumpable?)))
261
(else (navigation-list-filter (cdr l) type nr jumpable?))))
227
263
(tm-define (navigation-list-types l)
228
264
(list-remove-duplicates (map navigation-type l)))
230
266
(tm-define (navigation-list-xtypes l)
231
267
(let* ((direct (navigation-list-filter l #t 1 #t))
232
(inverse (navigation-list-filter l #t 0 #t))
233
(dtypes (map navigation-type direct))
234
(itypes (map (cut string-append <> "*")
235
(map navigation-type inverse))))
268
(inverse (navigation-list-filter l #t 0 #t))
269
(dtypes (map navigation-type direct))
270
(itypes (map (cut string-append <> "*")
271
(map navigation-type inverse))))
236
272
(list-remove-duplicates (append dtypes itypes))))
238
274
(tm-define (navigation-list-first-xtype l xtype)
239
275
(let* ((inverse? (string-ends? xtype "*"))
240
(type (if inverse? (string-drop-right xtype 1) xtype))
241
(fl (navigation-list-filter l type (if inverse? 0 1) #t)))
276
(type (if inverse? (string-drop-right xtype 1) xtype))
277
(fl (navigation-list-filter l type (if inverse? 0 1) #t)))
242
278
(and (nnull? fl) (navigation-type fl))))
244
280
(define (resolve-navigation-list l fun)
245
281
(if (null? l) (fun)
246
282
(let* ((id (vertex->id (navigation-target (car l))))
247
(ok (or (nstring? id) (nnull? (id->trees id)))))
248
(if ok (resolve-navigation-list (cdr l) fun)
251
(delayed (:idle 25) (resolve-navigation-list (cdr l) fun)))))))
283
(ok (or (nstring? id) (nnull? (id->trees id)))))
284
(if ok (resolve-navigation-list (cdr l) fun)
287
(delayed (:idle 25) (resolve-navigation-list (cdr l) fun)))))))
253
289
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257
293
(define (automatic-link-text back)
258
294
(cond ((func? back 'id 1)
259
(with ts (id->trees (vertex->id back))
260
(and (nnull? ts) (tree->stree (car ts)))))
262
`(verbatim ,(vertex->url back)))
263
((func? back 'script)
264
`(verbatim ,(vertex->script back)))
295
(with ts (id->trees (vertex->id back))
296
(and (nnull? ts) (tree->stree (car ts)))))
298
`(verbatim ,(vertex->url back)))
299
((func? back 'script)
300
`(verbatim ,(vertex->script back)))
267
303
(tm-define (automatic-link back . opt)
268
304
(let* ((broken-text (if (null? opt) "Broken" (car opt)))
269
(id (create-unique-id))
270
(text (automatic-link-text back)))
305
(id (create-unique-id))
306
(text (automatic-link-text back)))
271
307
(if (not text) `(with "color" "red" ,broken-text)
272
`(locus (id ,id) (link "automatic" (id ,id) ,back) ,text))))
308
`(locus (id ,id) (link "automatic" (id ,id) ,back) ,text))))
274
310
(tm-define (build-enumeration l)
275
311
(if (<= (length l) 1) l
278
,@(map (lambda (x) `(surround (item) "" ,x)) l))))))
314
,@(map (lambda (x) `(surround (item) "" ,x)) l))))))
280
316
(define (navigation-item->document item)
281
317
(automatic-link (navigation-target item)))
283
319
(define (navigation-list-by-type->document type l)
284
320
(cons `(strong ,type)
285
(build-enumeration (map navigation-item->document l))))
321
(build-enumeration (map navigation-item->document l))))
287
323
(define (navigation-list->document style l)
288
324
(let* ((direct (navigation-list-filter l #t 1 #t))
289
(inverse (navigation-list-filter l #t 0 #t))
290
(direct-types (navigation-list-types direct))
291
(inverse-types (navigation-list-types inverse))
292
(direct-by-type (map (cut navigation-list-filter direct <> #t #f)
294
(inverse-by-type (map (cut navigation-list-filter inverse <> #t #f)
325
(inverse (navigation-list-filter l #t 0 #t))
326
(direct-types (navigation-list-types direct))
327
(inverse-types (navigation-list-types inverse))
328
(direct-by-type (map (cut navigation-list-filter direct <> #t #f)
330
(inverse-by-type (map (cut navigation-list-filter inverse <> #t #f)
300
,(automatic-link `(id ,(navigation-source (car l)))
303
navigation-list-by-type->document
304
(map (cut string-append "Direct " <>) direct-types)
307
navigation-list-by-type->document
308
(map (cut string-append "Inverse " <>) inverse-types)
309
inverse-by-type))))))
336
,(automatic-link `(id ,(navigation-source (car l)))
339
navigation-list-by-type->document
340
(map (cut string-append "Direct " <>) direct-types)
343
navigation-list-by-type->document
344
(map (cut string-append "Inverse " <>) inverse-types)
345
inverse-by-type))))))
311
347
(define (build-navigation-page-sub style l)
312
348
(with doc (navigation-list->document style l)
313
349
(open-auxiliary "Link page" doc)))
315
(define (build-navigation-page l)
351
(tm-define (build-navigation-page l)
316
352
(let* ((style (tree->stree (get-style-tree)))
317
(fun (lambda () (build-navigation-page-sub style l))))
353
(fun (lambda () (build-navigation-page-sub style l))))
318
354
(resolve-navigation-list l fun)))
320
356
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
357
;; Jumping to different types of URLs is done in two stages. The load handler,
358
;; changing with the type of root of the url and the post-load handler, which
359
;; will tipically depend on the file format.
360
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
362
(define (url->item u)
363
(with (base qry) (process-url u)
364
(let* ((file (url->string u))
365
(help? (and (== "texmacs-file" (file-format u))
366
(url-exists-in-help? file)))
367
(text (if help? (help-file-title u) (basename (url->string base)))))
370
(define (url-list->document l)
372
($tmdoc-title "Link disambiguation")
373
($para "The link you followed points to several locations:")
374
($description-aligned
378
(number->string (begin (set! c (+ 1 c)) c)) (url->item x)))))))
380
(tm-define (build-disambiguation-page l)
381
(open-auxiliary "Disambiguation page" (url-list->document l)))
383
; FIXME: many corner cases will get through
384
;(inexistent relative paths for instance)
385
(define (default-filter-url u)
386
(with (base qry) (process-url u)
388
(or (!= (url-root base) "default")
389
(url-exists? base)))))
391
(define (default-root-disambiguator u)
392
(with l (list-filter (url->list u) default-filter-url)
394
(set-message `(verbatim ,(url->string u)) "Not found"))
395
((== 1 (length l)) (load-browse-buffer (car l)))
396
(else (build-disambiguation-page l)))))
398
(define (process-url u)
399
"Split a simple (not or'ed!!) url in base and query"
400
(let* ((s (url->string u))
401
(m (string-length s))
402
(h (or (string-index s #\#) m))
403
(a (or (string-index s #\?) m))
405
(base (substring s 0 i))
406
(qry (substring s (min m (+ 1 i)) m)))
407
(if (< i m) ; was there either a '?' or a '#' (with args)?
408
(list (string->url (string-drop-right s (+ 1 (string-length qry))))
409
(unescape-link-args qry))
412
(define (texmacs-file-post qry)
413
(if (and (string? qry) (not (string-null? qry)))
414
(with dest (unescape-link-args qry)
416
(set-message (replace "At %1." dest) ""))))
418
(define generic-file-post texmacs-file-post)
420
(define (source-file-post qry)
421
(let* ((lstr (or (query-ref qry "line") "0"))
422
(cstr (or (query-ref qry "column") "0"))
423
(sstr (or (query-ref qry "select") ""))
424
(line (or (string->number lstr) 0))
425
(column (or (string->number cstr) 0)))
427
(go-to-column column)
428
(set! column (or (select-word sstr (cursor-tree) column) 0))
429
(set-message sstr (string-append lstr ":" (number->string column)))))
431
; FIXME? will this jump to HTML anchors?
432
(define html-file-post generic-file-post)
434
(define (default-post-handler u)
435
(with (base qry) (process-url u)
436
(with fm (file-format base)
437
(cond ((== fm "texmacs-file") (texmacs-file-post qry))
438
((== fm "generic-file") (generic-file-post qry))
439
((== fm "scheme-file") (source-file-post qry))
440
((== fm "cpp-file") (source-file-post qry))
441
((== fm "html-file") (html-file-post qry))
443
(display* "Unhandled format for default queries: " fm "\n"))))))
445
(define (http-post-handler u)
446
; TODO: jump to anchors in HTML
449
(define (default-root-handler u)
450
(if (url-or? (url-expand u))
451
(default-root-disambiguator (url-expand u))
452
(with (base qry) (process-url u)
453
(if (!= "" (url->string base))
454
(load-browse-buffer base)))))
456
(define (tmfs-root-handler u)
457
(load-browse-buffer u))
459
(define (http-root-handler u)
460
(load-browse-buffer u))
462
(define (url-handlers u)
463
(with root (or (and (url-rooted? u) (url-root u)) "default")
464
(cond ((== root "default")
465
(list default-root-handler default-post-handler))
467
(list tmfs-root-handler (lambda (x) (noop))))
468
((or (== root "http") (== root "https"))
469
(list http-root-handler http-post-handler))
470
(else (display* "Unhandled url root: " root "\n")
471
(list default-root-handler default-post-handler)))))
473
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
321
474
;; Actual navigation
322
475
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
326
479
(:argument opt-from "Optional path for the cursor history")
327
480
(with l (id->trees id)
330
(if (nnull? opt-from) (cursor-history-add (car opt-from)))
331
(tree-go-to (car l) :end)
332
(if (nnull? opt-from) (cursor-history-add (cursor-path))))
334
(delayed (:idle 25) (apply go-to-id (cons id opt-from)))))))
336
(define (decompose-url s)
337
(with i (string-index s #\#)
338
(if (not i) (list s "")
339
(list (substring s 0 i) (substring s (+ i 1) (string-length s))))))
341
(tm-define (go-to-url name-label . opt-from)
342
(:synopsis "Jump to the url @name-label.")
483
(if (nnull? opt-from) (cursor-history-add (car opt-from)))
484
(tree-go-to (car l) :end)
485
(if (nnull? opt-from) (cursor-history-add (cursor-path))))
487
(delayed (:idle 25) (apply go-to-id (cons id opt-from)))))))
489
(tm-define (go-to-url u . opt-from)
490
(:synopsis "Jump to the url @u")
343
491
(:argument opt-from "Optional path for the cursor history")
344
492
(if (nnull? opt-from) (cursor-history-add (car opt-from)))
345
(with (name label) (decompose-url name-label)
346
(cond ((== name "") (go-to-label label))
348
(with u (url-relative (buffer-master) name)
349
(load-browse-buffer u)))
351
(with u (url-relative (buffer-master) name)
352
(load-browse-buffer u)
353
(go-to-label label)))))
493
(if (string? u) (set! u (string->url u)))
494
(with (action post) (url-handlers u)
354
496
(if (nnull? opt-from) (cursor-history-add (cursor-path))))
356
498
(define (execute-at cmd opt-location)
360
502
(tm-define (execute-script s secure-origin? . opt-location)
361
503
(let* ((secure-s (string-append "(secure? '" s ")"))
362
(ok? (or secure-origin? (eval (string->object secure-s))))
363
(cmd-s (string-append "(lambda () " s ")"))
364
(cmd (eval (string->object cmd-s))))
504
(ok? (or secure-origin? (eval (string->object secure-s))))
505
(cmd-s (string-append "(lambda () " s ")"))
506
(cmd (eval (string->object cmd-s))))
365
507
(cond ((or ok? (== (get-preference "security") "accept all scripts"))
366
(execute-at cmd opt-location))
367
((== (get-preference "security") "prompt on scripts")
368
(user-confirm `(concat "Execute " ,s "?") #f
370
(when answ (execute-at cmd opt-location)))))
371
(else (set-message "Unsecure script refused" "Evaluate script")))))
508
(execute-at cmd opt-location))
509
((== (get-preference "security") "prompt on scripts")
510
(user-confirm `(concat "Execute " ,s "?") #f
512
(when answ (execute-at cmd opt-location)))))
513
(else (set-message "Unsecure script refused" "Evaluate script")))))
373
515
(define (go-to-vertex v attrs)
374
516
(cond ((func? v 'id 1) (go-to-id (cadr v) (cursor-path)))
375
((func? v 'url 1) (go-to-url (cadr v) (cursor-path)))
377
(with ok? (== (assoc-ref attrs "secure") "true")
378
(apply execute-script (cons* (cadr v) ok? (cddr v)))))
517
((func? v 'url 1) (go-to-url (escape-link-args (cadr v)) (cursor-path)))
519
(with ok? (== (assoc-ref attrs "secure") "true")
520
(apply execute-script (cons* (cadr v) ok? (cddr v)))))
381
523
(define (vertex-linked-ids v)
382
524
(let* ((lns (vertex->links v))
383
(vs (list-difference (append-map link-vertices lns) (list v))))
525
(vs (list-difference (append-map link-vertices lns) (list v))))
384
526
(list-remove-duplicates (filter-map vertex->id vs))))
386
528
(define (id-update id)
387
529
(let* ((ts1 (id->trees id))
388
(ts2 (id->trees (string-append "&" id)))
389
(pl (filter-map tree->path (append ts1 ts2))))
530
(ts2 (id->trees (string-append "&" id)))
531
(pl (filter-map tree->path (append ts1 ts2))))
390
532
(for-each update-all-path pl)))
392
534
(define (id-set-visited id)