New command 'eww-copy-alternate-url'

This adds a new command to EWW that copies an alternate link to the
currently visited page into the kill ring.  This is useful for
subscribing to website feeds, etc.

* lisp/net/eww.el (eww--alternate-urls, eww-read-alternate-url):
 New functions.
(eww-copy-alternate-url): New command.
(eww-mode-map): Bind it to 'A'.

* doc/misc/eww.texi (Basics): Document it.

* etc/NEWS: Announce it.
(Bug#64126)
This commit is contained in:
Eshel Yaron 2023-06-17 13:48:51 +03:00 committed by Eli Zaretskii
parent 8e8667246a
commit dfba4347c7
3 changed files with 101 additions and 0 deletions

View file

@ -115,6 +115,21 @@ web page hit @kbd{g} (@code{eww-reload}).
@kbd{w} calls @code{eww-copy-page-url}, which will copy the current
page's URL to the kill ring instead.
@findex eww-copy-alternate-url
@kindex A
The @kbd{A} command (@code{eww-copy-alternate-url}) copies the URL
of an alternate link of the current page into the kill ring. If the
page specifies multiple alternate links, this command prompts for one
of them in the minibuffer, with completion. Alternate links are
references that an @acronym{HTML} page may include to point to other
documents that act as its alternative representations. Notably,
@acronym{HTML} pages can use alternate links to point to their
translated versions and to @acronym{RSS} feeds. Alternate links
appear in the @samp{<head>} section of @acronym{HTML} pages as
@samp{<link>} elements with @samp{rel} attribute equal to
@samp{``alternate''}, they are part of the page's metadata and are not
visible in its rendered content.
@findex eww-open-in-new-buffer
@kindex M-RET
The @kbd{M-@key{RET}} command (@code{eww-open-in-new-buffer}) opens the

View file

@ -266,6 +266,13 @@ The interactive minibuffer prompt when invoking 'eww' now provides
completions from 'eww-suggest-uris'. 'eww-suggest-uris' now includes
bookmark URIs.
+++
*** New command 'eww-copy-alternate-url'.
It copies an alternate link to the page currently visited in EWW into
the kill ring. Alternate links are optional metadata that HTML pages
use for linking to their alternative representations, such as
translated versions or associated RSS feeds.
** go-ts-mode
+++

View file

@ -1086,6 +1086,7 @@ the like."
"&" #'eww-browse-with-external-browser
"d" #'eww-download
"w" #'eww-copy-page-url
"A" #'eww-copy-alternate-url
"C" #'url-cookie-list
"v" #'eww-view-source
"R" #'eww-readable
@ -2576,4 +2577,82 @@ Otherwise, the restored buffer will contain a prompt to do so by using
(provide 'eww)
;;; Alternate links (RSS and Atom feeds, etc.)
(defun eww--alternate-urls (dom &optional base)
"Return an alist of alternate links in DOM.
Each element is a list of the form (URL TYPE TITLE) where URL is
the href attribute of the link expanded relative to BASE, TYPE is
its type attribute, and TITLE is its title attribute. If any of
these attributes is absent, the corresponding element is nil."
(let ((alternates
(seq-filter
(lambda (attrs) (string= (alist-get 'rel attrs)
"alternate"))
(mapcar #'dom-attributes (dom-by-tag dom 'link)))))
(mapcar (lambda (alternate)
(list (url-expand-file-name (alist-get 'href alternate)
base)
(alist-get 'type alternate)
(alist-get 'title alternate)))
alternates)))
(defun eww-read-alternate-url ()
"Get the URL of an alternate link of this page.
If there is just one alternate link, return its URL. If there
are multiple alternate links, prompt for one in the minibuffer
with completion. If there are none, return nil."
(when-let ((alternates (eww--alternate-urls
(plist-get eww-data :dom)
(plist-get eww-data :url))))
(let ((url-max-width
(seq-max (mapcar #'string-pixel-width
(mapcar #'car alternates))))
(title-max-width
(seq-max (mapcar #'string-pixel-width
(mapcar #'caddr alternates))))
(sep-width (string-pixel-width " ")))
(if (cdr alternates)
(let ((completion-extra-properties
(list :annotation-function
(lambda (feed)
(let* ((attrs (alist-get feed
alternates
nil
nil
#'string=))
(type (car attrs))
(title (cadr attrs)))
(concat
(propertize " " 'display
`(space :align-to
(,(+ sep-width
url-max-width))))
title
(when type
(concat
(propertize " " 'display
`(space :align-to
(,(+ (* 2 sep-width)
url-max-width
title-max-width))))
"[" type "]"))))))))
(completing-read "Alternate URL: " alternates nil t))
(caar alternates)))))
(defun eww-copy-alternate-url ()
"Copy an alternate URL of the current page into the kill ring.
Alternate links are references that an HTML page may include to
point to its alternative representations, such as a translated
version or an RSS feed."
(interactive nil eww-mode)
(if-let ((url (eww-read-alternate-url)))
(progn
(kill-new url)
(message "Copied %s to kill ring" url))
(user-error "No alternate links found on this page!")))
;;; eww.el ends here