def get_completions(self, document: Document, complete_event: CompleteEvent) -> Iterable[Completion]: # Get list of words. words = self.words if callable(words): words = words() # Get word/text before cursor. if self.sentence: word_before_cursor = document.text_before_cursor else: word_before_cursor = document.get_word_before_cursor( WORD=self.WORD, pattern=self.pattern) if self.ignore_case: word_before_cursor = word_before_cursor.lower() def word_matches(word: str) -> bool: """ True when the word before the cursor matches. """ if self.ignore_case: word = word.lower() if self.match_middle: return word_before_cursor in word else: return word.startswith(word_before_cursor) for a in words: if word_matches(a): display_meta = self.meta_dict.get(a, '') yield Completion(a, -len(word_before_cursor), display_meta=display_meta)
def _get_fuzzy_completions( self, document: Document, complete_event: CompleteEvent) -> Iterable[Completion]: word_before_cursor = document.get_word_before_cursor( pattern=re.compile(self._get_pattern())) # Get completions document2 = Document(text=document.text[:document.cursor_position - len(word_before_cursor)], cursor_position=document.cursor_position - len(word_before_cursor)) completions = list( self.completer.get_completions(document2, complete_event)) fuzzy_matches: List[_FuzzyMatch] = [] pat = '.*?'.join(map(re.escape, word_before_cursor)) pat = '(?=({0}))'.format( pat) # lookahead regex to manage overlapping matches regex = re.compile(pat, re.IGNORECASE) for compl in completions: matches = list(regex.finditer(compl.text)) if matches: # Prefer the match, closest to the left, then shortest. best = min(matches, key=lambda m: (m.start(), len(m.group(1)))) fuzzy_matches.append( _FuzzyMatch(len(best.group(1)), best.start(), compl)) def sort_key(fuzzy_match: '_FuzzyMatch') -> Tuple[int, int]: " Sort by start position, then by the length of the match. " return fuzzy_match.start_pos, fuzzy_match.match_length fuzzy_matches = sorted(fuzzy_matches, key=sort_key) for match in fuzzy_matches: # Include these completions, but set the correct `display` # attribute and `start_position`. yield Completion(match.completion.text, start_position=match.completion.start_position - len(word_before_cursor), display_meta=match.completion.display_meta, display=self._get_display(match, word_before_cursor), style=match.completion.style)