Make :colourscheme --url reuse downloaded themes

Simplifies using `:colourscheme` in RC files without having
to redownload the theme every time. You can use `--update`
to force an update
This commit is contained in:
Oliver Blanthorn 2026-07-31 21:29:46 +02:00
parent 6f8cee4e40
commit 20f60a2119
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3
3 changed files with 29 additions and 6 deletions

View file

@ -39,7 +39,7 @@ Codename "Carpenter"
- ex-mode completions now fall back to documentation search for unknown commands ([#944](https://github.com/tridactyl/tridactyl/issues/944))
- `:quickmarkremove` removes a quickmark and its associated `gn`, `go`, `gw`, and `gp` bindings ([#4724](https://github.com/tridactyl/tridactyl/issues/4724))
- `:set modeindicatorshowkeys` now shows Vimperator hint filters in the mode indicator ([#1669](https://github.com/tridactyl/tridactyl/issues/1669))
- `:sanitise tridactylconfig` clears stored user configuration without removing commandline history or other local Tridactyl data ([#5472](https://github.com/tridactyl/tridactyl/issues/5472))
- `:sanitise tridactylconfig` clears stored user configuration without removing commandline history or custom themes ([#5472](https://github.com/tridactyl/tridactyl/issues/5472))
- `:unkeymap` removes key translations set with `:keymap` ([#1169](https://github.com/tridactyl/tridactyl/issues/1169))
- `completions.History.autoselect` can now select the first history completion automatically ([#1370](https://github.com/tridactyl/tridactyl/issues/1370))
- `:set searchurlopen` controls whether searchurls appear in `:open`, `:tabopen` and `:winopen` completions ([#4741](https://github.com/tridactyl/tridactyl/issues/4741))
@ -58,6 +58,7 @@ Codename "Carpenter"
- `:urlmodify --safe` prevents repeated navigation to the same URL within one second, avoiding redirect loops in `:autocmd`s ([#516](https://github.com/tridactyl/tridactyl/issues/516))
- `:set hintmames words` uses random short words for hints ([#5482](https://github.com/tridactyl/tridactyl/issues/5482))
- `superignore` can now be toggled globally from the toolbar popup ([#822](https://github.com/tridactyl/tridactyl/issues/822))
- `:colourscheme --url` reuses downloaded themes unless given `--update` to ease use in RC files
- `:ttscontrol` now supports `play`, `pause`, `playpause`, and `stop` ([#217](https://github.com/tridactyl/tridactyl/issues/217))
- `:downloads` now opens `about:downloads` in a new tab ([#615](https://github.com/tridactyl/tridactyl/issues/615))
- `:dialog` opens Firefox `about:` pages, with `:d` as an alias ([#137](https://github.com/tridactyl/tridactyl/issues/137))

View file

@ -114,6 +114,28 @@ test("`set` preserves deep custom arrays", async () => {
expect(config.getDynamic("custom", "deep", "array")).toEqual([1, 2])
})
test("`colourscheme --url` only refetches with `--update`", async () => {
const args = ["--module=reader", "--url=x", "issue5490"]
const fetchMock = jest
.fn()
.mockResolvedValueOnce({ text: async () => "" })
.mockResolvedValueOnce({ text: async () => "updated" })
const originalFetch = globalThis.fetch
globalThis.fetch = fetchMock
try {
await backgroundExcmds.colourscheme(...args)
await backgroundExcmds.colourscheme(...args)
expect(fetchMock).toHaveBeenCalledTimes(1)
await backgroundExcmds.colourscheme("--update", ...args)
expect(fetchMock).toHaveBeenCalledTimes(2)
} finally {
globalThis.fetch = originalFetch
await config.unset("customthemes", args[2])
}
})
test("`autocontaindelete` removes only the matching rule", async () => {
const pattern = "^https?://([^/]*\\.|)one\\.example/"
await config.set("autocontain", pattern, "work")

View file

@ -530,7 +530,7 @@ export async function unloadtheme(themename: string) {
*
* If THEMENAME is set to any other value except `--url`, Tridactyl will attempt to use its native binary (see [[native]]) in order to load a CSS file named THEMENAME from disk. The CSS file has to be in a directory named "themes" and this directory has to be in the same directory as your tridactylrc. If this fails, Tridactyl will attempt to load the theme from its internal storage.
*
* Themes can be loaded from URLs with `:colourscheme --url [url] [themename]`. If omitted, the theme name is inferred from the URL's filename. They are stored internally - if you want to update the theme run the whole command again. You can use `%` as a placeholder for the current URL.
* Themes can be loaded from URLs with `:colourscheme --url [url] [themename]`. If omitted, the theme name is inferred from the URL's filename. They are stored internally and reused; use `--update` with `--url` to redownload a theme. You can use `%` as a placeholder for the current URL.
*
* Themes can be used for specific sites with `:colourscheme --regex [url regex]`. As a shorthand to style our `:reader` mode, you can use `:colourscheme --module=reader`, for example, `:colourscheme --module=reader --url=https://raw.githubusercontent.com/tridactyl/tridactyl/refs/heads/master/contrib/themes/reader/newspaper.css newspaper`
*
@ -553,7 +553,7 @@ export async function unloadtheme(themename: string) {
*/
//#background
export async function colourscheme(...args: string[]) {
const option = arg.lib({ "--url": String, "--regex": String, "--module": String }, { argv: args, allowNegativePositional: true })
const option = arg.lib({ "--url": String, "--update": Boolean, "--regex": String, "--module": String }, { argv: args, allowNegativePositional: true })
let url = option["--url"]
const regex = option["--module"] == "reader" ? "moz-extension://.*/static/reader\.html" : option["--regex"]
let themename = option._[0]
@ -567,12 +567,12 @@ export async function colourscheme(...args: string[]) {
// If this is a builtin theme, no need to bother with slow stuff
if (!staticThemes.includes(themename)) {
if (themename.search("\\.") >= 0) throw new Error(`Theme name should not contain any dots! (given name: ${themename}).`)
if (url) {
if (url && (option["--update"] || !Object.keys(config.get("customthemes")).includes(themename))) {
if (url === "%") url = window.location.href // this is basically an easter egg
if (!(url.startsWith("http://") || url.startsWith("https://"))) url = "http://" + url
const css = await (await fetch(url)).text()
await set("customthemes." + themename, css)
} else {
await config.set("customthemes", themename, css)
} else if (!url) {
await loadtheme(themename)
}
}