···11-# 1.0-rc2:
22- - moved argument handling to click
33- - `qbpm launch`'s -n/--new renamed to -c/--create
11+# 2.4
22+ - `qbpm choose`: an entry named `qutebrowser` that launches qutebrowser without a profile will no longer be included by default. Set `qutebrowser_in_choose = true` in `config.toml` to restore it
33+ - `config_py_template` is no longer required to be set if `config.toml` exists
44+ - if `config_py_template` is set to an empty string, no `config.py` will be generated
55+66+# 2.3
77+ - new profiles will have a symlink to `$XDG_DATA_HOME/qutebrowser/qtwebengine_dictionaries` and thus have access to any spellchecking dictionaries have been installed for the main qutebrowser profile
88+ - `qbpm config` now has a `--help` flag
99+1010+# ~2.1~ 2.2
1111+ - `config.toml` supports `application_name` for generated XDG desktop files
1212+ - defaults to `{profile_name} (qutebrowser profile)`, you may want just `{profile_name}`
1313+ - `qbpm desktop` can be used to replace existing desktop files
1414+ - bumped to 2.2 because I pushed a 2.1 tag prematurely
1515+1616+# 2.0
1717+## config
1818+qbpm now reads configuration options from `$XDG_CONFIG_HOME/qbpm/config.toml`!
1919+ - to install the default config file:
2020+ - run `qbpm config path` and confirm that it prints out a path
2121+ - run `qbpm config default > "$(qbpm config path)"`
2222+ - supported configuration options:
2323+ - `config_py_template`: control the contents of `config.py` in new profiles
2424+ - `symlink_autoconfig`: symlink qutebrowser's `autoconfig.yml` in new profiles
2525+ - `profile_directory` and `qutebrowser_config_directory`
2626+ - equivalent to `--profile-dir` and `--qutebrowser-config-dir`
2727+ - `generate_desktop_file` and `desktop_file_directory`
2828+ - whether to generate XDG desktop entries for new profiles and where to put them
2929+ - `menu`: equivalent to `--menu` for `qbpm choose`
3030+ - `menu_prompt`: prompt shown in most menus
3131+ - see default config file for more detailed documentation
3232+3333+## other
3434+ - support for symlinking `autoconfig.yml` in addition to or instead of sourcing `config.py`
3535+ - `qbpm new --overwrite`: back up existing config files by moving to e.g. `config.py.bak`
3636+ - `contrib/qbpm.desktop`: add `MimeType` and `Keywords`, fix incorrect formatting of `Categories`
3737+ - allow help text to be slightly wider to avoid awkward line breaks
3838+ - macOS: fix detection of qutebrowser binary in `/Applications`
3939+4040+# 1.0rc4
4141+ - `choose`: support `walker`, `tofi`, and `wmenu`
4242+ - better detection of invalid/nonexistent profiles
4343+4444+# 1.0rc3
4545+ - breaking: stop sourcing files from `~/.config/qutebrowser/conf.d/`
4646+ - this was undocumented, nonstandard, and didn't work as well as it could
4747+ - switch to `pyproject.toml`
4848+ - hopefully use the right qutebrowser dirs on Windows
4949+ - `choose`: add `qutebrowser` menu item for the main qutebrowser profile
5050+ - added `-C` argument to support referencing qutebrowser configs other than the one in ~/.config
5151+ - added `click`-generated completions for bash and zsh
5252+ - added option support to fish completions
5353+ - removed `--create` from `qbpm launch`
5454+ - make generated `.desktop` files match qutebrowser's more closely
5555+5656+# 1.0rc2:
5757+ - `choose`: support `fzf` and `fuzzel`
5858+ - use `click `for CLI parsing
5959+ - `qbpm launch`'s `-n`/`--new` renamed to `-c`/`--create`
6060+ - expand fish shell completions
6161+6262+# 1.0rc1:
6363+ - add a man page
6464+6565+# 0.6
6666+ - better error handling
6767+6868+# 0.5
6969+ - `choose`: support custom menu command
7070+ - `choose`: support `dmenu-wl` and `wofi`
7171+7272+# 0.4
7373+ - `choose` subcommand (thanks, @mtoohey31!)
7474+ - load autoconfig.yml by default
7575+ - shell completions for fish
+47-53
README.md
···11# qutebrowser profile manager
2233-[](https://builds.sr.ht/~pvsr/qbpm?)
33+[](https://builds.sr.ht/~pvsr/qbpm/commits/main?)
44+[](https://pypi.python.org/pypi/qbpm)
4555-qutebrowser profile manager (qbpm) is a tool for creating and managing
66-[qutebrowser](https://github.com/qutebrowser/qutebrowser) profiles. There isn't
77-any built in concept of profiles in qutebrowser, but there is a `--basedir` flag
66+qbpm (qutebrowser profile manager) is a tool for creating, managing, and running
77+[qutebrowser](https://github.com/qutebrowser/qutebrowser) profiles. Profile support
88+isn't built in to qutebrowser, at least not directly, but it does have a `--basedir` flag
89which allows qutebrowser to use any directory as the location of its config and
910data and effectively act as a profile. qbpm creates profiles that source your
1011main qutebrowser `config.py`, but have their own separate `autoconfig.yml`, bookmarks, cookies,
1111-history, and other data. It also acts as a wrapper around qutebrowser that sets
1212-up `--basedir` for you, so you can treat `qbpm launch` as an alias for
1313-`qutebrowser`, such as to open a url: `qbpm launch my-profile example.org`.
1212+history, and other data. Profiles can be run by starting qutebrowser with the
1313+appropriate `--basedir`, or more conveniently using the `qbpm launch` and `qbpm choose` commands.
14141515qutebrowser shares session depending on the basedir, so launching the same
1616profile twice will result in two windows sharing a session, which means running
···1919instances of qutebrowser which can be opened and closed independently.
20202121## Usage
2222-Create a new profile called "python", edit its `config.py`, then launch it:
2222+To create a new profile called "python" and launch it with the python docs open:
2323```
2424$ qbpm new python
2525-$ qbpm edit python
2625$ qbpm launch python docs.python.org
2727-$ qbpm choose # run dmenu or another launcher to pick a profile
2826```
29273030-`qbpm from-session` can copy the tabs of a [saved qutebrowser
3131-session](https://qutebrowser.org/doc/help/commands.html#session-save) to a new
3232-profile. If you have a window full of tabs related to planning a vacation, you
3333-could save it to a session called "vacation" using `:session-save -o vacation`
3434-in qutebrowser, then create a new profile with those tabs:
3535-```
3636-$ qbpm from-session vacation
3737-```
2828+Note that all arguments after `qbpm launch PROFILE` are passed to qutebrowser,
2929+so options can be passed too: `qbpm launch python --target window pypi.org`.
3030+3131+If you have multiple profiles you can use `qbpm choose` to bring up a list of
3232+profiles and select one to launch. Depending on what your system has available
3333+the menu may be `dmenu`, `fuzzel`, `fzf`, an applescript dialog, or one of many
3434+other menu programs qbpm can detect. Any dmenu-compatible menu can be used with
3535+`--menu`, e.g. `qbpm choose --menu 'fuzzel --dmenu'`. As with `qbpm launch`,
3636+extra arguments are passed to qutebrowser.
38373939-The default profile directory is `$XDG_DATA_HOME/qutebrowser-profiles`, where
4040-`$XDG_DATA_HOME` is usually `$HOME/.local/share`, but you can create and launch
4141-profiles from anywhere using `--profile-dir`/`-P`:
4242-```
4343-$ qbpm --profile-dir ~/dev/my-project new qb-profile
4444-$ cd ~/dev/my-project
4545-$ qbpm -P . launch qb-profile
4646-# or
4747-$ qutebrowser --basedir qb-profile
4848-```
3838+Run `qbpm --help` to see other available commands.
3939+4040+By default when you create a new profile a `.desktop` file is created that
4141+launches the profile. This launcher does not depend on qbpm at all, so if you
4242+want you can run `qbpm new` once and keep using the profile without needing
4343+qbpm installed on your system.
49445045## Installation
5151- - Pip: `pip install git+https://github.com/pvsr/qbpm.git#egg=qbpm`
5252- - Arch: [qbpm-git](https://aur.archlinux.org/packages/qbpm-git) in the AUR
5353- - Nix: clone the repository and run `nix-env -if default.nix`
5454- - MacOS: For command-line only usage, the pip command above is sufficient, but
5555- if you would like to set qbpm as the default browser app, first clone this
5656- repository, then install platypus by running `brew install playtpus`, and
5757- finally install the app by running `platypus -P contrib/qbpm.platypus
5858- /Applications/qbpm.app` inside the cloned repository. You should then be
5959- able to select qbpm as your default browser under: System Preferences
6060- \> General > Default web browser. Note that there is currently [an
6161- issue](https://github.com/qutebrowser/qutebrowser/issues/3719) with
6262- qutebrowser itself that results in unnecessary `file:///*` tabs being
6363- opened.
6464- - If you're on linux, you can copy `contrib/qbpm.desktop` to `~/.local/share/applications`.
6565- That desktop entry will run `qbpm choose`, which shows an application
6666- launcher (dmenu or rofi) with your qutebrowser profiles as the options.
4646+If you use Nix, you can install or run qbpm as a [Nix flake](https://nixos.wiki/wiki/Flakes).
4747+For example, to run qbpm without installing it you can use `nix run github:pvsr/qbpm -- new my-profile`.
67486868-## Future ideas that may or may not happen
6969-- Release through github
7070-- More shared or copied config and data
7171-- Use any profile as a base for new profiles (currently only the main config in
7272- `$XDG_CONFIG_HOME` is supported)
7373-- Source `autoconfig.yml` instead of `config.py`
7474-- Bundled config file optimized for single-site browsing
7575-- `qbpm.conf` to configure the features above
7676-- Someday: qutebrowser plugin
4949+On Arch and derivatives, you can install the AUR package: [qbpm-git](https://aur.archlinux.org/packages/qbpm-git).
5050+5151+Otherwise you can install directly from PyPI using [uv](https://docs.astral.sh/uv/guides/tools/),
5252+pip, or your preferred client. With uv it's `uv tool run qbpm` to run qbpm
5353+without installing and `uv tool install qbpm` to install to `~/.local/bin`.
5454+The downside of going through PyPI is that the [man page](https://github.com/pvsr/qbpm/blob/main/qbpm.1.scd)
5555+and shell completions will not be installed automatically.
5656+5757+On Linux you can copy [`contrib/qbpm.desktop`](https://raw.githubusercontent.com/pvsr/qbpm/main/contrib/qbpm.desktop)
5858+to `~/.local/share/applications` to create a qbpm desktop application that runs
5959+`qbpm choose`.
6060+6161+### MacOS
6262+6363+Nix and uv will install qbpm as a command-line application, but if you want a
6464+native Mac application you can download [`contrib/qbpm.platypus`](https://raw.githubusercontent.com/pvsr/qbpm/main/contrib/qbpm.platypus),
6565+install [platypus](https://sveinbjorn.org/platypus), and create a qbpm app with
6666+`platypus -P qbpm.platypus /Applications/qbpm.app`. That will also make qbpm
6767+available as a default browser in `System Preferences > General > Default web browser`.
6868+6969+Note that there is currently [a qutebrowser bug](https://github.com/qutebrowser/qutebrowser/issues/3719)
7070+that results in unnecessary `file:///*` tabs being opened.
+25-9
completions/qbpm.fish
···11function __fish_qbpm
22- set -l saved_args $argv
33- set -l global_args
44- set -l cmd (commandline -opc)
55- set -e cmd[1]
66- argparse -si P/profile-dir= -- $cmd 2>/dev/null
77- set -q _flag_P
88- and set global_args "-P $_flag_P"
99- eval qbpm $global_args $saved_args
22+ set -l saved_args $argv
33+ set -l global_args
44+ set -l cmd (commandline -opc)
55+ set -e cmd[1]
66+ argparse -si P/profile-dir= -- $cmd 2>/dev/null
77+ set -q _flag_P
88+ and set global_args "-P $_flag_P"
99+ eval qbpm $global_args $saved_args
1010end
11111212set -l commands new from-session desktop launch list edit choose
1313+set -l data_home (set -q XDG_DATA_HOME; and echo $XDG_DATA_HOME; or echo ~/.local/share)
13141415complete -c qbpm -f
1616+complete -c qbpm -s h -l help
1717+complete -c qbpm -s l -l log-level -a "debug info error"
1818+complete -c qbpm -s C -l config-dir -r
1919+complete -c qbpm -s P -l profile-dir -r
2020+1521complete -c qbpm -n "not __fish_seen_subcommand_from $commands" -a "$commands"
2222+2323+complete -c qbpm -n "__fish_seen_subcommand_from new from_session" -s l -l launch
2424+complete -c qbpm -n "__fish_seen_subcommand_from new from_session" -l desktop-file
2525+complete -c qbpm -n "__fish_seen_subcommand_from new from_session" -l no-desktop-file
2626+complete -c qbpm -n "__fish_seen_subcommand_from new from_session" -l overwrite
2727+complete -c qbpm -n "__fish_seen_subcommand_from new from_session launch choose" -s f -l foreground
2828+2929+complete -c qbpm -n "__fish_seen_subcommand_from launch" -s c -l create
3030+complete -c qbpm -n "__fish_seen_subcommand_from choose" -s m -l menu -r
3131+complete -c qbpm -n "__fish_seen_subcommand_from launch choose" -w qutebrowser
3232+1633complete -c qbpm -n "__fish_seen_subcommand_from launch edit desktop" -a "(__fish_qbpm list)"
1717-set -l data_home (set -q XDG_DATA_HOME; and echo $XDG_DATA_HOME; or echo ~/.local/share)
1834complete -c qbpm -n "__fish_seen_subcommand_from from-session" -a "(ls $data_home/qutebrowser/sessions | xargs basename -a -s .yml)"
···11-import platform
22-from collections.abc import Generator
33-from os import environ
44-from pathlib import Path
55-from shutil import which
66-from sys import exit, stderr
77-88-from xdg import BaseDirectory
99-1010-WAYLAND_MENUS = ["fuzzel", "wofi", "dmenu-wl"]
1111-X11_MENUS = ["rofi", "dmenu"]
1212-AUTO_MENUS = WAYLAND_MENUS + X11_MENUS
1313-SUPPORTED_MENUS = AUTO_MENUS + ["fzf", "applescript"]
1414-1515-1616-def error(msg: str) -> None:
1717- print(f"error: {msg}", file=stderr)
1818-1919-2020-def default_profile_dir() -> Path:
2121- return Path(BaseDirectory.save_data_path("qutebrowser-profiles"))
2222-2323-2424-def user_data_dir() -> Path:
2525- if platform.system() == "Linux":
2626- return Path(BaseDirectory.xdg_data_home) / "qutebrowser"
2727- if platform.system() == "Darwin":
2828- return Path.home() / "Library" / "Application Support" / "qutebrowser"
2929- error("This operation is only implemented for linux and macOS.")
3030- print(
3131- "If you're interested in adding support for another OS, send a PR "
3232- "to github.com/pvsr/qbpm adding the location of qutebrowser data such "
3333- "as history.sqlite on your OS to user_data_dir() in qbpm/utils.py.",
3434- file=stderr,
3535- )
3636- exit(1)
3737-3838-3939-def user_config_dir() -> Path:
4040- return Path(BaseDirectory.xdg_config_home) / "qutebrowser"
4141-4242-4343-def installed_menus() -> Generator[str, None, None]:
4444- if platform.system() == "Darwin":
4545- yield "applescript"
4646- if environ.get("WAYLAND_DISPLAY"):
4747- for menu_cmd in WAYLAND_MENUS:
4848- if which(menu_cmd) is not None:
4949- yield menu_cmd
5050- if environ.get("DISPLAY"):
5151- for menu_cmd in X11_MENUS:
5252- if which(menu_cmd) is not None:
5353- yield menu_cmd
5454- if environ.get("TMUX") and which("fzf-tmux") is not None:
5555- yield "fzf-tmux"
5656- # if there's no display and fzf is installed we're probably(?) in a term
5757- if which("fzf") is not None:
5858- print("no graphical launchers found, trying fzf", file=stderr)
5959- yield "fzf"
+43-26
qbpm.1.scd
···6677# SYNOPSIS
8899-*qbpm* [--profile-dir=<path>|-P <path>] <command> [<args>]
99+*qbpm* [--profile-dir=<path>|-P <path>] [--config-file|-c <path>] <command> [<args>]
10101111# DESCRIPTION
12121313-qbpm is a tool for creating and running qutebrowser profiles. qutebrowser
1414-doesn't have a native concept of profiles, but it does have a --basedir flag
1515-that allows qutebrowser's config, cache, and data to be stored in any directory.
1616-So a profile is simply a directory meant to be set as qutebrowser's basedir.
1717-qbpm creates profiles that source the config.py from your qutebrowser config dir
1818-in $XDG_CONFIG_HOME (typically $HOME/.config/qutebrowser). By default profiles
1919-are stored in a qutebrowser-profiles/ dir in $XDG_DATA_HOME (typically
2020-$HOME/.local/share), but this can be set to another directory by passing
2121-\--profile-dir to qbpm or setting the $QBPM_PROFILE_DIR environment variable.
1313+qbpm is a tool for creating, managing, and running qutebrowser profiles. Profile support
1414+isn't built in to qutebrowser, at least not directly, but it does have a \--basedir flag
1515+which allows qutebrowser to use any directory as the location of its config and
1616+data and effectively act as a profile. qbpm creates profiles that source your
1717+main qutebrowser config.py, but have their own separate autoconfig.yml, bookmarks, cookies,
1818+history, and other data. Profiles can be run by starting qutebrowser with the
1919+appropriate \--basedir, or more conveniently using the qbpm launch and qbpm choose commands.
22202321# OPTIONS
2422···3230 Use _path_ as the profile directory instead of the default location. Takes
3331 precedence over the QBPM_PROFILE_DIR environment variable.
34323333+*-c, --config-file* <path>
3434+ Read configuration for qbpm from _path_. Defaults to ~/.config/qbpm/config.toml.
3535+3536# COMMANDS
36373738*new* [options] <profile> [<url>]
3839 Create a new qutebrowser profile named _profile_. If _url_ is present it will
3939- be used as the profile's home page. By default, a .desktop file will be
4040- created for the profile in $XDG_DATA_HOME/applications/qbpm/.
4040+ be used as the profile's home page.
41414242 Options:
4343···4747 *-f, --foreground*
4848 If --launch is set, run qutebrowser in the foreground.
49495050- *--no-desktop-file*
5151- Do not generate a .desktop file for the profile.
5050+ *-C, --qutebrowser-config-dir* <path>
5151+ Source config files from the provided directory instead of the global
5252+ qutebrowser config location.
5353+5454+ *--desktop-file/--no-desktop-file*
5555+ Whether to generate an XDG desktop entry for the profile. Only relevant
5656+ on linux systems. See https://wiki.archlinux.org/title/Desktop_entries
5757+ for information on desktop entries.
52585359 *--overwrite*
5460 By default qbpm will refuse to create a profile if one with the same name
5555- already exists. --overwrite disables this check and rewrites the existing
5656- profile's configuration files from scratch. Profile data is left untouched.
6161+ already exists. --overwrite disables this check and replaces the existing
6262+ profile's configuration files. Profile data is left untouched.
57635858-*launch* [options] <profile> [argument...]
6464+*launch* [options] <profile> [arguments...]
5965 Start qutebrowser with --basedir set to the location of _profile_. All
6066 arguments following _profile_ will be passed on to qutebrowser.
6167···7379 \# launch my profile called work and open internal.mycompany.com
7480 qbpm launch work internal.mycompany.com
75817676- \# launch a new profile called qb-dev, passing the flags to qutebrowser
8282+ \# launch a new profile called qb-dev, passing the debugging flags to qutebrowser
7783 qbpm launch -n qb-dev --debug --json-logging
7884 ```
79858080-*choose* [options]
8686+*choose* [options] [arguments...]
8187 Open a menu to choose a qutebrowser profile to launch. On linux this defaults
8288 to dmenu or another compatible menu program such as rofi, and on macOS this
8383- will be an applescript dialog.
8989+ will be an applescript dialog. All arguments are passed to qutebrowser.
84908591 *-m, --menu* <menu>
8692 Use _menu_ instead of the default menu program. This may be the name of a
8793 program on $PATH or a path to a program, in which case it will be run in
8888- dmenu mode if qbpm knows about the program, or a full command line.
9494+ dmenu mode if qbpm knows about the program, or a full command line. On
9595+ MacOS the special value "applescript" is accepted. Run `qbpm choose --help`
9696+ for a list of known menu programs for your environment.
89979098 Examples:
919992100 ```
9393- \# runs "echo {profiles} | /path/to/rofi -dmenu -no-custom -p qutebrowser"
9494- qbpm choose -m /path/to/rofi
101101+ qbpm choose --menu fzf
951029696- qbpm choose -m "my-cool-menu --dmenu-mode --prompt qutebrowser"
103103+ qbpm choose --menu "./build/my-cool-menu --dmenu-mode --prompt qutebrowser"
104104+105105+ \# qbpm knows about fuzzel so it can automatically invoke it as "~/.local/bin/fuzzel --dmenu"
106106+ qbpm choose --menu ~/.local/bin/fuzzel
107107+108108+ \# if more than one word is provided it will be invoked as is, so `--dmenu` must be included
109109+ qbpm choose --menu 'fuzzel --dmenu --width 100'
97110 ```
9811199112*from-session* [options] <session> [<name>]
···104117 *new*.
105118106119*desktop* <profile>
107107- Generate a .desktop file for _profile_.
120120+ Generate an XDG desktop entry for _profile_.
108121109122*edit* <profile>
110123 Open _profile_'s config.py in your default editor.
···116129117130Peter Rice
118131119119-Contribute at https://github.com/pvsr/qbpm
132132+# CONTRIBUTE
133133+134134+_https://github.com/pvsr/qbpm_
135135+136136+_https://codeberg.org/pvsr/qbpm_
···11+# template that new config.py files are generated from
22+# supported placeholders: {profile_name}, {source_config_py}
33+config_py_template = """
44+config.source(r'{source_config_py}')
55+66+c.window.title_format += ' ({profile_name})'
77+88+config.load_autoconfig()
99+"""
1010+1111+# symlink autoconfig.yml in new profiles if the os supports it
1212+# symlink_autoconfig = false
1313+1414+# location to store qutebrowser profiles
1515+# profile_directory = "~/.local/share/qutebrowser-profiles"
1616+1717+# location of the qutebrowser config to inherit from
1818+# qutebrowser_config_directory = "~/.config/qutebrowser"
1919+2020+# when creating a profile also generate an XDG desktop file that launches the profile
2121+# defaults to true on linux
2222+# generate_desktop_file = false
2323+# desktop_file_directory = "~/.local/share/applications/qbpm"
2424+2525+# application name in XDG desktop file (replace existing with `qbpm desktop PROFILE_NAME`)
2626+# supported placeholders: {profile_name}
2727+# application_name = "{profile_name} (qutebrowser profile)"
2828+2929+# profile selection menu for `qbpm choose`
3030+# when not set, qbpm will try to find a menu program on your $PATH
3131+# run `qbpm choose --help` for a list of known menu programs
3232+# if menu is a known menu, dmenu-mode flags are set automatically
3333+# menu = "fuzzel" # gets turned into "fuzzel --dmenu", /path/to/fuzzel also works
3434+# otherwise menu must be a dmenu-compatible commandline
3535+# supported placeholders: {prompt}, {qb_args}
3636+# menu = "~/bin/my-dmenu"
3737+# menu = "fuzzel --dmenu --prompt '{prompt}> ' --lines 20 --width 50"
3838+# optionally menu can be written as a list to simplify quoting
3939+# menu = ["fuzzel", "--dmenu", "--prompt", "{prompt}> ", "--lines", "20", "--width", "50"]
4040+4141+# value of {prompt} in menu commands
4242+# supported placeholders: {qb_args}
4343+# defaults to "qutebrowser"
4444+# menu_prompt = "qbpm"
4545+# menu_prompt = "profiles"
4646+# menu_prompt = "qutebrowser {qb_args}"
4747+4848+# include a `qutebrowser` entry in `qbpm choose` that starts qutebrowser without a profile
4949+# qutebrowser_in_choose = false