Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A "_random_" color scheme option. Any new window chooses randomly from those in settings.schemes. #9845

Closed
wants to merge 5 commits into from

Conversation

hessedoneen
Copy link
Contributor

@hessedoneen hessedoneen commented Apr 15, 2021

Summary of the Pull Request

If the user sets schema = "_random", then every new terminal window they open will have a random color scheme applied. This color scheme is chosen from existing schemes in settings.schemes (as compared to colors/fonts being randomly generated).

Detailed Description of the Pull Request / Additional comments

Pull request will pass all of the following tests:

  1. "_random" chooses from both default and user added schemes (also ensure last or first never gets ignored)
  2. "_random" will work even if there are only default schemes
  3. "_random" will work no matter how many (or which) default schemes there are (will not hard code in Campbell/Vintage/Tango or anything)
  4. If someone tries to add a new scheme named "_random" then their new random scheme will take precedence (following current convention where if you make a new "Campbell" scheme, then the new scheme will show up instead.

Validation Steps Performed

N/A yet

@ghost ghost added Area-Settings Issues related to settings and customizability, for console or terminal Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal. labels Apr 15, 2021
@hessedoneen
Copy link
Contributor Author

Cases I don't know how to handle yet:

  • What to do if default and user made schemes are both empty? I don't think this can happen since users can't edit defaults.json, but I want to make sure I follow what y'all are doing.
  • I am pretty sure if a user defines "_random_" then it will automatically take care of test4, because I'm only checking if the scheme == "_random_" if it was already not found in the lookup, but I'm not sure yet until I implement everything

@hessedoneen
Copy link
Contributor Author

Chosen Implementation:
"_random_" is a keyword, and when present the scheme will randomly load one of the other defaults schemes

  • Pro: does not introduce too much change, can work quickly
  • Con: requires future programmers to know about and account for the "_random_" scheme case, which is applied functionally different from the other schemes.

Another implementation I considered: "_random_" comes as a "dummy" default scheme which is never used -

  • Pro: Do not have to hard-code in exceptions outside of TerminalSettings.cpp for applying "_random_". Future programmers don't even really have to know about "_random_"'s existence outside of TerminalSettings.cpp
  • Con: I don't know much about security, but if users aren't allowed to edit defaults.json, I assume overwriting "_random_" housed in defaults.json is a big no-no. If this is a problem we could start off userDefaults.json with a single scheme "_random_", with a comment saying what it does?
  • Con: I think opening a closing lots of windows, all of which rewrite the userDefaults.json, could lead to some weird race conditions. We could implement it so the file is not actually overwritten?
  • Con: this approach was getting more and more complicated the more I thought about it, and could be difficult to make follow the same default behavior as the other schemes.

@zadjii-msft
Copy link
Member

I think this is a great writeup! My thoughts:

What to do if default and user made schemes are both empty
That definitely can't happen, so don't worry about that. If that was possible, then we'd have much bigger problems to worry about 😄

If someone tries to add a new scheme named "random" then their new random scheme will take precedence

That seems sensible to me

I look forward to the whole PR!

@zadjii-msft zadjii-msft added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Apr 19, 2021
@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Apr 19, 2021
@hessedoneen
Copy link
Contributor Author

Okay great! Thank you for the feedback and I look forward to it too haha :)

@github-actions
Copy link

Misspellings found, please review:

  • strcmp
