95676
|
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
|
|
10 ;; Time-stamp: "7. Juni 2008, 23:37:09 (ulf)"
|
95684
|
11 ;; CVS-Version: $Id: newsticker-plainview.el,v 1.1 2008/06/08 15:35:39 u11 Exp $
|
95676
|
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.
|
|
51 See 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.
|
|
57 Calls all actions which are necessary in order to make the new
|
|
58 value 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.
|
|
68 Calls all actions which are necessary in order to make the new
|
|
69 value 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.
|
|
84 The 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.
|
|
103 The 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.
|
|
119 The 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).
|
|
134 The 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.
|
|
145 The 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.
|
|
246 If set to t old items will be completely folded and only new
|
|
247 items will show up in the *newsticker* buffer. Otherwise old as
|
|
248 well 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*.
|
|
256 If set to t old items will be folded and new items will be
|
|
257 unfolded. 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.
|
|
278 Each 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
|
|
282 The default value 'newsticker--buffer-make-item-completely-visible
|
|
283 assures 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.
|
|
291 Each function is called after one of `newsticker-next-feed', and
|
|
292 `newsticker-previous-feed' has been called.
|
|
293
|
|
294 The default value 'newsticker--buffer-make-item-completely-visible
|
|
295 assures 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.
|
|
303 Each function is called after `newsticker-buffer-update' has been called.
|
|
304
|
|
305 The default value '`newsticker-w3m-show-inline-images' loads inline
|
|
306 images."
|
|
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.
|
|
313 Each function is called after
|
|
314 `newsticker-toggle-auto-narrow-to-feed' or
|
|
315 `newsticker-toggle-auto-narrow-to-item' has been called.
|
|
316
|
|
317 The default value '`newsticker-w3m-show-inline-images' loads inline
|
|
318 images."
|
|
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 ;; ======================================================================
|
|
555 (defun newsticker-plainview ()
|
|
556 "Start newsticker plainview."
|
|
557 (interactive)
|
|
558 (newsticker-buffer-update t)
|
|
559 (switch-to-buffer "*newsticker*"))
|
|
560
|
|
561 (defun newsticker-buffer-force-update ()
|
|
562 "Update the newsticker buffer, even if not necessary."
|
|
563 (interactive)
|
|
564 (newsticker-buffer-update t))
|
|
565
|
|
566 (defun newsticker-buffer-update (&optional force)
|
|
567 "Update the *newsticker* buffer.
|
|
568 Unless FORCE is t this is done only if necessary, i.e. when the
|
|
569 *newsticker* buffer is not up-to-date."
|
|
570 (interactive)
|
|
571 ;; bring cache data into proper order....
|
|
572 (newsticker--cache-sort)
|
|
573 ;; fill buffer
|
|
574 (save-excursion
|
|
575 (let ((buf (get-buffer "*newsticker*")))
|
|
576 (if buf
|
|
577 (switch-to-buffer buf)
|
|
578 (switch-to-buffer (get-buffer-create "*newsticker*"))
|
|
579 (newsticker--buffer-set-uptodate nil)))
|
|
580 (when (or force
|
|
581 (not newsticker--buffer-uptodate-p))
|
|
582 (message "Preparing newsticker buffer...")
|
|
583 (setq buffer-undo-list t)
|
|
584 (let ((inhibit-read-only t))
|
|
585 (set-buffer-modified-p nil)
|
|
586 (erase-buffer)
|
|
587 (newsticker-mode)
|
|
588 ;; Emacs 21.3.50 does not care if we turn off auto-fill in the
|
|
589 ;; definition of newsticker-mode, so we do it here (again)
|
|
590 (auto-fill-mode -1)
|
|
591
|
|
592 (set-buffer-file-coding-system 'utf-8)
|
|
593
|
|
594 (if newsticker-use-full-width
|
|
595 (set (make-local-variable 'fill-column) (1- (window-width))))
|
|
596 (newsticker--buffer-insert-all-items)
|
|
597
|
|
598 ;; FIXME: needed for methods buffer in ecb
|
|
599 ;; (set-visited-file-name "*newsticker*")
|
|
600
|
|
601 (set-buffer-modified-p nil)
|
|
602 (newsticker-hide-all-desc)
|
|
603 (if newsticker-hide-old-items-in-newsticker-buffer
|
|
604 (newsticker-hide-old-items))
|
|
605 (if newsticker-show-descriptions-of-new-items
|
|
606 (newsticker-show-new-item-desc))
|
|
607 )
|
|
608 (message ""))
|
|
609 (newsticker--buffer-set-uptodate t)
|
|
610 (run-hooks 'newsticker-buffer-change-hook)))
|
|
611
|
|
612 (defun newsticker-get-news-at-point ()
|
|
613 "Launch retrieval of news for the feed point is in.
|
|
614 This does NOT start the retrieval timers."
|
|
615 (interactive)
|
|
616 ;; launch retrieval of news
|
|
617 (let ((feed (get-text-property (point) 'feed)))
|
|
618 (when feed
|
|
619 (newsticker--debug-msg "Getting news for %s" (symbol-name feed))
|
|
620 (newsticker-get-news (symbol-name feed)))))
|
|
621
|
|
622 (defun newsticker-w3m-show-inline-images ()
|
|
623 "Show inline images in visible text ranges.
|
|
624 In-line images in invisible text ranges are hidden. This function
|
|
625 calls `w3m-toggle-inline-image'. It works only if
|
|
626 `newsticker-html-renderer' is set to `w3m-region'."
|
|
627 (interactive)
|
|
628 (if (eq newsticker-html-renderer 'w3m-region)
|
|
629 (let ((inhibit-read-only t))
|
|
630 (save-excursion
|
|
631 (save-restriction
|
|
632 (widen)
|
|
633 (goto-char (point-min))
|
|
634 (let ((pos (point)))
|
|
635 (while pos
|
|
636 (setq pos (next-single-property-change pos 'w3m-image))
|
|
637 (when pos
|
|
638 (goto-char pos)
|
|
639 (when (get-text-property pos 'w3m-image)
|
|
640 (let ((invis (newsticker--lists-intersect-p
|
|
641 (get-text-property (1- (point))
|
|
642 'invisible)
|
|
643 buffer-invisibility-spec)))
|
|
644 (unless (car (get-text-property (1- (point))
|
|
645 'display))
|
|
646 (unless invis
|
|
647 (w3m-toggle-inline-image t)))))))))))))
|
|
648
|
|
649 ;; ======================================================================
|
|
650 ;;; Keymap stuff
|
|
651 ;; ======================================================================
|
|
652 (defun newsticker-close-buffer ()
|
|
653 "Close the newsticker buffer."
|
|
654 (interactive)
|
|
655 (newsticker--cache-update t)
|
|
656 (bury-buffer))
|
|
657
|
|
658 (defun newsticker-next-new-item (&optional do-not-wrap-at-eob)
|
|
659 "Go to next new news item.
|
|
660 If no new item is found behind point, search is continued at
|
|
661 beginning of buffer unless optional argument DO-NOT-WRAP-AT-EOB
|
|
662 is non-nil."
|
|
663 (interactive)
|
|
664 (widen)
|
|
665 (let ((go-ahead t))
|
|
666 (while go-ahead
|
|
667 (unless (newsticker--buffer-goto '(item) 'new)
|
|
668 ;; found nothing -- wrap
|
|
669 (unless do-not-wrap-at-eob
|
|
670 (goto-char (point-min))
|
|
671 (newsticker-next-new-item t))
|
|
672 (setq go-ahead nil))
|
|
673 (unless (newsticker--lists-intersect-p
|
|
674 (get-text-property (point) 'invisible)
|
|
675 buffer-invisibility-spec)
|
|
676 ;; this item is invisible -- continue search
|
|
677 (setq go-ahead nil))))
|
|
678 (run-hooks 'newsticker-select-item-hook)
|
|
679 (point))
|
|
680
|
|
681 (defun newsticker-previous-new-item (&optional do-not-wrap-at-bob)
|
|
682 "Go to previous new news item.
|
|
683 If no new item is found before point, search is continued at
|
|
684 beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
|
|
685 is non-nil."
|
|
686 (interactive)
|
|
687 (widen)
|
|
688 (let ((go-ahead t))
|
|
689 (while go-ahead
|
|
690 (unless (newsticker--buffer-goto '(item) 'new t)
|
|
691 (unless do-not-wrap-at-bob
|
|
692 (goto-char (point-max))
|
|
693 (newsticker--buffer-goto '(item) 'new t)))
|
|
694 (unless (newsticker--lists-intersect-p
|
|
695 (get-text-property (point) 'invisible)
|
|
696 buffer-invisibility-spec)
|
|
697 (setq go-ahead nil))))
|
|
698 (run-hooks 'newsticker-select-item-hook)
|
|
699 (point))
|
|
700
|
|
701 (defun newsticker-next-item (&optional do-not-wrap-at-eob)
|
|
702 "Go to next news item.
|
|
703 Return new buffer position.
|
|
704 If no item is found below point, search is continued at beginning
|
|
705 of buffer unless optional argument DO-NOT-WRAP-AT-EOB is
|
|
706 non-nil."
|
|
707 (interactive)
|
|
708 (widen)
|
|
709 (let ((go-ahead t)
|
|
710 (search-list '(item)))
|
|
711 (if newsticker--auto-narrow-to-item
|
|
712 (setq search-list '(item feed)))
|
|
713 (while go-ahead
|
|
714 (unless (newsticker--buffer-goto search-list)
|
|
715 ;; found nothing -- wrap
|
|
716 (unless do-not-wrap-at-eob
|
|
717 (goto-char (point-min)))
|
|
718 (setq go-ahead nil))
|
|
719 (unless (newsticker--lists-intersect-p
|
|
720 (get-text-property (point) 'invisible)
|
|
721 buffer-invisibility-spec)
|
|
722 (setq go-ahead nil))))
|
|
723 (run-hooks 'newsticker-select-item-hook)
|
|
724 (force-mode-line-update)
|
|
725 (point))
|
|
726
|
|
727 (defun newsticker-next-item-same-feed ()
|
|
728 "Go to next news item in the same feed.
|
|
729 Return new buffer position. If no item is found below point or if
|
|
730 auto-narrow-to-item is enabled, nil is returned."
|
|
731 (interactive)
|
|
732 (if newsticker--auto-narrow-to-item
|
|
733 nil
|
|
734 (let ((go-ahead t)
|
|
735 (current-pos (point))
|
|
736 (end-of-feed (save-excursion (newsticker--buffer-end-of-feed))))
|
|
737 (while go-ahead
|
|
738 (unless (newsticker--buffer-goto '(item))
|
|
739 (setq go-ahead nil))
|
|
740 (unless (newsticker--lists-intersect-p
|
|
741 (get-text-property (point) 'invisible)
|
|
742 buffer-invisibility-spec)
|
|
743 (setq go-ahead nil)))
|
|
744 (if (and (> (point) current-pos)
|
|
745 (< (point) end-of-feed))
|
|
746 (point)
|
|
747 (goto-char current-pos)
|
|
748 nil))))
|
|
749
|
|
750 (defun newsticker-previous-item (&optional do-not-wrap-at-bob)
|
|
751 "Go to previous news item.
|
|
752 Return new buffer position.
|
|
753 If no item is found before point, search is continued at
|
|
754 beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
|
|
755 is non-nil."
|
|
756 (interactive)
|
|
757 (widen)
|
|
758 (let ((go-ahead t)
|
|
759 (search-list '(item)))
|
|
760 (if newsticker--auto-narrow-to-item
|
|
761 (setq search-list '(item feed)))
|
|
762 (when (bobp)
|
|
763 (unless do-not-wrap-at-bob
|
|
764 (goto-char (point-max))))
|
|
765 (while go-ahead
|
|
766 (if (newsticker--buffer-goto search-list nil t)
|
|
767 (unless (newsticker--lists-intersect-p
|
|
768 (get-text-property (point) 'invisible)
|
|
769 buffer-invisibility-spec)
|
|
770 (setq go-ahead nil))
|
|
771 (goto-char (point-min))
|
|
772 (setq go-ahead nil))))
|
|
773 (run-hooks 'newsticker-select-item-hook)
|
|
774 (force-mode-line-update)
|
|
775 (point))
|
|
776
|
|
777 (defun newsticker-next-feed ()
|
|
778 "Go to next news feed.
|
|
779 Return new buffer position."
|
|
780 (interactive)
|
|
781 (widen)
|
|
782 (newsticker--buffer-goto '(feed))
|
|
783 (run-hooks 'newsticker-select-feed-hook)
|
|
784 (force-mode-line-update)
|
|
785 (point))
|
|
786
|
|
787 (defun newsticker-previous-feed ()
|
|
788 "Go to previous news feed.
|
|
789 Return new buffer position."
|
|
790 (interactive)
|
|
791 (widen)
|
|
792 (newsticker--buffer-goto '(feed) nil t)
|
|
793 (run-hooks 'newsticker-select-feed-hook)
|
|
794 (force-mode-line-update)
|
|
795 (point))
|
|
796
|
|
797 (defun newsticker-mark-all-items-at-point-as-read-and-redraw ()
|
|
798 "Mark all items as read and clear ticker contents."
|
|
799 (interactive)
|
|
800 (when (or newsticker--buffer-uptodate-p
|
|
801 (y-or-n-p
|
|
802 "Buffer is not up to date -- really mark items as read? "))
|
|
803 (newsticker-mark-all-items-of-feed-as-read
|
|
804 (get-text-property (point) 'feed))))
|
|
805
|
|
806 (defun newsticker-mark-all-items-of-feed-as-read (feed)
|
|
807 "Mark all items of FEED as read, clear ticker, and redraw buffer."
|
|
808 (when feed
|
|
809 (let ((pos (point)))
|
|
810 (message "Marking all items as read for %s" (symbol-name feed))
|
|
811 (newsticker--cache-replace-age newsticker--cache feed 'new 'old)
|
|
812 (newsticker--cache-replace-age newsticker--cache feed 'obsolete
|
|
813 'old)
|
|
814 (newsticker--cache-update)
|
|
815 (newsticker--buffer-set-uptodate nil)
|
|
816 (newsticker--ticker-text-setup)
|
|
817 (newsticker-buffer-update)
|
|
818 ;; go back to where we came frome
|
|
819 (goto-char pos)
|
|
820 (end-of-line)
|
|
821 (newsticker--buffer-goto '(feed) nil t))))
|
|
822
|
|
823 (defun newsticker-mark-all-items-at-point-as-read ()
|
|
824 "Mark all items as read and clear ticker contents."
|
|
825 (interactive)
|
|
826 (when (or newsticker--buffer-uptodate-p
|
|
827 (y-or-n-p
|
|
828 "Buffer is not up to date -- really mark items as read? "))
|
|
829 (newsticker--do-mark-item-at-point-as-read t)
|
|
830 (while (newsticker-next-item-same-feed)
|
|
831 (newsticker--do-mark-item-at-point-as-read t))
|
|
832 (newsticker-next-item t)))
|
|
833
|
|
834 (defun newsticker-mark-item-at-point-as-read (&optional respect-immortality)
|
|
835 "Mark item at point as read and move to next item.
|
|
836 If optional argument RESPECT-IMMORTALITY is not nil immortal items do
|
|
837 not get changed."
|
|
838 (interactive)
|
|
839 (when (or newsticker--buffer-uptodate-p
|
|
840 (y-or-n-p
|
|
841 "Buffer is not up to date -- really mark this item as read? "))
|
|
842 (newsticker--do-mark-item-at-point-as-read respect-immortality)
|
|
843 ;; move forward
|
|
844 (newsticker-next-item t)))
|
|
845
|
|
846 (defun newsticker--do-mark-item-at-point-as-read (&optional respect-immortality)
|
|
847 "Mark item at point as read.
|
|
848 If optional argument RESPECT-IMMORTALITY is not nil immortal items do
|
|
849 not get changed."
|
|
850 (let ((feed (get-text-property (point) 'feed)))
|
|
851 (when feed
|
|
852 (save-excursion
|
|
853 (newsticker--buffer-beginning-of-item)
|
|
854 (let ((inhibit-read-only t)
|
|
855 (age (get-text-property (point) 'nt-age))
|
|
856 (title (get-text-property (point) 'nt-title))
|
|
857 (guid (get-text-property (point) 'nt-guid))
|
|
858 (nt-desc (get-text-property (point) 'nt-desc))
|
|
859 (pos (save-excursion (newsticker--buffer-end-of-item)))
|
|
860 item)
|
|
861 (when (or (eq age 'new)
|
|
862 (eq age 'obsolete)
|
|
863 (and (eq age 'immortal)
|
|
864 (not respect-immortality)))
|
|
865 ;; find item
|
|
866 (setq item (newsticker--cache-contains newsticker--cache
|
|
867 feed title nt-desc
|
|
868 nil nil guid))
|
|
869 ;; mark as old
|
|
870 (when item
|
|
871 (setcar (nthcdr 4 item) 'old)
|
|
872 (newsticker--do-forget-preformatted item))
|
|
873 ;; clean up ticker
|
|
874 (if (or (and (eq age 'new)
|
|
875 newsticker-hide-immortal-items-in-echo-area)
|
|
876 (and (memq age '(old immortal))
|
|
877 (not
|
|
878 (eq newsticker-hide-old-items-in-newsticker-buffer
|
|
879 newsticker-hide-immortal-items-in-echo-area))))
|
|
880 (newsticker--ticker-text-remove feed title))
|
|
881 ;; set faces etc.
|
|
882 (save-excursion
|
|
883 (save-restriction
|
|
884 (widen)
|
|
885 (put-text-property (point) pos 'nt-age 'old)
|
|
886 (newsticker--buffer-set-faces (point) pos)))
|
|
887 (set-buffer-modified-p nil)))))))
|
|
888
|
|
889 (defun newsticker-mark-item-at-point-as-immortal ()
|
|
890 "Mark item at point as read."
|
|
891 (interactive)
|
|
892 (when (or newsticker--buffer-uptodate-p
|
|
893 (y-or-n-p
|
|
894 "Buffer is not up to date -- really mark this item as read? "))
|
|
895 (let ((feed (get-text-property (point) 'feed))
|
|
896 (item nil))
|
|
897 (when feed
|
|
898 (save-excursion
|
|
899 (newsticker--buffer-beginning-of-item)
|
|
900 (let ((inhibit-read-only t)
|
|
901 (oldage (get-text-property (point) 'nt-age))
|
|
902 (title (get-text-property (point) 'nt-title))
|
|
903 (guid (get-text-property (point) 'nt-guid))
|
|
904 (pos (save-excursion (newsticker--buffer-end-of-item))))
|
|
905 (let ((newage 'immortal))
|
|
906 (if (eq oldage 'immortal)
|
|
907 (setq newage 'old))
|
|
908 (setq item (newsticker--cache-contains newsticker--cache
|
|
909 feed title nil nil nil
|
|
910 guid))
|
|
911 ;; change age
|
|
912 (when item
|
|
913 (setcar (nthcdr 4 item) newage)
|
|
914 (newsticker--do-forget-preformatted item))
|
|
915 (if (or (and (eq newage 'immortal)
|
|
916 newsticker-hide-immortal-items-in-echo-area)
|
|
917 (and (eq newage 'obsolete)
|
|
918 newsticker-hide-obsolete-items-in-echo-area)
|
|
919 (and (eq oldage 'immortal)
|
|
920 (not
|
|
921 (eq newsticker-hide-old-items-in-newsticker-buffer
|
|
922 newsticker-hide-immortal-items-in-echo-area))))
|
|
923 (newsticker--ticker-text-remove feed title)
|
|
924 (newsticker--ticker-text-setup))
|
|
925 (save-excursion
|
|
926 (save-restriction
|
|
927 (widen)
|
|
928 (put-text-property (point) pos 'nt-age newage)
|
|
929 (if (eq newage 'immortal)
|
|
930 (put-text-property (point) pos 'nt-age 'immortal)
|
|
931 (put-text-property (point) pos 'nt-age 'old))
|
|
932 (newsticker--buffer-set-faces (point) pos))))))
|
|
933 (if item
|
|
934 (newsticker-next-item t))))))
|
|
935
|
|
936 (defun newsticker-mark-all-items-as-read ()
|
|
937 "Mark all items as read and clear ticker contents."
|
|
938 (interactive)
|
|
939 (when (or newsticker--buffer-uptodate-p
|
|
940 (y-or-n-p
|
|
941 "Buffer is not up to date -- really mark items as read? "))
|
|
942 (newsticker--cache-replace-age newsticker--cache 'any 'new 'old)
|
|
943 (newsticker--buffer-set-uptodate nil)
|
|
944 (newsticker--ticker-text-setup)
|
|
945 (newsticker--cache-update)
|
|
946 (newsticker-buffer-update)))
|
|
947
|
|
948 (defun newsticker-hide-extra ()
|
|
949 "Hide the extra elements of items."
|
|
950 (interactive)
|
|
951 (newsticker--buffer-hideshow 'extra nil)
|
|
952 (newsticker--buffer-redraw))
|
|
953
|
|
954 (defun newsticker-show-extra ()
|
|
955 "Show the extra elements of items."
|
|
956 (interactive)
|
|
957 (newsticker--buffer-hideshow 'extra t)
|
|
958 (newsticker--buffer-redraw))
|
|
959
|
|
960 (defun newsticker-hide-old-item-desc ()
|
|
961 "Hide the description of old items."
|
|
962 (interactive)
|
|
963 (newsticker--buffer-hideshow 'desc-old nil)
|
|
964 (newsticker--buffer-redraw))
|
|
965
|
|
966 (defun newsticker-show-old-item-desc ()
|
|
967 "Show the description of old items."
|
|
968 (interactive)
|
|
969 (newsticker--buffer-hideshow 'item-old t)
|
|
970 (newsticker--buffer-hideshow 'desc-old t)
|
|
971 (newsticker--buffer-redraw))
|
|
972
|
|
973 (defun newsticker-hide-new-item-desc ()
|
|
974 "Hide the description of new items."
|
|
975 (interactive)
|
|
976 (newsticker--buffer-hideshow 'desc-new nil)
|
|
977 (newsticker--buffer-hideshow 'desc-immortal nil)
|
|
978 (newsticker--buffer-hideshow 'desc-obsolete nil)
|
|
979 (newsticker--buffer-redraw))
|
|
980
|
|
981 (defun newsticker-show-new-item-desc ()
|
|
982 "Show the description of new items."
|
|
983 (interactive)
|
|
984 (newsticker--buffer-hideshow 'desc-new t)
|
|
985 (newsticker--buffer-hideshow 'desc-immortal t)
|
|
986 (newsticker--buffer-hideshow 'desc-obsolete t)
|
|
987 (newsticker--buffer-redraw))
|
|
988
|
|
989 (defun newsticker-hide-feed-desc ()
|
|
990 "Hide the description of feeds."
|
|
991 (interactive)
|
|
992 (newsticker--buffer-hideshow 'desc-feed nil)
|
|
993 (newsticker--buffer-redraw))
|
|
994
|
|
995 (defun newsticker-show-feed-desc ()
|
|
996 "Show the description of old items."
|
|
997 (interactive)
|
|
998 (newsticker--buffer-hideshow 'desc-feed t)
|
|
999 (newsticker--buffer-redraw))
|
|
1000
|
|
1001 (defun newsticker-hide-all-desc ()
|
|
1002 "Hide the descriptions of feeds and all items."
|
|
1003 (interactive)
|
|
1004 (newsticker--buffer-hideshow 'desc-feed nil)
|
|
1005 (newsticker--buffer-hideshow 'desc-immortal nil)
|
|
1006 (newsticker--buffer-hideshow 'desc-obsolete nil)
|
|
1007 (newsticker--buffer-hideshow 'desc-new nil)
|
|
1008 (newsticker--buffer-hideshow 'desc-old nil)
|
|
1009 (newsticker--buffer-redraw))
|
|
1010
|
|
1011 (defun newsticker-show-all-desc ()
|
|
1012 "Show the descriptions of feeds and all items."
|
|
1013 (interactive)
|
|
1014 (newsticker--buffer-hideshow 'desc-feed t)
|
|
1015 (newsticker--buffer-hideshow 'desc-immortal t)
|
|
1016 (newsticker--buffer-hideshow 'desc-obsolete t)
|
|
1017 (newsticker--buffer-hideshow 'desc-new t)
|
|
1018 (newsticker--buffer-hideshow 'desc-old t)
|
|
1019 (newsticker--buffer-redraw))
|
|
1020
|
|
1021 (defun newsticker-hide-old-items ()
|
|
1022 "Hide old items."
|
|
1023 (interactive)
|
|
1024 (newsticker--buffer-hideshow 'desc-old nil)
|
|
1025 (newsticker--buffer-hideshow 'item-old nil)
|
|
1026 (newsticker--buffer-redraw))
|
|
1027
|
|
1028 (defun newsticker-show-old-items ()
|
|
1029 "Show old items."
|
|
1030 (interactive)
|
|
1031 (newsticker--buffer-hideshow 'item-old t)
|
|
1032 (newsticker--buffer-redraw))
|
|
1033
|
|
1034 (defun newsticker-hide-entry ()
|
|
1035 "Hide description of entry at point."
|
|
1036 (interactive)
|
|
1037 (save-excursion
|
|
1038 (let* (pos1 pos2
|
|
1039 (inhibit-read-only t)
|
|
1040 inv-prop org-inv-prop
|
|
1041 is-invisible)
|
|
1042 (newsticker--buffer-beginning-of-item)
|
|
1043 (newsticker--buffer-goto '(desc))
|
|
1044 (setq pos1 (max (point-min) (1- (point))))
|
|
1045 (newsticker--buffer-goto '(extra feed item nil))
|
|
1046 (setq pos2 (max (point-min) (1- (point))))
|
|
1047 (setq inv-prop (get-text-property pos1 'invisible))
|
|
1048 (setq org-inv-prop (get-text-property pos1 'org-invisible))
|
|
1049 (cond ((eq inv-prop t)
|
|
1050 ;; do nothing
|
|
1051 )
|
|
1052 ((eq org-inv-prop nil)
|
|
1053 (add-text-properties pos1 pos2
|
|
1054 (list 'invisible (list t)
|
|
1055 'org-invisible inv-prop)))
|
|
1056 (t
|
|
1057 ;; toggle
|
|
1058 (add-text-properties pos1 pos2
|
|
1059 (list 'invisible org-inv-prop))
|
|
1060 (remove-text-properties pos1 pos2 '(org-invisible))))))
|
|
1061 (newsticker--buffer-redraw))
|
|
1062
|
|
1063 (defun newsticker-show-entry ()
|
|
1064 "Show description of entry at point."
|
|
1065 (interactive)
|
|
1066 (save-excursion
|
|
1067 (let* (pos1 pos2
|
|
1068 (inhibit-read-only t)
|
|
1069 inv-prop org-inv-prop
|
|
1070 is-invisible)
|
|
1071 (newsticker--buffer-beginning-of-item)
|
|
1072 (newsticker--buffer-goto '(desc))
|
|
1073 (setq pos1 (max (point-min) (1- (point))))
|
|
1074 (newsticker--buffer-goto '(extra feed item))
|
|
1075 (setq pos2 (max (point-min) (1- (point))))
|
|
1076 (setq inv-prop (get-text-property pos1 'invisible))
|
|
1077 (setq org-inv-prop (get-text-property pos1 'org-invisible))
|
|
1078 (cond ((eq org-inv-prop nil)
|
|
1079 (add-text-properties pos1 pos2
|
|
1080 (list 'invisible nil
|
|
1081 'org-invisible inv-prop)))
|
|
1082 (t
|
|
1083 ;; toggle
|
|
1084 (add-text-properties pos1 pos2
|
|
1085 (list 'invisible org-inv-prop))
|
|
1086 (remove-text-properties pos1 pos2 '(org-invisible))))))
|
|
1087 (newsticker--buffer-redraw))
|
|
1088
|
|
1089 (defun newsticker-toggle-auto-narrow-to-feed ()
|
|
1090 "Toggle narrowing to current news feed.
|
|
1091 If auto-narrowing is active, only news item of the current feed
|
|
1092 are visible."
|
|
1093 (interactive)
|
|
1094 (newsticker-set-auto-narrow-to-feed
|
|
1095 (not newsticker--auto-narrow-to-feed)))
|
|
1096
|
|
1097 (defun newsticker-set-auto-narrow-to-feed (value)
|
|
1098 "Turn narrowing to current news feed on or off.
|
|
1099 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
|
|
1100 (interactive)
|
|
1101 (setq newsticker--auto-narrow-to-item nil)
|
|
1102 (setq newsticker--auto-narrow-to-feed value)
|
|
1103 (widen)
|
|
1104 (newsticker--buffer-make-item-completely-visible)
|
|
1105 (run-hooks 'newsticker-narrow-hook))
|
|
1106
|
|
1107 (defun newsticker-toggle-auto-narrow-to-item ()
|
|
1108 "Toggle narrowing to current news item.
|
|
1109 If auto-narrowing is active, only one item of the current feed
|
|
1110 is visible."
|
|
1111 (interactive)
|
|
1112 (newsticker-set-auto-narrow-to-item
|
|
1113 (not newsticker--auto-narrow-to-item)))
|
|
1114
|
|
1115 (defun newsticker-set-auto-narrow-to-item (value)
|
|
1116 "Turn narrowing to current news item on or off.
|
|
1117 If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
|
|
1118 (interactive)
|
|
1119 (setq newsticker--auto-narrow-to-feed nil)
|
|
1120 (setq newsticker--auto-narrow-to-item value)
|
|
1121 (widen)
|
|
1122 (newsticker--buffer-make-item-completely-visible)
|
|
1123 (run-hooks 'newsticker-narrow-hook))
|
|
1124
|
|
1125 (defun newsticker-next-feed-available-p ()
|
|
1126 "Return t if position is before last feed, nil otherwise."
|
|
1127 (save-excursion
|
|
1128 (let ((p (point)))
|
|
1129 (newsticker--buffer-goto '(feed))
|
|
1130 (not (= p (point))))))
|
|
1131
|
|
1132 (defun newsticker-previous-feed-available-p ()
|
|
1133 "Return t if position is behind first feed, nil otherwise."
|
|
1134 (save-excursion
|
|
1135 (let ((p (point)))
|
|
1136 (newsticker--buffer-goto '(feed) nil t)
|
|
1137 (not (= p (point))))))
|
|
1138
|
|
1139 (defun newsticker-next-item-available-p ()
|
|
1140 "Return t if position is before last feed, nil otherwise."
|
|
1141 (save-excursion
|
|
1142 (catch 'result
|
|
1143 (while (< (point) (point-max))
|
|
1144 (unless (newsticker--buffer-goto '(item))
|
|
1145 (throw 'result nil))
|
|
1146 (unless (newsticker--lists-intersect-p
|
|
1147 (get-text-property (point) 'invisible)
|
|
1148 buffer-invisibility-spec)
|
|
1149 (throw 'result t))))))
|
|
1150
|
|
1151 (defun newsticker-previous-item-available-p ()
|
|
1152 "Return t if position is behind first item, nil otherwise."
|
|
1153 (save-excursion
|
|
1154 (catch 'result
|
|
1155 (while (> (point) (point-min))
|
|
1156 (unless (newsticker--buffer-goto '(item) nil t)
|
|
1157 (throw 'result nil))
|
|
1158 (unless (newsticker--lists-intersect-p
|
|
1159 (get-text-property (point) 'invisible)
|
|
1160 buffer-invisibility-spec)
|
|
1161 (throw 'result t))))))
|
|
1162
|
|
1163 (defun newsticker-item-not-old-p ()
|
|
1164 "Return t if there is an item at point which is not old, nil otherwise."
|
|
1165 (when (get-text-property (point) 'feed)
|
|
1166 (save-excursion
|
|
1167 (newsticker--buffer-beginning-of-item)
|
|
1168 (let ((age (get-text-property (point) 'nt-age)))
|
|
1169 (and (memq age '(new immortal obsolete)) t)))))
|
|
1170
|
|
1171 (defun newsticker-item-not-immortal-p ()
|
|
1172 "Return t if there is an item at point which is not immortal, nil otherwise."
|
|
1173 (when (get-text-property (point) 'feed)
|
|
1174 (save-excursion
|
|
1175 (newsticker--buffer-beginning-of-item)
|
|
1176 (let ((age (get-text-property (point) 'nt-age)))
|
|
1177 (and (memq age '(new old obsolete)) t)))))
|
|
1178
|
|
1179 ;; ======================================================================
|
|
1180 ;;; Imenu stuff
|
|
1181 ;; ======================================================================
|
|
1182 (defun newsticker--imenu-create-index ()
|
|
1183 "Scan newsticker buffer and return an index for imenu."
|
|
1184 (save-excursion
|
|
1185 (goto-char (point-min))
|
|
1186 (let ((index-alist nil)
|
|
1187 (feed-list nil)
|
|
1188 (go-ahead t))
|
|
1189 (while go-ahead
|
|
1190 (let ((type (get-text-property (point) 'nt-type))
|
|
1191 (title (get-text-property (point) 'nt-title)))
|
|
1192 (cond ((eq type 'feed)
|
|
1193 ;; we're on a feed heading
|
|
1194 (when feed-list
|
|
1195 (if index-alist
|
|
1196 (nconc index-alist (list feed-list))
|
|
1197 (setq index-alist (list feed-list))))
|
|
1198 (setq feed-list (list title)))
|
|
1199 (t
|
|
1200 (nconc feed-list
|
|
1201 (list (cons title (point)))))))
|
|
1202 (setq go-ahead (newsticker--buffer-goto '(item feed))))
|
|
1203 (if index-alist
|
|
1204 (nconc index-alist (list feed-list))
|
|
1205 (setq index-alist (list feed-list)))
|
|
1206 index-alist)))
|
|
1207
|
|
1208 (defun newsticker--imenu-goto (name pos &rest args)
|
|
1209 "Go to item NAME at position POS and show item.
|
|
1210 ARGS are ignored."
|
|
1211 (goto-char pos)
|
|
1212 ;; show headline
|
|
1213 (newsticker--buffer-goto '(desc extra feed item))
|
|
1214 (let* ((inhibit-read-only t)
|
|
1215 (pos1 (max (point-min) (1- pos)))
|
|
1216 (pos2 (max pos1 (1- (point))))
|
|
1217 (inv-prop (get-text-property pos 'invisible))
|
|
1218 (org-inv-prop (get-text-property pos 'org-invisible)))
|
|
1219 (when (eq org-inv-prop nil)
|
|
1220 (add-text-properties pos1 pos2 (list 'invisible nil
|
|
1221 'org-invisible inv-prop))))
|
|
1222 ;; show desc
|
|
1223 (newsticker-show-entry))
|
|
1224
|
|
1225 ;; ======================================================================
|
|
1226 ;;; Buffer stuff
|
|
1227 ;; ======================================================================
|
|
1228 (defun newsticker--buffer-set-uptodate (value)
|
|
1229 "Set the uptodate-status of the newsticker buffer to VALUE.
|
|
1230 The mode-line is changed accordingly."
|
|
1231 (setq newsticker--buffer-uptodate-p value)
|
|
1232 (let ((b (get-buffer "*newsticker*")))
|
|
1233 (when b
|
|
1234 (save-excursion
|
|
1235 (set-buffer b)
|
|
1236 (if value
|
|
1237 (setq mode-name "Newsticker -- up to date -- ")
|
|
1238 (setq mode-name "Newsticker -- NEED UPDATE -- ")))
|
|
1239 (force-mode-line-update 0))))
|
|
1240
|
|
1241 (defun newsticker--buffer-redraw ()
|
|
1242 "Redraw the newsticker window."
|
|
1243 (if (fboundp 'force-window-update)
|
|
1244 (force-window-update (current-buffer))
|
|
1245 (redraw-frame (selected-frame)))
|
|
1246 (run-hooks 'newsticker-buffer-change-hook)
|
|
1247 (sit-for 0))
|
|
1248
|
|
1249 (defun newsticker--buffer-insert-all-items ()
|
|
1250 "Insert all cached newsticker items into the current buffer.
|
|
1251 Keeps order of feeds as given in `newsticker-url-list' and
|
|
1252 `newsticker-url-list-defaults'."
|
|
1253 (goto-char (point-min))
|
|
1254 (mapc (lambda (url-item)
|
|
1255 (let* ((feed-name (car url-item))
|
|
1256 (feed-name-symbol (intern feed-name))
|
|
1257 (feed (assoc feed-name-symbol newsticker--cache))
|
|
1258 (items (cdr feed))
|
|
1259 (pos (point)))
|
|
1260 (when feed
|
|
1261 ;; insert the feed description
|
|
1262 (mapc (lambda (item)
|
|
1263 (when (eq (newsticker--age item) 'feed)
|
|
1264 (newsticker--buffer-insert-item item
|
|
1265 feed-name-symbol)))
|
|
1266 items)
|
|
1267 ;;insert the items
|
|
1268 (mapc (lambda (item)
|
|
1269 (if (memq (newsticker--age item) '(new immortal old
|
|
1270 obsolete))
|
|
1271 (newsticker--buffer-insert-item item
|
|
1272 feed-name-symbol)))
|
|
1273 items)
|
|
1274 (put-text-property pos (point) 'feed (car feed))
|
|
1275
|
|
1276 ;; insert empty line between feeds
|
|
1277 (let ((p (point)))
|
|
1278 (insert "\n")
|
|
1279 (put-text-property p (point) 'hard t)))))
|
|
1280 (append newsticker-url-list newsticker-url-list-defaults))
|
|
1281
|
|
1282 (newsticker--buffer-set-faces (point-min) (point-max))
|
|
1283 (newsticker--buffer-set-invisibility (point-min) (point-max))
|
|
1284 (goto-char (point-min)))
|
|
1285
|
|
1286 (defun newsticker--buffer-insert-item (item &optional feed-name-symbol)
|
|
1287 "Insert a news item in the current buffer.
|
|
1288 Insert a formatted representation of the ITEM. The optional parameter
|
|
1289 FEED-NAME-SYMBOL determines how the item is formatted and whether the
|
|
1290 item-retrieval time is added as well."
|
|
1291 ;; insert headline
|
|
1292 (if (eq (newsticker--age item) 'feed)
|
|
1293 (newsticker--buffer-do-insert-text item 'feed feed-name-symbol)
|
|
1294 (newsticker--buffer-do-insert-text item 'item feed-name-symbol))
|
|
1295 ;; insert the description
|
|
1296 (newsticker--buffer-do-insert-text item 'desc feed-name-symbol))
|
|
1297
|
|
1298 (defun newsticker--buffer-do-insert-text (item type feed-name-symbol)
|
|
1299 "Actually insert contents of news item, format it, render it and all that.
|
|
1300 ITEM is a news item, TYPE tells which part of the item shall be inserted,
|
|
1301 FEED-NAME-SYMBOL tells to which feed this item belongs."
|
|
1302 (let* ((pos (point))
|
|
1303 (format newsticker-desc-format)
|
|
1304 (pos-date-start nil)
|
|
1305 (pos-date-end nil)
|
|
1306 (pos-stat-start nil)
|
|
1307 (pos-stat-end nil)
|
|
1308 (pos-text-start nil)
|
|
1309 (pos-text-end nil)
|
|
1310 (pos-extra-start nil)
|
|
1311 (pos-extra-end nil)
|
|
1312 (pos-enclosure-start nil)
|
|
1313 (pos-enclosure-end nil)
|
|
1314 (age (newsticker--age item))
|
|
1315 (preformatted-contents (newsticker--preformatted-contents item))
|
|
1316 (preformatted-title (newsticker--preformatted-title item)))
|
|
1317 (cond ((and preformatted-contents
|
|
1318 (not (eq (aref preformatted-contents 0) ?\n));; we must
|
|
1319 ;; NOT have a line
|
|
1320 ;; break!
|
|
1321 (eq type 'desc))
|
|
1322 (insert preformatted-contents))
|
|
1323 ((and preformatted-title
|
|
1324 (not (eq (aref preformatted-title 0) ?\n));; we must NOT have a
|
|
1325 ;; line break!
|
|
1326 (eq type 'item))
|
|
1327 (insert preformatted-title))
|
|
1328 (t
|
|
1329 ;; item was not formatted before.
|
|
1330 ;; Let's go.
|
|
1331 (if (eq type 'item)
|
|
1332 (setq format newsticker-item-format)
|
|
1333 (if (eq type 'feed)
|
|
1334 (setq format newsticker-heading-format)))
|
|
1335
|
|
1336 (while (> (length format) 0)
|
|
1337 (let ((prefix (if (> (length format) 1)
|
|
1338 (substring format 0 2)
|
|
1339 "")))
|
|
1340 (cond ((string= "%c" prefix)
|
|
1341 ;; contents
|
|
1342 (when (newsticker--desc item)
|
|
1343 (setq pos-text-start (point-marker))
|
|
1344 (insert (newsticker--desc item))
|
|
1345 (setq pos-text-end (point-marker)))
|
|
1346 (setq format (substring format 2)))
|
|
1347 ((string= "%d" prefix)
|
|
1348 ;; date
|
|
1349 (setq pos-date-start (point-marker))
|
|
1350 (if (newsticker--time item)
|
|
1351 (insert (format-time-string newsticker-date-format
|
|
1352 (newsticker--time item))))
|
|
1353 (setq pos-date-end (point-marker))
|
|
1354 (setq format (substring format 2)))
|
|
1355 ((string= "%l" prefix)
|
|
1356 ;; logo
|
|
1357 (let ((disabled (cond ((eq (newsticker--age item) 'feed)
|
|
1358 (= (newsticker--stat-num-items
|
|
1359 feed-name-symbol 'new) 0))
|
|
1360 (t
|
|
1361 (not (eq (newsticker--age item)
|
|
1362 'new))))))
|
|
1363 (let ((img (newsticker--image-read feed-name-symbol
|
|
1364 disabled)))
|
|
1365 (when img
|
|
1366 (newsticker--insert-image img (car item)))))
|
|
1367 (setq format (substring format 2)))
|
|
1368 ((string= "%L" prefix)
|
|
1369 ;; logo or title
|
|
1370 (let ((disabled (cond ((eq (newsticker--age item) 'feed)
|
|
1371 (= (newsticker--stat-num-items
|
|
1372 feed-name-symbol 'new) 0))
|
|
1373 (t
|
|
1374 (not (eq (newsticker--age item)
|
|
1375 'new))))))
|
|
1376 (let ((img (newsticker--image-read feed-name-symbol
|
|
1377 disabled)))
|
|
1378 (if img
|
|
1379 (newsticker--insert-image img (car item))
|
|
1380 (when (car item)
|
|
1381 (setq pos-text-start (point-marker))
|
|
1382 (if (eq (newsticker--age item) 'feed)
|
|
1383 (insert (newsticker--title item))
|
|
1384 ;; FIXME: This is not the "real" title!
|
|
1385 (insert (format "%s"
|
|
1386 (car (newsticker--cache-get-feed
|
|
1387 feed-name-symbol)))))
|
|
1388 (setq pos-text-end (point-marker))))))
|
|
1389 (setq format (substring format 2)))
|
|
1390 ((string= "%s" prefix)
|
|
1391 ;; statistics
|
|
1392 (setq pos-stat-start (point-marker))
|
|
1393 (if (eq (newsticker--age item) 'feed)
|
|
1394 (insert (newsticker--buffer-statistics
|
|
1395 feed-name-symbol)))
|
|
1396 (setq pos-stat-end (point-marker))
|
|
1397 (setq format (substring format 2)))
|
|
1398 ((string= "%t" prefix)
|
|
1399 ;; title
|
|
1400 (when (car item)
|
|
1401 (setq pos-text-start (point-marker))
|
|
1402 (insert (car item))
|
|
1403 (setq pos-text-end (point-marker)))
|
|
1404 (setq format (substring format 2)))
|
|
1405 ((string-match "%." prefix)
|
|
1406 ;; unknown specifier!
|
|
1407 (insert prefix)
|
|
1408 (setq format (substring format 2)))
|
|
1409 ((string-match "^\\([^%]*\\)\\(.*\\)" format) ;; FIXME!
|
|
1410 ;; everything else
|
|
1411 (let ((p (point)))
|
|
1412 (insert (substring format
|
|
1413 (match-beginning 1) (match-end 1)))
|
|
1414 ;; in case that the format string contained newlines
|
|
1415 (put-text-property p (point) 'hard t))
|
|
1416 (setq format (substring format (match-beginning 2)))))))
|
|
1417
|
|
1418 ;; decode HTML if possible...
|
|
1419 (let ((is-rendered-HTML nil))
|
|
1420 (when (and newsticker-html-renderer pos-text-start pos-text-end)
|
|
1421 (condition-case error-data
|
|
1422 (save-excursion
|
|
1423 ;; check whether it is necessary to call html renderer
|
|
1424 ;; (regexp inspired by htmlr.el)
|
|
1425 (goto-char pos-text-start)
|
|
1426 (when (re-search-forward
|
|
1427 "</?[A-Za-z1-6]*\\|&#?[A-Za-z0-9]+;" pos-text-end t)
|
|
1428 ;; (message "%s" (newsticker--title item))
|
|
1429 (let ((w3m-fill-column (if newsticker-use-full-width
|
|
1430 -1 fill-column))
|
|
1431 (w3-maximum-line-length
|
|
1432 (if newsticker-use-full-width nil fill-column)))
|
|
1433 (save-excursion
|
|
1434 (funcall newsticker-html-renderer pos-text-start
|
|
1435 pos-text-end)))
|
|
1436 (cond ((eq newsticker-html-renderer 'w3m-region)
|
|
1437 (add-text-properties pos (point-max)
|
|
1438 (list 'keymap
|
|
1439 w3m-minor-mode-map)))
|
|
1440 ((eq newsticker-html-renderer 'w3-region)
|
|
1441 (add-text-properties pos (point-max)
|
|
1442 (list 'keymap w3-mode-map))))
|
|
1443 (setq is-rendered-HTML t)))
|
|
1444 (error
|
|
1445 (message "Error: HTML rendering failed: %s, %s"
|
|
1446 (car error-data) (cdr error-data)))))
|
|
1447 ;; After html rendering there might be chunks of blank
|
|
1448 ;; characters between rendered text and date, statistics or
|
|
1449 ;; whatever. Remove it
|
|
1450 (when (and (eq type 'item) is-rendered-HTML)
|
|
1451 (goto-char pos)
|
|
1452 (while (re-search-forward "[ \t]*\n[ \t]*" nil t)
|
|
1453 (replace-match " " nil nil))
|
|
1454 (goto-char (point-max)))
|
|
1455 (when (and newsticker-justification
|
|
1456 (memq type '(item desc))
|
|
1457 (not is-rendered-HTML))
|
|
1458 (condition-case nil
|
|
1459 (let ((use-hard-newlines t))
|
|
1460 (fill-region pos (point-max) newsticker-justification))
|
|
1461 (error nil))))
|
|
1462
|
|
1463 ;; remove leading and trailing newlines
|
|
1464 (goto-char pos)
|
|
1465 (unless (= 0 (skip-chars-forward " \t\r\n"))
|
|
1466 (delete-region pos (point)))
|
|
1467 (goto-char (point-max))
|
|
1468 (let ((end (point)))
|
|
1469 (unless (= 0 (skip-chars-backward " \t\r\n" (1+ pos)))
|
|
1470 (delete-region (point) end)))
|
|
1471 (goto-char (point-max))
|
|
1472 ;; closing newline
|
|
1473 (unless nil ;;(eq pos (point))
|
|
1474 (insert "\n")
|
|
1475 (put-text-property (1- (point)) (point) 'hard t))
|
|
1476
|
|
1477 ;; insert enclosure element
|
|
1478 (when (eq type 'desc)
|
|
1479 (setq pos-enclosure-start (point))
|
|
1480 (newsticker--insert-enclosure item newsticker--url-keymap)
|
|
1481 (setq pos-enclosure-end (point)))
|
|
1482
|
|
1483 ;; show extra elements
|
|
1484 (when (eq type 'desc)
|
|
1485 (goto-char (point-max))
|
|
1486 (setq pos-extra-start (point))
|
|
1487 (newsticker--print-extra-elements item newsticker--url-keymap)
|
|
1488 (setq pos-extra-end (point)))
|
|
1489
|
|
1490 ;; text properties
|
|
1491 (when (memq type '(feed item))
|
|
1492 (add-text-properties pos (1- (point))
|
|
1493 (list 'mouse-face 'highlight
|
|
1494 'nt-link (newsticker--link item)
|
|
1495 'help-echo
|
|
1496 (format "mouse-2: visit item (%s)"
|
|
1497 (newsticker--link item))
|
|
1498 'keymap newsticker--url-keymap))
|
|
1499 (add-text-properties pos (point)
|
|
1500 (list 'nt-title (newsticker--title item)
|
|
1501 'nt-desc (newsticker--desc item))))
|
|
1502
|
|
1503 (add-text-properties pos (point)
|
|
1504 (list 'nt-type type
|
|
1505 'nt-face type
|
|
1506 'nt-age age
|
|
1507 'nt-guid (newsticker--guid item)))
|
|
1508 (when (and pos-date-start pos-date-end)
|
|
1509 (put-text-property pos-date-start pos-date-end 'nt-face 'date))
|
|
1510 (when (and pos-stat-start pos-stat-end)
|
|
1511 (put-text-property pos-stat-start pos-stat-end 'nt-face 'stat))
|
|
1512 (when (and pos-extra-start pos-extra-end)
|
|
1513 (put-text-property pos-extra-start pos-extra-end
|
|
1514 'nt-face 'extra)
|
|
1515 (put-text-property pos-extra-start pos-extra-end
|
|
1516 'nt-type 'extra))
|
|
1517 (when (and pos-enclosure-start pos-enclosure-end
|
|
1518 (> pos-enclosure-end pos-enclosure-start))
|
|
1519 (put-text-property pos-enclosure-start (1- pos-enclosure-end)
|
|
1520 'nt-face 'enclosure))
|
|
1521
|
|
1522 ;; left margin
|
|
1523 ;;(unless (memq type '(feed item))
|
|
1524 ;;(set-left-margin pos (1- (point)) 1))
|
|
1525
|
|
1526 ;; save rendered stuff
|
|
1527 (cond ((eq type 'desc)
|
|
1528 ;; preformatted contents
|
|
1529 (newsticker--cache-set-preformatted-contents
|
|
1530 item (buffer-substring pos (point))))
|
|
1531 ((eq type 'item)
|
|
1532 ;; preformatted title
|
|
1533 (newsticker--cache-set-preformatted-title
|
|
1534 item (buffer-substring pos (point)))))))))
|
|
1535
|
|
1536 (defun newsticker--buffer-statistics (feed-name-symbol)
|
|
1537 "Return a statistic string for the feed given by FEED-NAME-SYMBOL.
|
|
1538 See `newsticker-statistics-format'."
|
|
1539 (let ((case-fold-search nil))
|
|
1540 (replace-regexp-in-string
|
|
1541 "%a"
|
|
1542 (format "%d" (newsticker--stat-num-items feed-name-symbol))
|
|
1543 (replace-regexp-in-string
|
|
1544 "%i"
|
|
1545 (format "%d" (newsticker--stat-num-items feed-name-symbol 'immortal))
|
|
1546 (replace-regexp-in-string
|
|
1547 "%n"
|
|
1548 (format "%d" (newsticker--stat-num-items feed-name-symbol 'new))
|
|
1549 (replace-regexp-in-string
|
|
1550 "%o"
|
|
1551 (format "%d" (newsticker--stat-num-items feed-name-symbol 'old))
|
|
1552 (replace-regexp-in-string
|
|
1553 "%O"
|
|
1554 (format "%d" (newsticker--stat-num-items feed-name-symbol 'obsolete))
|
|
1555 newsticker-statistics-format)))))))
|
|
1556
|
|
1557 (defun newsticker--buffer-set-faces (start end)
|
|
1558 "Add face properties according to mark property.
|
|
1559 Scans the buffer between START and END."
|
|
1560 (save-excursion
|
|
1561 (put-text-property start end 'face 'newsticker-default-face)
|
|
1562 (goto-char start)
|
|
1563 (let ((pos1 start)
|
|
1564 (pos2 1)
|
|
1565 (nt-face (get-text-property start 'nt-face))
|
|
1566 (nt-age (get-text-property start 'nt-age)))
|
|
1567 (when nt-face
|
|
1568 (setq pos2 (next-single-property-change (point) 'nt-face))
|
|
1569 (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
|
|
1570 (setq nt-face (get-text-property pos2 'nt-face))
|
|
1571 (setq pos1 pos2))
|
|
1572 (while (and (setq pos2 (next-single-property-change pos1 'nt-face))
|
|
1573 (<= pos2 end)
|
|
1574 (> pos2 pos1))
|
|
1575 (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
|
|
1576 (setq nt-face (get-text-property pos2 'nt-face))
|
|
1577 (setq nt-age (get-text-property pos2 'nt-age))
|
|
1578 (setq pos1 pos2)))))
|
|
1579
|
|
1580 (defun newsticker--buffer-set-invisibility (start end)
|
|
1581 "Add invisibility properties according to nt-type property.
|
|
1582 Scans the buffer between START and END. Sets the 'invisible
|
|
1583 property to '(<nt-type>-<nt-age> <nt-type> <nt-age>)."
|
|
1584 (save-excursion
|
|
1585 ;; reset invisibility settings
|
|
1586 (put-text-property start end 'invisible nil)
|
|
1587 ;; let's go
|
|
1588 (goto-char start)
|
|
1589 (let ((pos1 start)
|
|
1590 (pos2 1)
|
|
1591 (nt-type (get-text-property start 'nt-type))
|
|
1592 (nt-age (get-text-property start 'nt-age)))
|
|
1593 (when nt-type
|
|
1594 (setq pos2 (next-single-property-change (point) 'nt-type))
|
|
1595 (put-text-property (max (point-min) pos1) (1- pos2)
|
|
1596 'invisible
|
|
1597 (list (intern
|
|
1598 (concat
|
|
1599 (symbol-name
|
|
1600 (if (eq nt-type 'extra) 'desc nt-type))
|
|
1601 "-"
|
|
1602 (symbol-name nt-age)))
|
|
1603 nt-type
|
|
1604 nt-age))
|
|
1605 (setq nt-type (get-text-property pos2 'nt-type))
|
|
1606 (setq pos1 pos2))
|
|
1607 (while (and (setq pos2 (next-single-property-change pos1 'nt-type))
|
|
1608 (<= pos2 end)
|
|
1609 (> pos2 pos1))
|
|
1610 ;; must shift one char to the left in order to handle inivisible
|
|
1611 ;; newlines, motion in invisible text areas and all that correctly
|
|
1612 (put-text-property (1- pos1) (1- pos2)
|
|
1613 'invisible
|
|
1614 (list (intern
|
|
1615 (concat
|
|
1616 (symbol-name
|
|
1617 (if (eq nt-type 'extra) 'desc nt-type))
|
|
1618 "-"
|
|
1619 (symbol-name nt-age)))
|
|
1620 nt-type
|
|
1621 nt-age))
|
|
1622 (setq nt-type (get-text-property pos2 'nt-type))
|
|
1623 (setq nt-age (get-text-property pos2 'nt-age))
|
|
1624 (setq pos1 pos2)))))
|
|
1625
|
|
1626 (defun newsticker--set-face-properties (pos1 pos2 nt-face age)
|
|
1627 "Set the face for the text between the positions POS1 and POS2.
|
|
1628 The face is chosen according the values of NT-FACE and AGE."
|
|
1629 (let ((face (cond ((eq nt-face 'feed)
|
|
1630 'newsticker-feed-face)
|
|
1631 ((eq nt-face 'item)
|
|
1632 (cond ((eq age 'new)
|
|
1633 'newsticker-new-item-face)
|
|
1634 ((eq age 'old)
|
|
1635 'newsticker-old-item-face)
|
|
1636 ((eq age 'immortal)
|
|
1637 'newsticker-immortal-item-face)
|
|
1638 ((eq age 'obsolete)
|
|
1639 'newsticker-obsolete-item-face)))
|
|
1640 ((eq nt-face 'date)
|
|
1641 'newsticker-date-face)
|
|
1642 ((eq nt-face 'stat)
|
|
1643 'newsticker-statistics-face)
|
|
1644 ((eq nt-face 'extra)
|
|
1645 'newsticker-extra-face)
|
|
1646 ((eq nt-face 'enclosure)
|
|
1647 'newsticker-enclosure-face))))
|
|
1648 (when face
|
|
1649 (put-text-property pos1 (max pos1 pos2) 'face face))))
|
|
1650
|
|
1651 ;; ======================================================================
|
|
1652 ;;; Functions working on the *newsticker* buffer
|
|
1653 ;; ======================================================================
|
|
1654 (defun newsticker--buffer-make-item-completely-visible ()
|
|
1655 "Scroll buffer until current item is completely visible."
|
|
1656 (when newsticker--auto-narrow-to-feed
|
|
1657 (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-feed))
|
|
1658 (point-min)))
|
|
1659 (max (or (save-excursion (newsticker--buffer-end-of-feed))
|
|
1660 (point-max))))
|
|
1661 (narrow-to-region min max)))
|
|
1662 (when newsticker--auto-narrow-to-item
|
|
1663 (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-item))
|
|
1664 (point-min)))
|
|
1665 (max (or (save-excursion (newsticker--buffer-end-of-item))
|
|
1666 (point-max))))
|
|
1667 (narrow-to-region min max)))
|
|
1668 (sit-for 0)
|
|
1669 ;; do not count lines and stuff because that does not work when images
|
|
1670 ;; are displayed. Do it the simple way:
|
|
1671 (save-excursion
|
|
1672 (newsticker--buffer-end-of-item)
|
|
1673 (unless (pos-visible-in-window-p)
|
|
1674 (recenter -1)))
|
|
1675 (unless (pos-visible-in-window-p)
|
|
1676 (recenter 0)))
|
|
1677
|
|
1678 (defun newsticker--buffer-get-feed-title-at-point ()
|
|
1679 "Return feed symbol of headline at point."
|
|
1680 (format "%s" (or (get-text-property (point) 'feed) " ")))
|
|
1681
|
|
1682 (defun newsticker--buffer-get-item-title-at-point ()
|
|
1683 "Return feed symbol of headline at point."
|
|
1684 (format "%s" (or (get-text-property (point) 'nt-title) " ")))
|
|
1685
|
|
1686 (defun newsticker--buffer-goto (types &optional age backwards)
|
|
1687 "Search next occurrence of TYPES in current buffer.
|
|
1688 TYPES is a list of symbols. If TYPES is found point is moved, if
|
|
1689 not point is left unchanged. If optional parameter AGE is not
|
|
1690 nil, the type AND the age must match. If BACKWARDS is t, search
|
|
1691 backwards."
|
|
1692 (let ((pos (save-excursion
|
|
1693 (save-restriction
|
|
1694 (widen)
|
|
1695 (catch 'found
|
|
1696 (let ((tpos (point)))
|
|
1697 (while (setq tpos
|
|
1698 (if backwards
|
|
1699 (if (eq tpos (point-min))
|
|
1700 nil
|
|
1701 (or (previous-single-property-change
|
|
1702 tpos 'nt-type)
|
|
1703 (point-min)))
|
|
1704 (next-single-property-change
|
|
1705 tpos 'nt-type)))
|
|
1706 (and (memq (get-text-property tpos 'nt-type) types)
|
|
1707 (or (not age)
|
|
1708 (eq (get-text-property tpos 'nt-age) age))
|
|
1709 (throw 'found tpos)))))))))
|
|
1710 (when pos
|
|
1711 (goto-char pos))
|
|
1712 pos))
|
|
1713
|
|
1714 (defun newsticker--buffer-hideshow (mark-age onoff)
|
|
1715 "Hide or show items of type MARK-AGE.
|
|
1716 If ONOFF is nil the item is hidden, otherwise it is shown."
|
|
1717 (if onoff
|
|
1718 (remove-from-invisibility-spec mark-age)
|
|
1719 (add-to-invisibility-spec mark-age)))
|
|
1720
|
|
1721 (defun newsticker--buffer-beginning-of-item ()
|
|
1722 "Move point to the beginning of the item at point.
|
|
1723 Return new position."
|
|
1724 (if (bobp)
|
|
1725 (point)
|
|
1726 (let ((type (get-text-property (point) 'nt-type))
|
|
1727 (typebefore (get-text-property (1- (point)) 'nt-type)))
|
|
1728 (if (and (memq type '(item feed))
|
|
1729 (not (eq type typebefore)))
|
|
1730 (point)
|
|
1731 (newsticker--buffer-goto '(item feed) nil t)
|
|
1732 (point)))))
|
|
1733
|
|
1734 (defun newsticker--buffer-beginning-of-feed ()
|
|
1735 "Move point to the beginning of the feed at point.
|
|
1736 Return new position."
|
|
1737 (if (bobp)
|
|
1738 (point)
|
|
1739 (let ((type (get-text-property (point) 'nt-type))
|
|
1740 (typebefore (get-text-property (1- (point)) 'nt-type)))
|
|
1741 (if (and (memq type '(feed))
|
|
1742 (not (eq type typebefore)))
|
|
1743 (point)
|
|
1744 (newsticker--buffer-goto '(feed) nil t)
|
|
1745 (point)))))
|
|
1746
|
|
1747 (defun newsticker--buffer-end-of-item ()
|
|
1748 "Move point to the end of the item at point.
|
|
1749 Take care: end of item is at the end of its last line!"
|
|
1750 (when (newsticker--buffer-goto '(item feed nil))
|
|
1751 (point)))
|
|
1752
|
|
1753 (defun newsticker--buffer-end-of-feed ()
|
|
1754 "Move point to the end of the last item of the feed at point.
|
|
1755 Take care: end of item is at the end of its last line!"
|
|
1756 (when (newsticker--buffer-goto '(feed nil))
|
|
1757 (backward-char 1)
|
|
1758 (point)))
|
|
1759
|
|
1760 ;; ======================================================================
|
|
1761 ;;; misc
|
|
1762 ;; ======================================================================
|
|
1763
|
|
1764 (defun newsticker-mouse-browse-url (event)
|
|
1765 "Call `browse-url' for the link of the item at which the EVENT occurred."
|
|
1766 (interactive "e")
|
|
1767 (save-excursion
|
|
1768 (switch-to-buffer (window-buffer (posn-window (event-end event))))
|
|
1769 (let ((url (get-text-property (posn-point (event-end event))
|
|
1770 'nt-link)))
|
|
1771 (when url
|
|
1772 (browse-url url)
|
|
1773 (save-excursion
|
|
1774 (goto-char (posn-point (event-end event)))
|
|
1775 (if newsticker-automatically-mark-visited-items-as-old
|
|
1776 (newsticker-mark-item-at-point-as-read t)))))))
|
|
1777
|
|
1778 (defun newsticker-browse-url ()
|
|
1779 "Call `browse-url' for the link of the item at point."
|
|
1780 (interactive)
|
|
1781 (let ((url (get-text-property (point) 'nt-link)))
|
|
1782 (when url
|
|
1783 (browse-url url)
|
|
1784 (if newsticker-automatically-mark-visited-items-as-old
|
|
1785 (newsticker-mark-item-at-point-as-read t)))))
|
|
1786
|
|
1787 (defvar newsticker-open-url-history
|
|
1788 '("wget" "xmms" "realplay")
|
|
1789 "...")
|
|
1790
|
|
1791 (defun newsticker-handle-url ()
|
|
1792 "Ask for a program to open the link of the item at point."
|
|
1793 (interactive)
|
|
1794 (let ((url (get-text-property (point) 'nt-link)))
|
|
1795 (when url
|
|
1796 (let ((prog (read-string "Open url with: " nil
|
|
1797 'newsticker-open-url-history)))
|
|
1798 (when prog
|
|
1799 (message "%s %s" prog url)
|
|
1800 (start-process prog prog prog url)
|
|
1801 (if newsticker-automatically-mark-visited-items-as-old
|
|
1802 (newsticker-mark-item-at-point-as-read t)))))))
|
|
1803
|
|
1804
|
|
1805 ;; ======================================================================
|
|
1806 ;;; Misc
|
|
1807 ;; ======================================================================
|
|
1808
|
|
1809 (defun newsticker--cache-sort ()
|
|
1810 "Sort the newsticker cache data."
|
|
1811 (let ((sort-fun (cond ((eq newsticker-sort-method 'sort-by-time)
|
|
1812 'newsticker--cache-item-compare-by-time)
|
|
1813 ((eq newsticker-sort-method 'sort-by-title)
|
|
1814 'newsticker--cache-item-compare-by-title)
|
|
1815 ((eq newsticker-sort-method 'sort-by-original-order)
|
|
1816 'newsticker--cache-item-compare-by-position))))
|
|
1817 (mapc (lambda (feed-list)
|
|
1818 (setcdr feed-list (sort (cdr feed-list)
|
|
1819 sort-fun)))
|
|
1820 newsticker--cache)))
|
|
1821
|
|
1822 (provide 'newsticker-plainview)
|
95684
|
1823
|
|
1824 ;; arch-tag: 4e48b683-d48b-48dd-a13e-fe45baf41184
|
95676
|
1825 ;;; newsticker-plainview.el ends here
|