Skip to content

Commit ffb8d15

Browse files
authored
Improve the readability of CLI help page and table outputs (#604)
1 parent 544ba0d commit ffb8d15

File tree

12 files changed

+123
-126
lines changed

12 files changed

+123
-126
lines changed

linodecli/__init__.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from sys import argv
1111

1212
from rich import print as rprint
13-
from rich.table import Table
13+
from rich.table import Column, Table
1414

1515
from linodecli import plugins
1616

@@ -23,7 +23,14 @@
2323
from .cli import CLI
2424
from .completion import get_completions
2525
from .configuration import ENV_TOKEN_NAME
26-
from .help_pages import print_help_action, print_help_default
26+
from .help_pages import (
27+
HELP_TOPICS,
28+
print_help_action,
29+
print_help_commands,
30+
print_help_default,
31+
print_help_env_vars,
32+
print_help_plugins,
33+
)
2734
from .helpers import handle_url_overrides
2835
from .output import OutputMode
2936
from .version import __version__
@@ -154,7 +161,19 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
154161
# handle a help for the CLI
155162
if parsed.command is None or (parsed.command is None and parsed.help):
156163
parser.print_help()
157-
print_help_default(cli.ops, cli.config)
164+
print_help_default()
165+
sys.exit(0)
166+
167+
if parsed.command == "env-vars":
168+
print_help_env_vars()
169+
sys.exit(0)
170+
171+
if parsed.command == "commands":
172+
print_help_commands(cli.ops)
173+
sys.exit(0)
174+
175+
if parsed.command == "plugins":
176+
print_help_plugins(cli.config)
158177
sys.exit(0)
159178

160179
# configure
@@ -224,6 +243,7 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
224243
if (
225244
parsed.command not in cli.ops
226245
and parsed.command not in plugins.available(cli.config)
246+
and parsed.command not in HELP_TOPICS
227247
):
228248
print(f"Unrecognized command {parsed.command}")
229249
sys.exit(1)
@@ -243,9 +263,13 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
243263
for action, op in cli.ops[parsed.command].items()
244264
]
245265

246-
table = Table("action", "summary")
266+
table = Table(
267+
Column(header="action", no_wrap=True),
268+
Column(header="summary", style="cyan"),
269+
)
247270
for row in content:
248271
table.add_row(*row)
272+
249273
rprint(table)
250274
sys.exit(0)
251275

linodecli/baked/colors.py

Lines changed: 0 additions & 64 deletions
This file was deleted.

linodecli/baked/response.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
from openapi3.paths import MediaType
66

7-
from .colors import colorize_string
8-
97

108
def _is_paginated(response):
119
"""
@@ -112,9 +110,9 @@ def _get_value(self, model):
112110

113111
def render_value(self, model, colorize=True):
114112
"""
115-
Given the model returned from the API, returns the correctly- rendered
113+
Given the model returned from the API, returns the correctly rendered
116114
version of it. This can transform text based on various rules
117-
configured in the spec using custom tags. Currently supported tags:
115+
configured in the spec using custom tags. Currently supported tags:
118116
119117
x-linode-cli-color
120118
A list of key-value pairs that represent the value, and its ideal color.
@@ -125,10 +123,10 @@ def render_value(self, model, colorize=True):
125123
if isinstance(value, list):
126124
value = ", ".join([str(c) for c in value])
127125
if colorize and self.color_map is not None:
128-
# Add color
126+
# Add color using rich tags
129127
value = str(value)
130128
color = self.color_map.get(value) or self.color_map["default_"]
131-
value = colorize_string(value, color)
129+
value = f"[{color}]{value}[/]"
132130
if value is None:
133131
# Prints the word None if you don't change it
134132
value = ""

linodecli/help_pages.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,22 @@
3131
"(e.g. 'https')",
3232
}
3333

34+
HELP_TOPICS = {
35+
"env-vars": "Environment variables that can be used",
36+
"commands": "Learn about all available commands with linode-cli",
37+
"plugins": " Learn about all available plugins registered to linode-cli",
38+
}
3439