To accept these changes, run the following commands from this repository on this branch
pushd $(git rev-parse --show-toplevel)
perl -e '
my @expect_files=qw('".github/actions/spelling/expect/alphabet.txt
.github/actions/spelling/expect/expect.txt
.github/actions/spelling/expect/web.txt"');
@ARGV=@expect_files;
my @stale=qw('"aef aspnet boostorg BSODs Cac COINIT dahall DEFAPP DEFCON fde fea fmtlib HPCON isocpp mintty msvcrtd NVDA pinam QOL remoting Unk unte vcrt what3words xamarin "');
my $re=join "|", @stale;
my $suffix=".".time();
my $previous="";
sub maybe_unlink { unlink($_[0]) if $_[0]; }
while (<>) {
  if ($ARGV ne $old_argv) { maybe_unlink($previous); $previous="$ARGV$suffix"; rename($ARGV, $previous); open(ARGV_OUT, ">$ARGV"); select(ARGV_OUT); $old_argv = $ARGV; }
  next if /^(?:$re)(?:(?:\r|\n)*$| .*)/; print;
}; maybe_unlink($previous);'
perl -e '
my $new_expect_file=".github/actions/spelling/expect/cf8ac0eb071c474058292fe74aca61612a6f7b9c.txt";
use File::Path qw(make_path);
make_path ".github/actions/spelling/expect";
open FILE, q{<}, $new_expect_file; chomp(my @words = <FILE>); close FILE;
my @add=qw('"cac coinit defapp hpcon MSVCRTD Remoting strcmp unk "');
my %items; @items{@words} = @words x (1); @items{@add} = @add x (1);
@words = sort {lc($a) cmp lc($b)} keys %items;
open FILE, q{>}, $new_expect_file; for my $word (@words) { print FILE "$word\n" if $word =~ /\w/; };
close FILE;'
popd
✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. You can copy the contents of each perl command excluding the outer ' marks and dropping any '"/"' quotation mark pairs into a file and then run perl file.pl from the root of the repository to run the code. Alternatively, you can manually insert the items...

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/dictionary/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/dictionary/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

🗜️ If you see a bunch of garbage and it relates to a binary-ish string, please add a file path to the .github/actions/spelling/excludes.txt file instead of just accepting the garbage.

File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

@hessedoneen
Copy link
Contributor Author

Before I decided how to choose a scheme randomly, I wanted to make sure I could apply a scheme name which technically doesn't exist.

The first thing I tried was searching the following warning which comes up whenever I set the scheme to "_random":

"Found a profile with an invalid "colorScheme". Defaulting that profile to the default colors. Make sure that when setting a "colorScheme", the value matches the "name" of a color scheme in the "schemes" list."

Which took me down this line of files/functions/variables:

TerminalApp/Resources/en-US/Resources.resw::UnknownColorSchemeText -->
TerminalApp/AppLogic.cpp::settingsLoadWarningsLabels -->
TerminalApp/AppLogic.cpp::_GetWarningText -->
TerminalApp/AppLogic.cpp::_ShowLoadWarningsDialog -->
TerminalApp/AppLogic.cpp::_ShowLoadWarningsDialog::_warnings -->

At that point I realized I didn't understand the warnings system well enough to trace backward easily so I thought I would try a less frictioned way to find the warning throwing code: If the warning is thrown every time a scheme name is not found in ColorScheme, just find every instance where the color schemes are searched.

In this push I tried to do so. I tried to find and change every instance of .TryLookup() on a ColorScheme object I could find (when it didn't work when I changed the first one I just changed them all), but when I ran the terminal it still threw the warning :[

Could anyone give me some pointers on where to account for this error? Or maybe showing me where the documentation on how all these warnings objects mix with one another if that's the route I should go down? Or just any advice really, haha, thank you.

@hessedoneen
Copy link
Contributor Author

Also, this probably won't apply once I figure out where the error is actually handled, but all the functions I've had to edit so far ask for some behavior based on a ColorScheme object. Whether it was calling .ApplyColorScheme([some scheme which should come from "/_random"]), or "get_strong"?, or something like that.

I just let "/_random" be L"Campbell" in these intermediate steps, but it kind of makes me reconsider whether there should be a dummy "/_random" scheme? Because its random name wouldn't have been chosen by this point, right?

@hessedoneen
Copy link
Contributor Author

WAIT READ FIRST PLS :
What if its random name is chosen immediately after the user inputs "_/random" in their settings.json? If a random one is chosen immediately after input, then there won't be a need to account for it later. It'll immediately change its name to "Campbell" or "Tango Light" or whatever the random choice is. And then the previous framework will take care of it all correctly.

@zadjii-msft
Copy link
Member

Hey so that warning is coming from CascadiaSettings::_ValidateSettings, specifically CascadiaSettings::_ValidateAllSchemesExist. I'd probably just add a case in that method to skip validating _random as the name of a scheme. That should probably make the rest of the code just work ☺️

It'll immediately change its name to "Campbell" or "Tango Light" or whatever the random choice is

I think it's a cool idea, but A: I think it would be harder to implement. B: It would involve writing out the settings file when someone edits the scheme, even in json, and that's highly fraught with peril. We just tend to avoid it, because that means the file is going to get reformatted, and people generally don't love that. And C: I personally want this setting for "pick a random scheme each and every time". Like, I want the setting to be useful for booting to different schemes each time.

@zadjii-msft
Copy link
Member

I just let "/_random" be L"Campbell" in these intermediate steps, but it kind of makes me reconsider whether there should be a dummy "/_random" scheme? Because its random name wouldn't have been chosen by this point, right?

After reading the diff, it almost seems like we should have a helper for

GlobalSettings().ColorSchemes().TryLookup(*schemeName)

that's instead something like:

ColorScheme GlobalAppSettings::ResolveColorScheme(winrt::hstring name) {
    if (const auto scheme = ColorSchemes().TryLookup(realArgs.SchemeName()))
    {
        return scheme;
    }
    else if (realArgs.SchemeName() == winrt::to_hstring(L"_random"))
    {
        // do whatever to get a random scheme
        return scheme;
    }
    return nullptr;
}

So that we can do the logic for _random in only one place

@hessedoneen
Copy link
Contributor Author

That's a really great solution! Thank you so much for pointing me in the right direction, I had been looking for it for so long! I'm excited to get working on it now, and I really appreciate you helpful and thoughtful responses :)

@github-actions
Copy link

Misspellings found, please review:

  • strcmp
To accept these changes, run the following commands from this repository on this branch
pushd $(git rev-parse --show-toplevel)
perl -e '
my @expect_files=qw('".github/actions/spelling/expect/alphabet.txt
.github/actions/spelling/expect/expect.txt
.github/actions/spelling/expect/web.txt"');
@ARGV=@expect_files;
my @stale=qw('"aef aspnet boostorg BSODs Cac COINIT dahall DEFAPP DEFCON fde fea fmtlib HPCON isocpp mintty msvcrtd NVDA pinam QOL remoting Unk unte vcrt what3words xamarin "');
my $re=join "|", @stale;
my $suffix=".".time();
my $previous="";
sub maybe_unlink { unlink($_[0]) if $_[0]; }
while (<>) {
  if ($ARGV ne $old_argv) { maybe_unlink($previous); $previous="$ARGV$suffix"; rename($ARGV, $previous); open(ARGV_OUT, ">$ARGV"); select(ARGV_OUT); $old_argv = $ARGV; }
  next if /^(?:$re)(?:(?:\r|\n)*$| .*)/; print;
}; maybe_unlink($previous);'
perl -e '
my $new_expect_file=".github/actions/spelling/expect/aa54de1d648f45920996aeba1edecc67237c6642.txt";
use File::Path qw(make_path);
make_path ".github/actions/spelling/expect";
open FILE, q{<}, $new_expect_file; chomp(my @words = <FILE>); close FILE;
my @add=qw('"cac coinit defapp hpcon MSVCRTD Remoting strcmp unk "');
my %items; @items{@words} = @words x (1); @items{@add} = @add x (1);
@words = sort {lc($a) cmp lc($b)} keys %items;
open FILE, q{>}, $new_expect_file; for my $word (@words) { print FILE "$word\n" if $word =~ /\w/; };
close FILE;'
popd
✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. You can copy the contents of each perl command excluding the outer ' marks and dropping any '"/"' quotation mark pairs into a file and then run perl file.pl from the root of the repository to run the code. Alternatively, you can manually insert the items...

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/dictionary/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/dictionary/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

🗜️ If you see a bunch of garbage and it relates to a binary-ish string, please add a file path to the .github/actions/spelling/excludes.txt file instead of just accepting the garbage.

File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

@hessedoneen
Copy link
Contributor Author

Update:
So I wanted to make sure I could get the warning to stop at all before I went and implemented accounting for it, but I don't think I can do this only in CascadiaSettings. I removed the warning appending you mentioned, then every other warning I could find that seemed related to ColorScheme, then every warning which was appended at all in the file, but none of these fixed the problem. So I think this behavior might be reinforced in another file as well, or also I may have missed one.

I just cleaned the project in visual studio too and rebuilt but that wasn't the problem either. I'll keep working and seeing if I can find what I'll have to remove to get this error to stop.

@zadjii-msft
Copy link
Member

Weird. Hopefully I'll get a chance later this week to check out this branch and investigate.

@zadjii-msft zadjii-msft self-assigned this Apr 26, 2021
@DHowett
Copy link
Member

DHowett commented Jul 20, 2023

Hey there! Since this one has been in draft for a couple years, I'm hitting it as part of my cleanup spree.. I love this idea, and I'm sorry we weren't able to converge. You're always welcome here! 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants