1
;;; howm-view.el --- Wiki-like note-taking tool
2
;;; Copyright (c) 2002, 2003, 2004, 2005
3
;;; by HIRAOKA Kazuyuki <khi@users.sourceforge.jp>
4
;;; $Id: howm-view.el,v 1.204 2005/10/26 15:38:00 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
;;--------------------------------------------------------------------
23
(require 'howm-common)
25
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29
(defvar howm-view-summary-sep "|")
30
(defvar howm-view-summary-format
31
(let* ((path (format-time-string howm-file-name-format))
32
(width (length (file-name-nondirectory path))))
33
(concat "%-" (format "%s" width) "s " howm-view-summary-sep " ")))
34
;; (concat "%-" (format "%s" width) "s | ")))
35
(defvar howm-view-header-format
36
"\n==========================>>> %s\n"
37
"Format string of header for howm-view-contents.
38
%s is replaced with file name. See `format'.")
39
(defvar howm-view-header-regexp "^==========================>>> .*$")
40
(defvar howm-view-open-recenter howm-view-search-recenter)
41
(defvar howm-view-title-header "=")
42
;; howm-view-title-regexp is assumed to have a form "^xxxxxxx$"
43
(defvar howm-view-title-regexp (format "^%s\\( +\\(.*\\)\\|\\)$"
44
(regexp-quote howm-view-title-header)))
45
(defvar howm-view-title-regexp-pos 2)
46
(defvar howm-view-title-regexp-grep (format "^%s +"
47
(regexp-quote howm-view-title-header)))
48
(defun howm-view-title-regexp-grep ()
49
(if howm-view-use-grep
50
howm-view-title-regexp-grep
51
howm-view-title-regexp))
53
(defvar howm-view-sort-methods
54
'(("random" . howm-view-sort-by-random)
55
("name" . howm-view-sort-by-name)
56
("name-match" . howm-view-sort-by-name-match)
57
("numerical-name" . howm-view-sort-by-numerical-name)
58
("summary" . howm-view-sort-by-summary)
59
("summary-match" . howm-view-sort-by-summary-match)
60
; ("atime" . howm-view-sort-by-atime) ;; nonsense
61
; ("ctime" . howm-view-sort-by-ctime) ;; needless
62
("mtime" . howm-view-sort-by-mtime)
63
("date" . howm-view-sort-by-reverse-date)
64
("reminder" . howm-view-sort-by-reminder)
65
("reverse" . howm-view-sort-reverse)))
67
(defvar howm-view-filter-methods
68
'(("name" . howm-view-filter-by-name)
69
("summary" . howm-view-filter-by-summary)
70
("mtime" . howm-view-filter-by-mtime)
71
; ("ctime" . howm-view-filter-by-ctime) ;; needless
72
("date" . howm-view-filter-by-date)
73
("reminder" . howm-view-filter-by-reminder)
74
("contents" . howm-view-filter-by-contents)
75
("Region" . howm-view-filter-by-region)
76
("Around" . howm-view-filter-by-around)
77
; ("uniq" . howm-view-filter-uniq))
80
;; referred only when howm-view-use-grep is nil
81
(defvar howm-view-watch-modified-buffer t)
83
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86
(defun howm-view-item-basename (item &optional nonempty)
87
(let* ((f (howm-item-name item))
88
(b (file-name-nondirectory f)))
89
(if (and (string= b "") nonempty)
93
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
96
(defalias 'riffle-home:howm 'howm-view-item-home)
97
(defalias 'riffle-summary-item:howm 'howm-view-summary-item)
98
(defalias 'riffle-contents-item:howm 'howm-view-contents-item)
99
(defalias 'riffle-summary-set-mode:howm 'howm-view-summary-mode)
100
(defalias 'riffle-contents-set-mode:howm 'howm-view-contents-mode)
102
(defun riffle-summary-name-format:howm ()
103
howm-view-summary-name)
104
(defun riffle-contents-name-format:howm ()
105
howm-view-contents-name)
106
(defun riffle-post-update:howm (item)
107
(message "View: %s" (howm-view-item-filename item)))
111
;; Only howm-view.el should call riffle-xxx.
112
;; Define alias if it is used in howm-xxx besides howm-view.el.
113
(defalias 'howm-view-name #'riffle-name)
114
(defalias 'howm-view-item-list #'riffle-item-list)
115
(defalias 'howm-view-line-number #'riffle-line-number)
116
(defalias 'howm-view-summary-check #'riffle-summary-check)
117
(defalias 'howm-view-persistent-p #'riffle-persistent-p)
118
(defalias 'howm-view-kill-buffer #'riffle-kill-buffer)
119
(defalias 'howm-view-set-place #'riffle-set-place)
120
(defalias 'howm-view-summary-to-contents 'riffle-summary-to-contents)
121
(defalias 'howm-view-restore-window-configuration #'riffle-restore-window-configuration)
124
;; http://howm.sourceforge.jp/cgi-bin/hiki/hiki.cgi?howmoney
125
(defun howm-view-get-buffer (name-format &optional name new)
126
(let ((riffle-type ':howm)) ;; cheat
127
(riffle-get-buffer name-format name new)))
128
(defun howm-view-summary-buffer (&optional new)
129
(let ((riffle-type ':howm)) ;; cheat
130
(riffle-summary-buffer new)))
131
(defalias 'howm-view-summary-show 'riffle-summary-show)
132
(defalias 'howm-view-set-item-list 'riffle-set-item-list)
135
;; http://noir.s7.xrea.com/archives/000136.html
136
;; http://noir.s7.xrea.com/pub/zaurus/howmz.el
137
(defalias 'howm-view-sort-items 'howm-sort)
141
(defvar howm-view-font-lock-silent t
142
"Inhibit font-lock-verbose if non-nil.")
143
(defvar howm-view-summary-font-lock-keywords
144
'(("^[^ \t\r\n]+ +" . howm-view-name-face)
145
("^ +" . howm-view-empty-face)))
146
(defvar howm-view-contents-font-lock-keywords nil)
148
(defvar *howm-view-font-lock-keywords* nil
149
"For internal use. Don't set this variable.
150
This is a shameful global variable and should be clearned in future.")
151
(defvar howm-view-font-lock-keywords nil
153
(defvar howm-view-font-lock-first-time t
155
(make-variable-buffer-local 'howm-view-font-lock-keywords)
156
(make-variable-buffer-local 'howm-view-font-lock-first-time)
160
(riffle-define-derived-mode howm-view-summary-mode riffle-summary-mode "HowmS"
161
"memo viewer (summary mode)
164
\\[howm-view-summary-open] Open file
165
\\[next-line] Next item
166
\\[previous-line] Previous item
167
\\[riffle-pop-or-scroll-other-window] Pop and scroll contents
168
\\[scroll-other-window-down] Scroll contents
169
\\[riffle-scroll-other-window] Scroll contents one line
170
\\[riffle-scroll-other-window-down] Scroll contents one line
171
\\[riffle-summary-to-contents] Concatenate all contents
172
\\[howm-view-filter-uniq] Remove duplication of same file
173
\\[howm-view-summary-shell-command] Execute command in inferior shell
175
\\[delete-other-windows] Delete contents window
176
\\[riffle-pop-window] Pop contents window
177
\\[riffle-toggle-window] Toggle contents window
178
\\[howm-list-title] Show Title
180
\\[howm-view-filter] Filter (by date, contents, etc.)
181
\\[howm-view-filter-by-contents] Search (= filter by contents)
182
\\[howm-view-sort] Sort (by date, summary line, etc.)
183
\\[howm-view-sort-reverse] Reverse order
184
\\[howm-view-dired] Invoke Dired-X
185
\\[describe-mode] This help
186
\\[riffle-kill-buffer] Quit
188
(make-local-variable 'font-lock-keywords)
189
(make-local-variable 'font-lock-keywords-only)
190
(make-local-variable 'font-lock-keywords-case-fold-search)
191
(cheat-font-lock-mode howm-view-font-lock-silent)
192
(when howm-view-font-lock-first-time
193
(setq howm-view-font-lock-first-time nil)
194
(cheat-font-lock-merge-keywords howm-user-font-lock-keywords
195
howm-view-summary-font-lock-keywords))
196
(when *howm-view-font-lock-keywords*
197
(setq howm-view-font-lock-keywords *howm-view-font-lock-keywords*)
198
(cheat-font-lock-merge-keywords *howm-view-font-lock-keywords*
199
howm-user-font-lock-keywords
200
howm-view-summary-font-lock-keywords))
201
(setq font-lock-keywords-only t)
202
(setq font-lock-keywords-case-fold-search t)
203
;; (setq font-lock-keywords-case-fold-search
204
;; howm-view-grep-ignore-case-option)
208
(riffle-define-derived-mode howm-view-contents-mode riffle-contents-mode "HowmC"
209
"memo viewer (contents mode)
212
\\[howm-view-contents-open] Open file
213
\\[next-line] Next line
214
\\[previous-line] Previous line
215
\\[scroll-up] Scroll up
216
\\[scroll-down] Scroll down
217
\\[riffle-scroll-up] Scroll one line up
218
\\[riffle-scroll-down] Scroll one line down
219
\\[riffle-contents-to-summary] Summary
220
\\[riffle-contents-goto-next-item] Next item
221
\\[riffle-contents-goto-previous-item] Previous item
223
\\[howm-view-filter] Filter (by date, contents, etc.)
224
\\[howm-view-filter-by-contents] Search (= filter by contents)
225
\\[howm-view-sort] Sort
226
\\[howm-view-sort-reverse] Reverse order
227
\\[howm-view-dired] Invoke Dired-X
228
\\[describe-mode] This help
229
\\[riffle-kill-buffer] Quit
231
; (kill-all-local-variables)
232
(make-local-variable 'font-lock-keywords)
233
(make-local-variable 'font-lock-keywords-only)
234
(make-local-variable 'font-lock-keywords-case-fold-search)
235
(cheat-font-lock-mode howm-view-font-lock-silent)
236
(let ((ck `((,howm-view-header-regexp (0 howm-view-hilit-face))))
237
(sk (or (howm-view-font-lock-keywords)
238
*howm-view-font-lock-keywords*)))
239
;; ;; extremely dirty!! [2003/10/06 21:08]
240
;; (sk (or (with-current-buffer (riffle-summary-buffer)
241
;; font-lock-keywords)
242
;; *howm-view-font-lock-keywords*)))
243
(cheat-font-lock-merge-keywords sk ck
244
howm-user-font-lock-keywords
245
howm-view-contents-font-lock-keywords)
246
(setq font-lock-keywords-only t)
247
(setq font-lock-keywords-case-fold-search
248
howm-view-grep-ignore-case-option)
252
(defun howm-view-font-lock-keywords ()
253
(with-current-buffer (riffle-summary-buffer)
254
howm-view-font-lock-keywords))
258
;; (defvar howm-view-summary-mode-map nil)
259
;; (defvar howm-view-contents-mode-map nil)
261
(defun howm-view-define-common-key (keymap)
263
;; (define-key m "?" 'howm-view-help)
264
(define-key m "f" 'howm-view-filter)
265
(define-key m "G" 'howm-view-filter-by-contents)
266
(define-key m "S" 'howm-view-sort)
267
(define-key m "R" 'howm-view-sort-reverse)
268
(define-key m "q" 'howm-view-kill-buffer)
269
(define-key m "X" 'howm-view-dired)
272
(let ((m howm-view-summary-mode-map))
273
(define-key m "\C-m" 'howm-view-summary-open)
274
(define-key m "\C-j" 'howm-view-summary-open)
275
(define-key m "u" 'howm-view-filter-uniq)
276
(define-key m "!" 'howm-view-summary-shell-command)
277
(define-key m "T" 'howm-list-title) ;; defined in other file. dirty!
278
;; (define-key m howm-reminder-quick-check-key 'howm-reminder-quick-check)
279
;; (define-key m ";" 'howm-view-invoke-action-lock)
280
(define-key m "\C-i" 'howm-view-summary-next-section)
281
(define-key m "\M-\C-i" 'howm-view-summary-previous-section)
282
(define-key m [tab] 'howm-view-summary-next-section)
283
(define-key m [(meta tab)] 'howm-view-summary-previous-section)
284
(howm-view-define-common-key m))
286
(let ((m howm-view-contents-mode-map))
287
(define-key m "\C-m" 'howm-view-contents-open)
288
(define-key m "\C-j" 'howm-view-contents-open)
289
(howm-view-define-common-key m))
293
(defun howm-view-summary (&optional name item-list)
294
(let ((r (riffle-summary name item-list ':howm
295
(howm-view-in-background-p))))
297
(message "No match"))
300
;; (defun howm-view-summary (&optional name item-list)
301
;; (let ((*howm-view-font-lock-keywords* t))
302
;; (riffle-summary name item-list ':howm)))
304
(defun howm-view-summary-open (&optional reverse-delete-p)
306
(when (not (and howm-view-summary-keep-cursor
307
(get-buffer-window (riffle-contents-buffer))))
308
(riffle-summary-check t))
309
(let* ((p (riffle-persistent-p howm-view-summary-persistent))
310
(persistent (if reverse-delete-p
313
(howm-record-view-window-configuration)
314
(howm-view-summary-open-sub (not persistent))))
316
(defun howm-view-summary-open-sub (&optional kill)
318
(let ((b (riffle-contents-buffer))
319
(looking-at-str (buffer-substring-no-properties (point)
320
(line-end-position))))
321
(riffle-pop-to-buffer b howm-view-summary-window-size)
322
(let ((howm-view-open-hook nil)) ;; Don't execute it in contents-open.
323
(howm-view-contents-open-sub kill))
325
(or (search-backward looking-at-str (line-beginning-position) t)
327
(run-hooks 'howm-view-open-hook)))
329
(defvar howm-view-summary-item-previous-name nil
331
(defun howm-view-summary-item (item)
332
;; Clean me. This depends on implementation of `riffle-summary-show'
334
(when (eq (point) (point-min))
335
(setq howm-view-summary-item-previous-name ""))
336
(let* ((f (howm-view-item-basename item t))
337
(name (if (and howm-view-summary-omit-same-name
338
(string= f howm-view-summary-item-previous-name))
340
;; setq returns the last value.
341
(setq howm-view-summary-item-previous-name f)))
342
(h (format howm-view-summary-format name)))
343
(concat h (howm-view-item-summary item))))
345
(defun howm-view-summary-next-section (&optional n)
349
(step (if (>= n 0) 1 -1)))
351
(howm-view-summary-next-section-sub step))
353
(defun howm-view-summary-previous-section (&optional n)
356
(howm-view-summary-next-section (- n)))
357
(defun howm-view-summary-next-section-sub (step)
358
(let ((orig (howm-view-item-filename (riffle-summary-current-item))))
359
;; (let ((orig (riffle-controller 'section
360
;; (riffle-summary-current-item))))
361
(while (and (string= orig
362
(howm-view-item-filename (riffle-summary-current-item)))
363
;; (riffle-controller 'section
364
;; (riffle-summary-current-item)))
365
(= (forward-line step) 0))
371
(defun howm-view-contents-open (&optional reverse-delete-p)
373
(let* ((p (riffle-persistent-p howm-view-contents-persistent))
374
(persistent (if reverse-delete-p
377
(howm-record-view-window-configuration)
378
(howm-view-contents-open-sub (not persistent))))
380
(defvar *howm-view-item-privilege* nil) ;; dirty
382
(defun howm-view-contents-open-sub (&optional kill)
383
(let* ((n (riffle-contents-item-number (point)))
384
(item (nth n (riffle-item-list)))
385
(page (howm-item-page item))
386
(offset (howm-view-item-offset item))
387
(pos (- (point) offset))
388
(viewer (howm-view-external-viewer page)))
390
(riffle-kill-buffer))
391
(when (howm-view-item-privilege item)
392
(riffle-restore-window-configuration)) ;; force without mode check
393
(setq *howm-view-item-privilege* (howm-view-item-privilege item)) ;; dirty
394
(run-hooks 'howm-view-before-open-hook)
396
(howm-view-call-external-viewer viewer page)
398
(howm-page-open page)
399
(howm-view-set-mark-command)
400
(when (or (< pos (point-min)) (<= (point-max) pos))
403
(recenter howm-view-open-recenter)))
404
(run-hooks 'howm-view-open-hook)))
406
(defvar howm-view-previous-section-page nil "For internal use")
407
(defvar howm-view-previous-section-beg nil "For internal use")
408
(defvar howm-view-previous-section-end nil "For internal use")
410
(defun howm-view-contents-item (item)
411
(when (howm-buffer-empty-p)
412
(setq howm-view-previous-section-page ""
413
howm-view-previous-section-beg nil
414
howm-view-previous-section-end nil))
415
(let* ((page (howm-item-page item))
416
(place (howm-view-item-place item))
417
(peq (howm-page= page howm-view-previous-section-page)) ;; dirty!
420
(<= howm-view-previous-section-beg place)
421
(<= place howm-view-previous-section-end))
425
(let* ((header (format howm-view-header-format
426
(howm-page-abbreviate-name page)))
427
(header-length (howm-view-string-point-count header))
428
(viewer (howm-view-external-viewer page)))
430
(howm-view-contents-item-sub item page place header viewer
431
(+ (point) header-length)))))))
433
(defvar howm-view-string-point-count-strict nil)
434
(defun howm-view-string-point-count (str)
435
"Count points of string STR.
436
Namely, it is the difference between start position and end position
437
of STR if STR is inserted to a buffer.
438
It looks to be simply equal to (length STR) on emacs-21.1.1.
439
But I'm not sure for multi-byte characters on other versions of emacsen."
440
(if howm-view-string-point-count-strict
443
(- (point) (point-min)))
444
;; I assume (length (buffer-substring-no-properties START END))
445
;; is equal to (abs (- START END))). Is it correct?
446
;; (cf.) snap://Info-mode/elisp#Positions
449
(defun howm-view-contents-item-sub (item page place header viewer c)
453
(howm-view-contents-indicator viewer page)
454
(howm-page-insert page))
457
(riffle-set-place place)
459
(let ((r (howm-view-contents-region page)))
465
(howm-view-item-set-offset item (- c b))
466
(howm-view-item-set-home item (+ c (- b) h))
467
(setq howm-view-previous-section-page page ;; dirty!
468
howm-view-previous-section-beg (riffle-get-place b)
469
howm-view-previous-section-end (riffle-get-place e))
470
(buffer-substring-no-properties b e))))
472
(defvar howm-view-preview-narrow t)
473
(defun howm-view-contents-region (filename)
475
(howm-page-set-configuration filename))
476
(if (or howm-view-preview-narrow
477
(not (riffle-preview-p)))
478
(howm-view-paragraph-region)
479
(list (point-min) (point-max))))
481
(defun howm-view-contents-indicator (viewer fname)
483
(howm-viewer-indicator viewer fname)
486
(defun howm-view-paragraph-region (&optional include-following-blank-p)
487
(let ((b (save-excursion
489
(re-search-backward howm-view-title-regexp
491
(line-beginning-position)))
494
(let ((found (re-search-forward howm-view-title-regexp
496
(if include-following-blank-p
497
(if found (match-beginning 0) (point-max))
501
(goto-char (point-max)))
503
(while (and (looking-at "^$")
504
(= (forward-line -1) 0)) ;; successful
510
(defun howm-view-set-mark-command ()
511
(set-mark-command nil)
512
(howm-deactivate-mark))
514
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
517
(defun howm-view-file-list (&optional item-list)
518
(howm-cl-remove-duplicates (mapcar #'howm-view-item-filename
519
(or item-list (howm-view-item-list)))
522
(defun howm-view-xtime (file x)
524
(howm-view-time-to-string (howm-page-mtime file))
525
(error "Not supported: %stime" x)))
527
;; (defun howm-view-xtime (file x)
528
;; (let* ((a (file-attributes file))
529
;; (n (cdr (assoc x '((a . 4) (m . 5) (c . 6)))))
531
;; (howm-view-time-to-string ti)))
533
(defun howm-view-time-to-string (ti)
534
(format-time-string "%Y%m%d-%H%M%S" ti))
536
(defun howm-view-string> (a b)
539
(defun howm-view-string<= (a b)
542
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
545
(defcustom howm-ruby-mode-bug nil
546
"Non nil if ruby-mode.el is old and has a bug around font-lock;
547
global value of font-lock-keywords is set wrongly."
549
:group 'howm-experimental)
551
(defun howm-view-directory (dir &optional recursive-p)
552
(howm-view-summary "" (howm-view-directory-items dir recursive-p))
553
(when howm-ruby-mode-bug
555
;; (for old ruby-mode.el which sets global value of font-lock-keywords)
556
(setq font-lock-keywords nil))
559
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
562
(defun howm-view-filter (&optional remove-p)
564
(let* ((table howm-view-filter-methods)
565
(command (completing-read (if remove-p
566
"(Reject) filter by: "
569
(call-interactively (cdr (assoc command table)))))
571
(defvar howm-view-filter-uniq-prev "")
572
(defun howm-view-filter-uniq ()
574
(setq howm-view-filter-uniq-prev
575
(if howm-view-search-in-result-correctly
578
(howm-view-filter-general
580
(if howm-view-search-in-result-correctly
581
(let ((page (howm-item-page item))
582
(place (howm-item-place item))
583
(range (howm-item-range item))
584
(p-page (car howm-view-filter-uniq-prev))
585
(p-range (cdr howm-view-filter-uniq-prev)))
587
(not (and (howm-page= page p-page)
589
(<= (car p-range) place)
590
(<= place (second p-range)))))
591
(setq howm-view-filter-uniq-prev (cons page range))))
593
(let ((f (howm-view-item-filename item)))
595
(not (howm-page= f howm-view-filter-uniq-prev))
596
(setq howm-view-filter-uniq-prev f)))))))
598
(defun howm-view-filter-by-name (&optional remove-p regexp)
600
(howm-view-filter-by-name/summary #'howm-view-item-basename
603
(defun howm-view-filter-by-summary (&optional remove-p regexp)
605
(howm-view-filter-by-name/summary #'howm-view-item-summary
608
(defun howm-view-filter-by-name/summary (accessor remove-p regexp)
609
(let ((r (or regexp (howm-view-filter-read-from-minibuffer "Regexp: "
611
(howm-view-filter-general (lambda (item)
612
(string-match r (funcall accessor item)))
615
(defun howm-view-filter-by-date (&optional remove-p)
617
(let* ((r (howm-view-ask-time-range remove-p))
620
(form (howm-view-file-name-format))
621
(fts (mapcar (lambda (x)
622
(file-name-nondirectory (format-time-string form x)))
626
(howm-view-filter-general
628
(let ((cs (howm-view-item-basename item)))
629
(and (howm-view-string<= fs cs) (howm-view-string<= cs ts))))
633
(defun howm-view-filter-by-reminder (&optional remove-p)
635
(let* ((r (howm-view-ask-time-range remove-p))
638
(from-str (format-time-string howm-date-format from))
639
(to-str (format-time-string howm-date-format to))
640
(reg (howm-reminder-regexp howm-reminder-types)))
641
(howm-view-filter-general
643
(let ((s (howm-view-item-summary item)))
644
(and (string-match reg s)
645
(let* ((x (match-string-no-properties 0 s)) ;; [2004-02-07]@
646
(d (and (string-match howm-date-regexp x)
647
(match-string-no-properties 0 x)))) ;; [2004-02-07]
648
(and (howm-view-string<= from-str d)
649
(howm-view-string<= d to-str))))))
653
(defun howm-view-file-name-format ()
654
howm-file-name-format) ;; defined in howm-common.el
657
; (defun howm-view-filter-by-ctime (&optional remove-p)
659
; (howm-view-filter-by-xtime 'c remove-p))
661
(defun howm-view-filter-by-mtime (&optional remove-p range)
663
(howm-view-filter-by-xtime 'm remove-p range))
665
(defun howm-view-filter-by-xtime (x remove-p &optional range)
666
(let* ((r (or range (howm-view-ask-time-range remove-p)))
669
(fs (howm-view-time-to-string from))
670
(ts (howm-view-time-to-string to)))
671
(howm-view-filter-general
673
(let* ((cs (howm-view-xtime (howm-view-item-filename item) x)))
674
(and (howm-view-string<= fs cs) (howm-view-string<= cs ts))))
677
(defun howm-view-ask-time-range (&optional remove-p)
678
(let* ((now (current-time))
679
(from (howm-view-ask-time "From" now t remove-p))
680
(to (howm-view-ask-time "To" from nil remove-p)))
683
(defvar howm-view-min-year 1950)
684
(defvar howm-view-max-year 2030)
685
(defun howm-view-ask-time (prompt default &optional from-p remove-p)
686
(let* ((z (decode-time default))
690
(let (y0 m0 d0 hour0 min0 sec0)
692
(setq y0 howm-view-min-year m0 1 d0 1
693
hour0 0 min0 0 sec0 0)
694
(setq y0 howm-view-max-year m0 12 d0 'last-day-of-month
695
hour0 24 min0 0 sec0 0))
696
(let ((y (howm-ask-time-sub prompt "year" yd remove-p)))
698
(howm-view-encode-time sec0 min0 hour0 d0 m0 y0)
699
(let ((m (howm-ask-time-sub prompt "month" md remove-p)))
701
(howm-view-encode-time sec0 min0 hour0 d0 m0 y)
702
(let ((d (or (howm-ask-time-sub prompt "date" dd remove-p) d0)))
703
(howm-view-encode-time sec0 min0 hour0 d m y)))))))))
705
(defun howm-ask-time-sub (prompt ymd default remove-p)
706
(let* ((message (format "%s %s (* = no limit) [%d]: " prompt ymd default))
707
(raw (howm-view-filter-read-from-minibuffer message remove-p))
708
(n (if (string= raw "")
710
(string-to-number raw))))
715
(defun howm-view-encode-time (sec min hour d m y)
716
(when (eq d 'last-day-of-month)
719
(encode-time sec min hour d m y))
721
(defun howm-view-filter-by-region (beg end)
723
(let ((r (mapcar #'howm-view-line-number (list beg end))))
724
(howm-view-filter-by-line-range (car r) (second r))))
726
(defvar howm-view-filter-by-around-default 10)
727
(defun howm-view-filter-by-around (&optional distance)
729
(let* ((d (or distance howm-view-filter-by-around-default))
730
(c (howm-view-line-number)))
731
(howm-view-filter-by-line-range (- c d) (+ c d))))
733
(defun howm-view-filter-by-line-range (beg end)
734
(let ((howm-view-filter-by-line-range-beg beg)
735
(howm-view-filter-by-line-range-end end))
736
(howm-view-filter-general (lambda (item-count)
737
(let* ((line (1+ (second item-count)))
738
(b howm-view-filter-by-line-range-beg)
739
(e howm-view-filter-by-line-range-end))
740
(and (<= b line) (<= line e))))
743
(defun howm-view-filter-general (pred &optional remove-p with-index)
744
(let* ((item-list (howm-view-item-list))
746
(howm-map-with-index #'list item-list)
749
(howm-cl-remove-if pred s)
750
(howm-cl-remove-if-not pred s)))
751
(filtered (if with-index
754
(howm-view-summary-rebuild filtered)))
756
(defun howm-view-filter-read-from-minibuffer (message &optional remove-p)
757
(read-from-minibuffer (if remove-p
758
(concat "(Reject) " message)
761
(defun howm-view-summary-rebuild (item-list)
762
(howm-view-summary (howm-view-name) item-list))
764
(defun howm-view-filter-by-contents (&optional remove-p regexp)
766
(let ((r (or regexp (howm-view-filter-read-from-minibuffer
767
"Search in result (grep): "
770
(howm-view-remove-by-contents r)
771
(howm-view-search-in-result r))))
773
(defcustom howm-view-search-in-result-correctly nil
774
"*Non nil if search-in-result should be aware of paragraph."
776
:group 'howm-experimental)
778
(defun howm-view-search-in-result (regexp)
779
;; (interactive "sSearch in result (grep): ")
780
(let* ((orig (howm-view-name))
781
(name (if (string= orig "")
783
(format "%s&%s" orig regexp)))
784
(orig-item-list (howm-view-item-list))
785
(folder (howm-make-folder-from-items orig-item-list)))
786
(howm-write-history regexp)
787
(howm-view-search-folder regexp folder name)
788
(when howm-view-search-in-result-correctly
789
(howm-view-summary-rebuild (howm-item-list-filter (howm-view-item-list)
792
(defun howm-view-remove-by-contents (regexp)
793
;; (interactive "s(Reject) Search in result (grep): ")
794
(let* ((orig (howm-view-item-list))
795
(folder (howm-make-folder-from-items orig)))
796
(if howm-view-search-in-result-correctly
797
(let ((rejects (howm-view-search-folder-items regexp folder)))
798
(howm-view-summary-rebuild (howm-item-list-filter orig rejects t)))
800
(let ((rejects (howm-cl-remove-duplicates
801
(mapcar #'howm-item-name
802
(howm-view-search-folder-items regexp folder)))))
803
(howm-view-filter-general (lambda (item)
804
(member (howm-item-name item) rejects))
807
(defcustom howm-view-title-skip-regexp nil
808
"*Regular expression for lines which should not be titles.
809
If the original title matches this regexp, the first non-matched line
810
is shown as title instead.
811
Nil disables this feature.
813
This feature does not work when `howm-view-search-in-result-correctly' is nil."
814
:type '(radio (const :tag "Off"
816
(const :tag "Skip \"= \""
818
(const :tag "Skip \"= \" and \"[xxxx-xx-xx xx:xx]\""
819
"\\(^=? *$\\)\\|\\(^\\[[-: 0-9]+\\]\\)")
821
;; :group 'howm-efficiency
822
:group 'howm-experimental)
824
(defun howm-view-list-title (title-regexp)
825
(let* ((folder (howm-make-folder-from-items (howm-view-item-list)))
826
(items (howm-view-search-folder-items title-regexp folder))
827
(kw *howm-view-font-lock-keywords*))
828
(if howm-view-search-in-result-correctly
829
(let* ((hit-items (howm-item-list-filter items (howm-view-item-list)))
830
(nohit-items (howm-item-list-filter (howm-view-item-list)
832
(all-items (if (null nohit-items)
834
(append hit-items nohit-items))))
835
(when howm-view-title-skip-regexp
836
(mapcar #'howm-view-change-title all-items))
837
(let ((*howm-view-font-lock-keywords* kw)) ;; dirty!
838
(howm-view-summary-rebuild all-items)))
840
(let* ((pages (howm-cl-remove-duplicates (mapcar #'howm-item-page
841
(howm-view-item-list))))
842
(hit-pages (mapcar #'howm-item-page items))
843
(nohit-pages (howm-cl-remove-if
844
(lambda (p) (howm-cl-member* p hit-pages
847
(nohit-items (mapcar #'howm-make-item nohit-pages))
848
(all-items (if (null nohit-items)
850
(append items nohit-items))))
851
(let ((*howm-view-font-lock-keywords* kw)) ;; dirty!
852
(howm-view-summary-rebuild all-items))))))
854
;;; detect items in same paragraph (= entry = memo. sorry for inconsistent terminology)
856
(defun howm-item-range (item)
857
"List of beginning-place and end-place of paragraph to which ITEM belongs."
859
(howm-page-insert (howm-item-page item))
860
(let* ((p (howm-item-place item))
862
(list (point-min) (point-max))
865
(howm-view-paragraph-region)))))
870
(goto-char (second r))
871
(riffle-get-place))))))
873
(defun howm-item-list-rangeset (item-list)
874
"Make assoc list of page to rangeset.
875
ITEM-LIST is list of items.
876
Return value is assoc list; each element of it is a cons pair of page
877
and rangeset which indicates ranges of places of paragraphs to which items
878
in ITEM-LIST belongs."
879
(let ((alist nil)) ;; key = page, value = rangeset of place
881
(let* ((page (howm-item-page item))
882
(place (howm-item-place item))
883
(rs (cdr (assoc page alist))))
885
(setq alist (cons (cons page (howm-make-rangeset
886
(howm-item-range item)))
888
((howm-rangeset-belong-p place rs)
891
(howm-rangeset-add! rs (howm-item-range item))))))
895
(defun howm-item-list-filter (item-list reference-item-list
896
&optional remove-match)
897
"Select items in ITEM-LIST according to REFERENCE-ITEM-LIST.
898
When REMOVE-MATCH is nil, return value is list of items i in ITEM-LIST
899
which satisfy the condition \"there exists i' in REFERENCE-ITEM-LIST
900
such that i and i' belong to same paragraph\".
901
When REMOVE-MATCH is non-nil, return value is complement of the above list;
902
list of items in ITEM-LIST which do not satisfy the above condition."
903
;; split no-place items
905
(howm-cl-mapcan (lambda (item)
906
(if (howm-item-place item)
908
(let ((f (howm-make-folder-from-items (list item))))
909
(or (howm-view-search-folder-items (howm-view-title-regexp-grep)
913
(let* ((alist (howm-item-list-rangeset reference-item-list))
914
(matcher (lambda (item)
915
(let* ((page (howm-item-page item))
916
(place (howm-item-place item))
917
(rs (cdr (assoc page alist))))
918
(cond ((null rs) nil)
920
(t (howm-rangeset-belong-p place rs)))))))
922
(howm-cl-remove-if matcher item-list)
923
(howm-cl-remove-if-not matcher item-list))))
926
;;; ex. (*rangeset* (1 . 4) (5 . 6) (8 . 14))
928
(defun howm-make-rangeset (&optional beg-end)
930
(cons '*rangeset* nil)
931
(let ((rs (howm-make-rangeset)))
932
(howm-rangeset-add! rs beg-end))))
934
(defun howm-rangeset-belong-p (point rs)
935
(howm-cl-member-if (lambda (pair)
936
(and (<= (car pair) point) (<= point (cdr pair))))
939
(defun howm-rangeset-add! (rs beg-end)
940
;; c = cursor (pointing its cdr)
944
(end (second beg-end)))
945
(while (and (cdr c) beg)
947
(cond ((< end (car p)) ;; insert [beg, end] here
948
(rplacd c (cons (cons beg end) (cdr c)))
950
((< (cdr p) beg) ;; skip this
952
(t ;; merge into [beg, end]
953
(setq beg (min beg (car p))
954
end (max end (cdr p)))
955
(rplacd c (cddr c))))))
957
(rplacd c (list (cons beg end)))))
977
(((3 . 1) (4 . 1) (5 . 9))
979
(((3 . 1) (4 . 1) (5 . 9) (2 . 6) (5 . 3))
982
;; inhibit 'reference to free variable' warning in byte-compilation
984
(flet ((check (ans result)
985
(cond ((null ans) (null result))
986
((not (equal (car ans) (car result))) nil)
987
(t (funcall check (cdr ans) (cdr result))))))
989
(apply (lambda (prob ans)
990
(let* ((rs (howm-make-rangeset)))
994
(howm-rangeset-add! rs
998
(when (not (equal (cdr rs) ans))
999
(error "howm-rangeset-add: %s ==> %s" prob rs))))
1003
(let ((rs '(*rangeset* (1 . 4) (5 . 6) (8 . 14))))
1004
(if (and (howm-rangeset-belong-p 1 rs)
1005
(howm-rangeset-belong-p 3 rs)
1006
(howm-rangeset-belong-p 4 rs)
1007
(howm-rangeset-belong-p 5 rs)
1008
(not (howm-rangeset-belong-p 0 rs))
1009
(not (howm-rangeset-belong-p 4.5 rs))
1010
(not (howm-rangeset-belong-p 7 rs))
1011
(not (howm-rangeset-belong-p 15 rs)))
1013
(error "howm-rangeset-belong-p: wrong result")))
1015
(defun howm-view-change-title (item)
1016
(when (string-match howm-view-title-skip-regexp (howm-item-summary item))
1017
(let ((title-line (with-temp-buffer
1018
(howm-page-insert (howm-item-page item))
1019
(howm-view-set-place (howm-item-place item))
1020
(howm-view-get-title-line))))
1021
(howm-item-set-summary item title-line))))
1023
(defun howm-view-get-title-line ()
1024
(while (and (looking-at howm-view-title-skip-regexp)
1025
(= (forward-line 1) 0))
1028
(buffer-substring-no-properties (line-beginning-position)
1029
(line-end-position)))
1031
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1034
(defun howm-view-search (str file-list &optional
1035
name summarizer fixed-p hilit-keywords)
1036
(howm-view-search-folder str (howm-make-folder:files file-list)
1037
name summarizer fixed-p hilit-keywords))
1039
(defun howm-view-search-items (str file-list &optional summarizer fixed-p)
1040
(howm-view-search-folder-items str (howm-make-folder:files file-list)
1041
summarizer fixed-p))
1043
(defun howm-view-search-folder (str folder &optional
1044
name summarizer fixed-p hilit-keywords)
1045
;; clean me. str-orig can be string or list of strings.
1046
(let* ((str-orig str)
1047
(str-list (if (listp str-orig) str-orig (list str-orig)))
1048
(str-principal (if (listp str-orig) (car str-orig) str-orig)))
1050
(setq str str-principal)
1051
(setq name (or name str))
1052
(when howm-view-update-search-ring
1053
(isearch-update-ring str (not fixed-p)))
1054
(let* ((items (howm-view-search-folder-items str-orig
1055
folder summarizer fixed-p))
1056
(kw (or hilit-keywords
1057
`((,(regexp-opt str-list) . howm-view-hilit-face))))
1058
;; `((,(regexp-quote str) . howm-view-hilit-face))))
1060
(let* ((f (expand-file-name str)))
1061
(when (file-exists-p f)
1062
(let ((fi (howm-view-make-item f)))
1063
(howm-view-item-set-privilege fi t)
1064
(setq items (cons fi items)))))
1065
(let ((*howm-view-font-lock-keywords* kw)) ;; dirty!
1066
(howm-view-summary name items)))))
1068
(defun howm-view-search-folder-items (str folder &optional summarizer fixed-p)
1069
(let ((found (howm-folder-grep folder str fixed-p))
1070
(summarizer (or summarizer
1071
(lambda (file place content)
1072
(string-match "^ *\\(.*\\)" content)
1073
(match-string-no-properties 1 content)))))
1075
(let ((file (howm-page-name (howm-item-page i)))
1076
(place (howm-item-place i))
1077
(content (howm-item-summary i)))
1078
(howm-item-set-summary i (funcall summarizer
1079
file place content))))
1083
;; (defun howm-view-search-items (str file-list &optional summarizer fixed-p)
1084
;; (let ((found (howm-view-grep str file-list fixed-p))
1085
;; (summarizer (or summarizer
1086
;; (lambda (file place content)
1087
;; (string-match "^ *\\(.*\\)" content)
1088
;; (match-string-no-properties 1 content)))))
1089
;; (mapcar (lambda (z)
1090
;; (let ((file (car z))
1091
;; (place (second z))
1092
;; (content (third z)))
1093
;; (howm-view-make-item file
1094
;; (funcall summarizer
1095
;; file place content)
1099
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1102
(defun howm-view-sort ()
1104
(let* ((table howm-view-sort-methods)
1105
(command (completing-read "sort by: " table nil t)))
1106
(call-interactively (cdr (assoc command table)))))
1108
(defun howm-view-sort-by-random (&optional reverse-p)
1110
(howm-view-sort-general #'(lambda (dummy) (random)) #'< reverse-p))
1112
(defun howm-view-sort-by-name (&optional reverse-p)
1114
(howm-view-sort-general #'howm-view-item-basename #'string< reverse-p))
1116
(defun howm-view-sort-by-numerical-name (&optional reverse-p)
1118
(howm-view-sort-general #'(lambda (i)
1119
(let ((b (howm-view-item-basename i)))
1120
(if (string-match "^[0-9]+$" b)
1121
(string-to-number b)
1125
(defun howm-view-sort-by-name-match (&optional reverse-p regexp path-p)
1127
(howm-view-sort-by-general-match (if path-p
1129
;; #'howm-view-item-filename
1130
#'howm-view-item-basename)
1133
(defvar howm-view-sort-by-date-ignore-regexp "^[a-zA-Z]")
1134
(defun howm-view-sort-by-date (&optional reverse-p)
1136
(howm-view-sort-general #'howm-view-item-basename #'string<
1138
(howm-view-sort-by-general-match #'howm-view-item-basename t
1139
howm-view-sort-by-date-ignore-regexp))
1140
(defun howm-view-sort-by-reverse-date (&optional reverse-p)
1142
(howm-view-sort-by-date (not reverse-p)))
1144
(defun howm-view-sort-by-summary (&optional reverse-p)
1146
(howm-view-sort-general #'howm-view-item-summary #'string< reverse-p))
1148
(defun howm-view-sort-by-summary-match (&optional reverse-p regexp)
1150
(howm-view-sort-by-general-match #'howm-view-item-summary
1153
(defun howm-view-sort-by-general-match (picker &optional reverse-p regexp)
1154
(let ((r (or regexp (read-from-minibuffer "Regexp: ")))
1155
(howm-view-s-b-g-m-matched nil)) ;; need unique name?? :-(
1156
(howm-view-sort-general (lambda (item)
1158
(funcall picker item))
1160
(setq howm-view-s-b-g-m-matched t)
1165
howm-view-s-b-g-m-matched))
1167
(defun howm-view-sort-by-reminder (&optional reverse-p)
1169
(howm-view-sort-general (lambda (item)
1170
(let ((s (howm-view-item-summary item))
1171
(r (howm-reminder-regexp howm-reminder-types))
1172
(max-str (format-time-string
1173
howm-reminder-today-format
1174
(encode-time 59 59 23 31 12
1175
howm-view-max-year))))
1176
(if (string-match r s)
1177
(match-string-no-properties 0 s)
1179
#'string< reverse-p))
1182
; (defun howm-view-sort-by-atime (&optional reverse-p)
1184
; (howm-view-sort-by-xtime 'a reverse-p))
1187
; (defun howm-view-sort-by-ctime (&optional reverse-p)
1189
; (howm-view-sort-by-xtime 'c reverse-p))
1191
(defun howm-view-sort-by-mtime (&optional reverse-p)
1193
(howm-view-sort-by-xtime 'm reverse-p))
1195
(defun howm-view-sort-by-xtime (x reverse-p)
1196
(howm-view-sort-general (lambda (item)
1197
(howm-view-xtime (howm-view-item-filename item)
1205
(defun howm-view-sort-general (evaluator comparer &optional reverse-p)
1206
(let* ((howm-view-s-g-comparer comparer) ;; need unique name?? :-(
1208
(lambda (a b) (funcall howm-view-s-g-comparer b a))
1209
howm-view-s-g-comparer))
1210
(sorted (howm-sort evaluator cmp (howm-view-item-list))))
1211
(howm-view-summary (howm-view-name) sorted)))
1213
(defun howm-view-sort-reverse ()
1215
(howm-view-summary (howm-view-name)
1216
(reverse (howm-view-item-list))))
1218
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1221
(defvar howm-view-dired-buffer-name "*howm-dired*")
1222
(defvar howm-view-dired-ls-command "ls")
1223
(defvar howm-view-dired-ls-options '("-l"))
1225
(defun dired-virtual (dir)
1226
(howm-inhibit-warning-in-compilation))
1228
(defun howm-view-dired ()
1230
(require (if (howm-xemacsp) 'dired-vir 'dired-x))
1231
(when (not (member major-mode
1232
'(howm-view-summary-mode howm-view-contents-mode)))
1233
(error "Invalid mode for this command."))
1234
;; ;; bug in emacs-21.3.50?
1235
;; (when (not (fboundp 'dired-insert-headerline))
1236
;; (defun dired-insert-headerline (dir);; also used by dired-insert-subdir
1237
;; ;; Insert DIR's headerline with no trailing slash, exactly like ls
1238
;; ;; would, and put cursor where dired-build-subdir-alist puts subdir
1240
;; (save-excursion (insert " " (directory-file-name dir) ":\n"))))
1241
(let* ((i2f (lambda (item)
1242
(file-relative-name (howm-view-item-filename item))))
1243
(current-file (funcall i2f (riffle-summary-current-item)))
1244
(files (howm-cl-remove-duplicates (mapcar i2f (howm-view-item-list))
1246
;; (pos (howm-cl-position f files :test #'string=))
1247
(args (append howm-view-dired-ls-options files))
1248
(a `((howm-view-summary-mode . ,howm-view-summary-persistent)
1249
(howm-view-contents-mode . ,howm-view-contents-persistent)))
1250
(p (howm-view-persistent-p (cdr (assoc major-mode a)))))
1252
(howm-view-restore-window-configuration)
1253
(howm-view-kill-buffer))
1254
(switch-to-buffer (get-buffer-create howm-view-dired-buffer-name))
1255
(setq buffer-read-only nil)
1257
(howm-call-process-here howm-view-dired-ls-command args)
1258
(set-buffer-modified-p nil)
1259
(dired-virtual default-directory)
1260
(when howm-view-dired-keep-cursor
1261
(howm-view-dired-goto current-file))))
1263
(defun howm-view-dired-goto (rname)
1264
"In dired buffer, search file name RNAME and move cursor to corresponding line.
1265
RNAME must be relative name."
1266
(goto-char (point-min))
1267
;; Raw call of `dired-get-filename' and `dired-next-line' causes
1268
;; warnings in compilation.
1269
(while (let ((c (howm-funcall-if-defined (dired-get-filename 'no-dir t))))
1270
(not (and c (equal (file-relative-name c) rname))))
1271
(howm-funcall-if-defined (dired-next-line 1))))
1273
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1276
(defvar howm-view-summary-shell-hist '("ls -l FILE" "FILE"))
1277
(defvar howm-view-summary-shell-last-file "FILE")
1278
(defun howm-view-summary-shell-command ()
1280
(when (not (member major-mode
1281
'(howm-view-summary-mode)))
1282
(error "Invalid mode for this command."))
1283
(let* ((n (howm-view-line-number))
1284
(item (nth (1- n) (howm-view-item-list)))
1285
(file (howm-page-abbreviate-name (howm-view-item-filename item)))
1286
(last-reg (regexp-quote howm-view-summary-shell-last-file)))
1287
(setq howm-view-summary-shell-hist
1289
(replace-regexp-in-string last-reg file h t))
1290
howm-view-summary-shell-hist))
1291
(setq howm-view-summary-shell-last-file file)
1292
(let* ((default (car howm-view-summary-shell-hist))
1293
(c (read-string "command: "
1295
'(howm-view-summary-shell-hist . 1))))
1297
(let ((item-list (howm-cl-remove-if (lambda (item)
1299
(howm-view-item-filename item))))
1300
(howm-view-item-list))))
1301
(setq *riffle-summary-check* nil) ;; dirty
1302
(howm-view-summary (howm-view-name) item-list)
1304
(save-selected-window
1305
(let ((b (get-buffer "*Shell Command Output*")))
1306
(cond ((not (howm-buffer-empty-p b))
1307
(switch-to-buffer-other-window b))
1308
((eq item (riffle-summary-current-item))
1311
(setq *riffle-summary-check* t) ;; dirty
1312
(howm-view-summary-check t))))))
1315
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1318
(provide 'howm-view)
1320
;;; howm-view.el ends here