1 ;;; newst-reader.el --- Generic RSS reader functions.
3 ;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 ;; Free Software Foundation, Inc.
6 ;; Author: Ulf Jasper <ulf.jasper@web.de>
7 ;; Filename: newst-reader.el
8 ;; URL: http://www.nongnu.org/newsticker
9 ;; Time-stamp: "6. Dezember 2009, 19:16:38 (ulf)"
10 ;; Package: newsticker
12 ;; ======================================================================
14 ;; This file is part of GNU Emacs.
16 ;; GNU Emacs is free software: you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation, either version 3 of the License, or
19 ;; (at your option) any later version.
21 ;; GNU Emacs is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
29 ;; ======================================================================
34 ;; ======================================================================
37 (require 'newst-backend
)
39 ;; ======================================================================
41 ;; ======================================================================
42 (defun newsticker--set-customvar-formatting (symbol value
)
43 "Set newsticker-variable SYMBOL value to VALUE.
44 Calls all actions which are necessary in order to make the new
46 (if (or (not (boundp symbol
))
47 (equal (symbol-value symbol
) value
))
49 ;; something must have changed
51 (when (fboundp 'newsticker--forget-preformatted
)
52 (newsticker--forget-preformatted))))
54 ;; ======================================================================
56 (defgroup newsticker-reader nil
57 "Settings for the feed reader."
60 (defcustom newsticker-frontend
62 "Newsticker frontend for reading news.
63 This must be one of the functions `newsticker-plainview' or
64 `newsticker-treeview'."
65 :type
'(choice :tag
"Frontend"
66 (const :tag
"Single buffer (plainview)" newsticker-plainview
)
67 (const :tag
"Tree view (treeview)" newsticker-treeview
))
68 :group
'newsticker-reader
)
70 ;; image related things
71 (defcustom newsticker-enable-logo-manipulations
73 "If non-nil newsticker manipulates logo images.
74 This enables the following image properties: heuristic mask for all
75 logos, and laplace-conversion for images without new items."
77 :group
'newsticker-reader
)
79 (defcustom newsticker-justification
81 "How to fill item descriptions.
82 If non-nil newsticker calls `fill-region' to wrap long lines in
83 item descriptions. However, if an item description contains HTML
84 text and `newsticker-html-renderer' is non-nil, filling is not
86 :type
'(choice :tag
"Justification"
87 (const :tag
"No filling" nil
)
88 (const :tag
"Left" left
)
89 (const :tag
"Right" right
)
90 (const :tag
"Center" center
)
91 (const :tag
"Full" full
))
92 :set
'newsticker--set-customvar-formatting
93 :group
'newsticker-reader
)
95 (defcustom newsticker-use-full-width
97 "Decides whether to use the full window width when filling.
98 If non-nil newsticker sets `fill-column' so that the whole
99 window is used when filling. See also `newsticker-justification'."
101 :set
'newsticker--set-customvar-formatting
102 :group
'newsticker-reader
)
104 (defcustom newsticker-html-renderer
106 "Function for rendering HTML contents.
107 If non-nil, newsticker.el will call this function whenever it finds
108 HTML-like tags in item descriptions. Possible functions are, for
109 example, `w3m-region', `w3-region', and (if you have htmlr.el installed)
110 `newsticker-htmlr-render'.
112 In order to make sure that the HTML renderer is loaded when you
113 run newsticker, you should add one of the following statements to
114 your .emacs. If you use w3m,
116 (autoload 'w3m-region \"w3m\"
117 \"Render region in current buffer and replace with result.\" t)
119 (autoload 'w3m-toggle-inline-image \"w3m\"
120 \"Toggle the visibility of an image under point.\" t)
129 :type
'(choice :tag
"Function"
130 (const :tag
"None" nil
)
131 (const :tag
"w3" w3-region
)
132 (const :tag
"w3m" w3m-region
)
133 (const :tag
"htmlr" newsticker-htmlr-render
))
134 :set
'newsticker--set-customvar-formatting
135 :group
'newsticker-reader
)
137 (defcustom newsticker-date-format
139 "Format for the date part in item and feed lines.
140 See `format-time-string' for a list of valid specifiers."
142 :set
'newsticker--set-customvar-formatting
143 :group
'newsticker-reader
)
145 (defgroup newsticker-faces nil
146 "Settings for the faces of the feed reader."
147 :group
'newsticker-reader
)
149 (defface newsticker-feed-face
150 '((((class color
) (background dark
))
151 (:family
"helvetica" :bold t
:height
1.2 :foreground
"misty rose"))
152 (((class color
) (background light
))
153 (:family
"helvetica" :bold t
:height
1.2 :foreground
"black")))
154 "Face for news feeds."
155 :group
'newsticker-faces
)
157 (defface newsticker-extra-face
158 '((((class color
) (background dark
))
159 (:italic t
:foreground
"gray50" :height
0.8))
160 (((class color
) (background light
))
161 (:italic t
:foreground
"gray50" :height
0.8)))
162 "Face for newsticker dates."
163 :group
'newsticker-faces
)
165 (defface newsticker-enclosure-face
166 '((((class color
) (background dark
))
167 (:bold t
:background
"orange"))
168 (((class color
) (background light
))
169 (:bold t
:background
"orange")))
170 "Face for enclosed elements."
171 :group
'newsticker-faces
)
173 ;; ======================================================================
174 ;;; Utility functions
175 ;; ======================================================================
176 (defun newsticker--insert-enclosure (item keymap
)
177 "Insert enclosure element of a news ITEM into the current buffer.
178 KEYMAP will be applied."
179 (let ((enclosure (newsticker--enclosure item
))
182 (let ((url (cdr (assoc 'url enclosure
)))
183 (length (string-to-number (or (cdr (assoc 'length enclosure
))
185 (type (cdr (assoc 'type enclosure
))))
186 (cond ((> length
1048576)
187 (insert (format "Enclosed file (%s, %1.2f MBytes)" type
188 (/ length
1048576))))
190 (insert (format "Enclosed file (%s, %1.2f KBytes)" type
193 (insert (format "Enclosed file (%s, %1.2f Bytes)" type
196 (insert (format "Enclosed file (%s, unknown size)" type
))))
197 (add-text-properties beg
(point)
198 (list 'mouse-face
'highlight
201 "mouse-2: visit (%s)" url
)
207 (defun newsticker--print-extra-elements (item keymap
)
208 "Insert extra-elements of ITEM in a pretty form into the current buffer.
210 (let ((ignored-elements '(items link title description content
211 content
:encoded dc
:subject
212 dc
:date entry item guid pubDate
215 (left-column-width 1))
216 (mapc (lambda (extra-element)
217 (when (listp extra-element
) ;; take care of broken xml
219 (unless (memq (car extra-element
) ignored-elements
)
220 (setq left-column-width
(max left-column-width
222 (car extra-element
))))))))
223 (newsticker--extra item
))
224 (mapc (lambda (extra-element)
225 (when (listp extra-element
) ;; take care of broken xml
227 (unless (memq (car extra-element
) ignored-elements
)
228 (newsticker--do-print-extra-element extra-element
231 (newsticker--extra item
))))
233 (defun newsticker--do-print-extra-element (extra-element width keymap
)
234 "Actually print an EXTRA-ELEMENT using the given WIDTH.
236 (let ((name (symbol-name (car extra-element
))))
237 (insert (format "%s: " name
))
238 (insert (make-string (- width
(length name
)) ?
)))
239 (let (;;(attributes (cadr extra-element)) ;FIXME!!!!
240 (contents (cddr extra-element
)))
241 (cond ((listp contents
)
244 (string-match "^http://.*" i
))
246 (insert i
" ") ; avoid self-reference from the
250 (list 'mouse-face
'highlight
253 (format "mouse-2: visit (%s)" i
)
255 (insert (format "%s" i
))))
258 (insert (format "%s" contents
))))
261 (defun newsticker--image-read (feed-name-symbol disabled
)
262 "Read the cached image for FEED-NAME-SYMBOL from disk.
263 If DISABLED is non-nil the image will be converted to a disabled look
264 \(unless `newsticker-enable-logo-manipulations' is not t\).
266 (let ((image-name (concat (newsticker--images-dir)
267 (symbol-name feed-name-symbol
)))
269 (when (file-exists-p image-name
)
270 (condition-case error-data
271 (setq img
(create-image
273 :conversion
(and newsticker-enable-logo-manipulations
276 :mask
(and newsticker-enable-logo-manipulations
280 (message "Error: cannot create image for %s: %s"
281 feed-name-symbol error-data
))))
284 ;; the functions we need for retrieval and display
286 (defun newsticker-show-news ()
287 "Start reading news. You may want to bind this to a key."
289 (newsticker-start t
) ;; will start only if not running
290 (funcall newsticker-frontend
))
292 ;; ======================================================================
294 ;; ======================================================================
295 (defconst newsticker--next-item-image
296 (and (fboundp 'image-type-available-p
)
297 (image-type-available-p 'xpm
)
298 (create-image "/* XPM */
299 static char * next_xpm[] = {
369 "Image for the next item button.")
371 (defconst newsticker--previous-item-image
372 (and (fboundp 'image-type-available-p
)
373 (image-type-available-p 'xpm
)
374 (create-image "/* XPM */
375 static char * previous_xpm[] = {
442 "Image for the previous item button.")
444 (defconst newsticker--previous-feed-image
445 (and (fboundp 'image-type-available-p
)
446 (image-type-available-p 'xpm
)
447 (create-image "/* XPM */
448 static char * prev_feed_xpm[] = {
513 \" .&. .~[}>{*=-. \",
528 "Image for the previous feed button.")
530 (defconst newsticker--next-feed-image
531 (and (fboundp 'image-type-available-p
)
532 (image-type-available-p 'xpm
)
533 (create-image "/* XPM */
534 static char * next_feed_xpm[] = {
604 \" .&*=12'3~. .-. \",
619 "Image for the next feed button.")
621 (defconst newsticker--mark-read-image
622 (and (fboundp 'image-type-available-p
)
623 (image-type-available-p 'xpm
)
624 (create-image "/* XPM */
625 static char * mark_read_xpm[] = {
697 "Image for the mark read button.")
699 (defconst newsticker--mark-immortal-image
700 (and (fboundp 'image-type-available-p
)
701 (image-type-available-p 'xpm
)
702 (create-image "/* XPM */
703 static char * mark_immortal_xpm[] = {
802 \" $ @ % & * * = - + + \",
803 \" @ ; > , ' ) ' ! * - ~ @ \",
804 \" @ { > ! ] ^ / / ( ' * ; _ : \",
805 \" < _ ; [ ) / } | } / ] , 1 2 3 4 \",
806 \" 5 6 7 , ] 8 9 9 9 } ^ ! = ~ 0 a \",
807 \" b c 6 - , ] 8 9 9 9 } ^ ! % ~ 0 d 5 \",
808 \" : e _ ; * ) / 8 } } / ] , 1 2 3 f 5 \",
809 \" : g h { = i j ^ / ^ ] ! * ; k e l m \",
810 \" : f n o ; > , ' ) ' ! * - 2 0 p q r \",
811 \" : s g 0 6 ; % > * * = - ~ h t l u r \",
812 \" v u w x y k ~ z A z B o C D E F G b \",
813 \" 5 H I J e 0 h K h C c x L M N . \",
814 \" 4 O P q Q d g x g J L R H S T < \",
815 \" @ T U P F q V q M H N W X + \",
816 \" @ Y T O W G G W O X Y @ \",
817 \" 4 Z ` Y Y Y .` 4 4 \",
824 "Image for the mark immortal button.")
826 (defconst newsticker--narrow-image
827 (and (fboundp 'image-type-available-p
)
828 (image-type-available-p 'xpm
)
829 (create-image "/* XPM */
830 static char * narrow_xpm[] = {
883 \" .................. \",
884 \" .+@#$%&*=*-;>,')!. \",
885 \" .................. \",
888 \" .................. \",
889 \" .~{]^/(___:<[}|12. \",
890 \" .................. \",
893 \" .................. \",
894 \" .!3@45>666789'0ab. \",
895 \" .................. \",
898 \" .................. \",
899 \" .cccdefghhgficccc. \",
900 \" .................. \",
906 "Image for the narrow image button.")
908 (defconst newsticker--get-all-image
909 (and (fboundp 'image-type-available-p
)
910 (image-type-available-p 'xpm
)
911 (create-image "/* XPM */
912 static char * get_all_xpm[] = {
988 \" ................... \",
989 \" .+@#$%&*=*&-;>,')!. \",
990 \" ................... \",
992 \" ................... \",
993 \" .~{]^/(___:<[}|123. \",
994 \" ................... \",
996 \" ................... \",
997 \" .45678909abcdefg. \",
998 \" .h5icj7jklmeno. \",
1010 "Image for the get all image button.")
1012 (defconst newsticker--update-image
1013 (and (fboundp 'image-type-available-p
)
1014 (image-type-available-p 'xpm
)
1015 (create-image "/* XPM */
1016 static char * update_xpm[] = {
1081 "Image for the update button.")
1083 (defconst newsticker--browse-image
1084 (and (fboundp 'image-type-available-p
)
1085 (image-type-available-p 'xpm
)
1086 (create-image "/* XPM */
1087 static char * visit_xpm[] = {
1136 \" .++.%%%#&.++. \",
1137 \" .++.$%%%#*=.++. \",
1138 \" .++.-@;##$*>,.++. \",
1139 \" .++.')!&@@*=~{].++. \",
1140 \" .++.^{~>---)/(_:<.++. \",
1141 \" .++.^[,~/~'(_}|.++. \",
1142 \" .++.]_1[12^:|.++. \",
1143 \" .++.:}33:45.++. \",
1144 \" .++.<5567.++. \",
1154 "Image for the browse button.")
1156 (defun newsticker-browse-url-item (feed item
)
1157 "Convert FEED ITEM to html and call `browse-url' on result."
1159 (let ((t-file (make-temp-file "newsticker")))
1160 (with-temp-file t-file
1161 (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1162 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
1163 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
1164 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1166 (insert "<h1>" feed
": " (newsticker--title item
) "</h1>")
1167 (insert (format-time-string newsticker-date-format
1168 (newsticker--time item
)))
1170 (insert (or (newsticker--desc item
) "[No Description]"))
1171 (when (newsticker--enclosure item
)
1172 (insert "<br/><hr/><i>")
1173 (newsticker--insert-enclosure item nil
)
1175 (when (newsticker--extra item
)
1176 (insert "<br/><hr/><tt>")
1177 (newsticker--print-extra-elements item nil
)
1179 (insert "</body></html>"))
1180 (browse-url t-file
)))
1182 (provide 'newst-reader
)
1184 ;; arch-tag: c604b701-bdf1-4fc1-8d05-5fabd1939533
1185 ;;; newst-reader.el ends here