def test_pathcompleter_respects_completions_under_min_input_len(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # min len:1 and no text with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # min len:1 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = '1' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert [''] == result # min len:0 and text of len 2 with chdir(test_dir): completer = PathCompleter(min_input_len=0) doc_text = '1' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert [''] == result # create 10 files with a 2 char long name for i in range(10): with open(os.path.join(test_dir, str(i) * 2), 'wb') as out: out.write(b'') # min len:1 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = '2' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted(c.text for c in completions) assert ['', '2'] == result # min len:2 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=2) doc_text = '2' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_completes_directories_with_only_directories(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # create a sub directory there os.mkdir(os.path.join(test_dir, 'subdir')) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep with chdir(test_dir): completer = PathCompleter(only_directories=True) doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert ['subdir'] == result # check that there is no completion when passing a file with chdir(test_dir): completer = PathCompleter(only_directories=True) doc_text = '1' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_respects_completions_under_min_input_len(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # min len:1 and no text with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # min len:1 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = "1" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert [""] == result # min len:0 and text of len 2 with chdir(test_dir): completer = PathCompleter(min_input_len=0) doc_text = "1" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert [""] == result # create 10 files with a 2 char long name for i in range(10): with open(os.path.join(test_dir, str(i) * 2), "wb") as out: out.write(b"") # min len:1 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=1) doc_text = "2" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted(c.text for c in completions) assert ["", "2"] == result # min len:2 and text of len 1 with chdir(test_dir): completer = PathCompleter(min_input_len=2) doc_text = "2" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_completes_directories_with_only_directories(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # create a sub directory there os.mkdir(os.path.join(test_dir, "subdir")) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep with chdir(test_dir): completer = PathCompleter(only_directories=True) doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert ["subdir"] == result # check that there is no completion when passing a file with chdir(test_dir): completer = PathCompleter(only_directories=True) doc_text = "1" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions # cleanup shutil.rmtree(test_dir)
def get_path_matches(self, _, word_before_cursor): completer = PathCompleter(expanduser=True) document = Document( text=word_before_cursor, cursor_position=len(word_before_cursor) ) for c in completer.get_completions(document, None): yield Match(completion=c, priority=(0,))
def test_pathcompleter_can_expanduser(): completer = PathCompleter(expanduser=True) doc_text = '~' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert len(completions) > 0
def test_pathcompleter_completes_in_current_directory(): completer = PathCompleter() doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert len(completions) > 0
def test_pathcompleter_does_not_expanduser_by_default(): completer = PathCompleter() doc_text = "~" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions
def test_pathcompleter_does_not_expanduser_by_default(): completer = PathCompleter() doc_text = '~' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert [] == completions
def test_pathcompleter_completes_in_current_directory(): completer = PathCompleter() doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert len(completions) > 0
def test_pathcompleter_can_expanduser(monkeypatch): monkeypatch.setenv('HOME', '/tmp') completer = PathCompleter(expanduser=True) doc_text = "~" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) assert len(completions) > 0
def get_path_matches(self, _, word_before_cursor): # pylint: disable=no-self-use # function cannot be static since it has to be a callable for get_completions completer = PathCompleter(expanduser=True) document = Document(text=word_before_cursor, cursor_position=len(word_before_cursor)) for c in completer.get_completions(document, None): yield Match(completion=c, priority=(0, ))
class ShellCompleter(Completer): """Completer for shell commands and EQL syntax.""" def __init__(self, shell): # type: (EqlShell) -> None """Completer for EQL shell.""" self.shell = shell self.command_completer = WordCompleter(lambda: shell.completenames(""), match_middle=True) self.path_completer = PathCompleter(expanduser=True) def get_completions(self, document, complete_event): """Get possible completions depending on context.""" completer = None complete_remaining = False complete_eql = False first_word = None if not self.shell.multiline: self.shell.prompt_session.lexer = None first_word = document.text and document.text.split()[0] if ' ' not in document.text: completer = self.command_completer elif first_word == "search": complete_eql = True self.shell.prompt_session.lexer = self.shell.tk_lexer elif first_word in ("input", "config", "output"): completer = self.path_completer complete_remaining = True else: self.shell.prompt_session.lexer = self.shell.tk_lexer complete_eql = True if complete_eql: word = document.get_word_before_cursor() for match in self.shell.complete_search(word, document.text, document.cursor_position, len(document.text), contains=True): yield Completion(match, -len(word)) return if completer: if complete_remaining: offset = len(first_word) + 1 path_doc = Document(document.text[offset:]) for completion in self.path_completer.get_completions(path_doc, complete_event): yield Completion(completion.text, 0, display=completion.display) else: for completion in completer.get_completions(document, complete_event): yield completion elif first_word: word = document.get_word_before_cursor() method = getattr(self.shell, "complete_" + first_word, None) if method: for match in method(word, document.text_before_cursor, document.cursor_position, len(document.text)): yield Completion(match, -len(word))
class ReplCompleter(Completer): CROW_COMMANDS = { "bootloader": "Reboot into bootloader", "clear": "Clear the saved user script", "first": "Set First as the current script and reboot", "help": "Show help", "identity": "Show crow's serial number", "kill": "Restart the Lua environment", "print": "Print the current user script", "quit": "Quit druid", "reset": "Reboot crow", "run": "Send a file to crow and run it", "upload": "Send a file to crow, store and run it", "version": "Print the current firmware version" } def __init__(self): self.path_completer = PathCompleter( file_filter=lambda s: os.path.isdir(s) or s.endswith('.lua') ) self.word_completer = WordCompleter( words=self.CROW_COMMANDS.keys(), ignore_case=True, meta_dict=self.CROW_COMMANDS, ) def offset_document(self, document, offset): move_cursor = len(document.current_line) - offset return Document( document.current_line[offset:], cursor_position=document.cursor_position - offset ) def get_completions(self, document, complete_event): line = document.current_line.lstrip() offset = len(document.current_line) - len(line) if line.startswith('^^'): line = line[2:] offset += 2 new_document = self.offset_document(document, offset) yield from self.word_completer.get_completions(new_document, complete_event) elif line.startswith('r ') or line.startswith('u '): line = line[2:] offset += 2 rem = line.lstrip() offset += len(line) - len(rem) new_document = self.offset_document(document, offset) yield from self.path_completer.get_completions(new_document, complete_event)
class CustomCompleter(NestedCompleter): """ Custom completer to allow completion of file/path for set and setg command. Otherwise, NestedCompleter.get_completions() is called. """ def __init__(self, options: Dict[str, Optional[Completer]]): super().__init__(options) self.path_completer = PathCompleter(expanduser=True) self.owf_instance = None def get_completions( self, document: Document, complete_event: CompleteEvent ) -> Iterable[Completion]: # Code for path/file completion # Get the length of the command before the cursor text = document.text_before_cursor.lstrip() try: # File completer is always in the third position (set option PATH_COMPLETION_HERE) if " " in text and ((len(text.split()) == 2 and document.text_before_cursor[-1] == " ") or (len(text.split()) > 2)): # Extract the first term of the command line owf_ucmd = text.split()[0] # Add a path completer only on set and setg command if owf_ucmd in ["set", "setg"]: # Extract the option name supplied by the user to check if it needs file autocompletion supplied_opt_name = text.split()[1] # Check if the option requires a file for opt_name, opt in self.owf_instance.current_module.options.items(): if opt_name == supplied_opt_name and opt["Type"] in ["file_r", "file_w"]: cmd_len = sum(len(x) for x in text.split()[0:2]) + text.count(" ") # Extract only the file parts here (Cut owf cmd and option name) # and ignore text after the cursor sub_doc = Document(document.text[cmd_len:document.cursor_position]) yield from (Completion(completion.text, completion.start_position, display=completion.display) for completion in self.path_completer.get_completions(sub_doc, complete_event)) # current_module or current_module.options is None except AttributeError: pass # Standard nested completion (No file/path completion needed here) for c in super().get_completions(document, complete_event): yield c
def test_pathcompleter_completes_files_in_absolute_directory(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) expected = sorted(str(i) for i in range(10)) test_dir = os.path.abspath(test_dir) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep completer = PathCompleter() # force unicode doc_text = str(test_dir) doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted(c.text for c in completions) assert expected == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_completes_files_in_current_directory(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) expected = sorted(str(i) for i in range(10)) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep with chdir(test_dir): completer = PathCompleter() # this should complete on the cwd doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted(c.text for c in completions) assert expected == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_can_apply_file_filter(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # add a .csv file with open(os.path.join(test_dir, "my.csv"), "wb") as out: out.write(b"") file_filter = lambda f: f and f.endswith(".csv") with chdir(test_dir): completer = PathCompleter(file_filter=file_filter) doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert ["my.csv"] == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_can_apply_file_filter(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # add a .csv file with open(os.path.join(test_dir, 'my.csv'), 'wb') as out: out.write(b'') file_filter = lambda f: f and f.endswith('.csv') with chdir(test_dir): completer = PathCompleter(file_filter=file_filter) doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] assert ['my.csv'] == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_completes_files_in_current_directory(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) expected = sorted([str(i) for i in range(10)]) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep with chdir(test_dir): completer = PathCompleter() # this should complete on the cwd doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted(c.text for c in completions) assert expected == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_completes_files_in_absolute_directory(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) expected = sorted([str(i) for i in range(10)]) test_dir = os.path.abspath(test_dir) if not test_dir.endswith(os.path.sep): test_dir += os.path.sep completer = PathCompleter() # force unicode doc_text = text_type(test_dir) doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = sorted([c.text for c in completions]) assert expected == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_get_paths_constrains_path(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # add a subdir with 10 other files with different names subdir = os.path.join(test_dir, "subdir") os.mkdir(subdir) write_test_files(subdir, "abcdefghij") get_paths = lambda: ["subdir"] with chdir(test_dir): completer = PathCompleter(get_paths=get_paths) doc_text = "" doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] expected = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"] assert expected == result # cleanup shutil.rmtree(test_dir)
def test_pathcompleter_get_paths_constrains_path(): # setup: create a test dir with 10 files test_dir = tempfile.mkdtemp() write_test_files(test_dir) # add a subdir with 10 other files with different names subdir = os.path.join(test_dir, 'subdir') os.mkdir(subdir) write_test_files(subdir, 'abcdefghij') get_paths = lambda: ['subdir'] with chdir(test_dir): completer = PathCompleter(get_paths=get_paths) doc_text = '' doc = Document(doc_text, len(doc_text)) event = CompleteEvent() completions = list(completer.get_completions(doc, event)) result = [c.text for c in completions] expected = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] assert expected == result # cleanup shutil.rmtree(test_dir)
class HummingbotCompleter(Completer): def __init__(self, hummingbot_application): super(HummingbotCompleter, self).__init__() self.hummingbot_application = hummingbot_application # static completers self._path_completer = PathCompleter(get_paths=lambda: [f"./{CONF_FILE_PATH}"], file_filter=lambda fname: fname.endswith(".yml")) self._command_completer = WordCompleter(self.parser.commands, ignore_case=True) self._exchange_completer = WordCompleter(EXCHANGES, ignore_case=True) self._strategy_completer = WordCompleter(STRATEGIES, ignore_case=True) @property def prompt_text(self) -> str: return self.hummingbot_application.app.prompt_text @property def parser(self) -> ThrowingArgumentParser: return self.hummingbot_application.parser def get_subcommand_completer(self, first_word: str) -> Completer: subcommands: List[str] = self.parser.subcommands_from(first_word) return WordCompleter(subcommands, ignore_case=True) @property def _symbol_completer(self) -> Completer: symbol_fetcher = SymbolFetcher.get_instance() market = None for exchange in EXCHANGES: if exchange in self.prompt_text: market = exchange break symbols = symbol_fetcher.symbols.get(market, []) if symbol_fetcher.ready else [] return WordCompleter(symbols, ignore_case=True) @property def _wallet_address_completer(self): return WordCompleter(list_wallets(), ignore_case=True) @property def _option_completer(self): outer = re.compile("\((.+)\)") inner_str = outer.search(self.prompt_text).group(1) options = inner_str.split("/") if "/" in inner_str else [] return WordCompleter(options, ignore_case=True) @property def _config_completer(self): return WordCompleter(load_required_configs(), ignore_case=True) def _complete_strategies(self, document: Document) -> bool: return "strategy" in self.prompt_text def _complete_configs(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return "config" in text_before_cursor def _complete_options(self, document: Document) -> bool: return "(" in self.prompt_text and ")" in self.prompt_text and "/" in self.prompt_text def _complete_exchanges(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return "-e" in text_before_cursor or \ "--exchange" in text_before_cursor or \ "exchange" in self.prompt_text def _complete_symbols(self, document: Document) -> bool: return "symbol" in self.prompt_text def _complete_paths(self, document: Document) -> bool: return "path" in self.prompt_text and "file" in self.prompt_text def _complete_wallet_addresses(self, document: Document) -> bool: return "Which wallet" in self.prompt_text def _complete_command(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return " " not in text_before_cursor and len(self.prompt_text.replace(">>> ", "")) == 0 def _complete_subcommand(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor index: int = text_before_cursor.index(' ') return text_before_cursor[0:index] in self.parser.commands def get_completions(self, document: Document, complete_event: CompleteEvent): """ Get completions for the current scope. This is the defining function for the completer :param document: :param complete_event: """ if self._complete_paths(document): for c in self._path_completer.get_completions(document, complete_event): yield c return if self._complete_strategies(document): for c in self._strategy_completer.get_completions(document, complete_event): yield c if self._complete_wallet_addresses(document): for c in self._wallet_address_completer.get_completions(document, complete_event): yield c elif self._complete_exchanges(document): for c in self._exchange_completer.get_completions(document, complete_event): yield c elif self._complete_symbols(document): for c in self._symbol_completer.get_completions(document, complete_event): yield c elif self._complete_command(document): for c in self._command_completer.get_completions(document, complete_event): yield c elif self._complete_configs(document): for c in self._config_completer.get_completions(document, complete_event): yield c elif self._complete_options(document): for c in self._option_completer.get_completions(document, complete_event): yield c else: text_before_cursor: str = document.text_before_cursor first_word: str = text_before_cursor[0:text_before_cursor.index(' ')] subcommand_completer: Completer = self.get_subcommand_completer(first_word) if complete_event.completion_requested or self._complete_subcommand(document): for c in subcommand_completer.get_completions(document, complete_event): yield c
def get_path_matches(self, _, word_before_cursor): completer = PathCompleter(expanduser=True) document = Document(text=word_before_cursor, cursor_position=len(word_before_cursor)) for c in completer.get_completions(document, None): yield Match(completion=c, priority=(0,))
class HummingbotCompleter(Completer): def __init__(self, hummingbot_application): super(HummingbotCompleter, self).__init__() self.hummingbot_application = hummingbot_application self._symbols: Dict[str, List[str]] = {} # static completers self._path_completer = PathCompleter() self._command_completer = WordCompleter(self.parser.commands, ignore_case=True) self._exchange_completer = WordCompleter(EXCHANGES, ignore_case=True) self._strategy_completer = WordCompleter(STRATEGIES, ignore_case=True) asyncio.ensure_future(self._fetch_symbols()) async def _fetch_symbols(self): self._symbols: Dict[str, List[str]] = await fetch_all() @property def prompt_text(self) -> str: return self.hummingbot_application.app.prompt_text @property def parser(self) -> ThrowingArgumentParser: return self.hummingbot_application.parser def get_subcommand_completer(self, first_word: str) -> Completer: subcommands: List[str] = self.parser.subcommands_from(first_word) return WordCompleter(subcommands, ignore_case=True) @property def _symbol_completer(self) -> Completer: market = None for exchange in EXCHANGES: if exchange in self.prompt_text: market = exchange break return WordCompleter(self._symbols.get(market) or [], ignore_case=True) @property def _wallet_address_completer(self): return WordCompleter(list_wallets(), ignore_case=True) @property def _config_completer(self): return WordCompleter(load_required_configs(), ignore_case=True) def _complete_strategies(self, document: Document) -> bool: return "strategy" in self.prompt_text def _complete_configs(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return "config" in text_before_cursor def _complete_exchanges(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return "-e" in text_before_cursor or \ "--exchange" in text_before_cursor or \ "exchange" in self.prompt_text def _complete_symbols(self, document: Document) -> bool: return "symbol" in self.prompt_text def _complete_paths(self, document: Document) -> bool: return "path" in self.prompt_text and "file" in self.prompt_text def _complete_wallet_addresses(self, document: Document) -> bool: return "Which wallet" in self.prompt_text def _complete_command(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor return " " not in text_before_cursor and len( self.prompt_text.replace(">>> ", "")) == 0 def _complete_subcommand(self, document: Document) -> bool: text_before_cursor: str = document.text_before_cursor index: int = text_before_cursor.index(' ') return text_before_cursor[0:index] in self.parser.commands def get_completions(self, document: Document, complete_event: CompleteEvent): """ Get completions for the current scope. This is the defining function for the completer :param document: :param complete_event: """ if self._complete_paths(document): for c in self._path_completer.get_completions( document, complete_event): yield c if self._complete_strategies(document): for c in self._strategy_completer.get_completions( document, complete_event): yield c if self._complete_wallet_addresses(document): for c in self._wallet_address_completer.get_completions( document, complete_event): yield c elif self._complete_exchanges(document): for c in self._exchange_completer.get_completions( document, complete_event): yield c elif self._complete_symbols(document): for c in self._symbol_completer.get_completions( document, complete_event): yield c elif self._complete_command(document): for c in self._command_completer.get_completions( document, complete_event): yield c elif self._complete_configs(document): for c in self._config_completer.get_completions( document, complete_event): yield c else: text_before_cursor: str = document.text_before_cursor first_word: str = text_before_cursor[0:text_before_cursor.index(' ' )] subcommand_completer: Completer = self.get_subcommand_completer( first_word) if complete_event.completion_requested or self._complete_subcommand( document): for c in subcommand_completer.get_completions( document, complete_event): yield c