def OpenReferencePage(line, pos): tokens = gcloud_parser.ParseLine(line) tokens = [x for x in tokens if x.start < pos] url = _GetReferenceURL(tokens) browser = webbrowser.get() webbrowser.subprocess = FakeSubprocessModule() browser.open_new_tab(url)
def _GetReferenceURL(line, pos=None): """Determine the reference url of the command/group preceeding the pos. Args: line: a string with the current string directly from the shell. pos: the position of the cursor on the line. Returns: A string containing the URL of the reference page. """ if pos is None: pos = len(line) prefix = u'https://cloud.google.com/sdk/gcloud/reference/' invocations = gcloud_parser.ParseLine(line) if not invocations: return prefix tokens = invocations[-1].tokens tokens = [x for x in tokens if x.start < pos] invocation = gcloud_parser.GcloudInvocation(tokens) cmd = invocation.GetCommandOrGroup() if not cmd: return prefix return prefix + '/'.join(cmd.tree['path'][1:])
def GenerateHelpContent(cli, width): """Generates and renders the corresponding help content in the gcloud shell. Args: cli: the CLI in which to render the help contents. width: the width of the help prompt. Returns: A list with one list per line, each containing (token, string) tuples for words in the help text. These tuples represent (Markdown format, actual text) pairs. """ if width > 80: width = 80 doc = cli.current_buffer.document tok = GetCurrentToken(gcloud_parser.ParseLine(doc.text), doc.cursor_position) if not tok: return [] if tok.token_type == gcloud_parser.ArgTokenType.COMMAND: return GenerateHelpForCommand(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.GROUP: return GenerateHelpForCommand(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.FLAG: return GenerateHelpForFlag(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.FLAG_ARG: return GenerateHelpForFlag(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.POSITIONAL: return GenerateHelpForPositional(tok, width) return []
def GetHelpTokens(cli): doc = cli.current_buffer.document tok = GetCurrentToken(gcloud_parser.ParseLine(doc.text), doc.cursor_position) if tok is None: return [] return [(Token.HelpToolbar.SectionName, 'Description: '), (Token.HelpToolbar.SectionValue, tok.tree['description'])]
def GenerateHelpContent(cli, width): if width > 80: width = 80 doc = cli.current_buffer.document tok = GetCurrentToken(gcloud_parser.ParseLine(doc.text), doc.cursor_position) if not tok: return [] if tok.token_type == gcloud_parser.ArgTokenType.COMMAND: return GenerateHelpForCommand(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.GROUP: return GenerateHelpForCommand(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.FLAG: return GenerateHelpForFlag(tok, width) elif tok.token_type == gcloud_parser.ArgTokenType.POSITIONAL: return GenerateHelpForPositional(tok, width) return []
def get_completions(self, doc, complete_event): """Yields the completions for doc. Args: doc: A Document instance containing the shell command line to complete. complete_event: The CompleteEvent that triggered this completion. Yields: Completion instances for doc. """ commands = parser.ParseLine(doc.text_before_cursor) if not commands: return tokens = commands[-1] if not tokens: return if tokens[0].value != 'gcloud': gcloud_token = parser.ArgToken('gcloud', parser.ArgTokenType.GROUP, gcloud_tree, 0, 0) tokens = ([gcloud_token] + tokens) node = self.root info = None last_token = tokens[-1] path = [] # Autocomplete commands and groups after spaces. if (last_token.token_type == parser.ArgTokenType.GROUP and doc.cursor_position > last_token.end): for completion in CompleteCommandGroups(tokens): yield Completion(completion) return # Traverse the CLI tree. for token in tokens: if token.value in node: info = node[token.value] path.append(info) node = info.get('commands', {}) else: break last_token_name = last_token.value offset = -len(last_token_name) # Check for flags. if ((last_token_name.startswith('-') and info) or (last_token.token_type == parser.ArgTokenType.FLAG_ARG)): # Collect all non-hidden flags of current command and parents into node. node = FilterHiddenFlags(info.get('flags', {})) for info in path: node.update(FilterHiddenFlags(info.get('flags', {}))) if doc.text_before_cursor[-1].isspace(): return if last_token.token_type == parser.ArgTokenType.FLAG_ARG: flag_token = tokens[-2] if flag_token.value in node: choice_offset = doc.cursor_position - last_token.end info = node[flag_token.value] if info.get('type', None) != 'bool': choices = info.get('choices', None) if choices: # A flag with static choices. offset -= choice_offset for choice in choices: if choice.lower().startswith(last_token_name.lower()): yield Completion(choice, offset) return def _MetaTextForChoice(choice): if (self.experimental_autocomplete_enabled and FlagIsRequired(node[choice])): return 'required' ranked_completions = [] if self.experimental_autocomplete_enabled: ranked_completions = RankedCompletions(node, doc) else: ranked_completions = sorted(node) for choice in ranked_completions: if choice.startswith(last_token_name): yield Completion( choice, offset, display_meta=_MetaTextForChoice(choice))
def get_completions(self, doc, complete_event): """Yields the completions for doc. Args: doc: A Document instance containing the shell command line to complete. complete_event: The CompleteEvent that triggered this completion. Yields: Completion instances for doc. """ # Check there's at least one invocation invocations = parser.ParseLine(doc.text_before_cursor) if not invocations: return invocation = invocations[-1] # Check there's at least one token in the invocation tokens = invocation.tokens if not tokens: return # Only allow gcloud-related commands if tokens[0].value != 'gcloud': gcloud_token = parser.ArgToken('gcloud', parser.ArgTokenType.GROUP, gcloud_tree, 0, 0) tokens = ([gcloud_token] + tokens) invocation = parser.GcloudInvocation(tokens) last_token = tokens[-1] last_token_name = last_token.value offset = -len(last_token_name) suggestions = last_token.tree.get('commands', {}) # Autocomplete commands and groups after spaces if IsGroup(last_token): if CursorAheadOfToken(doc.cursor_position, last_token): offset = last_token.end - doc.cursor_position + 1 for completion in invocation.GetPossibleCommandGroups(): yield Completion(completion, offset) return elif IsFlag(last_token_name): suggestions = FilterHiddenFlags(invocation.GetPossibleFlags()) if CursorAheadOfToken(doc.cursor_position, last_token): offset = 0 # Check if the flag has a set of choices to choose from choices = suggestions.get(last_token.value, {}).get('choices', []) for choice in choices: yield Completion(choice, offset) return elif IsFlagArg(last_token): suggestions = FilterHiddenFlags(invocation.GetPossibleFlags()) flag_token = tokens[-2] if not CursorAheadOfToken(doc.cursor_position, last_token): # Check if the flag has a set of choices to choose from choices = suggestions.get(flag_token.value, {}).get('choices', []) for choice in choices: if choice.lower().startswith(last_token_name.lower()): yield Completion(choice, offset) return def _GetRankedCompletions(): if self.experimental_autocomplete_enabled: return RankedCompletions(suggestions, invocation) else: return sorted(suggestions) def _DisplayTextForChoice(choice): """Returns the appropriate display text for the given choice. If the choice is a non-bool flag and experimental autocomplete is enabled, an equal sign followed by the flag's metavariables will be shown. Otherwise, only the choice name will be shown. Args: choice: the choice for which to create the display text. Returns: The appropriate display text for the given choice. """ display_text = choice if self.experimental_autocomplete_enabled: if IsFlag(choice): flag_type = suggestions[choice].get('type', None) if flag_type != 'bool': display_text += '=' flag_arg_value = suggestions[choice].get('value', '') if flag_type == 'list' or flag_type == 'dict': display_text += '[' + flag_arg_value + ',...]' else: display_text += flag_arg_value return display_text def _MetaTextForChoice(choice): if (self.experimental_autocomplete_enabled and FlagIsRequired(suggestions[choice])): return 'required' ranked_completions = _GetRankedCompletions() for choice in ranked_completions: if choice.startswith(last_token_name): yield Completion(choice, offset, display=_DisplayTextForChoice(choice), display_meta=_MetaTextForChoice(choice))
def get_completions(self, doc, complete_event): """Yields the completions for doc. Args: doc: A Document instance containing the shell command line to complete. complete_event: The CompleteEvent that triggered this completion. Yields: Completion instances for doc. """ # Check there's at least one invocation invocations = parser.ParseLine(doc.text_before_cursor) if not invocations: return invocation = invocations[-1] # Check there's at least one token in the invocation tokens = invocation.tokens if not tokens: return # Only allow gcloud-related commands if tokens[0].value != 'gcloud': gcloud_token = parser.ArgToken('gcloud', parser.ArgTokenType.GROUP, gcloud_tree, 0, 0) tokens = ([gcloud_token] + tokens) invocation = parser.GcloudInvocation(tokens) last_token = tokens[-1] last_token_name = last_token.value offset = -len(last_token_name) suggestions = last_token.tree.get('commands', {}) if IsFlag(last_token_name) or IsFlagArg(last_token): suggestions = FilterHiddenFlags(invocation.GetPossibleFlags()) cursor_ahead = CursorAheadOfToken(doc.cursor_position, last_token) if IsGroup(last_token) and cursor_ahead: # Autocomplete commands and groups after spaces offset = last_token.end - doc.cursor_position + 1 for completion in invocation.GetPossibleCommandGroups(): yield Completion(completion, offset) elif IsFlag(last_token_name) and cursor_ahead: # Check if the flag has a set of choices to choose from offset = 0 choices = suggestions.get(last_token.value, {}).get('choices', []) for choice in choices: yield Completion(choice, offset) elif IsFlagArg(last_token): if cursor_ahead: return else: # Check if the flag has a set of choices to choose from flag_token = tokens[-2] choices = suggestions.get(flag_token.value, {}).get('choices', []) for choice in choices: if choice.lower().startswith(last_token_name.lower()): yield Completion(choice, offset) else: ranked_completions = self._GetRankedCompletions( suggestions, invocation) for choice in ranked_completions: if choice.startswith(last_token_name): yield Completion(choice, offset, display=self._DisplayTextForChoice( choice, suggestions[choice]), display_meta=self._MetaTextForChoice( suggestions[choice], invocation))