aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemsen2012-08-03 22:46:15 +0200
committerGravatar Tom Willemsen2012-08-03 22:46:15 +0200
commit469df1133372945e26d0574c4bdf4241d1b09062 (patch)
tree92044732bdbfcf7e15a89c3805bcad80784fe714
parent9f7c64aa6eda785993197c1f5faf934e5200063f (diff)
downloadavandu-469df1133372945e26d0574c4bdf4241d1b09062.tar.gz
avandu-469df1133372945e26d0574c4bdf4241d1b09062.zip
Rearrange
Hopefully this will make it a little clearer. More rearranging might happen in the future.
-rw-r--r--avandu.el430
1 files changed, 229 insertions, 201 deletions
diff --git a/avandu.el b/avandu.el
index 1ba8bca..1d441a6 100644
--- a/avandu.el
+++ b/avandu.el
@@ -49,10 +49,25 @@
(require 'url)
(require 'simple)
+(defconst avandu-entity-replacement-alist
+ '(("hellip" . 8230)
+ ("qout" . 34)
+ ("amp" . 38)
+ ("nbsp" . 32))
+ "What to replace the part between & and ; of HTML entities with
+ names.")
+
+;; Customization
(defgroup avandu nil
"Tiny Tiny RSS interface for emacs."
:group 'applications)
+;; Faces
+(defface avandu-overview-excerpt
+ '((t (:inherit shadow :slant italic)))
+ "Face for article excerpts in avandu overview."
+ :group 'avandu)
+
(defface avandu-overview-feed
'((((class color)
(background dark))
@@ -63,16 +78,6 @@
"Face for feed titles in avandu overview."
:group 'avandu)
-(defface avandu-overview-unread-article
- '((((class color)
- (background dark))
- (:foreground "orange3" :weight bold :family "sans"))
- (((class color)
- (background light))
- (:foregroung "red4" :weight bold :family "sans")))
- "Face for unread article titles in avandu overview."
- :group 'avandu)
-
(defface avandu-overview-read-article
'((((class color)
(background dark))
@@ -83,33 +88,27 @@
"Face for read article titles in avandu overview."
:group 'avandu)
-(defface avandu-overview-excerpt
- '((t (:inherit shadow :slant italic)))
- "Face for article excerpts in avandu overview."
+(defface avandu-overview-unread-article
+ '((((class color)
+ (background dark))
+ (:foreground "orange3" :weight bold :family "sans"))
+ (((class color)
+ (background light))
+ (:foregroung "red4" :weight bold :family "sans")))
+ "Face for unread article titles in avandu overview."
:group 'avandu)
+;; User options
(defcustom avandu-tt-rss-api-url nil
"URL of your Tiny Tiny RSS instance. For example:
http://tt-rss.org/demo/api/"
:group 'avandu
:type 'string)
+;; Variables
(defvar avandu--session-id nil
"*internal* Session id for avandu.")
-(defvar avandu-user nil
- "Username of your Tiny Tiny RSS account.")
-
-(defvar avandu-password nil
- "Password for your Tiny Tiny RSS account.")
-
-(defvar avandu-feed-button-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map button-map)
- (define-key map "c" 'avandu-feed-catchup)
- map)
- "Keymap for feeds in `avandu-overview-mode'.")
-
(defvar avandu-article-button-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map button-map)
@@ -118,6 +117,13 @@
map)
"Keymap for articles in `avandu-overview-mode'.")
+(defvar avandu-feed-button-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map button-map)
+ (define-key map "c" 'avandu-feed-catchup)
+ map)
+ "Keymap for feeds in `avandu-overview-mode'.")
+
(defvar avandu-overview-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map special-mode-map)
@@ -128,56 +134,143 @@
map)
"Keymap for `avandu-overview-mode'.")
-(defconst avandu-entity-replacement-alist
- '(("hellip" . 8230)
- ("qout" . 34)
- ("amp" . 38)
- ("nbsp" . 32))
- "What to replace the part between & and ; of HTML entities with
- names.")
+(defvar avandu-password nil
+ "Password for your Tiny Tiny RSS account.")
-(define-derived-mode avandu-overview-mode special-mode "Avandu:Overview"
- "Major mode fo the avandu overview screen.
+(defvar avandu-user nil
+ "Username of your Tiny Tiny RSS account.")
-This screen shows the articles categorized by feed as a list. It
-doesn't sort the list, so you'll have to set that up in tt-rss.
+;; Macros
+(defmacro avandu--next-button-of-type (direction type)
+ "Go DIRECTION and find the next button of a TYPE."
+ (let ((prop (case type
+ (feed 'feed-id)
+ (article 'article-id)
+ (t (error "Invalid type"))))
+ (next-point-function (case direction
+ (forward 'point-min)
+ (backward 'point-max)
+ (t (error "Invalid direction"))))
+ (next-button-function (case direction
+ (forward 'next-button)
+ (backward 'previous-button)
+ (t (error "Invalid direction")))))
+ `(let ((pos (point))
+ found-value)
+ (while (not found-value)
+ (let ((button (,next-button-function pos)))
+ (unless button
+ (setq pos (,next-point-function)
+ button (or (button-at pos)
+ (,next-button-function pos))))
+ (setq found-value (button-get button ',prop)
+ pos (overlay-start button))))
+ (goto-char pos))))
-\\{avandu-overview-map}
-\\<avandu-overview-map>"
- (use-local-map avandu-overview-map)
- (set (make-local-variable 'revert-buffer-function)
- #'(lambda (ignore-auto noconfirm) (avandu-list))))
+(defmacro avandu-getset (var prompt &optional passwdp)
+ "Ask the user for, and then save, VAR with PROMPT. Use
+`read-passwd' if PASSWDP and `read-string' otherwise."
+ `(or ,var (setq ,var (,(if passwdp 'read-passwd 'read-string)
+ ,prompt))))
+
+;; Internal
+(defun avandu--check-login ()
+ "Check to see if we're (still) logged in, try to login
+otherwise. Signals an error if we're not logged in *and* login
+was unsuccesful."
+ (unless (or (and avandu--session-id (avandu-logged-in-p))
+ (avandu-login))
+ (avandu--clear-data)
+ (error "Could not log in to tt-rss")))
+
+(defun avandu--clean-text (text)
+ "Go through TEXT and remove any trailing and leading whitespace
+from it, then look for any HTML entities and either replace them
+with their char value or with the value in
+`avandu-entity-replacement-alist'."
+ (with-temp-buffer
+ (insert text)
+ (while (re-search-forward
+ "\\`[[:space:][:cntrl:]]+\\|[[:space:][:cntrl:]]+\\'" nil t)
+ (replace-match ""))
+
+ (goto-char (point-min))
+ (while (search-forward "&" nil t)
+ (let ((pos (point)))
+ (save-excursion
+ (when (search-forward ";" nil t)
+ (let* ((sstring (buffer-substring pos (1- (point))))
+ (char-code
+ (if (= (char-after pos) ?#)
+ (unless (string-match-p "[^[:digit:]]"
+ (substring sstring 1))
+ (string-to-number (substring sstring 1)))
+ (assoc sstring avandu-entity-replacement-alist))))
+ (when char-code
+ (delete-region (1- pos) (point))
+ (insert-char (if (consp char-code)
+ (cdr char-code)
+ char-code) 1)))))))
+
+ (setq text (buffer-string)))
+ text)
(defun avandu--clear-data ()
"Clean up login data. This makes for a clean slate next time."
(setq avandu-user nil
- avandu-password nil
- avandu--session-id nil))
+ avandu--session-id nil)
+ (clear-string avandu-password))
+
+(defun avandu--get-session-id (results)
+ "Get the session id from RESULTS."
+ (cdr (assq 'session_id (assq 'content results))))
(defun avandu--get-status-id (results)
"Get the status id from RESULTS."
(cdr (assq 'status results)))
-(defun avandu--get-session-id (results)
- "Get the session id from RESULTS."
- (cdr (assq 'session_id (assq 'content results))))
+(defun avandu--insert-article-excerpt (excerpt)
+ "Insert the excerpt of an article."
+ (let ((start-pos (point))
+ end-pos
+ (text (replace-regexp-in-string
+ "[ \t\n]*$" "" (avandu--clean-text excerpt))))
+ (unless (or (not text) (string= text ""))
+ (insert
+ (propertize
+ text
+ 'face 'avandu-overview-excerpt))
+ (indent-region start-pos (point) tab-width)
+ (fill-region start-pos (point))
+ (insert-char ?\n 1))))
-(defun avandu--check-login ()
- "Check to see if we're (still) logged in, try to login
-otherwise. Signals an error if we're not logged in *and* login
-was unsuccesful."
- (unless (or (and avandu--session-id (avandu-logged-in-p))
- (avandu-login))
- (avandu--clear-data)
- (error "Could not log in to tt-rss")))
+(defun avandu--insert-article-title (id link title)
+ "Insert a button with the label TITLE and store ID and LINK in
+the article-id and link properties, respectively."
+ (insert-button
+ (replace-regexp-in-string "^[ \n\t]*\\|[ \n\t]*$" "" title)
+ 'face 'avandu-overview-unread-article
+ 'article-id id
+ 'link link
+ 'keymap avandu-article-button-map
+ 'action #'(lambda (button)
+ (message "%s" (button-get button 'link))))
+ (insert-char ?\n 1))
-(defmacro avandu-getset (var prompt &optional passwdp)
- "Ask the user for, and then save, VAR with PROMPT. Use
-`read-passwd' if PASSWDP and `read-string' otherwise."
- `(or ,var (setq ,var (,(if passwdp 'read-passwd 'read-string)
- ,prompt))))
+(defun avandu--insert-feed-title (id title)
+ "Insert a button with the label TITLE and store ID in the
+feed-id property."
+ (unless (eq (point) (point-min)) (insert-char ?\n 1))
+ (insert-button
+ (replace-regexp-in-string "^[ \n\t]*\\|[ \n\t]*$" "" title)
+ 'face 'avandu-overview-feed
+ 'feed-id id
+ 'keymap avandu-feed-button-map
+ 'action #'(lambda (button)
+ (message "%s" (button-label button))))
+ (insert-char ?\n 2))
-(defun avandu-send-command (data)
+(defun avandu--send-command (data)
"Send a command with parameters DATA to tt-rss. The current
session-id is added to the request and then DATA is passed on to
`json-encode'.
@@ -185,7 +278,7 @@ session-id is added to the request and then DATA is passed on to
DATA should be an association list with at least an OP value.
For example:
- (avandu-send-command '((op . \"isLoggedIn\")))
+ (avandu--send-command '((op . \"isLoggedIn\")))
This function returns the result of `json-read' passed over the
returned json."
@@ -205,6 +298,14 @@ returned json."
(kill-buffer buffer)
result))
+;; Commands
+(defun avandu-browse-article ()
+ "Browse the current button's article url."
+ (interactive)
+ (let ((button (button-at (point))))
+ (browse-url (button-get button 'link))
+ (avandu-mark-article-read button)))
+
(defun avandu-feed-catchup ()
"Send a request to tt-rss to \"Catch up\" with a feed. This
means that all the (unread) articles in a feed will be marked
@@ -213,37 +314,14 @@ returned json."
(interactive)
(let* ((button (button-at (point)))
(id (button-get button 'feed-id)))
- (avandu-send-command `((op . "catchupFeed")
+ (avandu--send-command `((op . "catchupFeed")
(feed_id . ,id))))
(revert-buffer))
-(defun avandu-mark-article-read (&optional button)
- "Send a request to tt-rss to mark an article as read.
-
-BUTTON, if given, should be a button widget, as created by
-`button-insert' and such, which contains FEED-ID. If BUTTON is
-nil, it will be assumed that `point' is currently within the
-bounds of a button."
- (interactive)
- (let* ((button (or button (button-at (point))))
- (id (button-get button 'article-id)))
- (avandu-send-command `((op . "updateArticle")
- (article_ids . ,id)
- (mode . 0)
- (field . 2)))
- (button-put button 'face 'avandu-overview-read-article))
- (avandu-next-article))
-
-(defun avandu-logout ()
- "Logout from Tiny Tiny RSS."
- (interactive)
- (avandu-send-command '((op . "logout")))
- (avandu--clear-data))
-
(defun avandu-logged-in-p ()
"Send a request to tt-rss to see if we're (still) logged
in. This function returns t if we are, or nil if we're not."
- (let* ((response (avandu-send-command '((op . "isLoggedIn"))))
+ (let* ((response (avandu--send-command '((op . "isLoggedIn"))))
(result (cdr (assq 'status (assq 'content response)))))
(if (eq result :json-false)
nil
@@ -255,7 +333,7 @@ in. This function returns t if we are, or nil if we're not."
and saved in memory. This function returns t on succes, nil
otherwise."
(interactive)
- (let ((result (avandu-send-command
+ (let ((result (avandu--send-command
`((op . "login")
(user . ,(avandu-getset avandu-user "Username: "))
(password
@@ -266,139 +344,69 @@ otherwise."
t)
nil)))
+(defun avandu-logout ()
+ "Logout from Tiny Tiny RSS."
+ (interactive)
+ (avandu--send-command '((op . "logout")))
+ (avandu--clear-data))
+
+(defun avandu-mark-article-read (&optional button)
+ "Send a request to tt-rss to mark an article as read.
+
+BUTTON, if given, should be a button widget, as created by
+`button-insert' and such, which contains FEED-ID. If BUTTON is
+nil, it will be assumed that `point' is currently within the
+bounds of a button."
+ (interactive)
+ (let* ((button (or button (button-at (point))))
+ (id (button-get button 'article-id)))
+ (avandu--send-command `((op . "updateArticle")
+ (article_ids . ,id)
+ (mode . 0)
+ (field . 2)))
+ (button-put button 'face 'avandu-overview-read-article))
+ (avandu-next-article))
+
(defun avandu-new-articles-count ()
"Send a request to tt-rss for the total number of unread
feeds."
(interactive)
(avandu--check-login)
- (let ((result (avandu-send-command '((op . "getUnread")))))
+ (let ((result (avandu--send-command '((op . "getUnread")))))
(message (cdr (assq 'unread (assq 'content result))))))
-(defmacro avandu--next-button-of-type (direction type)
- "Go DIRECTION and find the next button of a TYPE."
- (let ((prop (case type
- (feed 'feed-id)
- (article 'article-id)
- (t (error "Invalid type"))))
- (next-point-function (case direction
- (forward 'point-min)
- (backward 'point-max)
- (t (error "Invalid direction"))))
- (next-button-function (case direction
- (forward 'next-button)
- (backward 'previous-button)
- (t (error "Invalid direction")))))
- `(let ((pos (point))
- found-value)
- (while (not found-value)
- (let ((button (,next-button-function pos)))
- (unless button
- (setq pos (,next-point-function)
- button (or (button-at pos)
- (,next-button-function pos))))
- (setq found-value (button-get button ',prop)
- pos (overlay-start button))))
- (goto-char pos))))
-
(defun avandu-next-article ()
"Search forward for the next article."
(interactive)
(avandu--next-button-of-type forward article))
-(defun avandu-previous-article ()
- "Go backward and find the next article."
- (interactive)
- (avandu--next-button-of-type backward article))
-
(defun avandu-next-feed ()
"Go forward and find the next feed."
(interactive)
(avandu--next-button-of-type forward feed))
+(defun avandu-previous-article ()
+ "Go backward and find the next article."
+ (interactive)
+ (avandu--next-button-of-type backward article))
+
(defun avandu-previous-feed ()
"Go backward and find the next feed."
(interactive)
(avandu--next-button-of-type backward feed))
-(defun avandu--insert-feed-title (id title)
- "Insert a button with the label TITLE and store ID in the
-feed-id property."
- (unless (eq (point) (point-min)) (insert-char ?\n 1))
- (insert-button
- (replace-regexp-in-string "^[ \n\t]*\\|[ \n\t]*$" "" title)
- 'face 'avandu-overview-feed
- 'feed-id id
- 'keymap avandu-feed-button-map
- 'action #'(lambda (button)
- (message "%s" (button-label button))))
- (insert-char ?\n 2))
-
-(defun avandu-browse-article ()
- "Browse the current button's article url."
- (interactive)
- (let ((button (button-at (point))))
- (browse-url (button-get button 'link))
- (avandu-mark-article-read button)))
-
-(defun avandu--insert-article-title (id link title)
- "Insert a button with the label TITLE and store ID and LINK in
-the article-id and link properties, respectively."
- (insert-button
- (replace-regexp-in-string "^[ \n\t]*\\|[ \n\t]*$" "" title)
- 'face 'avandu-overview-unread-article
- 'article-id id
- 'link link
- 'keymap avandu-article-button-map
- 'action #'(lambda (button)
- (message "%s" (button-get button 'link))))
- (insert-char ?\n 1))
-
-(defun avandu-clean-text (text)
- "Go through TEXT and remove any trailing and leading whitespace
-from it, then look for any HTML entities and either replace them
-with their char value or with the value in
-`avandu-entity-replacement-alist'."
- (with-temp-buffer
- (insert text)
- (while (re-search-forward
- "\\`[[:space:][:cntrl:]]+\\|[[:space:][:cntrl:]]+\\'" nil t)
- (replace-match ""))
-
- (goto-char (point-min))
- (while (search-forward "&" nil t)
- (let ((pos (point)))
- (save-excursion
- (when (search-forward ";" nil t)
- (let* ((sstring (buffer-substring pos (1- (point))))
- (char-code
- (if (= (char-after pos) ?#)
- (unless (string-match-p "[^[:digit:]]"
- (substring sstring 1))
- (string-to-number (substring sstring 1)))
- (assoc sstring avandu-entity-replacement-alist))))
- (when char-code
- (delete-region (1- pos) (point))
- (insert-char (if (consp char-code)
- (cdr char-code)
- char-code) 1)))))))
+;; Overview
+(define-derived-mode avandu-overview-mode special-mode "Avandu:Overview"
+ "Major mode fo the avandu overview screen.
- (setq text (buffer-string)))
- text)
+This screen shows the articles categorized by feed as a list. It
+doesn't sort the list, so you'll have to set that up in tt-rss.
-(defun avandu--insert-article-excerpt (excerpt)
- "Insert the excerpt of an article."
- (let ((start-pos (point))
- end-pos
- (text (replace-regexp-in-string
- "[ \t\n]*$" "" (avandu-clean-text excerpt))))
- (unless (or (not text) (string= text ""))
- (insert
- (propertize
- text
- 'face 'avandu-overview-excerpt))
- (indent-region start-pos (point) tab-width)
- (fill-region start-pos (point))
- (insert-char ?\n 1))))
+\\{avandu-overview-map}
+\\<avandu-overview-map>"
+ (use-local-map avandu-overview-map)
+ (set (make-local-variable 'revert-buffer-function)
+ #'(lambda (ignore-auto noconfirm) (avandu-list))))
;;;###autoload
(defun avandu-list ()
@@ -407,10 +415,10 @@ by feed."
(interactive)
(avandu--check-login)
(let ((buffer (get-buffer-create "*avandu-overview*"))
- (result (avandu-send-command '((op . "getHeadlines")
- (feed_id . -4)
- (view_mode . "unread")
- (show_excerpt . t))))
+ (result (avandu--send-command '((op . "getHeadlines")
+ (feed_id . -4)
+ (view_mode . "unread")
+ (show_excerpt . t))))
feed-id)
(with-current-buffer buffer
(setq buffer-read-only nil)
@@ -449,3 +457,23 @@ by feed."
;; (marked . :json-false)
;; (unread . t)
;; (id . 109))
+
+;; (get-api-level)
+;; (get-version)
+;; (login user password)
+;; (logout)
+;; (is-logged-in)
+;; (get-unread)
+;; (get-counters output-mode)
+;; (get-feeds category-id unread-only limit offset)
+;; (get-categories unread-only)
+;; (get-headlines feed-id limit skip filter categoryp show-excerpt show-content view-mode include-attachments since-id search search-mode match-on)
+;; (update-article article-ids mode field data)
+;; (get-article article-id)
+;; (get-config icons-dir icons-url daemon-is-running num-feeds)
+;; (update-feed feed-id)
+;; (get-pref pref-name)
+;; (catchup-feed feed-id categoryp)
+;; (get-counters output-mode)
+;; (get-labels article-id)
+;; (set-article-label article-ids label-id assingp)