def update_decorated_match(self, max_len: Optional[int] = None) -> None: """Update the cached decorated match formatted string, and dirty the line, if needed""" if self.hovered and self.selected: attributes = ( curses.COLOR_WHITE, curses.COLOR_RED, FormattedText.BOLD_ATTRIBUTE, ) elif self.hovered: attributes = ( curses.COLOR_WHITE, curses.COLOR_BLUE, FormattedText.BOLD_ATTRIBUTE, ) elif self.selected: attributes = ( curses.COLOR_WHITE, curses.COLOR_GREEN, FormattedText.BOLD_ATTRIBUTE, ) elif not self.all_input: attributes = (0, 0, FormattedText.UNDERLINE_ATTRIBUTE) else: attributes = (0, 0, 0) decorator_text = self.get_decorator() # we may not be connected to a controller (during process_input, # for example) if self.controller: self.controller.dirty_line(self.index) plain_text = decorator_text + self.get_match() if max_len and len(plain_text + str(self.before_text)) > max_len: # alright, we need to chop the ends off of our # decorated match and glue them together with our # truncation decorator. We subtract the length of the # before text since we consider that important too. space_allowed = ( max_len - len(self.TRUNCATE_DECORATOR) - len(decorator_text) - len(str(self.before_text)) ) mid_point = int(space_allowed / 2) begin_match = plain_text[0:mid_point] end_match = plain_text[-mid_point : len(plain_text)] plain_text = begin_match + self.TRUNCATE_DECORATOR + end_match self.decorated_match = FormattedText( FormattedText.get_sequence_for_attributes(*attributes) + plain_text )
def get_line_objs_from_lines( input_lines: List[str], validate_file_exists: bool = True, all_input: bool = False ) -> Dict[int, LineBase]: line_objs: Dict[int, LineBase] = {} for index, line in enumerate(input_lines): line = line.replace("\t", " " * 4) # remove the new line as we place the cursor ourselves for each # line. this avoids curses errors when we newline past the end of the # screen line = line.replace("\n", "") formatted_line = FormattedText(line) result = parse.match_line( str(formatted_line), validate_file_exists=validate_file_exists, all_input=all_input, ) if not result: line_obj: LineBase = SimpleLine(formatted_line, index) else: line_obj = LineMatch( formatted_line, result, index, validate_file_exists=validate_file_exists, all_input=all_input, ) line_objs[index] = line_obj return line_objs
def testUnresolvable(self): file_line = ".../something/foo.py" result = parse.matchLine(file_line) line_obj = format.LineMatch(FormattedText(file_line), result, 0) self.assertTrue(not line_obj.isResolvable(), '"%s" should not be resolvable' % file_line) print("Tested unresolvable case.")
def getLineObjsFromLines(inputLines, validateFileExists=True, allInput=False): lineObjs = {} for index, line in enumerate(inputLines): line = line.replace("\t", " ") # remove the new line as we place the cursor ourselves for each # line. this avoids curses errors when we newline past the end of the # screen line = line.replace("\n", "") formattedLine = FormattedText(line) result = parse.matchLine( str(formattedLine), validateFileExists=validateFileExists, allInput=allInput ) if not result: line = format.SimpleLine(formattedLine, index) else: line = format.LineMatch( formattedLine, result, index, validateFileExists=validateFileExists, allInput=allInput, ) lineObjs[index] = line return lineObjs
def print_up_to( self, text: FormattedText, printer: ColorPrinter, y_pos: int, x_pos: int, max_len: int, ) -> Tuple[int, int]: """Attempt to print maxLen characters, returning a tuple (x, maxLen) updated with the actual number of characters printed""" if max_len <= 0: return x_pos, max_len max_printable = min(len(str(text)), max_len) text.print_text(y_pos, x_pos, printer, max_printable) return x_pos + max_printable, max_len - max_printable
def test_unresolvable(self) -> None: file_line = ".../something/foo.py" result = parse.match_line(file_line) if not result: raise AssertionError(f'"{file_line}": no result') line_obj = LineMatch(FormattedText(file_line), result, 0) self.assertTrue(not line_obj.is_resolvable(), f'"{file_line}" should not be resolvable') print("Tested unresolvable case.")
def __init__( self, formatted_line: FormattedText, result: MatchResult, index: int, validate_file_exists: bool = False, all_input: bool = False, ): super().__init__() self.formatted_line = formatted_line self.index = index self.all_input = all_input path, num, matches = result self.path = ( path if all_input else parse.prepend_dir(path, with_file_inspection=validate_file_exists) ) self.num = num line = str(self.formatted_line) # save a bunch of stuff so we can # pickle self.start = matches.start() self.end = min(matches.end(), len(line)) self.group: str = matches.group() # this is a bit weird but we need to strip # off the whitespace for the matches we got, # since matches like README are aggressive # about including whitespace. For most lines # this will be a no-op, but for lines like # "README " we will reset end to # earlier string_subset = line[self.start : self.end] stripped_subset = string_subset.strip() trailing_whitespace = len(string_subset) - len(stripped_subset) self.end -= trailing_whitespace self.group = self.group[0 : len(self.group) - trailing_whitespace] self.selected = False self.hovered = False self.is_truncated = False # precalculate the pre, post, and match strings (self.before_text, _) = self.formatted_line.breakat(self.start) (_, self.after_text) = self.formatted_line.breakat(self.end) self.decorated_match = FormattedText() self.update_decorated_match()
file_line = ".../something/foo.py" result = parse.match_line(file_line) if not result: raise AssertionError(f'"{file_line}": no result') line_obj = LineMatch(FormattedText(file_line), result, 0) self.assertTrue(not line_obj.is_resolvable(), f'"{file_line}" should not be resolvable') print("Tested unresolvable case.") def test_resolvable(self) -> None: to_check = [case for case in FILE_TEST_CASES if case.match] for test_case in to_check: result = parse.match_line(test_case.test_input) if not result: raise AssertionError(f'"{test_case.test_input}": no result') line_obj = LineMatch(FormattedText(test_case.test_input), result, 0) self.assertTrue( line_obj.is_resolvable(), f'Line "{test_case.test_input}" was not resolvable', ) print(f"Tested {len(to_check)} resolvable cases.") def test_file_match(self) -> None: for test_case in FILE_TEST_CASES: self.check_file_result(test_case) print(f"Tested {len(FILE_TEST_CASES)} cases.") def test_all_input_matches(self) -> None: for test_case in ALL_INPUT_TEST_CASES: result = parse.match_line(test_case.test_input, False, True)
self.checkFileResult(this_case) print("Tested %d cases for file fuzz." % len(FILE_TEST_CASES)) def testUnresolvable(self): file_line = ".../something/foo.py" result = parse.matchLine(file_line) line_obj = format.LineMatch(FormattedText(file_line), result, 0) self.assertTrue(not line_obj.isResolvable(), '"%s" should not be resolvable' % file_line) print("Tested unresolvable case.") def testResolvable(self): to_check = [case for case in FILE_TEST_CASES if case.match] for test_case in to_check: result = parse.matchLine(test_case.input) line_obj = format.LineMatch(FormattedText(test_case.input), result, 0) self.assertTrue( line_obj.isResolvable(), 'Line "%s" was not resolvable' % test_case.input, ) print("Tested %d resolvable cases." % len(to_check)) def testFileMatch(self): for test_case in FILE_TEST_CASES: self.checkFileResult(test_case) print("Tested %d cases." % len(FILE_TEST_CASES)) def testAllInputMatches(self): for test_case in ALL_INPUT_TEST_CASES: result = parse.matchLine(test_case.input, False, True)