diff --git a/preditor/gui/find_files.py b/preditor/gui/find_files.py index 2aa94cd6..f744c7cd 100644 --- a/preditor/gui/find_files.py +++ b/preditor/gui/find_files.py @@ -25,6 +25,8 @@ def __init__(self, find_text, case_sensitive): self.case_sensitive = case_sensitive self.find_text = find_text self.margin_format = " {line_num: 4d}{match_indicator} {line}" + self.match_count = 0 + self.match_file_count = 0 @abc.abstractmethod def indicate_line(self, line): @@ -56,21 +58,56 @@ def margin(self, line_num, match_found): def matches(self, line): """Returns bool for if find_text is contained in this line.""" + def title(self): + return '\nFind in workboxs: "{}"{}\n\n'.format(self.find_text, self.title_flags) + + @property + @abc.abstractmethod + def title_flags(self): + """Returns the text to show in the title for flags.""" + class RegexFinder(Finder): """Finder that processes the text using regex.""" def __init__(self, find_text, case_sensitive): super(RegexFinder, self).__init__(find_text, case_sensitive) - self.pattern = re.compile(find_text, flags=re.I if case_sensitive else 0) + self.pattern = re.compile(find_text, flags=0 if case_sensitive else re.I) + self._matches = None def indicate_line(self, line): - # TODO: Properly implement this - yield line, False + # Write the margin indicating if this line has any matches + yield None, bool(self._matches) + + start = 0 + if self._matches: + # print([line, self._matches]) + for m in self._matches: + pre = line[start : m.start()] + if pre: + yield pre, False + yield line[m.start() : m.end()], True + start = m.end() + # Record the match + self.match_count += 1 + post = line[start:] + if post: + yield post, False + else: + yield line, False + + # Reset regex cache for the next call to `matches` + self._matches = None def matches(self, txt): - match = self.pattern.search(txt) - return match is not None + self._matches = list(self.pattern.finditer(txt)) + return bool(self._matches) + + @property + def title_flags(self): + if self.case_sensitive: + return " (regex, case sensitive)" + return " (regex)" class SimpleFinder(Finder): @@ -113,6 +150,8 @@ def indicate_line(self, line): yield original_line[start:end], False # insert indicated text preserving case yield original_line[end : end + find_len], True + # Record the match + self.match_count += 1 # Check for any more matches in this line start = end + find_len @@ -125,6 +164,12 @@ def indicate_line(self, line): def matches(self, txt): return self._matches(txt) + @property + def title_flags(self): + if self.case_sensitive: + return " (case sensitive)" + return "" + class FindFiles(QWidget): def __init__(self, parent=None, managers=None, console=None): @@ -134,6 +179,7 @@ def __init__(self, parent=None, managers=None, console=None): self.managers = managers self.console = console self.finder = None + self.match_files_count = 0 loadUi(__file__, self) @@ -167,16 +213,16 @@ def activate(self): def find(self): find_text = self.uiFindTXT.text() - cs = " (case sensitive)" if self.uiCaseSensitiveBTN.isChecked() else "" - self.insert_text('\nFind in workboxs: "{}"{}\n\n'.format(find_text, cs)) - # Create an instance of the Finder to use for this search if self.uiRegexBTN.isChecked(): Finder = RegexFinder else: Finder = SimpleFinder - self.finder = Finder(find_text, cs) + self.finder = Finder(find_text, self.uiCaseSensitiveBTN.isChecked()) + + self.insert_text(self.finder.title()) + self.match_files_count = 0 for manager in self.managers: for ( editor, @@ -189,7 +235,11 @@ def find(self): workbox_id = '{},{}'.format(group_index, tab_index) self.search_file_simple(editor, find_text, path, workbox_id) - self.insert_text('\n{} matches in {} workboxes\n'.format(0, 0)) + self.insert_text( + '\n{} matches in {} workboxes\n'.format( + self.finder.match_count, self.match_files_count + ) + ) def indicate_results( self, @@ -285,8 +335,14 @@ def search_file_simple(self, editor, find_text, path, workbox_id): len_pre_history = len(pre_history) if first: # Print the filename on the first find - self.insert_text("# File: {}\n".format(path)) + self.insert_text("# File: ") + href = ', {}, 0'.format(workbox_id) + tool_tip = "Open {}".format(path) + self.insert_found_text(path, href, tool_tip) + self.insert_text("\n") first = False + # Record that we found a match in this file + self.match_files_count += 1 elif i > context and len_pre_history: self.insert_text( " {dot: >{padding}} \n".format(