-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Fixes/changes to interactive history #5636
Changes from 2 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 |
---|---|---|
|
@@ -34,7 +34,7 @@ | |
from azclishell.frequency_heuristic import DISPLAY_TIME, frequency_heuristic | ||
from azclishell.gather_commands import add_new_lines, GatherCommands | ||
from azclishell.key_bindings import InteractiveKeyBindings | ||
from azclishell.layout import create_layout, create_tutorial_layout, set_scope | ||
from azclishell.layout import create_layout, create_tutorial_layout, set_scope, get_scope | ||
from azclishell.progress import progress_view | ||
from azclishell.telemetry import Telemetry | ||
from azclishell.threads import LoadCommandTableThread | ||
|
@@ -88,8 +88,8 @@ def restart_completer(shell_ctx): | |
# pylint: disable=too-many-instance-attributes | ||
class AzInteractiveShell(object): | ||
|
||
def __init__(self, cli_ctx, style=None, completer=None, styles=None, | ||
lexer=None, history=InMemoryHistory(), | ||
def __init__(self, cli_ctx, style=None, completer=None, | ||
lexer=None, history=None, | ||
app=None, input_custom=sys.stdin, output_custom=None, | ||
user_feedback=False, intermediate_sleep=.25, final_sleep=4): | ||
|
||
|
@@ -106,7 +106,8 @@ def __init__(self, cli_ctx, style=None, completer=None, styles=None, | |
self.completer = completer or AzCompleter(self, GatherCommands(self.config)) | ||
except IOError: # if there is no cache | ||
self.completer = None | ||
self.history = history or FileHistory(os.path.join(self.config.config_dir, self.config.get_history())) | ||
self._default_history = history or FileHistory(os.path.join(self.config.config_dir, self.config.get_history())) | ||
self.history = self._default_history | ||
os.environ[ENV_ADDITIONAL_USER_AGENT] = 'AZURECLISHELL/' + __version__ | ||
self.telemetry = Telemetry(self.cli_ctx) | ||
|
||
|
@@ -142,7 +143,7 @@ def __init__(self, cli_ctx, style=None, completer=None, styles=None, | |
def __call__(self): | ||
|
||
if self.cli_ctx.data["az_interactive_active"]: | ||
logger.warning("You're in the interactive shell already.\n") | ||
logger.warning("You're in the interactive shell already.") | ||
return | ||
|
||
if self.config.BOOLEAN_STATES[self.config.config.get('DEFAULT', 'firsttime')]: | ||
|
@@ -527,7 +528,7 @@ def _special_cases(self, cmd, outside): | |
elif SELECT_SYMBOL['example'] in cmd: | ||
cmd, continue_flag = self.handle_example(cmd, continue_flag) | ||
self.telemetry.track_ssg('tutorial', cmd) | ||
elif len(cmd_stripped) > 2 and SELECT_SYMBOL['scope'] == cmd_stripped[0:2]: | ||
elif SELECT_SYMBOL['scope'] == cmd_stripped[0:2]: | ||
continue_flag, cmd = self.handle_scoping_input(continue_flag, cmd, cmd_stripped) | ||
|
||
return break_flag, continue_flag, outside, cmd | ||
|
@@ -579,6 +580,7 @@ def handle_scoping_input(self, continue_flag, cmd, text): | |
cmd = cmd.replace(SELECT_SYMBOL['scope'], '') | ||
|
||
continue_flag = True | ||
original_scope = get_scope() | ||
|
||
if not default_split: | ||
self.default_command = "" | ||
|
@@ -604,8 +606,7 @@ def handle_scoping_input(self, continue_flag, cmd, text): | |
cmd = cmd.replace(SELECT_SYMBOL['scope'], '') | ||
self.telemetry.track_ssg('scope command', value) | ||
|
||
elif SELECT_SYMBOL['unscope'] == default_split[0] and \ | ||
len(self.default_command.split()) > 0: | ||
elif SELECT_SYMBOL['unscope'] == default_split[0] and self.default_command.split(): | ||
|
||
value = self.default_command.split()[-1] | ||
self.default_command = ' ' + ' '.join(self.default_command.split()[:-1]) | ||
|
@@ -619,8 +620,16 @@ def handle_scoping_input(self, continue_flag, cmd, text): | |
print("Scope must be a valid command", file=self.output) | ||
|
||
default_split = default_split[1:] | ||
if not get_scope(): | ||
self.set_history(history=self._default_history) | ||
elif get_scope() != original_scope: | ||
self.set_history(history=InMemoryHistory()) | ||
return continue_flag, cmd | ||
|
||
def set_history(self, history=None): | ||
self.history = history | ||
self.cli.buffers[DEFAULT_BUFFER].history = history | ||
|
||
def cli_execute(self, cmd): | ||
""" sends the command to the CLI to be executed """ | ||
|
||
|
@@ -709,9 +718,9 @@ def run(self): | |
# when the user pressed Control D | ||
break | ||
else: | ||
self.history.append(text) | ||
b_flag, c_flag, outside, cmd = self._special_cases(cmd, outside) | ||
if not self.default_command: | ||
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. What is default_command? 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. It's the scope; empty string if not in one. 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. Seems to me then we should still not commit the default command to history? We wouldn't want empty strings appended. 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. We don't. The default_command is no longer included within history. |
||
self.history.append(text) | ||
|
||
if b_flag: | ||
break | ||
if c_flag: | ||
|
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.
I don't really understand this. If I was in a scope, say "network" and ran
public-ip create ...
why wouldnetwork public-ip- create ...
not appear in history? It sounds likepublic-ip create
would appear while I'm in the "network" scope but then when I change scope, that history vanishes. Is that right?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.
Yes, that's right, the reason why I did this is because the scoping commands
%% <whatever>
would not apply once the scope is changed, so at the very least, they should not be saved.The other option would be to match for different scenarios and save accordingly. i.e., scope commands are not saved, cli commands have the scope appended, non-azure cli commands (using
#
) are saved alone, etc.In addition, inside a scope, some history is no longer valid. i.e. all commands from other scopes. Thus, we would also need to parse through the history if all scopes use the same source.
This can be confusing, a user may wonder why some things are showing up, some aren't, and why some differ from what they typed.
To me, having a simpler rule defined, where scoping creates a different "environment" of sorts with its own history seems much more intuitive. Once that environment is left, the history is cleaned up and gone.
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.
After discussion with @tjprescott, decided to go with one source of history for all commands, no matter the scope.
It will be up to the user to deal with history from different scopes.
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.
After our discussion, I think what we agreed upon was:
IMO its a little less user-focused, but it's better than being broken. If you add support for ~ then bonus points :)