1
;;; howm-mode.el --- Wiki-like note-taking tool
2
;;; Copyright (c) 2002, 2003, 2004, 2005
3
;;; by HIRAOKA Kazuyuki <khi@users.sourceforge.jp>
4
;;; $Id: howm-mode.el,v 1.285 2005/11/04 13:04:33 hira Exp $
6
;;; This program is free software; you can redistribute it and/or modify
7
;;; it under the terms of the GNU General Public License as published by
8
;;; the Free Software Foundation; either version 1, or (at your option)
11
;;; This program is distributed in the hope that it will be useful,
12
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
;;; GNU General Public License for more details.
16
;;; The GNU General Public License is available by anonymouse ftp from
17
;;; prep.ai.mit.edu in pub/gnu/COPYING. Alternately, you can write to
18
;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
20
;;;--------------------------------------------------------------------
22
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
;; Backward compatibility
25
;; (require 'howm-mode) in .emacs is obsolete. Use (require 'howm) instead.
27
;; This must be earlier than (require 'howm-common), because
28
;; howm-common needs cl, and (require 'cl) should be written in howm.el.
29
(when (not (featurep 'howm-version))
30
(message "Warning: Requiring howm-mode is obsolete. Require howm instead.")
35
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
(require 'howm-common)
40
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45
;; You can easily modify them.
48
(concat howm-view-title-header " %title%cursor\n%date %file\n\n")
49
"Contents of new file. %xxx are replaced with specified items.
50
If it is a list, <n>-th one is used when you type C-u <n> M-x howm-create.
51
If it is a function, it is called to get template string with the argument <n>.")
52
(defvar howm-keyword-header "<<<"
53
"Header string for declaration of keyword (implicit link).")
54
(defvar howm-ref-header ">>>"
55
"Header string for explicit link.")
56
(defvar howm-lighter " howm"
57
"Mode line for howm-mode")
59
(defvar howm-inhibit-title-file-match t
60
"If non-nil, inhibit howm-list-title when search string matches file name")
61
(defvar howm-list-all-title nil) ;; obsolete [2003-11-30]
62
(defvar howm-list-recent-title nil) ;; obsolete [2003-11-30]
63
(defvar howm-date-separator "-") ;; "-" ==> 2003-10-21
65
(defvar howm-default-key-table
67
;; ("key" func list-mode-p global-p)
69
("l" howm-list-recent t t)
70
("a" howm-list-all t t)
71
("g" howm-list-grep t t)
72
("s" howm-list-grep-fixed t t)
73
("m" howm-list-migemo t t)
74
("t" howm-list-todo t t)
75
("y" howm-list-schedule t t)
78
("." howm-find-today nil t)
79
(":" howm-find-yesterday nil t)
80
("A" howm-list-around)
81
("h" howm-history nil t)
83
("i" howm-insert-keyword nil t)
84
("d" howm-insert-date nil t)
85
("T" howm-insert-dtime nil t)
86
("K" howm-keyword-to-kill-ring t t)
87
("n" action-lock-goto-next-link)
88
("p" action-lock-goto-previous-link)
89
("Q" howm-kill-all t t)
90
(" " howm-toggle-buffer nil t)
92
("P" howm-previous-memo)
95
("C" howm-create-here nil t)
96
("I" howm-create-interactively nil t)
97
("w" howm-random-walk nil t)
99
"List of (key function list-mode-p).
100
`howm-prefix' + this key is real stroke.
101
If optional argument list-mode-p is non-nil,
102
same key is also available in view mode."
105
(defvar howm-migemo-client nil)
106
;; (defvar howm-migemo-client "migemo-client")
110
;; Be careful to keep consistency.
112
(defvar howm-keyword/ref-regexp-format "\\(%s\\)[ \t]*\\([^ \t\r\n].*\\)")
113
(defvar howm-keyword-format (format "%s %%s" howm-keyword-header)
114
"Format for declaration of keyword. See `format'.")
115
(defvar howm-keyword-regexp (format howm-keyword/ref-regexp-format
116
(regexp-quote howm-keyword-header)))
117
(defvar howm-keyword-regexp-hilit-pos 1)
118
(defvar howm-keyword-regexp-pos 2)
119
(defvar howm-ref-regexp (format howm-keyword/ref-regexp-format
120
(regexp-quote howm-ref-header))
121
"Regexp for explicit link.")
122
(defvar howm-ref-regexp-hilit-pos 0
123
"Position of search string in `howm-ref-regexp'")
124
(defvar howm-ref-regexp-pos 2
125
"Position of search string in `howm-ref-regexp'")
126
(defvar howm-wiki-regexp "\\[\\[\\([^]\r\n]+\\)\\]\\]"
127
"Regexp for explicit link.")
128
(defvar howm-wiki-regexp-hilit-pos 1
129
"Position of hilight in `howm-wiki-regexp'")
130
(defvar howm-wiki-regexp-pos 1
131
"Position of search string in `howm-wiki-regexp'")
132
(defvar howm-wiki-format "[[%s]]"
133
"Format for declaration of wiki word. See `format'.")
134
;; (defvar howm-wiki-regexp "\\[\\[\\([^]\r\n]+\\)\\(\\]\\]\\)"
135
;; "Regexp for explicit link.")
136
;; (defvar howm-wiki-regexp-hilit-pos 2
137
;; "Position of search string in `howm-wiki-regexp'")
138
;; (defvar howm-wiki-regexp-pos 1
139
;; "Position of search string in `howm-wiki-regexp'")
141
;; Fix me: redundant (howm-date-* & howm-reminder-*)
142
(defvar howm-date-regexp-grep
143
(concat "[1-2][0-9][0-9][0-9]" howm-date-separator
144
"[0-1][0-9]" howm-date-separator
146
(defvar howm-date-regexp
147
(concat "\\([1-2][0-9][0-9][0-9]\\)" howm-date-separator
148
"\\([0-1][0-9]\\)" howm-date-separator
150
(defvar howm-date-regexp-year-pos 1)
151
(defvar howm-date-regexp-month-pos 2)
152
(defvar howm-date-regexp-day-pos 3)
153
(defvar howm-date-format
154
(concat "%Y" howm-date-separator "%m" howm-date-separator "%d"))
155
(defvar howm-dtime-body-format
156
(concat howm-date-format " %H:%M"))
157
(defvar howm-dtime-format
158
(concat "[" howm-dtime-body-format "]"))
159
(defvar howm-insert-date-format "[%s]")
160
(defvar howm-insert-date-future nil)
162
(defvar howm-template-rules
163
'(("%title" . howm-template-title)
164
("%date" . howm-template-date)
165
("%file" . howm-template-previous-file)
166
("%cursor" . howm-template-cursor))) ;; Cursor must be the last rule.
167
(defvar howm-template-date-format howm-dtime-format
168
"%date is replaced with `howm-template-date-format'
169
in `howm-template'. See `format-time-string'")
170
(defvar howm-template-file-format (concat howm-ref-header " %s")
171
"%file is replaced with `homw-template-file-format'
172
in `howm-template'. %s is replaced with name of last file. See `format'.")
178
(defun howm-action-lock-general (command regexp pos
182
`(lambda (&optional dummy)
183
(let ((s (match-string-no-properties ,pos)))
184
;; (when howm-keyword-case-fold-search
185
;; (setq s (downcase s)))
186
(,command s ,@options)))
190
(defun howm-action-lock-search (regexp
192
&optional hilit-pos create-p open-unique-p)
193
(howm-action-lock-general 'howm-keyword-search
194
regexp pos hilit-pos create-p open-unique-p))
195
(defun howm-action-lock-related (regexp pos hilit-pos)
196
(howm-action-lock-general 'howm-list-related regexp pos hilit-pos))
198
(defun howm-action-lock-date-rule ()
199
(action-lock-general 'howm-action-lock-date howm-date-regexp 0 0))
201
(defun howm-action-lock-setup ()
202
(setq action-lock-case-fold-search howm-keyword-case-fold-search)
204
(let* ((date-al (action-lock-date "{_}" howm-dtime-format)))
205
;; override the rule in action-lock.el
206
(action-lock-add-rules (list date-al) t))
207
(let* ((ks (howm-keyword-for-goto))
208
(r (mapconcat 'regexp-quote ks "\\|"))
209
(wiki (howm-action-lock-search howm-wiki-regexp
211
howm-wiki-regexp-hilit-pos
214
;; (explicit (howm-action-lock-goto howm-ref-regexp
215
(explicit (howm-action-lock-search howm-ref-regexp
217
howm-ref-regexp-hilit-pos
219
(implicit (howm-action-lock-search r 0))
220
(rev (howm-action-lock-related howm-keyword-regexp
221
howm-keyword-regexp-pos
222
howm-keyword-regexp-hilit-pos))
223
(date (howm-action-lock-date-rule))
224
(done (howm-action-lock-reminder-done-rule))
228
,@(if ks (list implicit) nil)
230
,@(if (howm-menu-p) nil (list date done))
233
;; don't override the rule in action-lock.el
234
;; esp. http://xxx should call browser even if "<<< http" exists
235
(action-lock-add-rules all)))
237
(defun howm-file-name (&optional time)
238
(format-time-string howm-file-name-format
239
(or time (current-time))))
241
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
244
(easy-mmode-define-minor-mode howm-mode
245
"With no argument, this command toggles the mode.
246
Non-null prefix argument turns on the mode.
247
Null prefix argument turns off the mode.
249
When the mode is enabled, underlines are drawn on texts which match
250
to titles of other files. Typing \\[action-lock-magic-return] there,
251
you can jump to the corresponding file.
255
\\[action-lock-magic-return] Follow link
256
\\[howm-refresh] Refresh buffer
257
\\[howm-list-all] List all files
258
\\[howm-list-grep] Search (grep)
259
\\[howm-create] Create new file
260
\\[howm-dup] Duplicate current file
261
\\[howm-insert-keyword] Insert keyword
262
\\[howm-insert-date] Insert date
263
\\[howm-insert-dtime] Insert date with time
264
\\[howm-keyword-to-kill-ring] Copy current keyword to kill ring
265
\\[action-lock-goto-next-link] Go to next link
266
\\[action-lock-goto-previous-link] Go to previous link
267
\\[howm-next-memo] Go to next entry in current buffer
268
\\[howm-previous-memo] Go to previous entry in current buffer
269
\\[howm-first-memo] Go to first entry in current buffer
270
\\[howm-last-memo] Go to last entry in current buffer
271
\\[howm-create-here] Add new entry to current buffer
272
\\[howm-create-interactively] Create new file interactively (not recommended)
273
\\[howm-random-walk] Browse random entries automtically
276
howm-lighter ;; mode-line
278
,@(mapcar (lambda (entry)
279
(let ((k (car entry))
281
(cons (concat howm-prefix k) f)))
282
howm-default-key-table)
285
(add-hook 'howm-mode-on-hook 'howm-initialize-buffer)
286
(add-hook 'howm-mode-off-hook 'howm-restore-buffer)
288
(defun howm-set-keymap ()
289
(mapc (lambda (entry)
290
(let* ((k (car entry))
292
(list-mode-p (third entry))
293
(global-p (fourth entry))
294
(pk (concat howm-prefix k)))
295
(define-key howm-mode-map pk f)
300
(list howm-view-summary-mode-map
301
howm-view-contents-mode-map)))
303
(define-key global-map pk f))))
304
howm-default-key-table)
305
(define-key howm-mode-map "\C-x\C-s" 'howm-save-buffer)
309
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312
(defun howm-refresh ()
316
(howm-initialize-buffer)))
318
(defun howm-initialize-buffer ()
320
(when (not howm-mode)
321
(error "Not howm-mode"))
322
(howm-message-time "init-buf"
325
(howm-set-configuration-for-major-mode major-mode)
326
(howm-action-lock-setup)
327
(howm-mode-add-font-lock)
328
(howm-reminder-add-font-lock)
329
;; font-lock-fontify-buffer is necessary for emacs20,
330
;; while -block is necessary for emacs21.
331
;; I don't understand this. [2004-12-18]
333
;; make-local-hook is obsolete for emacs >= 21.1.
334
(make-local-hook 'after-save-hook)
335
(add-hook 'after-save-hook 'howm-after-save t t))))
337
(defun howm-after-save ()
339
(howm-keyword-add-current-buffer)
340
(when howm-refresh-after-save
341
(howm-initialize-buffer))
342
(when (and howm-menu-refresh-after-save
343
(> howm-menu-expiry-hours 0))
344
(howm-menu-refresh-background))
345
(run-hooks 'howm-after-save-hook)))
347
(defun howm-restore-buffer ()
348
(action-lock-mode 0))
350
(defun howm-list-all ()
352
(howm-set-command 'howm-list-all)
353
(howm-view-directory (car (howm-search-path)) t)
354
(howm-list-normalize)
355
;; clean me [2004-07-11]
356
(cond ((howm-list-title-p) t) ;; already done in (howm-list-normalize)
357
(howm-list-all-title (howm-list-title))))
359
(defun howm-list-recent (&optional days)
361
(howm-set-command 'howm-list-recent)
362
(let* ((d (or days howm-list-recent-days))
364
(from (howm-days-before now d)))
365
(howm-view-directory howm-directory t)
366
(howm-view-filter-by-mtime nil (list from now))
367
(howm-list-normalize)
368
;; clean me [2003-11-30]
369
(cond ((howm-list-title-p) t) ;; already done in (howm-list-normalize)
370
(howm-list-recent-title (howm-list-title))
371
((not days) (howm-view-summary-to-contents)))))
373
;; clean me: direct access to howm-view-* is undesirable.
375
(defvar howm-list-title-previous nil
377
(make-variable-buffer-local 'howm-list-title-previous)
378
(defun howm-list-title-put-previous ()
379
(when howm-list-title-undo
380
(setq howm-list-title-previous (howm-view-item-list))))
381
(defun howm-list-title-get-previous ()
382
(if howm-list-title-undo
383
(let ((prev howm-list-title-previous))
384
(setq howm-list-title-previous nil)
385
(howm-view-summary-rebuild prev))
386
(error "Undo is not enabled.")))
387
(defun howm-list-title-regexp ()
388
(or howm-list-title-regexp (howm-view-title-regexp-grep)))
389
(defun howm-list-title (&optional undo)
391
(if (or undo howm-list-title-previous)
392
(howm-list-title-get-previous)
393
(let ((b (current-buffer)))
394
(howm-list-title-put-previous)
395
(howm-view-list-title (howm-list-title-regexp))
396
;; (howm-view-filter-by-contents (howm-list-title-regexp))
397
(let ((c (current-buffer)))
400
(howm-view-kill-buffer)
402
(howm-view-summary-check t))))))
404
(defun howm-list-title-p ()
405
(let ((a (howm-get-value howm-list-title)))
406
(cond ((null a) nil) ;; I know this is redundant.
407
((listp a) (member (howm-command) a))
410
(defun howm-days-after (ti days &optional hours)
411
(let* ((ne (decode-time ti))
414
(nh (nth hour-pos ne))
415
(nd (nth day-pos ne)))
416
(setf (nth hour-pos ne) (+ nh (or hours 0)))
417
(setf (nth day-pos ne) (+ nd days))
418
(apply #'encode-time ne)))
420
(defun howm-days-before (ti days)
421
(howm-days-after ti (- days)))
423
(defun howm-list-grep (&optional completion-p)
425
(howm-set-command 'howm-list-grep)
426
(howm-list-grep-general completion-p))
428
(defun howm-list-grep-fixed ()
430
(howm-set-command 'howm-list-grep-fixed)
431
(howm-list-grep-general t))
433
(defun howm-list-grep-general (&optional completion-p)
434
(let* ((regexp (if completion-p
435
(howm-completing-read-keyword)
436
(read-from-minibuffer "Search all (grep): "))))
437
(when completion-p ;; Goto link works only for fixed string at now.
438
(howm-write-history regexp))
439
(howm-search regexp completion-p)))
441
(defun howm-search (regexp fixed-p &optional emacs-regexp)
442
(if (string= regexp "")
444
(howm-message-time "search"
446
(howm-call-view-search regexp fixed-p emacs-regexp)
447
(howm-list-normalize (or emacs-regexp regexp))))))
449
(defvar *howm-view-window-configuration* nil
451
(defun howm-view-window-configuration ()
452
*howm-view-window-configuration*)
453
(defun howm-set-view-window-configuration (conf)
454
(setq *howm-view-window-configuration* conf))
455
(defun howm-record-view-window-configuration ()
456
(howm-set-view-window-configuration (current-window-configuration)))
457
(defun howm-restore-view-window-configuration ()
458
(set-window-configuration (howm-view-window-configuration)))
459
(defun howm-return-to-list ()
461
(howm-restore-view-window-configuration))
463
(defun howm-call-view-search (regexp fixed-p &optional emacs-regexp)
464
(let ((hilit (if emacs-regexp
465
`((,emacs-regexp . howm-view-hilit-face))
467
(howm-view-search-folder regexp (howm-search-path-folder)
468
nil nil fixed-p hilit)
469
(howm-record-view-window-configuration)))
471
(defun howm-list-migemo (&optional completion-p)
473
(howm-set-command 'howm-list-migemo)
476
(let* ((roma (read-from-minibuffer "Search all (migemo): "))
477
(e-reg (howm-migemo-get-pattern roma "emacs"))
478
(g-reg (if howm-view-use-grep
479
(howm-migemo-get-pattern roma "egrep")
481
(if (and e-reg g-reg)
482
(howm-search g-reg nil e-reg)
483
(message "No response from migemo-client.")))))
486
(defun howm-migemo-get-pattern (roma type)
487
(when (and (null howm-migemo-client) (not howm-view-use-grep))
489
(if (and (featurep 'migemo) (string= type "emacs"))
490
(howm-funcall-if-defined (migemo-get-pattern roma))
491
;; (migemo-get-pattern roma)
492
(car (howm-call-process (or howm-migemo-client "migemo-client")
493
`("-t" ,type ,roma) 0))))
495
(defun howm-list-normalize (&optional keyword comefrom-regexp no-list-title)
496
"Sort displayed items in the standard order.
497
--- Sorry, below documentation is incomplete. ---
498
When KEYWORD is given, matched items are placed on the top.
499
KEYWORD can be a string or a list of strings.
501
;; (let ((*howm-view-summary-nop* t)) ;; dirty
502
(let ((matched (howm-view-in-background
503
(howm-list-normalize-subr keyword comefrom-regexp
508
(defun howm-list-normalize-subr (keyword comefrom-regexp no-list-title)
511
(funcall howm-list-normalizer)
513
(let ((key-reg (or comefrom-regexp
514
(howm-make-keyword-regexp1 keyword)))
515
(word-reg (format "\\<%s\\>"
516
(if (stringp keyword)
517
(regexp-quote keyword)
518
(regexp-opt keyword t))))
519
(wiki-reg (regexp-quote (howm-make-wiki-string keyword)))
523
(regexp-quote (expand-file-name keyword)))))
524
(case-fold-search howm-keyword-case-fold-search))
525
(let ((check (lambda (tag flag reg)
528
(howm-view-sort-by-name-match nil reg t)
529
(howm-view-sort-by-summary-match nil reg))
530
(setq matched (cons tag matched))))))
531
(funcall check 'word howm-list-prefer-word word-reg)
532
(funcall check 'wiki howm-list-prefer-wiki wiki-reg)
533
(funcall check 'related-keyword t howm-keyword-regexp)
534
(funcall check 'keyword t key-reg)
535
(funcall check 'file file-reg file-reg))))
536
(when (and (howm-list-title-p)
538
(not (and (member 'file matched)
539
howm-inhibit-title-file-match)))
543
(defun howm-make-keyword-string (keyword)
544
(format howm-keyword-format keyword))
545
(defun howm-make-wiki-string (keyword)
546
(format howm-wiki-format keyword))
549
(defvar howm-keyword-regexp-format "%s$"
550
"Format to make entire-match regexp from keyword string.
551
Default is \"%s$\" because we want to make regexp \"<<< foo$\"
552
from keyword string \"<<< foo\",
553
so that we can accept \"<<< foo\" and reject \"<<< foobar\".
554
We need entire-match in order to
555
(1) place \"<<< foo\" on the top when \"foo\" is searched, and
556
(2) judge existence of \"<<< foo\" when [[foo]] is hit.")
557
(defun howm-make-keyword-regexp1 (keyword)
558
(howm-make-keyword-regexp-general keyword #'howm-make-keyword-regexp1-sub))
559
(defun howm-make-keyword-regexp2 (keyword)
560
(howm-make-keyword-regexp-general keyword #'howm-make-keyword-regexp2-sub))
561
(defun howm-make-keyword-regexp1-sub (keyword)
562
(format howm-keyword-regexp-format
563
(regexp-quote (howm-make-keyword-string keyword))))
564
(defun howm-make-keyword-regexp2-sub (keyword)
565
(format howm-keyword-regexp-format
566
(howm-make-keyword-string (regexp-quote keyword))))
567
(defun howm-make-keyword-regexp-general (keyword regexp-generator)
568
(cond ((stringp keyword)
569
(funcall regexp-generator keyword))
571
(mapconcat (lambda (s)
573
(funcall regexp-generator s)
577
(t (error "Wrong type: %s" keyword))))
579
(defun howm-list-related (str)
580
(howm-set-command 'howm-list-related)
581
(let ((keys (mapcar (lambda (k)
582
(if howm-keyword-case-fold-search
585
(howm-subkeyword str))))
586
(howm-search (howm-make-keyword-string ".*") nil)
587
(howm-view-filter-by-summary nil (regexp-opt keys))))
588
(defun howm-subkeyword (str)
591
(howm-keyword-for-goto)))
593
(defun howm-list-around ()
595
(howm-set-command 'howm-list-around)
596
(let ((f (buffer-file-name)))
598
(howm-view-sort-by-reverse-date)
599
(let ((pos (howm-cl-position-if (lambda (item)
600
(string= (howm-view-item-filename item)
602
(howm-view-item-list))))
603
(goto-char (point-min))
606
(howm-view-summary-check t)))
608
(defvar *howm-command* nil
610
(defun howm-set-command (com)
611
(setq *howm-command* com))
612
(defun howm-command ()
615
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
618
(defun howm-create (&optional which-template here)
620
(let* ((t-c (howm-create-default-title-content))
623
(howm-create-file-with-title title which-template nil here content)))
625
(howm-dont-warn-free-variable transient-mark-mode)
626
(howm-dont-warn-free-variable mark-active)
627
(defun howm-create-default-title-content ()
629
(m (or (mark t) -777))
632
(search-str (howm-view-name)))
633
(let* ((transient-mark-p (and (boundp 'transient-mark-mode)
634
transient-mark-mode))
635
(mark-active-p (and (boundp 'mark-active) mark-active))
636
(active-p (if transient-mark-p
639
(strictly-active-p (and transient-mark-p mark-active-p))
640
(title-p (let* ((b (line-beginning-position))
641
(e (line-end-position)))
643
(< 0 beg) (<= b beg) (<= end e) (not (= beg end)))))
644
(content-p (and strictly-active-p
645
howm-content-from-region))
646
(search-p (and howm-title-from-search
647
(stringp search-str)))
648
(s (cond ((or title-p content-p) (buffer-substring-no-properties beg
650
(search-p search-str))))
651
(cond ((null s) (cons "" ""))
652
((eq content-p t) (cons "" s))
653
((or title-p search-p) (cons s ""))
654
(content-p (cons "" s))
657
(defun howm-create-here (&optional which-template)
659
(howm-create which-template t))
661
(defun howm-create-file-with-title (title &optional
662
which-template not-use-file here content)
663
(let ((b (current-buffer)))
666
(cond ((howm-buffer-empty-p) nil)
667
((and here howm-create-here-just) (beginning-of-line))
668
(t (howm-create-newline)))
670
(insert-f (lambda (switch)
671
(howm-insert-template (if switch title "")
672
b which-template (not switch))))
673
(use-file (not not-use-file)))
674
;; second candidate which appears when undo is called
675
(let ((end (funcall insert-f not-use-file)))
678
(insert (or content "")))
680
(delete-region p end))
681
(funcall insert-f use-file))
683
(run-hooks 'howm-create-hook)))
685
(defun howm-create-newline ()
688
(howm-create-newline-prepend)
689
(howm-create-newline-append)))
690
(defun howm-create-newline-prepend ()
691
(goto-char (point-min)))
692
(defun howm-create-newline-append ()
693
(goto-char (point-max))
695
(when (not (= (line-beginning-position) (point))) ;; not empty line
699
(defun howm-insert-template (title &optional
700
previous-buffer which-template not-use-file)
702
(f (buffer-file-name previous-buffer))
703
(af (and f (howm-abbreviate-file-name f))))
704
(insert (howm-template-string which-template previous-buffer))
705
(let* ((date (format-time-string howm-template-date-format))
706
(use-file (not not-use-file))
707
(file (cond ((not use-file) "")
709
((string= f (buffer-file-name)) "")
710
(t (format howm-template-file-format af)))))
711
(let ((arg `((title . ,title) (date . ,date) (file . ,file)))
712
(end (point-marker)))
713
(howm-replace howm-template-rules arg beg end)
716
(defvar howm-template-receive-buffer t
717
"Non nil if howm-template should receive previous-buffer
718
when howm-template is a function.
719
Set this option to nil if backward compatibility with howm-1.2.4 or earlier
722
(defun howm-template-string (which-template previous-buffer)
723
;; which-template should be 1, 2, 3, ...
724
(setq which-template (or which-template 1))
725
(cond ((stringp howm-template) howm-template)
726
((listp howm-template) (nth (- which-template 1) howm-template))
727
((functionp howm-template) (let ((args (if howm-template-receive-buffer
730
(list which-template))))
731
(apply howm-template args)))))
733
(defun howm-replace (rules arg &optional beg end)
735
(let ((spell (car pair))
737
(goto-char (or beg (point-min)))
738
(while (re-search-forward spell end t)
739
(delete-region (match-beginning 0) (match-end 0))
740
(funcall disp-f arg))))
743
;; Use dynamic bindings dirtily!
744
(defun howm-template-title (arg)
745
(insert (cdr (assoc 'title arg))))
746
(defun howm-template-date (arg)
747
(insert (cdr (assoc 'date arg))))
748
(defun howm-template-previous-file (arg)
749
(insert (cdr (assoc 'file arg))))
750
(defun howm-template-cursor (arg)) ;; do nothing
754
(let* ((r (howm-view-paragraph-region))
755
(s (buffer-substring-no-properties (car r) (second r))))
760
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
763
(defun howm-completing-read-keyword ()
764
(message "Scanning...")
765
(let* ((kl (howm-keyword-list))
766
(table (mapcar #'list kl))
767
(completion-ignore-case howm-keyword-case-fold-search))
768
(completing-read "Keyword: " table)))
770
(defun howm-insert-keyword ()
772
(insert (howm-completing-read-keyword)))
774
(defun howm-keyword-to-kill-ring (&optional filename-p)
776
(let ((title (howm-title-at-current-point filename-p)))
778
(howm-string-to-kill-ring title)
779
(error "No keyword."))))
781
(defun howm-title-at-current-point (&optional filename-p
782
title-regexp title-regexp-pos)
783
(let ((reg (or title-regexp howm-view-title-regexp))
784
(pos (or title-regexp-pos howm-view-title-regexp-pos)))
787
(cond ((and (not filename-p)
788
(re-search-backward reg nil t))
789
(match-string-no-properties pos))
791
(howm-abbreviate-file-name (buffer-file-name)))
794
(defun howm-string-to-kill-ring (str)
801
(defun howm-keyword-for-comefrom ()
803
(goto-char (point-min))
804
(let ((keyword-list nil))
805
(while (re-search-forward howm-keyword-regexp nil t)
807
(cons (match-string-no-properties howm-keyword-regexp-pos)
809
(reverse keyword-list))))
811
(defun howm-keyword-list ()
812
(let ((sep (format "[\n%s]" (or howm-keyword-list-alias-sep ""))))
813
(with-current-buffer (howm-keyword-buffer)
815
(split-string (buffer-substring (point-min) (point-max)) sep)))))
817
(defun howm-keyword-add (keyword-list)
818
(interactive "sKeyword: ")
819
(setq keyword-list (if (stringp keyword-list)
823
(set-buffer (howm-keyword-buffer))
824
(goto-char (point-max))
826
(when (howm-keyword-new-p k)
829
(when (buffer-file-name)
830
(howm-basic-save-buffer))
833
(defun howm-keyword-new-p (str)
835
(let ((r (format "^%s$" (regexp-quote str)))
836
(case-fold-search howm-keyword-case-fold-search))
837
(goto-char (point-min))
838
(not (re-search-forward r nil t)))))
840
(defun howm-support-aliases-p ()
841
howm-keyword-list-alias-sep)
842
(defun howm-aliases ()
843
(if (howm-support-aliases-p)
846
(defun howm-read-aliases ()
847
(with-current-buffer (howm-keyword-buffer)
850
(goto-char (point-min))
851
(while (search-forward howm-keyword-list-alias-sep nil t)
852
(let ((line (buffer-substring-no-properties (line-beginning-position)
853
(line-end-position))))
855
(cons (split-string line howm-keyword-list-alias-sep) ans))
859
(defun howm-expand-aliases-recursively (keyword aliases)
860
(let ((keys (list keyword))
862
(flet ((expand (keys)
863
(sort (howm-cl-remove-duplicates
864
(howm-cl-mapcan (lambda (k)
866
(lambda (a) (if (member k a)
870
keys) :test #'string=)
872
(while (not (equal prev keys))
874
(setq keys (expand keys))))
876
(assert (equal (howm-expand-aliases-recursively "a"
877
'(("d" "e" "f") ("a" "b" "c")))
879
(assert (equal (howm-expand-aliases-recursively "a"
880
'(("d" "e" "b") ("a" "b" "c")))
881
'("a" "b" "c" "d" "e")))
883
(defun howm-keyword-aliases (keyword)
884
"List of strings which are equivalent to KEYWORD.
885
KEYWORD itself is always at the head of the returneded list.
887
(let* ((aliases (howm-aliases))
888
(equiv (if howm-keyword-aliases-recursive
889
(howm-expand-aliases-recursively keyword aliases)
890
(howm-cl-remove-duplicates
892
(howm-cl-remove-if-not (lambda (a) (member keyword a))
896
(cons keyword (remove keyword equiv)))))
898
(defun howm-keyword-search (keyword &optional create-p open-unique-p)
899
(howm-message-time "key-search"
900
(howm-set-command 'howm-keyword-search)
901
(howm-keyword-search-subr keyword create-p open-unique-p)))
903
(defun howm-keyword-search-subr (keyword create-p open-unique-p)
904
(let* ((wconf (current-window-configuration))
905
(aliases (if (howm-support-aliases-p)
906
(howm-keyword-aliases keyword)
908
(menu-p (howm-menu-keyword-p keyword))
909
(comefrom-regexp (if menu-p
911
(howm-make-keyword-regexp2 aliases)))
912
(found (let ((howm-search-other-dir (if menu-p
914
howm-search-other-dir))
915
(*howm-view-force-case-fold-search* howm-keyword-case-fold-search)) ;; dirty!
916
(howm-call-view-search aliases t)))
917
;; code for <http://pc8.2ch.net/test/read.cgi/unix/1077881095/823>.
918
;; but this change is canceled; I'll try more fundamental fix. [2005-11-04]
920
;; (let ((r (concat "^" (regexp-quote keyword) "$")))
921
;; (howm-call-view-search r nil))
922
;; (howm-call-view-search aliases t))))
923
(matched (and found (howm-list-normalize aliases comefrom-regexp t)))
924
(keyword-matched (member 'keyword matched))
925
(file-matched (member 'file matched))
926
(title (howm-make-keyword-string keyword)))
927
;; main processing (clean me!) [2003-12-01]
930
((and menu-p keyword-matched)
931
(howm-keyword-search-open-menu keyword wconf))
933
((and create-p (not keyword-matched))
934
(howm-keyword-search-create title))
935
;; open if unique match
936
((and open-unique-p (howm-single-element-p (howm-view-item-list)))
937
(howm-keyword-search-open-unique wconf))
941
(not (and file-matched howm-inhibit-title-file-match)))
945
(howm-write-history keyword))
946
;; return information
950
(keyword-matched . ,keyword-matched)
951
(create-p . ,create-p))
954
(defun howm-keyword-search-open-menu (keyword wconf)
955
"Open KEYWORD as menu."
956
;; dirty. peeking howm-view.el
957
(let* ((item (car (howm-view-item-list)))
958
(fname (howm-view-item-filename item))
959
(place (howm-view-item-place item)))
960
(howm-view-kill-buffer)
961
(set-window-configuration wconf)
962
(howm-menu-open fname place
963
(howm-menu-name keyword))))
965
(defun howm-keyword-search-create (title)
966
"create new memo <<< TITLE."
967
(howm-view-kill-buffer)
968
(howm-create-file-with-title title)
969
(message "New keyword."))
971
(defun howm-keyword-search-open-unique (wconf)
973
;; dirty. peeking howm-view.el
974
(howm-view-summary-open)
975
(let ((b (current-buffer)))
976
(set-window-configuration wconf)
977
(switch-to-buffer b)))
979
;; (defvar *howm-keyword-buffer* nil) ;; for internal use
980
(defun howm-keyword-for-goto ()
982
(let ((keys (howm-keyword-list))
983
(case-fold-search howm-keyword-case-fold-search))
984
(sort (howm-cl-mapcan (lambda (k)
985
(goto-char (point-min))
986
(if (search-forward k nil 'noerr)
991
(> (length x) (length y)))))))
993
(defun howm-keyword-add-current-buffer ()
995
(goto-char (point-min))
996
(let ((m (current-message))
998
(while (re-search-forward howm-keyword-regexp nil t)
999
(let ((key-str (if howm-keyword-list-alias-sep
1000
(mapconcat #'identity
1002
howm-keyword-list-alias-sep)
1003
(match-string-no-properties howm-keyword-regexp-pos))))
1004
(setq keyword-list (cons key-str keyword-list))))
1005
(howm-keyword-add keyword-list)
1008
(defun howm-keyword-read ()
1010
(beg (line-beginning-position)))
1012
(skip-chars-backward " ")
1013
(while (re-search-backward howm-keyword-regexp beg t)
1014
(setq ks (cons (match-string-no-properties howm-keyword-regexp-pos) ks))
1015
(skip-chars-backward " "))
1019
;; (defun howm-keyword-read ()
1021
;; (howm-keyword-read-string (buffer-substring-no-properties
1022
;; (line-beginning-position)
1023
;; (line-end-position)))
1026
;; (defun howm-keyword-read-string (str)
1027
;; (with-temp-buffer
1029
;; (goto-char (point-max))
1031
;; (while (re-search-backward howm-keyword-regexp nil t)
1032
;; (let* ((mbeg (match-beginning 0))
1033
;; (key (match-string-no-properties howm-keyword-regexp-pos)))
1034
;; (setq ans (cons key ans))
1035
;; (delete-region mbeg (point-max))
1036
;; (skip-chars-backward " ")
1037
;; (delete-region (point) (point-max))))
1040
(provide 'howm-mode)
1042
;;; howm-mode.el ends here