From 24dd1dfa89d1a133b0a6c2301bbde4524b3d4650 Mon Sep 17 00:00:00 2001 From: jao Date: Thu, 25 Mar 2021 23:15:10 +0000 Subject: jao-w3m-session is back from the dead, as eww-session --- lib/net/jao-eww-session.el | 390 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 lib/net/jao-eww-session.el (limited to 'lib/net/jao-eww-session.el') diff --git a/lib/net/jao-eww-session.el b/lib/net/jao-eww-session.el new file mode 100644 index 0000000..8717d3c --- /dev/null +++ b/lib/net/jao-eww-session.el @@ -0,0 +1,390 @@ +;;; jao-eww-session.el --- Persistent emacs-eww sessions -*- lexical-binding: t; -*- + +;; Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2012, 2021 Jose A Ortega Ruiz + +;; Author: Jose A Ortega Ruiz +;; Version: 0.3.6 +;; Keywords: hypermedia, eww, WWW + +;; This file 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, or (at your option) +;; any later version. + +;; This file 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; INTRODUCTION: +;; +;; jao-eww-session provides persistent emacs-eww browsing sessions. When +;; quitting eww (or, if you request it, at any other time while using +;; it) you can save the current eww session (that is, the set of open +;; tabs and the URLs they're visiting). Upon restarting emacs-eww +;; (possibly after restarting Emacs itself) you'll have the possibity +;; of recovering the saved session (that is, of re-opening the saved +;; tabs and URLs). You also have at your disposal a command to recover +;; the saved session at any other time. +;; +;; INSTALLATION: +;; +;; Just put this file somewhere on your Emacs load path and add the +;; following line to your .emacs file: +;; +;; (require 'jao-eww-session) +;; +;; After restarting Emacs (or evaluating the form above), each time +;; you start emacs-eww with 'eww' you'll get a prompt asking whether +;; your last browsing session should be loaded. Likewise, when +;; quitting the browser, you'll have the possibility of saving your +;; current session (overwriting the previous one). +;; +;; In addition, two new interactive functions are defined: +;; +;; jao-eww-session-load -- load the last stored session +;; jao-eww-session-save -- save the current session +;; +;; These functions can be invoked at any time while running emacs-eww. +;; Optionally, you can bind them to key shortcuts with the proper +;; variations of the following elisp magic in your .emacs: +;; (defun eww-add-keys () +;; (define-key eww-mode-map "S" 'jao-eww-session-save) +;; (define-key eww-mode-map "L" 'jao-eww-session-load)) +;; (add-hook 'eww-mode-hook 'eww-add-keys) +;; +;; CUSTOMIZATION: +;; +;; A new customization group, jao-eww-session, is available. There you can +;; customize the following variables: +;; +;; jao-eww-session-load-always -- if t, `jao-eww-session-load' will *not* ask +;; for confirmation (default nil) +;; jao-eww-session-save-always -- if t, `jao-eww-session-save' will *not* ask +;; for confirmation (default nil) +;; jao-eww-session-show-titles -- if t, the load prompt will list the +;; session URL titles (default t) +;; jao-eww-session-duplicate-tabs -- what to do when loading a session that +;; contains a URL already open +;; jao-eww-session-file -- the file where eww session info +;; is stored (default "~/.jao-eww-session") +;; jao-eww-session-autosave-period -- the period, in seconds, for automatic +;; session backup file updating. +;; +;; +;; You can also customize them in your .emacs file, to wit: +;; +;; (setq jao-eww-session-file "~/.emacs.d/jao-eww-session") +;; (setq jao-eww-session-save-always nil) +;; (setq jao-eww-session-load-always nil) +;; (setq jao-eww-session-show-titles t) +;; (setq jao-eww-session-duplicate-tabs 'ask) ; 'never, 'always, 'ask +;; +;; HISTORY: +;; +;; Version 0.4 (March, 2021): +;; +;; - Migrated to eww. +;; +;; Version 0.3.7 : +;; +;; - `jao-eww-session-deactivate-builtin-sessions', to do what it +;; says. +;; +;; Version 0.3.6 (Sat Apr 19, 2008): +;; +;; - eww-session -> jao-eww-session to avoid collisions with +;; emacs-eww's session manager. +;; +;; Version 0.3.5 (Sun Jan 14, 2007): +;; +;; - automatic session backup every `jao-eww-session-autosave-period' +;; seconds. +;; +;; Version 0.3.4 (Wed Jul 19, 2006): +;; +;; - save session file on quitting Emacs (without using +;; desktop.el) +;; +;; Version 0.3.3 (Thu Jun 8, 2006): +;; +;; - save session file with pretty print. +;; - handle correctly multiple emacs-eww (re)starts during a +;; single emacs session. +;; - save URLs in hexified form to allow & in them. +;; - code cleanup. +;; +;; Version 0.3.2 (Mon Sep 29, 2003): +;; +;; - bug fix: when searching or going to home/bookmarks/etc, +;; keep the current tab's focus. +;; +;; Version 0.3.1 (Tue Aug 26, 2003): +;; +;; - type of `jao-eww-session-file' set to 'file' in customisation +;; buffer. +;; - bug fix: syntax error due to a typo in `jao-eww-session-file' +;; +;; Version 0.3 (Mon Aug 25, 2003): +;; +;; - the load session tab lists the titles of the session's pages +;; (customizable via 'jao-eww-session-show-titles'). +;; - the duplicated tab prompt displays also the URL's title. +;; - bug fix: active tab in session now is correctly saved. +;; +;; Version 0.2 (Fri Aug 22, 2003): +;; +;; - the session info now includes the active tab, which gets +;; displayed when the session is reloaded. +;; - when reloading a session in a running emacs-eww, if the +;; session contains a URL that is already being displayed by the +;; browser, the tab can be reused or duplicated (customizable +;; via `jao-eww-session-duplicate-tabs'). +;; +;; Version 0.1 (Wed Aug 20, 2003) -- Initial release. +;; + + +;;; Code: + +;;; Dependencies: + +(require 'eww) +(require 'url) + +;;; Custom variables: + +(defgroup jao-eww-session nil + "eww - session saving in eww." + :group 'eww + :prefix "jao-eww-session-") + +(defcustom jao-eww-session-save-always nil + "If on, always save eww session without asking." + :group 'jao-eww-session + :type 'boolean) + +(defcustom jao-eww-session-load-always nil + "If on, always load eww session without asking." + :group 'jao-eww-session + :type 'boolean) + +(defcustom jao-eww-session-show-titles t + "If on, show URL titles in the load prompt." + :group 'jao-eww-session + :type 'boolean) + +(defcustom jao-eww-session-duplicate-tabs 'never + "How to treat session URL already being visited. + +When loading a session with `jao-eww-session-load', if one of the URLs in +the session is already displayed in a eww tab, jao-eww-session can: +- `never' create a new tab (just reload it), or +- `always' duplicate the URL in a new tab, or +- `ask' the user what to do." + :group 'jao-eww-session + :type '(choice (const :value never) + (const :value always) + (const :value ask))) + +(defcustom jao-eww-session-file "~/.jao-eww-session" + "File to save the eww session data." + :group 'jao-eww-session + :type 'file) + +(defvar jao-eww-session-autosave-period 180 + "A backup of the current session is saved with this period (in secs).") + +(defvar jao-eww-url-filters nil "URL filters.") + +;;; Internals: + +;;;; auxiliary functions + +(defvar jao-eww-current-session '(jao-eww-session 0 nil)) + +(defun jao-eww-session--filter (url filters) + (cond ((not filters) url) + ((string-match-p (caar filters) url) + (cond ((functionp (cdar filters)) (funcall (cadr filters) url)) + ((stringp (cdar filters)) (cdar filters)))) + (t (jao-eww-session--filter url (cdr filters))))) + +(defun jao-eww-session--list-buffers () + (save-window-excursion + (when (ignore-errors (eww-list-buffers)) + (goto-char (point-min)) + (let* ((buffers) + (cf (lambda () + (when-let (b (get-text-property (line-beginning-position) + 'eww-buffer)) + (push b buffers)) + (forward-line) + (not (eobp))))) + (while (funcall cf)) + buffers)))) + +(defun jao-eww-session--current-urls () + (let ((urls) + (cb (current-buffer)) + (pos 0) + (count 0)) + (dolist (b (jao-eww-session--list-buffers) (list pos (reverse urls))) + (set-buffer b) + (let ((url (jao-eww-session--filter (jao-eww-buffer-url) jao-eww-url-filters))) + (when url + (when (eq b cb) (setq pos count)) + (setq count (1+ count)) + (push (cons (url-encode-url url) (jao-eww-buffer-title)) urls)))))) + +(defun jao-eww-session-urls (&optional s) + (let ((s (or s jao-eww-current-session))) + (mapcar 'car (nth 2 s)))) + +(defun jao-eww-session-offset (&optional s) + (let ((s (or s jao-eww-current-session))) + (nth 1 s))) + +(defun jao-eww-session-titles (&optional s) + (let ((s (or s jao-eww-current-session))) + (mapcar 'cdr (nth 2 s)))) + +(defun jao-eww-session-current (&optional s) + (save-current-buffer + (setq jao-eww-current-session + (or s (cons 'jao-eww-session (jao-eww-session--current-urls)))))) + +(defun jao-eww-session-find-duplicated (urls) + (save-current-buffer + (let* ((duplicate-p + (lambda () + (y-or-n-p + (format "'%s' (%s) is already open. Duplicate tab? " + (jao-eww-buffer-title) (jao-eww-buffer-url))))) + (urls (regexp-opt urls)) + (test-b + (lambda (b) + (set-buffer b) + (or (and (string-match urls (jao-eww-buffer-url)) + (or (equal jao-eww-session-duplicate-tabs 'never) + (not (duplicate-p))) + b) + 'not))) + (buffers (mapcar test-b (jao-eww-session--list-buffers)))) + (delete 'not buffers)))) + +(defun jao-eww-session-close-buffers (buffers) + (save-current-buffer + (mapc 'kill-buffer buffers))) + +(defun jao-eww-session-load-aux () + (let ((new-session (jao-eww-session-from-file + (expand-file-name jao-eww-session-file)))) + (when (and new-session + (or jao-eww-session-load-always + (y-or-n-p + (if jao-eww-session-show-titles + (format "Load last eww session %S? " + (jao-eww-session-titles new-session)) + "Load last eww session? ")))) + (jao-eww-session-current new-session)))) + +(defun jao-eww-session-from-file (fname) + (let ((fname (jao-eww-session--check--backup fname))) + (when (file-readable-p fname) + (with-temp-buffer + (insert-file-contents fname) + (goto-char (point-min)) + (let ((sexp (read (current-buffer)))) + (and (equal 'jao-eww-session (car sexp)) sexp)))))) + +(defun jao-eww-session-current-to-file () + (jao-eww-session--to--file jao-eww-session-file)) + +(defun jao-eww-session--to--file (filename &optional is-auto) + (require 'pp) + (let ((inhibit-message is-auto)) + (with-temp-buffer + (insert ";;;; File generated by jao-eww-session. DO NOT EDIT!\n") + (pp (jao-eww-session-current) (current-buffer)) + (insert "\n" ";;;; End of " + (file-name-nondirectory jao-eww-session-file) "\n") + (write-region (point-min) (point-max) (expand-file-name filename))))) + +(defvar jao-eww-session--timer nil) + +(defun jao-eww-session--backup-name (fname) + (concat (expand-file-name fname) ".bak")) + +(defun jao-eww-session--check--backup (fname) + (let ((bfname (jao-eww-session--backup-name fname))) + (if (and (file-newer-than-file-p bfname fname) + (y-or-n-p "A newer autosaved session exists. Use it? ")) + bfname + fname))) + +(defun jao-eww-session--save-backup () + (jao-eww-session--to--file (jao-eww-session--backup-name jao-eww-session-file) t)) + +(defun jao-eww-session--restart--autosave () + (when (> jao-eww-session-autosave-period 0) + (when jao-eww-session--timer (cancel-timer jao-eww-session--timer)) + (setq jao-eww-session--timer + (run-at-time jao-eww-session-autosave-period + jao-eww-session-autosave-period + 'jao-eww-session--save-backup)))) + +;;;; save session on exit +(add-to-list 'kill-emacs-query-functions (lambda () (jao-eww-session-save) t)) +(add-hook 'eww-after-render-hook #'jao-eww-session--save-backup) + +;;; Interactive functions: +;;;###autoload +(defun jao-eww-buffer-url () (plist-get eww-data :url)) + +;;;###autoload +(defun jao-eww-buffer-title () (plist-get eww-data :title)) + +;;;###autoload +(defun jao-eww-session-save () + "Save the current eww session." + (interactive) + (when (or jao-eww-session-save-always + (y-or-n-p "Save current eww session? ")) + (jao-eww-session-current-to-file) + (jao-eww-session--restart--autosave))) + +;;;###autoload +(defun jao-eww-session-load () + "Load last stored session into eww." + (interactive) + (let ((s (jao-eww-session-load-aux))) + (when s + (jao-eww-session--restart--autosave) + (let* ((urls (jao-eww-session-urls s)) + (offset (jao-eww-session-offset s)) + (buffers (unless (equal jao-eww-session-duplicate-tabs 'always) + (jao-eww-session-find-duplicated urls)))) + (dolist (url urls) (eww url 4)) + (when buffers (jao-eww-session-close-buffers buffers)) + (unless (zerop offset) + (switch-to-buffer (nth offset (jao-eww-session--list-buffers)))))))) + +;;;###autoload +(defun jao-eww-session-set-autosave-period (secs) + "Set new value for the period between session backup autosaves." + (interactive "p") + (let ((secs (or secs (read-number "New period (secs): " 0)))) + (when (> secs 0) + (setq jao-eww-session-autosave-period secs) + (jao-eww-session--restart--autosave)))) + +(provide 'jao-eww-session) +;;; jao-eww-session.el ends here -- cgit v1.2.3