-
Notifications
You must be signed in to change notification settings - Fork 3.3k
{Style} Support style with color #16220
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # -------------------------------------------------------------------------------------------- | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. See License.txt in the project root for license information. | ||
| # -------------------------------------------------------------------------------------------- | ||
|
|
||
| """ | ||
| Support styled output. | ||
| Currently, only color is supported, underline/bold/italic may be supported in the future. | ||
| Design spec: | ||
| https://devdivdesignguide.azurewebsites.net/command-line-interface/color-guidelines-for-command-line-interface/ | ||
| For a complete demo, see `src/azure-cli/azure/cli/command_modules/util/custom.py` and run `az demo style`. | ||
| """ | ||
|
|
||
| import sys | ||
| from enum import Enum | ||
|
|
||
| from colorama import Fore | ||
|
|
||
|
|
||
| class Style(str, Enum): | ||
| PRIMARY = "primary" | ||
| SECONDARY = "secondary" | ||
| IMPORTANT = "important" | ||
| ACTION = "action" # name TBD | ||
| HYPERLINK = "hyperlink" | ||
| # Message colors | ||
| ERROR = "error" | ||
| SUCCESS = "success" | ||
| WARNING = "warning" | ||
|
|
||
|
|
||
| THEME = { | ||
| # Style to ANSI escape sequence mapping | ||
| # https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences | ||
| Style.PRIMARY: Fore.LIGHTWHITE_EX, | ||
| Style.SECONDARY: Fore.LIGHTBLACK_EX, # may use WHITE, but will lose contrast to LIGHTWHITE_EX | ||
| Style.IMPORTANT: Fore.LIGHTMAGENTA_EX, | ||
| Style.ACTION: Fore.LIGHTBLUE_EX, | ||
| Style.HYPERLINK: Fore.LIGHTCYAN_EX, | ||
| # Message colors | ||
| Style.ERROR: Fore.LIGHTRED_EX, | ||
| Style.SUCCESS: Fore.LIGHTGREEN_EX, | ||
| Style.WARNING: Fore.LIGHTYELLOW_EX, | ||
| } | ||
|
|
||
|
|
||
| def print_styled_text(styled, file=sys.stderr): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May I ask why the default value of the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only the JSON output should go to https://en.wikipedia.org/wiki/Standard_streams#sys.stderr
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, got it~
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes |
||
| formatted = format_styled_text(styled) | ||
| print(formatted, file=file) | ||
|
|
||
|
|
||
| def format_styled_text(styled_text): | ||
| # https://python-prompt-toolkit.readthedocs.io/en/stable/pages/printing_text.html#style-text-tuples | ||
| formatted_parts = [] | ||
|
|
||
| for text in styled_text: | ||
| # str can also be indexed, bypassing IndexError, so explicitly check if the type is tuple | ||
| if not (isinstance(text, tuple) and len(text) == 2): | ||
| from azure.cli.core.azclierror import CLIInternalError | ||
| raise CLIInternalError("Invalid styled text. It should be a list of 2-element tuples.") | ||
|
|
||
| style = text[0] | ||
| if style not in THEME: | ||
| from azure.cli.core.azclierror import CLIInternalError | ||
| raise CLIInternalError("Invalid style. Only use pre-defined style in Style enum.") | ||
|
|
||
| formatted_parts.append(THEME[text[0]] + text[1]) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. key checking for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch. Added checks and tests as requested. |
||
|
|
||
| # Reset control sequence | ||
| formatted_parts.append(Fore.RESET) | ||
| return ''.join(formatted_parts) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # -------------------------------------------------------------------------------------------- | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. See License.txt in the project root for license information. | ||
| # -------------------------------------------------------------------------------------------- | ||
|
|
||
| import unittest | ||
|
|
||
|
|
||
| class TestStyle(unittest.TestCase): | ||
|
|
||
| def test_format_styled_text(self): | ||
| from azure.cli.core.style import Style, format_styled_text | ||
| styled_text = [ | ||
| (Style.PRIMARY, "Bright White: Primary text color\n"), | ||
| (Style.SECONDARY, "White: Secondary text color\n"), | ||
| (Style.IMPORTANT, "Bright Magenta: Important text color\n"), | ||
| (Style.ACTION, "Bright Blue: Commands, parameters, and system inputs\n"), | ||
| (Style.HYPERLINK, "Bright Cyan: Hyperlink\n"), | ||
| (Style.ERROR, "Bright Red: Error message indicator\n"), | ||
| (Style.SUCCESS, "Bright Green: Success message indicator\n"), | ||
| (Style.WARNING, "Bright Yellow: Warning message indicator\n"), | ||
| ] | ||
| formatted = format_styled_text(styled_text) | ||
| excepted = """\x1b[97mBright White: Primary text color | ||
| \x1b[90mWhite: Secondary text color | ||
| \x1b[95mBright Magenta: Important text color | ||
| \x1b[94mBright Blue: Commands, parameters, and system inputs | ||
| \x1b[96mBright Cyan: Hyperlink | ||
| \x1b[91mBright Red: Error message indicator | ||
| \x1b[92mBright Green: Success message indicator | ||
| \x1b[93mBright Yellow: Warning message indicator | ||
| \x1b[39m""" | ||
| self.assertEqual(formatted, excepted) | ||
|
|
||
| # Test invalid style | ||
| from azure.cli.core.azclierror import CLIInternalError | ||
| with self.assertRaisesRegex(CLIInternalError, "Invalid style."): | ||
| format_styled_text([("invalid_style", "dummy text",)]) | ||
|
|
||
| # Test invalid styled style | ||
| with self.assertRaisesRegex(CLIInternalError, "Invalid styled text."): | ||
| format_styled_text([(Style.PRIMARY,)]) | ||
| with self.assertRaisesRegex(CLIInternalError, "Invalid styled text."): | ||
| format_styled_text(["dummy text"]) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,3 +45,13 @@ | |||||||
| type: command | ||||||||
| short-summary: Upgrade Azure CLI and extensions | ||||||||
| """ | ||||||||
|
|
||||||||
| helps['demo'] = """ | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious is this a convention to add a demo command here? The command is convenient for developers but also visible to users right?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No. We don't have such convention. The only existing usage of this pattern is
It is not visible to the user, as the parent command group has been marked as azure-cli/src/azure-cli/azure/cli/command_modules/util/commands.py Lines 18 to 19 in bc2d0d4
|
||||||||
| type: group | ||||||||
| short-summary: Demos for designing, developing and demonstrating Azure CLI. | ||||||||
| """ | ||||||||
|
|
||||||||
| helps['demo style'] = """ | ||||||||
| type: command | ||||||||
| short-summary: A demo showing supported text styles. | ||||||||
| """ | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chenlomis, what style name should we use for light blue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there
Am slightly confused
Did you mean finding an internal short name for the the bright blue?
https://devdivdesignguide.azurewebsites.net/command-line-interface/color-guidelines-for-command-line-interface/#action-colors