From a535ed12b01ce46f7efc6c5c75e641e0a105ca97 Mon Sep 17 00:00:00 2001 From: Jann Stute <46534683+Computerdores@users.noreply.github.com> Date: Sat, 7 Dec 2024 00:43:08 +0100 Subject: [PATCH] feat: implement query language (#606) * add files * fix: term was parsing ANDList instead of ORList * make mypy happy * ruff format * add missing todo * add more constraint types * add parent property to AST * add BaseVisitor class * make mypy happy * add __init__.py * Revert "make mypy happy" This reverts commit 926d0dd2e79d06203e84e2f83c06c7fe5b33de23. * refactoring and fixes * rudimentary search field integration * fix: check for None properly * fix: Entries without Tags are now searchable * make mypy happy * Revert "fix: Entries without Tags are now searchable" This reverts commit 19b40af7480b0c068b81b642b51536a9ec96d030. * fix: changed joins to outerjoins and added missing outerjoin * use query lang instead of tag_id FIlterState * add todos * fix: remove uncecessary line that broke search when searching for exact name * fix tag search * refactoring * fix: path now uses GLOB operator for proper GLOBs * refactoring: remove FilterState.id and implement Library.get_entry_full as replacement * fix: use default value notation instead of if None statement in __post_init__ * remove obsolete Search Mode UI and related code * ruff fixes * remove obsolete tests * fix: item_thumb didn't query entries correctly * fix: search_library now correctly returns the number of *unique* entries * make mypy happy * implement NOT * remove obsolete filename search * remove summary as it is not applicable anymore * finish refactoring of FilterState * implement special:untagged * fix: make mypy happy * Revert changes to search_tags in favor of changes from #604 * fix: also port test changes * fix: remove unneccessary import * fix: remove unused dataclass * fix: AND now works correctly with tags * simplify structure of parsed AST * add performance logging * perf: Improve performance of search by reducing number of required joins from 4 to 1 * perf: double NOT is now optimized out of the AST * fix: bug where pages would show less than the configured number of entries * Revert "add performance logging" This reverts commit c3c7d7546d285c6dad51872cbf80bc6070262570. * fix: tag_id search was broken * somewhat adapt the existing autocompletion to this PR * perf: Use Relational Division Queries to improve Query Execution Time * fix: raise Exception so as to not fail silently * fix: Parser bug broke parentheses * little bit of clean up * remove unnecessary comment * add library for testing search * feat: add basic tests * fix: and queries containing just one tag were broken * chore: remove debug code * feat: more tests * refactor: more consistent name for variable Co-authored-by: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com> * fix: ruff check complaint over double import --------- Co-authored-by: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com> --- tagstudio/src/core/library/alchemy/enums.py | 110 +++++-------- tagstudio/src/core/library/alchemy/library.py | 89 ++++------- .../src/core/library/alchemy/visitors.py | 125 +++++++++++++++ tagstudio/src/core/query_lang/__init__.py | 11 ++ tagstudio/src/core/query_lang/ast.py | 126 +++++++++++++++ tagstudio/src/core/query_lang/parser.py | 120 ++++++++++++++ tagstudio/src/core/query_lang/tokenizer.py | 147 ++++++++++++++++++ tagstudio/src/core/query_lang/util.py | 15 ++ tagstudio/src/core/utils/dupe_files.py | 2 +- tagstudio/src/qt/main_window.py | 11 -- tagstudio/src/qt/ts_qt.py | 82 +++++----- tagstudio/src/qt/widgets/item_thumb.py | 5 +- tagstudio/src/qt/widgets/preview_panel.py | 11 +- tagstudio/src/qt/widgets/tag_box.py | 2 +- tagstudio/tests/conftest.py | 9 +- .../search_library/.TagStudio/ts_library.json | 1 + .../.TagStudio/ts_library.sqlite | Bin 0 -> 86016 bytes .../comp colors shapes/r_circle_b_square.png | Bin 0 -> 3617 bytes .../comp colors shapes/r_circle_g_square.png | Bin 0 -> 3737 bytes .../comp colors shapes/r_circle_o_square.png | Bin 0 -> 3672 bytes .../comp colors shapes/r_circle_r_square.png | Bin 0 -> 3266 bytes .../comp colors shapes/r_circle_y_square.png | Bin 0 -> 3624 bytes .../inherit colors shapes/blue.jpg | Bin 0 -> 6073 bytes .../inherit colors shapes/blue_circle.jpg | Bin 0 -> 8601 bytes .../inherit colors shapes/blue_ellipse.png | Bin 0 -> 5570 bytes .../inherit colors shapes/blue_square.jpg | Bin 0 -> 8314 bytes .../inherit colors shapes/circle.png | Bin 0 -> 4911 bytes .../inherit colors shapes/ellipse.png | Bin 0 -> 5440 bytes .../inherit colors shapes/green.png | Bin 0 -> 8333 bytes .../inherit colors shapes/green_circle.png | Bin 0 -> 15946 bytes .../inherit colors shapes/green_ellipse.png | Bin 0 -> 15794 bytes .../inherit colors shapes/green_square.png | Bin 0 -> 8559 bytes .../inherit colors shapes/orange.png | Bin 0 -> 9149 bytes .../inherit colors shapes/orange_circle.png | Bin 0 -> 16167 bytes .../inherit colors shapes/orange_ellipse.png | Bin 0 -> 16250 bytes .../inherit colors shapes/orange_square.png | Bin 0 -> 9382 bytes .../inherit colors shapes/red.jpg | Bin 0 -> 9889 bytes .../inherit colors shapes/red_circle.jpg | Bin 0 -> 8295 bytes .../inherit colors shapes/red_ellipse.png | Bin 0 -> 5956 bytes .../inherit colors shapes/red_square.jpg | Bin 0 -> 8016 bytes .../inherit colors shapes/shape.png | Bin 0 -> 3571 bytes .../inherit colors shapes/square.png | Bin 0 -> 4084 bytes .../inherit colors shapes/yellow.png | Bin 0 -> 3677 bytes .../inherit colors shapes/yellow_circle.png | Bin 0 -> 6656 bytes .../inherit colors shapes/yellow_ellipse.png | Bin 0 -> 6310 bytes .../inherit colors shapes/yellow_square.png | Bin 0 -> 3878 bytes tagstudio/tests/macros/test_missing_files.py | 2 +- tagstudio/tests/qt/test_qt_driver.py | 4 +- tagstudio/tests/test_filter_state.py | 36 ----- tagstudio/tests/test_library.py | 76 ++++----- tagstudio/tests/test_search.py | 124 +++++++++++++++ 51 files changed, 831 insertions(+), 277 deletions(-) create mode 100644 tagstudio/src/core/library/alchemy/visitors.py create mode 100644 tagstudio/src/core/query_lang/__init__.py create mode 100644 tagstudio/src/core/query_lang/ast.py create mode 100644 tagstudio/src/core/query_lang/parser.py create mode 100644 tagstudio/src/core/query_lang/tokenizer.py create mode 100644 tagstudio/src/core/query_lang/util.py create mode 100644 tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.json create mode 100644 tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.sqlite create mode 100644 tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_b_square.png create mode 100644 tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_g_square.png create mode 100644 tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_o_square.png create mode 100644 tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_r_square.png create mode 100644 tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_y_square.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/blue.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_circle.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_square.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/circle.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/green.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/green_circle.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/green_ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/green_square.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/orange.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_circle.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_square.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/red.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/red_circle.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/red_ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/red_square.jpg create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/shape.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/square.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_circle.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_ellipse.png create mode 100644 tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_square.png delete mode 100644 tagstudio/tests/test_filter_state.py create mode 100644 tagstudio/tests/test_search.py diff --git a/tagstudio/src/core/library/alchemy/enums.py b/tagstudio/src/core/library/alchemy/enums.py index 7c70f92e..0036fbbd 100644 --- a/tagstudio/src/core/library/alchemy/enums.py +++ b/tagstudio/src/core/library/alchemy/enums.py @@ -1,7 +1,10 @@ import enum -from dataclasses import dataclass +from dataclasses import dataclass, replace from pathlib import Path +from src.core.query_lang import AST as Query # noqa: N811 +from src.core.query_lang import Constraint, ConstraintType, Parser + class TagColor(enum.IntEnum): DEFAULT = 1 @@ -50,13 +53,6 @@ class TagColor(enum.IntEnum): return TagColor.DEFAULT -class SearchMode(enum.IntEnum): - """Operational modes for item searching.""" - - AND = 0 - OR = 1 - - class ItemType(enum.Enum): ENTRY = 0 COLLATION = 1 @@ -68,71 +64,12 @@ class FilterState: """Represent a state of the Library grid view.""" # these should remain - page_index: int | None = None - page_size: int | None = None - search_mode: SearchMode = SearchMode.AND # TODO - actually implement this + page_index: int | None = 0 + page_size: int | None = 500 # these should be erased on update - # tag name - tag: str | None = None - # tag ID - tag_id: int | None = None - - # entry id - id: int | None = None - # whole path - path: Path | str | None = None - # file name - name: str | None = None - # file type - filetype: str | None = None - mediatype: str | None = None - - # a generic query to be parsed - query: str | None = None - - def __post_init__(self): - # strip values automatically - if query := (self.query and self.query.strip()): - # parse the value - if ":" in query: - kind, _, value = query.partition(":") - value = value.replace('"', "") - else: - # default to tag search - kind, value = "tag", query - - if kind == "tag_id": - self.tag_id = int(value) - elif kind == "tag": - self.tag = value - elif kind == "path": - self.path = value - elif kind == "name": - self.name = value - elif kind == "id": - self.id = int(self.id) if str(self.id).isnumeric() else self.id - elif kind == "filetype": - self.filetype = value - elif kind == "mediatype": - self.mediatype = value - - else: - self.tag = self.tag and self.tag.strip() - self.tag_id = int(self.tag_id) if str(self.tag_id).isnumeric() else self.tag_id - self.path = self.path and str(self.path).strip() - self.name = self.name and self.name.strip() - self.id = int(self.id) if str(self.id).isnumeric() else self.id - - if self.page_index is None: - self.page_index = 0 - if self.page_size is None: - self.page_size = 500 - - @property - def summary(self): - """Show query summary.""" - return self.query or self.tag or self.name or self.tag_id or self.path or self.id + # Abstract Syntax Tree Of the current Search Query + ast: Query = None @property def limit(self): @@ -142,6 +79,37 @@ class FilterState: def offset(self): return self.page_size * self.page_index + @classmethod + def show_all(cls) -> "FilterState": + return FilterState() + + @classmethod + def from_search_query(cls, search_query: str) -> "FilterState": + return cls(ast=Parser(search_query).parse()) + + @classmethod + def from_tag_id(cls, tag_id: int | str) -> "FilterState": + return cls(ast=Constraint(ConstraintType.TagID, str(tag_id), [])) + + @classmethod + def from_path(cls, path: Path | str) -> "FilterState": + return cls(ast=Constraint(ConstraintType.Path, str(path).strip(), [])) + + @classmethod + def from_mediatype(cls, mediatype: str) -> "FilterState": + return cls(ast=Constraint(ConstraintType.MediaType, mediatype, [])) + + @classmethod + def from_filetype(cls, filetype: str) -> "FilterState": + return cls(ast=Constraint(ConstraintType.FileType, filetype, [])) + + @classmethod + def from_tag_name(cls, tag_name: str) -> "FilterState": + return cls(ast=Constraint(ConstraintType.Tag, tag_name, [])) + + def with_page_size(self, page_size: int) -> "FilterState": + return replace(self, page_size=page_size) + class FieldTypeEnum(enum.Enum): TEXT_LINE = "Text Line" diff --git a/tagstudio/src/core/library/alchemy/library.py b/tagstudio/src/core/library/alchemy/library.py index a5398a6d..56b114ff 100644 --- a/tagstudio/src/core/library/alchemy/library.py +++ b/tagstudio/src/core/library/alchemy/library.py @@ -28,7 +28,6 @@ from sqlalchemy import ( from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import ( Session, - aliased, contains_eager, make_transient, selectinload, @@ -42,7 +41,6 @@ from ...constants import ( TS_FOLDER_NAME, ) from ...enums import LibraryPrefs -from ...media_types import MediaCategories from .db import make_tables from .enums import FieldTypeEnum, FilterState, TagColor from .fields import ( @@ -54,6 +52,7 @@ from .fields import ( ) from .joins import TagField, TagSubtag from .models import Entry, Folder, Preferences, Tag, TagAlias, ValueType +from .visitors import SQLBoolExpressionBuilder logger = structlog.get_logger(__name__) @@ -402,6 +401,29 @@ class Library: make_transient(entry) return entry + def get_entry_full(self, entry_id: int) -> Entry | None: + """Load entry an join with all joins and all tags.""" + with Session(self.engine) as session: + statement = select(Entry).where(Entry.id == entry_id) + statement = ( + statement.outerjoin(Entry.text_fields) + .outerjoin(Entry.datetime_fields) + .outerjoin(Entry.tag_box_fields) + ) + statement = statement.options( + selectinload(Entry.text_fields), + selectinload(Entry.datetime_fields), + selectinload(Entry.tag_box_fields) + .joinedload(TagBoxField.tags) + .options(selectinload(Tag.aliases), selectinload(Tag.subtags)), + ) + entry = session.scalar(statement) + if not entry: + return None + session.expunge(entry) + make_transient(entry) + return entry + @property def entries_count(self) -> int: with Session(self.engine) as session: @@ -518,63 +540,18 @@ class Library: with Session(self.engine, expire_on_commit=False) as session: statement = select(Entry) - if search.tag: - SubtagAlias = aliased(Tag) # noqa: N806 - statement = ( - statement.join(Entry.tag_box_fields) - .join(TagBoxField.tags) - .outerjoin(Tag.aliases) - .outerjoin(SubtagAlias, Tag.subtags) - .where( - or_( - Tag.name.ilike(search.tag), - Tag.shorthand.ilike(search.tag), - TagAlias.name.ilike(search.tag), - SubtagAlias.name.ilike(search.tag), - ) - ) - ) - elif search.tag_id: - statement = ( - statement.join(Entry.tag_box_fields) - .join(TagBoxField.tags) - .where(Tag.id == search.tag_id) - ) - - elif search.id: - statement = statement.where(Entry.id == search.id) - elif search.name: - statement = select(Entry).where( - and_( - Entry.path.ilike(f"%{search.name}%"), - # dont match directory name (ie. has following slash) - ~Entry.path.ilike(f"%{search.name}%/%"), - ) - ) - elif search.path: - search_str = str(search.path).replace("*", "%") - statement = statement.where(Entry.path.ilike(search_str)) - elif search.filetype: - statement = statement.where(Entry.suffix.ilike(f"{search.filetype}")) - elif search.mediatype: - extensions: set[str] = set[str]() - for media_cat in MediaCategories.ALL_CATEGORIES: - if search.mediatype == media_cat.name: - extensions = extensions | media_cat.extensions - break - # just need to map it to search db - suffixes do not have '.' - statement = statement.where( - Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions)) + if search.ast: + statement = statement.outerjoin(Entry.tag_box_fields).where( + SQLBoolExpressionBuilder(self).visit(search.ast) ) extensions = self.prefs(LibraryPrefs.EXTENSION_LIST) is_exclude_list = self.prefs(LibraryPrefs.IS_EXCLUDE_LIST) - if not search.id: # if `id` is set, we don't need to filter by extensions - if extensions and is_exclude_list: - statement = statement.where(Entry.suffix.notin_(extensions)) - elif extensions: - statement = statement.where(Entry.suffix.in_(extensions)) + if extensions and is_exclude_list: + statement = statement.where(Entry.suffix.notin_(extensions)) + elif extensions: + statement = statement.where(Entry.suffix.in_(extensions)) statement = statement.options( selectinload(Entry.text_fields), @@ -584,6 +561,8 @@ class Library: .options(selectinload(Tag.aliases), selectinload(Tag.subtags)), ) + statement = statement.distinct(Entry.id) + query_count = select(func.count()).select_from(statement.alias("entries")) count_all: int = session.execute(query_count).scalar() @@ -597,7 +576,7 @@ class Library: res = SearchResult( total_count=count_all, - items=list(session.scalars(statement).unique()), + items=list(session.scalars(statement)), ) session.expunge_all() diff --git a/tagstudio/src/core/library/alchemy/visitors.py b/tagstudio/src/core/library/alchemy/visitors.py new file mode 100644 index 00000000..6f73a45a --- /dev/null +++ b/tagstudio/src/core/library/alchemy/visitors.py @@ -0,0 +1,125 @@ +from typing import TYPE_CHECKING + +from sqlalchemy import and_, distinct, func, or_, select +from sqlalchemy.orm import Session +from sqlalchemy.sql.expression import BinaryExpression, ColumnExpressionArgument +from src.core.media_types import MediaCategories +from src.core.query_lang import BaseVisitor +from src.core.query_lang.ast import AST, ANDList, Constraint, ConstraintType, Not, ORList, Property + +from .joins import TagField +from .models import Entry, Tag, TagAlias, TagBoxField + +# workaround to have autocompletion in the Editor +if TYPE_CHECKING: + from .library import Library +else: + Library = None # don't import .library because of circular imports + + +class SQLBoolExpressionBuilder(BaseVisitor[ColumnExpressionArgument]): + def __init__(self, lib: Library) -> None: + super().__init__() + self.lib = lib + + def visit_or_list(self, node: ORList) -> ColumnExpressionArgument: + return or_(*[self.visit(element) for element in node.elements]) + + def visit_and_list(self, node: ANDList) -> ColumnExpressionArgument: + tag_ids: list[int] = [] + bool_expressions: list[ColumnExpressionArgument] = [] + + # Search for TagID / unambigous Tag Constraints and store the respective tag ids seperately + for term in node.terms: + if isinstance(term, Constraint) and len(term.properties) == 0: + match term.type: + case ConstraintType.TagID: + tag_ids.append(int(term.value)) + continue + case ConstraintType.Tag: + if len(ids := self.__get_tag_ids(term.value)) == 1: + tag_ids.append(ids[0]) + continue + + bool_expressions.append(self.__entry_satisfies_ast(term)) + + # If there are at least two tag ids use a relational division query + # to efficiently check all of them + if len(tag_ids) > 1: + bool_expressions.append(self.__entry_has_all_tags(tag_ids)) + # If there is just one tag id, check the normal way + elif len(tag_ids) == 1: + bool_expressions.append( + self.__entry_satisfies_expression(TagField.tag_id == tag_ids[0]) + ) + + return and_(*bool_expressions) + + def visit_constraint(self, node: Constraint) -> ColumnExpressionArgument: + if len(node.properties) != 0: + raise NotImplementedError("Properties are not implemented yet") # TODO TSQLANG + + if node.type == ConstraintType.Tag: + return TagBoxField.tags.any(Tag.id.in_(self.__get_tag_ids(node.value))) + elif node.type == ConstraintType.TagID: + return TagBoxField.tags.any(Tag.id == int(node.value)) + elif node.type == ConstraintType.Path: + return Entry.path.op("GLOB")(node.value) + elif node.type == ConstraintType.MediaType: + extensions: set[str] = set[str]() + for media_cat in MediaCategories.ALL_CATEGORIES: + if node.value == media_cat.name: + extensions = extensions | media_cat.extensions + break + return Entry.suffix.in_(map(lambda x: x.replace(".", ""), extensions)) + elif node.type == ConstraintType.FileType: + return Entry.suffix.ilike(node.value) + elif node.type == ConstraintType.Special: # noqa: SIM102 unnecessary once there is a second special constraint + if node.value.lower() == "untagged": + return ~Entry.id.in_( + select(Entry.id).join(Entry.tag_box_fields).join(TagBoxField.tags) + ) + + # raise exception if Constraint stays unhandled + raise NotImplementedError("This type of constraint is not implemented yet") + + def visit_property(self, node: Property) -> None: + raise NotImplementedError("This should never be reached!") + + def visit_not(self, node: Not) -> ColumnExpressionArgument: + return ~self.__entry_satisfies_ast(node.child) + + def __get_tag_ids(self, tag_name: str) -> list[int]: + """Given a tag name find the ids of all tags that this name could refer to.""" + with Session(self.lib.engine, expire_on_commit=False) as session: + return list( + session.scalars( + select(Tag.id) + .where(or_(Tag.name.ilike(tag_name), Tag.shorthand.ilike(tag_name))) + .union(select(TagAlias.tag_id).where(TagAlias.name.ilike(tag_name))) + ) + ) + + def __entry_has_all_tags(self, tag_ids: list[int]) -> BinaryExpression[bool]: + """Returns Binary Expression that is true if the Entry has all provided tag ids.""" + # Relational Division Query + return Entry.id.in_( + select(Entry.id) + .outerjoin(TagBoxField) + .outerjoin(TagField) + .where(TagField.tag_id.in_(tag_ids)) + .group_by(Entry.id) + .having(func.count(distinct(TagField.tag_id)) == len(tag_ids)) + ) + + def __entry_satisfies_ast(self, partial_query: AST) -> BinaryExpression[bool]: + """Returns Binary Expression that is true if the Entry satisfies the partial query.""" + return self.__entry_satisfies_expression(self.visit(partial_query)) + + def __entry_satisfies_expression( + self, expr: ColumnExpressionArgument + ) -> BinaryExpression[bool]: + """Returns Binary Expression that is true if the Entry satisfies the column expression.""" + return Entry.id.in_( + select(Entry.id).outerjoin(Entry.tag_box_fields).outerjoin(TagField).where(expr) + ) diff --git a/tagstudio/src/core/query_lang/__init__.py b/tagstudio/src/core/query_lang/__init__.py new file mode 100644 index 00000000..9f1afca1 --- /dev/null +++ b/tagstudio/src/core/query_lang/__init__.py @@ -0,0 +1,11 @@ +from src.core.query_lang.ast import ( # noqa + AST, + ANDList, + BaseVisitor, + Constraint, + ConstraintType, + ORList, + Property, +) +from src.core.query_lang.parser import Parser # noqa +from src.core.query_lang.util import ParsingError # noqa diff --git a/tagstudio/src/core/query_lang/ast.py b/tagstudio/src/core/query_lang/ast.py new file mode 100644 index 00000000..9ebab448 --- /dev/null +++ b/tagstudio/src/core/query_lang/ast.py @@ -0,0 +1,126 @@ +from abc import ABC, abstractmethod +from enum import Enum +from typing import Generic, TypeVar + + +class ConstraintType(Enum): + Tag = 0 + TagID = 1 + MediaType = 2 + FileType = 3 + Path = 4 + Special = 5 + + @staticmethod + def from_string(text: str) -> "ConstraintType": + return { + "tag": ConstraintType.Tag, + "tag_id": ConstraintType.TagID, + "mediatype": ConstraintType.MediaType, + "filetype": ConstraintType.FileType, + "path": ConstraintType.Path, + "special": ConstraintType.Special, + }.get(text.lower(), None) + + +class AST: + parent: "AST" = None + + def __str__(self): + class_name = self.__class__.__name__ + fields = vars(self) # Get all instance variables as a dictionary + field_str = ", ".join(f"{key}={value}" for key, value in fields.items()) + return f"{class_name}({field_str})" + + def __repr__(self) -> str: + return self.__str__() + + +class ANDList(AST): + terms: list[AST] + + def __init__(self, terms: list[AST]) -> None: + super().__init__() + for term in terms: + term.parent = self + self.terms = terms + + +class ORList(AST): + elements: list[AST] + + def __init__(self, elements: list[AST]) -> None: + super().__init__() + for element in elements: + element.parent = self + self.elements = elements + + +class Constraint(AST): + type: ConstraintType + value: str + properties: list["Property"] + + def __init__(self, type: ConstraintType, value: str, properties: list["Property"]) -> None: + super().__init__() + for prop in properties: + prop.parent = self + self.type = type + self.value = value + self.properties = properties + + +class Property(AST): + key: str + value: str + + def __init__(self, key: str, value: str) -> None: + super().__init__() + self.key = key + self.value = value + + +class Not(AST): + child: AST + + def __init__(self, child: AST) -> None: + super().__init__() + self.child = child + + +T = TypeVar("T") + + +class BaseVisitor(ABC, Generic[T]): + def visit(self, node: AST) -> T: + if isinstance(node, ANDList): + return self.visit_and_list(node) + elif isinstance(node, ORList): + return self.visit_or_list(node) + elif isinstance(node, Constraint): + return self.visit_constraint(node) + elif isinstance(node, Property): + return self.visit_property(node) + elif isinstance(node, Not): + return self.visit_not(node) + raise Exception(f"Unknown Node Type of {node}") # pragma: nocover + + @abstractmethod + def visit_and_list(self, node: ANDList) -> T: + raise NotImplementedError() # pragma: nocover + + @abstractmethod + def visit_or_list(self, node: ORList) -> T: + raise NotImplementedError() # pragma: nocover + + @abstractmethod + def visit_constraint(self, node: Constraint) -> T: + raise NotImplementedError() # pragma: nocover + + @abstractmethod + def visit_property(self, node: Property) -> T: + raise NotImplementedError() # pragma: nocover + + @abstractmethod + def visit_not(self, node: Not) -> T: + raise NotImplementedError() # pragma: nocover diff --git a/tagstudio/src/core/query_lang/parser.py b/tagstudio/src/core/query_lang/parser.py new file mode 100644 index 00000000..7194faad --- /dev/null +++ b/tagstudio/src/core/query_lang/parser.py @@ -0,0 +1,120 @@ +from .ast import AST, ANDList, Constraint, Not, ORList, Property +from .tokenizer import ConstraintType, Token, Tokenizer, TokenType +from .util import ParsingError + + +class Parser: + text: str + tokenizer: Tokenizer + next_token: Token + + last_constraint_type: ConstraintType = ConstraintType.Tag + + def __init__(self, text: str) -> None: + self.text = text + self.tokenizer = Tokenizer(self.text) + self.next_token = self.tokenizer.get_next_token() + + def parse(self) -> AST: + if self.next_token.type == TokenType.EOF: + return ORList([]) + out = self.__or_list() + if self.next_token.type != TokenType.EOF: + raise ParsingError(self.next_token.start, self.next_token.end, "Syntax Error") + return out + + def __or_list(self) -> AST: + terms = [self.__and_list()] + + while self.__is_next_or(): + self.__eat(TokenType.ULITERAL) + terms.append(self.__and_list()) + + return ORList(terms) if len(terms) > 1 else terms[0] + + def __is_next_or(self) -> bool: + return self.next_token.type == TokenType.ULITERAL and self.next_token.value.upper() == "OR" + + def __and_list(self) -> AST: + elements = [self.__term()] + while ( + self.next_token.type + in [ + TokenType.QLITERAL, + TokenType.ULITERAL, + TokenType.CONSTRAINTTYPE, + TokenType.RBRACKETO, + ] + and not self.__is_next_or() + ): + self.__skip_and() + elements.append(self.__term()) + return ANDList(elements) if len(elements) > 1 else elements[0] + + def __skip_and(self) -> None: + if self.__is_next_and(): + self.__eat(TokenType.ULITERAL) + + if self.__is_next_and(): + raise self.__syntax_error("Unexpected AND") + + def __is_next_and(self) -> bool: + return self.next_token.type == TokenType.ULITERAL and self.next_token.value.upper() == "AND" + + def __term(self) -> AST: + if self.__is_next_not(): + self.__eat(TokenType.ULITERAL) + term = self.__term() + if isinstance(term, Not): # instead of Not(Not(child)) return child + return term.child + return Not(term) + if self.next_token.type == TokenType.RBRACKETO: + self.__eat(TokenType.RBRACKETO) + out = self.__or_list() + self.__eat(TokenType.RBRACKETC) + return out + else: + return self.__constraint() + + def __is_next_not(self) -> bool: + return self.next_token.type == TokenType.ULITERAL and self.next_token.value.upper() == "NOT" + + def __constraint(self) -> Constraint: + if self.next_token.type == TokenType.CONSTRAINTTYPE: + self.last_constraint_type = self.__eat(TokenType.CONSTRAINTTYPE).value + + value = self.__literal() + + properties = [] + if self.next_token.type == TokenType.SBRACKETO: + self.__eat(TokenType.SBRACKETO) + properties.append(self.__property()) + + while self.next_token.type == TokenType.COMMA: + self.__eat(TokenType.COMMA) + properties.append(self.__property()) + + self.__eat(TokenType.SBRACKETC) + + return Constraint(self.last_constraint_type, value, properties) + + def __property(self) -> Property: + key = self.__eat(TokenType.ULITERAL).value + self.__eat(TokenType.EQUALS) + value = self.__literal() + return Property(key, value) + + def __literal(self) -> str: + if self.next_token.type in [TokenType.QLITERAL, TokenType.ULITERAL]: + return self.__eat(self.next_token.type).value + raise self.__syntax_error() + + def __eat(self, type: TokenType) -> Token: + if self.next_token.type != type: + raise self.__syntax_error(f"expected {type} found {self.next_token.type}") + out = self.next_token + self.next_token = self.tokenizer.get_next_token() + return out + + def __syntax_error(self, msg: str = "Syntax Error") -> ParsingError: + return ParsingError(self.next_token.start, self.next_token.end, msg) diff --git a/tagstudio/src/core/query_lang/tokenizer.py b/tagstudio/src/core/query_lang/tokenizer.py new file mode 100644 index 00000000..ba86abdf --- /dev/null +++ b/tagstudio/src/core/query_lang/tokenizer.py @@ -0,0 +1,147 @@ +from enum import Enum +from typing import Any + +from .ast import ConstraintType +from .util import ParsingError + + +class TokenType(Enum): + EOF = -1 + QLITERAL = 0 # Quoted Literal + ULITERAL = 1 # Unquoted Literal (does not contain ":", " ", "[", "]", "(", ")", "=", ",") + RBRACKETO = 2 # Round Bracket Open + RBRACKETC = 3 # Round Bracket Close + SBRACKETO = 4 # Square Bracket Open + SBRACKETC = 5 # Square Bracket Close + CONSTRAINTTYPE = 6 + COLON = 10 + COMMA = 11 + EQUALS = 12 + + +class Token: + type: TokenType + value: Any + + start: int + end: int + + def __init__(self, type: TokenType, value: Any, start: int = None, end: int = None) -> None: + self.type = type + self.value = value + self.start = start + self.end = end + + @staticmethod + def from_type(type: TokenType, pos: int = None) -> "Token": + return Token(type, None, pos, pos) + + @staticmethod + def EOF() -> "Token": # noqa: N802 + return Token.from_type(TokenType.EOF) + + def __str__(self) -> str: + return f"Token({self.type}, {self.value}, {self.start}, {self.end})" # pragma: nocover + + def __repr__(self) -> str: + return self.__str__() # pragma: nocover + + +class Tokenizer: + text: str + pos: int + current_char: str + + ESCAPABLE_CHARS = ["\\", '"', '"'] + NOT_IN_ULITERAL = [":", " ", "[", "]", "(", ")", "=", ","] + + def __init__(self, text: str) -> None: + self.text = text + self.pos = 0 + self.current_char = self.text[self.pos] if len(text) > 0 else None + + def get_next_token(self) -> Token: + self.__skip_whitespace() + if self.current_char is None: + return Token.EOF() + + if self.current_char in ("'", '"'): + return self.__quoted_string() + elif self.current_char == "(": + self.__advance() + return Token.from_type(TokenType.RBRACKETO, self.pos - 1) + elif self.current_char == ")": + self.__advance() + return Token.from_type(TokenType.RBRACKETC, self.pos - 1) + elif self.current_char == "[": + self.__advance() + return Token.from_type(TokenType.SBRACKETO, self.pos - 1) + elif self.current_char == "]": + self.__advance() + return Token.from_type(TokenType.SBRACKETC, self.pos - 1) + elif self.current_char == ",": + self.__advance() + return Token.from_type(TokenType.COMMA, self.pos - 1) + elif self.current_char == "=": + self.__advance() + return Token.from_type(TokenType.EQUALS, self.pos - 1) + else: + return self.__unquoted_string_or_constraint_type() + + def __unquoted_string_or_constraint_type(self) -> Token: + out = "" + + start = self.pos + + while self.current_char not in self.NOT_IN_ULITERAL and self.current_char is not None: + out += self.current_char + self.__advance() + + end = self.pos - 1 + + if self.current_char == ":": + if len(out) == 0: + raise ParsingError(self.pos, self.pos) + self.__advance() + constraint_type = ConstraintType.from_string(out) + if constraint_type is None: + raise ParsingError(start, end, f'Invalid ContraintType "{out}"') + return Token(TokenType.CONSTRAINTTYPE, constraint_type, start, end) + else: + return Token(TokenType.ULITERAL, out, start, end) + + def __quoted_string(self) -> Token: + start = self.pos + quote = self.current_char + self.__advance() + escape = False + out = "" + + while escape or self.current_char != quote: + if escape: + escape = False + if self.current_char not in Tokenizer.ESCAPABLE_CHARS: + out += "\\" + else: + out += self.current_char + self.__advance() + continue + if self.current_char == "\\": + escape = True + else: + out += self.current_char + self.__advance() + end = self.pos + self.__advance() + return Token(TokenType.QLITERAL, out, start, end) + + def __advance(self) -> None: + if self.pos < len(self.text) - 1: + self.pos += 1 + self.current_char = self.text[self.pos] + else: + self.current_char = None + + def __skip_whitespace(self) -> None: + while self.current_char is not None and self.current_char.isspace(): + self.__advance() diff --git a/tagstudio/src/core/query_lang/util.py b/tagstudio/src/core/query_lang/util.py new file mode 100644 index 00000000..8deaecf2 --- /dev/null +++ b/tagstudio/src/core/query_lang/util.py @@ -0,0 +1,15 @@ +class ParsingError(BaseException): + start: int + end: int + msg: str + + def __init__(self, start: int, end: int, msg: str = "Syntax Error") -> None: + self.start = start + self.end = end + self.msg = msg + + def __str__(self) -> str: + return f"Syntax Error {self.start}->{self.end}: {self.msg}" # pragma: nocover + + def __repr__(self) -> str: + return self.__str__() # pragma: nocover diff --git a/tagstudio/src/core/utils/dupe_files.py b/tagstudio/src/core/utils/dupe_files.py index 2d0a074b..3c1d55d1 100644 --- a/tagstudio/src/core/utils/dupe_files.py +++ b/tagstudio/src/core/utils/dupe_files.py @@ -50,7 +50,7 @@ class DupeRegistry: continue results = self.library.search_library( - FilterState(path=path_relative), + FilterState.from_path(path_relative), ) if not results: diff --git a/tagstudio/src/qt/main_window.py b/tagstudio/src/qt/main_window.py index 621ed9cf..3de0118d 100644 --- a/tagstudio/src/qt/main_window.py +++ b/tagstudio/src/qt/main_window.py @@ -74,14 +74,6 @@ class Ui_MainWindow(QMainWindow): spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem) - # Search type selector - self.comboBox_2 = QComboBox(self.centralwidget) - self.comboBox_2.setMinimumSize(QSize(165, 0)) - self.comboBox_2.setObjectName("comboBox_2") - self.comboBox_2.addItem("") - self.comboBox_2.addItem("") - self.horizontalLayout_3.addWidget(self.comboBox_2) - # Thumbnail Size placeholder self.thumb_size_combobox = QComboBox(self.centralwidget) self.thumb_size_combobox.setObjectName(u"thumbSizeComboBox") @@ -214,9 +206,6 @@ class Ui_MainWindow(QMainWindow): self.searchButton.setText( QCoreApplication.translate("MainWindow", u"Search", None)) - # Search type selector - self.comboBox_2.setItemText(0, QCoreApplication.translate("MainWindow", "And (Includes All Tags)")) - self.comboBox_2.setItemText(1, QCoreApplication.translate("MainWindow", "Or (Includes Any Tag)")) self.thumb_size_combobox.setCurrentText("") # Thumbnail size selector diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index c6ef2034..4e3cfaed 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -65,14 +65,14 @@ from src.core.constants import ( ) from src.core.driver import DriverMixin from src.core.enums import LibraryPrefs, MacroID, SettingItems +from src.core.library.alchemy import Library from src.core.library.alchemy.enums import ( FieldTypeEnum, FilterState, ItemType, - SearchMode, ) from src.core.library.alchemy.fields import _FieldID -from src.core.library.alchemy.library import Entry, Library, LibraryStatus +from src.core.library.alchemy.library import Entry, LibraryStatus from src.core.media_types import MediaCategories from src.core.ts_core import TagStudioCore from src.core.utils.refresh_dir import RefreshDirTracker @@ -140,7 +140,7 @@ class QtDriver(DriverMixin, QObject): self.rm: ResourceManager = ResourceManager() self.args = args self.frame_content = [] - self.filter = FilterState() + self.filter = FilterState.show_all() self.pages_count = 0 self.scrollbar_pos = 0 @@ -468,7 +468,7 @@ class QtDriver(DriverMixin, QObject): ] self.item_thumbs: list[ItemThumb] = [] self.thumb_renderers: list[ThumbRenderer] = [] - self.filter = FilterState() + self.filter = FilterState.show_all() self.init_library_window() self.migration_modal: JsonMigrationModal = None @@ -510,18 +510,17 @@ class QtDriver(DriverMixin, QObject): # Search Button search_button: QPushButton = self.main_window.searchButton search_button.clicked.connect( - lambda: self.filter_items(FilterState(query=self.main_window.searchField.text())) + lambda: self.filter_items( + FilterState.from_search_query(self.main_window.searchField.text()) + ) ) # Search Field search_field: QLineEdit = self.main_window.searchField search_field.returnPressed.connect( # TODO - parse search field for filters - lambda: self.filter_items(FilterState(query=self.main_window.searchField.text())) - ) - # Search Type Selector - search_type_selector: QComboBox = self.main_window.comboBox_2 - search_type_selector.currentIndexChanged.connect( - lambda: self.set_search_type(SearchMode(search_type_selector.currentIndex())) + lambda: self.filter_items( + FilterState.from_search_query(self.main_window.searchField.text()) + ) ) # Thumbnail Size ComboBox thumb_size_combobox: QComboBox = self.main_window.thumb_size_combobox @@ -963,11 +962,20 @@ class QtDriver(DriverMixin, QObject): self.autofill_action.setDisabled(not self.selected) def update_completions_list(self, text: str) -> None: - matches = re.search(r"(mediatype|filetype|path|tag):(\"?[A-Za-z0-9\ \t]+\"?)?", text) + matches = re.search( + r"((?:.* )?)(mediatype|filetype|path|tag|tag_id):(\"?[A-Za-z0-9\ \t]+\"?)?", text + ) completion_list: list[str] = [] if len(text) < 3: - completion_list = ["mediatype:", "filetype:", "path:", "tag:"] + completion_list = [ + "mediatype:", + "filetype:", + "path:", + "tag:", + "tag_id:", + "special:untagged", + ] self.main_window.searchFieldCompletionList.setStringList(completion_list) if not matches: @@ -975,26 +983,28 @@ class QtDriver(DriverMixin, QObject): query_type: str query_value: str | None - query_type, query_value = matches.groups() + prefix, query_type, query_value = matches.groups() if not query_value: return if query_type == "tag": - completion_list = list(map(lambda x: "tag:" + x.name, self.lib.tags)) + completion_list = list(map(lambda x: prefix + "tag:" + x.name, self.lib.tags)) + elif query_type == "tag_id": + completion_list = list(map(lambda x: prefix + "tag_id:" + str(x.id), self.lib.tags)) elif query_type == "path": - completion_list = list(map(lambda x: "path:" + x, self.lib.get_paths())) + completion_list = list(map(lambda x: prefix + "path:" + x, self.lib.get_paths())) elif query_type == "mediatype": single_word_completions = map( - lambda x: "mediatype:" + x.name, + lambda x: prefix + "mediatype:" + x.name, filter(lambda y: " " not in y.name, MediaCategories.ALL_CATEGORIES), ) single_word_completions_quoted = map( - lambda x: 'mediatype:"' + x.name + '"', + lambda x: prefix + 'mediatype:"' + x.name + '"', filter(lambda y: " " not in y.name, MediaCategories.ALL_CATEGORIES), ) multi_word_completions = map( - lambda x: 'mediatype:"' + x.name + '"', + lambda x: prefix + 'mediatype:"' + x.name + '"', filter(lambda y: " " in y.name, MediaCategories.ALL_CATEGORIES), ) @@ -1008,7 +1018,9 @@ class QtDriver(DriverMixin, QObject): extensions_list: set[str] = set() for media_cat in MediaCategories.ALL_CATEGORIES: extensions_list = extensions_list | media_cat.extensions - completion_list = list(map(lambda x: "filetype:" + x.replace(".", ""), extensions_list)) + completion_list = list( + map(lambda x: prefix + "filetype:" + x.replace(".", ""), extensions_list) + ) update_completion_list: bool = ( completion_list != self.main_window.searchFieldCompletionList.stringList() @@ -1125,8 +1137,12 @@ class QtDriver(DriverMixin, QObject): if filter: self.filter = dataclasses.replace(self.filter, **dataclasses.asdict(filter)) - self.main_window.statusbar.showMessage(f'Searching Library: "{self.filter.summary}"') + # inform user about running search + self.main_window.statusbar.showMessage("Searching Library...") self.main_window.statusbar.repaint() + + # search the library + start_time = time.time() results = self.lib.search_library(self.filter) @@ -1134,17 +1150,11 @@ class QtDriver(DriverMixin, QObject): logger.info("items to render", count=len(results)) end_time = time.time() - if self.filter.summary: - # fmt: off - self.main_window.statusbar.showMessage( - f"{results.total_count} Results Found for \"{self.filter.summary}\"" - f" ({format_timespan(end_time - start_time)})" - ) - # fmt: on - else: - self.main_window.statusbar.showMessage( - f"{results.total_count} Results ({format_timespan(end_time - start_time)})" - ) + + # inform user about completed search + self.main_window.statusbar.showMessage( + f"{results.total_count} Results Found ({format_timespan(end_time - start_time)})" + ) # update page content self.frame_content = results.items @@ -1156,14 +1166,6 @@ class QtDriver(DriverMixin, QObject): self.pages_count, self.filter.page_index, emit=False ) - def set_search_type(self, mode: SearchMode = SearchMode.AND): - self.filter_items( - FilterState( - search_mode=mode, - path=self.main_window.searchField.text(), - ) - ) - def remove_recent_library(self, item_key: str): self.settings.beginGroup(SettingItems.LIBS_LIST) self.settings.remove(item_key) diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index a6983959..07bf4862 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -25,7 +25,6 @@ from src.core.constants import ( TAG_FAVORITE, ) from src.core.library import Entry, ItemType, Library -from src.core.library.alchemy.enums import FilterState from src.core.library.alchemy.fields import _FieldID from src.core.media_types import MediaCategories, MediaType from src.qt.flowlayout import FlowWidget @@ -453,9 +452,7 @@ class ItemThumb(FlowWidget): entry, toggle_value, tag_id, _FieldID.TAGS_META.name, create_field=True ) # update the entry - self.driver.frame_content[idx] = self.lib.search_library( - FilterState(id=entry.id) - ).items[0] + self.driver.frame_content[idx] = self.lib.get_entry_full(entry.id) self.driver.update_badges(update_items) diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index 70fce9b5..7e8e0c8b 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -36,7 +36,6 @@ from src.core.constants import ( TS_FOLDER_NAME, ) from src.core.enums import SettingItems, Theme -from src.core.library.alchemy.enums import FilterState from src.core.library.alchemy.fields import ( BaseField, DatetimeField, @@ -295,14 +294,13 @@ class PreviewPanel(QWidget): def update_selected_entry(self, driver: "QtDriver"): for grid_idx in driver.selected: entry = driver.frame_content[grid_idx] - results = self.lib.search_library(FilterState(id=entry.id)) + result = self.lib.get_entry_full(entry.id) logger.info( "found item", - entries=len(results.items), grid_idx=grid_idx, lookup_id=entry.id, ) - self.driver.frame_content[grid_idx] = results[0] + self.driver.frame_content[grid_idx] = result def remove_field_prompt(self, name: str) -> str: return f'Are you sure you want to remove field "{name}"?' @@ -564,14 +562,13 @@ class PreviewPanel(QWidget): # TODO - Entry reload is maybe not necessary for grid_idx in self.driver.selected: entry = self.driver.frame_content[grid_idx] - results = self.lib.search_library(FilterState(id=entry.id)) + result = self.lib.get_entry_full(entry.id) logger.info( "found item", - entries=len(results.items), grid_idx=grid_idx, lookup_id=entry.id, ) - self.driver.frame_content[grid_idx] = results[0] + self.driver.frame_content[grid_idx] = result if len(self.driver.selected) == 1: # 1 Selected Entry diff --git a/tagstudio/src/qt/widgets/tag_box.py b/tagstudio/src/qt/widgets/tag_box.py index c4496e62..a1c7301b 100755 --- a/tagstudio/src/qt/widgets/tag_box.py +++ b/tagstudio/src/qt/widgets/tag_box.py @@ -100,7 +100,7 @@ class TagBoxWidget(FieldWidget): tag_widget.on_click.connect( lambda tag_id=tag.id: ( self.driver.main_window.searchField.setText(f"tag_id:{tag_id}"), - self.driver.filter_items(FilterState(tag_id=tag_id)), + self.driver.filter_items(FilterState.from_tag_id(tag_id)), ) ) diff --git a/tagstudio/tests/conftest.py b/tagstudio/tests/conftest.py index 39c3f753..7a59d05e 100644 --- a/tagstudio/tests/conftest.py +++ b/tagstudio/tests/conftest.py @@ -117,13 +117,20 @@ def library(request): yield lib +@pytest.fixture +def search_library() -> Library: + lib = Library() + lib.open_library(pathlib.Path(CWD / "fixtures" / "search_library")) + return lib + + @pytest.fixture def entry_min(library): yield next(library.get_entries()) @pytest.fixture -def entry_full(library): +def entry_full(library: Library): yield next(library.get_entries(with_joins=True)) diff --git a/tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.json b/tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.json new file mode 100644 index 00000000..ff3fb742 --- /dev/null +++ b/tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.json @@ -0,0 +1 @@ +{"ts-version":"9.4.2","ext_list":[".json",".xmp",".aae",".txt"],"is_exclude_list":true,"tags":[{"id":0,"name":"Archived","aliases":["Archive"],"color":"Red"},{"id":1,"name":"Favorite","aliases":["Favorited","Favorites"],"color":"Yellow"},{"id":1000,"name":"Parent","aliases":[""],"subtag_ids":[1000]},{"id":1001,"name":"Default","aliases":[""]},{"id":1002,"name":"Black","aliases":[""],"subtag_ids":[1040],"color":"black"},{"id":1003,"name":"Dark Gray","aliases":["Dark Grey"],"subtag_ids":[1040,1002,1004],"color":"dark gray"},{"id":1004,"name":"Gray","aliases":["Grey"],"subtag_ids":[1040,1002,1006],"color":"gray"},{"id":1005,"name":"Light Gray","aliases":["Light Grey"],"subtag_ids":[1040,1006,1004],"color":"light gray"},{"id":1006,"name":"White","aliases":[""],"subtag_ids":[1040],"color":"white"},{"id":1007,"name":"Light Pink","aliases":[""],"subtag_ids":[1040,1009,1006],"color":"light pink"},{"id":1008,"name":"Pink","aliases":[""],"subtag_ids":[1040,1006,1009],"color":"pink"},{"id":1009,"name":"Red","aliases":[""],"subtag_ids":[1040],"color":"red"},{"id":1010,"name":"Red Orange","aliases":[""],"subtag_ids":[1040,1009,1011],"color":"red orange"},{"id":1011,"name":"Orange","aliases":[""],"subtag_ids":[1040,1009,1013],"color":"orange"},{"id":1012,"name":"Yellow Orange","aliases":[""],"subtag_ids":[1040,1011],"color":"yellow orange"},{"id":1013,"name":"Yellow","aliases":[""],"subtag_ids":[1040],"color":"yellow"},{"id":1014,"name":"Lime","aliases":[""],"subtag_ids":[1040,1017,1006],"color":"lime"},{"id":1015,"name":"Light Green","aliases":[""],"color":"light green"},{"id":1016,"name":"Mint","aliases":[""],"subtag_ids":[1040,1017,1019],"color":"mint"},{"id":1017,"name":"Green","aliases":[""],"subtag_ids":[1040,1021,1013],"color":"green"},{"id":1018,"name":"Teal","aliases":[""],"subtag_ids":[1040,1017,1021],"color":"teal"},{"id":1019,"name":"Cyan","aliases":[""],"subtag_ids":[1040,1017,1021],"color":"cyan"},{"id":1020,"name":"Light Blue","aliases":[""],"subtag_ids":[1040,1021,1006],"color":"light blue"},{"id":1021,"name":"Blue","aliases":[""],"subtag_ids":[1040],"color":"blue"},{"id":1022,"name":"Blue Violet","aliases":[""],"subtag_ids":[1040,1021,1023],"color":"blue violet"},{"id":1023,"name":"Violet","aliases":[""],"subtag_ids":[1040,1009,1021],"color":"violet"},{"id":1024,"name":"Purple","aliases":[""],"subtag_ids":[1040,1009,1021],"color":"purple"},{"id":1025,"name":"Lavender","aliases":[""],"subtag_ids":[1040,1024,1006],"color":"lavender"},{"id":1026,"name":"Berry","aliases":[""],"color":"berry"},{"id":1027,"name":"Magenta","aliases":[""],"color":"magenta"},{"id":1028,"name":"Salmon","aliases":[""],"color":"salmon"},{"id":1029,"name":"Auburn","aliases":[""],"color":"auburn"},{"id":1030,"name":"Dark Brown","aliases":[""],"color":"dark brown"},{"id":1031,"name":"Brown","aliases":[""],"color":"brown"},{"id":1032,"name":"Light Brown","aliases":[""],"color":"light brown"},{"id":1033,"name":"Blonde","aliases":[""],"color":"blonde"},{"id":1034,"name":"Peach","aliases":[""],"color":"peach"},{"id":1035,"name":"Warm Gray","aliases":["Warm Grey"],"subtag_ids":[1040,1004,1011],"color":"warm gray"},{"id":1036,"name":"Cool Gray","aliases":["Cool Grey"],"subtag_ids":[1040,1004,1021],"color":"cool gray"},{"id":1037,"name":"Olive","aliases":[""],"subtag_ids":[1040,1017,1004],"color":"olive"},{"id":1038,"name":"Square","aliases":[""],"subtag_ids":[1039]},{"id":1039,"name":"Shape","aliases":[""]},{"id":1040,"name":"Color","aliases":[""]},{"id":1041,"name":"Circle","aliases":[""],"subtag_ids":[1039,1042]},{"id":1042,"name":"Ellipse","aliases":[""],"subtag_ids":[1039,1043]},{"id":1043,"name":"Round","aliases":[""]}],"collations":[],"fields":[],"macros":[],"entries":[{"id":0,"filename":"red.jpg","path":"inherit colors shapes"},{"id":1,"filename":"red_square.jpg","path":"inherit colors shapes","fields":[{"6":[1009,1038]}]},{"id":2,"filename":"red_circle.jpg","path":"inherit colors shapes","fields":[{"6":[1041,1009]}]},{"id":3,"filename":"blue_circle.jpg","path":"inherit colors shapes","fields":[{"6":[1021,1041]}]},{"id":4,"filename":"blue_square.jpg","path":"inherit colors shapes","fields":[{"6":[1021,1038]}]},{"id":5,"filename":"blue.jpg","path":"inherit colors shapes","fields":[{"6":[1021]}]},{"id":10,"filename":"green_circle.png","path":"inherit colors shapes","fields":[{"6":[1041,1017]}]},{"id":11,"filename":"green.png","path":"inherit colors shapes","fields":[{"6":[1017]}]},{"id":12,"filename":"green_square.png","path":"inherit colors shapes","fields":[{"6":[1017,1038]}]},{"id":13,"filename":"yellow_circle.png","path":"inherit colors shapes","fields":[{"6":[1041,1013]}]},{"id":14,"filename":"yellow_square.png","path":"inherit colors shapes","fields":[{"6":[1038,1013]}]},{"id":15,"filename":"yellow.png","path":"inherit colors shapes","fields":[{"6":[1013]}]},{"id":16,"filename":"square.png","path":"inherit colors shapes","fields":[{"6":[1038]}]},{"id":17,"filename":"circle.png","path":"inherit colors shapes","fields":[{"6":[1041]}]},{"id":18,"filename":"shape.png","path":"inherit colors shapes","fields":[{"6":[1039]}]},{"id":19,"filename":"orange_circle.png","path":"inherit colors shapes","fields":[{"6":[1041,1011]}]},{"id":20,"filename":"orange_square.png","path":"inherit colors shapes","fields":[{"6":[1011,1038]}]},{"id":21,"filename":"orange.png","path":"inherit colors shapes","fields":[{"6":[1011]}]},{"id":22,"filename":"yellow_ellipse.png","path":"inherit colors shapes","fields":[{"6":[1042,1013]}]},{"id":23,"filename":"ellipse.png","path":"inherit colors shapes","fields":[{"6":[1042]}]},{"id":24,"filename":"red_ellipse.png","path":"inherit colors shapes","fields":[{"6":[1042,1009]}]},{"id":25,"filename":"blue_ellipse.png","path":"inherit colors shapes","fields":[{"6":[1021,1042]}]},{"id":26,"filename":"green_ellipse.png","path":"inherit colors shapes","fields":[{"6":[1042,1017]}]},{"id":27,"filename":"orange_ellipse.png","path":"inherit colors shapes","fields":[{"6":[1042,1011]}]},{"id":30,"filename":"r_circle_b_square.png","path":"comp colors shapes","fields":[{"6":[1021,1041,1009,1038]}]},{"id":31,"filename":"r_circle_g_square.png","path":"comp colors shapes","fields":[{"6":[1041,1017,1009,1038]}]},{"id":32,"filename":"r_circle_y_square.png","path":"comp colors shapes","fields":[{"6":[1041,1009,1038,1013]}]},{"id":33,"filename":"r_circle_o_square.png","path":"comp colors shapes","fields":[{"6":[1041,1011,1009,1038]}]},{"id":34,"filename":"r_circle_r_square.png","path":"comp colors shapes","fields":[{"6":[1041,1009,1038]}]}]} \ No newline at end of file diff --git a/tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.sqlite b/tagstudio/tests/fixtures/search_library/.TagStudio/ts_library.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..449f380b02fad6ca8fbcc08dddf2ca8d99116aaf GIT binary patch literal 86016 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 TZ;*GE|JoT5&GpN4kB9vaG5Ohp literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_g_square.png b/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_g_square.png new file mode 100644 index 0000000000000000000000000000000000000000..0df75c52512230f865e944e48beb95d79741e3ef GIT binary patch literal 3737 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_o_square.png b/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_o_square.png new file mode 100644 index 0000000000000000000000000000000000000000..d49991095c166afb60b7d6c84a34f919e82d8486 GIT binary patch literal 3672 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 LX=hPl<{kS#i`Vv) literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_r_square.png b/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_r_square.png new file mode 100644 index 0000000000000000000000000000000000000000..5a3b5ee99117f2689ad200699fe8449e01f3134d GIT binary patch literal 3266 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_y_square.png b/tagstudio/tests/fixtures/search_library/comp colors shapes/r_circle_y_square.png new file mode 100644 index 0000000000000000000000000000000000000000..170279182496b11e36de47d13fe8086d476c736b GIT binary patch literal 3624 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 TCCGVx=9iQ75C4$}ZT0^bloX2b literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_ellipse.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..e73e917113476fd2b729485fd486dce7529f1da2 GIT binary patch literal 5570 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 E0FE(v&;S4c literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_square.jpg b/tagstudio/tests/fixtures/search_library/inherit colors shapes/blue_square.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5589a7cbe007e87e2b399a32cc92303f4a30271 GIT binary patch literal 8314 zcmeHK2{@GP*T3yTZ&|WMjX`!ZM#R`&yCGSJQYvN!BV(8u#*k3GmP+$#uboco+}pZlEiJkL4I4rU)% zYi)tC0Bq1uWm5%!`3jsh4Q)QPmm=UNr3Ne62B>Tfy8a+J8K{Nw6 zwDXclq=0W~|Mcw3i~&Am8ky=t{sH^9iC&C9<6O)eh!Ya|$_fPu??LnUADO=$AI)N2vIWYH9~-hFU`qBQQy`llyEWmk z6*|V$)Sg22BKkoKR7Xn_7{=UGTSHe{TMebI!HVvpbJ12rDveBGe9adpLf}{AM}#f< z6YYUx#ohoOKq2FUa0ER3E1gRAqR~Al1Y>W=i3V_EFE64$k;Z`8vjPo+o+Bs^wU(Lb zJ_Ja`KOX0MZy}&v5v=rDG63=4ZChOXE)|#Aq5NjSZx4zg?C1FDfuA1u>4Bdf`00V4 z9{B&~ft6C5;15+$bf}PKegLYARSB#7glVcHfsP5rmQ$Wpx`VZC(#JXzKso17gsmXFl}-y_;Zz8V z;Cwvr5WWCmRSIMvgxgqj&m}y_!rn`Gj)f`Cj;7Gr)xoewTe&Vmo)-w#YDu##Y99!C8gyzO0Jic5*3B1 z!elooC@CvRY*a(4DI(<+l@wV@*m!t&_;~q*`S^qtB}F9_|Mp0EZwj0(JK$ zbRR`78upKqR0p9kri&2$Y@}H+@vzLMd?gFIprF|Gj0AP+_IB!te$!$3g+}{6^v$$) zSsYb)MygIz?}zQ=PR41uCf*LBt2{>Ygqbc8Wd%1CjfwwKI>31M>qj5Lkpn$hn0`;W z_T8pz?cHVigVG-aF4=WmF4R9}mRa1m_p8dB6H2qeK?+H+DOiR8k1OTY_*r@ds@}-I z`P`U>kZ+kxTQo={boD#z>yFUitLl4wuDfQv{pY6tNz;-{;AL$ttNU-bB%-0v#pZV|+?!nDWg{-iu+N7ab zZdyT9Ldp)tF@`JEY`lzKi83(S+noAIV{9KnW7!^V%Yye3t!KCmZ3%BR2Hcy3o2z>J z8Ykutp`C93$ixg|@AiBLvE5FIe_*8s2I*eN50za>rAjK8%48HuYZsm{C8AtWED$Vl zrqS(4JSDfU;C+p!l~)qpS0#PG@Z5a1M)_3y0Yt{=*!CA!uCDo@I z#Bj&;L9*JH^4|5)3G#<@dIr@H8ou$43PHw}Pd)`~DPJ{yy!Tv3E9>37Jos!jKXTjS z9NlBp^t;c@v~(wCZ}XN=ew#;bdCqY?_6`&KrB=T`xc|+yLha45k?hG$nxg6LGS?h6 z_emNa;0bozt{LBZuytJYLOY!9EE2wvha(J@t@B~nHXaUJ-UGUyyS%kNf6|K7cI-t% zLUvS7>Is22^s^PW>Wj3jvf8;eTGrm~ZB+QbdKe!UDlSpWU8LT4z0s~Jey2D$+tf^Z zjKleHhYQs_My``)SNT0VWsmZWR97zyMby_{P$ebBPVPMZ0QYL*WmGUcz3|nhZLlgy zCw#KQTwuO6-01C|HkYH%D%V)J^|`?3$qVa*uYY*P-#UdJ7t#^S%$(f# zcxDpkDj~5y>3EmabMtu5-t^tsR3ol{i_SGycWQY(HZq+NR*nbh)zjMkISJyoXcO|Y{lU8VTjF3XeA z_r1KVG44SFb9)l2+>36cd0}33tF#M^jDA5J)YDhe{Did|Nwx90;+eN_#q0Sq5k%Vz zA-rMt+!iJnl;82t=7G53^p>88vGBT0dg~ZPbs?cCcXexpT~FEESP&C8+4k{NJTA?< zq-2dvmv_xrHUGZ7o(FPGo~jnPS~>A$8av0Gyk#d-14}%3D=nfdH=$$SlX*)6i>I;4 zQk>Uam>{B{FFH)c(@O|FwqZGOwMUi`w?d-fqcM?j)Y&&luZYhu;ZRgnqTT7>$xRJO zYk%-2bKC9NE_rU-@WF(i>?U$x}2WrjgB%w|!z8`N5Ur*%D#Yo0Koz2eq zh3}Hj@rT1Anb_+kwb*{*ukGQdxD4ODxfCiI=&iXb-`KV8t_`8^uy*RpGd8ac;V6fm zp`pN@&+{HzE)-3LJ__tqwRNqYT~PnBKWt&HD&fR-Y4+mYYcg?IYAj$6PY@S?-7tlX)K<9ScXb%w}>iT#zB*;8UiANLrIGQk}kCNPfZ zSa>`yrfgI&KDU9kF;^nyyi#_jwdR8Uwl6VnuRfm9qhDi!RINNF@To~wxl@fdCzg(C zYgdu;x*D=l%l0;xzDc$GVB&ToVlbv5qM_!JUGc)lvF%+=nQiUi-fNIa#uXFFu*Ca? z6M@P z*SxgIn+5!~Ub`!Y$8(ID)}y+uyMiuX#~5v%x4Osg9G4Orf2lG33iet-U+ZrVy3~d~ zqY-O@ny~sM>r^uDnQhH)HZAd=8K@tS2va%QU1nrcRb~DX+p4O)bAzF1-i9OT?vry7 z$$C;_2Gi<0TOO0Fu{`ouW>N*N@cOS4B&n(8b#hnac$t4P^EEPVc|sC$BdVUjR&}T> ztaF-H+1BPa95nhVn`E_*C+BAa%st_zLl*+qol{}^9Z%-j;oae zwbdUBYRcWm8NU2DoTrB4c*U_lxa}`CU)kDvkuq6gG^}<9B|G!V+9~|yBbS6H)}Lid zsKuqT5z56KQ&(qGzDRlo3R|7*Y(1aC<0>ffW+AND;Y*2YFRp@+m2@{YPTg0&(f%$r zSm;btMBT1(*_g-qQuLUvh!IW3pQQWg-55kv&bEnjQ+hTEv}vpM>XG!9b4d?L`#MT2=8~rzd{g*%vkyC? zyoA!*8!iMPqO7pbB@>H}k31M@eE973lw{iDZS^iU%!2u!j*N$fH>ytM$8-(wXJpmX z-m%&3m3-bU@<>=)4>dA5EkcZse==bvLqI27LM~ah%1m%1kv5=-V8eQ{J}UIxOKudCyq)IJ0NyHob-NAtCbs}=)v$8564Pn66#%izwW!_ z7P=65VgeHuA8J&fP~a9gW*eQZ?EZ0bF7dIi-|w{+-KL$(g=x=HVe0Z%#nIm@iB^i7 zzgZmp)A_kr->q!(_bR>rpNG_lD%9j^G_@m*)mcy_sEWZL_xr#y@4V<)$37TG43m$Tn6 c`^xXWT7?uD$&!WPfDH+eE6>+A#KY|TFHE8f^#A|> literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/circle.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..722f9f3653d1ade89ce4bf49a52e9e667e0a10f9 GIT binary patch literal 4911 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 XzUAEO@uLgt|8p7W;&qC&ox}eF@XBol literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/ellipse.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..43f903e734d877e4fec36778f3b1198622f4b23a GIT binary patch literal 5440 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 k)k^>Rs>XPKjG%PIVS00?VgyZ`_I literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/green.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/green.png new file mode 100644 index 0000000000000000000000000000000000000000..96020e586985903879dc75adfc0b64ebb00d8915 GIT binary patch literal 8333 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/green_circle.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/green_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..faaf1f1931075850b00ad6ce1df46a463368c9bc GIT binary patch literal 15946 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 CQ41;n literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/green_square.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/green_square.png new file mode 100644 index 0000000000000000000000000000000000000000..5080b3df479beb33d88944565454bd3aa4eebd93 GIT binary patch literal 8559 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 XZ2G}g^8@w&CZMgUuTgZxCgi^W#4=uG literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_circle.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..780eddbbf122373ea71c2f7191217d37cf5ac02d GIT binary patch literal 16167 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_ellipse.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..7496518bb181d72b75c20f6325aea49a89725185 GIT binary patch literal 16250 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_square.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/orange_square.png new file mode 100644 index 0000000000000000000000000000000000000000..8929649d18267770b6db48ef453f0260c1d00b2b GIT binary patch literal 9382 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

NNOC~wgw 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 I%Ngze0)uXgV*mgE literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/red_circle.jpg b/tagstudio/tests/fixtures/search_library/inherit colors shapes/red_circle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4edd09cebba10cfc7ec6d8e1e399eed637ed0a0b GIT binary patch literal 8295 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 E0@E&D2><{9 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/red_square.jpg b/tagstudio/tests/fixtures/search_library/inherit colors shapes/red_square.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2c6568c35e30a6a796c29dfd69a3194ca8452e2 GIT binary patch literal 8016 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/square.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/square.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6014c4262002add34f760d7190346347587f46 GIT binary patch literal 4084 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..38f2434e9706da6211115efb46183d7af693e43b GIT binary patch literal 3677 zcmd5j z6eTShp&JG05G5A zV7C?ej*~708R&Dfza$3$& zGnnSck@^cr1cPdh^fDr2$ZT6Mgy9gy0o|gU-Gie-gH5PNOAEM}hyW=F2YD2PC_IeG zC5X(CGkOWoZ|N}_iI}1ALd}uhWLJbOivuEzP(~;W(gKb!<4|dYt#&_u5r%f=$PgZn zO+cfCLLo|MfMRjzXsn5e2^xb#<8b;AL!TSTZluz3s?6Cu?} z31abi=13%jBmVL%oc&cfllvulC=X~6g^k9dFzD~e><|`@#SLNojmTGcjvy#ve2d`+ zGg4#@oyVa44PA=Np+mVQlm9u2@bDi3;qr(AC=p+h`h!D%#m#k(WP|9fAeY7G1cO8Y z$mD6ykl4V4F#!lV2*{I3ZoNZGSaL8bYR9(|LsWreXgkaJKB1~cZrK_pvSR}PED z2!k;0R(l%+iD+w#H8D2U$Dyz@TW4eGVeMqcFa-$UT@0=vHwvF3bpdf5V_4F&OlB zmVD-7(#AoU&6E?tfx+dmIFU0)v)$wdM$GPJw_%K#HbNj~iito8mU>{0WOGr<-+2k93~4F+$BjShKmqSBUeCd5k>KL#kBB6_uM zRMETl>f%Z-9v`<#<@PNLtu>y5%v_l-=Y;v2ABWTJifZYfM)>kB%Lq`=t33&p9qg_GqWBf4qPnP`VBz z@6An5Eeer*W(B^#^U|TH?y~B2bmE&{Ree)e)bi%8Qd7HDxcxDe|zx!T!%eBDIP3SyP~uP`FP91f*4FQdV7!^86fUGcEwJ?X0%yBtI@&6 z@X)|Dog_qc^}BmRsP66KSzW3IM^Hmzf$;tDClf_lwB82Ou^VI2DLZ>7PUd6Nl@e7F z>R_3sdU5JYt(27ziSlZfW%f{DS55*!-T?N0d;H9CBJIeLw<##a#=eD@-x5E=hr)}~ zfdiTA-sz=!bFgrDLjJu>9QhS1bE-8Bmv>F&#m&~@pA8;o>J&LL&i;9$;jx>B25xCa zsqR}PyQhoJ8e+q;9L~KuutR=(z3sntgRL&S;kqgOI!q0Ie^bEc7|EdT5Q`bP zVCzwFbFx=|n-GTY(i6rmc|G}hJPcByFr&W+IuY5Scz zh6HkxZ;xz30?M*g+tYf2`gF}%A*Vy9*EzL!hiWIO9s=Gfog9s+IPLhb%Csh&tK2Bj zKUF`x|N61pz~X4RI9IiRBN)!@2S}K^=Z1!;swlqn_|xHp7SX*UhX{q*2 zi~I8*k7?AzUCNEofIDh?Rp+JwYd3G*`JNVin71;&z~0K*dO)WAS8@KHB(H(HZ;F$* zgl-cETa#Z8P0*+F7t@<#Q;OFvPX-!CHxfaQk!O#LJBQ6JcPy*zU$w6MVxAnk(nm(! z+!J=IcP&g#wkD3^E(7#fkTonxu+jI+PQ_a+YHT?FroetPpsL?hsg8Zw&|g#gV9R0e z;{#Ew$GVj#Q&z5|($%2^Ma%IV05Y8nXxnd$GuM!xT-a!|DE-Q7<#e8GA${)>mwWNs zTJ9c8=d{ifj9(bPXx%jh!#|2|O0ae^t15jyzN22T>R7vLxEKt>dwlZ6E`{4Q7)emA9#B4jBd$ig62A(O~ zqzT)>SbHzpGW#W?EQF6d~T~EzO|JW(8 zKG1S9tFkn6``wtM^*!CSV#0^?jC4gn|9ZPG->FqT?umAKim`pcmdK}Bih1~CJ>}&+ z`wpA52(mXVb}N}8>jj|B_~+kzq*JV?Ti&~~W{WQ=E@Ne8#&02V^p(^`)xyk#)$uYM z&Y(2eX2%o z(qGHoB`8P5Q0Di37?4v~r#jNGWGE0X+!cEDw7c$!V;#bweHs=aKTV3F0~Wumu#8O& z{n*xSu9T+;y8a0QcG9gHWL zAE!>2`yU_ub#OJQj@yWS7NLmP=!a)b<;+`-vn!ma+Yl_1b?3~gl00kq|Fb7#_A#53 Ye;w=D=3r2tD*abTB0Aeu+H4d58=VKXmjD0& literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_circle.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4666dd966f3013148016799125c997c273bd8f GIT binary patch literal 6656 zcma($cRbYp|8Iv}WY0tn+2c@T@4aR3ad)_Icih=qQrVmA?5%{dLMlm;9TB0(h!Tn7 z_g0_z?eYEnet*30?)7?(*K@yL&*$ARHq@ddXC(&!fKo?W{Sx>car{6b;HSRbZXN)T zvY^eZ2v!FAvIwk~s527lf)Wkz!hvuAkXH)8IU_t!1egoT4UJLY+HCLQf}xQLT$Yjs zVg@)hlsj5G$OmN_WN3y6@<7NSxs(*iR~Gzzybb4q z{X`*nC~#RB7{k=CJ}8)^sHCVEmm)b#-UsO_dr4jM4`Ohoz~xRL;AG)&e}8{b|MQ|) zA2+zTjEoFiOad+;Ap&BE-~%xP=Kv85p8J@^FCOYBJi-T!BcQPu*fCFM7pyNqfr|@- z!~T@a3-=du4E_)8K|8<$oN;h*Q8D;Gk#X)=0v7L%{Vybcfqx@J1)%@d;a|rbLw-Xi zpk4n9`Z44;bkNoY2LHPjUS9uF1W(ZL0}b(qQU4{-pL*lX0&yt#B@`a(>w`dP_@OWa z?w_^*Pm@*iK{*pp>focmB_SqpK}1|aL`=d=LPAzdOjb-@Q>kEE4S+_&f4> zS#dF0$zx=Y>Thf?Jdn-==l>7>Uj~;w#{MM~7@Gg9M1Rw$VLh=vpm3lL=YJmmH%LcK z&DaO)iuMFy_)A)=#@t?TIev>su2cSHy)X`oj3?7Uz1uk(3>HmOQ z|2OE*(@nwT0+0B`^4PbsI$q9hC`&Yw;QlwazXAFvjN5OJV;_0?9tXKO1`T>u;-?5d ziLCyHfl7*r!T)iR_3yCb#DU5G3@2G_G@gL<3H-VBE1OJF-oIAAmY(RJX#|7)3?^A; z#IXblTsR*r(iee3{uBaa_X~>0x)S`IeNZZHU>qrMskpkLL0JP~#>W{2lYmKpxi9%| z5`T9T$nKxM{CB{>{}2s+oY{ZMCJ+BjdikFS|0o3@-LE~c#DKL5{#UUA7k`yI6b1|= zAF!B3wy`4tfG7eDhQx27008_cz9~a`swy;nN|#NtosF+WQPEBGKO`>|RnfJAak?gt zYd9W4$Ifn^=Cr?3uc|Uu=6G$NVwIIZ6;%u^#xEC(@-zer@Tc5eUw7-0JHP%SN;1dX zCn$~C=UWuh$$fi@I~tY)LR7-9KJ=WiB=}0OQ4POTdW zyo-MK?mm9Xw=9Tbn_>?KhmiY7g0UTH2#m>pGE(M2gyIH5% zX>{n)CYX;P`R8eU?W_4v1~&@QQ_9?TkFbtAV=LNaZN1ck@R(0;s72(AMNdDOyyKj1 z)V+Jk@|(@!G;Mt7b%$#7M>QO#=drJW-g?hFDS}d!x5%N;6w=02AVBWQE(_sJRA|-6 z-Bp>2B%0auhPKEb#4O1H%b%%@2 z7Ld1L9~i=5-g1aB_w|>ZC3!j>sSL2I&@gDw7SNw2q0?4oVkEN8;HSPymdMKR93Dk? zjrMFV1x%eGayiNga+2s|5loRiownyHk1%h3#-op4E)C=>RgavciL5sp$uI44JTkHG zTCHB)o(+DXuv`!<+G;gLPP9iA-{4qO#;qKYL<{TggVM|+NT6Hd5RyF>B1lL)K%}S{ z0dV{$I7f=87;5rmM{kTeufcI%wuqsOr)kUI2AM%lQP~{9#H2g1dLb#NKJ*c77X8<9KwRu=J zoU{v}^FJc4?Jw0#dbL3~auDY;eLBb_C@NsalCX40_A2@uW(E4fbGI|-vp7-5nN2M2 zXmjo32%UzqID7V69_hIgmVdhr9#o;>oq_U@*t3x#>nqgVU zcH<0$ik*g81os1HMgl5dknhHFQK!N@xQiAlFNIy2vsxDvEe1Z`Ps{Im`Es*CQEW89 zp!)_#+2kdA$0c$=pH~9WqWJA}zAU3-_^XXC`HbIf2WHL98M?cBX7n0Z+IHN{<|;oy z=V!HphcoU>7zjvHB^iwV7}}1xu05CAv%uB1?mJmd*#V27(Z5-56gv3QJ?2&l6!gX@ z2R`IS1{CIf?jn5rWaHO+sw=$$I4>-krfD$<5L@73RCSUq6s#&)!bQ&*owP(^TJ@308x!dA~QXcuk3Y zXZt{zABS=u27WBuG$qW_)JJOeQ@Rl6QN^>H>}=4cEZ%n4dHJaCjCXW{fK>e=v-~Cl z$xJA`9TkjIBS~qRJej^Qb@K%_={jd!f96Jyf#p8Ht8nY}cWa!s$LAx*xbX1lDVjFz zV2Fi?Z}_hGkhj&*tzo_gWi2ZleGl6EpL)OArR@s3X}f*kq2K*6|KVE0eL&cTZtPSk zyd<2heTzc{7#X!|ZNG4q8LiXZzc@0QBq#8A=|dZDU10r_Qa(aj!Aq0ao1=Mr;g^(D z2$C1hKP=<9;H^CV4S(rK+HbpM{z-hTBo)coMNM;dS(x9-)AbpS+Kj?l18UIw1uMy& zb&_Wi295RsY4!=v3s3x9UKFOK^2r7yJdczjDeYX@-xnJ8tNLhO+F`VGY=7Su6{AMa6lO=dhtAc`6_6m`Ra;bJ9rfeLmwtBn4^z;K_OE4Z6G_> z1xm#`cck}x#sWU6uK*_Q2ec?~-gWJVv+JD{T3Q{~=M%(MdGD)-lFbx|IFR?ZhjeLE z&V9T2UV6QYNM1&dnO5iXkan&_!1zTIorportg?0@dAXtan!FQ*y+|&+=_w$yyxmhO zqgF=oc!rHiv=joX*?d8mDAQ>b`H*(-fyw{kgpb|+%Z?={U zAY+}N9nq_@y-N-((A!2Y`+7a19wmDEnmcGDwlj(qLiLe8pXw38sqL$$3gSpfEy+Ru zfaS^CBC_o<0z{H7ea9%Ic! z1Q?O1vL@d%K1N5b5{p*hUp9tfnt022zO-XIT)RCWNW7AC5o!!Hu!%uE0_t?8z^Ubd`E?a!~HqiH%L z#}v2Spp@LFN@jFZE8X%PHnx2q*2F37EmGUyOa$R2CQMI85=ltycWd;rD!WZHc?x6{ zzx|M5M~}vgg;k1Y11r-nGzG$>QB+A=F1Q7IwH790fHvh3l8Y}f?#jM7(e=jUA9FWt zn%mZ^D#9`rJ~k4&bExfxB1X;tPT#frlKSc;;|S%iY8w)3rakZf;5`^$UW>M5Cgz8i zY}OJQLP~gJnMPQ*nOV=Ctw?)K9>I8o>%1GgIhr+9-~oZfHig662V;8FrsC^*070RQ zYY$pES9-+TwxE~n)ayvcgdiQJDif+FmD8^hy{wZv|Cy62qB+?iU*zrvH;QgYKhZLEBTKkQ&im9U?7*(>ehMQ|3|1z~^d`A_EZ8VXduA7eh5kl#E!3tu^IcuF6>9IHd@7z5-GA>>w&CVU`EfLhbZef)epB%y^Ku&y za#*FRY}L$LRa^AlqV$z6(U+C}vvPtNnZ{{1?W%cU7t)Jtgx}E3=QEH~@Bk@H?*>_7 zl?A<6rabbtrX>BD6N zh_d%f>(y%KNaJ+l7^`L{;>OoJ;!O{zo_%^uF@_KZbbnrluK1^>4sY$EDA2Q1(u9_?>l&B7U{+oq5-Sfz4$G)WgM}l z_l}|aDt^rK$>2RPAeNj5K%p3vvvL_vSDUIhusR1aFoaIE_wo5`Af7&^Aef#|a?Qg` zE<++{OImHQ2c~|LUA>N8(R_xZ2j&*}{qfhe!3cbp8Mc41YMH&(lZBj|KO)s7*2Z27 zOnbqn6cBY)V=qg}E8W5}px3ql2Gyu+} zOpLyFij|G3MhfT{DvrAIxnM06Eyw~G7@r{?uAX&r2GSW!OdcgY8!BXRmH-)jCO25@&QWMj`ur#W^$Et4}L~Bw685C+ldfi4BivEwO&1 z$y$+cm+}Hs!;a0hq??}yo?C_#zdkV8&f@gQC{`7;wbzq_6d{DSdrfXEf2eZg0cgid z%&osgYtc0bss&CG3x{J?=(Pl=g-az*oa%TXgkzIVwEOg_cfrMH?eGUzMm{igF%hE` za51b)d0-&oGW=8lZR}&Ylpz0R7q?X|n6yH*7WQjhTMj!rhj-UhRY zAB2nB=~Hrc#&m5H1_ZqZmRVq8yc({gL?Uf%=e*^jJu9OWC>?j>>Z;&&duB~cDM z{USd@-jSQ@^cYu>!A^IN%_PmIHsg{gxgJ~RP$TsR?y@*ID4vaO(VDzx=sUoImgCaFH6i+(wOjUkcng`jxOg6 z$=TK^!MhoqyhTQiQWxUQ?26~uFbh`~n|o8#Tu`Kx6ny@(i@wki4~P}hm21^Q8eW;n z8sY)`6~)T!Ik+a56OA1&ARd`TX8qb`S#`BB5%;^iHMv`H4ypMmOo@wqrE$#XN>T#K zcaGoYQStYWh?sV)vPScg@1~K7InmVA7w0`YE#BH5+L(cTi{Omx&5!-$>~lUs#4bKA3OY}< zllD2uV7SlEH8yS~Cqtx(zT<8bT(tO3{>_u7V{Xb-e99GC&jwBaSP}mL{DcVkV+}K^ z>LI;4%esT0va)jt3z*Hp=?%iv+Vt4wWmT)3kJZ)1{xki&3DuJ>w}NQ9#j?9z0#2hR z91JtioYFsXo6yA6PKT;$3V4~--0X3sM0V+HdJ$-t{^ zk`eAYm!?v2u8h{fkDVsI2%7JB^Ov(<8#5RQGf%4%)^cu(PTx=DxY$_T81)A1ERZN; zHDM?BWK^k&rsvdI;jdQ$@%eDYHBX;KuE@TQ))(M1Dq=Wkh1H#c=fa9bOuEaCgnv*@ z+@&u`h)GXR30sQvtYOd^YGmrF$*GsKWwhpSasI3!@P4p|s^IXS-nh_0pY|zS^Jva# zewlt`>`vnMyQ%%^$C}QpIz*me?n`!_NmS@*Op*$5$|&rM+eK1vpRG*otYZ(pa>i!g zodg09)_TB3VrElu!nGug!~2{OA@6W-Q&qDf{J4AIRa&?`<=%Dhs4d^IXhnf z>{^-O{JToRdCv{R^|OmTF8Dg~h3H3|%1!t<%?UySgVnF8IT!n$k>D?gGg>%t%4PiY z$@cvB8?<k4&@FKO(Id|(XZm!OCt#n16Pg73 zbMR5BA#**J_jC2iL)Cs8WeRZeVk{_VMpaANRGJ+`x6=EtKiSzXgzM`hksUE9<5*7@ zbW54x)9l6LflGcBzlZPjjpwJ>Ux33A|JmMZD}`a`mMKL3c$PC}qg-bJ@~k5@!)$(z zv{M%RHOTQT++tI=(YCtJG2zsD>d>&enKLWy>ri><758b$`?*aksJ&p%#;N}t7yTd8 bq(kC2_S;JSH-euX|8b+EVW?iO>J;@q=o5&7 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_ellipse.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..c1950355e0e2aa92e8003dbfac337250932e169b GIT binary patch literal 6310 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 literal 0 HcmV?d00001 diff --git a/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_square.png b/tagstudio/tests/fixtures/search_library/inherit colors shapes/yellow_square.png new file mode 100644 index 0000000000000000000000000000000000000000..3080357d8d5670cba72ad8098f92ef1687c70143 GIT binary patch literal 3878 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 IVD1<5Uv^