Skip to content
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

General improvement to ZSH completion + bug fix in it #357

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

doronbehar
Copy link
Contributor

@doronbehar doronbehar commented May 17, 2019

EDIT: fixes #356

Use _files to complete the diretories in the path of tasks according to
'path =' in configuration file. Also, parse configuration file much more
effectively.
Don't use any external tools other then todo command itself.
@doronbehar doronbehar changed the title Fixes #356 General improvement to ZSH completion + bug fix in it May 17, 2019
@0x17de
Copy link

0x17de commented May 18, 2019

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 :)

@doronbehar
Copy link
Contributor Author

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)?

@WhyNotHugo
Copy link
Member

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?

@doronbehar
Copy link
Contributor Author

Thanks for commenting on that @WhyNotHugo although TBH I could have tested that myself 😸. 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.

@WhyNotHugo
Copy link
Member

WhyNotHugo commented May 22, 2019

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.

@doronbehar
Copy link
Contributor Author

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?

Don't stop reading configuration file when a `path = ` is encountered.
Build an array instead of all values of `path = ` in configuration file.
Use every element in that array and expand any `*` in it and don't rely
on the existence of a `displayname` file in the expanded directories.
In case a directory without a `displayname` file in it is encountered,
we revert to suggest the name of the directory itself.
@0x17de
Copy link

0x17de commented May 23, 2019

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 :)

@doronbehar
Copy link
Contributor Author

@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.

@WhyNotHugo
Copy link
Member

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
Copy link
Member

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. :)

Look for the first `path = ` and then break. Expand it's value
accordingly.
@doronbehar
Copy link
Contributor Author

Oh right then, to me this is ready.

@WhyNotHugo
Copy link
Member

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.

@doronbehar
Copy link
Contributor Author

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.

@WhyNotHugo
Copy link
Member

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="hugo@3dhubs.com"

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.

@doronbehar
Copy link
Contributor Author

doronbehar commented May 27, 2019

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.

Base automatically changed from master to main March 9, 2021 18:59
@WhyNotHugo
Copy link
Member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

regular expression inside zsh-completion script needs adjustments
3 participants