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

Enable themes #852

Merged
merged 52 commits into from
Nov 9, 2023
Merged

Enable themes #852

merged 52 commits into from
Nov 9, 2023

Conversation

AllanOricil
Copy link
Contributor

@AllanOricil AllanOricil commented Nov 5, 2023

With this feature developers will be able to create custom color themes for their CLI.

obs: disregard the --json I added in the pictures below

BEFORE

image image image image

AFTER

image image image image

A theme is enabled when:

  • there is a json file called theme in ~/.config/data/<CLI>/theme.json
  • <CLI>_DISABLE_THEME env var is not set

All theme colors are optional

image

LIGHT THEME EXAMPLES

image image

Configurable Tokens

Colors are set with the values from ~/.config/<CLI>/theme.json file, if one is present. Colors can be set with Hex and RGB color codes strings, which are converted to colors using the color package.

{
       "alias" : "red",
       "bin" : "rgb(255, 255, 255)",
       "command" : "#45C65A",
       "commandSummary" : "#FFFFFF",
       "dollarSign" : "#FFFF00",
       "flag" : "#45C65A",
       "flagDefaultValue" : "#1AB9FF",
       "flagOptions" : "#45C65A",
       "flagRequired" : "#FE5C4C",
       "flagSeparator" : "#FFFFFF",
       "flagType" : "#0EAEE8",
       "sectionDescription" : "#FFFFFF",
       "sectionHeader" : "#FFFF00",
       "topic" : "#45C65A",
       "version" : "#45C65A"
}

In the following pictures you can understand the regions each token affect.

alias
image

bin
image

command
image

image

commandSummary

image image

dollarSign
image

flag
image

flagDefaultValue
image

flagOptions
image

flagRequired
image

flagSeparator
image

flagType

NOT IMPLEMENTED YET.

It depends on a new attribute called "typeLabel" which has to be added to the flag configuration. Without allowing CLI developers to specify a custom label for the types of their flags, like filePath, users would only see "boolean | option" which is the value from flag.type.

sectionDescription
image

sectionHeader
image

topic
image

version
image

@AllanOricil AllanOricil marked this pull request as ready for review November 7, 2023 20:01
@AllanOricil
Copy link
Contributor Author

AllanOricil commented Nov 7, 2023

Some tests are failing and I have not write any tests for my changes, but I'm ready for a review since the feature is mostly done and I need to know if there are bugs and your opinion on this. I have not tested few sections like: ARGUMENTS, DESCRIPTION, ALIASES,EXAMPLES and FLAG DESCRIPTIONS. How can I test if they are rendered properly?

@AllanOricil
Copy link
Contributor Author

AllanOricil commented Nov 7, 2023

Using the Heroku CLI, I found that the DESCRIPTION, ALIASES, ARGUMENTS and EXAMPLES sections aren't working well, . I'm going to fix it, now that I have means to test it. But I could not find a command that displays the FLAG DESCRIPTIONS section. It would be good if you could help me to find a CLI or command that has it.

image image image

Copy link
Contributor

@mdonnalley mdonnalley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AllanOricil Great work 🏆

My biggest concern here is that users will have different terminal themes that would conflict with the configured theme. CLI developers would need to configure a theme that works on most terminal themes, which would be a challenging task.

I wonder if this should be something that we defer to users? Instead of looking in the CLI's package.json, oclif/core could look for a config file on the users machine. That would allow users to have colorful help without forcing them to use a specific terminal theme that works with it.

What do you think?

src/config/config.ts Outdated Show resolved Hide resolved
@AllanOricil AllanOricil restored the feat/themes branch November 9, 2023 02:29
@AllanOricil AllanOricil reopened this Nov 9, 2023
@mdonnalley
Copy link
Contributor

@AllanOricil

Works for me if I do this in interfaces/config.ts

import * as Color from 'color'

export function parseTheme(untypedTheme: Record<string, string>): Theme {
  return Object.fromEntries(
    Object.entries(untypedTheme)
      .filter(([key]) => THEME_KEYS.includes(key))
      // eslint-disable-next-line new-cap
      .map(([key, value]) => [key, new Color.default(value)]),
  )
}

and this in help/util.ts

import * as Color from 'color'

src/config/config.ts Outdated Show resolved Hide resolved
src/interfaces/config.ts Outdated Show resolved Hide resolved
src/interfaces/config.ts Outdated Show resolved Hide resolved
@AllanOricil
Copy link
Contributor Author

/@types/color/index"' can only be default-imported using the 'esModuleInterop' flag

fixed

Copy link
Contributor

@mdonnalley mdonnalley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few small things and then I'll approve.

src/interfaces/pjson.ts Outdated Show resolved Hide resolved
src/interfaces/config.ts Outdated Show resolved Hide resolved
@@ -325,6 +328,11 @@ export class Config implements IConfig {

this.npmRegistry = this.scopedEnvVar('NPM_REGISTRY') || this.pjson.oclif.npmRegistry

const themeFilePath = resolve(this.configDir, 'theme.json')
const theme = this.scopedEnvVarTrue('DISABLE_THEME') ? undefined : await safeReadJson(themeFilePath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const theme = this.scopedEnvVarTrue('DISABLE_THEME') ? undefined : await safeReadJson<Record<string, string>>(themeFilePath)

That way you don't have to use as when passing it to parseTheme

Copy link
Contributor Author

@AllanOricil AllanOricil Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdonnalley

fixed at 00a6ccd

Could you tell me if you agree with what I did. I removed enableTheme from config.

@mdonnalley
Copy link
Contributor

@AllanOricil I'm going to merge this into a separate feature branch so that we can run all the integration tests before merging. I'm taking a vacation tomorrow so I would expect to get this merged into main early next week

@mdonnalley mdonnalley changed the base branch from main to mdonnalley/852 November 9, 2023 19:45
@mdonnalley mdonnalley merged commit fc3d81e into oclif:mdonnalley/852 Nov 9, 2023
1 check passed
@AllanOricil
Copy link
Contributor Author

@mdonnalley thank you for all the help 👍

mdonnalley added a commit that referenced this pull request Nov 20, 2023
* feat: create type for storing theme colors

* feat: include color and @types/color, and simiplify theme schema

* feat: set theme's default colors to white

* feat: set FORCE_COLOR to 0||3 to follow the NO_COLOR manifest

* feat: create DEFAULT_THEME to store default colors

* revert: remove NO_COLOR manifest

* feat: add new theme variables to style $, flag, and flag options

* feat: add color to section headers

* feat: configure default colors

* feat: add colors for bin, command summary and version

* feat: topics, commands, bin, version, sections, dollar sign are colorized

* feat: configure default colors

* feat: add feature flag to enabled/disable theme

* feat: add colorize function to simplify the way colors are added to strings

* feat: change all chalk.hex calls to colorize

* feat: configure OCLIF_ENABLE_THEME to have precence over PJSON prop

* feat: all theme colors are optional

* fix: error TS2322: Type 'string' is not assignable to type 'boolean'

* fix: error TS2345: arg of type 'Color<ColorParam>|undefined' not assignable to 'Color<ColorParam>'

* fix: runtime error TypeError: color.hex is not a function

* fix:  this.pjson.oclif.enableTheme was not being evaluated when OCLIF_ENABLE_THEME was unset

* chore(deps): update yarn.lock

* refactor: simplified code removing OCLIF_ENABLE_THEME constant

* fix: command summary was not changing its color when running the root command

* feat: theme is now read from ~/config/<CLI>/theme.json if one exists

* fix: add colors to other ARGUMENTS, EXAMPLES, DESCRIPTION, FLAGS DESCRIPTIONS sections

* feat: add color token for aliases

* fix(test): change template strings to avoid expected results printing bin twice

* fix(test): add a missing parenthesis back so that all options are wraped by ()

* fix(test): remove single quotes wraping default flag values

* feat: add test:debug script to ease debuging

* refactor: add a constant with all possible THEME_KEYS

* test: add tests to prove parsing untyped json object with color strings work

* chore(package): add new scripts to ease development while writing tests

* revert: remove theme from PJSON because a theme will be loaded from config_dir/<CLI>/theme.json

* feat: add scopedEnvVarBoolean because scopedEnvVarTrue does not consider unset env vars

* feat(test): add tests to prove the behavior that enables theme

* refactor: replace all scopedEnvVarTrue by scopedEnvVarBoolean, which considers unset env variables

* test: add tests to prove the enableTheme behavior

* refactor: simplify parseTheme method

* chore(package): remove localhost:4873 from lock file

* revert: rever scopedEnvVarBoolean back to scopedEnvVarTrue

* test: add tests to prove when this.theme is set

* feat: ensure colorize returns string only

* test: add tests to prove colorize works as expected

* revert: rollback scopedEnvVarTrue as it was before

* refactor: move parseTheme to src/util/util.js

* refactor: make Theme type dinamically based on the values of THEME_KEYS at runtime

* fix: err TS1259: Module /@types/color/index can only be default-imported using 'esModuleInterop'

* revert: remove enableTheme from pjson because we don't want to cli devs to force users to use theme

* revert: remove undefined as a return type for scopedEnvVarTrue

* refactor: remove config.enableTheme

Co-authored-by: Allan Oricil <55927613+AllanOricil@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla:signed enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants