Initial commit
This commit is contained in:
178
nob.el
Normal file
178
nob.el
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
;;; nob.el --- custom bookmarks for dealing with novels in eww. -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2019 Robert Rose
|
||||||
|
|
||||||
|
;; Author: Robert Rose <overclucker@gmail.com>
|
||||||
|
;; Keywords: lisp eww novel bookmark
|
||||||
|
;; Version: 0.0.1
|
||||||
|
;; Package-Requires ((dash "2.15.0) (emacs "24") (ivy "20190214.1032")
|
||||||
|
|
||||||
|
;; This program 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.
|
||||||
|
|
||||||
|
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; This package provides functions for saving and selecting novels for
|
||||||
|
;; for reading in eww. I wrote nob because bookmarking a chapter in eww
|
||||||
|
;; and then always having to remove old bookmarks is ridiculous. nov-save
|
||||||
|
;; works by queryinh the bookmark list a pattern that matches the current
|
||||||
|
;; url. If it finds a match, it updates the title and url and moves it to
|
||||||
|
;; the front of the list. This makes shoosing what to to read next, and
|
||||||
|
;; picking up where you left off much easier. The nob-select function
|
||||||
|
;; provides an easy to navigate pop up list.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'eww)
|
||||||
|
(require 'eww-http-code-advice)
|
||||||
|
(require 'dash)
|
||||||
|
(require 'ivy)
|
||||||
|
|
||||||
|
(defgroup nob nil
|
||||||
|
"Settings for nob."
|
||||||
|
:group 'novels)
|
||||||
|
|
||||||
|
(defcustom nob-bookmarks-file (concat user-emacs-directory "nob-bookmarks.el")
|
||||||
|
"Location of the file nob uses for bookmark storage."
|
||||||
|
:group 'nob)
|
||||||
|
|
||||||
|
(defcustom nob-autosave-on-render t
|
||||||
|
"Adds `nob-eww-after-render-hook' to `eww-after-render-hook' (locally) when `nob-mode' is enabled."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'nob)
|
||||||
|
|
||||||
|
(defmacro with-nob (&rest body)
|
||||||
|
"Execute body with variable: `novels' set."
|
||||||
|
`(let ((novels
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents nob-bookmarks-file)
|
||||||
|
(read (buffer-string)))))
|
||||||
|
(unwind-protect ,@body)))
|
||||||
|
|
||||||
|
(defmacro with-eww-buffer (&rest body)
|
||||||
|
"Execute body with variables: `title' and `url' set."
|
||||||
|
`(let ((title (plist-get eww-data :title))
|
||||||
|
(url (plist-get eww-data :url)))
|
||||||
|
(unwind-protect ,@body)))
|
||||||
|
|
||||||
|
;;; I will need to explore options for replacing `--map-first'
|
||||||
|
;;; Maybe it's as simple as popping and pushing. That would be nice.
|
||||||
|
(defun nob-update-bookmark (novels title url)
|
||||||
|
"Update an existing bookmark. Returns updated novels list.'
|
||||||
|
This function has no side affects."
|
||||||
|
(--map-first (string-match (car it) url) `(,(car it) ,title ,url)
|
||||||
|
(--sort (string-match (car it) url) novels)))
|
||||||
|
|
||||||
|
(defun nob-write-file (novels)
|
||||||
|
(let ((inhibit-message 1))
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert (pp novels))
|
||||||
|
(write-file nob-bookmarks-file))))
|
||||||
|
|
||||||
|
(defun nob-convert-bookmarks ()
|
||||||
|
"Used to convert bookmarks file to the new format.
|
||||||
|
(cons pattern (cons title url))
|
||||||
|
As I've started hacking away at nob mode, I've come
|
||||||
|
to realize that I can't simply rewrite the functions.
|
||||||
|
I'll need some scafolding in place so that nob remains
|
||||||
|
functional while I continue working on it."
|
||||||
|
(interactive))
|
||||||
|
(with-temp-file (concat user-emacs-directory "nob-bookmarks")
|
||||||
|
(with-nob
|
||||||
|
(let*
|
||||||
|
((n (mapcar
|
||||||
|
(lambda (x)
|
||||||
|
(cons (car x) (cons (cadr x) (caddr x))))
|
||||||
|
novels)))
|
||||||
|
(insert (pp n)) )))
|
||||||
|
|
||||||
|
(defun nob-save ()
|
||||||
|
"Saves current novel."
|
||||||
|
(interactive)
|
||||||
|
(with-nob
|
||||||
|
(with-eww-buffer
|
||||||
|
(let ((n (--first (string-match (car it) url) novels)))
|
||||||
|
(if n
|
||||||
|
(if (not (string-equal (nth 2 n) url))
|
||||||
|
(progn
|
||||||
|
(nob-write-file (nob-update-bookmark novels title url))
|
||||||
|
(message "Bookmarked: %s" title))
|
||||||
|
(message "Already Bookmarked"))
|
||||||
|
(if (y-or-n-p "Add this novel?")
|
||||||
|
(progn
|
||||||
|
(nob-write-file
|
||||||
|
(push `(,(read-string "Match: " url) ,title ,url) novels))
|
||||||
|
(message "Bookmarked: %s" title))) )) )) )
|
||||||
|
|
||||||
|
(defun nob-select ()
|
||||||
|
"Select novel for reading in `eww'."
|
||||||
|
(interactive)
|
||||||
|
;;
|
||||||
|
;; version two
|
||||||
|
;; `assoc' is a wonderful thing.
|
||||||
|
;; originally required `--map' and `--first' from `dash.el'
|
||||||
|
;; okay, still using `--map'
|
||||||
|
(with-nob ; novels: ((pattern title url))
|
||||||
|
(let*
|
||||||
|
((n (--map (cons (cadr it) (caddr it)) novels))
|
||||||
|
;; the mapcar version is bigger.
|
||||||
|
;; (n (mapcar
|
||||||
|
;; (lambda (x)
|
||||||
|
;; (cons (cadr x) (caddr x)))
|
||||||
|
;; novels))
|
||||||
|
(s (cdr (assoc (ivy-read "Select Novel: " n) n))) )
|
||||||
|
(switch-to-buffer "*nob*")
|
||||||
|
(unless (eq major-mode 'eww-mode)
|
||||||
|
(eww-mode))
|
||||||
|
(stride-mode 1)
|
||||||
|
(nob-mode 1)
|
||||||
|
(article-mode 1)
|
||||||
|
(eww-browse-url s))))
|
||||||
|
|
||||||
|
(defun nob-remove ()
|
||||||
|
"Remove an novel."
|
||||||
|
(interactive)
|
||||||
|
(with-nob
|
||||||
|
(let ((s (ivy-read "Remove Novel: " (--map (cdr it) novels))))
|
||||||
|
(when (y-or-n-p (format "Remove \"%s\"?" s))
|
||||||
|
(nob-write-file
|
||||||
|
(--remove (string-equal s (car (cdr it))) novels))
|
||||||
|
(message "Removed: %s" s)) )) )
|
||||||
|
|
||||||
|
(defun nob-eww-after-render-hook ()
|
||||||
|
"Eww render hook for nob autosave"
|
||||||
|
(let ((status (third (plist-get eww-data :error))))
|
||||||
|
(if (not (member status '(400 404)))
|
||||||
|
(with-nob
|
||||||
|
(with-eww-buffer
|
||||||
|
(let ((n (--first (string-match (car it) url) novels)))
|
||||||
|
(if n
|
||||||
|
(if (not (string-equal (nth 2 n) url))
|
||||||
|
(nob-write-file (nob-update-bookmark novels title url))))) )))) )
|
||||||
|
|
||||||
|
(setq nob-mode-map (make-sparse-keymap))
|
||||||
|
(define-key nob-mode-map [?b] 'nob-save)
|
||||||
|
(define-key nob-mode-map [?B] 'nob-select)
|
||||||
|
|
||||||
|
(define-minor-mode nob-mode
|
||||||
|
"Novel bookmarks minor mode."
|
||||||
|
:lighter " Nob"
|
||||||
|
:keymap nob-mode-map
|
||||||
|
(when nob-autosave-on-render
|
||||||
|
(if nob-mode
|
||||||
|
(add-hook 'eww-after-render-hook 'nob-eww-after-render-hook nil t)
|
||||||
|
(remove-hook 'eww-after-render-hook 'nob-eww-after-render-hook t) )))
|
||||||
|
|
||||||
|
(provide 'nob)
|
||||||
|
|
||||||
|
;;; nob.el ends here
|
||||||
Reference in New Issue
Block a user