;; -*- lexical-binding: t; -*- (use-package eww :straight (:type built-in) :config (defun eww-before-advice (&rest args) (interactive (let* ((uris (eww-suggested-uris)) (browser-history (mapcar (lambda (h) (plist-get h :url)) eww-history)) (bookmarks (mapcar (lambda (b) (plist-get b :url)) eww-bookmarks)) (suggestions (delete-dups (append uris eww-prompt-history browser-history))) (current-uri (plist-get eww-data :url))) (list (completing-read "URL or keywords: " suggestions nil nil current-uri 'eww-prompt-history) current-prefix-arg)))) (advice-add 'eww :before #'eww-before-advice) (defun eww-rename-buffer-to-title () (rename-buffer (format "*eww: %s*" (plist-get eww-data :title)) t)) (add-hook 'eww-after-render-hook #'eww-rename-buffer-to-title) ;; Copied from https://protesilaos.com/emacs/dotemacs#h:abc20037-7a4f-4555-809a-dc4165c5db6a (defun eww-capture-urls-on-page (&optional position) "Capture all the links on the current web page. Return a list of strings. Strings are in the form LABEL @ URL. When optional argument POSITION is non-nil, include position info in the strings too, so strings take the form LABEL @ URL ~ POSITION." (let (links match) (save-excursion (goto-char (point-max)) ;; NOTE 2021-07-25: The first clause in the `or' is meant to ;; address a bug where if a URL is in `point-min' it does not get ;; captured. (while (setq match (text-property-search-backward 'shr-url)) (let* ((raw-url (prop-match-value match)) (start-point-prop (prop-match-beginning match)) (end-point-prop (prop-match-end match)) (url (when (stringp raw-url) (propertize raw-url 'face 'link))) (label (replace-regexp-in-string "\n" " " ; NOTE 2021-07-25: newlines break completion (buffer-substring-no-properties start-point-prop end-point-prop))) (point start-point-prop) (line (line-number-at-pos point t)) (column (save-excursion (goto-char point) (current-column))) (coordinates (propertize (format "%d,%d (%d)" line column point) 'face 'shadow))) (when url (if position (push (format "%-15s ~ %s @ %s" coordinates label url) links) (push (format "%s @ %s" label url) links)))))) links)) (defun eww-visit-url-on-page (&optional arg) "Visit URL from list of links on the page using completion. With optional prefix ARG (\\[universal-argument]) open URL in a new EWW buffer." (interactive "P") (when (derived-mode-p 'eww-mode) (let* ((links (eww-capture-urls-on-page)) (selection (completing-read "Browse URL: " links nil t)) (url (replace-regexp-in-string ".*@ " "" selection))) (eww url (when arg 4))))) (defun eww-jump-to-url-on-page (&optional arg) "Jump to URL position on the page using completion." (interactive "P") (when (derived-mode-p 'eww-mode) (let* ((links (eww-capture-urls-on-page t)) (prompt (format "Jump to URL: ")) (selection (completing-read prompt links nil t)) (position (replace-regexp-in-string "^.*(\\([0-9]+\\))[\s\t]+~" "\\1" selection)) (point (string-to-number position))) (goto-char point)))) (defun eww-visit-bookmark (bookmark &optional arg) "Visit BOOKMARK in EWW." (interactive (list (let* ((bookmarks (mapcar (lambda (b) (cons (format "%s | %s" (plist-get b :title) (plist-get b :url)) (plist-get b :url))) eww-bookmarks)) (bookmark (completing-read "Bookmark: " bookmarks))) (cdr (assoc bookmark bookmarks))) current-prefix-arg)) (eww bookmark arg)) ;; Don't try to render SVGs, for some reason they are not rendered correctly (add-to-list 'shr-external-rendering-functions '(svg . ignore)) ;; https://github.com/alphapapa/unpackaged.el/commit/3b46f9c0e0195d78df8c4ca6e1953b69539e2844 (defun imenu-eww-headings () "Return alist of HTML headings in current EWW buffer for Imenu. Suitable for `imenu-create-index-function'." (let ((faces '(shr-h1 shr-h2 shr-h3 shr-h4 shr-h5 shr-h6 shr-heading))) (save-excursion (save-restriction (widen) (goto-char (point-min)) (cl-loop for next-pos = (next-single-property-change (point) 'face) while next-pos do (goto-char next-pos) for face = (get-text-property (point) 'face) when (cl-typecase face (list (cl-intersection face faces)) (symbol (member face faces))) collect (cons (buffer-substring (point-at-bol) (point-at-eol)) (point)) and do (forward-line 1)))))) (add-hook 'eww-mode-hook (lambda () (setq-local imenu-create-index-function #'imenu-eww-headings))) :general (leader-map "E" #'eww) (normal eww-mode-map "go" #'eww "gb" #'eww-visit-bookmark "gB" #'eww-list-bookmarks "gJ"#'eww-jump-to-url-on-page "gV" #'eww-visit-url-on-page)) (use-package shr-tag-pre-highlight :ensure t :after shr :config (add-to-list 'shr-external-rendering-functions '(pre . shr-tag-pre-highlight))) (use-package browse-url :straight (:type built-in) :config (defun browse-url-or-search (url-or-symbol) "If URL-OR-SYMBOL is a URL, browse it. Otherwise, search for it." (interactive (list (thing-at-point 'symbol))) (if (ffap-url-p url-or-symbol) (browse-url url-or-symbol) (browse-url (format "https://www.google.com/search?q=%s" url-or-symbol)))) :custom (browse-url-browser-function 'eww-browse-url) (browse-url-handlers '(("\\`https?://docs.aws.amazon.com" . browse-url-default-browser) ("\\`https?://github.com" . browse-url-default-browser) ("\\`https?://.*.console.aws.amazon.com" . browse-url-default-browser)))) (use-package webjump :straight (:type built-in) :init (defalias 'web-search #'webjump) :general (leader-map "S" #'web-search) :custom (webjump-sites '(("Emacs Wiki" . [simple-query "www.emacswiki.org" "www.emacswiki.org/cgi-bin/wiki/" ""]) ("DuckDuckGo" . [simple-query "duckduckgo.com" "duckduckgo.com/?q=" ""]) ("Wikipedia" . [simple-query "wikipedia.org" "https://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s" ""]) ("Google" . [simple-query "google.com" "https://www.google.com/search?ie=utf-8&oe=utf-8&q=" ""]) ("StackOverflow" . [simple-query "stackoverflow.com" "https://stackoverflow.com/search?q=" ""]) ("AWS Docs" . [simple-query "docs.aws.amazon.com" "https://docs.aws.amazon.com/search/doc-search.html?searchPath=documentation&searchQuery=" ""])))) (provide 'init-eww)