Пример #1
0
 def search_score(self, query):
     # Also use the executable name, such as "baobab" or "nautilus", but score that lower
     return max([
         get_score(query, self.name),
         get_score(query, self._executable) * .8,
         get_score(query, self.description) * .7
     ] + [get_score(query, k) * .6 for k in self.keywords])
Пример #2
0
    def append(self, result_item):
        # get_search_name() returns a string with the app display name, but it may contain a
        # second line in which case that line is the name of the executable
        search_fields = result_item.get_search_name()
        name, exec_name, *_ = '{}\n'.format(search_fields).split('\n')
        score = max(get_score(self._query, name),
                    get_score(self._query, exec_name) * .8)

        if score >= self._min_score:
            result_item.score = -score  # use negative to sort by score in desc. order
            self._items.insert(result_item)
            while len(self._items) > self._limit:
                self._items.pop(
                )  # remove items with the lowest score to maintain limited number of items
Пример #3
0
 def append(self, result_item):
     score = get_score(self._query, result_item.get_search_name())
     if score >= self._min_score:
         result_item.score = -score  # use negative to sort by score in desc. order
         self._items.insert(result_item)
         while len(self._items) > self._limit:
             self._items.pop(
             )  # remove items with the lowest score to maintain limited number of items
Пример #4
0
    def handle_query(self, query: str) -> List[FileBrowserResult]:
        try:
            path = Path(os.path.expandvars(query.strip())).expanduser()
            results = []

            closest_parent = str(
                next(parent for parent in [path] + list(path.parents)
                     if parent.exists()))
            remainder = "/".join(path.parts[closest_parent.count('/') + 1:])

            if closest_parent == '.':
                raise RuntimeError(f'Invalid path "{path}"')

            if not remainder:
                file_names = self.list_files(str(path), sort_by_atime=True)
                for name in self.filter_dot_files(file_names)[:self.LIMIT]:
                    file = os.path.join(closest_parent, name)
                    results.append(FileBrowserResult(file))

            else:
                file_names = self.list_files(closest_parent)
                query = remainder

                if not query.startswith('.'):
                    file_names = self.filter_dot_files(file_names)

                sorted_files = sorted(file_names,
                                      key=lambda fn: get_score(query, fn),
                                      reverse=True)
                filtered_files = list(
                    filter(lambda fn: get_score(query, fn) > 40,
                           sorted_files))[:self.LIMIT]
                results = [
                    FileBrowserResult(os.path.join(closest_parent, name))
                    for name in filtered_files
                ]

        except (RuntimeError, OSError):
            results = []

        return results
Пример #5
0
def fuzzyfinder(search: str, items: List[str], root_path: str) -> List[str]:
    """
    >>> fuzzyfinder("hallo", ["hi", "hu", "hallo", "false"])
    ['hallo', 'false', 'hi', 'hu']
    """
    scores = []
    for i in items:
        score = get_score(search, get_name_from_path(i, root_path=root_path))
        scores.append((score, i))

    scores = sorted(scores, key=lambda score: score[0], reverse=True)

    return list(map(lambda score: score[1], scores))
Пример #6
0
def score_name_query_match(
    name_chunks: List[str], query_chunks: List[str], basename_query: str
) -> Tuple[float, float]:
    """
    Score how well given name matches given query using Ulauncher fuzzy search algo
    """
    # Basename match only matters if our search query includes one
    if len(query_chunks) > 1:
        basename = ".".join(name_chunks[: len(query_chunks) - 1])
        basename_match_score = fuzzy_search.get_score(basename_query, basename)
    else:
        basename_match_score = 0

    # The last part of the name match is only relevant
    # if this name has at least that many parts
    if len(name_chunks) >= len(query_chunks):
        leafname_match_score = fuzzy_search.get_score(
            query_chunks[len(query_chunks) - 1], name_chunks[len(query_chunks) - 1]
        )
    else:
        leafname_match_score = 0

    return (basename_match_score, leafname_match_score)
Пример #7
0
def test_get_score():
    assert get_score('fiwebro', 'Firefox Web Browser') > get_score(
        'fiwebro', 'Firefox Web SBrowser')
    assert get_score('j', 'johnny') < get_score('j', 'john')
    assert get_score('calc', 'LibreOffice Calc') < get_score('calc', 'Calc')
    assert get_score('calc', 'Contacts') < get_score('calc',
                                                     'LibreOffice Calc')
    assert get_score('pla', 'Pycharm') < get_score('pla', 'Google Play Music')
    assert get_score('', 'LibreOffice Calc') == 0
    assert get_score('0', 'LibreOffice Calc') == 0
Пример #8
0
def xtest_speed():
    t0 = time.time()
    for _ in range(1000):
        get_score('fiwebro', 'Firefox Web Browser')
    print('time for get_score:', (time.time() - t0))
    assert 0
Пример #9
0
def search_fullname(query: str, module_names: Iterable[str]) -> List[str]:
    """
    Rank and sort module names by how well they match a wildcard query.
    Nesting of the names doesn't matter.

    Treat first asterisk as a wildcard that can match any part of the name:

    >>> search_fullname('ht*error', ['http', 'http.cli.error', 'http.cli'])[0]
    'http.cli.error'

    Module names must contain all characters from the first part of the query
    to be included in the results:

    >>> search_fullname('ul*action', ['ulauncher.shared.action', 'cozmo.actions'])
    ['ulauncher.shared.action']

    Query can also start with a wildcard, in which case the first part doesn't matter:

    >>> len(search_fullname('*action', ['http.cli.action', 'boo.action']))
    2

    Dots can be used in any part of the query:

    >>> search_fullname('ht.c*t.', ['http.client.err', 'http.server.request'])
    ['http.client.err']

    Exact matches of the query's tail are scored higher, to allow for quick lookup
    of modules with known names:

    >>> search_fullname('*widg', ['ulauncher.api.itemwidget', 'wedge'])[0]
    'ulauncher.api.itemwidget'

    """

    # Split the query into 2 parts: head and tail, separated by an asterisk
    qhead, _, qtail = query.lower().partition("*")

    # Every character in the "head" part of the query
    # must be present in the given order, so we turn it into a regex pattern
    head_regex = ordered_char_list_regex(qhead) if qhead else None

    result_items = []
    for name in module_names:
        # The search is case insensitive
        name_lower = name.lower()
        if head_regex:
            # If head is present, it regex must match
            head_match = re.search(head_regex, name_lower)

            # Head and tail parts of the name don't overlap
            name_tail_idx = head_match.span()[1] if head_match else 0
            name_tail = name_lower[name_tail_idx:]
        else:
            # If the wildcard was the first character in the query,
            # then every name matches it, and we treat the whole name as "tail"
            name_tail = name_lower

        if not head_regex or head_match:
            head_score = fuzzy_search.get_score(qhead, name_lower) if qhead else 0
            tail_score = fuzzy_search.get_score(qtail, name_tail) if qtail else 0
            result_items.append(
                FullNameSearchResultItem(
                    module_name=name,
                    head_match_score=head_score,
                    tail_match_score=tail_score,
                    tail_exact_contains=1 if qtail in name_tail else 0,
                )
            )

    def sort_key(item):
        return (
            item.tail_exact_contains,
            item.tail_match_score,
            item.head_match_score,
            item.module_name,
        )

    return [res.module_name for res in sorted(result_items, key=sort_key, reverse=True)]
Пример #10
0
 def search_score(self, query):
     return get_score(query, self.get_name())