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

[Interactive] Optimize the visualization of help text when the window is reduced horizontally #6611

Merged
merged 7 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/interactive/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Release History
===============

0.5.3
+++++
* Optimize the visualization of help text when the window is reduced horizontally

0.5.2
+++++
* Add command skipped message in Scenario Execution Mode
Expand Down
2 changes: 1 addition & 1 deletion src/interactive/azext_interactive/azclishell/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

VERSION = '0.5.2'
VERSION = '0.5.3'
42 changes: 37 additions & 5 deletions src/interactive/azext_interactive/azclishell/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,15 @@ def on_input_timeout(self, cli):
self._update_default_info()

cli.buffers['description'].reset(
initial_document=Document(self.description_docs, cursor_position=0))
initial_document=Document(self._wrap_desc_param(self.description_docs), cursor_position=0))
cli.buffers['parameter'].reset(
initial_document=Document(self.param_docs))
initial_document=Document(self._wrap_desc_param(self.param_docs)))
cli.buffers['examples'].reset(
initial_document=Document(self.example_docs))
cli.buffers['default_values'].reset(
initial_document=Document(
u'{}'.format(self.config_default if self.config_default else 'No Default Values')))
self._update_help_text()
self._update_toolbar()
cli.request_redraw()

Expand All @@ -246,6 +247,21 @@ def redraw_scenario_recommendation_info(self):
initial_document=Document(u'{}'.format(scenarios_rec_info)))
self.cli.request_redraw()

def _desc_param_buffer_width(self):
_, cols = get_window_dim()
# The rightmost column in window doesn't seem to be used
cols = int(cols) - 1
if self.config.get_boolean('Layout', 'command_description') \
and self.config.get_boolean('Layout', 'param_description'):
return (cols - 1) // 2
else:
return cols

def _wrap_desc_param(self, content, max_lines=4):
width = self._desc_param_buffer_width()
from textwrap import fill
return fill(content, width=width, max_lines=max_lines, placeholder='...')

def _space_examples(self, list_examples, rows, section_value):
""" makes the example text """
examples_with_index = []
Expand Down Expand Up @@ -277,6 +293,25 @@ def _space_examples(self, list_examples, rows, section_value):

return example + page_number + ' CTRL+Y (^) CTRL+N (v)'

def _update_help_text(self):
_, cols = get_window_dim()
cols = int(cols) - 1

from .configuration import GESTURE_INFO, GESTURE_LENGTH
from textwrap import fill
lines = []
for key in GESTURE_INFO:
# Build the help text of each GESTURE_INFO, use `fill` to support wrap(but here we fix the max_lines to 1)
# `subsequent_indent` is to align the lines of GESTURE_INFO with the first line
# e.g.
# %%[cmd] : set a scope, and scopes
# can be chained
lines.append(fill(GESTURE_INFO[key], initial_indent=key.ljust(GESTURE_LENGTH) + ': ',
subsequent_indent=' ' * (GESTURE_LENGTH + 2), width=cols, max_lines=1,
placeholder='...'))
ReaNAiveD marked this conversation as resolved.
Show resolved Hide resolved

self.cli.buffers['symbols'].reset(initial_document=Document(u'{}'.format('\n'.join(lines))))

def _update_toolbar(self):
cli = self.cli
_, cols = get_window_dim()
Expand Down Expand Up @@ -956,9 +991,6 @@ def run(self):
self.cli_ctx.get_progress_controller().init_progress(ShellProgressView())
self.cli_ctx.get_progress_controller = self.progress_patch

from .configuration import SHELL_HELP
self.cli.buffers['symbols'].reset(
initial_document=Document(u'{}'.format(SHELL_HELP)))
# flush telemetry for new commands and send successful interactive mode entry event
telemetry.set_success()
telemetry.flush()
Expand Down
31 changes: 10 additions & 21 deletions src/interactive/azext_interactive/azclishell/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,19 @@

GESTURE_INFO = {
# pylint: disable=line-too-long
SELECT_SYMBOL['search'] + ' [keyword]': "search for commands and scenarios",
SELECT_SYMBOL['search'] + '[keyword]': "search for commands and scenarios",
SELECT_SYMBOL['outside'] + "[cmd]": "use commands outside the application",
SELECT_SYMBOL['example'] + " [num]": "complete a recommended scenario step by step",
"[cmd] + [param] +" + "\"" + SELECT_SYMBOL[
'query'] + "[query]" + "\"": "Inject jmespath query from previous command",
"\"" + SELECT_SYMBOL['query'] + "[query]" + "\"": "Jmespath query of the previous command",
"[cmd] " + SELECT_SYMBOL['example'] + " [num]": "do a step by step tutorial of example",
SELECT_SYMBOL['example'] + "[num]": "complete a recommended scenario step by step",
"[cmd][param]" + SELECT_SYMBOL['query'] + "[query]": "Inject jmespath query from previous command",
SELECT_SYMBOL['query'] + "[query]": "Jmespath query of the previous command",
"[cmd]" + SELECT_SYMBOL['example'] + "[num]": "do a step by step tutorial of example",
SELECT_SYMBOL['exit_code']: "get the exit code of the previous command",
SELECT_SYMBOL['scope'] + '[cmd]': "set a scope, and scopes can be chained with spaces",
SELECT_SYMBOL['scope'] + ' ' + SELECT_SYMBOL['unscope']: "go back a scope",
SELECT_SYMBOL['scope'] + SELECT_SYMBOL['unscope']: "go back a scope",
}

CONFIG_FILE_NAME = 'shell-config'
GESTURE_LENGTH = max(len(key) for key in GESTURE_INFO) + 1


def help_text(values):
""" reformats the help text """
result = ""
for key in values:
# ' '.join('' for x in range(GESTURE_LENGTH - len(key))) is used to make the help text aligned
# Example: If values = {'/ [keyword]': 'description1', '#[cmd]': 'description2'}, the result will be:'/ [keyword]: description1\n#[cmd] : description2\n'
result += key + ' '.join('' for x in range(GESTURE_LENGTH - len(key))) + ': ' + values[key] + '\n'
return result


SHELL_HELP = help_text(GESTURE_INFO)
GESTURE_LENGTH = max(len(key) for key in GESTURE_INFO)


class Configuration(object):
Expand Down Expand Up @@ -150,6 +136,9 @@ def update(self):
with open(os.path.join(self.config_dir, CONFIG_FILE_NAME), 'w') as config_file:
self.config.write(config_file)

def get_boolean(self, section, option):
return self.BOOLEAN_STATES[self.config.get(section, option)]


def ask_user_for_telemetry():
""" asks the user for if we can collect telemetry """
Expand Down