home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / gnu / emacs / sources / 914 < prev    next >
Encoding:
Text File  |  1992-12-31  |  16.7 KB  |  501 lines

  1. Xref: sparky gnu.emacs.sources:914 gnu.emacs.gnus:1443
  2. Path: sparky!uunet!spool.mu.edu!wupost!csus.edu!ucdavis!caldwr!rfinch
  3. From: rfinch@caldwr.water.ca.gov (Ralph Finch)
  4. Newsgroups: gnu.emacs.sources,gnu.emacs.gnus
  5. Subject: gnus-3.14: aging kill lines
  6. Keywords: kill files
  7. Message-ID: <949@caldwr.water.ca.gov>
  8. Date: 1 Jan 93 03:54:54 GMT
  9. Followup-To: gnu.emacs.gnus
  10. Organization: Calif. Dept. of Water Resources, Sac.
  11. Lines: 488
  12.  
  13.  
  14. Following is a patch to implement 2 additions to gnus-3.14 kill files:
  15. easy kills and aging kills.
  16.  
  17. WARNING: THIS PATCH IS EXPERIMENTAL.  Please don't use it until you've
  18. backed up your .newsrc* files and your kill files, and your gnus.el
  19. file.  Hopefully a few people will be willing to try this for a while,
  20. make suggestions, and eventually I'll release a non-beta version.
  21.  
  22. You will need timezone.el to use this; I think it comes with gnus-3.14.
  23.  
  24. Explanation.  I use C-k (and sometimes k) a lot in subject buffers to
  25. zip through uninteresting articles.  But when I exit gnus and start it
  26. up the next day, the same articles (threads) appear again, of course.
  27. Firing up kill files all the time is too cumbersome for me.  So I
  28. wanted an easy way to place subject lines killed with C-k and k in
  29. kill files.
  30.  
  31. However, that brings up another problem: huge kill files.  You need
  32. some way of deleting the old kill lines automatically after they've
  33. served their purpose.
  34.  
  35. This patch implements both of the above ideas.
  36.  
  37. After installing the patch, the first concept (easy kill files), is
  38. activated with the variable gnus-save-kills.  If non-nil (default), it
  39. will place the subject line of every C-k or k in the proper kill file,
  40. and also put the line '(gnus-expunge "X")' at the end of the file if
  41. it's not there already.  That way when you look at that group the next
  42. day, the old subjects will be automatically killed for you.
  43.  
  44. The second concept, aging kill lines, is implemented with two
  45. variables, gnus-max-creation-intrvl and gnus-max-hit-intrvl.  These
  46. two variables control how many days to allow before deleting kill
  47. lines in kill files, after creation of the line and its last 'hit',
  48. that is, when that kill line last killed anything.  Default values are
  49. 30 days and 10 days respectively.  You can use both of these, or
  50. either one; set them to nil to turn them off.  If these are some
  51. integer value, gnus will put the current date for each one after a
  52. comment on each line in your kill files.  The creation date will then
  53. never change; the hit date will be updated every time that line gets a
  54. hit.  If, when initially going through a kill file, gnus sees that
  55. either interval is exceeded, it will delete that line, thus preventing
  56. your kill files from growing forever with obsolete kills.
  57.  
  58. Kill files are now automatically saved when you exit gnus.
  59.  
  60. You can still hand edit your kill files in the usual way, they will
  61. just have dates in them.  Aging kill lines works with both subject and
  62. author kill lines.  Also, new style kill files can still be read by an
  63. original gnus-3.14.
  64.  
  65. There's one other new variable: gnus-kill-header-length.  Set this to
  66. some int (default is 20) to specify the length of a center subsection
  67. of a subject line to use in kill files.  This prevents missing kills
  68. because of Re: stuck on the front, or some other often subtle change
  69. in a subject line.
  70.  
  71. Please send comments and bug reports to rfinch@water.ca.gov.
  72.  
  73. *** gnus.el~    1992/12/02 01:28:34
  74. --- gnus.el    1992/12/16 00:49:36
  75. ***************
  76. *** 109,114 ****
  77. --- 110,116 ----
  78.   (provide 'gnus)
  79.   (require 'nntp)
  80.   (require 'mail-utils)
  81. + (require 'timezone)
  82.   
  83.   (defvar gnus-nntp-server (getenv "NNTPSERVER")
  84.     "*The name of the host running NNTP server.
  85. ***************
  86. *** 558,563 ****
  87. --- 560,578 ----
  88.   (defvar gnus-Info-directory Info-directory
  89.     "*A directory placing an Info file of GNUS.")
  90.   
  91. + (defvar gnus-max-creation-intrvl 30
  92. +   "*Maximum days to allow a kill item to exist since creation;
  93. + nil if no limit.")
  94. + (defvar gnus-max-hit-intrvl 10
  95. +   "*Maximum days to allow a kill item to exist since last hit;
  96. + nil if no limit.")
  97. + (defvar gnus-save-kills t
  98. +   "*If non-nil, when \\[gnus-Subject-kill-same-subject] is done,
  99. + save in kill file also.")
  100. + (defvar gnus-kill-header-length 20
  101. +   "*If int, the length of a center substring to save from the
  102. + subject line when used in kill files.")
  103.   
  104.   ;; Internal variables.
  105.   
  106. ***************
  107. *** 709,714 ****
  108. --- 724,732 ----
  109.   (defvar rmail-last-file (expand-file-name "~/XMBOX"))
  110.   (defvar rmail-last-rmail-file (expand-file-name "~/XNEWS"))
  111.   
  112. + (defvar gnus-successful-kill nil
  113. +   "t if gnus-kill was successful.")
  114.   ;; Define GNUS Subsystems.
  115.   (autoload 'gnus-Group-post-news "gnuspost"
  116.         "Post an article." t)
  117. ***************
  118. *** 1537,1542 ****
  119. --- 1555,1561 ----
  120.         (progn
  121.       (message "")            ;Erase "Yes or No" question.
  122.       (run-hooks 'gnus-Exit-gnus-hook)
  123. +     (gnus-exit-kill-files)
  124.       (gnus-save-newsrc-file)
  125.       (gnus-clear-system)
  126.       (gnus-close-server))
  127. ***************
  128. *** 1749,1756 ****
  129.   \\[gnus-Subject-catch-up-all-and-exit]
  130.       Catch up all articles, and then exit the current newsgroup.
  131.   C-t    Toggle truncations of subject lines.
  132. - x    Delete subject lines marked as read.
  133. - X    Delete subject lines with the specific marks.
  134.   C-c C-s C-n    Sort subjects by article number.
  135.   C-c C-s C-a    Sort subjects by article author.
  136.   C-c C-s C-s    Sort subjects alphabetically.
  137. --- 1768,1773 ----
  138. ***************
  139. *** 2977,2982 ****
  140. --- 2994,3016 ----
  141.     (let ((count
  142.        (gnus-Subject-mark-same-subject
  143.         (gnus-Subject-subject-string) unmark)))
  144. +     ;; save in kill file if desired
  145. +     (if gnus-save-kills
  146. +     (progn
  147. +       (setq gnus-current-kill-article (gnus-Subject-article-number))
  148. +       (save-excursion
  149. +         (find-file (gnus-newsgroup-kill-file gnus-newsgroup-name))
  150. +         (save-excursion
  151. +           (beginning-of-buffer)
  152. +           (gnus-Kill-file-kill-by-subject)
  153. +           ;; add gnus-expunge at end of buffer, if needed
  154. +           (if (not (re-search-forward "^ *\(gnus-expunge" nil t))
  155. +           (progn
  156. +             (end-of-buffer)
  157. +             (if (not (bolp))
  158. +             (insert "\n"))
  159. +             (insert "(gnus-expunge \"X\")\n"))))
  160. +         (bury-buffer))))
  161.       ;; Select next unread article. If auto-select-same mode, should
  162.       ;; select the first unread article.
  163.       (gnus-Subject-next-article t (and gnus-auto-select-same
  164. ***************
  165. *** 2995,3000 ****
  166. --- 3029,3051 ----
  167.     (let ((count
  168.        (gnus-Subject-mark-same-subject
  169.         (gnus-Subject-subject-string) unmark)))
  170. +     ;; save in kill file if desired
  171. +     (if gnus-save-kills
  172. +     (progn
  173. +       (setq gnus-current-kill-article (gnus-Subject-article-number))
  174. +       (save-excursion
  175. +         (find-file (gnus-newsgroup-kill-file gnus-newsgroup-name))
  176. +         (save-excursion
  177. +           (beginning-of-buffer)
  178. +           (gnus-Kill-file-kill-by-subject)
  179. +           ;; add gnus-expunge at end of buffer, if needed
  180. +           (if (not (re-search-forward "^ *\(gnus-expunge" nil t))
  181. +           (progn
  182. +             (end-of-buffer)
  183. +             (if (not (bolp))
  184. +             (insert "\n"))
  185. +             (insert "(gnus-expunge \"X\")\n"))))
  186. +         (bury-buffer))))
  187.       ;; If marked as read, go to next unread subject.
  188.       (if (null unmark)
  189.       ;; Go to next unread subject.
  190. ***************
  191. *** 3149,3164 ****
  192.   (defun gnus-Subject-delete-marked-with (marks)
  193.     "Delete lines which are marked with MARKS (e.g. \"DK\")."
  194.     (interactive "sMarks: ")
  195. !   (let ((buffer-read-only nil))
  196. !     (save-excursion
  197. !       (goto-char (point-min))
  198. !       (delete-matching-lines (concat "^[" marks "]")))
  199. !     ;; Adjust point.
  200. !     (or (zerop (buffer-size))
  201. !     (if (eobp)
  202. !         (gnus-Subject-prev-subject 1)
  203. !       (beginning-of-line)
  204. !       (search-forward ":" nil t)))
  205.       ))
  206.   
  207.   ;; Thread-based commands.
  208. --- 3200,3217 ----
  209.   (defun gnus-Subject-delete-marked-with (marks)
  210.     "Delete lines which are marked with MARKS (e.g. \"DK\")."
  211.     (interactive "sMarks: ")
  212. !   (save-excursion
  213. !     (set-buffer gnus-Subject-buffer)
  214. !     (let ((buffer-read-only nil))
  215. !       (save-excursion
  216. !     (goto-char (point-min))
  217. !     (delete-matching-lines (concat "^[" marks "]")))
  218. !       ;; Adjust point.
  219. !       (or (zerop (buffer-size))
  220. !       (if (eobp)
  221. !           (gnus-Subject-prev-subject 1)
  222. !         (beginning-of-line)
  223. !         (search-forward ":" nil t))))
  224.       ))
  225.   
  226.   ;; Thread-based commands.
  227. ***************
  228. *** 4310,4331 ****
  229.     "Insert KILL command for current subject."
  230.     (interactive)
  231.     (insert
  232. !    (format "(gnus-kill \"Subject\" %s)\n"
  233.          (prin1-to-string
  234.           (if gnus-current-kill-article
  235.           (regexp-quote
  236. !          (nntp-header-subject
  237. !           ;; No need to speed up this command.
  238. !           ;;(gnus-get-header-by-number gnus-current-kill-article)
  239. !           (gnus-find-header-by-number gnus-newsgroup-headers
  240. !                           gnus-current-kill-article)))
  241. !           "")))))
  242.   
  243.   (defun gnus-Kill-file-kill-by-author ()
  244.     "Insert KILL command for current author."
  245.     (interactive)
  246.     (insert
  247. !    (format "(gnus-kill \"From\" %s)\n"
  248.          (prin1-to-string
  249.           (if gnus-current-kill-article
  250.           (regexp-quote
  251. --- 4363,4397 ----
  252.     "Insert KILL command for current subject."
  253.     (interactive)
  254.     (insert
  255. !    (format "(gnus-kill \"Subject\" %s)%s%s\n"
  256.          (prin1-to-string
  257.           (if gnus-current-kill-article
  258.           (regexp-quote
  259. !          (let ((lendiff nil)
  260. !                (str (nntp-header-subject
  261. !                  ;; No need to speed up this command.
  262. !                  ;;(gnus-get-header-by-number gnus-current-kill-article)
  263. !                  (gnus-find-header-by-number gnus-newsgroup-headers
  264. !                              gnus-current-kill-article))))
  265. !            (if (and gnus-kill-header-length
  266. !                 (> (setq lendiff2 (/ (- (length str)
  267. !                             gnus-kill-header-length)
  268. !                          2)) 0))
  269. !                (substring str lendiff2 (- lendiff2))
  270. !              str)))
  271. !           ""))
  272. !        (if gnus-max-creation-intrvl
  273. !            (concat "; creation-date #" (current-time-string) "#")
  274. !          "")
  275. !        (if gnus-max-hit-intrvl
  276. !            (concat "; hit-date #" (current-time-string) "#")
  277. !          ""))))
  278.   
  279.   (defun gnus-Kill-file-kill-by-author ()
  280.     "Insert KILL command for current author."
  281.     (interactive)
  282.     (insert
  283. !    (format "(gnus-kill \"From\" %s)%s%s\n"
  284.          (prin1-to-string
  285.           (if gnus-current-kill-article
  286.           (regexp-quote
  287. ***************
  288. *** 4334,4340 ****
  289.             ;;(gnus-get-header-by-number gnus-current-kill-article)
  290.             (gnus-find-header-by-number gnus-newsgroup-headers
  291.                             gnus-current-kill-article)))
  292. !           "")))))
  293.   
  294.   (defun gnus-Kill-file-apply-buffer ()
  295.     "Apply current buffer to current newsgroup."
  296. --- 4400,4413 ----
  297.             ;;(gnus-get-header-by-number gnus-current-kill-article)
  298.             (gnus-find-header-by-number gnus-newsgroup-headers
  299.                             gnus-current-kill-article)))
  300. !           ""))
  301. !        (if gnus-max-creation-intrvl
  302. !            (concat "; creation-date #" (current-time-string) "#")
  303. !          "")
  304. !        (if gnus-max-hit-intrvl
  305. !            (concat "; hit-date #" (current-time-string) "#")
  306. !          ""))))
  307.   
  308.   (defun gnus-Kill-file-apply-buffer ()
  309.     "Apply current buffer to current newsgroup."
  310. ***************
  311. *** 4367,4373 ****
  312.   (defun gnus-Kill-file-exit ()
  313.     "Save a KILL file, then return to the previous buffer."
  314.     (interactive)
  315. !   (save-buffer)
  316.     (let ((killbuf (current-buffer)))
  317.       ;; We don't want to return to Article buffer.
  318.       (and (get-buffer gnus-Article-buffer)
  319. --- 4440,4446 ----
  320.   (defun gnus-Kill-file-exit ()
  321.     "Save a KILL file, then return to the previous buffer."
  322.     (interactive)
  323. !   (if (buffer-modified-p) (save-buffer))
  324.     (let ((killbuf (current-buffer)))
  325.       ;; We don't want to return to Article buffer.
  326.       (and (get-buffer gnus-Article-buffer)
  327. ***************
  328. *** 4519,4527 ****
  329.   (defun gnus-apply-kill-file ()
  330.     "Apply KILL file to the current newsgroup."
  331.     ;; Apply the global KILL file.
  332. !   (load (gnus-newsgroup-kill-file nil) t nil t)
  333.     ;; And then apply the local KILL file.
  334. !   (load (gnus-newsgroup-kill-file gnus-newsgroup-name) t nil t))
  335.   
  336.   (defun gnus-Newsgroup-kill-file (newsgroup)
  337.     "Return the name of a KILL file of NEWSGROUP.
  338. --- 4592,4726 ----
  339.   (defun gnus-apply-kill-file ()
  340.     "Apply KILL file to the current newsgroup."
  341.     ;; Apply the global KILL file.
  342. !   (gnus-load (gnus-newsgroup-kill-file nil))
  343.     ;; And then apply the local KILL file.
  344. !   (gnus-load (gnus-newsgroup-kill-file gnus-newsgroup-name)))
  345. ! (defun gnus-load (fn)
  346. !   "Load FILENAME (containing lisp code) and execute commands, if
  347. ! either the creation or hit date are ok or if they don't exist; if
  348. ! command returns non-nil, update hit-date, which if exists is in a
  349. ! comment after each command.  No error if filename does not exist; do
  350. ! not add .el and .elc suffixes."
  351. !   (if (not (file-readable-p fn))
  352. !       nil
  353. !     (let ((creation-date nil)
  354. !       (hit-date nil)
  355. !       (hit-date-start nil)
  356. !       (hit-date-end nil)
  357. !       (kill-line nil)
  358. !       (bol nil)
  359. !       (eol nil)
  360. !       (writable (file-writable-p fn)))
  361. !       (save-excursion
  362. !     (find-file fn)
  363. !     (goto-char (point-min))
  364. !     (while (not (eobp))
  365. !       (beginning-of-line)
  366. !       (setq bol (point)
  367. !         kill-line (looking-at "(gnus-kill")
  368. !         gnus-successful-kill nil)
  369. !       (save-excursion
  370. !         (end-of-line)
  371. !         (setq eol (point)))
  372. !       (setq creation-date (if (re-search-forward
  373. !                    "; *creation-date *#\\([^#]+\\) *#" eol t)
  374. !                   (buffer-substring (match-beginning 1) (match-end 1))
  375. !                 nil)
  376. !         hit-date (if (re-search-forward
  377. !                   "; *hit-date *#\\([^#]+\\) *#" eol t)
  378. !                  (buffer-substring (match-beginning 1) (match-end 1))
  379. !                nil)
  380. !         hit-date-start (if hit-date
  381. !                    (match-beginning 1) nil)
  382. !         hit-date-end (if hit-date
  383. !                  (match-end 1) nil))
  384. !       (if (and (or (and creation-date
  385. !                 (> (gnus-date-diff (current-time-string) creation-date)
  386. !                    gnus-max-creation-intrvl))
  387. !                (and hit-date
  388. !                 (> (gnus-date-diff (current-time-string) hit-date)
  389. !                    gnus-max-hit-intrvl)))
  390. !            writable)
  391. !           ;; delete the line, it's old
  392. !           (progn
  393. !         (setq del-line t)
  394. !         (goto-char bol)
  395. !         (kill-line 1))
  396. !         (eval-region bol eol)
  397. !         (if kill-line
  398. !         (progn
  399. !           (if (and hit-date
  400. !                gnus-successful-kill
  401. !                writable)
  402. !               (progn
  403. !             (goto-char hit-date-start)
  404. !             (delete-region (point) hit-date-end)
  405. !             (insert (current-time-string))))
  406. !           (if writable
  407. !               (progn
  408. !             (if (and gnus-max-creation-intrvl
  409. !                  (not creation-date))
  410. !                 (progn
  411. !                   (end-of-line)
  412. !                   (insert (concat "; creation-date #" (current-time-string) "#"))))
  413. !             (if (and gnus-max-hit-intrvl
  414. !                  (not hit-date))
  415. !                 (progn
  416. !                   (end-of-line)
  417. !                   (insert (concat "; hit-date #" (current-time-string) "#"))))))))
  418. !         (forward-line 1))))
  419. !       )))
  420. !      
  421. ! (defun gnus-julday (date)
  422. !   "Returns the Julian day for DATE."
  423. !   (let* ((date   (timezone-parse-date date))
  424. !      (year   (string-to-int (aref date 0)))
  425. !      (month  (string-to-int (aref date 1)))
  426. !      (day    (string-to-int (aref date 2)))
  427. !      (m 1)
  428. !      (juldays 0))
  429. !     (while (< m month)
  430. !       (setq juldays (+ juldays (timezone-last-day-of-month m year))
  431. !         m (+ m 1)))
  432. !     (+ juldays day)))
  433. ! (defun gnus-date-diff (date1 date2)
  434. !   "Calculate the difference in days between DATE1 and DATE2."
  435. !   (let* (
  436. !      (date1-orig date1)
  437. !      (date1   (timezone-parse-date date1))
  438. !      (year1   (string-to-int (aref date1 0)))
  439. !      (month1  (string-to-int (aref date1 1)))
  440. !      (day1    (string-to-int (aref date1 2)))
  441. !      (julday1 (gnus-julday date1-orig))
  442. !      (date2-orig date2)
  443. !      (date2   (timezone-parse-date date2))
  444. !      (year2   (string-to-int (aref date2 0)))
  445. !      (month2  (string-to-int (aref date2 1)))
  446. !      (day2    (string-to-int (aref date2 2)))
  447. !      (julday2 (gnus-julday date2-orig))
  448. !      
  449. !      (year-diff (- year1 year2))
  450. !      (day-diff (- julday1 julday2))
  451. !      (tot-days-diff (+ (* year-diff 365) day-diff)))
  452. !     tot-days-diff))
  453. ! (defun gnus-exit-kill-files ()
  454. !   "Exit all kill files."
  455. !   (save-excursion
  456. !     (let ((list (buffer-list)))
  457. !       (while list
  458. !     (let* ((buf (car list))
  459. !            (fn (buffer-file-name buf)))
  460. !       (if (and fn
  461. !            (string-equal (substring fn (- (length gnus-kill-file-name)))
  462. !                  gnus-kill-file-name))
  463. !           (progn
  464. !         (switch-to-buffer buf)
  465. !         (gnus-Kill-file-exit))))
  466. !     (setq list (cdr list))))))
  467.   
  468.   (defun gnus-Newsgroup-kill-file (newsgroup)
  469.     "Return the name of a KILL file of NEWSGROUP.
  470. ***************
  471. *** 4832,4837 ****
  472. --- 5031,5037 ----
  473.                (or (stringp value)
  474.                (setq value (prin1-to-string value)))
  475.                (string-match regexp value))
  476. +            (setq gnus-successful-kill t)
  477.              (if (stringp form)    ;Keyboard macro.
  478.                  (execute-kbd-macro form)
  479.                (funcall form))))
  480. ***************
  481. *** 4847,4852 ****
  482. --- 5047,5053 ----
  483.             (set-buffer gnus-Article-buffer)
  484.             (goto-char (point-min))
  485.             (re-search-forward regexp nil t))
  486. +         (setq gnus-successful-kill t)
  487.           (if (stringp form)    ;Keyboard macro.
  488.               (execute-kbd-macro form)
  489.             (funcall form))))
  490. -- 
  491. Ralph Finch            916-653-8268
  492. rfinch@water.ca.gov        ...ucbvax!ucdavis!caldwr!rfinch
  493. Any opinions expressed are my own; they do not represent the DWR
  494.