-
-
Notifications
You must be signed in to change notification settings - Fork 394
feat: add autocomplete for search engine #586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic work! Seems to work great in my testing, I've just got a few changes/suggestions in the review.
One thing I didn't mention is the suggestion to use tag aliases to match with the main tag name, or even subtags that match with parent tags in the autocompletion, due to the current lack of these implementations on main
. I would imagine this working on a priority system where actual tag names are prioritized first in the completion list, then the list of alias matches, then the list of subtag matches. I believe this is how the search results are ordered in any tag search panel, but could be mistaken. This is something we can explore later once those aspects of tags are implemented, though.
tagstudio/src/qt/ts_qt.py
Outdated
@@ -92,6 +93,8 @@ | |||
from src.qt.widgets.progress import ProgressWidget | |||
from src.qt.widgets.thumb_renderer import ThumbRenderer | |||
|
|||
from ..core.media_types import MediaCategories |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion to make this an absolute import to match the other imports:
from src.core.media_types import MediaCategories
tagstudio/src/qt/ts_qt.py
Outdated
elif query_type == "tag_id": | ||
completion_list = list(map(lambda x: "tag_id:" + str(x.id), self.lib.tags)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tag IDs are intended for internal/backend usage only, so there's no need to include them in the user-facing autocomplete list
tagstudio/src/qt/ts_qt.py
Outdated
elif query_type == "mediatype": | ||
completion_list = list( | ||
map(lambda x: 'mediatype:"' + x.name + '"', MediaCategories.ALL_CATEGORIES) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion to allow for mediatype names typed without quotes to still be recognized by the autocomplete list. Currently, typing mediatype:im
will not suggest mediatype:"image"
due to the lack of quotations. This would save the user the step of needing to type in a quote character before every mediatype.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added this, but the reason I didn't add it originally is because when you type mediatype:
and scroll through the completions, you will get the section that isn't quoted and then the section that is quoted, just due to how the QCompleter works. Niche and, now that I think about it, probably not an issue, but a little quirky.
Actually now that I'm trying it, it is even less of an issue because you first have to type mediatype:
(with a space) for it to fill in the completion list with all of the mediatypes, and then remove the space and scroll through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So is there no (straightforward) way to just have the suggestions with quotations show up using QCompleter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand it, no. If you look at QCompleter.setFilterMode(), it uses Qt::MatchFlags to define how it decides what items to show from its completion list, but the description of setFilterMode() tells you that only MatchStartsWith
, MatchContains
, and MatchEndsWith
are implemented. Using anything else just throws an error.
Because of that, the unquoted and quoted mediatypes will never show up at the same time, because the quoted ones technically start with mediatype:"
and the unquoted ones start with mediatype:
. My hack around that was to just always have them quoted, but that is annoying and, I'm now realizing, will not work for single quotes unless we explicitly add it.
Just as a note: we can't use MatchContains, because, for the same reason as above, the completion list needs to have strings that start with the type of query (i.e. we can't just have a list that contains photoshop
, plaintext
, etc. They need to be mediatype:photoshop
, mediatype:plaintext
, or mediatype:"photoshop"
, mediatype:"plaintext"
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dang, sounds like it would involve quite a bit of custom work in order to do this. Thanks for looking into this, perhaps it's something we can tackle in the future, but for now I'm content settling for Qt's limitations here if you are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, as it stands it is pretty far from what I was envisioning, but still useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like we're on the same page, works enough for this PR then 👍
if query_type == "tag": | ||
completion_list = list(map(lambda x: "tag:" + x.name, self.lib.tags)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using the tag's "display name" here might be better, as that would reduce confusion between identical tag names. It would also be nice if the tag name text was colored in the dropdown, but speaking from personal experience I don't know of a way to do that without creating a completely custom widget from scratch, so I don't expect that from you here.
For the future, I'm picturing the search bar as something a bit more abstracted from the internal search query. For tags, this could mean that the user would see a tag label widget (alongside other query text) in the search bar while internally the query can refer to it by the tag's ID, eliminating any confusion between tags with the same name.
Example:
This is a bigger undertaking than the scope of this PR though, and having the functionality here is already a great help over having no auto-completion at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
potentially dumb question: what is a tag's display name? its' shorthand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just realized that display names didn't make the jump from JSON... If #534 doesn't implement them then they'll need to be implemented in another new PR.
Essentially, they're a version of a Tag's named combined with their first parent tag in parenthesis (with preference to that parent tag's shorthand) to aide in telling tags with the same name apart. In 9.4 they were generated and grabbed from a method rather than being stored directly, which likely contributed to them going unnoticed during the migration so far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tomorrow I'll look into getting the display names add in on #534, no point in having another PR just for that.
I was trying this out yesterday and this will be an great addition. A couple of thoughts/suggestions, don't feel obligated to implement or even listen to, just food for thought:
Anyways, great feature. |
I was originally going to implement it as you talk about in your second point, but I talked to Cyan and he thought it'd be better if it just showed all the options all the time. Maybe we could make that a setting later on. Your third point is something I noticed too. I originally wanted the autocomplete to work so you could type something like "path:folder*" and it autocomplete everything in from that, but the way QCompleter works, it will not show anything if you have a "*" in the text box because it doesn't show up anywhere in the actual completions. I'm gonna have to mess with it a little more until I like it. I will make it show the search types on an empty search bar though, because that also seems like a good solution to your first point. |
Can confirm, although I was really intending this for mediatypes and didn't notice that the behavior also applied to filetypes (my test library contains most of these filetypes). I can see arguments for both cases though - to de-clutter searches that don't need superfluous media type results, but also to keep all potential types in order to inform the user of what's possible. Ideally this could be behind a toggle, but that would rely on settings menu (which I think is open for development again now?) |
After I've given it another thought I will keep the path search as it is. It does, effectively, stand in as a filename search for the time being (it does let you search directories, but not well), but making it any more useful would require moving away from the current implementation and making a custom widget, which we will have to do in the future anyway for it to not be entirely text based. |
The behavior of the full array of media type suggestions only showing up after backspacing from the |
unless you know of a better way to do it, it will be a little hacky - QCompleter doesn't give me access to the previous key the user pressed, so I will have to either:
just to be clear, im not opposed to hacky solutions, it just wouldnt be elegant (and i can already think of some weird edge cases) |
Ahh if it's QCompleter shenanigans holding things back then I'm good pulling this as it is. Definitely room in the future to create a more expansive and controllable system, but for this PR I think it's a great first step in that direction. Thanks again for your work on this! |
currently, the autocomplete will automatically show up when the user types something that can be autocompleted (right now, "filetype:", "mediatype:", "tag:", "tag_id:", and "path:").
filetype
andmediatype
: autocompletes with all filetypes/mediatypes currently registered in tagstudio, regardless of whether the current library contains any files of a type.tag
: autocompletes with all tag names, case-insensitivetag_id
: autocompletes with ids of all tagspath
: autocompletes with all paths currently stored in the library