(w3m-toggle-inline-images): Declare.
[bpt/emacs.git] / lisp / net / newsticker-plainview.el
CommitLineData
2415d4c6
UJ
1;;; newsticker-plainview.el --- Single buffer frontend for newsticker.
2
3;; Copyright (C) 2008 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; Author: Ulf Jasper <ulf.jasper@web.de>
8;; Filename: newsticker-plainview.el
9;; URL: http://www.nongnu.org/newsticker
4da498eb
UJ
10;; Time-stamp: "8. Juni 2008, 20:39:46 (ulf)"
11;; CVS-Version: $Id: newsticker-plainview.el,v 1.2 2008/06/08 18:09:06 miles Exp $
2415d4c6
UJ
12
13;; ======================================================================
14
15;; GNU Emacs is free software: you can redistribute it and/or modify
16;; it under the terms of the GNU General Public License as published by
17;; the Free Software Foundation, either version 3 of the License, or
18;; (at your option) any later version.
19
20;; GNU Emacs is distributed in the hope that it will be useful,
21;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23;; GNU General Public License for more details.
24
25;; You should have received a copy of the GNU General Public License
26;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27
28;; ======================================================================
29;;; Commentary:
30
31;; See newsticker.el
32
33;; ======================================================================
34;;; Code:
35
36(require 'newsticker-ticker)
37(require 'newsticker-reader)
38(require 'derived)
39(require 'xml)
40
41;; Silence warnings
42(defvar tool-bar-map)
43(defvar w3-mode-map)
44(defvar w3m-minor-mode-map)
45
46;; ======================================================================
47;;; Customization
48;; ======================================================================
49(defgroup newsticker-plainview nil
50 "Settings for the simple plain view reader.
51See also `newsticker-plainview-hooks'."
52 :group 'newsticker-reader)
53
54
55(defun newsticker--set-customvar-buffer (symbol value)
56 "Set newsticker-variable SYMBOL value to VALUE.
57Calls all actions which are necessary in order to make the new
58value effective."
59 (if (or (not (boundp symbol))
60 (equal (symbol-value symbol) value))
61 (set symbol value)
62 ;; something must have changed
63 (set symbol value)
64 (newsticker--buffer-set-uptodate nil)))
65
66(defun newsticker--set-customvar-sorting (symbol value)
67 "Set newsticker-variable SYMBOL value to VALUE.
68Calls all actions which are necessary in order to make the new
69value effective."
70 (if (or (not (boundp symbol))
71 (equal (symbol-value symbol) value))
72 (set symbol value)
73 ;; something must have changed
74 (set symbol value)
75 (message "Applying new sort method...")
76 (when (fboundp 'newsticker--cache-sort) (newsticker--cache-sort))
77 (when (fboundp 'newsticker--buffer-set-uptodate)
78 (newsticker--buffer-set-uptodate nil))
79 (message "Applying new sort method...done")))
80
81(defcustom newsticker-sort-method
82 'sort-by-original-order
83 "Sort method for news items.
84The following sort methods are available:
85* `sort-by-original-order' keeps the order in which the items
86 appear in the headline file (please note that for immortal items,
87 which have been removed from the news feed, there is no original
88 order),
89* `sort-by-time' looks at the time at which an item has been seen
90 the first time. The most recent item is put at top,
91* `sort-by-title' will put the items in an alphabetical order."
92 :type '(choice
93 (const :tag "Keep original order" sort-by-original-order)
94 (const :tag "Sort by time" sort-by-time)
95 (const :tag "Sort by title" sort-by-title))
96 :set 'newsticker--set-customvar-sorting
97 :group 'newsticker-plainview)
98
99(defcustom newsticker-heading-format
100 "%l
101%t %d %s"
102 "Format string for feed headings.
103The following printf-like specifiers can be used:
104%d The date the feed was retrieved. See `newsticker-date-format'.
105%l The logo (image) of the feed. Most news feeds provide a small
106 image as logo. Newsticker can display them, if Emacs can --
107 see `image-types' for a list of supported image types.
108%L The logo (image) of the feed. If the logo is not available
109 the title of the feed is used.
110%s The statistical data of the feed. See `newsticker-statistics-format'.
111%t The title of the feed, i.e. its name."
112 :type 'string
113 :set 'newsticker--set-customvar-formatting
114 :group 'newsticker-plainview)
115
116(defcustom newsticker-item-format
117 "%t %d"
118 "Format string for news item headlines.
119The following printf-like specifiers can be used:
120%d The date the item was (first) retrieved. See `newsticker-date-format'.
121%l The logo (image) of the feed. Most news feeds provide a small
122 image as logo. Newsticker can display them, if Emacs can --
123 see `image-types' for a list of supported image types.
124%L The logo (image) of the feed. If the logo is not available
125 the title of the feed is used.
126%t The title of the item."
127 :type 'string
128 :set 'newsticker--set-customvar-formatting
129 :group 'newsticker-plainview)
130
131(defcustom newsticker-desc-format
132 "%d %c"
133 "Format string for news descriptions (contents).
134The following printf-like specifiers can be used:
135%c The contents (description) of the item.
136%d The date the item was (first) retrieved. See
137 `newsticker-date-format'."
138 :type 'string
139 :set 'newsticker--set-customvar-formatting
140 :group 'newsticker-plainview)
141
142(defcustom newsticker-statistics-format
143 "[%n + %i + %o + %O = %a]"
144 "Format for the statistics part in feed lines.
145The following printf-like specifiers can be used:
146%a The number of all items in the feed.
147%i The number of immortal items in the feed.
148%n The number of new items in the feed.
149%o The number of old items in the feed.
150%O The number of obsolete items in the feed."
151 :type 'string
152 :set 'newsticker--set-customvar-formatting
153 :group 'newsticker-plainview)
154
155
156;; ======================================================================
157;; faces
158(defgroup newsticker-faces nil
159 "Settings for the faces of the feed reader."
160 :group 'newsticker-plainview)
161
162(defface newsticker-feed-face
163 '((((class color) (background dark))
164 (:family "helvetica" :bold t :height 1.2 :foreground "misty rose"))
165 (((class color) (background light))
166 (:family "helvetica" :bold t :height 1.2 :foreground "black")))
167 "Face for news feeds."
168 :group 'newsticker-faces)
169
170(defface newsticker-new-item-face
171 '((((class color) (background dark))
172 (:family "helvetica" :bold t))
173 (((class color) (background light))
174 (:family "helvetica" :bold t)))
175 "Face for new news items."
176 :group 'newsticker-faces)
177
178(defface newsticker-old-item-face
179 '((((class color) (background dark))
180 (:family "helvetica" :bold t :foreground "orange3"))
181 (((class color) (background light))
182 (:family "helvetica" :bold t :foreground "red4")))
183 "Face for old news items."
184 :group 'newsticker-faces)
185
186(defface newsticker-immortal-item-face
187 '((((class color) (background dark))
188 (:family "helvetica" :bold t :italic t :foreground "orange"))
189 (((class color) (background light))
190 (:family "helvetica" :bold t :italic t :foreground "blue")))
191 "Face for immortal news items."
192 :group 'newsticker-faces)
193
194(defface newsticker-obsolete-item-face
195 '((((class color) (background dark))
196 (:family "helvetica" :bold t :strike-through t))
197 (((class color) (background light))
198 (:family "helvetica" :bold t :strike-through t)))
199 "Face for old news items."
200 :group 'newsticker-faces)
201
202(defface newsticker-date-face
203 '((((class color) (background dark))
204 (:family "helvetica" :italic t :height 0.8))
205 (((class color) (background light))
206 (:family "helvetica" :italic t :height 0.8)))
207 "Face for newsticker dates."
208 :group 'newsticker-faces)
209
210(defface newsticker-statistics-face
211 '((((class color) (background dark))
212 (:family "helvetica" :italic t :height 0.8))
213 (((class color) (background light))
214 (:family "helvetica" :italic t :height 0.8)))
215 "Face for newsticker dates."
216 :group 'newsticker-faces)
217
218(defface newsticker-enclosure-face
219 '((((class color) (background dark))
220 (:bold t :background "orange"))
221 (((class color) (background light))
222 (:bold t :background "orange")))
223 "Face for enclosed elements."
224 :group 'newsticker-faces)
225
226(defface newsticker-extra-face
227 '((((class color) (background dark))
228 (:italic t :foreground "gray50" :height 0.8))
229 (((class color) (background light))
230 (:italic t :foreground "gray50" :height 0.8)))
231 "Face for newsticker dates."
232 :group 'newsticker-faces)
233
234(defface newsticker-default-face
235 '((((class color) (background dark))
236 (:inherit default))
237 (((class color) (background light))
238 (:inherit default)))
239 "Face for the description of news items."
240 ;;:set 'newsticker--set-customvar
241 :group 'newsticker-faces)
242
243(defcustom newsticker-hide-old-items-in-newsticker-buffer
244 nil
245 "Decides whether to automatically hide old items in the *newsticker* buffer.
246If set to t old items will be completely folded and only new
247items will show up in the *newsticker* buffer. Otherwise old as
248well as new items will be visible."
249 :type 'boolean
250 :set 'newsticker--set-customvar-buffer
251 :group 'newsticker-plainview)
252
253(defcustom newsticker-show-descriptions-of-new-items
254 t
255 "Whether to automatically show descriptions of new items in *newsticker*.
256If set to t old items will be folded and new items will be
257unfolded. Otherwise old as well as new items will be folded."
258 :type 'boolean
259 :set 'newsticker--set-customvar-buffer
260 :group 'newsticker-plainview)
261
262(defcustom newsticker-show-all-news-elements
263 nil
264 "Show all news elements."
265 :type 'boolean
266 ;;:set 'newsticker--set-customvar
267 :group 'newsticker-plainview)
268
269;; ======================================================================
270;; hooks
271(defgroup newsticker-plainview-hooks nil
272 "Settings for newsticker hooks which apply to plainview only."
273 :group 'newsticker-hooks)
274
275(defcustom newsticker-select-item-hook
276 'newsticker--buffer-make-item-completely-visible
277 "List of functions run after a headline has been selected.
278Each function is called after one of `newsticker-next-item',
279`newsticker-next-new-item', `newsticker-previous-item',
280`newsticker-previous-new-item' has been called.
281
282The default value 'newsticker--buffer-make-item-completely-visible
283assures that the current item is always completely visible."
284 :type 'hook
285 :options '(newsticker--buffer-make-item-completely-visible)
286 :group 'newsticker-plainview-hooks)
287
288(defcustom newsticker-select-feed-hook
289 'newsticker--buffer-make-item-completely-visible
290 "List of functions run after a feed has been selected.
291Each function is called after one of `newsticker-next-feed', and
292`newsticker-previous-feed' has been called.
293
294The default value 'newsticker--buffer-make-item-completely-visible
295assures that the current feed is completely visible."
296 :type 'hook
297 :options '(newsticker--buffer-make-item-completely-visible)
298 :group 'newsticker-plainview-hooks)
299
300(defcustom newsticker-buffer-change-hook
301 'newsticker-w3m-show-inline-images
302 "List of functions run after the newsticker buffer has been updated.
303Each function is called after `newsticker-buffer-update' has been called.
304
305The default value '`newsticker-w3m-show-inline-images' loads inline
306images."
307 :type 'hook
308 :group 'newsticker-plainview-hooks)
309
310(defcustom newsticker-narrow-hook
311 'newsticker-w3m-show-inline-images
312 "List of functions run after narrowing in newsticker buffer has changed.
313Each function is called after
314`newsticker-toggle-auto-narrow-to-feed' or
315`newsticker-toggle-auto-narrow-to-item' has been called.
316
317The default value '`newsticker-w3m-show-inline-images' loads inline
318images."
319 :type 'hook
320 :group 'newsticker-plainview-hooks)
321
322;; ======================================================================
323;;; Toolbar
324;; ======================================================================
325
326(defvar newsticker--plainview-tool-bar-map
327 (if (featurep 'xemacs)
328 nil
329 (let ((tool-bar-map (make-sparse-keymap)))
330 (define-key tool-bar-map [newsticker-sep-1]
331 (list 'menu-item "--double-line"))
332 (define-key tool-bar-map [newsticker-browse-url]
333 (list 'menu-item "newsticker-browse-url" 'newsticker-browse-url
334 :visible t
335 :help "Browse URL for item at point"
336 :image newsticker--browse-image))
337 (define-key tool-bar-map [newsticker-buffer-force-update]
338 (list 'menu-item "newsticker-buffer-force-update"
339 'newsticker-buffer-force-update
340 :visible t
341 :help "Update newsticker buffer"
342 :image newsticker--update-image
343 :enable '(not newsticker--buffer-uptodate-p)))
344 (define-key tool-bar-map [newsticker-get-all-news]
345 (list 'menu-item "newsticker-get-all-news" 'newsticker-get-all-news
346 :visible t
347 :help "Get news for all feeds"
348 :image newsticker--get-all-image))
349 (define-key tool-bar-map [newsticker-mark-item-at-point-as-read]
350 (list 'menu-item "newsticker-mark-item-at-point-as-read"
351 'newsticker-mark-item-at-point-as-read
352 :visible t
353 :image newsticker--mark-read-image
354 :help "Mark current item as read"
355 :enable '(newsticker-item-not-old-p)))
356 (define-key tool-bar-map [newsticker-mark-item-at-point-as-immortal]
357 (list 'menu-item "newsticker-mark-item-at-point-as-immortal"
358 'newsticker-mark-item-at-point-as-immortal
359 :visible t
360 :image newsticker--mark-immortal-image
361 :help "Mark current item as immortal"
362 :enable '(newsticker-item-not-immortal-p)))
363 (define-key tool-bar-map [newsticker-toggle-auto-narrow-to-feed]
364 (list 'menu-item "newsticker-toggle-auto-narrow-to-feed"
365 'newsticker-toggle-auto-narrow-to-feed
366 :visible t
367 :help "Toggle visibility of other feeds"
368 :image newsticker--narrow-image))
369 (define-key tool-bar-map [newsticker-next-feed]
370 (list 'menu-item "newsticker-next-feed" 'newsticker-next-feed
371 :visible t
372 :help "Go to next feed"
373 :image newsticker--next-feed-image
374 :enable '(newsticker-next-feed-available-p)))
375 (define-key tool-bar-map [newsticker-next-item]
376 (list 'menu-item "newsticker-next-item" 'newsticker-next-item
377 :visible t
378 :help "Go to next item"
379 :image newsticker--next-item-image
380 :enable '(newsticker-next-item-available-p)))
381 (define-key tool-bar-map [newsticker-previous-item]
382 (list 'menu-item "newsticker-previous-item" 'newsticker-previous-item
383 :visible t
384 :help "Go to previous item"
385 :image newsticker--previous-item-image
386 :enable '(newsticker-previous-item-available-p)))
387 (define-key tool-bar-map [newsticker-previous-feed]
388 (list 'menu-item "newsticker-previous-feed" 'newsticker-previous-feed
389 :visible t
390 :help "Go to previous feed"
391 :image newsticker--previous-feed-image
392 :enable '(newsticker-previous-feed-available-p)))
393 ;; standard icons / actions
394 (tool-bar-add-item "close"
395 'newsticker-close-buffer
396 'newsticker-close-buffer
397 :help "Close newsticker buffer")
398 (tool-bar-add-item "preferences"
399 'newsticker-customize
400 'newsticker-customize
401 :help "Customize newsticker")
402 tool-bar-map)))
403
404;; ======================================================================
405;;; Newsticker mode
406;; ======================================================================
407
408(define-derived-mode newsticker-mode fundamental-mode
409 "NewsTicker"
410 "Viewing news feeds in Emacs."
411 (set (make-local-variable 'tool-bar-map) newsticker--plainview-tool-bar-map)
412 (set (make-local-variable 'imenu-sort-function) nil)
413 (set (make-local-variable 'scroll-conservatively) 999)
414 (setq imenu-create-index-function 'newsticker--imenu-create-index)
415 (setq imenu-default-goto-function 'newsticker--imenu-goto)
416 (setq buffer-read-only t)
417 (auto-fill-mode -1) ;; turn auto-fill off!
418 (font-lock-mode -1) ;; turn off font-lock!!
419 (set (make-local-variable 'font-lock-defaults) nil)
420 (set (make-local-variable 'line-move-ignore-invisible) t)
421 (setq mode-line-format
422 (list "-"
423 'mode-line-mule-info
424 'mode-line-modified
425 'mode-line-frame-identification
426 " Newsticker ("
427 '(newsticker--buffer-uptodate-p
428 "up to date"
429 "NEED UPDATE")
430 ") "
431 '(:eval (format "[%d]" (length newsticker--process-ids)))
432 " -- "
433 '(:eval (newsticker--buffer-get-feed-title-at-point))
434 ": "
435 '(:eval (newsticker--buffer-get-item-title-at-point))
436 " %-"))
437 (add-to-invisibility-spec 't)
438 (unless newsticker-show-all-news-elements
439 (add-to-invisibility-spec 'extra))
440 (newsticker--buffer-set-uptodate nil))
441
442;; refine its mode-map
443(define-key newsticker-mode-map "sO" 'newsticker-show-old-items)
444(define-key newsticker-mode-map "hO" 'newsticker-hide-old-items)
445(define-key newsticker-mode-map "sa" 'newsticker-show-all-desc)
446(define-key newsticker-mode-map "ha" 'newsticker-hide-all-desc)
447(define-key newsticker-mode-map "sf" 'newsticker-show-feed-desc)
448(define-key newsticker-mode-map "hf" 'newsticker-hide-feed-desc)
449(define-key newsticker-mode-map "so" 'newsticker-show-old-item-desc)
450(define-key newsticker-mode-map "ho" 'newsticker-hide-old-item-desc)
451(define-key newsticker-mode-map "sn" 'newsticker-show-new-item-desc)
452(define-key newsticker-mode-map "hn" 'newsticker-hide-new-item-desc)
453(define-key newsticker-mode-map "se" 'newsticker-show-entry)
454(define-key newsticker-mode-map "he" 'newsticker-hide-entry)
455(define-key newsticker-mode-map "sx" 'newsticker-show-extra)
456(define-key newsticker-mode-map "hx" 'newsticker-hide-extra)
457
458(define-key newsticker-mode-map " " 'scroll-up)
459(define-key newsticker-mode-map "q" 'newsticker-close-buffer)
460(define-key newsticker-mode-map "p" 'newsticker-previous-item)
461(define-key newsticker-mode-map "P" 'newsticker-previous-new-item)
462(define-key newsticker-mode-map "F" 'newsticker-previous-feed)
463(define-key newsticker-mode-map "\t" 'newsticker-next-item)
464(define-key newsticker-mode-map "n" 'newsticker-next-item)
465(define-key newsticker-mode-map "N" 'newsticker-next-new-item)
466(define-key newsticker-mode-map "f" 'newsticker-next-feed)
467(define-key newsticker-mode-map "M" 'newsticker-mark-all-items-as-read)
468(define-key newsticker-mode-map "m"
469 'newsticker-mark-all-items-at-point-as-read-and-redraw)
470(define-key newsticker-mode-map "o"
471 'newsticker-mark-item-at-point-as-read)
472(define-key newsticker-mode-map "O"
473 'newsticker-mark-all-items-at-point-as-read)
474(define-key newsticker-mode-map "G" 'newsticker-get-all-news)
475(define-key newsticker-mode-map "g" 'newsticker-get-news-at-point)
476(define-key newsticker-mode-map "u" 'newsticker-buffer-update)
477(define-key newsticker-mode-map "U" 'newsticker-buffer-force-update)
478(define-key newsticker-mode-map "a" 'newsticker-add-url)
479
480(define-key newsticker-mode-map "i"
481 'newsticker-mark-item-at-point-as-immortal)
482
483(define-key newsticker-mode-map "xf"
484 'newsticker-toggle-auto-narrow-to-feed)
485(define-key newsticker-mode-map "xi"
486 'newsticker-toggle-auto-narrow-to-item)
487
488;; maps for the clickable portions
489(defvar newsticker--url-keymap (make-sparse-keymap)
490 "Key map for click-able headings in the newsticker buffer.")
491(define-key newsticker--url-keymap [mouse-1]
492 'newsticker-mouse-browse-url)
493(define-key newsticker--url-keymap [mouse-2]
494 'newsticker-mouse-browse-url)
495(define-key newsticker--url-keymap "\n"
496 'newsticker-browse-url)
497(define-key newsticker--url-keymap "\C-m"
498 'newsticker-browse-url)
499(define-key newsticker--url-keymap [(control return)]
500 'newsticker-handle-url)
501
502;; newsticker menu
503(defvar newsticker-menu (make-sparse-keymap "Newsticker"))
504
505(define-key newsticker-menu [newsticker-browse-url]
506 '("Browse URL for item at point" . newsticker-browse-url))
507(define-key newsticker-menu [newsticker-separator-1]
508 '("--"))
509(define-key newsticker-menu [newsticker-buffer-update]
510 '("Update buffer" . newsticker-buffer-update))
511(define-key newsticker-menu [newsticker-separator-2]
512 '("--"))
513(define-key newsticker-menu [newsticker-get-all-news]
514 '("Get news from all feeds" . newsticker-get-all-news))
515(define-key newsticker-menu [newsticker-get-news-at-point]
516 '("Get news from feed at point" . newsticker-get-news-at-point))
517(define-key newsticker-menu [newsticker-separator-3]
518 '("--"))
519(define-key newsticker-menu [newsticker-mark-all-items-as-read]
520 '("Mark all items as read" . newsticker-mark-all-items-as-read))
521(define-key newsticker-menu [newsticker-mark-all-items-at-point-as-read]
522 '("Mark all items in feed at point as read" .
523 newsticker-mark-all-items-at-point-as-read))
524(define-key newsticker-menu [newsticker-mark-item-at-point-as-read]
525 '("Mark item at point as read" .
526 newsticker-mark-item-at-point-as-read))
527(define-key newsticker-menu [newsticker-mark-item-at-point-as-immortal]
528 '("Toggle immortality for item at point" .
529 newsticker-mark-item-at-point-as-immortal))
530(define-key newsticker-menu [newsticker-separator-4]
531 '("--"))
532(define-key newsticker-menu [newsticker-toggle-auto-narrow-to-item]
533 '("Narrow to single item" . newsticker-toggle-auto-narrow-to-item))
534(define-key newsticker-menu [newsticker-toggle-auto-narrow-to-feed]
535 '("Narrow to single news feed" . newsticker-toggle-auto-narrow-to-feed))
536(define-key newsticker-menu [newsticker-hide-old-items]
537 '("Hide old items" . newsticker-hide-old-items))
538(define-key newsticker-menu [newsticker-show-old-items]
539 '("Show old items" . newsticker-show-old-items))
540(define-key newsticker-menu [newsticker-next-item]
541 '("Go to next item" . newsticker-next-item))
542(define-key newsticker-menu [newsticker-previous-item]
543 '("Go to previous item" . newsticker-previous-item))
544
545;; bind menu to mouse
546(define-key newsticker-mode-map [down-mouse-3] newsticker-menu)
547;; Put menu in menu-bar
548(define-key newsticker-mode-map [menu-bar Newsticker]
549 (cons "Newsticker" newsticker-menu))
550
551
552;; ======================================================================
553;;; User fun
554;; ======================================================================
4da498eb 555;;;###autoload
2415d4c6
UJ
556(defun newsticker-plainview ()
557 "Start newsticker plainview."
558 (interactive)
559 (newsticker-buffer-update t)
560 (switch-to-buffer "*newsticker*"))
561
562(defun newsticker-buffer-force-update ()
563 "Update the newsticker buffer, even if not necessary."
564 (interactive)
565 (newsticker-buffer-update t))
566
567(defun newsticker-buffer-update (&optional force)
568 "Update the *newsticker* buffer.
569Unless FORCE is t this is done only if necessary, i.e. when the
570*newsticker* buffer is not up-to-date."
571 (interactive)
572 ;; bring cache data into proper order....
573 (newsticker--cache-sort)
574 ;; fill buffer
575 (save-excursion
576 (let ((buf (get-buffer "*newsticker*")))
577 (if buf
578 (switch-to-buffer buf)
579 (switch-to-buffer (get-buffer-create "*newsticker*"))
580 (newsticker--buffer-set-uptodate nil)))
581 (when (or force
582 (not newsticker--buffer-uptodate-p))
583 (message "Preparing newsticker buffer...")
584 (setq buffer-undo-list t)
585 (let ((inhibit-read-only t))
586 (set-buffer-modified-p nil)
587 (erase-buffer)
588 (newsticker-mode)
589 ;; Emacs 21.3.50 does not care if we turn off auto-fill in the
590 ;; definition of newsticker-mode, so we do it here (again)
591 (auto-fill-mode -1)
592
593 (set-buffer-file-coding-system 'utf-8)
594
595 (if newsticker-use-full-width
596 (set (make-local-variable 'fill-column) (1- (window-width))))
597 (newsticker--buffer-insert-all-items)
598
599 ;; FIXME: needed for methods buffer in ecb
600 ;; (set-visited-file-name "*newsticker*")
601
602 (set-buffer-modified-p nil)
603 (newsticker-hide-all-desc)
604 (if newsticker-hide-old-items-in-newsticker-buffer
605 (newsticker-hide-old-items))
606 (if newsticker-show-descriptions-of-new-items
607 (newsticker-show-new-item-desc))
608 )
609 (message ""))
610 (newsticker--buffer-set-uptodate t)
611 (run-hooks 'newsticker-buffer-change-hook)))
612
613(defun newsticker-get-news-at-point ()
614 "Launch retrieval of news for the feed point is in.
615This does NOT start the retrieval timers."
616 (interactive)
617 ;; launch retrieval of news
618 (let ((feed (get-text-property (point) 'feed)))
619 (when feed
620 (newsticker--debug-msg "Getting news for %s" (symbol-name feed))
621 (newsticker-get-news (symbol-name feed)))))
622
623(defun newsticker-w3m-show-inline-images ()
624 "Show inline images in visible text ranges.
625In-line images in invisible text ranges are hidden. This function
626calls `w3m-toggle-inline-image'. It works only if
627`newsticker-html-renderer' is set to `w3m-region'."
628 (interactive)
629 (if (eq newsticker-html-renderer 'w3m-region)
630 (let ((inhibit-read-only t))
631 (save-excursion
632 (save-restriction
633 (widen)
634 (goto-char (point-min))
635 (let ((pos (point)))
636 (while pos
637 (setq pos (next-single-property-change pos 'w3m-image))
638 (when pos
639 (goto-char pos)
640 (when (get-text-property pos 'w3m-image)
641 (let ((invis (newsticker--lists-intersect-p
642 (get-text-property (1- (point))
643 'invisible)
644 buffer-invisibility-spec)))
645 (unless (car (get-text-property (1- (point))
646 'display))
647 (unless invis
648 (w3m-toggle-inline-image t)))))))))))))
649
650;; ======================================================================
651;;; Keymap stuff
652;; ======================================================================
653(defun newsticker-close-buffer ()
654 "Close the newsticker buffer."
655 (interactive)
656 (newsticker--cache-update t)
657 (bury-buffer))
658
659(defun newsticker-next-new-item (&optional do-not-wrap-at-eob)
660 "Go to next new news item.
661If no new item is found behind point, search is continued at
662beginning of buffer unless optional argument DO-NOT-WRAP-AT-EOB
663is non-nil."
664 (interactive)
665 (widen)
666 (let ((go-ahead t))
667 (while go-ahead
668 (unless (newsticker--buffer-goto '(item) 'new)
669 ;; found nothing -- wrap
670 (unless do-not-wrap-at-eob
671 (goto-char (point-min))
672 (newsticker-next-new-item t))
673 (setq go-ahead nil))
674 (unless (newsticker--lists-intersect-p
675 (get-text-property (point) 'invisible)
676 buffer-invisibility-spec)
677 ;; this item is invisible -- continue search
678 (setq go-ahead nil))))
679 (run-hooks 'newsticker-select-item-hook)
680 (point))
681
682(defun newsticker-previous-new-item (&optional do-not-wrap-at-bob)
683 "Go to previous new news item.
684If no new item is found before point, search is continued at
685beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
686is non-nil."
687 (interactive)
688 (widen)
689 (let ((go-ahead t))
690 (while go-ahead
691 (unless (newsticker--buffer-goto '(item) 'new t)
692 (unless do-not-wrap-at-bob
693 (goto-char (point-max))
694 (newsticker--buffer-goto '(item) 'new t)))
695 (unless (newsticker--lists-intersect-p
696 (get-text-property (point) 'invisible)
697 buffer-invisibility-spec)
698 (setq go-ahead nil))))
699 (run-hooks 'newsticker-select-item-hook)
700 (point))
701
702(defun newsticker-next-item (&optional do-not-wrap-at-eob)
703 "Go to next news item.
704Return new buffer position.
705If no item is found below point, search is continued at beginning
706of buffer unless optional argument DO-NOT-WRAP-AT-EOB is
707non-nil."
708 (interactive)
709 (widen)
710 (let ((go-ahead t)
711 (search-list '(item)))
712 (if newsticker--auto-narrow-to-item
713 (setq search-list '(item feed)))
714 (while go-ahead
715 (unless (newsticker--buffer-goto search-list)
716 ;; found nothing -- wrap
717 (unless do-not-wrap-at-eob
718 (goto-char (point-min)))
719 (setq go-ahead nil))
720 (unless (newsticker--lists-intersect-p
721 (get-text-property (point) 'invisible)
722 buffer-invisibility-spec)
723 (setq go-ahead nil))))
724 (run-hooks 'newsticker-select-item-hook)
725 (force-mode-line-update)
726 (point))
727
728(defun newsticker-next-item-same-feed ()
729 "Go to next news item in the same feed.
730Return new buffer position. If no item is found below point or if
731auto-narrow-to-item is enabled, nil is returned."
732 (interactive)
733 (if newsticker--auto-narrow-to-item
734 nil
735 (let ((go-ahead t)
736 (current-pos (point))
737 (end-of-feed (save-excursion (newsticker--buffer-end-of-feed))))
738 (while go-ahead
739 (unless (newsticker--buffer-goto '(item))
740 (setq go-ahead nil))
741 (unless (newsticker--lists-intersect-p
742 (get-text-property (point) 'invisible)
743 buffer-invisibility-spec)
744 (setq go-ahead nil)))
745 (if (and (> (point) current-pos)
746 (< (point) end-of-feed))
747 (point)
748 (goto-char current-pos)
749 nil))))
750
751(defun newsticker-previous-item (&optional do-not-wrap-at-bob)
752 "Go to previous news item.
753Return new buffer position.
754If no item is found before point, search is continued at
755beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
756is non-nil."
757 (interactive)
758 (widen)
759 (let ((go-ahead t)
760 (search-list '(item)))
761 (if newsticker--auto-narrow-to-item
762 (setq search-list '(item feed)))
763 (when (bobp)
764 (unless do-not-wrap-at-bob
765 (goto-char (point-max))))
766 (while go-ahead
767 (if (newsticker--buffer-goto search-list nil t)
768 (unless (newsticker--lists-intersect-p
769 (get-text-property (point) 'invisible)
770 buffer-invisibility-spec)
771 (setq go-ahead nil))
772 (goto-char (point-min))
773 (setq go-ahead nil))))
774 (run-hooks 'newsticker-select-item-hook)
775 (force-mode-line-update)
776 (point))
777
778(defun newsticker-next-feed ()
779 "Go to next news feed.
780Return new buffer position."
781 (interactive)
782 (widen)
783 (newsticker--buffer-goto '(feed))
784 (run-hooks 'newsticker-select-feed-hook)
785 (force-mode-line-update)
786 (point))
787
788(defun newsticker-previous-feed ()
789 "Go to previous news feed.
790Return new buffer position."
791 (interactive)
792 (widen)
793 (newsticker--buffer-goto '(feed) nil t)
794 (run-hooks 'newsticker-select-feed-hook)
795 (force-mode-line-update)
796 (point))
797
798(defun newsticker-mark-all-items-at-point-as-read-and-redraw ()
799 "Mark all items as read and clear ticker contents."
800 (interactive)
801 (when (or newsticker--buffer-uptodate-p
802 (y-or-n-p
803 "Buffer is not up to date -- really mark items as read? "))
804 (newsticker-mark-all-items-of-feed-as-read
805 (get-text-property (point) 'feed))))
806
807(defun newsticker-mark-all-items-of-feed-as-read (feed)
808 "Mark all items of FEED as read, clear ticker, and redraw buffer."
809 (when feed
810 (let ((pos (point)))
811 (message "Marking all items as read for %s" (symbol-name feed))
812 (newsticker--cache-replace-age newsticker--cache feed 'new 'old)
813 (newsticker--cache-replace-age newsticker--cache feed 'obsolete
814 'old)
815 (newsticker--cache-update)
816 (newsticker--buffer-set-uptodate nil)
817 (newsticker--ticker-text-setup)
818 (newsticker-buffer-update)
819 ;; go back to where we came frome
820 (goto-char pos)
821 (end-of-line)
822 (newsticker--buffer-goto '(feed) nil t))))
823
824(defun newsticker-mark-all-items-at-point-as-read ()
825 "Mark all items as read and clear ticker contents."
826 (interactive)
827 (when (or newsticker--buffer-uptodate-p
828 (y-or-n-p
829 "Buffer is not up to date -- really mark items as read? "))
830 (newsticker--do-mark-item-at-point-as-read t)
831 (while (newsticker-next-item-same-feed)
832 (newsticker--do-mark-item-at-point-as-read t))
833 (newsticker-next-item t)))
834
835(defun newsticker-mark-item-at-point-as-read (&optional respect-immortality)
836 "Mark item at point as read and move to next item.
837If optional argument RESPECT-IMMORTALITY is not nil immortal items do
838not get changed."
839 (interactive)
840 (when (or newsticker--buffer-uptodate-p
841 (y-or-n-p
842 "Buffer is not up to date -- really mark this item as read? "))
843 (newsticker--do-mark-item-at-point-as-read respect-immortality)
844 ;; move forward
845 (newsticker-next-item t)))
846
847(defun newsticker--do-mark-item-at-point-as-read (&optional respect-immortality)
848 "Mark item at point as read.
849If optional argument RESPECT-IMMORTALITY is not nil immortal items do
850not get changed."
851 (let ((feed (get-text-property (point) 'feed)))
852 (when feed
853 (save-excursion
854 (newsticker--buffer-beginning-of-item)
855 (let ((inhibit-read-only t)
856 (age (get-text-property (point) 'nt-age))
857 (title (get-text-property (point) 'nt-title))
858 (guid (get-text-property (point) 'nt-guid))
859 (nt-desc (get-text-property (point) 'nt-desc))
860 (pos (save-excursion (newsticker--buffer-end-of-item)))
861 item)
862 (when (or (eq age 'new)
863 (eq age 'obsolete)
864 (and (eq age 'immortal)
865 (not respect-immortality)))
866 ;; find item
867 (setq item (newsticker--cache-contains newsticker--cache
868 feed title nt-desc
869 nil nil guid))
870 ;; mark as old
871 (when item
872 (setcar (nthcdr 4 item) 'old)
873 (newsticker--do-forget-preformatted item))
874 ;; clean up ticker
875 (if (or (and (eq age 'new)
876 newsticker-hide-immortal-items-in-echo-area)
877 (and (memq age '(old immortal))
878 (not
879 (eq newsticker-hide-old-items-in-newsticker-buffer
880 newsticker-hide-immortal-items-in-echo-area))))
881 (newsticker--ticker-text-remove feed title))
882 ;; set faces etc.
883 (save-excursion
884 (save-restriction
885 (widen)
886 (put-text-property (point) pos 'nt-age 'old)
887 (newsticker--buffer-set-faces (point) pos)))
888 (set-buffer-modified-p nil)))))))
889
890(defun newsticker-mark-item-at-point-as-immortal ()
891 "Mark item at point as read."
892 (interactive)
893 (when (or newsticker--buffer-uptodate-p
894 (y-or-n-p
895 "Buffer is not up to date -- really mark this item as read? "))
896 (let ((feed (get-text-property (point) 'feed))
897 (item nil))
898 (when feed
899 (save-excursion
900 (newsticker--buffer-beginning-of-item)
901 (let ((inhibit-read-only t)
902 (oldage (get-text-property (point) 'nt-age))
903 (title (get-text-property (point) 'nt-title))
904 (guid (get-text-property (point) 'nt-guid))
905 (pos (save-excursion (newsticker--buffer-end-of-item))))
906 (let ((newage 'immortal))
907 (if (eq oldage 'immortal)
908 (setq newage 'old))
909 (setq item (newsticker--cache-contains newsticker--cache
910 feed title nil nil nil
911 guid))
912 ;; change age
913 (when item
914 (setcar (nthcdr 4 item) newage)
915 (newsticker--do-forget-preformatted item))
916 (if (or (and (eq newage 'immortal)
917 newsticker-hide-immortal-items-in-echo-area)
918 (and (eq newage 'obsolete)
919 newsticker-hide-obsolete-items-in-echo-area)
920 (and (eq oldage 'immortal)
921 (not
922 (eq newsticker-hide-old-items-in-newsticker-buffer
923 newsticker-hide-immortal-items-in-echo-area))))
924 (newsticker--ticker-text-remove feed title)
925 (newsticker--ticker-text-setup))
926 (save-excursion
927 (save-restriction
928 (widen)
929 (put-text-property (point) pos 'nt-age newage)
930 (if (eq newage 'immortal)
931 (put-text-property (point) pos 'nt-age 'immortal)
932 (put-text-property (point) pos 'nt-age 'old))
933 (newsticker--buffer-set-faces (point) pos))))))
934 (if item
935 (newsticker-next-item t))))))
936
937(defun newsticker-mark-all-items-as-read ()
938 "Mark all items as read and clear ticker contents."
939 (interactive)
940 (when (or newsticker--buffer-uptodate-p
941 (y-or-n-p
942 "Buffer is not up to date -- really mark items as read? "))
943 (newsticker--cache-replace-age newsticker--cache 'any 'new 'old)
944 (newsticker--buffer-set-uptodate nil)
945 (newsticker--ticker-text-setup)
946 (newsticker--cache-update)
947 (newsticker-buffer-update)))
948
949(defun newsticker-hide-extra ()
950 "Hide the extra elements of items."
951 (interactive)
952 (newsticker--buffer-hideshow 'extra nil)
953 (newsticker--buffer-redraw))
954
955(defun newsticker-show-extra ()
956 "Show the extra elements of items."
957 (interactive)
958 (newsticker--buffer-hideshow 'extra t)
959 (newsticker--buffer-redraw))
960
961(defun newsticker-hide-old-item-desc ()
962 "Hide the description of old items."
963 (interactive)
964 (newsticker--buffer-hideshow 'desc-old nil)
965 (newsticker--buffer-redraw))
966
967(defun newsticker-show-old-item-desc ()
968 "Show the description of old items."
969 (interactive)
970 (newsticker--buffer-hideshow 'item-old t)
971 (newsticker--buffer-hideshow 'desc-old t)
972 (newsticker--buffer-redraw))
973
974(defun newsticker-hide-new-item-desc ()
975 "Hide the description of new items."
976 (interactive)
977 (newsticker--buffer-hideshow 'desc-new nil)
978 (newsticker--buffer-hideshow 'desc-immortal nil)
979 (newsticker--buffer-hideshow 'desc-obsolete nil)
980 (newsticker--buffer-redraw))
981
982(defun newsticker-show-new-item-desc ()
983 "Show the description of new items."
984 (interactive)
985 (newsticker--buffer-hideshow 'desc-new t)
986 (newsticker--buffer-hideshow 'desc-immortal t)
987 (newsticker--buffer-hideshow 'desc-obsolete t)
988 (newsticker--buffer-redraw))
989
990(defun newsticker-hide-feed-desc ()
991 "Hide the description of feeds."
992 (interactive)
993 (newsticker--buffer-hideshow 'desc-feed nil)
994 (newsticker--buffer-redraw))
995
996(defun newsticker-show-feed-desc ()
997 "Show the description of old items."
998 (interactive)
999 (newsticker--buffer-hideshow 'desc-feed t)
1000 (newsticker--buffer-redraw))
1001
1002(defun newsticker-hide-all-desc ()
1003 "Hide the descriptions of feeds and all items."
1004 (interactive)
1005 (newsticker--buffer-hideshow 'desc-feed nil)
1006 (newsticker--buffer-hideshow 'desc-immortal nil)
1007 (newsticker--buffer-hideshow 'desc-obsolete nil)
1008 (newsticker--buffer-hideshow 'desc-new nil)
1009 (newsticker--buffer-hideshow 'desc-old nil)
1010 (newsticker--buffer-redraw))
1011
1012(defun newsticker-show-all-desc ()
1013 "Show the descriptions of feeds and all items."
1014 (interactive)
1015 (newsticker--buffer-hideshow 'desc-feed t)
1016 (newsticker--buffer-hideshow 'desc-immortal t)
1017 (newsticker--buffer-hideshow 'desc-obsolete t)
1018 (newsticker--buffer-hideshow 'desc-new t)
1019 (newsticker--buffer-hideshow 'desc-old t)
1020 (newsticker--buffer-redraw))
1021
1022(defun newsticker-hide-old-items ()
1023 "Hide old items."
1024 (interactive)
1025 (newsticker--buffer-hideshow 'desc-old nil)
1026 (newsticker--buffer-hideshow 'item-old nil)
1027 (newsticker--buffer-redraw))
1028
1029(defun newsticker-show-old-items ()
1030 "Show old items."
1031 (interactive)
1032 (newsticker--buffer-hideshow 'item-old t)
1033 (newsticker--buffer-redraw))
1034
1035(defun newsticker-hide-entry ()
1036 "Hide description of entry at point."
1037 (interactive)
1038 (save-excursion
1039 (let* (pos1 pos2
1040 (inhibit-read-only t)
1041 inv-prop org-inv-prop
1042 is-invisible)
1043 (newsticker--buffer-beginning-of-item)
1044 (newsticker--buffer-goto '(desc))
1045 (setq pos1 (max (point-min) (1- (point))))
1046 (newsticker--buffer-goto '(extra feed item nil))
1047 (setq pos2 (max (point-min) (1- (point))))
1048 (setq inv-prop (get-text-property pos1 'invisible))
1049 (setq org-inv-prop (get-text-property pos1 'org-invisible))
1050 (cond ((eq inv-prop t)
1051 ;; do nothing
1052 )
1053 ((eq org-inv-prop nil)
1054 (add-text-properties pos1 pos2
1055 (list 'invisible (list t)
1056 'org-invisible inv-prop)))
1057 (t
1058 ;; toggle
1059 (add-text-properties pos1 pos2
1060 (list 'invisible org-inv-prop))
1061 (remove-text-properties pos1 pos2 '(org-invisible))))))
1062 (newsticker--buffer-redraw))
1063
1064(defun newsticker-show-entry ()
1065 "Show description of entry at point."
1066 (interactive)
1067 (save-excursion
1068 (let* (pos1 pos2
1069 (inhibit-read-only t)
1070 inv-prop org-inv-prop
1071 is-invisible)
1072 (newsticker--buffer-beginning-of-item)
1073 (newsticker--buffer-goto '(desc))
1074 (setq pos1 (max (point-min) (1- (point))))
1075 (newsticker--buffer-goto '(extra feed item))
1076 (setq pos2 (max (point-min) (1- (point))))
1077 (setq inv-prop (get-text-property pos1 'invisible))
1078 (setq org-inv-prop (get-text-property pos1 'org-invisible))
1079 (cond ((eq org-inv-prop nil)
1080 (add-text-properties pos1 pos2
1081 (list 'invisible nil
1082 'org-invisible inv-prop)))
1083 (t
1084 ;; toggle
1085 (add-text-properties pos1 pos2
1086 (list 'invisible org-inv-prop))
1087 (remove-text-properties pos1 pos2 '(org-invisible))))))
1088 (newsticker--buffer-redraw))
1089
1090(defun newsticker-toggle-auto-narrow-to-feed ()
1091 "Toggle narrowing to current news feed.
1092If auto-narrowing is active, only news item of the current feed
1093are visible."
1094 (interactive)
1095 (newsticker-set-auto-narrow-to-feed
1096 (not newsticker--auto-narrow-to-feed)))
1097
1098(defun newsticker-set-auto-narrow-to-feed (value)
1099 "Turn narrowing to current news feed on or off.
1100If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
1101 (interactive)
1102 (setq newsticker--auto-narrow-to-item nil)
1103 (setq newsticker--auto-narrow-to-feed value)
1104 (widen)
1105 (newsticker--buffer-make-item-completely-visible)
1106 (run-hooks 'newsticker-narrow-hook))
1107
1108(defun newsticker-toggle-auto-narrow-to-item ()
1109 "Toggle narrowing to current news item.
1110If auto-narrowing is active, only one item of the current feed
1111is visible."
1112 (interactive)
1113 (newsticker-set-auto-narrow-to-item
1114 (not newsticker--auto-narrow-to-item)))
1115
1116(defun newsticker-set-auto-narrow-to-item (value)
1117 "Turn narrowing to current news item on or off.
1118If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
1119 (interactive)
1120 (setq newsticker--auto-narrow-to-feed nil)
1121 (setq newsticker--auto-narrow-to-item value)
1122 (widen)
1123 (newsticker--buffer-make-item-completely-visible)
1124 (run-hooks 'newsticker-narrow-hook))
1125
1126(defun newsticker-next-feed-available-p ()
1127 "Return t if position is before last feed, nil otherwise."
1128 (save-excursion
1129 (let ((p (point)))
1130 (newsticker--buffer-goto '(feed))
1131 (not (= p (point))))))
1132
1133(defun newsticker-previous-feed-available-p ()
1134 "Return t if position is behind first feed, nil otherwise."
1135 (save-excursion
1136 (let ((p (point)))
1137 (newsticker--buffer-goto '(feed) nil t)
1138 (not (= p (point))))))
1139
1140(defun newsticker-next-item-available-p ()
1141 "Return t if position is before last feed, nil otherwise."
1142 (save-excursion
1143 (catch 'result
1144 (while (< (point) (point-max))
1145 (unless (newsticker--buffer-goto '(item))
1146 (throw 'result nil))
1147 (unless (newsticker--lists-intersect-p
1148 (get-text-property (point) 'invisible)
1149 buffer-invisibility-spec)
1150 (throw 'result t))))))
1151
1152(defun newsticker-previous-item-available-p ()
1153 "Return t if position is behind first item, nil otherwise."
1154 (save-excursion
1155 (catch 'result
1156 (while (> (point) (point-min))
1157 (unless (newsticker--buffer-goto '(item) nil t)
1158 (throw 'result nil))
1159 (unless (newsticker--lists-intersect-p
1160 (get-text-property (point) 'invisible)
1161 buffer-invisibility-spec)
1162 (throw 'result t))))))
1163
1164(defun newsticker-item-not-old-p ()
1165 "Return t if there is an item at point which is not old, nil otherwise."
1166 (when (get-text-property (point) 'feed)
1167 (save-excursion
1168 (newsticker--buffer-beginning-of-item)
1169 (let ((age (get-text-property (point) 'nt-age)))
1170 (and (memq age '(new immortal obsolete)) t)))))
1171
1172(defun newsticker-item-not-immortal-p ()
1173 "Return t if there is an item at point which is not immortal, nil otherwise."
1174 (when (get-text-property (point) 'feed)
1175 (save-excursion
1176 (newsticker--buffer-beginning-of-item)
1177 (let ((age (get-text-property (point) 'nt-age)))
1178 (and (memq age '(new old obsolete)) t)))))
1179
1180;; ======================================================================
1181;;; Imenu stuff
1182;; ======================================================================
1183(defun newsticker--imenu-create-index ()
1184 "Scan newsticker buffer and return an index for imenu."
1185 (save-excursion
1186 (goto-char (point-min))
1187 (let ((index-alist nil)
1188 (feed-list nil)
1189 (go-ahead t))
1190 (while go-ahead
1191 (let ((type (get-text-property (point) 'nt-type))
1192 (title (get-text-property (point) 'nt-title)))
1193 (cond ((eq type 'feed)
1194 ;; we're on a feed heading
1195 (when feed-list
1196 (if index-alist
1197 (nconc index-alist (list feed-list))
1198 (setq index-alist (list feed-list))))
1199 (setq feed-list (list title)))
1200 (t
1201 (nconc feed-list
1202 (list (cons title (point)))))))
1203 (setq go-ahead (newsticker--buffer-goto '(item feed))))
1204 (if index-alist
1205 (nconc index-alist (list feed-list))
1206 (setq index-alist (list feed-list)))
1207 index-alist)))
1208
1209(defun newsticker--imenu-goto (name pos &rest args)
1210 "Go to item NAME at position POS and show item.
1211ARGS are ignored."
1212 (goto-char pos)
1213 ;; show headline
1214 (newsticker--buffer-goto '(desc extra feed item))
1215 (let* ((inhibit-read-only t)
1216 (pos1 (max (point-min) (1- pos)))
1217 (pos2 (max pos1 (1- (point))))
1218 (inv-prop (get-text-property pos 'invisible))
1219 (org-inv-prop (get-text-property pos 'org-invisible)))
1220 (when (eq org-inv-prop nil)
1221 (add-text-properties pos1 pos2 (list 'invisible nil
1222 'org-invisible inv-prop))))
1223 ;; show desc
1224 (newsticker-show-entry))
1225
1226;; ======================================================================
1227;;; Buffer stuff
1228;; ======================================================================
1229(defun newsticker--buffer-set-uptodate (value)
1230 "Set the uptodate-status of the newsticker buffer to VALUE.
1231The mode-line is changed accordingly."
1232 (setq newsticker--buffer-uptodate-p value)
1233 (let ((b (get-buffer "*newsticker*")))
1234 (when b
1235 (save-excursion
1236 (set-buffer b)
1237 (if value
1238 (setq mode-name "Newsticker -- up to date -- ")
1239 (setq mode-name "Newsticker -- NEED UPDATE -- ")))
1240 (force-mode-line-update 0))))
1241
1242(defun newsticker--buffer-redraw ()
1243 "Redraw the newsticker window."
1244 (if (fboundp 'force-window-update)
1245 (force-window-update (current-buffer))
1246 (redraw-frame (selected-frame)))
1247 (run-hooks 'newsticker-buffer-change-hook)
1248 (sit-for 0))
1249
1250(defun newsticker--buffer-insert-all-items ()
1251 "Insert all cached newsticker items into the current buffer.
1252Keeps order of feeds as given in `newsticker-url-list' and
1253`newsticker-url-list-defaults'."
1254 (goto-char (point-min))
1255 (mapc (lambda (url-item)
1256 (let* ((feed-name (car url-item))
1257 (feed-name-symbol (intern feed-name))
1258 (feed (assoc feed-name-symbol newsticker--cache))
1259 (items (cdr feed))
1260 (pos (point)))
1261 (when feed
1262 ;; insert the feed description
1263 (mapc (lambda (item)
1264 (when (eq (newsticker--age item) 'feed)
1265 (newsticker--buffer-insert-item item
1266 feed-name-symbol)))
1267 items)
1268 ;;insert the items
1269 (mapc (lambda (item)
1270 (if (memq (newsticker--age item) '(new immortal old
1271 obsolete))
1272 (newsticker--buffer-insert-item item
1273 feed-name-symbol)))
1274 items)
1275 (put-text-property pos (point) 'feed (car feed))
1276
1277 ;; insert empty line between feeds
1278 (let ((p (point)))
1279 (insert "\n")
1280 (put-text-property p (point) 'hard t)))))
1281 (append newsticker-url-list newsticker-url-list-defaults))
1282
1283 (newsticker--buffer-set-faces (point-min) (point-max))
1284 (newsticker--buffer-set-invisibility (point-min) (point-max))
1285 (goto-char (point-min)))
1286
1287(defun newsticker--buffer-insert-item (item &optional feed-name-symbol)
1288 "Insert a news item in the current buffer.
1289Insert a formatted representation of the ITEM. The optional parameter
1290FEED-NAME-SYMBOL determines how the item is formatted and whether the
1291item-retrieval time is added as well."
1292 ;; insert headline
1293 (if (eq (newsticker--age item) 'feed)
1294 (newsticker--buffer-do-insert-text item 'feed feed-name-symbol)
1295 (newsticker--buffer-do-insert-text item 'item feed-name-symbol))
1296 ;; insert the description
1297 (newsticker--buffer-do-insert-text item 'desc feed-name-symbol))
1298
1299(defun newsticker--buffer-do-insert-text (item type feed-name-symbol)
1300 "Actually insert contents of news item, format it, render it and all that.
1301ITEM is a news item, TYPE tells which part of the item shall be inserted,
1302FEED-NAME-SYMBOL tells to which feed this item belongs."
1303 (let* ((pos (point))
1304 (format newsticker-desc-format)
1305 (pos-date-start nil)
1306 (pos-date-end nil)
1307 (pos-stat-start nil)
1308 (pos-stat-end nil)
1309 (pos-text-start nil)
1310 (pos-text-end nil)
1311 (pos-extra-start nil)
1312 (pos-extra-end nil)
1313 (pos-enclosure-start nil)
1314 (pos-enclosure-end nil)
1315 (age (newsticker--age item))
1316 (preformatted-contents (newsticker--preformatted-contents item))
1317 (preformatted-title (newsticker--preformatted-title item)))
1318 (cond ((and preformatted-contents
1319 (not (eq (aref preformatted-contents 0) ?\n));; we must
1320 ;; NOT have a line
1321 ;; break!
1322 (eq type 'desc))
1323 (insert preformatted-contents))
1324 ((and preformatted-title
1325 (not (eq (aref preformatted-title 0) ?\n));; we must NOT have a
1326 ;; line break!
1327 (eq type 'item))
1328 (insert preformatted-title))
1329 (t
1330 ;; item was not formatted before.
1331 ;; Let's go.
1332 (if (eq type 'item)
1333 (setq format newsticker-item-format)
1334 (if (eq type 'feed)
1335 (setq format newsticker-heading-format)))
1336
1337 (while (> (length format) 0)
1338 (let ((prefix (if (> (length format) 1)
1339 (substring format 0 2)
1340 "")))
1341 (cond ((string= "%c" prefix)
1342 ;; contents
1343 (when (newsticker--desc item)
1344 (setq pos-text-start (point-marker))
1345 (insert (newsticker--desc item))
1346 (setq pos-text-end (point-marker)))
1347 (setq format (substring format 2)))
1348 ((string= "%d" prefix)
1349 ;; date
1350 (setq pos-date-start (point-marker))
1351 (if (newsticker--time item)
1352 (insert (format-time-string newsticker-date-format
1353 (newsticker--time item))))
1354 (setq pos-date-end (point-marker))
1355 (setq format (substring format 2)))
1356 ((string= "%l" prefix)
1357 ;; logo
1358 (let ((disabled (cond ((eq (newsticker--age item) 'feed)
1359 (= (newsticker--stat-num-items
1360 feed-name-symbol 'new) 0))
1361 (t
1362 (not (eq (newsticker--age item)
1363 'new))))))
1364 (let ((img (newsticker--image-read feed-name-symbol
1365 disabled)))
1366 (when img
1367 (newsticker--insert-image img (car item)))))
1368 (setq format (substring format 2)))
1369 ((string= "%L" prefix)
1370 ;; logo or title
1371 (let ((disabled (cond ((eq (newsticker--age item) 'feed)
1372 (= (newsticker--stat-num-items
1373 feed-name-symbol 'new) 0))
1374 (t
1375 (not (eq (newsticker--age item)
1376 'new))))))
1377 (let ((img (newsticker--image-read feed-name-symbol
1378 disabled)))
1379 (if img
1380 (newsticker--insert-image img (car item))
1381 (when (car item)
1382 (setq pos-text-start (point-marker))
1383 (if (eq (newsticker--age item) 'feed)
1384 (insert (newsticker--title item))
1385 ;; FIXME: This is not the "real" title!
1386 (insert (format "%s"
1387 (car (newsticker--cache-get-feed
1388 feed-name-symbol)))))
1389 (setq pos-text-end (point-marker))))))
1390 (setq format (substring format 2)))
1391 ((string= "%s" prefix)
1392 ;; statistics
1393 (setq pos-stat-start (point-marker))
1394 (if (eq (newsticker--age item) 'feed)
1395 (insert (newsticker--buffer-statistics
1396 feed-name-symbol)))
1397 (setq pos-stat-end (point-marker))
1398 (setq format (substring format 2)))
1399 ((string= "%t" prefix)
1400 ;; title
1401 (when (car item)
1402 (setq pos-text-start (point-marker))
1403 (insert (car item))
1404 (setq pos-text-end (point-marker)))
1405 (setq format (substring format 2)))
1406 ((string-match "%." prefix)
1407 ;; unknown specifier!
1408 (insert prefix)
1409 (setq format (substring format 2)))
1410 ((string-match "^\\([^%]*\\)\\(.*\\)" format) ;; FIXME!
1411 ;; everything else
1412 (let ((p (point)))
1413 (insert (substring format
1414 (match-beginning 1) (match-end 1)))
1415 ;; in case that the format string contained newlines
1416 (put-text-property p (point) 'hard t))
1417 (setq format (substring format (match-beginning 2)))))))
1418
1419 ;; decode HTML if possible...
1420 (let ((is-rendered-HTML nil))
1421 (when (and newsticker-html-renderer pos-text-start pos-text-end)
1422 (condition-case error-data
1423 (save-excursion
1424 ;; check whether it is necessary to call html renderer
1425 ;; (regexp inspired by htmlr.el)
1426 (goto-char pos-text-start)
1427 (when (re-search-forward
1428 "</?[A-Za-z1-6]*\\|&#?[A-Za-z0-9]+;" pos-text-end t)
1429 ;; (message "%s" (newsticker--title item))
1430 (let ((w3m-fill-column (if newsticker-use-full-width
1431 -1 fill-column))
1432 (w3-maximum-line-length
1433 (if newsticker-use-full-width nil fill-column)))
1434 (save-excursion
1435 (funcall newsticker-html-renderer pos-text-start
1436 pos-text-end)))
1437 (cond ((eq newsticker-html-renderer 'w3m-region)
1438 (add-text-properties pos (point-max)
1439 (list 'keymap
1440 w3m-minor-mode-map)))
1441 ((eq newsticker-html-renderer 'w3-region)
1442 (add-text-properties pos (point-max)
1443 (list 'keymap w3-mode-map))))
1444 (setq is-rendered-HTML t)))
1445 (error
1446 (message "Error: HTML rendering failed: %s, %s"
1447 (car error-data) (cdr error-data)))))
1448 ;; After html rendering there might be chunks of blank
1449 ;; characters between rendered text and date, statistics or
1450 ;; whatever. Remove it
1451 (when (and (eq type 'item) is-rendered-HTML)
1452 (goto-char pos)
1453 (while (re-search-forward "[ \t]*\n[ \t]*" nil t)
1454 (replace-match " " nil nil))
1455 (goto-char (point-max)))
1456 (when (and newsticker-justification
1457 (memq type '(item desc))
1458 (not is-rendered-HTML))
1459 (condition-case nil
1460 (let ((use-hard-newlines t))
1461 (fill-region pos (point-max) newsticker-justification))
1462 (error nil))))
1463
1464 ;; remove leading and trailing newlines
1465 (goto-char pos)
1466 (unless (= 0 (skip-chars-forward " \t\r\n"))
1467 (delete-region pos (point)))
1468 (goto-char (point-max))
1469 (let ((end (point)))
1470 (unless (= 0 (skip-chars-backward " \t\r\n" (1+ pos)))
1471 (delete-region (point) end)))
1472 (goto-char (point-max))
1473 ;; closing newline
1474 (unless nil ;;(eq pos (point))
1475 (insert "\n")
1476 (put-text-property (1- (point)) (point) 'hard t))
1477
1478 ;; insert enclosure element
1479 (when (eq type 'desc)
1480 (setq pos-enclosure-start (point))
1481 (newsticker--insert-enclosure item newsticker--url-keymap)
1482 (setq pos-enclosure-end (point)))
1483
1484 ;; show extra elements
1485 (when (eq type 'desc)
1486 (goto-char (point-max))
1487 (setq pos-extra-start (point))
1488 (newsticker--print-extra-elements item newsticker--url-keymap)
1489 (setq pos-extra-end (point)))
1490
1491 ;; text properties
1492 (when (memq type '(feed item))
1493 (add-text-properties pos (1- (point))
1494 (list 'mouse-face 'highlight
1495 'nt-link (newsticker--link item)
1496 'help-echo
1497 (format "mouse-2: visit item (%s)"
1498 (newsticker--link item))
1499 'keymap newsticker--url-keymap))
1500 (add-text-properties pos (point)
1501 (list 'nt-title (newsticker--title item)
1502 'nt-desc (newsticker--desc item))))
1503
1504 (add-text-properties pos (point)
1505 (list 'nt-type type
1506 'nt-face type
1507 'nt-age age
1508 'nt-guid (newsticker--guid item)))
1509 (when (and pos-date-start pos-date-end)
1510 (put-text-property pos-date-start pos-date-end 'nt-face 'date))
1511 (when (and pos-stat-start pos-stat-end)
1512 (put-text-property pos-stat-start pos-stat-end 'nt-face 'stat))
1513 (when (and pos-extra-start pos-extra-end)
1514 (put-text-property pos-extra-start pos-extra-end
1515 'nt-face 'extra)
1516 (put-text-property pos-extra-start pos-extra-end
1517 'nt-type 'extra))
1518 (when (and pos-enclosure-start pos-enclosure-end
1519 (> pos-enclosure-end pos-enclosure-start))
1520 (put-text-property pos-enclosure-start (1- pos-enclosure-end)
1521 'nt-face 'enclosure))
1522
1523 ;; left margin
1524 ;;(unless (memq type '(feed item))
1525 ;;(set-left-margin pos (1- (point)) 1))
1526
1527 ;; save rendered stuff
1528 (cond ((eq type 'desc)
1529 ;; preformatted contents
1530 (newsticker--cache-set-preformatted-contents
1531 item (buffer-substring pos (point))))
1532 ((eq type 'item)
1533 ;; preformatted title
1534 (newsticker--cache-set-preformatted-title
1535 item (buffer-substring pos (point)))))))))
1536
1537(defun newsticker--buffer-statistics (feed-name-symbol)
1538 "Return a statistic string for the feed given by FEED-NAME-SYMBOL.
1539See `newsticker-statistics-format'."
1540 (let ((case-fold-search nil))
1541 (replace-regexp-in-string
1542 "%a"
1543 (format "%d" (newsticker--stat-num-items feed-name-symbol))
1544 (replace-regexp-in-string
1545 "%i"
1546 (format "%d" (newsticker--stat-num-items feed-name-symbol 'immortal))
1547 (replace-regexp-in-string
1548 "%n"
1549 (format "%d" (newsticker--stat-num-items feed-name-symbol 'new))
1550 (replace-regexp-in-string
1551 "%o"
1552 (format "%d" (newsticker--stat-num-items feed-name-symbol 'old))
1553 (replace-regexp-in-string
1554 "%O"
1555 (format "%d" (newsticker--stat-num-items feed-name-symbol 'obsolete))
1556 newsticker-statistics-format)))))))
1557
1558(defun newsticker--buffer-set-faces (start end)
1559 "Add face properties according to mark property.
1560Scans the buffer between START and END."
1561 (save-excursion
1562 (put-text-property start end 'face 'newsticker-default-face)
1563 (goto-char start)
1564 (let ((pos1 start)
1565 (pos2 1)
1566 (nt-face (get-text-property start 'nt-face))
1567 (nt-age (get-text-property start 'nt-age)))
1568 (when nt-face
1569 (setq pos2 (next-single-property-change (point) 'nt-face))
1570 (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
1571 (setq nt-face (get-text-property pos2 'nt-face))
1572 (setq pos1 pos2))
1573 (while (and (setq pos2 (next-single-property-change pos1 'nt-face))
1574 (<= pos2 end)
1575 (> pos2 pos1))
1576 (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
1577 (setq nt-face (get-text-property pos2 'nt-face))
1578 (setq nt-age (get-text-property pos2 'nt-age))
1579 (setq pos1 pos2)))))
1580
1581(defun newsticker--buffer-set-invisibility (start end)
1582 "Add invisibility properties according to nt-type property.
1583Scans the buffer between START and END. Sets the 'invisible
1584property to '(<nt-type>-<nt-age> <nt-type> <nt-age>)."
1585 (save-excursion
1586 ;; reset invisibility settings
1587 (put-text-property start end 'invisible nil)
1588 ;; let's go
1589 (goto-char start)
1590 (let ((pos1 start)
1591 (pos2 1)
1592 (nt-type (get-text-property start 'nt-type))
1593 (nt-age (get-text-property start 'nt-age)))
1594 (when nt-type
1595 (setq pos2 (next-single-property-change (point) 'nt-type))
1596 (put-text-property (max (point-min) pos1) (1- pos2)
1597 'invisible
1598 (list (intern
1599 (concat
1600 (symbol-name
1601 (if (eq nt-type 'extra) 'desc nt-type))
1602 "-"
1603 (symbol-name nt-age)))
1604 nt-type
1605 nt-age))
1606 (setq nt-type (get-text-property pos2 'nt-type))
1607 (setq pos1 pos2))
1608 (while (and (setq pos2 (next-single-property-change pos1 'nt-type))
1609 (<= pos2 end)
1610 (> pos2 pos1))
1611 ;; must shift one char to the left in order to handle inivisible
1612 ;; newlines, motion in invisible text areas and all that correctly
1613 (put-text-property (1- pos1) (1- pos2)
1614 'invisible
1615 (list (intern
1616 (concat
1617 (symbol-name
1618 (if (eq nt-type 'extra) 'desc nt-type))
1619 "-"
1620 (symbol-name nt-age)))
1621 nt-type
1622 nt-age))
1623 (setq nt-type (get-text-property pos2 'nt-type))
1624 (setq nt-age (get-text-property pos2 'nt-age))
1625 (setq pos1 pos2)))))
1626
1627(defun newsticker--set-face-properties (pos1 pos2 nt-face age)
1628 "Set the face for the text between the positions POS1 and POS2.
1629The face is chosen according the values of NT-FACE and AGE."
1630 (let ((face (cond ((eq nt-face 'feed)
1631 'newsticker-feed-face)
1632 ((eq nt-face 'item)
1633 (cond ((eq age 'new)
1634 'newsticker-new-item-face)
1635 ((eq age 'old)
1636 'newsticker-old-item-face)
1637 ((eq age 'immortal)
1638 'newsticker-immortal-item-face)
1639 ((eq age 'obsolete)
1640 'newsticker-obsolete-item-face)))
1641 ((eq nt-face 'date)
1642 'newsticker-date-face)
1643 ((eq nt-face 'stat)
1644 'newsticker-statistics-face)
1645 ((eq nt-face 'extra)
1646 'newsticker-extra-face)
1647 ((eq nt-face 'enclosure)
1648 'newsticker-enclosure-face))))
1649 (when face
1650 (put-text-property pos1 (max pos1 pos2) 'face face))))
1651
1652;; ======================================================================
1653;;; Functions working on the *newsticker* buffer
1654;; ======================================================================
1655(defun newsticker--buffer-make-item-completely-visible ()
1656 "Scroll buffer until current item is completely visible."
1657 (when newsticker--auto-narrow-to-feed
1658 (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-feed))
1659 (point-min)))
1660 (max (or (save-excursion (newsticker--buffer-end-of-feed))
1661 (point-max))))
1662 (narrow-to-region min max)))
1663 (when newsticker--auto-narrow-to-item
1664 (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-item))
1665 (point-min)))
1666 (max (or (save-excursion (newsticker--buffer-end-of-item))
1667 (point-max))))
1668 (narrow-to-region min max)))
1669 (sit-for 0)
1670 ;; do not count lines and stuff because that does not work when images
1671 ;; are displayed. Do it the simple way:
1672 (save-excursion
1673 (newsticker--buffer-end-of-item)
1674 (unless (pos-visible-in-window-p)
1675 (recenter -1)))
1676 (unless (pos-visible-in-window-p)
1677 (recenter 0)))
1678
1679(defun newsticker--buffer-get-feed-title-at-point ()
1680 "Return feed symbol of headline at point."
1681 (format "%s" (or (get-text-property (point) 'feed) " ")))
1682
1683(defun newsticker--buffer-get-item-title-at-point ()
1684 "Return feed symbol of headline at point."
1685 (format "%s" (or (get-text-property (point) 'nt-title) " ")))
1686
1687(defun newsticker--buffer-goto (types &optional age backwards)
1688 "Search next occurrence of TYPES in current buffer.
1689TYPES is a list of symbols. If TYPES is found point is moved, if
1690not point is left unchanged. If optional parameter AGE is not
1691nil, the type AND the age must match. If BACKWARDS is t, search
1692backwards."
1693 (let ((pos (save-excursion
1694 (save-restriction
1695 (widen)
1696 (catch 'found
1697 (let ((tpos (point)))
1698 (while (setq tpos
1699 (if backwards
1700 (if (eq tpos (point-min))
1701 nil
1702 (or (previous-single-property-change
1703 tpos 'nt-type)
1704 (point-min)))
1705 (next-single-property-change
1706 tpos 'nt-type)))
1707 (and (memq (get-text-property tpos 'nt-type) types)
1708 (or (not age)
1709 (eq (get-text-property tpos 'nt-age) age))
1710 (throw 'found tpos)))))))))
1711 (when pos
1712 (goto-char pos))
1713 pos))
1714
1715(defun newsticker--buffer-hideshow (mark-age onoff)
1716 "Hide or show items of type MARK-AGE.
1717If ONOFF is nil the item is hidden, otherwise it is shown."
1718 (if onoff
1719 (remove-from-invisibility-spec mark-age)
1720 (add-to-invisibility-spec mark-age)))
1721
1722(defun newsticker--buffer-beginning-of-item ()
1723 "Move point to the beginning of the item at point.
1724Return new position."
1725 (if (bobp)
1726 (point)
1727 (let ((type (get-text-property (point) 'nt-type))
1728 (typebefore (get-text-property (1- (point)) 'nt-type)))
1729 (if (and (memq type '(item feed))
1730 (not (eq type typebefore)))
1731 (point)
1732 (newsticker--buffer-goto '(item feed) nil t)
1733 (point)))))
1734
1735(defun newsticker--buffer-beginning-of-feed ()
1736 "Move point to the beginning of the feed at point.
1737Return new position."
1738 (if (bobp)
1739 (point)
1740 (let ((type (get-text-property (point) 'nt-type))
1741 (typebefore (get-text-property (1- (point)) 'nt-type)))
1742 (if (and (memq type '(feed))
1743 (not (eq type typebefore)))
1744 (point)
1745 (newsticker--buffer-goto '(feed) nil t)
1746 (point)))))
1747
1748(defun newsticker--buffer-end-of-item ()
1749 "Move point to the end of the item at point.
1750Take care: end of item is at the end of its last line!"
1751 (when (newsticker--buffer-goto '(item feed nil))
1752 (point)))
1753
1754(defun newsticker--buffer-end-of-feed ()
1755 "Move point to the end of the last item of the feed at point.
1756Take care: end of item is at the end of its last line!"
1757 (when (newsticker--buffer-goto '(feed nil))
1758 (backward-char 1)
1759 (point)))
1760
1761;; ======================================================================
1762;;; misc
1763;; ======================================================================
1764
1765(defun newsticker-mouse-browse-url (event)
1766 "Call `browse-url' for the link of the item at which the EVENT occurred."
1767 (interactive "e")
1768 (save-excursion
1769 (switch-to-buffer (window-buffer (posn-window (event-end event))))
1770 (let ((url (get-text-property (posn-point (event-end event))
1771 'nt-link)))
1772 (when url
1773 (browse-url url)
1774 (save-excursion
1775 (goto-char (posn-point (event-end event)))
1776 (if newsticker-automatically-mark-visited-items-as-old
1777 (newsticker-mark-item-at-point-as-read t)))))))
1778
1779(defun newsticker-browse-url ()
1780 "Call `browse-url' for the link of the item at point."
1781 (interactive)
1782 (let ((url (get-text-property (point) 'nt-link)))
1783 (when url
1784 (browse-url url)
1785 (if newsticker-automatically-mark-visited-items-as-old
1786 (newsticker-mark-item-at-point-as-read t)))))
1787
1788(defvar newsticker-open-url-history
1789 '("wget" "xmms" "realplay")
1790 "...")
1791
1792(defun newsticker-handle-url ()
1793 "Ask for a program to open the link of the item at point."
1794 (interactive)
1795 (let ((url (get-text-property (point) 'nt-link)))
1796 (when url
1797 (let ((prog (read-string "Open url with: " nil
1798 'newsticker-open-url-history)))
1799 (when prog
1800 (message "%s %s" prog url)
1801 (start-process prog prog prog url)
1802 (if newsticker-automatically-mark-visited-items-as-old
1803 (newsticker-mark-item-at-point-as-read t)))))))
1804
1805
1806;; ======================================================================
1807;;; Misc
1808;; ======================================================================
1809
1810(defun newsticker--cache-sort ()
1811 "Sort the newsticker cache data."
1812 (let ((sort-fun (cond ((eq newsticker-sort-method 'sort-by-time)
1813 'newsticker--cache-item-compare-by-time)
1814 ((eq newsticker-sort-method 'sort-by-title)
1815 'newsticker--cache-item-compare-by-title)
1816 ((eq newsticker-sort-method 'sort-by-original-order)
1817 'newsticker--cache-item-compare-by-position))))
1818 (mapc (lambda (feed-list)
1819 (setcdr feed-list (sort (cdr feed-list)
1820 sort-fun)))
1821 newsticker--cache)))
1822
1823(provide 'newsticker-plainview)
041fa0d4
MB
1824
1825;; arch-tag: 4e48b683-d48b-48dd-a13e-fe45baf41184
2415d4c6 1826;;; newsticker-plainview.el ends here