summaryrefslogtreecommitdiff
path: root/lisp/net/eww.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/net/eww.el')
-rw-r--r--lisp/net/eww.el186
1 files changed, 132 insertions, 54 deletions
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index b720edc7fef..ebc75e0e8a7 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -134,6 +134,15 @@ The string will be passed through `substitute-command-keys'."
:type '(choice (const :tag "Unlimited" nil)
integer))
+(defcustom eww-retrieve-command nil
+ "Command to retrieve an URL via an external program.
+If nil, `url-retrieve' is used to download the data. If non-nil,
+this should be a list where the first item is the program, and
+the rest are the arguments."
+ :version "28.1"
+ :type '(choice (const :tag "Use `url-retrieve'" nil)
+ (repeat string)))
+
(defcustom eww-use-external-browser-for-content-type
"\\`\\(video/\\|audio/\\|application/ogg\\)"
"Always use external browser for specified content-type."
@@ -346,9 +355,34 @@ killed after rendering."
(let ((eww-buffer (current-buffer)))
(with-current-buffer buffer
(eww-render nil url nil eww-buffer)))
- (url-retrieve url #'eww-render
+ (eww-retrieve url #'eww-render
(list url nil (current-buffer))))))
+(defun eww-retrieve (url callback cbargs)
+ (if (null eww-retrieve-command)
+ (url-retrieve url #'eww-render
+ (list url nil (current-buffer)))
+ (let ((buffer (generate-new-buffer " *eww retrieve*"))
+ (error-buffer (generate-new-buffer " *eww error*")))
+ (with-current-buffer buffer
+ (set-buffer-multibyte nil)
+ (make-process
+ :name "*eww fetch*"
+ :buffer (current-buffer)
+ :stderr error-buffer
+ :command (append eww-retrieve-command (list url))
+ :sentinel (lambda (process _)
+ (unless (process-live-p process)
+ (when (buffer-live-p error-buffer)
+ (when (get-buffer-process error-buffer)
+ (delete-process (get-buffer-process error-buffer) ))
+ (kill-buffer error-buffer))
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (goto-char (point-min))
+ (insert "Content-type: text/html; charset=utf-8\n\n")
+ (apply #'funcall callback nil cbargs))))))))))
+
(function-put 'eww 'browse-url-browser-kind 'internal)
(defun eww--dwim-expand-url (url)
@@ -416,11 +450,11 @@ killed after rendering."
;;;###autoload
(defun eww-search-words ()
- "Search the web for the text between BEG and END.
+ "Search the web for the text in the region.
If region is active (and not whitespace), search the web for
-the text between BEG and END. Else, prompt the user for a search
-string. See the `eww-search-prefix' variable for the search
-engine used."
+the text between region beginning and end. Else, prompt the
+user for a search string. See the variable `eww-search-prefix'
+for the search engine used."
(interactive)
(if (use-region-p)
(let ((region-string (buffer-substring (region-beginning) (region-end))))
@@ -661,47 +695,83 @@ Currently this means either text/html or application/xhtml+xml."
(eww-handle-link dom)
(let ((start (point)))
(shr-tag-a dom)
- (put-text-property start (point)
- 'keymap
- (if (mm-images-in-region-p start (point))
- eww-image-link-keymap
- eww-link-keymap))))
+ (if (dom-attr dom 'href)
+ (put-text-property start (point)
+ 'keymap
+ (if (mm-images-in-region-p start (point))
+ eww-image-link-keymap
+ eww-link-keymap)))))
+
+(defun eww--limit-string-pixelwise (string pixels)
+ (if (not pixels)
+ string
+ (with-temp-buffer
+ (insert string)
+ (if (< (eww--pixel-column) pixels)
+ string
+ ;; Iterate to find appropriate length.
+ (while (and (> (eww--pixel-column) pixels)
+ (not (bobp)))
+ (forward-char -1))
+ ;; Return at least one character.
+ (buffer-substring (point-min) (max (point)
+ (1+ (point-min))))))))
+
+(defun eww--pixel-column ()
+ (if (not (get-buffer-window (current-buffer)))
+ (save-window-excursion
+ ;; Avoid errors if the selected window is a dedicated one,
+ ;; and they just want to insert a document into it.
+ (set-window-dedicated-p nil nil)
+ (set-window-buffer nil (current-buffer))
+ (car (window-text-pixel-size nil (line-beginning-position) (point))))
+ (car (window-text-pixel-size nil (line-beginning-position) (point)))))
(defun eww-update-header-line-format ()
(setq header-line-format
(and eww-header-line-format
- (let ((title (plist-get eww-data :title))
- (peer (plist-get eww-data :peer))
- (url (plist-get eww-data :url)))
- (when (zerop (length title))
- (setq title "[untitled]"))
+ (let ((peer (plist-get eww-data :peer))
+ (url (plist-get eww-data :url))
+ (title (propertize
+ (if (zerop (length (plist-get eww-data :title)))
+ "[untitled]"
+ (plist-get eww-data :title))
+ 'face 'variable-pitch)))
+ ;; This connection is https.
+ (when peer
+ (add-face-text-property 0 (length title)
+ (if (plist-get peer :warnings)
+ 'eww-invalid-certificate
+ 'eww-valid-certificate)
+ t title))
;; Limit the length of the title so that the host name
;; of the URL is always visible.
(when url
+ (setq url (propertize url 'face 'variable-pitch))
(let* ((parsed (url-generic-parse-url url))
- (host-length (length (format "%s://%s"
- (url-type parsed)
- (url-host parsed))))
- (width (window-width)))
+ (host-length (shr-string-pixel-width
+ (propertize
+ (format "%s://%s" (url-type parsed)
+ (url-host parsed))
+ 'face 'variable-pitch)))
+ (width (window-width nil t)))
(cond
;; The host bit is wider than the window, so nix
;; the title.
- ((> (+ host-length 5) width)
+ ((> (+ host-length (shr-string-pixel-width "xxxxx")) width)
(setq title ""))
;; Trim the title.
- ((> (+ (length title) host-length 2) width)
- (setq title (concat
- (substring title 0 (- width
- host-length
- 5))
- "..."))))))
- ;; This connection has is https.
- (when peer
- (setq title
- (propertize title 'face
- (if (plist-get peer :warnings)
- 'eww-invalid-certificate
- 'eww-valid-certificate))))
+ ((> (+ (shr-string-pixel-width (concat title "xx"))
+ host-length)
+ width)
+ (setq title
+ (concat
+ (eww--limit-string-pixelwise
+ title (- width host-length
+ (shr-string-pixel-width
+ (propertize "...: " 'face
+ 'variable-pitch))))
+ (propertize "..." 'face 'variable-pitch)))))))
(replace-regexp-in-string
"%" "%%"
(format-spec
@@ -1085,7 +1155,7 @@ just re-display the HTML already fetched."
(eww-display-html 'utf-8 url (plist-get eww-data :dom)
(point) (current-buffer)))
(let ((url-mime-accept-string eww-accept-content-types))
- (url-retrieve url #'eww-render
+ (eww-retrieve url #'eww-render
(list url (point) (current-buffer) encode))))))
;; Form support.
@@ -1120,6 +1190,7 @@ just re-display the HTML already fetched."
(define-key map [(control e)] 'eww-end-of-text)
(define-key map [?\t] 'shr-next-link)
(define-key map [?\M-\t] 'shr-previous-link)
+ (define-key map [backtab] 'shr-previous-link)
map))
(defvar eww-textarea-map
@@ -1129,11 +1200,14 @@ just re-display the HTML already fetched."
(define-key map [(control c) (control c)] 'eww-submit)
(define-key map [?\t] 'shr-next-link)
(define-key map [?\M-\t] 'shr-previous-link)
+ (define-key map [backtab] 'shr-previous-link)
map))
(defvar eww-select-map
(let ((map (make-sparse-keymap)))
(define-key map "\r" 'eww-change-select)
+ (define-key map [follow-link] 'mouse-face)
+ (define-key map [mouse-2] 'eww-change-select)
(define-key map [(control c) (control c)] 'eww-submit)
map))
@@ -1436,26 +1510,30 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.")
(setq display (plist-get (cdr elem) :display))))
display))
-(defun eww-change-select ()
+(defun eww--form-items (form)
+ (cl-loop for elem in form
+ when (and (consp elem)
+ (eq (car elem) 'item))
+ collect (cdr elem)))
+
+(defun eww-change-select (event)
"Change the value of the select drop-down menu under point."
- (interactive)
- (let* ((input (get-text-property (point) 'eww-form))
- (completion-ignore-case t)
- (options
- (delq nil
- (mapcar (lambda (elem)
- (and (consp elem)
- (eq (car elem) 'item)
- (cons (plist-get (cdr elem) :display)
- (plist-get (cdr elem) :value))))
- input)))
- (display (completing-read "Change value: " options nil 'require-match))
- (inhibit-read-only t))
- ;; If the user doesn't enter anything, don't change anything.
- (when (> (length display) 0)
- (plist-put input :value (cdr (assoc-string display options t)))
- (goto-char
- (eww-update-field display)))))
+ (interactive (list last-nonmenu-event))
+ (mouse-set-point event)
+ (let ((input (get-text-property (point) 'eww-form)))
+ (popup-menu
+ (cons
+ "Change Value"
+ (mapcar
+ (lambda (elem)
+ (vector (plist-get elem :display)
+ (lambda ()
+ (interactive)
+ (plist-put input :value (plist-get elem :value))
+ (goto-char (eww-update-field (plist-get elem :display))))
+ t))
+ (eww--form-items input)))
+ event)))
(defun eww-update-field (string &optional offset)
(unless offset
@@ -1559,7 +1637,7 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.")
(cond
((member (plist-get input :type) '("checkbox" "radio"))
(when (plist-get input :checked)
- (push (cons name (plist-get input :value))
+ (push (cons name (or (plist-get input :value) "on"))
values)))
((equal (plist-get input :type) "file")
(when-let ((file (plist-get input :filename)))