87
107
:options '(flyspell-mode footnote-mode turn-on-auto-fill
88
108
highlight-changes-mode)
89
:set #'(lambda (sym val)
90
(when (featurep 'muse-wiki)
91
(add-to-list 'val 'muse-wiki-update-custom-values))
111
(defcustom muse-grep-command
112
"find %D -type f ! -name '*~' | xargs -I {} echo \\\"{}\\\" | xargs egrep -n -e \"%W\""
113
"The command to use when grepping for backlinks and other
114
searches through the muse projects. The string %D is replaced by
115
the directories from muse-project-alist, space-separated. The
116
string %W is replaced with the name of the muse page or whatever
117
else you are searching for. This command has been modified to
118
handle spaces in filenames, which were giving egrep a problem.
120
Note: We highly recommend using glimpse to search large projects.
121
To use glimpse, install and edit a file called .glimpse_exclude
122
in your home directory. Put a list of glob patterns in that file
123
to exclude Emacs backup files, etc. Then, run the indexer using:
125
glimpseindex -o <list of Wiki directories>
127
Once that's completed, customize this variable to have the
132
Your searches will go much, much faster, especially for very
133
large projects. Don't forget to add a user cronjob to update the
138
(defvar muse-insert-map
139
(let ((map (make-sparse-keymap)))
140
(define-key map "l" 'muse-insert-relative-link-to-file)
141
(define-key map "t" 'muse-insert-tag)
142
(define-key map "u" 'muse-insert-url)
95
146
(defvar muse-mode-map
96
147
(let ((map (make-sparse-keymap)))
97
148
(define-key map [(control ?c) (control ?a)] 'muse-index)
98
(define-key map [(control ?c) (control ?b)] 'muse-browse-result)
99
(define-key map [(control ?c) (control ?c)] 'muse-follow-name-at-point)
100
149
(define-key map [(control ?c) (control ?e)] 'muse-edit-link-at-point)
101
(define-key map [(control ?c) (control ?t)] 'muse-publish-this-file)
102
(define-key map [(control ?c) (control ?v)] 'muse-follow-name-at-point)
104
150
(define-key map [(control ?c) (control ?l)] 'font-lock-mode)
151
(define-key map [(control ?c) (control ?t)]
152
'muse-project-publish-this-file)
153
(define-key map [(control ?c) (control ?T)] 'muse-publish-this-file)
154
(define-key map [(control ?c) (meta control ?t)] 'muse-publish-this-file)
155
(define-key map [(control ?c) (control ?v)] 'muse-browse-result)
106
157
(define-key map [(control ?c) ?=] 'muse-what-changed)
127
178
(define-key map [(control ?c) (control ?f)] 'muse-project-find-file)
128
179
(define-key map [(control ?c) (control ?p)] 'muse-project-publish)
130
(define-key map [(control ?c) tab] 'muse-insert-tag)
131
(define-key map [(control ?c) (control ?i)] 'muse-insert-tag)
181
(define-key map [(control ?c) (control ?i)] 'muse-insert-thing)
182
(define-key map [(control ?c) tab] 'muse-insert-thing)
184
;; Searching functions
185
(define-key map [(control ?c) (control ?b)] 'muse-find-backlinks)
186
(define-key map [(control ?c) (control ?s)] 'muse-search)
188
;; Enhanced list functions
189
(define-key map [(meta return)] 'muse-insert-list-item)
190
(define-key map [(control ?>)] 'muse-increase-list-item-indentation)
191
(define-key map [(control ?<)] 'muse-decrease-list-item-indentation)
133
193
(when (featurep 'pcomplete)
134
194
(define-key map [(meta tab)] 'pcomplete)
233
295
(funcall (or (muse-get-keyword :major-mode (cadr project) t)
298
;;; Enhanced list editing
300
(defun muse-on-blank-line ()
301
"See if point is on a blank line"
304
(looking-at (concat "[" muse-regexp-blank "]?[\n]+"))))
306
(defun muse-get-paragraph-start ()
307
"Return the start of the current paragraph. This function will
308
return nil if there are no prior paragraphs and the beginning of
309
the line if point is on a blank line."
310
(let ((para-start (concat "[\n]+[" muse-regexp-blank "]?[\n]+")))
311
;; search back to start of paragraph
314
(if (not (muse-on-blank-line))
315
(re-search-backward para-start nil t)
316
(line-beginning-position))))))
318
(defun muse-insert-thing ()
319
"Prompt for something to insert into the current buffer."
321
(message "Insert:\nl link\nt Muse tag\nu URL")
323
(let ((overriding-local-map muse-insert-map))
324
(setq key (read-key-sequence nil)))
325
(if (commandp (setq cmd (lookup-key muse-insert-map key)))
327
(call-interactively cmd))
328
(message "Not inserting anything"))))
331
(defun muse-insert-list-item ()
332
"Insert a list item at the current point, taking into account
333
your current list type and indentation level."
335
(let ((newitem " - ")
337
(pstart (muse-get-paragraph-start))
338
(list-item (format muse-list-item-regexp
339
(concat "[" muse-regexp-blank "]*"))))
340
;; search backwards for start of current item
342
(when (re-search-backward list-item pstart t)
343
;; save the matching item
344
(setq newitem (match-string 0))
345
;; see what type it is
346
(if (string-match "::" (match-string 0))
347
;; is a definition, replace the term
348
(setq newitem (concat " "
349
(read-string "Term: ")
351
;; see if it's a numbered list
352
(when (string-match "[0-9]+" newitem)
353
;; is numbered, so increment
356
(match-string 0 newitem))))
357
(setq newitem (replace-match
358
(number-to-string itemno)
359
nil nil newitem))))))
360
;; insert the new item
361
(insert (concat "\n" newitem))))
363
(defun muse-alter-list-item-indentation (operation)
364
"Alter the indentation of the current list item.
365
Valid values of OPERATION are 'increase and 'decrease."
366
(let ((pstart (muse-get-paragraph-start))
367
(list-item (format muse-list-item-regexp
368
(concat "[" muse-regexp-blank "]*")))
369
beg move-func indent)
370
;; search backwards until start of paragraph to see if we are on a
373
(if (or (progn (goto-char (muse-line-beginning-position))
375
(looking-at list-item))
376
;; not on item, so search backwards
377
(re-search-backward list-item pstart t))
380
(setq indent (buffer-substring (match-beginning 0)
381
(match-beginning 1)))
382
(muse-forward-list-item (muse-list-item-type (match-string 1))
383
(concat "[" muse-regexp-blank "]*")
386
(narrow-to-region beg (point))
387
(goto-char (point-min))
389
(while (< (point) (point-max))
390
;; increase or decrease the indentation
392
(cond ((eq operation 'increase)
394
((eq operation 'decrease)
396
;; we have enough space, so delete it
397
(delete-region (match-beginning 0)
401
;; we are not on an item, so warn
402
(message "You are not on a list item.")))))
405
(defun muse-increase-list-item-indentation ()
406
"Increase the indentation of the current list item."
408
(muse-alter-list-item-indentation 'increase))
411
(defun muse-decrease-list-item-indentation ()
412
"Decrease the indentation of the current list item."
414
(muse-alter-list-item-indentation 'decrease))
236
416
;;; Support page name completion using pcomplete
238
(defun muse-completions ()
418
(defun muse-mode-completions ()
239
419
"Return a list of possible completions names for this buffer."
240
420
(let ((project (muse-project-of-file)))
242
422
(while (pcomplete-here
243
423
(mapcar 'car (muse-project-file-alist project)))))))
245
(defun muse-current-word ()
425
(defun muse-mode-current-word ()
246
426
(let ((end (point)))
248
428
(save-restriction
257
437
(let ((case-fold-search nil)
258
438
(inhibit-point-motion-hooks t)
259
439
(here (or pos (point))))
261
(and (char-after pos)
262
(not (eq (char-syntax (char-after pos)) ?\ ))))
265
;; Check for explicit link here or before point
266
(if (or (looking-at muse-explicit-link-regexp)
268
(re-search-backward "\\[\\[\\|\\]\\]"
269
(muse-line-beginning-position)
271
(string= (or (match-string 0) "") "[[")
272
(looking-at muse-explicit-link-regexp)))
274
(goto-char (match-beginning 1))
275
(muse-handle-explicit-link))
440
;; if we are using muse-colors, we can just use link properties to
441
;; determine whether we are on a link
442
(if (featurep 'muse-colors)
443
(when (get-text-property here 'muse-link)
445
(when (and (not (bobp))
446
(get-text-property (1- here) 'muse-link))
447
(goto-char (or (previous-single-property-change here 'muse-link)
449
(if (looking-at muse-explicit-link-regexp)
451
(goto-char (match-beginning 1))
452
(muse-handle-explicit-link))
453
(muse-handle-implicit-link))))
454
;; use fallback method to find a link
456
(and (char-after pos)
457
(not (eq (char-syntax (char-after pos)) ?\ ))))
277
;; Check for bare URL or other link type
278
(skip-chars-backward (concat "^'\"<>{}(\n" muse-regexp-blank))
279
(and (looking-at muse-implicit-link-regexp)
280
(muse-handle-implicit-link)))))))
460
;; check for explicit link here or before point
461
(if (or (looking-at muse-explicit-link-regexp)
463
(re-search-backward "\\[\\[\\|\\]\\]"
464
(muse-line-beginning-position)
466
(string= (or (match-string 0) "") "[[")
467
(looking-at muse-explicit-link-regexp)))
469
(goto-char (match-beginning 1))
470
(muse-handle-explicit-link))
472
;; check for bare URL or other link type
473
(skip-chars-backward (concat "^'\"<>{}(\n" muse-regexp-blank))
474
(and (looking-at muse-implicit-link-regexp)
475
(muse-handle-implicit-link))))))))
282
(defun muse-make-link (link &optional name)
283
"Return a link to LINK with NAME as the text."
477
(defun muse-make-link (link &optional desc)
478
"Return a link to LINK with DESC as the description."
284
479
(when (string-match muse-explicit-link-regexp link)
285
(unless name (setq name (match-string 2 link)))
286
(setq link (match-string 1 link)))
480
(unless desc (setq desc (muse-get-link-desc link)))
481
(setq link (muse-get-link link)))
289
(not (string= name ""))
290
(not (string= link name)))
291
(concat "[[" (muse-link-escape link) "][" (muse-link-escape name) "]]")
292
(concat "[[" (muse-link-escape link) "]]")))
484
(not (string= desc ""))
485
(not (string= link desc)))
486
(concat "[[" (muse-link-escape link) "][" (muse-link-escape desc) "]]")
487
(concat "[[" (or (muse-link-escape link) "") "]]")))
490
(defun muse-insert-relative-link-to-file ()
491
"Insert a relative link to a file, with optional description, at point."
492
;; Perhaps the relative location should be configurable, so that the
493
;; file search would start in the publishing directory and then
494
;; insert the link relative to the publishing directory
497
(muse-make-link (file-relative-name (read-file-name "Link: "))
498
(read-string "Text: "))))
500
(defun muse-insert-url ()
501
"Insert a URL, with optional description, at point."
504
(muse-make-link (read-string "URL: ")
505
(read-string "Text: "))))
295
508
(defun muse-edit-link-at-point ()
393
609
(defun muse-follow-name-at-mouse (event &optional other-window)
394
610
"Visit the link at point, or yank text if none is found."
395
611
(interactive "eN")
397
(cond ((fboundp 'event-window) ; XEmacs
398
(set-buffer (window-buffer (event-window event)))
399
(and (funcall (symbol-function 'event-point) event)
400
(goto-char (funcall (symbol-function 'event-point) event))))
401
((fboundp 'posn-window) ; Emacs
402
(set-buffer (window-buffer (posn-window (event-start event))))
403
(goto-char (posn-point (event-start event)))))
404
(let ((link (muse-link-at-point)))
406
(muse-visit-link link other-window)
407
;; Fall back to normal binding for this event
409
(lookup-key (current-global-map) (this-command-keys)))))))
614
(cond ((fboundp 'event-window) ; XEmacs
615
(set-buffer (window-buffer (event-window event)))
616
(and (funcall (symbol-function 'event-point) event)
617
(goto-char (funcall (symbol-function 'event-point)
619
((fboundp 'posn-window) ; Emacs
620
(set-buffer (window-buffer (posn-window (event-start event))))
621
(goto-char (posn-point (event-start event)))))
622
(let ((link (muse-link-at-point)))
624
(muse-visit-link link other-window)
626
;; Fall back to normal binding for this event
628
(lookup-key (current-global-map) (this-command-keys)))))
411
630
(defun muse-follow-name-at-mouse-other-window (event)
412
631
"Visit the link at point"
420
639
(defun muse-next-reference ()
421
640
"Move forward to next Muse link or URL, cycling if necessary."
423
(let ((cycled 0) pos)
425
(when (memq (get-text-property (point) 'face)
426
'(muse-link-face muse-bad-link-face))
427
(goto-char (or (next-single-property-change (point) 'face)
644
(when (get-text-property (point) 'muse-link)
645
(goto-char (or (next-single-property-change (point) 'muse-link)
430
(let ((next (point)))
431
(if (while (and (null pos)
433
(next-single-property-change
435
(when (memq (get-text-property next 'face)
436
'(muse-link-face muse-bad-link-face))
439
(goto-char (point-min))
440
(setq cycled (1+ cycled))))))
648
(setq pos (next-single-property-change (point) 'muse-link))
651
(if (get-text-property (point-min) 'muse-link)
652
(setq pos (point-min))
653
(setq pos (next-single-property-change (point-min) 'muse-link)))))
445
659
(defun muse-previous-reference ()
446
660
"Move backward to the next Muse link or URL, cycling if necessary.
661
In case of Emacs x <= 21 and ignoring of intangible properties (see
662
`muse-mode-intangible-links').
447
664
This function is not entirely accurate, but it's close enough."
449
(let ((cycled 0) pos)
452
(let ((prev (point)))
453
(if (while (and (null pos)
455
(previous-single-property-change
457
(when (memq (get-text-property prev 'face)
458
'(muse-link-face muse-bad-link-face))
461
(goto-char (point-max))
462
(setq cycled (1+ cycled))))))
669
;; Hack: The user perceives the two cases of point ("|")
670
;; position (1) "|[[" and (2) "[[|" or "][|" as "point is at
671
;; start of link". But in the sense of the function
672
;; "previous-single-property-change" these two cases are
673
;; different. The following code aligns these two cases. Emacs
674
;; 21: If the intangible property is ignored case (2) is more
675
;; complicate and this hack only solves the problem partially.
677
(when (and (get-text-property (point) 'muse-link)
678
(muse-looking-back "\\[\\|\\]"))
679
(goto-char (or (previous-single-property-change (point) 'muse-link)
682
(when (eq (point) (point-min))
683
(goto-char (point-max)))
685
(setq pos (previous-single-property-change (point) 'muse-link))
688
(if (get-text-property (point-min) 'muse-link)
689
(setq pos (point-min))
690
(setq pos (previous-single-property-change (point-max)
694
(if (get-text-property pos 'muse-link)
696
(goto-char (or (previous-single-property-change pos 'muse-link)
467
700
(defun muse-what-changed ()
470
703
(diff-backup buffer-file-name))
706
;;; Find text in project pages, or pages referring to the current page
708
(defvar muse-search-history nil)
710
(defun muse-grep (string &optional grep-command-no-shadow)
711
"Grep for STRING in the project directories.
712
GREP-COMMAND if passed will supplant `muse-grep-command'."
713
;; careful - grep-command leaks into compile, so we call it
714
;; -no-shadow instead
716
(let* ((str (or grep-command-no-shadow muse-grep-command))
717
(muse-directories (mapcar
721
(dirs (mapconcat (lambda (dir)
722
(shell-quote-argument
723
(expand-file-name dir)))
724
muse-directories " ")))
725
(while (string-match "%W" str)
726
(setq str (replace-match string t t str)))
727
(while (string-match "%D" str)
728
(setq str (replace-match dirs t t str)))
729
(if (fboundp 'compilation-start)
730
(compilation-start str nil (lambda (&rest args) "*search*")
732
(and (fboundp 'compile-internal)
733
(compile-internal str "No more search hits" "search"
734
nil grep-regexp-alist)))))
737
(defun muse-search-with-command (text)
738
"Search for the given TEXT string in the project directories
739
using the specified command."
741
(list (let ((str (concat muse-grep-command)) pos)
742
(when (string-match "%W" str)
743
(setq pos (match-beginning 0))
744
(unless (featurep 'xemacs)
746
(setq str (replace-match "" t t str)))
747
(read-from-minibuffer "Search command: "
748
(cons str pos) nil nil
749
'muse-search-history))))
750
(muse-grep nil text))
753
(defun muse-search ()
754
"Search for the given TEXT using the default grep command."
756
(muse-grep (read-string "Search: ")))
759
(defun muse-find-backlinks ()
760
"Grep for the current pagename in all the project directories."
762
(muse-grep (muse-page-name)))
472
765
;;; Generate an index of all known Muse pages
474
767
(defun muse-generate-index (&optional as-list exclude-private)