todoman icon indicating copy to clipboard operation
todoman copied to clipboard

General improvement to ZSH completion + bug fix in it

Open doronbehar opened this issue 5 years ago • 16 comments

EDIT: fixes #356

doronbehar avatar May 17 '19 20:05 doronbehar

Hey @doronbehar , some things i'd add:

at the point where you match for ^\s*path\s*=\s*: maybe use ${BASH_REMATCH[1]} later and use a capture group inside your [[ ... ]] expression to retrieve the path information - that way you'd not need to trim spaces in the end.

if some file named displayname exists inside the calendar's directory you could use the contents of that file as the resulting string.

Thanks for the changes :)

0x17de avatar May 18 '19 22:05 0x17de

use a capture group inside your [[ ... ]] expression to retrieve the path information ...

I'm not sure what do you mean by 'capture group'. Never the less, thanks for pointing out the parameter $BASH_REMATCH! I've searched for that in the docs and so I've come up with a solution that uses features mentioned there as well. See last commit.

if some file named displayname exists inside the calendar's directory you could use the contents of that file as the resulting string.

I think this should be consulted with @WhyNotHugo because I'm not totally sure as for the behaviour of todoman in this regard. When I run e.g. todo new --list <arg>, does todoman expects the argument <arg> to be the list's 'displayname' or the list's path (relative to the directory of the whole calendars of course)?

doronbehar avatar May 19 '19 05:05 doronbehar

todo new --list XXX expects the displayname if one exists (since that's how the list will be referred to everywhere).

Thanks for your time on this, I'm not very fluent in zsh-completion scripts, but changes look good so far. Do you want to address the above comments in this PR too?

WhyNotHugo avatar May 20 '19 08:05 WhyNotHugo

Thanks for commenting on that @WhyNotHugo although TBH I could have tested that myself :smile_cat:. I've tested your statement and fortunately it seems todoman does accept both arguments to --list i.e the name of the calendar as written in displayname and the name of it according to it's actual relative path on the file system.

The question is then, whether we should actually support displaying the displayname of it? I won't object that but it's kind of a hassle for me... I mean I have to read and evaluate the glob that may appear in the path given in the config and then I'll have to read the content of each of those displayname files within those directories and then group all of those options considering that not necessarily all calendars have a displayname file so these should be given as options without trying to read their displayname file...

The way things work now is with a very simple file completion function that uses the parent directory of all calendars as a prefix. I like this simplicity so I would rather not change it.

doronbehar avatar May 20 '19 10:05 doronbehar

Generally, displayname is what we expect people to interact with. In my case, my lists have directory names which are incomprehensible (while they have human-friendly displaynames):

502708f4-4b94-4963-b042-f7340c829bdf/
9bcef3fa-504d-4c6f-b320-fd24257de5a7/
9f57caac-df79-4488-8019-51b21648c4a8/
d6aa4f1e-bdf6-4b6b-999d-b89afd62c994/

This is because I set up vdirsyncer to pull all remote calendars, so it just uses the remote ID. I'd expect that setup to be relatively common.

WhyNotHugo avatar May 22 '19 07:05 WhyNotHugo

Oh right then, that's a definitely good reason to implement this suggestion. I've implemented that and according to my initial testings it works well. Pushing the current version.

I'm not sure however, how should the completion handle calendar directories it finds that don't have a displayname file at all. Right now, it suggests the full paths of these. This seems reasonable in case multiple path = directives may appear and not necessarily all of them have a * which is expanded by the completion.

I hope this is not to hard to understand, I'm trying to support the use case of multiple path = directives which not all of them nescessarily have a displayname file in them - whether there's a * at the end of them or not. Is this too much? The question is: How does todoman behave when it encounters multiple path = directives with or without * in them?

doronbehar avatar May 22 '19 11:05 doronbehar

Hey @doronbehar , with capture group i meant the ( ) symbols inside the regex - ${BASH_REMATCH[1]} would point to the first ( ) surrounded part inside regex. E.g. ^\s*([^ ]+)\s*=\s*(.*)$ here ${BASH_REMATCH[2]} is equal to the matched data after the equals sign. To have some non capturing group you usually do something like (?: standard regex inbetween and a closing ). I would personally expect the last part of the path (basename) to be shown if no displayname is present. Thanks for including my suggestions :)

0x17de avatar May 23 '19 21:05 0x17de

@0x17de I understood what you meant :) But according to the manual (and I tested that inside and outside the completion function), the variable BASH_REMATCH is set only if the option BASH_REMATCH is set. See here: http://zsh.sourceforge.net/Doc/Release/Conditional-Expressions.html#Conditional-Expressions

