summaryrefslogtreecommitdiff
path: root/lisp/net/newst-plainview.el
diff options
context:
space:
mode:
authorUlf Jasper <ulf.jasper@web.de>2008-06-13 17:08:25 +0000
committerUlf Jasper <ulf.jasper@web.de>2008-06-13 17:08:25 +0000
commit2900b2d8f8b4979854676fe6a2f0d0700d49efcc (patch)
treefab7a3db93a452e7b4e69c7fc8dbad5dab2f90db /lisp/net/newst-plainview.el
parenta879ee6f98dfc8572450ff2f5a7c242e9467050d (diff)
downloademacs-2900b2d8f8b4979854676fe6a2f0d0700d49efcc.tar.gz
Renamed newsticker-*.el to newst-*.el.
Diffstat (limited to 'lisp/net/newst-plainview.el')
-rw-r--r--lisp/net/newst-plainview.el1830
1 files changed, 1830 insertions, 0 deletions
diff --git a/lisp/net/newst-plainview.el b/lisp/net/newst-plainview.el
new file mode 100644
index 00000000000..e47048843fa
--- /dev/null
+++ b/lisp/net/newst-plainview.el
@@ -0,0 +1,1830 @@
+;;; newst-plainview.el --- Single buffer frontend for newsticker.
+
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+;; Free Software Foundation, Inc.
+
+;; Author: Ulf Jasper <ulf.jasper@web.de>
+;; Filename: newst-plainview.el
+;; URL: http://www.nongnu.org/newsticker
+;; Time-stamp: "13. Juni 2008, 18:49:26 (ulf)"
+
+;; ======================================================================
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;; ======================================================================
+;;; Commentary:
+
+;; See newsticker.el
+
+;; ======================================================================
+;;; Code:
+
+(require 'newsticker-ticker)
+(require 'newsticker-reader)
+(require 'derived)
+(require 'xml)
+
+;; Silence warnings
+(defvar w3-mode-map)
+(defvar w3m-minor-mode-map)
+
+;; ======================================================================
+;;; Customization
+;; ======================================================================
+(defgroup newsticker-plainview nil
+ "Settings for the simple plain view reader.
+See also `newsticker-plainview-hooks'."
+ :group 'newsticker-reader)
+
+
+(defun newsticker--set-customvar-buffer (symbol value)
+ "Set newsticker-variable SYMBOL value to VALUE.
+Calls all actions which are necessary in order to make the new
+value effective."
+ (if (or (not (boundp symbol))
+ (equal (symbol-value symbol) value))
+ (set symbol value)
+ ;; something must have changed
+ (set symbol value)
+ (newsticker--buffer-set-uptodate nil)))
+
+(defun newsticker--set-customvar-sorting (symbol value)
+ "Set newsticker-variable SYMBOL value to VALUE.
+Calls all actions which are necessary in order to make the new
+value effective."
+ (if (or (not (boundp symbol))
+ (equal (symbol-value symbol) value))
+ (set symbol value)
+ ;; something must have changed
+ (set symbol value)
+ (message "Applying new sort method...")
+ (when (fboundp 'newsticker--cache-sort) (newsticker--cache-sort))
+ (when (fboundp 'newsticker--buffer-set-uptodate)
+ (newsticker--buffer-set-uptodate nil))
+ (message "Applying new sort method...done")))
+
+(defcustom newsticker-sort-method
+ 'sort-by-original-order
+ "Sort method for news items.
+The following sort methods are available:
+* `sort-by-original-order' keeps the order in which the items
+ appear in the headline file (please note that for immortal items,
+ which have been removed from the news feed, there is no original
+ order),
+* `sort-by-time' looks at the time at which an item has been seen
+ the first time. The most recent item is put at top,
+* `sort-by-title' will put the items in an alphabetical order."
+ :type '(choice
+ (const :tag "Keep original order" sort-by-original-order)
+ (const :tag "Sort by time" sort-by-time)
+ (const :tag "Sort by title" sort-by-title))
+ :set 'newsticker--set-customvar-sorting
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-heading-format
+ "%l
+%t %d %s"
+ "Format string for feed headings.
+The following printf-like specifiers can be used:
+%d The date the feed was retrieved. See `newsticker-date-format'.
+%l The logo (image) of the feed. Most news feeds provide a small
+ image as logo. Newsticker can display them, if Emacs can --
+ see `image-types' for a list of supported image types.
+%L The logo (image) of the feed. If the logo is not available
+ the title of the feed is used.
+%s The statistical data of the feed. See `newsticker-statistics-format'.
+%t The title of the feed, i.e. its name."
+ :type 'string
+ :set 'newsticker--set-customvar-formatting
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-item-format
+ "%t %d"
+ "Format string for news item headlines.
+The following printf-like specifiers can be used:
+%d The date the item was (first) retrieved. See `newsticker-date-format'.
+%l The logo (image) of the feed. Most news feeds provide a small
+ image as logo. Newsticker can display them, if Emacs can --
+ see `image-types' for a list of supported image types.
+%L The logo (image) of the feed. If the logo is not available
+ the title of the feed is used.
+%t The title of the item."
+ :type 'string
+ :set 'newsticker--set-customvar-formatting
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-desc-format
+ "%d %c"
+ "Format string for news descriptions (contents).
+The following printf-like specifiers can be used:
+%c The contents (description) of the item.
+%d The date the item was (first) retrieved. See
+ `newsticker-date-format'."
+ :type 'string
+ :set 'newsticker--set-customvar-formatting
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-statistics-format
+ "[%n + %i + %o + %O = %a]"
+ "Format for the statistics part in feed lines.
+The following printf-like specifiers can be used:
+%a The number of all items in the feed.
+%i The number of immortal items in the feed.
+%n The number of new items in the feed.
+%o The number of old items in the feed.
+%O The number of obsolete items in the feed."
+ :type 'string
+ :set 'newsticker--set-customvar-formatting
+ :group 'newsticker-plainview)
+
+
+;; ======================================================================
+;; faces
+(defgroup newsticker-faces nil
+ "Settings for the faces of the feed reader."
+ :group 'newsticker-plainview)
+
+(defface newsticker-feed-face
+ '((((class color) (background dark))
+ (:family "helvetica" :bold t :height 1.2 :foreground "misty rose"))
+ (((class color) (background light))
+ (:family "helvetica" :bold t :height 1.2 :foreground "black")))
+ "Face for news feeds."
+ :group 'newsticker-faces)
+
+(defface newsticker-new-item-face
+ '((((class color) (background dark))
+ (:family "helvetica" :bold t))
+ (((class color) (background light))
+ (:family "helvetica" :bold t)))
+ "Face for new news items."
+ :group 'newsticker-faces)
+
+(defface newsticker-old-item-face
+ '((((class color) (background dark))
+ (:family "helvetica" :bold t :foreground "orange3"))
+ (((class color) (background light))
+ (:family "helvetica" :bold t :foreground "red4")))
+ "Face for old news items."
+ :group 'newsticker-faces)
+
+(defface newsticker-immortal-item-face
+ '((((class color) (background dark))
+ (:family "helvetica" :bold t :italic t :foreground "orange"))
+ (((class color) (background light))
+ (:family "helvetica" :bold t :italic t :foreground "blue")))
+ "Face for immortal news items."
+ :group 'newsticker-faces)
+
+(defface newsticker-obsolete-item-face
+ '((((class color) (background dark))
+ (:family "helvetica" :bold t :strike-through t))
+ (((class color) (background light))
+ (:family "helvetica" :bold t :strike-through t)))
+ "Face for old news items."
+ :group 'newsticker-faces)
+
+(defface newsticker-date-face
+ '((((class color) (background dark))
+ (:family "helvetica" :italic t :height 0.8))
+ (((class color) (background light))
+ (:family "helvetica" :italic t :height 0.8)))
+ "Face for newsticker dates."
+ :group 'newsticker-faces)
+
+(defface newsticker-statistics-face
+ '((((class color) (background dark))
+ (:family "helvetica" :italic t :height 0.8))
+ (((class color) (background light))
+ (:family "helvetica" :italic t :height 0.8)))
+ "Face for newsticker dates."
+ :group 'newsticker-faces)
+
+(defface newsticker-enclosure-face
+ '((((class color) (background dark))
+ (:bold t :background "orange"))
+ (((class color) (background light))
+ (:bold t :background "orange")))
+ "Face for enclosed elements."
+ :group 'newsticker-faces)
+
+(defface newsticker-extra-face
+ '((((class color) (background dark))
+ (:italic t :foreground "gray50" :height 0.8))
+ (((class color) (background light))
+ (:italic t :foreground "gray50" :height 0.8)))
+ "Face for newsticker dates."
+ :group 'newsticker-faces)
+
+(defface newsticker-default-face
+ '((((class color) (background dark))
+ (:inherit default))
+ (((class color) (background light))
+ (:inherit default)))
+ "Face for the description of news items."
+ ;;:set 'newsticker--set-customvar
+ :group 'newsticker-faces)
+
+(defcustom newsticker-hide-old-items-in-newsticker-buffer
+ nil
+ "Decides whether to automatically hide old items in the *newsticker* buffer.
+If set to t old items will be completely folded and only new
+items will show up in the *newsticker* buffer. Otherwise old as
+well as new items will be visible."
+ :type 'boolean
+ :set 'newsticker--set-customvar-buffer
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-show-descriptions-of-new-items
+ t
+ "Whether to automatically show descriptions of new items in *newsticker*.
+If set to t old items will be folded and new items will be
+unfolded. Otherwise old as well as new items will be folded."
+ :type 'boolean
+ :set 'newsticker--set-customvar-buffer
+ :group 'newsticker-plainview)
+
+(defcustom newsticker-show-all-news-elements
+ nil
+ "Show all news elements."
+ :type 'boolean
+ ;;:set 'newsticker--set-customvar
+ :group 'newsticker-plainview)
+
+;; ======================================================================
+;; hooks
+(defgroup newsticker-plainview-hooks nil
+ "Settings for newsticker hooks which apply to plainview only."
+ :group 'newsticker-hooks)
+
+(defcustom newsticker-select-item-hook
+ 'newsticker--buffer-make-item-completely-visible
+ "List of functions run after a headline has been selected.
+Each function is called after one of `newsticker-next-item',
+`newsticker-next-new-item', `newsticker-previous-item',
+`newsticker-previous-new-item' has been called.
+
+The default value 'newsticker--buffer-make-item-completely-visible
+assures that the current item is always completely visible."
+ :type 'hook
+ :options '(newsticker--buffer-make-item-completely-visible)
+ :group 'newsticker-plainview-hooks)
+
+(defcustom newsticker-select-feed-hook
+ 'newsticker--buffer-make-item-completely-visible
+ "List of functions run after a feed has been selected.
+Each function is called after one of `newsticker-next-feed', and
+`newsticker-previous-feed' has been called.
+
+The default value 'newsticker--buffer-make-item-completely-visible
+assures that the current feed is completely visible."
+ :type 'hook
+ :options '(newsticker--buffer-make-item-completely-visible)
+ :group 'newsticker-plainview-hooks)
+
+(defcustom newsticker-buffer-change-hook
+ 'newsticker-w3m-show-inline-images
+ "List of functions run after the newsticker buffer has been updated.
+Each function is called after `newsticker-buffer-update' has been called.
+
+The default value '`newsticker-w3m-show-inline-images' loads inline
+images."
+ :type 'hook
+ :group 'newsticker-plainview-hooks)
+
+(defcustom newsticker-narrow-hook
+ 'newsticker-w3m-show-inline-images
+ "List of functions run after narrowing in newsticker buffer has changed.
+Each function is called after
+`newsticker-toggle-auto-narrow-to-feed' or
+`newsticker-toggle-auto-narrow-to-item' has been called.
+
+The default value '`newsticker-w3m-show-inline-images' loads inline
+images."
+ :type 'hook
+ :group 'newsticker-plainview-hooks)
+
+;; ======================================================================
+;;; Toolbar
+;; ======================================================================
+
+(defvar newsticker--plainview-tool-bar-map
+ (if (featurep 'xemacs)
+ nil
+ (if (boundp 'tool-bar-map)
+ (let ((tool-bar-map (make-sparse-keymap)))
+ (define-key tool-bar-map [newsticker-sep-1]
+ (list 'menu-item "--double-line"))
+ (define-key tool-bar-map [newsticker-browse-url]
+ (list 'menu-item "newsticker-browse-url" 'newsticker-browse-url
+ :visible t
+ :help "Browse URL for item at point"
+ :image newsticker--browse-image))
+ (define-key tool-bar-map [newsticker-buffer-force-update]
+ (list 'menu-item "newsticker-buffer-force-update"
+ 'newsticker-buffer-force-update
+ :visible t
+ :help "Update newsticker buffer"
+ :image newsticker--update-image
+ :enable '(not newsticker--buffer-uptodate-p)))
+ (define-key tool-bar-map [newsticker-get-all-news]
+ (list 'menu-item "newsticker-get-all-news" 'newsticker-get-all-news
+ :visible t
+ :help "Get news for all feeds"
+ :image newsticker--get-all-image))
+ (define-key tool-bar-map [newsticker-mark-item-at-point-as-read]
+ (list 'menu-item "newsticker-mark-item-at-point-as-read"
+ 'newsticker-mark-item-at-point-as-read
+ :visible t
+ :image newsticker--mark-read-image
+ :help "Mark current item as read"
+ :enable '(newsticker-item-not-old-p)))
+ (define-key tool-bar-map [newsticker-mark-item-at-point-as-immortal]
+ (list 'menu-item "newsticker-mark-item-at-point-as-immortal"
+ 'newsticker-mark-item-at-point-as-immortal
+ :visible t
+ :image newsticker--mark-immortal-image
+ :help "Mark current item as immortal"
+ :enable '(newsticker-item-not-immortal-p)))
+ (define-key tool-bar-map [newsticker-toggle-auto-narrow-to-feed]
+ (list 'menu-item "newsticker-toggle-auto-narrow-to-feed"
+ 'newsticker-toggle-auto-narrow-to-feed
+ :visible t
+ :help "Toggle visibility of other feeds"
+ :image newsticker--narrow-image))
+ (define-key tool-bar-map [newsticker-next-feed]
+ (list 'menu-item "newsticker-next-feed" 'newsticker-next-feed
+ :visible t
+ :help "Go to next feed"
+ :image newsticker--next-feed-image
+ :enable '(newsticker-next-feed-available-p)))
+ (define-key tool-bar-map [newsticker-next-item]
+ (list 'menu-item "newsticker-next-item" 'newsticker-next-item
+ :visible t
+ :help "Go to next item"
+ :image newsticker--next-item-image
+ :enable '(newsticker-next-item-available-p)))
+ (define-key tool-bar-map [newsticker-previous-item]
+ (list 'menu-item "newsticker-previous-item" 'newsticker-previous-item
+ :visible t
+ :help "Go to previous item"
+ :image newsticker--previous-item-image
+ :enable '(newsticker-previous-item-available-p)))
+ (define-key tool-bar-map [newsticker-previous-feed]
+ (list 'menu-item "newsticker-previous-feed" 'newsticker-previous-feed
+ :visible t
+ :help "Go to previous feed"
+ :image newsticker--previous-feed-image
+ :enable '(newsticker-previous-feed-available-p)))
+ ;; standard icons / actions
+ (tool-bar-add-item "close"
+ 'newsticker-close-buffer
+ 'newsticker-close-buffer
+ :help "Close newsticker buffer")
+ (tool-bar-add-item "preferences"
+ 'newsticker-customize
+ 'newsticker-customize
+ :help "Customize newsticker")
+ tool-bar-map))))
+
+;; ======================================================================
+;;; Newsticker mode
+;; ======================================================================
+
+(define-derived-mode newsticker-mode fundamental-mode
+ "NewsTicker"
+ "Viewing news feeds in Emacs."
+ (if (boundp 'tool-bar-map)
+ (set (make-local-variable 'tool-bar-map)
+ newsticker--plainview-tool-bar-map))
+ (set (make-local-variable 'imenu-sort-function) nil)
+ (set (make-local-variable 'scroll-conservatively) 999)
+ (setq imenu-create-index-function 'newsticker--imenu-create-index)
+ (setq imenu-default-goto-function 'newsticker--imenu-goto)
+ (setq buffer-read-only t)
+ (auto-fill-mode -1) ;; turn auto-fill off!
+ (font-lock-mode -1) ;; turn off font-lock!!
+ (set (make-local-variable 'font-lock-defaults) nil)
+ (set (make-local-variable 'line-move-ignore-invisible) t)
+ (setq mode-line-format
+ (list "-"
+ 'mode-line-mule-info
+ 'mode-line-modified
+ 'mode-line-frame-identification
+ " Newsticker ("
+ '(newsticker--buffer-uptodate-p
+ "up to date"
+ "NEED UPDATE")
+ ") "
+ '(:eval (format "[%d]" (length newsticker--process-ids)))
+ " -- "
+ '(:eval (newsticker--buffer-get-feed-title-at-point))
+ ": "
+ '(:eval (newsticker--buffer-get-item-title-at-point))
+ " %-"))
+ (add-to-invisibility-spec 't)
+ (unless newsticker-show-all-news-elements
+ (add-to-invisibility-spec 'extra))
+ (newsticker--buffer-set-uptodate nil))
+
+;; refine its mode-map
+(define-key newsticker-mode-map "sO" 'newsticker-show-old-items)
+(define-key newsticker-mode-map "hO" 'newsticker-hide-old-items)
+(define-key newsticker-mode-map "sa" 'newsticker-show-all-desc)
+(define-key newsticker-mode-map "ha" 'newsticker-hide-all-desc)
+(define-key newsticker-mode-map "sf" 'newsticker-show-feed-desc)
+(define-key newsticker-mode-map "hf" 'newsticker-hide-feed-desc)
+(define-key newsticker-mode-map "so" 'newsticker-show-old-item-desc)
+(define-key newsticker-mode-map "ho" 'newsticker-hide-old-item-desc)
+(define-key newsticker-mode-map "sn" 'newsticker-show-new-item-desc)
+(define-key newsticker-mode-map "hn" 'newsticker-hide-new-item-desc)
+(define-key newsticker-mode-map "se" 'newsticker-show-entry)
+(define-key newsticker-mode-map "he" 'newsticker-hide-entry)
+(define-key newsticker-mode-map "sx" 'newsticker-show-extra)
+(define-key newsticker-mode-map "hx" 'newsticker-hide-extra)
+
+(define-key newsticker-mode-map " " 'scroll-up)
+(define-key newsticker-mode-map "q" 'newsticker-close-buffer)
+(define-key newsticker-mode-map "p" 'newsticker-previous-item)
+(define-key newsticker-mode-map "P" 'newsticker-previous-new-item)
+(define-key newsticker-mode-map "F" 'newsticker-previous-feed)
+(define-key newsticker-mode-map "\t" 'newsticker-next-item)
+(define-key newsticker-mode-map "n" 'newsticker-next-item)
+(define-key newsticker-mode-map "N" 'newsticker-next-new-item)
+(define-key newsticker-mode-map "f" 'newsticker-next-feed)
+(define-key newsticker-mode-map "M" 'newsticker-mark-all-items-as-read)
+(define-key newsticker-mode-map "m"
+ 'newsticker-mark-all-items-at-point-as-read-and-redraw)
+(define-key newsticker-mode-map "o"
+ 'newsticker-mark-item-at-point-as-read)
+(define-key newsticker-mode-map "O"
+ 'newsticker-mark-all-items-at-point-as-read)
+(define-key newsticker-mode-map "G" 'newsticker-get-all-news)
+(define-key newsticker-mode-map "g" 'newsticker-get-news-at-point)
+(define-key newsticker-mode-map "u" 'newsticker-buffer-update)
+(define-key newsticker-mode-map "U" 'newsticker-buffer-force-update)
+(define-key newsticker-mode-map "a" 'newsticker-add-url)
+
+(define-key newsticker-mode-map "i"
+ 'newsticker-mark-item-at-point-as-immortal)
+
+(define-key newsticker-mode-map "xf"
+ 'newsticker-toggle-auto-narrow-to-feed)
+(define-key newsticker-mode-map "xi"
+ 'newsticker-toggle-auto-narrow-to-item)
+
+;; maps for the clickable portions
+(defvar newsticker--url-keymap (make-sparse-keymap)
+ "Key map for click-able headings in the newsticker buffer.")
+(define-key newsticker--url-keymap [mouse-1]
+ 'newsticker-mouse-browse-url)
+(define-key newsticker--url-keymap [mouse-2]
+ 'newsticker-mouse-browse-url)
+(define-key newsticker--url-keymap "\n"
+ 'newsticker-browse-url)
+(define-key newsticker--url-keymap "\C-m"
+ 'newsticker-browse-url)
+(define-key newsticker--url-keymap [(control return)]
+ 'newsticker-handle-url)
+
+;; newsticker menu
+(defvar newsticker-menu (make-sparse-keymap "Newsticker"))
+
+(define-key newsticker-menu [newsticker-browse-url]
+ '("Browse URL for item at point" . newsticker-browse-url))
+(define-key newsticker-menu [newsticker-separator-1]
+ '("--"))
+(define-key newsticker-menu [newsticker-buffer-update]
+ '("Update buffer" . newsticker-buffer-update))
+(define-key newsticker-menu [newsticker-separator-2]
+ '("--"))
+(define-key newsticker-menu [newsticker-get-all-news]
+ '("Get news from all feeds" . newsticker-get-all-news))
+(define-key newsticker-menu [newsticker-get-news-at-point]
+ '("Get news from feed at point" . newsticker-get-news-at-point))
+(define-key newsticker-menu [newsticker-separator-3]
+ '("--"))
+(define-key newsticker-menu [newsticker-mark-all-items-as-read]
+ '("Mark all items as read" . newsticker-mark-all-items-as-read))
+(define-key newsticker-menu [newsticker-mark-all-items-at-point-as-read]
+ '("Mark all items in feed at point as read" .
+ newsticker-mark-all-items-at-point-as-read))
+(define-key newsticker-menu [newsticker-mark-item-at-point-as-read]
+ '("Mark item at point as read" .
+ newsticker-mark-item-at-point-as-read))
+(define-key newsticker-menu [newsticker-mark-item-at-point-as-immortal]
+ '("Toggle immortality for item at point" .
+ newsticker-mark-item-at-point-as-immortal))
+(define-key newsticker-menu [newsticker-separator-4]
+ '("--"))
+(define-key newsticker-menu [newsticker-toggle-auto-narrow-to-item]
+ '("Narrow to single item" . newsticker-toggle-auto-narrow-to-item))
+(define-key newsticker-menu [newsticker-toggle-auto-narrow-to-feed]
+ '("Narrow to single news feed" . newsticker-toggle-auto-narrow-to-feed))
+(define-key newsticker-menu [newsticker-hide-old-items]
+ '("Hide old items" . newsticker-hide-old-items))
+(define-key newsticker-menu [newsticker-show-old-items]
+ '("Show old items" . newsticker-show-old-items))
+(define-key newsticker-menu [newsticker-next-item]
+ '("Go to next item" . newsticker-next-item))
+(define-key newsticker-menu [newsticker-previous-item]
+ '("Go to previous item" . newsticker-previous-item))
+
+;; bind menu to mouse
+(define-key newsticker-mode-map [down-mouse-3] newsticker-menu)
+;; Put menu in menu-bar
+(define-key newsticker-mode-map [menu-bar Newsticker]
+ (cons "Newsticker" newsticker-menu))
+
+
+;; ======================================================================
+;;; User fun
+;; ======================================================================
+;;;###autoload
+(defun newsticker-plainview ()
+ "Start newsticker plainview."
+ (interactive)
+ (newsticker-buffer-update t)
+ (switch-to-buffer "*newsticker*"))
+
+(defun newsticker-buffer-force-update ()
+ "Update the newsticker buffer, even if not necessary."
+ (interactive)
+ (newsticker-buffer-update t))
+
+(defun newsticker-buffer-update (&optional force)
+ "Update the *newsticker* buffer.
+Unless FORCE is t this is done only if necessary, i.e. when the
+*newsticker* buffer is not up-to-date."
+ (interactive)
+ ;; bring cache data into proper order....
+ (newsticker--cache-sort)
+ ;; fill buffer
+ (save-excursion
+ (let ((buf (get-buffer "*newsticker*")))
+ (if buf
+ (switch-to-buffer buf)
+ (switch-to-buffer (get-buffer-create "*newsticker*"))
+ (newsticker--buffer-set-uptodate nil)))
+ (when (or force
+ (not newsticker--buffer-uptodate-p))
+ (message "Preparing newsticker buffer...")
+ (setq buffer-undo-list t)
+ (let ((inhibit-read-only t))
+ (set-buffer-modified-p nil)
+ (erase-buffer)
+ (newsticker-mode)
+ ;; Emacs 21.3.50 does not care if we turn off auto-fill in the
+ ;; definition of newsticker-mode, so we do it here (again)
+ (auto-fill-mode -1)
+
+ (set-buffer-file-coding-system 'utf-8)
+
+ (if newsticker-use-full-width
+ (set (make-local-variable 'fill-column) (1- (window-width))))
+ (newsticker--buffer-insert-all-items)
+
+ ;; FIXME: needed for methods buffer in ecb
+ ;; (set-visited-file-name "*newsticker*")
+
+ (set-buffer-modified-p nil)
+ (newsticker-hide-all-desc)
+ (if newsticker-hide-old-items-in-newsticker-buffer
+ (newsticker-hide-old-items))
+ (if newsticker-show-descriptions-of-new-items
+ (newsticker-show-new-item-desc))
+ )
+ (message ""))
+ (newsticker--buffer-set-uptodate t)
+ (run-hooks 'newsticker-buffer-change-hook)))
+
+(defun newsticker-get-news-at-point ()
+ "Launch retrieval of news for the feed point is in.
+This does NOT start the retrieval timers."
+ (interactive)
+ ;; launch retrieval of news
+ (let ((feed (get-text-property (point) 'feed)))
+ (when feed
+ (newsticker--debug-msg "Getting news for %s" (symbol-name feed))
+ (newsticker-get-news (symbol-name feed)))))
+
+(declare-function w3m-toggle-inline-image "ext:w3m" (&optional force no-cache))
+
+(defun newsticker-w3m-show-inline-images ()
+ "Show inline images in visible text ranges.
+In-line images in invisible text ranges are hidden. This function
+calls `w3m-toggle-inline-image'. It works only if
+`newsticker-html-renderer' is set to `w3m-region'."
+ (interactive)
+ (if (eq newsticker-html-renderer 'w3m-region)
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (let ((pos (point)))
+ (while pos
+ (setq pos (next-single-property-change pos 'w3m-image))
+ (when pos
+ (goto-char pos)
+ (when (get-text-property pos 'w3m-image)
+ (let ((invis (newsticker--lists-intersect-p
+ (get-text-property (1- (point))
+ 'invisible)
+ buffer-invisibility-spec)))
+ (unless (car (get-text-property (1- (point))
+ 'display))
+ (unless invis
+ (w3m-toggle-inline-image t)))))))))))))
+
+;; ======================================================================
+;;; Keymap stuff
+;; ======================================================================
+(defun newsticker-close-buffer ()
+ "Close the newsticker buffer."
+ (interactive)
+ (newsticker--cache-update t)
+ (bury-buffer))
+
+(defun newsticker-next-new-item (&optional do-not-wrap-at-eob)
+ "Go to next new news item.
+If no new item is found behind point, search is continued at
+beginning of buffer unless optional argument DO-NOT-WRAP-AT-EOB
+is non-nil."
+ (interactive)
+ (widen)
+ (let ((go-ahead t))
+ (while go-ahead
+ (unless (newsticker--buffer-goto '(item) 'new)
+ ;; found nothing -- wrap
+ (unless do-not-wrap-at-eob
+ (goto-char (point-min))
+ (newsticker-next-new-item t))
+ (setq go-ahead nil))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ ;; this item is invisible -- continue search
+ (setq go-ahead nil))))
+ (run-hooks 'newsticker-select-item-hook)
+ (point))
+
+(defun newsticker-previous-new-item (&optional do-not-wrap-at-bob)
+ "Go to previous new news item.
+If no new item is found before point, search is continued at
+beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
+is non-nil."
+ (interactive)
+ (widen)
+ (let ((go-ahead t))
+ (while go-ahead
+ (unless (newsticker--buffer-goto '(item) 'new t)
+ (unless do-not-wrap-at-bob
+ (goto-char (point-max))
+ (newsticker--buffer-goto '(item) 'new t)))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (setq go-ahead nil))))
+ (run-hooks 'newsticker-select-item-hook)
+ (point))
+
+(defun newsticker-next-item (&optional do-not-wrap-at-eob)
+ "Go to next news item.
+Return new buffer position.
+If no item is found below point, search is continued at beginning
+of buffer unless optional argument DO-NOT-WRAP-AT-EOB is
+non-nil."
+ (interactive)
+ (widen)
+ (let ((go-ahead t)
+ (search-list '(item)))
+ (if newsticker--auto-narrow-to-item
+ (setq search-list '(item feed)))
+ (while go-ahead
+ (unless (newsticker--buffer-goto search-list)
+ ;; found nothing -- wrap
+ (unless do-not-wrap-at-eob
+ (goto-char (point-min)))
+ (setq go-ahead nil))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (setq go-ahead nil))))
+ (run-hooks 'newsticker-select-item-hook)
+ (force-mode-line-update)
+ (point))
+
+(defun newsticker-next-item-same-feed ()
+ "Go to next news item in the same feed.
+Return new buffer position. If no item is found below point or if
+auto-narrow-to-item is enabled, nil is returned."
+ (interactive)
+ (if newsticker--auto-narrow-to-item
+ nil
+ (let ((go-ahead t)
+ (current-pos (point))
+ (end-of-feed (save-excursion (newsticker--buffer-end-of-feed))))
+ (while go-ahead
+ (unless (newsticker--buffer-goto '(item))
+ (setq go-ahead nil))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (setq go-ahead nil)))
+ (if (and (> (point) current-pos)
+ (< (point) end-of-feed))
+ (point)
+ (goto-char current-pos)
+ nil))))
+
+(defun newsticker-previous-item (&optional do-not-wrap-at-bob)
+ "Go to previous news item.
+Return new buffer position.
+If no item is found before point, search is continued at
+beginning of buffer unless optional argument DO-NOT-WRAP-AT-BOB
+is non-nil."
+ (interactive)
+ (widen)
+ (let ((go-ahead t)
+ (search-list '(item)))
+ (if newsticker--auto-narrow-to-item
+ (setq search-list '(item feed)))
+ (when (bobp)
+ (unless do-not-wrap-at-bob
+ (goto-char (point-max))))
+ (while go-ahead
+ (if (newsticker--buffer-goto search-list nil t)
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (setq go-ahead nil))
+ (goto-char (point-min))
+ (setq go-ahead nil))))
+ (run-hooks 'newsticker-select-item-hook)
+ (force-mode-line-update)
+ (point))
+
+(defun newsticker-next-feed ()
+ "Go to next news feed.
+Return new buffer position."
+ (interactive)
+ (widen)
+ (newsticker--buffer-goto '(feed))
+ (run-hooks 'newsticker-select-feed-hook)
+ (force-mode-line-update)
+ (point))
+
+(defun newsticker-previous-feed ()
+ "Go to previous news feed.
+Return new buffer position."
+ (interactive)
+ (widen)
+ (newsticker--buffer-goto '(feed) nil t)
+ (run-hooks 'newsticker-select-feed-hook)
+ (force-mode-line-update)
+ (point))
+
+(defun newsticker-mark-all-items-at-point-as-read-and-redraw ()
+ "Mark all items as read and clear ticker contents."
+ (interactive)
+ (when (or newsticker--buffer-uptodate-p
+ (y-or-n-p
+ "Buffer is not up to date -- really mark items as read? "))
+ (newsticker-mark-all-items-of-feed-as-read
+ (get-text-property (point) 'feed))))
+
+(defun newsticker-mark-all-items-of-feed-as-read (feed)
+ "Mark all items of FEED as read, clear ticker, and redraw buffer."
+ (when feed
+ (let ((pos (point)))
+ (message "Marking all items as read for %s" (symbol-name feed))
+ (newsticker--cache-replace-age newsticker--cache feed 'new 'old)
+ (newsticker--cache-replace-age newsticker--cache feed 'obsolete
+ 'old)
+ (newsticker--cache-update)
+ (newsticker--buffer-set-uptodate nil)
+ (newsticker--ticker-text-setup)
+ (newsticker-buffer-update)
+ ;; go back to where we came frome
+ (goto-char pos)
+ (end-of-line)
+ (newsticker--buffer-goto '(feed) nil t))))
+
+(defun newsticker-mark-all-items-at-point-as-read ()
+ "Mark all items as read and clear ticker contents."
+ (interactive)
+ (when (or newsticker--buffer-uptodate-p
+ (y-or-n-p
+ "Buffer is not up to date -- really mark items as read? "))
+ (newsticker--do-mark-item-at-point-as-read t)
+ (while (newsticker-next-item-same-feed)
+ (newsticker--do-mark-item-at-point-as-read t))
+ (newsticker-next-item t)))
+
+(defun newsticker-mark-item-at-point-as-read (&optional respect-immortality)
+ "Mark item at point as read and move to next item.
+If optional argument RESPECT-IMMORTALITY is not nil immortal items do
+not get changed."
+ (interactive)
+ (when (or newsticker--buffer-uptodate-p
+ (y-or-n-p
+ "Buffer is not up to date -- really mark this item as read? "))
+ (newsticker--do-mark-item-at-point-as-read respect-immortality)
+ ;; move forward
+ (newsticker-next-item t)))
+
+(defun newsticker--do-mark-item-at-point-as-read (&optional respect-immortality)
+ "Mark item at point as read.
+If optional argument RESPECT-IMMORTALITY is not nil immortal items do
+not get changed."
+ (let ((feed (get-text-property (point) 'feed)))
+ (when feed
+ (save-excursion
+ (newsticker--buffer-beginning-of-item)
+ (let ((inhibit-read-only t)
+ (age (get-text-property (point) 'nt-age))
+ (title (get-text-property (point) 'nt-title))
+ (guid (get-text-property (point) 'nt-guid))
+ (nt-desc (get-text-property (point) 'nt-desc))
+ (pos (save-excursion (newsticker--buffer-end-of-item)))
+ item)
+ (when (or (eq age 'new)
+ (eq age 'obsolete)
+ (and (eq age 'immortal)
+ (not respect-immortality)))
+ ;; find item
+ (setq item (newsticker--cache-contains newsticker--cache
+ feed title nt-desc
+ nil nil guid))
+ ;; mark as old
+ (when item
+ (setcar (nthcdr 4 item) 'old)
+ (newsticker--do-forget-preformatted item))
+ ;; clean up ticker
+ (if (or (and (eq age 'new)
+ newsticker-hide-immortal-items-in-echo-area)
+ (and (memq age '(old immortal))
+ (not
+ (eq newsticker-hide-old-items-in-newsticker-buffer
+ newsticker-hide-immortal-items-in-echo-area))))
+ (newsticker--ticker-text-remove feed title))
+ ;; set faces etc.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (put-text-property (point) pos 'nt-age 'old)
+ (newsticker--buffer-set-faces (point) pos)))
+ (set-buffer-modified-p nil)))))))
+
+(defun newsticker-mark-item-at-point-as-immortal ()
+ "Mark item at point as read."
+ (interactive)
+ (when (or newsticker--buffer-uptodate-p
+ (y-or-n-p
+ "Buffer is not up to date -- really mark this item as read? "))
+ (let ((feed (get-text-property (point) 'feed))
+ (item nil))
+ (when feed
+ (save-excursion
+ (newsticker--buffer-beginning-of-item)
+ (let ((inhibit-read-only t)
+ (oldage (get-text-property (point) 'nt-age))
+ (title (get-text-property (point) 'nt-title))
+ (guid (get-text-property (point) 'nt-guid))
+ (pos (save-excursion (newsticker--buffer-end-of-item))))
+ (let ((newage 'immortal))
+ (if (eq oldage 'immortal)
+ (setq newage 'old))
+ (setq item (newsticker--cache-contains newsticker--cache
+ feed title nil nil nil
+ guid))
+ ;; change age
+ (when item
+ (setcar (nthcdr 4 item) newage)
+ (newsticker--do-forget-preformatted item))
+ (if (or (and (eq newage 'immortal)
+ newsticker-hide-immortal-items-in-echo-area)
+ (and (eq newage 'obsolete)
+ newsticker-hide-obsolete-items-in-echo-area)
+ (and (eq oldage 'immortal)
+ (not
+ (eq newsticker-hide-old-items-in-newsticker-buffer
+ newsticker-hide-immortal-items-in-echo-area))))
+ (newsticker--ticker-text-remove feed title)
+ (newsticker--ticker-text-setup))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (put-text-property (point) pos 'nt-age newage)
+ (if (eq newage 'immortal)
+ (put-text-property (point) pos 'nt-age 'immortal)
+ (put-text-property (point) pos 'nt-age 'old))
+ (newsticker--buffer-set-faces (point) pos))))))
+ (if item
+ (newsticker-next-item t))))))
+
+(defun newsticker-mark-all-items-as-read ()
+ "Mark all items as read and clear ticker contents."
+ (interactive)
+ (when (or newsticker--buffer-uptodate-p
+ (y-or-n-p
+ "Buffer is not up to date -- really mark items as read? "))
+ (newsticker--cache-replace-age newsticker--cache 'any 'new 'old)
+ (newsticker--buffer-set-uptodate nil)
+ (newsticker--ticker-text-setup)
+ (newsticker--cache-update)
+ (newsticker-buffer-update)))
+
+(defun newsticker-hide-extra ()
+ "Hide the extra elements of items."
+ (interactive)
+ (newsticker--buffer-hideshow 'extra nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-extra ()
+ "Show the extra elements of items."
+ (interactive)
+ (newsticker--buffer-hideshow 'extra t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-old-item-desc ()
+ "Hide the description of old items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-old nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-old-item-desc ()
+ "Show the description of old items."
+ (interactive)
+ (newsticker--buffer-hideshow 'item-old t)
+ (newsticker--buffer-hideshow 'desc-old t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-new-item-desc ()
+ "Hide the description of new items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-new nil)
+ (newsticker--buffer-hideshow 'desc-immortal nil)
+ (newsticker--buffer-hideshow 'desc-obsolete nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-new-item-desc ()
+ "Show the description of new items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-new t)
+ (newsticker--buffer-hideshow 'desc-immortal t)
+ (newsticker--buffer-hideshow 'desc-obsolete t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-feed-desc ()
+ "Hide the description of feeds."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-feed nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-feed-desc ()
+ "Show the description of old items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-feed t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-all-desc ()
+ "Hide the descriptions of feeds and all items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-feed nil)
+ (newsticker--buffer-hideshow 'desc-immortal nil)
+ (newsticker--buffer-hideshow 'desc-obsolete nil)
+ (newsticker--buffer-hideshow 'desc-new nil)
+ (newsticker--buffer-hideshow 'desc-old nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-all-desc ()
+ "Show the descriptions of feeds and all items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-feed t)
+ (newsticker--buffer-hideshow 'desc-immortal t)
+ (newsticker--buffer-hideshow 'desc-obsolete t)
+ (newsticker--buffer-hideshow 'desc-new t)
+ (newsticker--buffer-hideshow 'desc-old t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-old-items ()
+ "Hide old items."
+ (interactive)
+ (newsticker--buffer-hideshow 'desc-old nil)
+ (newsticker--buffer-hideshow 'item-old nil)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-old-items ()
+ "Show old items."
+ (interactive)
+ (newsticker--buffer-hideshow 'item-old t)
+ (newsticker--buffer-redraw))
+
+(defun newsticker-hide-entry ()
+ "Hide description of entry at point."
+ (interactive)
+ (save-excursion
+ (let* (pos1 pos2
+ (inhibit-read-only t)
+ inv-prop org-inv-prop
+ is-invisible)
+ (newsticker--buffer-beginning-of-item)
+ (newsticker--buffer-goto '(desc))
+ (setq pos1 (max (point-min) (1- (point))))
+ (newsticker--buffer-goto '(extra feed item nil))
+ (setq pos2 (max (point-min) (1- (point))))
+ (setq inv-prop (get-text-property pos1 'invisible))
+ (setq org-inv-prop (get-text-property pos1 'org-invisible))
+ (cond ((eq inv-prop t)
+ ;; do nothing
+ )
+ ((eq org-inv-prop nil)
+ (add-text-properties pos1 pos2
+ (list 'invisible (list t)
+ 'org-invisible inv-prop)))
+ (t
+ ;; toggle
+ (add-text-properties pos1 pos2
+ (list 'invisible org-inv-prop))
+ (remove-text-properties pos1 pos2 '(org-invisible))))))
+ (newsticker--buffer-redraw))
+
+(defun newsticker-show-entry ()
+ "Show description of entry at point."
+ (interactive)
+ (save-excursion
+ (let* (pos1 pos2
+ (inhibit-read-only t)
+ inv-prop org-inv-prop
+ is-invisible)
+ (newsticker--buffer-beginning-of-item)
+ (newsticker--buffer-goto '(desc))
+ (setq pos1 (max (point-min) (1- (point))))
+ (newsticker--buffer-goto '(extra feed item))
+ (setq pos2 (max (point-min) (1- (point))))
+ (setq inv-prop (get-text-property pos1 'invisible))
+ (setq org-inv-prop (get-text-property pos1 'org-invisible))
+ (cond ((eq org-inv-prop nil)
+ (add-text-properties pos1 pos2
+ (list 'invisible nil
+ 'org-invisible inv-prop)))
+ (t
+ ;; toggle
+ (add-text-properties pos1 pos2
+ (list 'invisible org-inv-prop))
+ (remove-text-properties pos1 pos2 '(org-invisible))))))
+ (newsticker--buffer-redraw))
+
+(defun newsticker-toggle-auto-narrow-to-feed ()
+ "Toggle narrowing to current news feed.
+If auto-narrowing is active, only news item of the current feed
+are visible."
+ (interactive)
+ (newsticker-set-auto-narrow-to-feed
+ (not newsticker--auto-narrow-to-feed)))
+
+(defun newsticker-set-auto-narrow-to-feed (value)
+ "Turn narrowing to current news feed on or off.
+If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
+ (interactive)
+ (setq newsticker--auto-narrow-to-item nil)
+ (setq newsticker--auto-narrow-to-feed value)
+ (widen)
+ (newsticker--buffer-make-item-completely-visible)
+ (run-hooks 'newsticker-narrow-hook))
+
+(defun newsticker-toggle-auto-narrow-to-item ()
+ "Toggle narrowing to current news item.
+If auto-narrowing is active, only one item of the current feed
+is visible."
+ (interactive)
+ (newsticker-set-auto-narrow-to-item
+ (not newsticker--auto-narrow-to-item)))
+
+(defun newsticker-set-auto-narrow-to-item (value)
+ "Turn narrowing to current news item on or off.
+If VALUE is nil, auto-narrowing is turned off, otherwise it is turned on."
+ (interactive)
+ (setq newsticker--auto-narrow-to-feed nil)
+ (setq newsticker--auto-narrow-to-item value)
+ (widen)
+ (newsticker--buffer-make-item-completely-visible)
+ (run-hooks 'newsticker-narrow-hook))
+
+(defun newsticker-next-feed-available-p ()
+ "Return t if position is before last feed, nil otherwise."
+ (save-excursion
+ (let ((p (point)))
+ (newsticker--buffer-goto '(feed))
+ (not (= p (point))))))
+
+(defun newsticker-previous-feed-available-p ()
+ "Return t if position is behind first feed, nil otherwise."
+ (save-excursion
+ (let ((p (point)))
+ (newsticker--buffer-goto '(feed) nil t)
+ (not (= p (point))))))
+
+(defun newsticker-next-item-available-p ()
+ "Return t if position is before last feed, nil otherwise."
+ (save-excursion
+ (catch 'result
+ (while (< (point) (point-max))
+ (unless (newsticker--buffer-goto '(item))
+ (throw 'result nil))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (throw 'result t))))))
+
+(defun newsticker-previous-item-available-p ()
+ "Return t if position is behind first item, nil otherwise."
+ (save-excursion
+ (catch 'result
+ (while (> (point) (point-min))
+ (unless (newsticker--buffer-goto '(item) nil t)
+ (throw 'result nil))
+ (unless (newsticker--lists-intersect-p
+ (get-text-property (point) 'invisible)
+ buffer-invisibility-spec)
+ (throw 'result t))))))
+
+(defun newsticker-item-not-old-p ()
+ "Return t if there is an item at point which is not old, nil otherwise."
+ (when (get-text-property (point) 'feed)
+ (save-excursion
+ (newsticker--buffer-beginning-of-item)
+ (let ((age (get-text-property (point) 'nt-age)))
+ (and (memq age '(new immortal obsolete)) t)))))
+
+(defun newsticker-item-not-immortal-p ()
+ "Return t if there is an item at point which is not immortal, nil otherwise."
+ (when (get-text-property (point) 'feed)
+ (save-excursion
+ (newsticker--buffer-beginning-of-item)
+ (let ((age (get-text-property (point) 'nt-age)))
+ (and (memq age '(new old obsolete)) t)))))
+
+;; ======================================================================
+;;; Imenu stuff
+;; ======================================================================
+(defun newsticker--imenu-create-index ()
+ "Scan newsticker buffer and return an index for imenu."
+ (save-excursion
+ (goto-char (point-min))
+ (let ((index-alist nil)
+ (feed-list nil)
+ (go-ahead t))
+ (while go-ahead
+ (let ((type (get-text-property (point) 'nt-type))
+ (title (get-text-property (point) 'nt-title)))
+ (cond ((eq type 'feed)
+ ;; we're on a feed heading
+ (when feed-list
+ (if index-alist
+ (nconc index-alist (list feed-list))
+ (setq index-alist (list feed-list))))
+ (setq feed-list (list title)))
+ (t
+ (nconc feed-list
+ (list (cons title (point)))))))
+ (setq go-ahead (newsticker--buffer-goto '(item feed))))
+ (if index-alist
+ (nconc index-alist (list feed-list))
+ (setq index-alist (list feed-list)))
+ index-alist)))
+
+(defun newsticker--imenu-goto (name pos &rest args)
+ "Go to item NAME at position POS and show item.
+ARGS are ignored."
+ (goto-char pos)
+ ;; show headline
+ (newsticker--buffer-goto '(desc extra feed item))
+ (let* ((inhibit-read-only t)
+ (pos1 (max (point-min) (1- pos)))
+ (pos2 (max pos1 (1- (point))))
+ (inv-prop (get-text-property pos 'invisible))
+ (org-inv-prop (get-text-property pos 'org-invisible)))
+ (when (eq org-inv-prop nil)
+ (add-text-properties pos1 pos2 (list 'invisible nil
+ 'org-invisible inv-prop))))
+ ;; show desc
+ (newsticker-show-entry))
+
+;; ======================================================================
+;;; Buffer stuff
+;; ======================================================================
+(defun newsticker--buffer-set-uptodate (value)
+ "Set the uptodate-status of the newsticker buffer to VALUE.
+The mode-line is changed accordingly."
+ (setq newsticker--buffer-uptodate-p value)
+ (let ((b (get-buffer "*newsticker*")))
+ (when b
+ (save-excursion
+ (set-buffer b)
+ (if value
+ (setq mode-name "Newsticker -- up to date -- ")
+ (setq mode-name "Newsticker -- NEED UPDATE -- ")))
+ (force-mode-line-update 0))))
+
+(defun newsticker--buffer-redraw ()
+ "Redraw the newsticker window."
+ (if (fboundp 'force-window-update)
+ (force-window-update (current-buffer))
+ (redraw-frame (selected-frame)))
+ (run-hooks 'newsticker-buffer-change-hook)
+ (sit-for 0))
+
+(defun newsticker--buffer-insert-all-items ()
+ "Insert all cached newsticker items into the current buffer.
+Keeps order of feeds as given in `newsticker-url-list' and
+`newsticker-url-list-defaults'."
+ (goto-char (point-min))
+ (mapc (lambda (url-item)
+ (let* ((feed-name (car url-item))
+ (feed-name-symbol (intern feed-name))
+ (feed (assoc feed-name-symbol newsticker--cache))
+ (items (cdr feed))
+ (pos (point)))
+ (when feed
+ ;; insert the feed description
+ (mapc (lambda (item)
+ (when (eq (newsticker--age item) 'feed)
+ (newsticker--buffer-insert-item item
+ feed-name-symbol)))
+ items)
+ ;;insert the items
+ (mapc (lambda (item)
+ (if (memq (newsticker--age item) '(new immortal old
+ obsolete))
+ (newsticker--buffer-insert-item item
+ feed-name-symbol)))
+ items)
+ (put-text-property pos (point) 'feed (car feed))
+
+ ;; insert empty line between feeds
+ (let ((p (point)))
+ (insert "\n")
+ (put-text-property p (point) 'hard t)))))
+ (append newsticker-url-list newsticker-url-list-defaults))
+
+ (newsticker--buffer-set-faces (point-min) (point-max))
+ (newsticker--buffer-set-invisibility (point-min) (point-max))
+ (goto-char (point-min)))
+
+(defun newsticker--buffer-insert-item (item &optional feed-name-symbol)
+ "Insert a news item in the current buffer.
+Insert a formatted representation of the ITEM. The optional parameter
+FEED-NAME-SYMBOL determines how the item is formatted and whether the
+item-retrieval time is added as well."
+ ;; insert headline
+ (if (eq (newsticker--age item) 'feed)
+ (newsticker--buffer-do-insert-text item 'feed feed-name-symbol)
+ (newsticker--buffer-do-insert-text item 'item feed-name-symbol))
+ ;; insert the description
+ (newsticker--buffer-do-insert-text item 'desc feed-name-symbol))
+
+(defun newsticker--buffer-do-insert-text (item type feed-name-symbol)
+ "Actually insert contents of news item, format it, render it and all that.
+ITEM is a news item, TYPE tells which part of the item shall be inserted,
+FEED-NAME-SYMBOL tells to which feed this item belongs."
+ (let* ((pos (point))
+ (format newsticker-desc-format)
+ (pos-date-start nil)
+ (pos-date-end nil)
+ (pos-stat-start nil)
+ (pos-stat-end nil)
+ (pos-text-start nil)
+ (pos-text-end nil)
+ (pos-extra-start nil)
+ (pos-extra-end nil)
+ (pos-enclosure-start nil)
+ (pos-enclosure-end nil)
+ (age (newsticker--age item))
+ (preformatted-contents (newsticker--preformatted-contents item))
+ (preformatted-title (newsticker--preformatted-title item)))
+ (cond ((and preformatted-contents
+ (not (eq (aref preformatted-contents 0) ?\n));; we must
+ ;; NOT have a line
+ ;; break!
+ (eq type 'desc))
+ (insert preformatted-contents))
+ ((and preformatted-title
+ (not (eq (aref preformatted-title 0) ?\n));; we must NOT have a
+ ;; line break!
+ (eq type 'item))
+ (insert preformatted-title))
+ (t
+ ;; item was not formatted before.
+ ;; Let's go.
+ (if (eq type 'item)
+ (setq format newsticker-item-format)
+ (if (eq type 'feed)
+ (setq format newsticker-heading-format)))
+
+ (while (> (length format) 0)
+ (let ((prefix (if (> (length format) 1)
+ (substring format 0 2)
+ "")))
+ (cond ((string= "%c" prefix)
+ ;; contents
+ (when (newsticker--desc item)
+ (setq pos-text-start (point-marker))
+ (insert (newsticker--desc item))
+ (setq pos-text-end (point-marker)))
+ (setq format (substring format 2)))
+ ((string= "%d" prefix)
+ ;; date
+ (setq pos-date-start (point-marker))
+ (if (newsticker--time item)
+ (insert (format-time-string newsticker-date-format
+ (newsticker--time item))))
+ (setq pos-date-end (point-marker))
+ (setq format (substring format 2)))
+ ((string= "%l" prefix)
+ ;; logo
+ (let ((disabled (cond ((eq (newsticker--age item) 'feed)
+ (= (newsticker--stat-num-items
+ feed-name-symbol 'new) 0))
+ (t
+ (not (eq (newsticker--age item)
+ 'new))))))
+ (let ((img (newsticker--image-read feed-name-symbol
+ disabled)))
+ (when img
+ (newsticker--insert-image img (car item)))))
+ (setq format (substring format 2)))
+ ((string= "%L" prefix)
+ ;; logo or title
+ (let ((disabled (cond ((eq (newsticker--age item) 'feed)
+ (= (newsticker--stat-num-items
+ feed-name-symbol 'new) 0))
+ (t
+ (not (eq (newsticker--age item)
+ 'new))))))
+ (let ((img (newsticker--image-read feed-name-symbol
+ disabled)))
+ (if img
+ (newsticker--insert-image img (car item))
+ (when (car item)
+ (setq pos-text-start (point-marker))
+ (if (eq (newsticker--age item) 'feed)
+ (insert (newsticker--title item))
+ ;; FIXME: This is not the "real" title!
+ (insert (format "%s"
+ (car (newsticker--cache-get-feed
+ feed-name-symbol)))))
+ (setq pos-text-end (point-marker))))))
+ (setq format (substring format 2)))
+ ((string= "%s" prefix)
+ ;; statistics
+ (setq pos-stat-start (point-marker))
+ (if (eq (newsticker--age item) 'feed)
+ (insert (newsticker--buffer-statistics
+ feed-name-symbol)))
+ (setq pos-stat-end (point-marker))
+ (setq format (substring format 2)))
+ ((string= "%t" prefix)
+ ;; title
+ (when (car item)
+ (setq pos-text-start (point-marker))
+ (insert (car item))
+ (setq pos-text-end (point-marker)))
+ (setq format (substring format 2)))
+ ((string-match "%." prefix)
+ ;; unknown specifier!
+ (insert prefix)
+ (setq format (substring format 2)))
+ ((string-match "^\\([^%]*\\)\\(.*\\)" format) ;; FIXME!
+ ;; everything else
+ (let ((p (point)))
+ (insert (substring format
+ (match-beginning 1) (match-end 1)))
+ ;; in case that the format string contained newlines
+ (put-text-property p (point) 'hard t))
+ (setq format (substring format (match-beginning 2)))))))
+
+ ;; decode HTML if possible...
+ (let ((is-rendered-HTML nil))
+ (when (and newsticker-html-renderer pos-text-start pos-text-end)
+ (condition-case error-data
+ (save-excursion
+ ;; check whether it is necessary to call html renderer
+ ;; (regexp inspired by htmlr.el)
+ (goto-char pos-text-start)
+ (when (re-search-forward
+ "</?[A-Za-z1-6]*\\|&#?[A-Za-z0-9]+;" pos-text-end t)
+ ;; (message "%s" (newsticker--title item))
+ (let ((w3m-fill-column (if newsticker-use-full-width
+ -1 fill-column))
+ (w3-maximum-line-length
+ (if newsticker-use-full-width nil fill-column)))
+ (save-excursion
+ (funcall newsticker-html-renderer pos-text-start
+ pos-text-end)))
+ (cond ((eq newsticker-html-renderer 'w3m-region)
+ (add-text-properties pos (point-max)
+ (list 'keymap
+ w3m-minor-mode-map)))
+ ((eq newsticker-html-renderer 'w3-region)
+ (add-text-properties pos (point-max)
+ (list 'keymap w3-mode-map))))
+ (setq is-rendered-HTML t)))
+ (error
+ (message "Error: HTML rendering failed: %s, %s"
+ (car error-data) (cdr error-data)))))
+ ;; After html rendering there might be chunks of blank
+ ;; characters between rendered text and date, statistics or
+ ;; whatever. Remove it
+ (when (and (eq type 'item) is-rendered-HTML)
+ (goto-char pos)
+ (while (re-search-forward "[ \t]*\n[ \t]*" nil t)
+ (replace-match " " nil nil))
+ (goto-char (point-max)))
+ (when (and newsticker-justification
+ (memq type '(item desc))
+ (not is-rendered-HTML))
+ (condition-case nil
+ (let ((use-hard-newlines t))
+ (fill-region pos (point-max) newsticker-justification))
+ (error nil))))
+
+ ;; remove leading and trailing newlines
+ (goto-char pos)
+ (unless (= 0 (skip-chars-forward " \t\r\n"))
+ (delete-region pos (point)))
+ (goto-char (point-max))
+ (let ((end (point)))
+ (unless (= 0 (skip-chars-backward " \t\r\n" (1+ pos)))
+ (delete-region (point) end)))
+ (goto-char (point-max))
+ ;; closing newline
+ (unless nil ;;(eq pos (point))
+ (insert "\n")
+ (put-text-property (1- (point)) (point) 'hard t))
+
+ ;; insert enclosure element
+ (when (eq type 'desc)
+ (setq pos-enclosure-start (point))
+ (newsticker--insert-enclosure item newsticker--url-keymap)
+ (setq pos-enclosure-end (point)))
+
+ ;; show extra elements
+ (when (eq type 'desc)
+ (goto-char (point-max))
+ (setq pos-extra-start (point))
+ (newsticker--print-extra-elements item newsticker--url-keymap)
+ (setq pos-extra-end (point)))
+
+ ;; text properties
+ (when (memq type '(feed item))
+ (add-text-properties pos (1- (point))
+ (list 'mouse-face 'highlight
+ 'nt-link (newsticker--link item)
+ 'help-echo
+ (format "mouse-2: visit item (%s)"
+ (newsticker--link item))
+ 'keymap newsticker--url-keymap))
+ (add-text-properties pos (point)
+ (list 'nt-title (newsticker--title item)
+ 'nt-desc (newsticker--desc item))))
+
+ (add-text-properties pos (point)
+ (list 'nt-type type
+ 'nt-face type
+ 'nt-age age
+ 'nt-guid (newsticker--guid item)))
+ (when (and pos-date-start pos-date-end)
+ (put-text-property pos-date-start pos-date-end 'nt-face 'date))
+ (when (and pos-stat-start pos-stat-end)
+ (put-text-property pos-stat-start pos-stat-end 'nt-face 'stat))
+ (when (and pos-extra-start pos-extra-end)
+ (put-text-property pos-extra-start pos-extra-end
+ 'nt-face 'extra)
+ (put-text-property pos-extra-start pos-extra-end
+ 'nt-type 'extra))
+ (when (and pos-enclosure-start pos-enclosure-end
+ (> pos-enclosure-end pos-enclosure-start))
+ (put-text-property pos-enclosure-start (1- pos-enclosure-end)
+ 'nt-face 'enclosure))
+
+ ;; left margin
+ ;;(unless (memq type '(feed item))
+ ;;(set-left-margin pos (1- (point)) 1))
+
+ ;; save rendered stuff
+ (cond ((eq type 'desc)
+ ;; preformatted contents
+ (newsticker--cache-set-preformatted-contents
+ item (buffer-substring pos (point))))
+ ((eq type 'item)
+ ;; preformatted title
+ (newsticker--cache-set-preformatted-title
+ item (buffer-substring pos (point)))))))))
+
+(defun newsticker--buffer-statistics (feed-name-symbol)
+ "Return a statistic string for the feed given by FEED-NAME-SYMBOL.
+See `newsticker-statistics-format'."
+ (let ((case-fold-search nil))
+ (replace-regexp-in-string
+ "%a"
+ (format "%d" (newsticker--stat-num-items feed-name-symbol))
+ (replace-regexp-in-string
+ "%i"
+ (format "%d" (newsticker--stat-num-items feed-name-symbol 'immortal))
+ (replace-regexp-in-string
+ "%n"
+ (format "%d" (newsticker--stat-num-items feed-name-symbol 'new))
+ (replace-regexp-in-string
+ "%o"
+ (format "%d" (newsticker--stat-num-items feed-name-symbol 'old))
+ (replace-regexp-in-string
+ "%O"
+ (format "%d" (newsticker--stat-num-items feed-name-symbol 'obsolete))
+ newsticker-statistics-format)))))))
+
+(defun newsticker--buffer-set-faces (start end)
+ "Add face properties according to mark property.
+Scans the buffer between START and END."
+ (save-excursion
+ (put-text-property start end 'face 'newsticker-default-face)
+ (goto-char start)
+ (let ((pos1 start)
+ (pos2 1)
+ (nt-face (get-text-property start 'nt-face))
+ (nt-age (get-text-property start 'nt-age)))
+ (when nt-face
+ (setq pos2 (next-single-property-change (point) 'nt-face))
+ (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
+ (setq nt-face (get-text-property pos2 'nt-face))
+ (setq pos1 pos2))
+ (while (and (setq pos2 (next-single-property-change pos1 'nt-face))
+ (<= pos2 end)
+ (> pos2 pos1))
+ (newsticker--set-face-properties pos1 pos2 nt-face nt-age)
+ (setq nt-face (get-text-property pos2 'nt-face))
+ (setq nt-age (get-text-property pos2 'nt-age))
+ (setq pos1 pos2)))))
+
+(defun newsticker--buffer-set-invisibility (start end)
+ "Add invisibility properties according to nt-type property.
+Scans the buffer between START and END. Sets the 'invisible
+property to '(<nt-type>-<nt-age> <nt-type> <nt-age>)."
+ (save-excursion
+ ;; reset invisibility settings
+ (put-text-property start end 'invisible nil)
+ ;; let's go
+ (goto-char start)
+ (let ((pos1 start)
+ (pos2 1)
+ (nt-type (get-text-property start 'nt-type))
+ (nt-age (get-text-property start 'nt-age)))
+ (when nt-type
+ (setq pos2 (next-single-property-change (point) 'nt-type))
+ (put-text-property (max (point-min) pos1) (1- pos2)
+ 'invisible
+ (list (intern
+ (concat
+ (symbol-name
+ (if (eq nt-type 'extra) 'desc nt-type))
+ "-"
+ (symbol-name nt-age)))
+ nt-type
+ nt-age))
+ (setq nt-type (get-text-property pos2 'nt-type))
+ (setq pos1 pos2))
+ (while (and (setq pos2 (next-single-property-change pos1 'nt-type))
+ (<= pos2 end)
+ (> pos2 pos1))
+ ;; must shift one char to the left in order to handle inivisible
+ ;; newlines, motion in invisible text areas and all that correctly
+ (put-text-property (1- pos1) (1- pos2)
+ 'invisible
+ (list (intern
+ (concat
+ (symbol-name
+ (if (eq nt-type 'extra) 'desc nt-type))
+ "-"
+ (symbol-name nt-age)))
+ nt-type
+ nt-age))
+ (setq nt-type (get-text-property pos2 'nt-type))
+ (setq nt-age (get-text-property pos2 'nt-age))
+ (setq pos1 pos2)))))
+
+(defun newsticker--set-face-properties (pos1 pos2 nt-face age)
+ "Set the face for the text between the positions POS1 and POS2.
+The face is chosen according the values of NT-FACE and AGE."
+ (let ((face (cond ((eq nt-face 'feed)
+ 'newsticker-feed-face)
+ ((eq nt-face 'item)
+ (cond ((eq age 'new)
+ 'newsticker-new-item-face)
+ ((eq age 'old)
+ 'newsticker-old-item-face)
+ ((eq age 'immortal)
+ 'newsticker-immortal-item-face)
+ ((eq age 'obsolete)
+ 'newsticker-obsolete-item-face)))
+ ((eq nt-face 'date)
+ 'newsticker-date-face)
+ ((eq nt-face 'stat)
+ 'newsticker-statistics-face)
+ ((eq nt-face 'extra)
+ 'newsticker-extra-face)
+ ((eq nt-face 'enclosure)
+ 'newsticker-enclosure-face))))
+ (when face
+ (put-text-property pos1 (max pos1 pos2) 'face face))))
+
+;; ======================================================================
+;;; Functions working on the *newsticker* buffer
+;; ======================================================================
+(defun newsticker--buffer-make-item-completely-visible ()
+ "Scroll buffer until current item is completely visible."
+ (when newsticker--auto-narrow-to-feed
+ (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-feed))
+ (point-min)))
+ (max (or (save-excursion (newsticker--buffer-end-of-feed))
+ (point-max))))
+ (narrow-to-region min max)))
+ (when newsticker--auto-narrow-to-item
+ (let* ((min (or (save-excursion (newsticker--buffer-beginning-of-item))
+ (point-min)))
+ (max (or (save-excursion (newsticker--buffer-end-of-item))
+ (point-max))))
+ (narrow-to-region min max)))
+ (sit-for 0)
+ ;; do not count lines and stuff because that does not work when images
+ ;; are displayed. Do it the simple way:
+ (save-excursion
+ (newsticker--buffer-end-of-item)
+ (unless (pos-visible-in-window-p)
+ (recenter -1)))
+ (unless (pos-visible-in-window-p)
+ (recenter 0)))
+
+(defun newsticker--buffer-get-feed-title-at-point ()
+ "Return feed symbol of headline at point."
+ (format "%s" (or (get-text-property (point) 'feed) " ")))
+
+(defun newsticker--buffer-get-item-title-at-point ()
+ "Return feed symbol of headline at point."
+ (format "%s" (or (get-text-property (point) 'nt-title) " ")))
+
+(defun newsticker--buffer-goto (types &optional age backwards)
+ "Search next occurrence of TYPES in current buffer.
+TYPES is a list of symbols. If TYPES is found point is moved, if
+not point is left unchanged. If optional parameter AGE is not
+nil, the type AND the age must match. If BACKWARDS is t, search
+backwards."
+ (let ((pos (save-excursion
+ (save-restriction
+ (widen)
+ (catch 'found
+ (let ((tpos (point)))
+ (while (setq tpos
+ (if backwards
+ (if (eq tpos (point-min))
+ nil
+ (or (previous-single-property-change
+ tpos 'nt-type)
+ (point-min)))
+ (next-single-property-change
+ tpos 'nt-type)))
+ (and (memq (get-text-property tpos 'nt-type) types)
+ (or (not age)
+ (eq (get-text-property tpos 'nt-age) age))
+ (throw 'found tpos)))))))))
+ (when pos
+ (goto-char pos))
+ pos))
+
+(defun newsticker--buffer-hideshow (mark-age onoff)
+ "Hide or show items of type MARK-AGE.
+If ONOFF is nil the item is hidden, otherwise it is shown."
+ (if onoff
+ (remove-from-invisibility-spec mark-age)
+ (add-to-invisibility-spec mark-age)))
+
+(defun newsticker--buffer-beginning-of-item ()
+ "Move point to the beginning of the item at point.
+Return new position."
+ (if (bobp)
+ (point)
+ (let ((type (get-text-property (point) 'nt-type))
+ (typebefore (get-text-property (1- (point)) 'nt-type)))
+ (if (and (memq type '(item feed))
+ (not (eq type typebefore)))
+ (point)
+ (newsticker--buffer-goto '(item feed) nil t)
+ (point)))))
+
+(defun newsticker--buffer-beginning-of-feed ()
+ "Move point to the beginning of the feed at point.
+Return new position."
+ (if (bobp)
+ (point)
+ (let ((type (get-text-property (point) 'nt-type))
+ (typebefore (get-text-property (1- (point)) 'nt-type)))
+ (if (and (memq type '(feed))
+ (not (eq type typebefore)))
+ (point)
+ (newsticker--buffer-goto '(feed) nil t)
+ (point)))))
+
+(defun newsticker--buffer-end-of-item ()
+ "Move point to the end of the item at point.
+Take care: end of item is at the end of its last line!"
+ (when (newsticker--buffer-goto '(item feed nil))
+ (point)))
+
+(defun newsticker--buffer-end-of-feed ()
+ "Move point to the end of the last item of the feed at point.
+Take care: end of item is at the end of its last line!"
+ (when (newsticker--buffer-goto '(feed nil))
+ (backward-char 1)
+ (point)))
+
+;; ======================================================================
+;;; misc
+;; ======================================================================
+
+(defun newsticker-mouse-browse-url (event)
+ "Call `browse-url' for the link of the item at which the EVENT occurred."
+ (interactive "e")
+ (save-excursion
+ (switch-to-buffer (window-buffer (posn-window (event-end event))))
+ (let ((url (get-text-property (posn-point (event-end event))
+ 'nt-link)))
+ (when url
+ (browse-url url)
+ (save-excursion
+ (goto-char (posn-point (event-end event)))
+ (if newsticker-automatically-mark-visited-items-as-old
+ (newsticker-mark-item-at-point-as-read t)))))))
+
+(defun newsticker-browse-url ()
+ "Call `browse-url' for the link of the item at point."
+ (interactive)
+ (let ((url (get-text-property (point) 'nt-link)))
+ (when url
+ (browse-url url)
+ (if newsticker-automatically-mark-visited-items-as-old
+ (newsticker-mark-item-at-point-as-read t)))))
+
+(defvar newsticker-open-url-history
+ '("wget" "xmms" "realplay")
+ "...")
+
+(defun newsticker-handle-url ()
+ "Ask for a program to open the link of the item at point."
+ (interactive)
+ (let ((url (get-text-property (point) 'nt-link)))
+ (when url
+ (let ((prog (read-string "Open url with: " nil
+ 'newsticker-open-url-history)))
+ (when prog
+ (message "%s %s" prog url)
+ (start-process prog prog prog url)
+ (if newsticker-automatically-mark-visited-items-as-old
+ (newsticker-mark-item-at-point-as-read t)))))))
+
+
+;; ======================================================================
+;;; Misc
+;; ======================================================================
+
+(defun newsticker--cache-sort ()
+ "Sort the newsticker cache data."
+ (let ((sort-fun (cond ((eq newsticker-sort-method 'sort-by-time)
+ 'newsticker--cache-item-compare-by-time)
+ ((eq newsticker-sort-method 'sort-by-title)
+ 'newsticker--cache-item-compare-by-title)
+ ((eq newsticker-sort-method 'sort-by-original-order)
+ 'newsticker--cache-item-compare-by-position))))
+ (mapc (lambda (feed-list)
+ (setcdr feed-list (sort (cdr feed-list)
+ sort-fun)))
+ newsticker--cache)))
+
+(provide 'newsticker-plainview)
+
+;; arch-tag: 4e48b683-d48b-48dd-a13e-fe45baf41184
+;;; newst-plainview.el ends here