35-
# pylint: disable=too-many-locals
36-
def print_help_default(ops, config):
37-
"""
38-
Prints help output with options from the API spec
40+
41+
def print_help_env_vars():
3942
"""
43+
Print Environment variables overrides. Usage:
4044
41-
# Environment variables overrides
42-
print("\nEnvironment variables:")
45+
linode-cli env-vars
46+
"""
47+
rprint("\n[bold cyan]Environment variables:")
4348

44-
table = Table(show_header=True, header_style="", box=box.SQUARE)
49+
table = Table(show_header=True, header_style="bold", box=box.SQUARE)
4550
table.add_column("Name")
4651
table.add_column("Description")
4752

@@ -50,32 +55,39 @@ def print_help_default(ops, config):
5055

5156
rprint(table)
5257

58+
59+
def print_help_commands(ops):
60+
"""
61+
Prints available commands. Usage:
62+
63+
linode-cli commands
64+
"""
5365
# commands to manage CLI users (don't call out to API)
54-
print("\nCLI user management commands:")
66+
rprint("\n[bold cyan]CLI user management commands:")
5567
um_commands = [["configure", "set-user", "show-users"], ["remove-user"]]
5668
table = Table(show_header=False)
5769
for cmd in um_commands:
5870
table.add_row(*cmd)
5971
rprint(table)
6072

6173
# commands to manage plugins (don't call out to API)
62-
print("\nCLI Plugin management commands:")
74+
rprint("\n[bold cyan]CLI Plugin management commands:")
6375
pm_commands = [["register-plugin", "remove-plugin"]]
6476
table = Table(show_header=False)
6577
for cmd in pm_commands:
6678
table.add_row(*cmd)
6779
rprint(table)
6880

6981
# other CLI commands
70-
print("\nOther CLI commands:")
82+
rprint("\n[bold cyan]Other CLI commands:")
7183
other_commands = [["completion"]]
7284
table = Table(show_header=False)
7385
for cmd in other_commands:
7486
table.add_row(*cmd)
7587
rprint(table)
7688

7789
# commands generated from the spec (call the API directly)
78-
print("\nAvailable commands:")
90+
rprint("\n[bold cyan]Available commands:")
7991

8092
content = list(sorted(ops.keys()))
8193
proc = []
@@ -89,10 +101,16 @@ def print_help_default(ops, config):
89101
table.add_row(*cmd)
90102
rprint(table)
91103

92-
# plugins registered to the CLI (do arbitrary things)
104+
105+
def print_help_plugins(config):
106+
"""
107+
Print available plugins registered to the CLI (do arbitrary things). Usage:
108+
109+
linode-cli plugins
110+
"""
93111
if plugins.available(config):
94112
# only show this if there are any available plugins
95-
print("Available plugins:")
113+
rprint("\n[bold cyan]Available plugins:")
96114

97115
plugin_content = list(plugins.available(config))
98116
plugin_proc = []
@@ -107,7 +125,15 @@ def print_help_default(ops, config):
107125
plugin_table.add_row(*plugin)
108126
rprint(plugin_table)
109127

110-
print("\nTo reconfigure, call `linode-cli configure`")
128+
129+
def print_help_default():
130+
"""
131+
Prints help output with options from the API spec
132+
"""
133+
rprint("\n[bold cyan]Help Topics")
134+
for k, v in HELP_TOPICS.items():
135+
print(" " + k + ": " + v)
136+
rprint("\n[bold]To reconfigure[/], call `linode-cli configure`")
111137
print(
112138
"For comprehensive documentation, "
113139
"visit https://www.linode.com/docs/api/"
@@ -134,11 +160,11 @@ def print_help_action(
134160
console.print(f" [{pname}]", end="")
135161

136162
console.print()
137-
console.print(f"[bold]{op.summary}[/]")
163+
console.print(f"[cyan]{op.summary}[/]")
138164

139165
if op.docs_url:
140166
console.print(
141-
f"[bold]API Documentation: [link={op.docs_url}]{op.docs_url}[/link][/]"
167+
f"[bold]API Documentation[/]: [link={op.docs_url}]{op.docs_url}[/link]"
142168
)
143169

144170
if len(op.samples) > 0:

linodecli/output.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from rich import print as rprint
1313
from rich.console import OverflowMethod
1414
from rich.table import Column, Table
15-
from rich.text import Text
1615

1716
from linodecli.baked.response import OpenAPIResponse, OpenAPIResponseAttr
1817

@@ -288,13 +287,13 @@ def _table_output(
288287

289288
tab = Table(
290289
*header_columns,
291-
header_style="",
290+
header_style="bold",
292291
box=box_style,
293292
show_header=self.headers,
294293
title_justify="left",
294+
show_lines=True,
295295
)
296296
for row in content:
297-
row = [Text.from_ansi(item) for item in row]
298297
tab.add_row(*row)
299298

300299
if title is not None and self.headers:

linodecli/overrides.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from typing import Dict
88

9+
from rich import box
10+
from rich import print as rprint
911
from rich.align import Align
1012
from rich.console import Console
1113
from rich.table import Table
@@ -65,7 +67,10 @@ def linode_types_with_region_prices(
6567
if len(json_data["data"]) < 1:
6668
return True
6769

68-
output = Table()
70+
output = Table(
71+
header_style="bold",
72+
show_lines=True,
73+
)
6974

7075
# To ensure the order of the headers and make sure we have region_prices as the last column
7176
headers = sorted(
@@ -96,11 +101,11 @@ def linode_types_with_region_prices(
96101
console = Console()
97102
console.print(output)
98103

99-
print(
100-
"See our [Pricing Page](https://www.linode.com/pricing/) for Region-specific pricing, "
101-
+ "which applies after migration is complete."
104+
rprint(
105+
"[cyan]See our [Pricing Page](https://www.linode.com/pricing/) "
106+
"for Region-specific pricing, "
107+
"which applies after migration is complete."
102108
)
103-
104109
return False
105110

106111

@@ -119,7 +124,7 @@ def format_region_prices(data: Dict[str, any]) -> any:
119124
"""
120125
subheaders = ["id", "hourly", "monthly"]
121126

122-
sub_table = Table()
127+
sub_table = Table(box=box.SIMPLE_HEAVY)
123128

124129
for header in subheaders:
125130
sub_table.add_column(header, justify="center")

linodecli/plugins/obj/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def print_help(parser: ArgumentParser):
269269

270270
# additional help
271271
print()
272-
print("Available commands: ")
272+
rprint("[bold cyan]Available commands: ")
273273

274274
command_help_map = [
275275
[name, func.__doc__.strip()]

linodecli/plugins/obj/helpers.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from datetime import datetime
99

1010
from rich.table import Table
11-
from rich.text import Text
1211

1312
from linodecli.plugins.obj.config import DATE_FORMAT
1413

@@ -126,7 +125,6 @@ def _borderless_table(data):
126125
"""
127126
tab = Table.grid(padding=(0, 2, 0, 2))
128127
for row in data:
129-
row = [Text.from_ansi(str(item)) for item in row]
130128
tab.add_row(*row)
131129

132130
return tab

0 commit comments

Comments
 (0)