436
436
contents have changed. On Windows, it is always reread from
438
438
(setq project (muse-project project))
439
(let* ((file-alist (assoc (car project) muse-project-file-alist))
440
(last-mod (cdr (cdr file-alist))))
441
;; Determine the last modified of any directory mentioned in the
442
;; project's pattern list
443
(unless (or muse-under-windows-p no-check-p)
444
(let ((pats (cadr project)))
446
(if (symbolp (car pats))
447
(setq pats (cddr pats))
448
(let* ((fnd (file-name-directory (car pats)))
449
(dir (cond ((file-directory-p (car pats))
451
((and (not (file-readable-p (car pats)))
453
(file-directory-p fnd))
456
(let ((mod-time (nth 5 (file-attributes dir))))
457
(when (or (null last-mod)
459
(muse-time-less-p last-mod mod-time)))
460
(setq last-mod mod-time)))))
461
(setq pats (cdr pats))))))
462
;; Either return the currently known list, or read it again from
464
(if (or (and no-check-p (cadr file-alist))
465
muse-updating-file-alist-p
466
(not (or muse-under-windows-p
467
(null (cddr file-alist))
469
(muse-time-less-p (cddr file-alist) last-mod))))
472
(setcdr (cdr file-alist) last-mod)
473
(setq file-alist (cons (car project) (cons nil last-mod))
474
muse-project-file-alist
475
(cons file-alist muse-project-file-alist)))
476
;; Read in all of the file entries
477
(let ((muse-updating-file-alist-p t))
482
(let* ((names (list t))
483
(pats (cadr project)))
485
(if (symbolp (car pats))
486
(setq pats (cddr pats))
487
(nconc names (muse-project-file-entries (car pats)))
488
(setq pats (cdr pats))))
490
(run-hooks 'muse-project-file-alist-hook))))))
439
(when (and project muse-project-alist)
440
(let* ((file-alist (assoc (car project) muse-project-file-alist))
441
(last-mod (cdr (cdr file-alist))))
442
;; Determine the last modified of any directory mentioned in the
443
;; project's pattern list
444
(unless (or muse-under-windows-p no-check-p)
445
(let ((pats (cadr project)))
447
(if (symbolp (car pats))
448
(setq pats (cddr pats))
449
(let* ((fnd (file-name-directory (car pats)))
450
(dir (cond ((file-directory-p (car pats))
452
((and (not (file-readable-p (car pats)))
454
(file-directory-p fnd))
457
(let ((mod-time (nth 5 (file-attributes dir))))
458
(when (or (null last-mod)
460
(muse-time-less-p last-mod mod-time)))
461
(setq last-mod mod-time)))))
462
(setq pats (cdr pats))))))
463
;; Either return the currently known list, or read it again from
465
(if (or (and no-check-p (cadr file-alist))
466
muse-updating-file-alist-p
467
(not (or muse-under-windows-p
468
(null (cddr file-alist))
470
(muse-time-less-p (cddr file-alist) last-mod))))
473
(setcdr (cdr file-alist) last-mod)
474
(setq file-alist (cons (car project) (cons nil last-mod))
475
muse-project-file-alist
476
(cons file-alist muse-project-file-alist)))
477
;; Read in all of the file entries
478
(let ((muse-updating-file-alist-p t))
483
(let* ((names (list t))
484
(pats (cadr project)))
486
(if (symbolp (car pats))
487
(setq pats (cddr pats))
488
(nconc names (muse-project-file-entries (car pats)))
489
(setq pats (cdr pats))))
491
(run-hooks 'muse-project-file-alist-hook)))))))
492
493
(defun muse-project-of-file (&optional pathname)
493
494
"Determine which project the given PATHNAME relates to.
507
509
(let* ((file (file-truename pathname))
508
510
(dir (file-name-directory file))
509
(project-entry muse-project-alist)
511
(while (and project-entry (not found))
512
(let ((pats (car (cdar project-entry))))
513
(while (and pats (not found))
514
(if (symbolp (car pats))
515
(setq pats (cddr pats))
516
(let ((truename (file-truename (car pats))))
517
(if (or (string= truename file)
518
(string= truename dir)
519
(string-match (regexp-quote truename) file))
520
(setq found (car project-entry))))
521
(setq pats (cdr pats))))
522
(setq project-entry (cdr project-entry))))
511
found rating matches)
513
(dolist (project-entry muse-project-alist)
514
(let ((pats (cadr project-entry)))
516
(if (symbolp (car pats))
517
(setq pats (cddr pats))
518
(let ((tname (file-truename (car pats))))
519
(cond ((or (string= tname file)
521
(throw 'found project-entry))
522
((string-match (concat "\\`" (regexp-quote tname))
524
(setq matches (cons (cons (match-end 0)
527
(setq pats (cdr pats))))))
528
;; if we haven't found an exact match, pick a candidate
529
(car (muse-sort-by-rating matches))))))))
525
531
(defun muse-project-after-save-hook ()
526
532
"Update Muse's file-alist if we are saving a Muse file."
540
546
(if (and (not no-assume)
541
547
(= 1 (length muse-project-alist)))
542
548
(car muse-project-alist)
543
(assoc (completing-read prompt muse-project-alist)
549
(assoc (funcall muse-completing-read-function
550
prompt muse-project-alist)
544
551
muse-project-alist)))))
546
553
(defvar muse-project-page-history nil)
548
555
(defun muse-read-project-file (project prompt &optional default)
549
(let ((name (completing-read prompt (muse-project-file-alist project)
550
nil nil nil 'muse-project-page-history
556
(let ((name (funcall muse-completing-read-function
557
prompt (muse-project-file-alist project)
558
nil nil nil 'muse-project-page-history
552
560
(cons name (muse-project-page-file name project))))
636
644
(let ((include-regexp (muse-style-element :include style))
637
645
(exclude-regexp (muse-style-element :exclude style))
639
(when (and (or ignore-regexp
640
(and (null include-regexp)
647
(when (and (or (and (null include-regexp)
641
648
(null exclude-regexp))
642
649
(if include-regexp
643
650
(setq rating (string-match include-regexp file))
644
651
(not (string-match exclude-regexp file))))
645
(or (not (file-exists-p file))
646
(not (muse-project-private-p file))))
653
(not (muse-project-private-p file)))
647
654
(setq used-styles (cons (cons rating style) used-styles)))))
648
655
(muse-sort-by-rating (nreverse used-styles)))))
655
662
(cons (muse-get-keyword :base style) style))
656
663
(muse-project-applicable-styles file styles))))
665
(defun muse-project-resolve-directory (page local-style remote-style)
666
"Figure out the directory part of the path that provides a link to PAGE.
667
LOCAL-STYLE is the style of the current Muse file, and
668
REMOTE-STYLE is the style associated with PAGE.
670
If REMOTE-STYLE has a :base-url element, concatenate it and PAGE.
671
Otherwise, return a relative link."
672
(let ((prefix (muse-style-element :base-url remote-style)))
675
(file-relative-name (expand-file-name
676
(file-name-nondirectory page)
677
(muse-style-element :path remote-style))
679
(muse-style-element :path local-style))))))
658
681
(defun muse-project-resolve-link (page local-style remote-styles)
659
"Return a published relative link from the output path of one file
682
"Return a published link from the output path of one file to another file.
662
684
The best match for PAGE is determined by comparing the link
663
685
suffix of the given local style and that of the remote styles.
665
687
The remote styles are usually populated by
666
`muse-project-applicable-styles'."
688
`muse-project-applicable-styles'.
690
If no remote style is found, return PAGE verbatim
692
If PAGE has a :base-url associated with it, return the
693
concatenation of the :base-url value and PAGE.
695
Otherwise, return a relative path from the directory of
696
LOCAL-STYLE to the best directory among REMOTE-STYLES."
667
697
(let ((link-suffix (or (muse-style-element :link-suffix local-style)
668
698
(muse-style-element :suffix local-style)))
676
706
(if (null remote-style)
678
(muse-publish-link-file
679
(let ((prefix (muse-style-element :base-url remote-style)))
682
(file-relative-name (expand-file-name
683
(file-name-nondirectory page)
684
(muse-style-element :path remote-style))
686
(muse-style-element :path local-style)))))
708
(setq page (muse-project-resolve-directory
709
page local-style remote-style))
710
(concat (file-name-directory page)
711
(muse-publish-link-name page remote-style)))))
689
713
(defun muse-project-current-output-style (&optional file project)
690
714
(or muse-current-output-style
734
758
If FORCE is given, publish the file even if it is up-to-date."
735
759
(interactive (list current-prefix-arg))
736
(let* ((style (muse-project-get-applicable-style
737
buffer-file-name (cddr muse-current-project)))
738
(output-dir (muse-style-element :path style)))
739
(unless (muse-publish-file buffer-file-name style output-dir force)
740
(message (concat "The published version is up-to-date; use"
741
" C-u C-c C-t to force an update.")))))
760
(let ((muse-current-project (muse-project-of-file)))
761
(if (not muse-current-project)
762
;; file is not part of a project, so fall back to muse-publish
763
(if (interactive-p) (call-interactively 'muse-publish-this-file)
764
(muse-publish-this-file nil nil force))
765
(let* ((style (muse-project-get-applicable-style
766
buffer-file-name (cddr muse-current-project)))
767
(output-dir (muse-style-element :path style))
768
(muse-current-output-style (list :base (car style)
770
(unless (muse-publish-file buffer-file-name style output-dir force)
771
(message (concat "The published version is up-to-date; use"
772
" C-u C-c C-t to force an update.")))))))
743
774
(defun muse-project-save-buffers (&optional project)
744
775
(setq project (muse-project project))
748
(and (buffer-modified-p buffer)
749
(not (buffer-base-buffer buffer))
750
(or (buffer-file-name buffer)
753
(and buffer-offer-save
754
(> (buffer-size) 0))))
755
(with-current-buffer buffer
756
(let ((proj (muse-project-of-file)))
757
(and proj (string= (car proj)
759
(if (buffer-file-name buffer)
760
(format "Save file %s? "
761
(buffer-file-name buffer))
762
(format "Save buffer %s? "
763
(buffer-name buffer))))))
769
'("buffer" "buffers" "save")
770
(if (boundp 'save-some-buffers-action-alist)
771
save-some-buffers-action-alist)))
780
(and (buffer-modified-p buffer)
781
(not (buffer-base-buffer buffer))
782
(or (buffer-file-name buffer)
785
(and buffer-offer-save
786
(> (buffer-size) 0))))
787
(with-current-buffer buffer
788
(let ((proj (muse-project-of-file)))
789
(and proj (string= (car proj)
791
(if (buffer-file-name buffer)
792
(format "Save file %s? "
793
(buffer-file-name buffer))
794
(format "Save buffer %s? "
795
(buffer-name buffer))))))
801
'("buffer" "buffers" "save")
802
(if (boundp 'save-some-buffers-action-alist)
803
save-some-buffers-action-alist))))
773
805
(defun muse-project-publish-default (project styles &optional force)
774
806
"Publish the pages of PROJECT that need publishing."