home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / packages / gnus-topic.el < prev    next >
Encoding:
Text File  |  1991-07-03  |  13.7 KB  |  510 lines

  1. ; Path: dg-rtp!rock!mcnc!stanford.edu!agate!ucbvax!cis.ohio-state.edu!zaphod.mps.ohio-state.edu!swrinde!cs.utexas.edu!uunet!lll-winken!aunro!alberta!cpsc.ucalgary.ca!krawchuk
  2. ; From: krawchuk@cpsc.UCalgary.ca (Bj Krawchuk)
  3. ; Newsgroups: gnu.emacs.sources,gnu.emacs.gnus,news.software.readers
  4. ; Subject: gnus-topic.el 1.0 : A Topic Mode for GNUS
  5. ; Date: 29 Jun 91 06:18:03 GMT
  6. ; Organization: The University of Calgary
  7. ; gnus-topic 1.0 provides another mode to GNUS, in addition to 
  8. ; The idea of it is to organize the selection and maintenance
  9. ; of groups of newsgroups, which I call Topics.
  10. ; This is not yet a finished product. I am posting it in the hope
  11. ; that people will help me work on it. I am low on time and would
  12. ; like the emergence of an excellent product sooner than I could
  13. ; provide it working on it alone.
  14. ; Anyone wishing to do enhancements, bug fixes and changes should 
  15. ; contact me, and I will coordinate the development. 
  16. ; Or we could do the development via posting. 
  17. ; Any volunteers?
  18. ; Since this is not nearly finished, expect bugs, and annoyances.
  19. ; Nevertheless, I have been using this current version for several
  20. ; days now, and still would rather not do without it.
  21. ; Number one on the priority list for enhancements is to speed up 
  22. ; article counting. Right now it takes me about 3 seconds to update 
  23. ; the topic listing. (But I have a huge .newsrc ...). Also,
  24. ; maintence of the newsgroup regexps has not been written yet.
  25. ; They currently have to be edited in the ~/.topics file. 
  26. ; (And I have a bunch of other beefs...)
  27.  
  28. ; I have posted this news.software.readers since there has recently
  29. ; been some talk there about newsgroup organization. 
  30. ; This may provide a starting point for further GNUS development
  31. ; on group handling. For example, group melding could be done using
  32. ; this as its user interface. 
  33. ;
  34. ; Enjoy, and please help me out, if you can and want to.
  35. ;
  36. ; Cheers
  37. ;    Bj  <krawchuk@cpsc.ucalgary.ca>
  38. ;
  39.  
  40. ;;;-------------------------------------------------------------------
  41. ;;;
  42. ;;; gnus-topic.el 1.0
  43. ;;; Organize newsgroups by topic   
  44. ;;; Jun 91
  45. ;;; Bj Krawchuk <krawchuk@cpsc.ucalgary.ca>
  46. ;;; [Awefold Compatible]
  47. ;;;
  48. ;;; LCD Archive Entry:
  49. ;;; gnus-topic|Bj Krawchuk|krawchuk@cpsc.UCalgary.ca
  50. ;;; |Topics mode for GNUS for organizing newsgroups
  51. ;;; |91-06-29|1.0|~/packages/gnus-topic.el.Z
  52. ;;;
  53. ;;; See mode description for keybindings 
  54. ;;; (type ? in topic mode eg.)
  55. ;;;
  56. ;;; ------------------------
  57. ;:: .topics file
  58. ;;; ------------------------
  59. ;;;
  60. ;;; in this version a .topics file must be included in your home directory
  61. ;;; Here is my .topics file
  62. ;;;
  63. ;;; (setq gnus-topic-alist 
  64. ;;; '( 
  65. ;;;  ("Health"     "sci.med" "alt.psychoactives" "sci.psychology")
  66. ;;;  ("Drugs"      "alt.drugs" "talk.politics.drugs")  
  67. ;;;  ("Politics"   "alt.individualism")
  68. ;;;  ("Misc"    "misc.misc" "comp.archives" "comp.risks")
  69. ;;;  ("PC"    "comp.binaries" "comp.sys.ibm.pc")
  70. ;;;  ("Emacs"      "emacs")
  71. ;;;  ("Gnu"        "gnu")
  72. ;;;  ("Vm"    "gnu.emacs.vm")
  73. ;;;  ("News"       "alt.config" "news")
  74. ;;;  ("Sources"    "source")
  75. ;;;  ("Skepticism" "sci.skeptic" "talk.origins" "alt.paranormal" "alt.atheism")
  76. ;;;  ("Religion"   "alt.atheism" "religion"  "alt.magick" "alt.pagan" 
  77. ;;;        "newage" "talk.origins")
  78. ;;;  ("Research" "sci.logic" "comp.theory")
  79. ;;;  ("Radio"    "radio")
  80. ;;;  ("Calgary"    "calgary")
  81. ;;;  ("Cpsc"    "cpsc")
  82. ;;;  ("Comp"    "comp")
  83. ;;;  ("Sci"    "sci")
  84. ;;;  ("Can"    "can")
  85. ;;;  ("Music"    "music")
  86. ;;;  ("Ai"    "ai")
  87. ;;;  ("All"    "")
  88. ;;;  ))
  89. ;;;
  90. ;:|
  91. ;;; ------------------------
  92. ;:: .emacs startup additions
  93. ;;; ------------------------
  94. ;;;
  95. ;;; (setq gnus-Startup-hook 
  96. ;;;  (function (lambda () (gnus-create-topic-buffer))))
  97. ;;;
  98. ;;; (setq gnus-Group-prepare-hook
  99. ;;;  (function (lambda () (gnus-topic-Group-prepare-hook-fn))))
  100. ;;;    
  101. ;;;
  102. ;;; (setq gnus-Group-mode-hook 
  103. ;;;  (function (lambda () (require 'gnus-topic) 
  104. ;;;              (gnus-topic-Group-mode-hook-fn))))
  105. ;;;
  106. ;:|
  107. ;;;-------------------------------------------------------------------
  108.  
  109. (require 'cl)
  110.  
  111. ;:: Variables
  112.  
  113. (defvar gnus-Topic-buffer "*Topic*") ; gnus-buffer-list should have this
  114.  
  115. (defvar gnus-topic-alist 
  116.  '(     ("Health" "sci.med" "alt.psychoactives")
  117.     ("Emacs"  "comp.emacs" "gnu.emacs.sources" "gnu.emacs.help")
  118.   ) ; just a sample
  119.  "Association List")
  120.  
  121. (defvar gnus-topic-newsgroups 
  122.     '("")     ; startup Group buffer with all newsgroups
  123.     "Currently chosen newsgroups")
  124.  
  125. ;:|
  126.  
  127. ;:: Topic Mode
  128.  
  129. ;:: Topic Mode Keymap
  130. (defvar gnus-Topic-mode-map nil)
  131.  
  132. (if gnus-Topic-mode-map 
  133.     nil
  134.   (setq gnus-Topic-mode-map (make-keymap))
  135.   (suppress-keymap gnus-Topic-mode-map)
  136.   (define-key gnus-Topic-mode-map " " 'gnus-Topic-select-topic)
  137.   (define-key gnus-Topic-mode-map "=" 'gnus-Topic-select-all-topic)
  138.   (define-key gnus-Topic-mode-map "n" 'gnus-Topic-next-topic)
  139.   (define-key gnus-Topic-mode-map "p" 'gnus-Topic-prev-topic)
  140.   (define-key gnus-Topic-mode-map "l" 'gnus-Topic-list-topics)
  141.   (define-key gnus-Topic-mode-map "L" 'gnus-Topic-list-topics-verbose)
  142.   (define-key gnus-Topic-mode-map "r" 'gnus-Topic-read-topic-file)
  143.   (define-key gnus-Topic-mode-map "x" 'gnus-Group-force-update)
  144.   (define-key gnus-Topic-mode-map "s" 'gnus-Group-force-update)
  145.   (define-key gnus-Topic-mode-map "t" 'gnus-Topic-toggle-regexp-display) 
  146.   (define-key gnus-Topic-mode-map "g" 'gnus-Topic-select-group-buffer)
  147.   (define-key gnus-Topic-mode-map "q" 'gnus-Group-exit)
  148.   (define-key gnus-Topic-mode-map "Q" 'gnus-Group-quit)
  149.   (define-key gnus-Topic-mode-map "?" 'describe-mode)
  150. )
  151.  
  152.  
  153. ;:|
  154.  
  155. ;:: Gnus Topic Mode
  156.  
  157. (defun gnus-Topic-mode ()
  158.  "Major mode for organizing, selecting topics in GNUS.
  159. A Topic enables grouping of newsgroups together.
  160.  
  161. SPC    Select this topic
  162. =    Select this topic including unread groups
  163. n    Move to the next topic
  164. p    Move to the previous topic
  165. l    List (update) current topic list
  166. L    List all topics, even those with no unread articles
  167. r    Read topic file (~/.topics)
  168. s,x    Force update of .newsrc
  169. t    Toggle newsgroup regexp display
  170. g    Jump to Group buffer (last selected)
  171. q    exit news (gnus-Group-exit)
  172. Q    quit news (gnus-Group-quit)
  173.  
  174. In the Group mode:
  175.  
  176. q    return to Topic mode
  177. Q    return to Topic mode without recomputing article totals."
  178.  
  179.  
  180.  (interactive)
  181.   (cond ((boundp 'mode-line-modified)
  182.      (setq mode-line-modified "--- "))
  183.     ((listp (default-value 'mode-line-format))
  184.      (setq mode-line-format
  185.            (cons "--- " (cdr (default-value 'mode-line-format)))))
  186.     (t
  187.      (setq mode-line-format
  188.            "--- GNUS: List of Topics  %[(%m)%]----%3p-%-")))
  189.   (setq major-mode 'gnus-Topic-mode)
  190.   (setq mode-name "Topic")
  191.   (setq mode-line-buffer-identification    "GNUS: List of Topics")
  192.   (setq mode-line-process nil)
  193.   (use-local-map gnus-Topic-mode-map)
  194.   (buffer-flush-undo (current-buffer))
  195.   (gnus-Topic-read-topic-file)
  196.   (gnus-Topic-list-topics)
  197.   (goto-char (point-min))
  198.   (if (not (eobp))
  199.    (progn (search-forward ":" nil t)
  200.         (forward-char -1)))
  201.   (setq buffer-read-only t)        ;Disable modification
  202.   (run-hooks 'gnus-Topic-mode-hook) 
  203. )
  204.  
  205.  
  206.  
  207. ;:|
  208.  
  209. ;:: Startup stuff
  210.  
  211. (defvar gnus-topic-startup-in-topic-buffer t
  212.   "Should the topic buffer be the first thing you see?")
  213.  
  214. (defun gnus-create-topic-buffer ()
  215.  "For use in gnus-Startup-hook."
  216.   (set-buffer (get-buffer-create gnus-Topic-buffer))
  217.   (setq gnus-topic-starting t)
  218.   (gnus-Topic-mode)
  219.   (setq gnus-buffer-list (cons gnus-Topic-buffer gnus-buffer-list))
  220.   (set-buffer gnus-Group-buffer))
  221.  
  222.  
  223.  
  224. ;:|
  225.  
  226.  
  227. ;:|
  228.  
  229. ;:: Interactive Functions
  230.  
  231. ;:: Topic Listing
  232.  
  233.  
  234. (defun gnus-Topic-list-topics (&optional show-all)
  235.   "List topics in the Topic buffer."
  236.   (interactive nil)
  237.   (setq gnus-Topic-current-topic 1)
  238.   (gnus-topic-list-topics-aux show-all))
  239.  
  240. (defun gnus-topic-list-topics-aux (&optional show-all)
  241.   "List topics in the Topic buffer."
  242.   (interactive nil)
  243.   (let ((topics gnus-topic-alist)
  244.         (buffer-read-only nil))
  245.   (erase-buffer)
  246.   (while topics
  247.    (let ((topic (car topics)))
  248.     (let ((num-arts (gnus-topic-calc-number-of-articles (cdr topic))))
  249.      (if (or show-all (not (zerop num-arts)))
  250.        (progn
  251.          (insert (format "[%3d] : %s\n" num-arts (car topic)))
  252.      (if gnus-Topic-regexp-display
  253.         (progn (setq topic (cdr topic))    
  254.             (while topic
  255.               (insert (format "\t  %s\n" (car topic))) 
  256.               (setq topic (cdr topic)))))))))
  257.    (setq topics (cdr topics)))
  258.   (set-buffer-modified-p nil)
  259.   (gnus-Topic-jump-to-topic gnus-Topic-current-topic)))
  260.  
  261. (defun gnus-Topic-list-topics-verbose ()
  262.   "List topics in the Topic buffer with newsgroups."
  263.   (interactive)
  264.   (gnus-Topic-list-topics t))
  265.  
  266. ;:|
  267.  
  268. ;:: Topic Navigation
  269.  
  270. (defun gnus-Topic-first-topic ()
  271.  "Move to first topic."
  272.  (interactive)
  273.  (goto-char (point-min))
  274.  (gnus-Topic-find-topic-marker))
  275.  
  276. (defun gnus-Topic-find-topic-marker ()
  277.  "Find the colon on current line."
  278.  (beginning-of-line)
  279.  (if (not (= (point-min) (point-max)))
  280.   (progn (search-forward ":" nil t)
  281.      (forward-char -1))))
  282.  
  283.  
  284. (defun gnus-Topic-next-topic ()
  285.  "Move to next topic."
  286.  (interactive)
  287.  (forward-char 1)
  288.  (if (not (re-search-forward ":" nil t))
  289.     (gnus-Topic-first-topic)
  290.     (forward-char -1)))
  291.  
  292. (defun gnus-Topic-prev-topic ()
  293.  "Move to next topic."
  294.  (interactive)
  295.  (beginning-of-line)
  296.  (if (not (re-search-backward ":" nil t))
  297.     (progn (goto-char (point-max))
  298.         (re-search-backward ":" nil t))))
  299.  
  300. ;:|
  301.  
  302. ;:: Topic Selection
  303. (defvar gnus-Topic-current-topic 1
  304.     "The currently selected topic's line-number. Just a hack for now.")
  305.  
  306. (defun gnus-Topic-jump-to-topic (line-no)
  307.  "Move to topic on line-no."
  308.  (interactive "p")
  309.  (goto-line line-no)
  310.  (gnus-Topic-find-topic-marker)
  311.  (setq gnus-Topic-current-topic line-no))
  312.  
  313.  
  314. (defun gnus-Topic-select-topic (&optional select-all)
  315.  "Choose to read newsgroups for this topic."
  316.   (interactive nil)
  317.   (setq gnus-Topic-current-topic (count-lines (point-min) (point)))
  318.   (setq gnus-topic-newsgroups
  319.     (gnus-topic-lookup gnus-topic-alist
  320.                (gnus-topic-get-topic-name)))
  321.   (set-buffer gnus-Group-buffer)
  322.   (let ((buffer-read-only nil))
  323.       (gnus-Group-prepare select-all)
  324.       (set-buffer-modified-p nil))
  325.   (gnus-Topic-select-group-buffer))
  326.  
  327.  
  328. (defun gnus-Topic-select-all-topic ()
  329.  "Select newsgroups, even empty or unsubscribed groups"
  330.   (interactive)
  331.   (gnus-Topic-select-topic t))
  332.  
  333. (defun gnus-Group-select-topic-buffer (&optional no-update)
  334.  "Move back to topic buffer."
  335.  (interactive nil)
  336.  (switch-to-buffer gnus-Topic-buffer)
  337.  (if (not no-update)
  338.      (gnus-topic-list-topics-aux)))
  339.  
  340. (defun gnus-Group-select-topic-buffer-no-update ()
  341.  "Move back to topic buffer without updating totals"
  342.  (interactive)
  343.  (gnus-Group-select-topic-buffer t)
  344. )  
  345.  
  346. (defun gnus-Topic-select-group-buffer ()
  347.  "Move back to group buffer."
  348.  (interactive)
  349.  (switch-to-buffer gnus-Group-buffer))
  350.  
  351.  
  352. ;:|
  353.  
  354. ;:: Topic file
  355. (defun gnus-Topic-read-topic-file ()
  356.  "bleck"
  357.  (interactive)
  358.  (load "~/.topics")
  359. )
  360.  
  361. (defun gnus-Topic-save-topic-file ()
  362.  "bleck"
  363.  (interactive)
  364.  (message "Not implemented yet.")
  365. )
  366.  
  367.  
  368. ;:|
  369.  
  370. ;:: Regexp display handling
  371. (defvar gnus-Topic-regexp-display nil 
  372.  "Variable to control if the newsgroup regexps should be 
  373. shown beside the topic names.")
  374.  
  375. (defun gnus-Topic-toggle-regexp-display ()
  376.  "Toggle gnus-Topic-regexp-display."
  377.  (interactive)
  378.  (setq gnus-Topic-regexp-display (not gnus-Topic-regexp-display))
  379.  (setq gnus-Topic-current-topic 1)
  380.  (gnus-Topic-list-topics)
  381.  (message "Newsgroup regular expression display %s" 
  382.     (if gnus-Topic-regexp-display "on." "off."))
  383. )
  384.  
  385. ;:|
  386.  
  387.  
  388.  
  389. ;:|
  390.  
  391. ;:: Support Functions
  392. ;:: Topic select stuff
  393.  
  394. (defun gnus-topic-lookup (topic-alist topic)
  395.  "Lookup the regexps for a topic."
  396.     (cond   ((null topic-alist) nil)
  397.         ((string-equal (caar topic-alist) topic)
  398.             (cdar topic-alist))
  399.         (t (gnus-topic-lookup (cdr topic-alist) topic))))
  400.  
  401.  
  402.  
  403. (defun gnus-topic-get-topic-name ()
  404.  "Find the topic name of the currently pointed at topic"
  405.  (save-excursion
  406.  (beginning-of-line)
  407.  (if (not (looking-at "\\[[ 0-9]+\\] :"))
  408.     (re-search-backward ":" nil t))
  409.  (search-forward ":" nil t)
  410.  (forward-char 1)
  411.  (buffer-substring (point) (progn (end-of-line) (point)))))
  412.  
  413.  
  414.  
  415. ;:|
  416.  
  417. ;:: Group Buffer stuff
  418.  
  419. (defun gnus-Group-topic-format-group-buffer ()
  420.  "*Format group buffer, restricting it to currently chosen topic."
  421.  (interactive)  
  422.  (set-buffer gnus-Group-buffer)
  423.   (let ((buffer-read-only nil))
  424.    (goto-char (point-min))
  425.    (while (not (eobp))
  426.      (if (not (string-match-member (gnus-Group-group-name) 
  427.                       gnus-topic-newsgroups))
  428.     (gnus-topic-delete-newsgroup)
  429.     (next-line 1)))
  430.    (goto-char (point-min))
  431.    (if (not (search-forward ":" nil t))
  432.     (message "No newsgroups with messages for this topic"))
  433.    (set-buffer-modified-p nil)))
  434.  
  435.  
  436. (defun gnus-topic-delete-newsgroup ()
  437.  "*Remove current line from newsgroup buffer"
  438.  (beginning-of-line)
  439.  (kill-line 1)
  440. )
  441.  
  442.  
  443.  
  444.  
  445. ;:|
  446.  
  447. ;:: Hook function stuff
  448.  
  449. (defun gnus-topic-Group-prepare-hook-fn ()
  450.  "Topic mode handling hook function for gnus-Group-prepare-hook."
  451.    (if (and gnus-topic-startup-in-topic-buffer
  452.         gnus-topic-starting)
  453.     (gnus-Group-select-topic-buffer))
  454.    (gnus-Group-topic-format-group-buffer)
  455.    (setq gnus-topic-starting nil))
  456.  
  457.  
  458. (defun gnus-topic-Group-mode-hook-fn ()
  459.  "Topic mode handling hook function for gnus-Group-mode-hook."
  460.  (define-key gnus-Group-mode-map "q" 'gnus-Group-select-topic-buffer)
  461.  (define-key gnus-Group-mode-map "Q" 'gnus-Group-select-topic-buffer-no-update)
  462.  
  463. ;:|
  464.  
  465. ;:: Misc support
  466.  
  467. ;:: Counting stuff
  468. (defun gnus-topic-calc-number-of-articles (nglist)
  469.  "Count the number of unread articles covered by the newgroup list"
  470.   (let ((unread-count 0)
  471.     (group-info nil)
  472.     (group-name nil)
  473.         (newsrc gnus-newsrc-assoc))
  474.     (while newsrc
  475.       (if (nth 1 (car newsrc)) ; if subscribed
  476.       (progn
  477.        (setq group-name (caar newsrc))
  478.       (if (string-match-member group-name nglist)
  479.         (setq unread-count 
  480.           (+ unread-count
  481.         (nth 1 (gnus-gethash group-name gnus-unread-hashtb)))))))
  482.       (setq newsrc (cdr newsrc)))
  483.   unread-count))
  484.  
  485.  
  486. ;:|
  487. ;:|
  488. ;:|
  489.  
  490. ;:: Misc Functions
  491.  
  492. (defun string-match-member (str slist)
  493.  "*Check list for string"
  494.  (cond  ((null slist) '())
  495.       ((string-match (car slist) str))
  496.     (t (string-match-member str (cdr slist)))))
  497.  
  498.  
  499. ;:|
  500.  
  501. (provide 'gnus-topic)
  502.  
  503. ;:|
  504.