From c5286d132bb1afa6078b45e0f7df9ecdecf104ce Mon Sep 17 00:00:00 2001 From: Daniel Mendler Date: Wed, 11 Dec 2024 07:36:16 +0100 Subject: [PATCH] Add `browse-url-qutebrowser' The browser launcher supports the NEW-WINDOW argument and `browse-url-qutebrowser-new-window-is-tab' to open tabs. Furthermore opening new URLs is sped up via Unix socket IPC if available. * lisp/net/browse-url.el (browse-url-qutebrowser-send): Function to send command to Qutebrowser via IPC. (browse-url-qutebrowser): New browser launcher. Use `browse-url-qutebrowser-send'. (browse-url-qutebrowser-program, browse-url-qutebrowser-arguments) (browse-url-qutebrowser-new-window-is-tab): New customizables. (browse-url-mozilla-new-window-is-tab) (browse-url-firefox-new-window-is-tab) (browse-url-epiphany-new-window-is-tab): Improve docstrings. * etc/NEWS: Announce the change. --- etc/NEWS | 6 +++ lisp/net/browse-url.el | 93 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 043e55edf3e..add18c68d4e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -296,6 +296,12 @@ modal editing packages. * Changes in Specialized Modes and Packages in Emacs 31.1 +** Browse URL + +*** New function 'browse-url-qutebrowser' for the Qutebrowser. +For better integration with the Qutebrowser, set +'browse-url(-secondary)-browser-function' to 'browse-url-qutebrowser'. + ** CL-Lib +++ *** 'cl-labels' now also accepts (FUNC EXP) bindings, like 'cl-flet'. diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 8ec025d017b..e96a24d3ff1 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -140,6 +140,7 @@ ;;; Code: (require 'url) +(require 'xdg) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Variables @@ -342,6 +343,16 @@ browse-url-epiphany-startup-arguments `browse-url' is loaded." :type '(repeat (string :tag "Argument"))) +(defcustom browse-url-qutebrowser-program "qutebrowser" + "The name by which to invoke Qutebrowser." + :type 'string + :version "31.1") + +(defcustom browse-url-qutebrowser-arguments nil + "A list of strings to pass to Qutebrowser when it starts up." + :type '(repeat (string :tag "Argument")) + :version "31.1") + (defcustom browse-url-webpositive-program "WebPositive" "The name by which to invoke WebPositive." :type 'string @@ -360,33 +371,45 @@ browse-url-gnome-moz-arguments (make-obsolete-variable 'browse-url-gnome-moz-arguments nil "25.1") (defcustom browse-url-mozilla-new-window-is-tab nil - "Whether to open up new windows in a tab or a new window. + "Whether to open up new Mozilla windows in a tab or a new window. If non-nil, then open the URL in a new tab rather than a new window if -`browse-url-mozilla' is asked to open it in a new window." +`browse-url-mozilla' is asked to open it in a new window via the +NEW-WINDOW argument." :type 'boolean) (make-obsolete-variable 'browse-url-mozilla-new-window-is-tab nil "29.1") (defcustom browse-url-firefox-new-window-is-tab nil - "Whether to open up new windows in a tab or a new window. + "Whether to open up new Firefox windows in a tab or a new window. If non-nil, then open the URL in a new tab rather than a new window if -`browse-url-firefox' is asked to open it in a new window." +`browse-url-firefox' is asked to open it in a new window via the +NEW-WINDOW argument." :type 'boolean) (defcustom browse-url-conkeror-new-window-is-buffer nil - "Whether to open up new windows in a buffer or a new window. + "Whether to open up new Conkeror windows in a buffer or a new window. If non-nil, then open the URL in a new buffer rather than a new window if -`browse-url-conkeror' is asked to open it in a new window." +`browse-url-conkeror' is asked to open it in a new window via the +NEW-WINDOW argument." :version "25.1" :type 'boolean) (make-obsolete-variable 'browse-url-conkeror-new-window-is-buffer nil "28.1") (defcustom browse-url-epiphany-new-window-is-tab nil - "Whether to open up new windows in a tab or a new window. + "Whether to open up new Epiphany windows in a tab or a new window. If non-nil, then open the URL in a new tab rather than a new window if -`browse-url-epiphany' is asked to open it in a new window." +`browse-url-epiphany' is asked to open it in a new window via the +NEW-WINDOW argument." :type 'boolean) +(defcustom browse-url-qutebrowser-new-window-is-tab nil + "Whether to open up new Qutebrowser windows in a tab or a new window. +If non-nil, then open the URL in a new tab rather than a new window if +`browse-url-qutebrowser' is asked to open it in a new window via the +NEW-WINDOW argument." + :type 'boolean + :version "31.1") + (defcustom browse-url-new-window-flag nil "Non-nil means always open a new browser window with appropriate browsers. Passing an interactive argument to \\[browse-url], or specific browser @@ -1294,6 +1317,60 @@ browse-url-epiphany-sentinel browse-url-epiphany-program (append browse-url-epiphany-startup-arguments (list url)))))) +(defun browse-url-qutebrowser-send (cmd) + "Send CMD to Qutebrowser via IPC." + (let* ((dir (xdg-runtime-dir)) + (sock (and dir (expand-file-name + (format "qutebrowser/ipc-%s" (md5 (user-login-name))) + dir)))) + (unless (file-exists-p sock) + (error "No Qutebrowser IPC socket found")) + (let ((proc + (make-network-process + :name "qutebrowser" + :family 'local + :service sock + :coding 'utf-8))) + (unwind-protect + (process-send-string + proc + (concat + (json-serialize `( :args [,cmd] + :target_arg :null + :protocol_version 1)) + "\n")) + (delete-process proc))))) + +(defun browse-url-qutebrowser (url &optional new-window) + "Ask the Qutebrowser WWW browser to load URL. +Default to the URL around or before point. + +When called interactively, if variable `browse-url-new-window-flag' is +non-nil, load the document in a new Qutebrowser window, otherwise use a +random existing one. A non-nil interactive prefix argument reverses +the effect of `browse-url-new-window-flag'. + +If `browse-url-qutebrowser-new-window-is-tab' is non-nil, then whenever a +document would otherwise be loaded in a new window, it is loaded in a +new tab in an existing window instead. + +When called non-interactively, optional second argument NEW-WINDOW is +used instead of `browse-url-new-window-flag'." + (interactive (browse-url-interactive-arg "URL: ")) + (let ((cmd (concat ":open " + (and (browse-url-maybe-new-window new-window) + (if browse-url-qutebrowser-new-window-is-tab + "-t " "-w ")) + (browse-url-encode-url url)))) + (condition-case nil + (browse-url-qutebrowser-send cmd) + (error + (apply #'start-process (concat "qutebrowser " url) nil + browse-url-qutebrowser-program + (append browse-url-qutebrowser-arguments (list cmd))))))) + +(function-put 'browse-url-qutebrowser 'browse-url-browser-kind 'external) + (defvar url-handler-regexp) ;;;###autoload -- 2.45.2