Well… I don't quite love the proposed query API, but well, I don't know. But it's not too crazy -- well, not more than a DB API would be crazy at least.
But maybe you could show real use cases of why this kind of API is good and fits everyone?
Below is the python code of that I can improve with the new API. As I mentioned, the initial code causes a half-second UI lag which is unbearable. And my session doesn't even have too much tags, although I use ProjectManager to load tags for the project so it's just not open files (this is when I work on Geany, not the Linux kernel). It was under 10000 tags when I profiled the python code.
Let me describe my use case and what I found when I searched for an existing good fit. - My use case is: I'm developing a [quickswitch](https://github.com/kugel-/peasy/blob/master/plugins/quickswitch.py) plugin (inside Peasy). The plugin adds a dialog and a keybinding to allow to quickly type the prefix of a tag name to jump to its definition or location. If the prefix is ambigious, it gives a list of candidates so I can chose one. So I press Alt+3, type tm_q, then it opens a list of tm_query_* functions to jump to. If I type tm_query_ex, then it immediately jumps to the definition of tm_query_exec. - I found `tm_workspace_find()` which does exact match (I need prefix matching). `tm_workspace_find()` is tied to the use case of finding the destination of go-to-definition/declaraiton - I found `tm_workspace_find_prefix()` which dedups. I don't want deduplication. `tm_workspace_find_prefix()` is tied to the use case of showing candidates in the autocomplete list - Both have a bug that "lang == -1" doesn't actually work (despite their doc comments) because `tm_tag_langs_compatible()` doesn't actually look for -1. I cannot specifiy a lang in the plugin. - Both unconditionally search in the global tags as well which is isn't needed in my case so just a waste of resources.
So I thought it would be more useful to implement a generic, query interface that can be used by Geany itself and plugins, instead of adding one more special-purpose `tm_workspace_find_prefix_no_dedup_no_global` function. One could also add tons of parameters to `tm_workspace_find()` to make it fit, but I really liked the idea of having a dedicated C file with a generic query API more. I always care about extensibility if stuff is in the plugin API. The query API can be easily extended with more filters or other stuff without breaking existing users, which is not possible with a single, one-size-fits-all function (new stuff would require new argments, therefore an API break).
The idea is also to use query API inside geany so that `tm_workspace_find*` can be removed or refactored. The API is generic enough that `tm_workspace_find`, `tm_workspace_find_prefix` and `tm_workspace_find_scope_members` can be replaced or implemented with the query interface. Yes, it kind of resembles a DB query. This is quite on purpose because that makes it extensible. Plus, we could probably even replace tagmanager with sqlite and without having to change this interface :-)
``` def search_tags2(self, prefix): print("search_tags2") ws = self.geany_plugin.geany_data.app.tm_workspace q = Geany.tm_query_create(ws, Geany.TMQuerySource.SESSION_TAGS); q.add_name(prefix, len(prefix)) return q.exec(None, None)
def search_tags(self, prefix): if (hasattr(Geany, "tm_query_create")): return self.search_tags2(prefix) ret = [] # This is super slow with lots of tags. pygobject seems to call getattr() # for all elements on the first use, regardless of how it used array = self.geany_plugin.geany_data.app.tm_workspace.tags_array n = tag_bisect_left(array, prefix) for tag in array[n:]: if (tag.name.startswith(prefix)): ret.append(tag) else: break return ret ```