From: Drew Adams <drew.adams@oracle.com>
To: Michael Heerdegen <michael_heerdegen@web.de>,
Stefan Monnier <monnier@iro.umontreal.ca>
Cc: help-gnu-emacs@gnu.org
Subject: RE: Bookmarks in EWW
Date: Wed, 25 Mar 2020 14:48:34 -0700 (PDT) [thread overview]
Message-ID: <6d3b94ad-c804-47aa-acb0-3ec64159ee50@default> (raw)
In-Reply-To: <87tv2d3zii.fsf@web.de>
[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]
> Ok, I've thrown something together (draft!) and tested quickly:
Attached is something I threw together, by removing some
of the Bookmark+ features for EWW and adapting the code
to what vanilla bookmark.el offers. Completely untested;
as is. Perhaps you can make some use of it.
Features:
* An auto-bookmarking mode, for those who might want to
automatically update an existing bookmark, or create
a new bookmark, whenever they visit a URL with EWW.
* A user option for whether that mode can create new
bookmarks or just update existing ones.
* A toggle command for that user option.
* A command to set (create or update) a bookmark for
the URL currently visited by EWW.
* An option for whether and how an EWW buffer gets
renamed (the default is to use vanilla EWW name,
`*eww*'). Note: this acts beyond just bookmarking.
* An option for whether to generate a new buffer when
you jump to an EWW bookmark (the default is to reuse
an existing buffer for that URL).
* An option for whether to replace corresponding EWW
"bookmarking" commands with standard bookmarking
commands, in EWW key bindings (`eww-mode-map').
* A command to create regular Emacs bookmarks from a
file of existing EWW "bookmarks".
HTH.
[-- Attachment #2: bmk-eww.el --]
[-- Type: application/octet-stream, Size: 12361 bytes --]
;; Quiet the byte-compiler.
(defvar bookmark-alist) ; In `bookmark.el'
(defvar bookmark-default-file) ; In `bookmark.el'
(defvar bookmark-make-record-function) ; In `bookmark.el'
(defvar eww-data) ; In `eww.el'
(defvar eww-local-regex) ; In `eww.el'
(defvar eww-mode-map) ; In `eww.el'
(defvar eww-search-prefix) ; In `eww.el'
(require 'bookmark)
(require 'cl-seq) ; `cl-remove-if-not'
(defcustom bmkp-eww-auto-type 'update-only
"How `bmkp-eww-auto-bookmark-mode' behaves when enabled.
You can toggle this option using `\\[bmkp-toggle-eww-auto-type]'."
:type '(choice
(const :tag "Create EWW bookmark or update existing EWW bookmark"
create-or-update)
(const :tag "Update existing EWW bookmark (only)"
update-only))
:group 'bookmark)
(defcustom bmkp-eww-buffer-renaming nil
"Whether and how an EWW buffer is renamed.
Non-nil values affect EWW behavior even when bookmarks are not used.
* nil: Do not rename buffer - use `*eww*' (vanilla EWW behavior).
* `url': Rename buffer to web-page title plus last 20 chars of URL.
* `page': Rename buffer to web-page title (only)."
:type '(choice
(const :tag "Do not rename buffer (use name `*eww*')"
nil)
(const :tag "Rename buffer to web-page title plus last 20 chars of URL"
url)
;; Any symbol other than `page' and nil is treated the same as `page'.
(const :tag "Rename buffer to web-page title"
page))
:group 'bookmark)
(defcustom bmkp-eww-generate-buffer-flag nil
"Whether to generate a new buffer when jumping to an EWW bookmark.
* nil means reuse an existing buffer for the bookmarked URL.
* Non-nil means use a new buffer."
:type 'boolean :group 'bookmark)
(defcustom bmkp-eww-replace-keys-flag t
"Non-nil means replace EWW bookmark keys with Emacs bookmark ones.
If you change the value of this option then you must restart Emacs for
it to take effect."
:type 'boolean :group 'bookmark)
;; This is set by `bmkp-eww-rename-buffer',
;; and used in `bmkp-jump-eww' for local var `after-render-function'.
(defvar bmkp-eww-new-buf-name nil
"If non-nil, the name of the EWW buffer to jump to.")
(make-variable-buffer-local 'bmkp-eww-new-buf-name)
;; This is set by `bmkp-jump-eww',
;; and used in `bmkp-eww-rename-buffer'.
(defvar bmkp-eww-jumping-p nil
"Non-nil only if we are currently jumping to an EWW bookmark.")
(make-variable-buffer-local 'bmkp-eww-jumping-p)
(defun bmkp-eww-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is an EWW bookmark.
BOOKMARK is a bookmark name or a bookmark record.
If it is a record then it need not belong to `bookmark-alist'."
(eq (bookmark-get-handler bookmark) 'bmkp-jump-eww))
(defun bmkp-eww-alist-only ()
"`bookmark-alist', filtered to retain only EWW bookmarks.
A new list is returned (no side effects)."
(bookmark-maybe-load-default-file)
(cl-remove-if-not #'bmkp-eww-bookmark-p bookmark-alist))
(defun bmkp-eww-title ()
"Return the web-page title of the current `eww-mode' buffer."
(plist-get eww-data :title))
(defun bmkp-eww-url ()
"Return the URL of the current `eww-mode' buffer."
(eww-current-url))
(defun bmkp-make-eww-record ()
"Make a record for an EWW buffer."
`(,(bmkp-eww-title)
(buffer-name . ,(bmkp-eww-new-buffer-name))
,@(bookmark-make-record-default 'NO-FILE)
(location . ,(bmkp-eww-url))
(handler . bmkp-jump-eww)))
(defun bmkp-eww-new-buffer-name ()
"Return a new buffer name for the current `eww-mode' buffer.
The name format is determined by option `bmkp-eww-buffer-renaming'."
(concat
"*eww*"
(and bmkp-eww-buffer-renaming
(concat
"-"
(bmkp-eww-title)
(let ((url (bmkp-eww-url)))
(and (eq 'url bmkp-eww-buffer-renaming)
(concat " " (if (>= (length url) 20) (substring url -20) url))))))))
(defun bmkp-jump-eww (bookmark)
"Handler function for record returned by `bmkp-make-eww-record'.
BOOKMARK is a bookmark name or a bookmark record."
(require 'eww)
(let ((buffer
(or (and (not bmkp-eww-generate-buffer-flag)
(get-buffer (bookmark-prop-get bookmark 'buffer-name)))
(generate-new-buffer "*eww*"))) ; Might get renamed later.
;; `bmkp-eww-new-buf-name' is free here, bound in `bmkp-eww-rename-buffer'.
(after-render-function
`(lambda ()
(when (and bmkp-eww-buffer-renaming bmkp-eww-new-buf-name)
(kill-buffer)
(set-buffer bmkp-eww-new-buf-name))
(bookmark-default-handler
`("" (buffer . ,(current-buffer))
. ,(bookmark-get-bookmark-record ,(car bookmark))))
(dolist (var '(bmkp-eww-jumping-p eww-after-render-hook))
(kill-local-variable var)))))
(setq bmkp-eww-jumping-p t)
(with-current-buffer buffer
(eww-mode)
(save-window-excursion ; Because `eww' calls `pop-to-buffer-same-window'.
(eww (bookmark-location bookmark)))
(add-hook 'eww-after-render-hook after-render-function 'APPEND 'LOCAL))))
(defun bmkp-eww-rename-buffer (&rest _ignored)
"Rename current buffer according to option `bmkp-eww-buffer-renaming'.
When jumping to EWW bookmark with nil `bmkp-eww-generate-buffer-flag',
if the buffer has already been visited, set `bmkp-eww-new-buf-name' so
that `bmkp-jump-eww' will use the already visited buffer."
(when bmkp-eww-buffer-renaming
(let ((new-bname (bmkp-eww-new-buffer-name)))
(condition-case nil
(rename-buffer new-bname)
;; `bmkp-eww-jumping-p' is free here, set in `bmkp-jump-eww'.
(error (if (and bmkp-eww-jumping-p (not bmkp-eww-generate-buffer-flag))
;; Save buf name for `after-render-function' in `bmkp-jump-eww'.
(setq bmkp-eww-new-buf-name new-bname)
(rename-buffer (generate-new-buffer-name new-bname))))))))
(define-minor-mode bmkp-eww-auto-bookmark-mode
"Toggle automatically setting a bookmark when you visit a URL with EWW.
The bookmark name is the title of the web page.
If option `bmkp-eww-auto-type' is `create-or-update' then such a
bookmark is created for the URL if none exists. If the option value
is `update-only' then no new bookmark is created automatically, but an
existing bookmark is updated. (Updating a bookmark increments the
recorded number of visits.) You can toggle the option using
`\\[bmkp-toggle-eww-auto-type]'."
:init-value nil :global t :group 'bookmark
(cond (bmkp-eww-auto-bookmark-mode
(add-hook 'eww-after-render-hook 'bmkp-set-eww-bookmark-here)
(advice-add 'eww-restore-history :after 'bmkp-set-eww-bookmark-here))
(t
(remove-hook 'eww-after-render-hook 'bmkp-set-eww-bookmark-here)
(advice-remove 'eww-restore-history 'bmkp-set-eww-bookmark-here)))
(when (called-interactively-p 'any)
(message "Automatic EWW bookmarking is now %s"
(if bmkp-eww-auto-bookmark-mode
(if (eq bmkp-eww-auto-type 'update-only)
"ON, updating only"
"ON, creating or UPDATING")
"OFF"))))
(defun bmkp-set-eww-bookmark-here (&optional nomsg)
"Set an EWW bookmark for the URL of the current EWW buffer.
The current buffer is assumed to be in `eww-mode' and visiting a URL."
(interactive)
(let* ((bname (bmkp-eww-title))
(url (bmkp-eww-url))
(bmk (bookmark-get-bookmark bname 'NO-ERROR))
(visits (and bmk (bookmark-prop-get bmk 'visits))))
(when bname
(cond ((and (not visits) (eq bmkp-eww-auto-type 'create-or-update))
(bookmark-set bname)
(unless nomsg (message "Created EWW bookmark `%s'" bname)))
(visits
(bookmark-prop-set bmk 'visits (1+ visits))
(bookmark-prop-set bmk 'time (current-time))
(bookmark-bmenu-surreptitiously-rebuild-list)
(unless nomsg (message "Updated EWW bookmark `%s'" bname)))))))
(defun bmkp-toggle-eww-auto-type (&optional msgp)
"Toggle the value of option `bmkp-eww-auto-type'."
(interactive "p")
(setq bmkp-eww-auto-type (if (eq bmkp-eww-auto-type 'create-or-update)
'update-only
'create-or-update))
(when msgp (message "`bmkp-eww-auto-bookmark-mode' now %s"
(if (eq bmkp-eww-auto-type 'create-or-update)
"CREATES, as well as updates, EWW bookmarks"
"only UPDATES EXISTING EWW bookmarks"))))
;; You can use this to convert existing EWW bookmarks to Emacs bookmarks.
(defun bmkp-convert-eww-bookmarks (eww-file bmk-file &optional msgp)
"Add bookmarks from EWW-FILE to BMK-FILE.
EWW-FILE is a file of \"bookmarks\" created by EWW, which are not
compatible with Emacs bookmarks. EWW-FILE is not modified.
BMK-FILE is an Emacs bookmarks file.
If BMK-FILE exists then it is updated to include the converted
bookmarks. If it does not exist then it is created."
(interactive
(let ((default bookmark-default-file))
(list
(expand-file-name
(read-file-name "EWW \"bookmarks\" file: " nil
(expand-file-name "eww-bookmarks" user-emacs-directory)
t))
(expand-file-name
(read-file-name "Emacs bookmark file: "
(or (file-name-directory default) "~/")
bookmark-default-file))
t)))
(when (file-directory-p eww-file)
(error "`%s' is a directory, not a file" eww-file))
(unless (file-readable-p eww-file)
(error "Cannot read bookmark file `%s'" eww-file))
(when (file-directory-p bmk-file)
(error "`%s' is a directory, not a file" bmk-file))
(unless (file-readable-p bmk-file) ; Create empty bookmark file.
(setq bmk-file (expand-file-name bmk-file))
(bookmark-maybe-load-default-file)
(let ((bookmark-alist ())) (bookmark-write-file bmk-file)))
(with-temp-buffer
(insert-file-contents eww-file)
(let ((bookmark-alist ())
url title created bmk)
(dolist (ebmk (read (current-buffer)))
(setq url (plist-get ebmk :url)
title (plist-get ebmk :title)
created (date-to-time (plist-get ebmk :time))
bmk `(,title
,@(bookmark-make-record-default 'NO-FILE)
(location . ,url)
(handler . bmkp-jump-eww)))
(let ((buf-cell (assq 'buffer-name bmk))) (setcdr buf-cell "*eww*"))
(let ((created-cell (assq 'created bmk))) (setcdr created-cell created))
(push bmk bookmark-alist))
(bookmark-write-file bmk-file)))
(when msgp (message "Wrote Bookmark file `%s'" bmk-file)))
(defun bmkp-eww-jump (bookmark-name)
"Jump to an EWW bookmark."
(interactive (let ((bookmark-alist (bmkp-eww-alist-only)))
(list (bookmark-completing-read "Jump to EWW bookmark: "))))
(bookmark--jump-via bookmark-name 'pop-to-buffer-same-window))
(defun bmkp-eww-jump-other-window (bookmark-name)
"Jump to an EWW bookmark in another window."
(interactive (let ((bookmark-alist (bmkp-eww-alist-only)))
(list (bookmark-completing-read "Jump to EWW bookmark: "))))
(bookmark--jump-via bookmark-name (lambda (buf) (pop-to-buffer buf t))))
;; Non-nil `bmkp-eww-buffer-renaming' means EWW buffer is renamed on each visit.
(eval-after-load "eww"
'(progn
(add-hook 'eww-after-render-hook 'bmkp-eww-rename-buffer)
(advice-add 'eww-restore-history :after 'bmkp-eww-rename-buffer)
(add-hook 'eww-mode-hook (lambda ()
(setq-local bookmark-make-record-function
'bmkp-make-eww-record)
(unless (lookup-key eww-mode-map "j")
(define-key eww-mode-map "j" 'bmkp-eww-jump))))
(when bmkp-eww-replace-keys-flag
(define-key eww-mode-map [remap eww-add-bookmark] 'bookmark-set)
(define-key eww-mode-map [remap eww-list-bookmarks] 'bookmark-bmenu-list))))
next prev parent reply other threads:[~2020-03-25 21:48 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-23 11:26 Bookmarks in EWW Marcin Borkowski
2020-03-23 14:56 ` Drew Adams
2020-03-25 11:48 ` Marcin Borkowski
2020-03-23 20:41 ` Michael Heerdegen
2020-03-24 14:46 ` Stefan Monnier
2020-03-25 3:05 ` Michael Heerdegen
2020-03-25 3:45 ` `declare-function' docu (was: Re: Bookmarks in EWW) Emanuel Berg via Users list for the GNU Emacs text editor
2020-03-28 17:59 ` `declare-function' docu Bruno Félix Rezende Ribeiro
2020-03-28 18:38 ` Drew Adams
2020-04-09 12:30 ` Bruno Félix Rezende Ribeiro
2020-04-09 15:47 ` Drew Adams
2020-03-28 21:38 ` Emanuel Berg via Users list for the GNU Emacs text editor
2020-03-25 14:06 ` Bookmarks in EWW Stefan Monnier
2020-03-26 1:09 ` Michael Heerdegen
2020-03-26 4:07 ` Stefan Monnier
2020-03-27 2:07 ` Michael Heerdegen
2020-03-27 3:44 ` Stefan Monnier
2020-03-28 2:31 ` Michael Heerdegen
2020-03-28 2:55 ` Stefan Monnier
2020-04-19 3:42 ` Michael Heerdegen
2020-04-19 13:18 ` Stefan Monnier
2020-04-20 3:17 ` Michael Heerdegen
2020-04-20 13:24 ` Stefan Monnier
2020-04-21 0:59 ` Michael Heerdegen
2020-04-29 22:53 ` Michael Heerdegen
2020-04-30 1:25 ` Stefan Monnier
2020-04-30 2:08 ` Michael Heerdegen
2020-04-30 3:08 ` Stefan Monnier
2020-04-30 20:09 ` Michael Heerdegen
2020-04-27 2:43 ` Michael Heerdegen
2020-03-27 4:32 ` buffer-localness (was: Re: Bookmarks in EWW) Emanuel Berg via Users list for the GNU Emacs text editor
2020-03-25 21:48 ` Drew Adams [this message]
2020-03-26 2:29 ` Bookmarks in EWW Michael Heerdegen
2020-03-26 3:21 ` Drew Adams
2020-03-26 3:53 ` Michael Heerdegen
2020-03-26 14:02 ` Drew Adams
2020-03-26 22:33 ` Michael Heerdegen
2020-03-26 8:41 ` Marcin Borkowski
2020-03-25 11:49 ` Marcin Borkowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6d3b94ad-c804-47aa-acb0-3ec64159ee50@default \
--to=drew.adams@oracle.com \
--cc=help-gnu-emacs@gnu.org \
--cc=michael_heerdegen@web.de \
--cc=monnier@iro.umontreal.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).