11

M-x eww prompts for url or keywords and opens a new *eww* buffer. In eww-mode, G is bound to eww, which replaces the content of the single eww buffer.

To make multiple buffers for different webpages, I've resorted to creating a new buffer, setting eww-mode manually, then pressing G (or M-x eww) to visit a URL.

I can easily write a function that does all this for me, but I'm surprised this functionality isn't just built-in. Am I just missing it?

R. P. Dillon
  • 415
  • 3
  • 11
  • Emacs 27 now adds support for calling `eww` with a prefix argument; see my answer below. – Basil Mar 22 '19 at 12:22

5 Answers5

7

You are correct that eww does not automatically create new buffers for you. But I have been using this trick from ergoemacs.org and it works great!

With the below eval'ed, each time you do M-x eww from a non-eww buffer, a unique eww buffer will be created.

;; Auto-rename new eww buffers
(defun xah-rename-eww-hook ()
  "Rename eww browser's buffer so sites open in new page."
  (rename-buffer "eww" t))
(add-hook 'eww-mode-hook #'xah-rename-eww-hook)

If you'd like to spawn a new eww buffer while being in an eww buffer, eval the below advice (you will still need to eval the above so that new eww buffers are assigned unique names).

;; C-u M-x eww will force a new eww buffer
(defun modi/force-new-eww-buffer (orig-fun &rest args)
  "When prefix argument is used, a new eww buffer will be created,
regardless of whether the current buffer is in `eww-mode'."
  (if current-prefix-arg
      (with-temp-buffer
        (apply orig-fun args))
    (apply orig-fun args)))  
(advice-add 'eww :around #'modi/force-new-eww-buffer)
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
  • This doesn't seem to work for me in Emacs 25 (I'm building from master). I did get a partial fix using `rename-uniquely`, though, which is effective if I activate `eww` from a non-eww buffer. If I'm in an eww buffer, however, the hook doesn't fire, because the mode isn't changing. At least I think that's whats happening. – R. P. Dillon Jul 08 '16 at 21:49
  • You're right. What I posted works exactly as intended only if you do `M-x eww` from a non-eww buffer. It was not clear if you were intending to have a new eww buffer spawn while in an eww buffer. I'll update the solution if I come up with something. I am also on the latest build of master. – Kaushal Modi Jul 08 '16 at 22:01
  • This behavior is in the design of the `eww` function as seen in the source code: `(pop-to-buffer-same-window (if (eq major-mode 'eww-mode) (current-buffer) (get-buffer-create "*eww*")))`. – Kaushal Modi Jul 08 '16 at 22:04
  • @R.P.Dillon See the the update with the advice works for you. – Kaushal Modi Jul 08 '16 at 22:17
  • Thanks for the update! The approach using advice doesn't seem to fire, actually. I'm thinking a simpler approach using a function might suit me best. – R. P. Dillon Jul 08 '16 at 22:25
  • @R.P.Dillon Hmm, odd. It tested to work fine for me. You can also wrap the `(with-temp-buffer ..)` form in a separate interactive form. I like advices as I can use the default `G` binding as usual (without having to create new bindings), and still be able to do `C-u G` to force create new eww buffer. I even tested this to work in `emacs -Q`. Make sure that you kill **all** eww buffers, eval all of the above elisp and then do `M-x eww ..`. Then do `C-u G ..`. – Kaushal Modi Jul 08 '16 at 22:31
  • This is nuts, it must be Emacs 25. I'm using `emacs -q` and failing to get `C-u M-x eww` to spawn the temp buffer. To be clear, I'm evaling the code above (both lines), and then `C-u M-x eww google.com` and then, from that buffer, executing `C-u M-x eww yahoo.com`. Yahoo opens in the same buffer, replacing Google. I've verified the advice is firing when it should by adding `message` statements in each branch, which makes me think the `with-temp-buffer` isn't working correctly with eww in Emacs 25. – R. P. Dillon Jul 08 '16 at 22:45
  • You'll need to evaluate all the 4 forms (2 forms related to the auto-renaming and 2 forms related to the advice). I am not using anything master branch specific in this code. I expect it to work fine on 24.5 too. The best way to check if the hook and advice got add are to do `C-h v` for the hook var and `C-h f` for the function (`eww`). – Kaushal Modi Jul 08 '16 at 22:49
5

Update

This behaviour was discussed in bug#34374 and merged on 2019-02-15.

So in Emacs 27, calling eww with a prefix argument tells it to use a new buffer instead of reusing the default *eww* buffer.


I'm surprised this functionality isn't just built-in. Am I just missing it?

Yes and no. Similar functionality was added in Emacs 26 as the command eww-open-in-new-buffer, which is bound to M-RET in EWW buffers by default:

eww-open-in-new-buffer is an interactive compiled Lisp function in
‘eww.el’.

It is bound to M-RET, <menu-bar> <Eww> <Follow URL in new buffer>.

(eww-open-in-new-buffer)

Fetch link at point in a new EWW buffer.

The only problem is that, at the time of writing, this command is limited to working only in EWW buffers. In particular, it throws a user-error if no meaningful link is found at point, as determined by the user option eww-suggest-uris:

eww-suggest-uris is a variable defined in ‘eww.el’.
Its value is
(eww-links-at-point url-get-url-at-point eww-current-url)

Documentation:
List of functions called to form the list of default URIs for ‘eww’.
Each of the elements is a function returning either a string or a list
of strings.  The results will be joined into a single list with
duplicate entries (if any) removed.

You can customize this variable.

This variable was introduced, or its default value was changed, in
version 25.1 of Emacs.

A further limitation of the command is that it does not prompt the user for a URL or search terms, as the command eww would.

Here's a simple example of how you could bridge these differences between eww and eww-open-in-new-buffer:

(defun my-eww-new-buffer (url)
  "Like `eww', but fetch URL in a new EWW buffer."
  (interactive (advice-eval-interactive-spec (cadr (interactive-form 'eww))))
  (let ((eww-suggest-uris (list (lambda () url))))
    (eww-open-in-new-buffer)))

What this does is first call the interactive spec of eww, which prompts for URLs or search terms as usual. It then calls eww-open-in-new-buffer with the previously input URLs or search terms as the only suggested URI, so that the command does not throw a tantrum.

This command will work both within and without EWW buffers, so it can act as a drop-in replacement for the default eww-open-in-new-buffer, if you prefer:

(with-eval-after-load 'eww
  (define-key eww-mode-map [remap eww-open-in-new-buffer] #'my-eww-new-buffer))

Either way, you can invoke it from anywhere as M-xmy-eww-new-bufferRET or bind it globally to a more convenient key.

Basil
  • 12,019
  • 43
  • 69
3

It seems eww is designed to avoid this behavior. This function, eww-new, can be called when a new eww buffer is desired:

(defun eww-new ()
  (interactive)
  (let ((url (read-from-minibuffer "Enter URL or keywords: ")))
    (switch-to-buffer (generate-new-buffer "eww"))
    (eww-mode)
    (eww url)))
R. P. Dillon
  • 415
  • 3
  • 11
0

I extended a bit R. P. Dillon snippet. Which make it good candidate to create alias like (defalias 'w #'af/eww) and open eww using function below. The only difference is conditional check if the *eww* buffer already exists, then new one is created, if not the native eww is invoked.

(defun af/eww ()
  (interactive)
  (let ((eww-current-buffer (get-buffer "*eww*"))
         (url nil))
    (if (eq eww-current-buffer nil)
      (eww)
      (setq url (read-from-minibuffer "Enter URL or keywords: "))
      (switch-to-buffer (generate-new-buffer "eww"))
      (eww-mode)
      (eww url)
    )))
Navidot
  • 732
  • 5
  • 12
0

I use Emacs 25.1 and eww-open-in-new-buffer function isn't there. So I have to rename the eww buffer I'm in, usually with some easy title about the page I'm in, and calling again eww from any other buffer opened in Emacs (by example from the buffer-mode buffer, or dired buffers, from scratch, another document, any) takes me to another eww buffer. Finally I go with S to the eww buffers list to select from there. Odd but it works, and with few steps. I wonder why eww-new wasn't built-in from start. Of course it is cleaner with the code above, I'll give that a try. I'm glad to see that the function was added in Emacs 26.

techapu
  • 1
  • 2
  • In Emacs 27, calling `eww` with a prefix argument now creates a new EWW buffer; see my answer above. – Basil Mar 22 '19 at 12:19
  • If you don't want to invent a new buffer name, go with `M-x rename-uniquely`. – Stefan Mar 22 '19 at 13:18
  • Thank you Stefan for the tip. I have Debian 9 and I'm so far of Emacs 27 :( – techapu Apr 02 '19 at 10:15
  • Anyway I'll have to update my Emacs, I use the built-in browser all the time. And w3m breaks my flow with the tabs. Eww is practical and it's all I need. This feature is really important, thanks Basil for the update, the custom command you share seems a clever alternative to the standard behavior. I go between the org files, the info buffers, the terminals and the eww browser all the time and it would be nice to have eww at hand without burying the previous page. – techapu Apr 02 '19 at 10:25
  • @Stefan the problem I see with that solution is that I need to know what in the buffer so I'm returning later there . What would be the rename-uniquely output? – techapu Apr 02 '19 at 10:33