From 3e958f5f655872fde690178b4562e4a5f5b1220c Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Wed, 2 Aug 2023 14:00:52 +0800 Subject: [PATCH 1/7] Shorten help text --- src/interactive/HISTORY.rst | 4 +++ .../azext_interactive/azclishell/app.py | 22 +++++++++++++-- .../azclishell/configuration.py | 28 +++++-------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/interactive/HISTORY.rst b/src/interactive/HISTORY.rst index 61c6ad834ca..f6f0d11f022 100644 --- a/src/interactive/HISTORY.rst +++ b/src/interactive/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +upcoming ++++++ +* Optimize the visualization of help text when the window is reduced horizontally + 0.5.2 +++++ * Add command skipped message in Scenario Execution Mode diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index 230c8c2de6a..90abbe205b3 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -222,6 +222,7 @@ def on_input_timeout(self, cli): 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() @@ -277,6 +278,24 @@ 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 + info_width = cols - GESTURE_LENGTH - 2 + + def add_ellip(info): + if info_width <= 0: + return '' + elif len(info) <= info_width: + return info + else: + return info[:info_width-3]+'...' + + lines = ['{}: {}'.format(key.ljust(GESTURE_LENGTH), add_ellip(GESTURE_INFO[key])) for key in GESTURE_INFO] + self.cli.buffers['symbols'].reset(initial_document=Document(u'{}'.format('\n'.join(lines)))) + def _update_toolbar(self): cli = self.cli _, cols = get_window_dim() @@ -956,9 +975,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() diff --git a/src/interactive/azext_interactive/azclishell/configuration.py b/src/interactive/azext_interactive/azclishell/configuration.py index ef6b248427f..c5bd43ae900 100644 --- a/src/interactive/azext_interactive/azclishell/configuration.py +++ b/src/interactive/azext_interactive/azclishell/configuration.py @@ -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): From a538a7408ca1c9740b881dabf002516f97da47be Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Thu, 3 Aug 2023 09:35:06 +0800 Subject: [PATCH 2/7] wrap desc and param in help --- .../azext_interactive/azclishell/app.py | 42 ++++++++++++++++++- .../azclishell/configuration.py | 3 ++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index 90abbe205b3..c0ce25894a0 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -214,9 +214,9 @@ 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, 3), cursor_position=0)) cli.buffers['parameter'].reset( - initial_document=Document(self.param_docs)) + initial_document=Document(self._wrap_desc_param(self.param_docs, 3))) cli.buffers['examples'].reset( initial_document=Document(self.example_docs)) cli.buffers['default_values'].reset( @@ -247,6 +247,44 @@ 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): + lines = [] + width = self._desc_param_buffer_width() + for raw_line in content.split('\n'): + remains = raw_line + while len(lines) < max_lines: + if len(remains) <= width: + lines.append(remains) + break + elif len(remains) == width + 1: + lines.append(remains[:width]) + lines.append(remains[width:]) + break + line = remains[:width+1] + if line[-1] == ' ': + lines.append(line.strip()) + remains = remains[width+1:] + elif line[-2] == ' ': + lines.append(line[:-2]) + remains = remains[width:] + elif line[-3] == ' ': + lines.append(line[:-3]) + remains = remains[width-1:] + else: + lines.append(line[:-2]+'-') + remains = remains[width-1:] + return '\n'.join(lines[:max_lines]) + def _space_examples(self, list_examples, rows, section_value): """ makes the example text """ examples_with_index = [] diff --git a/src/interactive/azext_interactive/azclishell/configuration.py b/src/interactive/azext_interactive/azclishell/configuration.py index c5bd43ae900..a2b2e26a17a 100644 --- a/src/interactive/azext_interactive/azclishell/configuration.py +++ b/src/interactive/azext_interactive/azclishell/configuration.py @@ -136,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 """ From 2a46238877e64fa0cb874cd678fb7e4c17da9cc0 Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Fri, 4 Aug 2023 16:26:17 +0800 Subject: [PATCH 3/7] change some logic --- src/interactive/azext_interactive/azclishell/app.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index c0ce25894a0..f7a033863fa 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -214,9 +214,9 @@ def on_input_timeout(self, cli): self._update_default_info() cli.buffers['description'].reset( - initial_document=Document(self._wrap_desc_param(self.description_docs, 3), cursor_position=0)) + initial_document=Document(self._wrap_desc_param(self.description_docs), cursor_position=0)) cli.buffers['parameter'].reset( - initial_document=Document(self._wrap_desc_param(self.param_docs, 3))) + 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( @@ -257,19 +257,17 @@ def _desc_param_buffer_width(self): else: return cols - def _wrap_desc_param(self, content, max_lines): + def _wrap_desc_param(self, content, max_lines=4): lines = [] width = self._desc_param_buffer_width() for raw_line in content.split('\n'): remains = raw_line while len(lines) < max_lines: + if len(remains) <= 0: + break if len(remains) <= width: lines.append(remains) break - elif len(remains) == width + 1: - lines.append(remains[:width]) - lines.append(remains[width:]) - break line = remains[:width+1] if line[-1] == ' ': lines.append(line.strip()) From a0f5650606c2e1b2abc177cb4dc4eae0c4da5710 Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Mon, 7 Aug 2023 14:58:58 +0800 Subject: [PATCH 4/7] Use `textwrap` to support Wrap --- .../azext_interactive/azclishell/app.py | 41 ++++--------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index f7a033863fa..e30e271070f 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -258,30 +258,9 @@ def _desc_param_buffer_width(self): return cols def _wrap_desc_param(self, content, max_lines=4): - lines = [] width = self._desc_param_buffer_width() - for raw_line in content.split('\n'): - remains = raw_line - while len(lines) < max_lines: - if len(remains) <= 0: - break - if len(remains) <= width: - lines.append(remains) - break - line = remains[:width+1] - if line[-1] == ' ': - lines.append(line.strip()) - remains = remains[width+1:] - elif line[-2] == ' ': - lines.append(line[:-2]) - remains = remains[width:] - elif line[-3] == ' ': - lines.append(line[:-3]) - remains = remains[width-1:] - else: - lines.append(line[:-2]+'-') - remains = remains[width-1:] - return '\n'.join(lines[:max_lines]) + 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 """ @@ -319,17 +298,13 @@ def _update_help_text(self): cols = int(cols) - 1 from .configuration import GESTURE_INFO, GESTURE_LENGTH - info_width = cols - GESTURE_LENGTH - 2 - - def add_ellip(info): - if info_width <= 0: - return '' - elif len(info) <= info_width: - return info - else: - return info[:info_width-3]+'...' + from textwrap import fill + lines = [] + for key in GESTURE_INFO: + lines.append(fill(GESTURE_INFO[key], initial_indent=key.ljust(GESTURE_LENGTH) + ': ', + subsequent_indent=' ' * (GESTURE_LENGTH + 2), width=cols, max_lines=2, + placeholder='...')) - lines = ['{}: {}'.format(key.ljust(GESTURE_LENGTH), add_ellip(GESTURE_INFO[key])) for key in GESTURE_INFO] self.cli.buffers['symbols'].reset(initial_document=Document(u'{}'.format('\n'.join(lines)))) def _update_toolbar(self): From 3ce3144203e5a240e81f71c7a03e31ba5aae331c Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Tue, 8 Aug 2023 14:39:14 +0800 Subject: [PATCH 5/7] single line help content --- src/interactive/azext_interactive/azclishell/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index e30e271070f..850e82c7b02 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -302,7 +302,7 @@ def _update_help_text(self): lines = [] for key in GESTURE_INFO: lines.append(fill(GESTURE_INFO[key], initial_indent=key.ljust(GESTURE_LENGTH) + ': ', - subsequent_indent=' ' * (GESTURE_LENGTH + 2), width=cols, max_lines=2, + subsequent_indent=' ' * (GESTURE_LENGTH + 2), width=cols, max_lines=1, placeholder='...')) self.cli.buffers['symbols'].reset(initial_document=Document(u'{}'.format('\n'.join(lines)))) From a2a329fbd1a8d386b60a5612c7c8e098aa86c2a5 Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Thu, 10 Aug 2023 09:52:04 +0800 Subject: [PATCH 6/7] add comment to explain the textwrap.fill --- src/interactive/azext_interactive/azclishell/app.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/interactive/azext_interactive/azclishell/app.py b/src/interactive/azext_interactive/azclishell/app.py index 850e82c7b02..bfadd3e2013 100644 --- a/src/interactive/azext_interactive/azclishell/app.py +++ b/src/interactive/azext_interactive/azclishell/app.py @@ -301,6 +301,11 @@ def _update_help_text(self): 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='...')) From e6af99b209820939100099361a796bfe61078f39 Mon Sep 17 00:00:00 2001 From: qinkaiwu Date: Fri, 11 Aug 2023 09:36:58 +0800 Subject: [PATCH 7/7] Release --- src/interactive/HISTORY.rst | 2 +- src/interactive/azext_interactive/azclishell/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interactive/HISTORY.rst b/src/interactive/HISTORY.rst index f6f0d11f022..0ef82e3085c 100644 --- a/src/interactive/HISTORY.rst +++ b/src/interactive/HISTORY.rst @@ -3,7 +3,7 @@ Release History =============== -upcoming +0.5.3 +++++ * Optimize the visualization of help text when the window is reduced horizontally diff --git a/src/interactive/azext_interactive/azclishell/__init__.py b/src/interactive/azext_interactive/azclishell/__init__.py index 484c399852c..a7b8e9c0b87 100644 --- a/src/interactive/azext_interactive/azclishell/__init__.py +++ b/src/interactive/azext_interactive/azclishell/__init__.py @@ -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'