It would have been possible to set it temporarily and then unset back according to this option's state before but completion function started, similarly to what's done often with IFS. But it seems like a big hassle in my view while using $MEND achieves the same goal, as suggested right before the manual mentions BASH_REMATCH.

As for suggesting the basename in case of a lacking displayname file, I suppose you are right but I'd like @WhyNotHugo to confirm that before I'll go ahead and implement this.

Above all, I'm not sure that todoman even supports more than a single path = directives in the config, with / without * at the end of each. I hope he'll be able to enlighten us as for choosing the best way to complete these.

doronbehar avatar May 26 '19 07:05 doronbehar

The question is: How does todoman behave when it encounters multiple path = directives with or without * in them?

I had to check because I wasn't sure. More than one path directive is invalid, and will be rejected by todoman. So completion it's okay for completion to have "undefined behaviour" for that scenario.

WhyNotHugo avatar May 27 '19 09:05 WhyNotHugo

As for suggesting the basename in case of a lacking displayname file, I suppose you are right but I'd like @WhyNotHugo to confirm that before I'll go ahead and implement this.

Yes, that's what todoman does. :)

WhyNotHugo avatar May 27 '19 09:05 WhyNotHugo

Oh right then, to me this is ready.

doronbehar avatar May 27 '19 13:05 doronbehar

Out of curiosity: would helper methods inside todoman be of any use, or is that too slow for completion scripts?

I'm thinking, of, for example, a command that prints all configuration and list settings in a shell-friendly manner.

WhyNotHugo avatar May 27 '19 13:05 WhyNotHugo

That's an excellent suggestion! As a somewhat experienced ZSH completions writer, I have encountered completion functions which needed to be aware of the command's configuration they are completing and thus they would either need to parse the configuration file themselves or ask the program for these specific values.

Here are a few examples:

  • Git: Very friendly for shell completion functions with it's git config command which prints values as parsed by Git itself.
  • Taskwarrior: Has sub-commands prefixed with _ and used by shell completion functions. They complete values such as tasks' attributes and tasks' projects which are changed dynamically through out the use of the program.
  • Luarocks: Has the sub command config which it's completion function uses. I happen to be the writer of it.

Todoman could certainly use such a helper command. As for it perhaps being slow, that doesn't have to be an issue if the user enables completion cache. We can base the cache validation check based on the modification date of the config file and if that's not newer then the cache, we'll check the modification date of the directory todoman reported back when we first created the cache. I've implemented a similar mechanism with Luarocks' completion.

doronbehar avatar May 27 '19 13:05 doronbehar

I can implement a config command. Do you think something like this is useful? Or does it end up slowing stuff? I'll fully trust your input on whether this is worthwhile or not:

$ todo config
main.path="/home/hugo/.local/share/calendars/*"
main.time_format=""
main.default_list="personal"
main.humanize="True"
main.startable="True"
main.color="auto"
main.date_format="%x"
main.dt_separator=" "
main.default_due="24"
main.cache_path="/home/hugo/.cache/todoman/cache.sqlite3"
main.default_command="list"
main.default_priority="None"
list="Holidays: Netherlands"
list="study"
list="work"
list="personal"
list="[email protected]"

Note: this took like 5 minutes, so feel free to say if it's useless. Also, format is aimed at being as shell-friendly as possible, so let me know if some other format is actually better.

WhyNotHugo avatar May 27 '19 15:05 WhyNotHugo

As I said before, if a user has enabled completion cache, the completion function will run the todoman command only once to get the values it needs and then it'll count on a heuristic cache validation test to know if it needs an update.

Never the less, both for the sake of it being more comfortable for me and for the quickness of it for users without completion cache enabled, perhaps an option to query a specific variable only will be better. I'd print only the requested variable's value in that case.

Note that currently the completion parses dt_separator and date|time_formats as well so these will be more easily retrieved as well. They are used in todo new --due= for example. As an example for what I would expect from todo config's usage, I'd like to run: todo config main.dt_separator and todo config main.date_format and get those values.

As for the lists, I'd say that supplying main.path could be enough since the whole logic around it is already implemented but since you said this wasn't too hard, It would have been a little more comfortable to have the lists show up without the list= prefix and only when running todo config lists.

There shouldn't be a need to see all configuration variables i.e when todo config runs without an additional argument but that won't hurt of course.

doronbehar avatar May 27 '19 16:05 doronbehar

Sorry, it's been a while, but I don't think there's anything blocking this from being merged, right?

WhyNotHugo avatar Mar 07 '23 14:03 WhyNotHugo