diff --git a/README.md b/README.md
index 73f9563..b122226 100644
--- a/README.md
+++ b/README.md
@@ -176,7 +176,7 @@ The following is a table of the available subcommands for the CLI tool (Tinty),
| `sync` | Installs and updates schemes and templates defined in `tinty/config.toml` | - | `tinty sync` |
| `list` | Lists all available themes. | Optional argument `--custom-schemes` to list saved custom theme files using `tinty generate-scheme`.
Optional argument `--json` to output more info about each scheme in JSON form | `tinty list` |
| `apply` | Applies a specific theme. | `-`: Name of the system and scheme to apply. | `tinty apply base16-mocha` |
-| `cycle` | Applies the next theme among your preferred ones. See [Configuration](#configuration). | | `tinty cycle` |
+| `cycle` | Applies the next theme in a configured ring. See [Configuration](#configuration). | Optional `--ring ` to choose a specific ring. | `tinty cycle --ring dark` |
| `init` | Initializes the tool with the last applied theme otherwise `default-scheme` from `config.toml`. | - | `tinty init` |
| `current` | Displays the currently applied theme or current theme values. | `` (Optional argument with the following supported values: `author` \| `description` \| `name` \| `slug` \| `system` \| `variant`) | `tinty current` |
| `config` | Displays config related information currently in use by Tinty. Without flags it returns `config.yml` content. | - | `tinty config` |
@@ -220,10 +220,19 @@ to your preferences and environment.
|-------------------|--------------------|----------|----------------------------------------------------------------------------------------|---------|---------|
| `shell` | `string` | Optional | Specifies the shell command used to execute hooks. | `"sh -c '{}'"` | `shell = "bash -c '{}'"` |
| `default-scheme` | `string` | Optional | Defines the default theme scheme to be applied if no specific scheme is set. | None | `default-scheme = "base16-mocha"` |
-| `preferred-schemes` | `array` | Optional | A list of your favorite theme schemes you'd like to cycle through | `[]` | `preferred-schemes = ["base16-gruvbox-dark", "base16-gruvbox-light"]` |
+| `default-cycle-ring` | `string` | Optional | The configured ring used by `tinty cycle` when `--ring` is not provided. | None | `default-cycle-ring = "default"` |
+| `[[rings]]` | `array` | Optional | Named scheme cycles used by `tinty cycle`. | - | See below |
| `hooks` | `array` | Optional | A list of strings which are executed after every `tinty apply` | None | `hooks = ["echo \"The current scheme is: $(tinty current)\""]` |
| `[[items]]` | `array` | Required | An array of `items` configurations. Each item represents a themeable component. Detailed structure provided in the next section. | - | - |
+```toml
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = ["base16-gruvbox-dark", "base16-gruvbox-light"]
+```
+
#### hooks
**New in Tinty 0.29+**: Theme & color values are now available to hooks as environment variables:
@@ -326,7 +335,15 @@ multiple items along with global settings:
# Global settings
shell = "zsh -c '{}'"
default-scheme = "base16-mocha"
-preferred-schemes = ["base16-gruvbox-dark", "base16-gruvbox-light", "base16-github-dark"]
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = ["base16-gruvbox-dark", "base16-gruvbox-light", "base16-github-dark"]
+
+[[rings]]
+name = "dark"
+schemes = ["base16-gruvbox-dark", "base16-github-dark"]
# Item configurations
[[items]]
diff --git a/contrib/completion/tinty.bash b/contrib/completion/tinty.bash
index 6a440ef..ceefced 100644
--- a/contrib/completion/tinty.bash
+++ b/contrib/completion/tinty.bash
@@ -253,12 +253,19 @@ _tinty() {
return 0
;;
tinty__cycle)
- opts="-q -c -d -h --quiet --config --data-dir --help"
+ opts="-q -c -d -h --ring --quiet --config --data-dir --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
+ --ring)
+ COMPREPLY=("${cur}")
+ if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
+ compopt -o nospace
+ fi
+ return 0
+ ;;
--config)
COMPREPLY=($(compgen -f "${cur}"))
return 0
diff --git a/contrib/completion/tinty.elvish b/contrib/completion/tinty.elvish
index 8bc0821..bbf6ab3 100644
--- a/contrib/completion/tinty.elvish
+++ b/contrib/completion/tinty.elvish
@@ -30,7 +30,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand current 'Prints the last scheme name applied or specific values from the current scheme'
cand generate-completion 'Generates a shell completion script'
cand generate-scheme 'Generates a scheme based on an image'
- cand info 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)'
+ cand info 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)'
cand init 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up'
cand list 'Lists available schemes'
cand config 'Provides config related information'
@@ -38,7 +38,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand install 'Install the environment needed for tinty'
cand update 'Update to the latest themes'
cand sync 'Install missing templates in tinty/config.toml and update existing templates'
- cand cycle 'Cycle through your preferred themes'
+ cand cycle 'Cycle through a configured ring of schemes'
cand help 'Print this message or the help of the given subcommand(s)'
}
&'tinty;build'= {
@@ -87,6 +87,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand --config 'Optional path to the tinty config.toml file'
cand -d 'Optional path to the tinty data directory'
cand --data-dir 'Optional path to the tinty data directory'
+ cand --all 'Lists all availabile custom schemes'
cand --custom-schemes 'Lists availabile custom schemes'
cand -h 'Print help'
cand --help 'Print help'
@@ -161,6 +162,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand --help 'Print help'
}
&'tinty;cycle'= {
+ cand --ring 'Name of the configured ring to cycle through'
cand -c 'Optional path to the tinty config.toml file'
cand --config 'Optional path to the tinty config.toml file'
cand -d 'Optional path to the tinty data directory'
@@ -175,7 +177,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand current 'Prints the last scheme name applied or specific values from the current scheme'
cand generate-completion 'Generates a shell completion script'
cand generate-scheme 'Generates a scheme based on an image'
- cand info 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)'
+ cand info 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)'
cand init 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up'
cand list 'Lists available schemes'
cand config 'Provides config related information'
@@ -183,7 +185,7 @@ set edit:completion:arg-completer[tinty] = {|@words|
cand install 'Install the environment needed for tinty'
cand update 'Update to the latest themes'
cand sync 'Install missing templates in tinty/config.toml and update existing templates'
- cand cycle 'Cycle through your preferred themes'
+ cand cycle 'Cycle through a configured ring of schemes'
cand help 'Print this message or the help of the given subcommand(s)'
}
&'tinty;help;build'= {
diff --git a/contrib/completion/tinty.fish b/contrib/completion/tinty.fish
index b9195a9..7040c75 100644
--- a/contrib/completion/tinty.fish
+++ b/contrib/completion/tinty.fish
@@ -32,7 +32,7 @@ complete -c tinty -n "__fish_tinty_needs_command" -f -a "build" -d 'Builds the t
complete -c tinty -n "__fish_tinty_needs_command" -f -a "current" -d 'Prints the last scheme name applied or specific values from the current scheme'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "generate-completion" -d 'Generates a shell completion script'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "generate-scheme" -d 'Generates a scheme based on an image'
-complete -c tinty -n "__fish_tinty_needs_command" -f -a "info" -d 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)'
+complete -c tinty -n "__fish_tinty_needs_command" -f -a "info" -d 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "init" -d 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "list" -d 'Lists available schemes'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "config" -d 'Provides config related information'
@@ -40,7 +40,7 @@ complete -c tinty -n "__fish_tinty_needs_command" -f -a "apply" -d 'Applies a th
complete -c tinty -n "__fish_tinty_needs_command" -f -a "install" -d 'Install the environment needed for tinty'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "update" -d 'Update to the latest themes'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "sync" -d 'Install missing templates in tinty/config.toml and update existing templates'
-complete -c tinty -n "__fish_tinty_needs_command" -f -a "cycle" -d 'Cycle through your preferred themes'
+complete -c tinty -n "__fish_tinty_needs_command" -f -a "cycle" -d 'Cycle through a configured ring of schemes'
complete -c tinty -n "__fish_tinty_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
complete -c tinty -n "__fish_tinty_using_subcommand build" -s c -l config -d 'Optional path to the tinty config.toml file' -r
complete -c tinty -n "__fish_tinty_using_subcommand build" -s d -l data-dir -d 'Optional path to the tinty data directory' -r
@@ -66,6 +66,7 @@ complete -c tinty -n "__fish_tinty_using_subcommand generate-scheme" -l save -d
complete -c tinty -n "__fish_tinty_using_subcommand generate-scheme" -s h -l help -d 'Print help'
complete -c tinty -n "__fish_tinty_using_subcommand info" -s c -l config -d 'Optional path to the tinty config.toml file' -r
complete -c tinty -n "__fish_tinty_using_subcommand info" -s d -l data-dir -d 'Optional path to the tinty data directory' -r
+complete -c tinty -n "__fish_tinty_using_subcommand info" -l all -d 'Lists all availabile custom schemes'
complete -c tinty -n "__fish_tinty_using_subcommand info" -l custom-schemes -d 'Lists availabile custom schemes'
complete -c tinty -n "__fish_tinty_using_subcommand info" -s h -l help -d 'Print help'
complete -c tinty -n "__fish_tinty_using_subcommand init" -s c -l config -d 'Optional path to the tinty config.toml file' -r
@@ -98,6 +99,7 @@ complete -c tinty -n "__fish_tinty_using_subcommand sync" -s c -l config -d 'Opt
complete -c tinty -n "__fish_tinty_using_subcommand sync" -s d -l data-dir -d 'Optional path to the tinty data directory' -r
complete -c tinty -n "__fish_tinty_using_subcommand sync" -s q -l quiet -d 'Silence stdout'
complete -c tinty -n "__fish_tinty_using_subcommand sync" -s h -l help -d 'Print help'
+complete -c tinty -n "__fish_tinty_using_subcommand cycle" -l ring -d 'Name of the configured ring to cycle through' -r
complete -c tinty -n "__fish_tinty_using_subcommand cycle" -s c -l config -d 'Optional path to the tinty config.toml file' -r
complete -c tinty -n "__fish_tinty_using_subcommand cycle" -s d -l data-dir -d 'Optional path to the tinty data directory' -r
complete -c tinty -n "__fish_tinty_using_subcommand cycle" -s q -l quiet -d 'Silence stdout'
@@ -106,7 +108,7 @@ complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_su
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "current" -d 'Prints the last scheme name applied or specific values from the current scheme'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "generate-completion" -d 'Generates a shell completion script'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "generate-scheme" -d 'Generates a scheme based on an image'
-complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "info" -d 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)'
+complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "info" -d 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "init" -d 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "list" -d 'Lists available schemes'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "config" -d 'Provides config related information'
@@ -114,5 +116,5 @@ complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_su
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "install" -d 'Install the environment needed for tinty'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "update" -d 'Update to the latest themes'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "sync" -d 'Install missing templates in tinty/config.toml and update existing templates'
-complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "cycle" -d 'Cycle through your preferred themes'
+complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "cycle" -d 'Cycle through a configured ring of schemes'
complete -c tinty -n "__fish_tinty_using_subcommand help; and not __fish_seen_subcommand_from build current generate-completion generate-scheme info init list config apply install update sync cycle help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
diff --git a/contrib/completion/tinty.powershell b/contrib/completion/tinty.powershell
index aa31453..4bf7217 100644
--- a/contrib/completion/tinty.powershell
+++ b/contrib/completion/tinty.powershell
@@ -33,7 +33,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
[CompletionResult]::new('current', 'current', [CompletionResultType]::ParameterValue, 'Prints the last scheme name applied or specific values from the current scheme')
[CompletionResult]::new('generate-completion', 'generate-completion', [CompletionResultType]::ParameterValue, 'Generates a shell completion script')
[CompletionResult]::new('generate-scheme', 'generate-scheme', [CompletionResultType]::ParameterValue, 'Generates a scheme based on an image')
- [CompletionResult]::new('info', 'info', [CompletionResultType]::ParameterValue, 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)')
+ [CompletionResult]::new('info', 'info', [CompletionResultType]::ParameterValue, 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)')
[CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up')
[CompletionResult]::new('list', 'list', [CompletionResultType]::ParameterValue, 'Lists available schemes')
[CompletionResult]::new('config', 'config', [CompletionResultType]::ParameterValue, 'Provides config related information')
@@ -41,7 +41,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
[CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install the environment needed for tinty')
[CompletionResult]::new('update', 'update', [CompletionResultType]::ParameterValue, 'Update to the latest themes')
[CompletionResult]::new('sync', 'sync', [CompletionResultType]::ParameterValue, 'Install missing templates in tinty/config.toml and update existing templates')
- [CompletionResult]::new('cycle', 'cycle', [CompletionResultType]::ParameterValue, 'Cycle through your preferred themes')
+ [CompletionResult]::new('cycle', 'cycle', [CompletionResultType]::ParameterValue, 'Cycle through a configured ring of schemes')
[CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
break
}
@@ -95,6 +95,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'Optional path to the tinty config.toml file')
[CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'Optional path to the tinty data directory')
[CompletionResult]::new('--data-dir', '--data-dir', [CompletionResultType]::ParameterName, 'Optional path to the tinty data directory')
+ [CompletionResult]::new('--all', '--all', [CompletionResultType]::ParameterName, 'Lists all availabile custom schemes')
[CompletionResult]::new('--custom-schemes', '--custom-schemes', [CompletionResultType]::ParameterName, 'Lists availabile custom schemes')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
@@ -177,6 +178,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
break
}
'tinty;cycle' {
+ [CompletionResult]::new('--ring', '--ring', [CompletionResultType]::ParameterName, 'Name of the configured ring to cycle through')
[CompletionResult]::new('-c', '-c', [CompletionResultType]::ParameterName, 'Optional path to the tinty config.toml file')
[CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'Optional path to the tinty config.toml file')
[CompletionResult]::new('-d', '-d', [CompletionResultType]::ParameterName, 'Optional path to the tinty data directory')
@@ -192,7 +194,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
[CompletionResult]::new('current', 'current', [CompletionResultType]::ParameterValue, 'Prints the last scheme name applied or specific values from the current scheme')
[CompletionResult]::new('generate-completion', 'generate-completion', [CompletionResultType]::ParameterValue, 'Generates a shell completion script')
[CompletionResult]::new('generate-scheme', 'generate-scheme', [CompletionResultType]::ParameterValue, 'Generates a scheme based on an image')
- [CompletionResult]::new('info', 'info', [CompletionResultType]::ParameterValue, 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha)')
+ [CompletionResult]::new('info', 'info', [CompletionResultType]::ParameterValue, 'Shows scheme colors for all schemes matching - (Eg: tinty info base16-mocha or tinty info tinted8-mocha)')
[CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Initializes with the exising config. Used to Initialize exising theme for when your shell starts up')
[CompletionResult]::new('list', 'list', [CompletionResultType]::ParameterValue, 'Lists available schemes')
[CompletionResult]::new('config', 'config', [CompletionResultType]::ParameterValue, 'Provides config related information')
@@ -200,7 +202,7 @@ Register-ArgumentCompleter -Native -CommandName 'tinty' -ScriptBlock {
[CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install the environment needed for tinty')
[CompletionResult]::new('update', 'update', [CompletionResultType]::ParameterValue, 'Update to the latest themes')
[CompletionResult]::new('sync', 'sync', [CompletionResultType]::ParameterValue, 'Install missing templates in tinty/config.toml and update existing templates')
- [CompletionResult]::new('cycle', 'cycle', [CompletionResultType]::ParameterValue, 'Cycle through your preferred themes')
+ [CompletionResult]::new('cycle', 'cycle', [CompletionResultType]::ParameterValue, 'Cycle through a configured ring of schemes')
[CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
break
}
diff --git a/contrib/completion/tinty.zsh b/contrib/completion/tinty.zsh
index 3a3a1b1..6d1fba3 100644
--- a/contrib/completion/tinty.zsh
+++ b/contrib/completion/tinty.zsh
@@ -91,10 +91,11 @@ _arguments "${_arguments_options[@]}" : \
'--config=[Optional path to the tinty config.toml file]:FILE:_default' \
'-d+[Optional path to the tinty data directory]:DIRECTORY:_default' \
'--data-dir=[Optional path to the tinty data directory]:DIRECTORY:_default' \
+'--all[Lists all availabile custom schemes]' \
'--custom-schemes[Lists availabile custom schemes]' \
'-h[Print help]' \
'--help[Print help]' \
-'::scheme_name -- The scheme you want to get information about:_default' \
+'::scheme-name -- The scheme you want to get information about:_default' \
&& ret=0
;;
(init)
@@ -142,7 +143,7 @@ _arguments "${_arguments_options[@]}" : \
'--quiet[Silence stdout]' \
'-h[Print help]' \
'--help[Print help]' \
-':scheme_name -- The scheme you want to apply:_default' \
+':scheme-name -- The scheme you want to apply:_default' \
&& ret=0
;;
(install)
@@ -183,6 +184,7 @@ _arguments "${_arguments_options[@]}" : \
;;
(cycle)
_arguments "${_arguments_options[@]}" : \
+'--ring=[Name of the configured ring to cycle through]:RING:_default' \
'-c+[Optional path to the tinty config.toml file]:FILE:_default' \
'--config=[Optional path to the tinty config.toml file]:FILE:_default' \
'-d+[Optional path to the tinty data directory]:DIRECTORY:_default' \
@@ -277,7 +279,7 @@ _tinty_commands() {
'current:Prints the last scheme name applied or specific values from the current scheme' \
'generate-completion:Generates a shell completion script' \
'generate-scheme:Generates a scheme based on an image' \
-'info:Shows scheme colors for all schemes matching - (Eg\: tinty info base16-mocha)' \
+'info:Shows scheme colors for all schemes matching - (Eg\: tinty info base16-mocha or tinty info tinted8-mocha)' \
'init:Initializes with the exising config. Used to Initialize exising theme for when your shell starts up' \
'list:Lists available schemes' \
'config:Provides config related information' \
@@ -285,7 +287,7 @@ _tinty_commands() {
'install:Install the environment needed for tinty' \
'update:Update to the latest themes' \
'sync:Install missing templates in tinty/config.toml and update existing templates' \
-'cycle:Cycle through your preferred themes' \
+'cycle:Cycle through a configured ring of schemes' \
'help:Print this message or the help of the given subcommand(s)' \
)
_describe -t commands 'tinty commands' commands "$@"
@@ -332,7 +334,7 @@ _tinty__help_commands() {
'current:Prints the last scheme name applied or specific values from the current scheme' \
'generate-completion:Generates a shell completion script' \
'generate-scheme:Generates a scheme based on an image' \
-'info:Shows scheme colors for all schemes matching - (Eg\: tinty info base16-mocha)' \
+'info:Shows scheme colors for all schemes matching - (Eg\: tinty info base16-mocha or tinty info tinted8-mocha)' \
'init:Initializes with the exising config. Used to Initialize exising theme for when your shell starts up' \
'list:Lists available schemes' \
'config:Provides config related information' \
@@ -340,7 +342,7 @@ _tinty__help_commands() {
'install:Install the environment needed for tinty' \
'update:Update to the latest themes' \
'sync:Install missing templates in tinty/config.toml and update existing templates' \
-'cycle:Cycle through your preferred themes' \
+'cycle:Cycle through a configured ring of schemes' \
'help:Print this message or the help of the given subcommand(s)' \
)
_describe -t commands 'tinty help commands' commands "$@"
diff --git a/example.toml b/example.toml
index 93bc322..1a4d38e 100644
--- a/example.toml
+++ b/example.toml
@@ -18,6 +18,16 @@
# # Default scheme to apply if a previously set scheme doesn't exist.
# # Used specifically in the `tinty init` subcommand.
# default-scheme = "base16-mocha"
+# # Default ring to use when running `tinty cycle` without `--ring`.
+# default-cycle-ring = "default"
+#
+# [[rings]]
+# name = "default"
+# schemes = ["base16-mocha", "base16-gruvbox-dark"]
+#
+# [[rings]]
+# name = "light"
+# schemes = ["base16-gruvbox-light", "base16-github"]
#
# [[items]]
# # Path to template repository. Can be a URL, absolute path or path
@@ -39,6 +49,11 @@
# shell = "zsh -c '{}'"
# default-scheme = "base16-oceanicnext"
+# default-cycle-ring = "default"
+#
+# [[rings]]
+# name = "default"
+# schemes = ["base16-oceanicnext", "base16-gruvbox-dark", "base16-github-dark"]
#
# [[items]]
# path = "https://github.com/tinted-theming/tinted-shell"
diff --git a/src/cli.rs b/src/cli.rs
index c8b6882..147d62d 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -243,7 +243,14 @@ pub fn build_cli() -> Command {
),
)
.subcommand(
- Command::new("cycle").about("Cycle through your preferred themes")
+ Command::new("cycle").about("Cycle through a configured ring of schemes")
+ .arg(
+ Arg::new("ring")
+ .long("ring")
+ .help("Name of the configured ring to cycle through")
+ .value_name("RING")
+ .action(ArgAction::Set),
+ )
.arg(
Arg::new("quiet")
.long("quiet")
diff --git a/src/config.rs b/src/config.rs
index e474505..81dd99c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -64,6 +64,29 @@ impl fmt::Display for ConfigItem {
}
}
+/// Structure for configuration cycle rings
+#[derive(Deserialize, Debug)]
+pub struct ConfigRing {
+ pub name: String,
+ pub schemes: Vec,
+}
+
+impl fmt::Display for ConfigRing {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let schemes_text = self
+ .schemes
+ .iter()
+ .map(|scheme| format!("\"{scheme}\""))
+ .collect::>()
+ .join(", ");
+
+ writeln!(f)?;
+ writeln!(f, "[[rings]]")?;
+ writeln!(f, "name = \"{}\"", self.name)?;
+ write!(f, "schemes = [{schemes_text}]")
+ }
+}
+
/// Structure for configuration
#[derive(Deserialize, Debug)]
pub struct Config {
@@ -72,6 +95,9 @@ pub struct Config {
pub default_scheme: Option,
#[serde(rename = "preferred-schemes")]
pub preferred_schemes: Option>,
+ pub rings: Option>,
+ #[serde(rename = "default-cycle-ring")]
+ pub default_cycle_ring: Option,
pub items: Option>,
pub hooks: Option>,
}
@@ -88,6 +114,22 @@ fn ensure_item_name_is_unique(items: &[ConfigItem]) -> Result<()> {
Ok(())
}
+fn ensure_ring_names_are_valid(rings: &[ConfigRing]) -> Result<()> {
+ let mut names = HashSet::new();
+
+ for ring in rings {
+ if ring.name.trim().is_empty() {
+ return Err(anyhow!("config.toml rings.name should not be empty"));
+ }
+
+ if !names.insert(&ring.name) {
+ return Err(anyhow!("config.toml rings.name should be unique values, but \"{}\" is used for more than 1 rings.name. Please change this to a unique value.", ring.name));
+ }
+ }
+
+ Ok(())
+}
+
impl Config {
pub fn read(path: &Path) -> Result {
if path.exists() && !path.is_file() {
@@ -131,6 +173,22 @@ impl Config {
}
}
+ if let Some(rings) = config.rings.as_ref() {
+ ensure_ring_names_are_valid(rings)?;
+
+ if let Some(default_cycle_ring) = config.default_cycle_ring.as_ref() {
+ if !rings.iter().any(|ring| ring.name == *default_cycle_ring) {
+ return Err(anyhow!(
+ "config.toml default-cycle-ring is set to \"{default_cycle_ring}\", but no ring with that name exists"
+ ));
+ }
+ }
+ } else if let Some(default_cycle_ring) = config.default_cycle_ring.as_ref() {
+ return Err(anyhow!(
+ "config.toml default-cycle-ring is set to \"{default_cycle_ring}\", but no rings are configured"
+ ));
+ }
+
// Set default `system` property for missing systems
if let Some(ref mut items) = config.items {
for item in items.iter_mut() {
@@ -188,6 +246,10 @@ impl fmt::Display for Config {
writeln!(f, "default-scheme = \"{default_scheme}\"")?;
}
+ if let Some(default_cycle_ring) = &self.default_cycle_ring {
+ writeln!(f, "default-cycle-ring = \"{default_cycle_ring}\"")?;
+ }
+
if let Some(items) = &self.preferred_schemes {
let preferred_schemes_text = items
.clone()
@@ -206,6 +268,12 @@ impl fmt::Display for Config {
writeln!(f, "]")?;
}
+ if let Some(rings) = &self.rings {
+ for ring in rings {
+ writeln!(f, "{ring}")?;
+ }
+ }
+
if let Some(items) = &self.items {
for item in items {
writeln!(f, "{item}")?;
diff --git a/src/main.rs b/src/main.rs
index 2b9f055..f90092e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -162,8 +162,9 @@ fn main() -> Result<()> {
let is_quiet = sub_matches
.get_one::("quiet")
.is_some_and(ToOwned::to_owned);
+ let ring_name = sub_matches.get_one::("ring").map(String::as_str);
- operations::cycle::cycle(&config_path, &data_path, is_quiet, None)
+ operations::cycle::cycle(&config_path, &data_path, is_quiet, ring_name, None)
.context("Failed to cycle to your next preferred theme")?;
}
Some(("install", sub_matches)) => {
diff --git a/src/operations/cycle.rs b/src/operations/cycle.rs
index 264078d..30c14b0 100644
--- a/src/operations/cycle.rs
+++ b/src/operations/cycle.rs
@@ -1,26 +1,24 @@
use crate::config::Config;
use crate::operations::apply::apply;
use crate::operations::current::get_current_scheme_slug;
-use crate::utils::{next_scheme_in_cycle, user_curated_scheme_list};
+use crate::utils::{cycle_scheme_list, next_scheme_in_cycle};
use anyhow::Result;
use std::path::Path;
-/// Cycle to next preferred scheme
+/// Cycle to next scheme in a configured ring.
pub fn cycle(
config_path: &Path,
data_path: &Path,
is_quiet: bool,
+ ring_name: Option<&str>,
active_operation: Option<&str>,
) -> Result<()> {
let config = Config::read(config_path)?;
let current_scheme_slug = get_current_scheme_slug(data_path);
- // Figure out what the next theme should be given current theme & preferred schemes.
- let next_theme = user_curated_scheme_list(&config)
- .as_ref()
- .map(|vec| next_scheme_in_cycle(¤t_scheme_slug, vec))
- .unwrap_or(current_scheme_slug);
+ let schemes = cycle_scheme_list(&config, ring_name)?;
+ let next_theme = next_scheme_in_cycle(¤t_scheme_slug, &schemes);
if !is_quiet {
println!("Applying next theme in cycle: {next_theme}");
diff --git a/src/utils.rs b/src/utils.rs
index 6fa4373..ff0b88e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,5 +1,5 @@
#![allow(clippy::arithmetic_side_effects)]
-use crate::config::{Config, ConfigItem, DEFAULT_CONFIG_SHELL};
+use crate::config::{Config, ConfigItem, ConfigRing, DEFAULT_CONFIG_SHELL};
use crate::constants::REPO_NAME;
use anyhow::{anyhow, Context, Error, Result};
use home::home_dir;
@@ -538,32 +538,77 @@ pub fn next_scheme_in_cycle(current: &String, schemes: &[String]) -> String {
}
}
-pub fn user_curated_scheme_list(config: &Config) -> Option> {
- // Return a list of preferred schemes based on presence of this value in the config, and
- // whatever the default scheme is if specified in config also.
- config
- .preferred_schemes
+fn ring_names(rings: &[ConfigRing]) -> String {
+ rings
+ .iter()
+ .map(|ring| ring.name.clone())
+ .collect::>()
+ .join(", ")
+}
+
+pub fn preferred_schemes_migration_message(config: &Config) -> String {
+ let mut migration_schemes = config.preferred_schemes.clone().unwrap_or_default();
+
+ if let Some(default_scheme) = config
+ .default_scheme
.as_ref()
- .map(|preferred| {
- // If default scheme is defined, add it to the cycle.
- config
- .default_scheme
- .as_ref()
- .filter(|default| !preferred.contains(default))
- .map_or_else(
- || preferred.clone(),
- |default| {
- let mut result = vec![default.clone()];
- result.extend(preferred.clone());
- result
- },
- )
- })
- .or_else(|| {
- // If default scheme is defined, use it if preferred schemes is unset.
- config
- .default_scheme
- .as_ref()
- .map(|theme| vec![theme.clone()])
- })
+ .filter(|default_scheme| !migration_schemes.contains(default_scheme))
+ {
+ migration_schemes.insert(0, default_scheme.clone());
+ }
+
+ let schemes = migration_schemes
+ .iter()
+ .map(|scheme| format!("\"{scheme}\""))
+ .collect::>()
+ .join(", ");
+
+ format!(
+ "`preferred-schemes` is no longer supported by `tinty cycle`.\n\
+Remove `preferred-schemes` from your config and add this instead:\n\n\
+default-cycle-ring = \"default\"\n\n\
+[[rings]]\n\
+name = \"default\"\n\
+schemes = [{schemes}]"
+ )
+}
+
+pub fn cycle_scheme_list(config: &Config, requested_ring: Option<&str>) -> Result> {
+ if config.preferred_schemes.is_some() {
+ return Err(anyhow!(preferred_schemes_migration_message(config)));
+ }
+
+ let ring_name = requested_ring
+ .or(config.default_cycle_ring.as_deref())
+ .ok_or_else(|| {
+ anyhow!(
+ "`tinty cycle` requires either `default-cycle-ring` in config.toml or `--ring `"
+ )
+ })?;
+
+ let rings = config
+ .rings
+ .as_ref()
+ .ok_or_else(|| anyhow!("`tinty cycle` requires at least one configured `[[rings]]`"))?;
+
+ let ring = rings
+ .iter()
+ .find(|ring| ring.name == ring_name)
+ .ok_or_else(|| {
+ let available_rings = ring_names(rings);
+ if available_rings.is_empty() {
+ anyhow!("No ring named \"{ring_name}\" exists")
+ } else {
+ anyhow!("No ring named \"{ring_name}\" exists. Available rings: {available_rings}")
+ }
+ })?;
+
+ if ring.schemes.is_empty() {
+ return Err(anyhow!(
+ "Ring \"{}\" does not contain any schemes and cannot be cycled",
+ ring.name
+ ));
+ }
+
+ Ok(ring.schemes.clone())
}
diff --git a/tests/cli_config_subcommand_tests.rs b/tests/cli_config_subcommand_tests.rs
index aacb180..e4f5e16 100644
--- a/tests/cli_config_subcommand_tests.rs
+++ b/tests/cli_config_subcommand_tests.rs
@@ -71,6 +71,51 @@ themes-dir = "colors"
Ok(())
}
+#[test]
+fn test_cli_config_with_rings() -> Result<()> {
+ let config_text = r#"shell = "zsh -c '{}'"
+default-scheme = "base16-oceanicnext"
+default-cycle-ring = "default"
+hooks = [
+ "echo hook"
+]
+
+[[rings]]
+name = "default"
+schemes = ["base16-oceanicnext", "base16-gruvbox-dark"]
+
+[[rings]]
+name = "light"
+schemes = ["base16-github", "base16-gruvbox-light"]
+
+[[items]]
+name = "tinted-vim"
+path = "https://github.com/tinted-theming/tinted-vim"
+supported-systems = ["base16", "base24"]
+themes-dir = "colors"
+
+"#;
+ let (config_path, data_path, command_vec, _temp_dir) =
+ setup("test_cli_config_with_rings", "config")?;
+
+ write_to_file(&config_path, config_text)?;
+
+ let (stdout, _) = utils::run_command(&command_vec, &data_path, true)?;
+
+ ensure!(stdout == config_text, "std not as expected");
+ ensure!(
+ stdout.find("default-cycle-ring").unwrap_or_default()
+ < stdout.find("[[rings]]").unwrap_or_default(),
+ "default-cycle-ring should be printed before [[rings]]"
+ );
+ ensure!(
+ stdout.find("hooks = [").unwrap_or_default() < stdout.find("[[rings]]").unwrap_or_default(),
+ "hooks should be printed before [[rings]]"
+ );
+
+ Ok(())
+}
+
#[test]
fn test_cli_config_with_config_flag() -> Result<()> {
// -------
diff --git a/tests/cli_cycle_subcommand_tests.rs b/tests/cli_cycle_subcommand_tests.rs
index 789e78f..36bbbcb 100644
--- a/tests/cli_cycle_subcommand_tests.rs
+++ b/tests/cli_cycle_subcommand_tests.rs
@@ -1,8 +1,7 @@
//! Integration tests for the `cycle` subcommand.
//!
-//! Covers: cycling through preferred schemes, default-scheme behavior,
-//! wrap-around at end of list, default-scheme prepended to cycle, and
-//! deduplication when default-scheme is already in preferred-schemes.
+//! Covers cycling through configured rings, default-cycle-ring behavior,
+//! wrap-around at end of list, and legacy preferred-schemes migration errors.
//!
//! Requires network access on first run (repos are cached in `tmp/repos/`).
@@ -10,43 +9,45 @@ mod utils;
use crate::utils::{setup, write_to_file};
use anyhow::{ensure, Result};
+use std::fs;
use utils::build_command_vec;
#[test]
-fn test_cli_cycle_subcommand_with_default_scheme_only() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_with_explicit_ring() -> Result<()> {
let scheme_name = "base16-oceanicnext";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_with_default_scheme_only",
+ "test_cli_cycle_subcommand_with_explicit_ring",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-default-scheme = "base16-dracula"
+[[rings]]
+name = "dark"
+schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
+
+[[rings]]
+name = "light"
+schemes = ["base16-github", "base16-gruvbox-material-light-soft"]
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
let (cycle_stdout, cycle_stderr) = utils::run_command(
- &build_command_vec("cycle", config_path.as_path(), data_path.as_path())?,
+ &build_command_vec(
+ "cycle --ring dark",
+ config_path.as_path(),
+ data_path.as_path(),
+ )?,
&data_path,
true,
)?;
- // ------
- // Assert
- // ------
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
);
ensure!(
- cycle_stdout == "Applying next theme in cycle: base16-dracula\n",
+ cycle_stdout == "Applying next theme in cycle: base24-dracula\n",
"cycle_stdout not as expected"
);
ensure!(
@@ -58,97 +59,61 @@ default-scheme = "base16-dracula"
}
#[test]
-fn test_cli_cycle_subcommand_with_preferred_schemes() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_uses_default_cycle_ring() -> Result<()> {
let scheme_name = "base16-oceanicnext";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_with_preferred_schemes",
+ "test_cli_cycle_subcommand_uses_default_cycle_ring",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
+default-cycle-ring = "dark"
+
+[[rings]]
+name = "dark"
+schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
- let (cycle1_stdout, cycle1_stderr) = utils::run_command(
+ let (cycle_stdout, cycle_stderr) = utils::run_command(
&build_command_vec("cycle", config_path.as_path(), data_path.as_path())?,
&data_path,
true,
)?;
- // ------
- // Assert
- // ------
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
);
ensure!(
- cycle1_stdout == "Applying next theme in cycle: base24-dracula\n",
- "cycle1_stdout not as expected"
- );
- ensure!(
- cycle1_stderr.is_empty(),
- "Expected empty stderr, got: {cycle1_stderr}"
- );
-
- let (cycle2_stdout, cycle2_stderr) = utils::run_command(
- &build_command_vec("cycle", config_path.as_path(), data_path.as_path())?,
- &data_path,
- true,
- )?;
-
- ensure!(
- cycle2_stdout == "Applying next theme in cycle: base24-zenburn\n",
- "cycle2_stdout not as expected"
- );
- ensure!(
- cycle2_stderr.is_empty(),
- "Expected empty stderr, got: {cycle2_stderr}"
- );
- let (cycle3_stdout, cycle3_stderr) = utils::run_command(
- &build_command_vec("cycle", config_path.as_path(), data_path.as_path())?,
- &data_path,
- true,
- )?;
-
- ensure!(
- cycle3_stdout == "Applying next theme in cycle: base24-ubuntu\n",
- "cycle3 stdout not as expected"
+ cycle_stdout == "Applying next theme in cycle: base24-dracula\n",
+ "cycle_stdout not as expected"
);
ensure!(
- cycle3_stderr.is_empty(),
- "Expected empty stderr, got: {cycle3_stderr}"
+ cycle_stderr.is_empty(),
+ "Expected empty stderr, got: {cycle_stderr}"
);
Ok(())
}
#[test]
-fn test_cli_cycle_subcommand_correct_next_scheme() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_correct_next_scheme_in_ring() -> Result<()> {
let scheme_name = "base24-zenburn";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_correct_next_scheme",
+ "test_cli_cycle_subcommand_correct_next_scheme_in_ring",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
let (cycle_stdout, cycle_stderr) = utils::run_command(
@@ -157,9 +122,6 @@ preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
true,
)?;
- // ------
- // Assert
- // ------
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
@@ -177,23 +139,21 @@ preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
}
#[test]
-fn test_cli_cycle_subcommand_wraps_around() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_wraps_around_ring() -> Result<()> {
let scheme_name = "base24-ubuntu";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_wraps_around",
+ "test_cli_cycle_subcommand_wraps_around_ring",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
let (cycle_stdout, cycle_stderr) = utils::run_command(
@@ -202,9 +162,6 @@ preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
true,
)?;
- // ------
- // Assert
- // ------
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
@@ -213,7 +170,6 @@ preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
cycle_stdout == "Applying next theme in cycle: base24-dracula\n",
"cycle_stdout not as expected"
);
-
ensure!(
cycle_stderr.is_empty(),
"Expected empty stderr, got: {cycle_stderr}"
@@ -223,24 +179,21 @@ preferred-schemes = ["base24-dracula", "base24-zenburn", "base24-ubuntu"]
}
#[test]
-fn test_cli_cycle_subcommand_default_scheme_prepended_to_cycle() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_errors_for_empty_ring() -> Result<()> {
let scheme_name = "base16-oceanicnext";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_default_scheme_prepended_to_cycle",
+ "test_cli_cycle_subcommand_errors_for_empty_ring",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-default-scheme = "base24-dracula"
-preferred-schemes = ["base24-zenburn", "base24-ubuntu"]
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = []
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
let (cycle_stdout, cycle_stderr) = utils::run_command(
@@ -249,44 +202,104 @@ preferred-schemes = ["base24-zenburn", "base24-ubuntu"]
true,
)?;
- // ------
- // Assert
- // ------
+ let current_scheme = fs::read_to_string(data_path.join("current_scheme"))?;
+
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
);
+ ensure!(cycle_stdout.is_empty(), "Expected empty stdout");
ensure!(
- cycle_stdout == "Applying next theme in cycle: base24-dracula\n",
- "cycle_stdout not as expected"
+ cycle_stderr.contains("Ring \"default\" does not contain any schemes and cannot be cycled"),
+ "cycle_stderr not as expected: {cycle_stderr}"
);
ensure!(
- cycle_stderr.is_empty(),
- "Expected empty stderr, got: {cycle_stderr}"
+ current_scheme == scheme_name,
+ "Expected current scheme to remain unchanged"
+ );
+
+ Ok(())
+}
+
+#[test]
+fn test_cli_cycle_subcommand_errors_for_missing_ring() -> Result<()> {
+ let (config_path, data_path, _apply_command_vec, _temp_dir) = setup(
+ "test_cli_cycle_subcommand_errors_for_missing_ring",
+ "cycle --ring dark",
+ )?;
+ let config_content = r#"
+[[rings]]
+name = "light"
+schemes = ["base16-github"]
+"#;
+ write_to_file(&config_path, config_content)?;
+
+ let (cycle_stdout, cycle_stderr) = utils::run_command(
+ &build_command_vec(
+ "cycle --ring dark",
+ config_path.as_path(),
+ data_path.as_path(),
+ )?,
+ &data_path,
+ false,
+ )?;
+
+ ensure!(cycle_stdout.is_empty(), "Expected empty stdout");
+ ensure!(
+ cycle_stderr.contains("No ring named \"dark\" exists. Available rings: light"),
+ "cycle_stderr not as expected: {cycle_stderr}"
);
Ok(())
}
#[test]
-fn test_cli_cycle_subcommand_default_scheme_not_duplicated_in_cycle() -> Result<()> {
- // -------
- // Arrange
- // -------
+fn test_cli_cycle_subcommand_errors_for_duplicate_ring_names() -> Result<()> {
+ let (config_path, data_path, _apply_command_vec, _temp_dir) = setup(
+ "test_cli_cycle_subcommand_errors_for_duplicate_ring_names",
+ "cycle",
+ )?;
+ let config_content = r#"
+default-cycle-ring = "default"
+
+[[rings]]
+name = "default"
+schemes = ["base16-github"]
+
+[[rings]]
+name = "default"
+schemes = ["base16-dracula"]
+"#;
+ write_to_file(&config_path, config_content)?;
+
+ let (cycle_stdout, cycle_stderr) = utils::run_command(
+ &build_command_vec("cycle", config_path.as_path(), data_path.as_path())?,
+ &data_path,
+ false,
+ )?;
+
+ ensure!(cycle_stdout.is_empty(), "Expected empty stdout");
+ ensure!(
+ cycle_stderr.contains("config.toml rings.name should be unique values"),
+ "cycle_stderr not as expected: {cycle_stderr}"
+ );
+
+ Ok(())
+}
+
+#[test]
+fn test_cli_cycle_subcommand_errors_for_preferred_schemes_with_migration() -> Result<()> {
let scheme_name = "base16-oceanicnext";
let (config_path, data_path, apply_command_vec, _temp_dir) = setup(
- "test_cli_cycle_subcommand_default_scheme_not_duplicated_in_cycle",
+ "test_cli_cycle_subcommand_errors_for_preferred_schemes_with_migration",
format!("apply {scheme_name}").as_str(),
)?;
let config_content = r#"
-default-scheme = "base24-dracula"
-preferred-schemes = ["base24-zenburn", "base24-dracula", "base24-ubuntu"]
+default-scheme = "base24-ubuntu"
+preferred-schemes = ["base24-dracula", "base24-zenburn"]
"#;
write_to_file(&config_path, config_content)?;
- // ---
- // Act
- // ---
let (_, apply_stderr) = utils::run_command(&apply_command_vec, &data_path, true)?;
let (cycle_stdout, cycle_stderr) = utils::run_command(
@@ -295,20 +308,33 @@ preferred-schemes = ["base24-zenburn", "base24-dracula", "base24-ubuntu"]
true,
)?;
- // ------
- // Assert
- // ------
+ let current_scheme = fs::read_to_string(data_path.join("current_scheme"))?;
+
ensure!(
apply_stderr.is_empty(),
"Expected empty stderr, got: {apply_stderr}"
);
+ ensure!(cycle_stdout.is_empty(), "Expected empty stdout");
ensure!(
- cycle_stdout == "Applying next theme in cycle: base24-zenburn\n",
- "cycle_stdout not as expected"
+ cycle_stderr.contains("`preferred-schemes` is no longer supported by `tinty cycle`"),
+ "cycle_stderr did not include deprecation message: {cycle_stderr}"
);
ensure!(
- cycle_stderr.is_empty(),
- "Expected empty stderr, got: {cycle_stderr}"
+ cycle_stderr
+ .contains("schemes = [\"base24-ubuntu\", \"base24-dracula\", \"base24-zenburn\"]"),
+ "cycle_stderr did not include migration snippet: {cycle_stderr}"
+ );
+ ensure!(
+ cycle_stderr.contains("default-cycle-ring = \"default\""),
+ "cycle_stderr did not include default-cycle-ring: {cycle_stderr}"
+ );
+ ensure!(
+ cycle_stderr.find("default-cycle-ring = \"default\"") < cycle_stderr.find("[[rings]]"),
+ "default-cycle-ring should appear before [[rings]] in migration snippet: {cycle_stderr}"
+ );
+ ensure!(
+ current_scheme == scheme_name,
+ "Expected current scheme to remain unchanged"
);
Ok(())