Closed eugnma closed 4 years ago
It looks feasible. But it is good to learn more about details and use cases.
As far as I understand, if there is a tag in a special format, before printing out the line, ttdl takes value, calls a program from tag name, and replace tag:value
with output. Correct?
Questions:
ttdl-tagpart1-tagpart2
looks like too specific for ttdl. Can an arbitrary binary be called? E.g, git:branch
as a tag.$git:branch
or $git:$branch
(I am not sure if dollar sign is OK to use in tags - it is just an example). Maybe, an extra command line option to turn the feature on would be good to add.Good to hear that it's feasible to implement it, the behavior I though was like below:
Assume the input and output for external commands is JSON format.
For example, the item This is an example tag1:value tag2p1/tag2p2:value
, the steps for calling external commands as below:
{"description": "This is an example", "specialTags":[{"tag1": "value"}]}
to ttdl-tag1
, then it returns {"description": "This is an example", "specialTags":[{"tag1": "value"}]}
;{"description": "This is an example", "specialTags":[{"tag1": "value"}, {"tag2p1/tag2p2": "value"}]}
to ttdl-tag1p1-tag2p2
, then it returns {"description": "This is an example", "specialTags":[{"tag1": "value"}, {"tag2p1/tag2p2": "value"}]}
.Please be noted that:
The are some many calendars are using now, sometimes we may use it as a date, it may be added like This is an example due/calendar1:2020-02-02 rec/calendar1:1m
, it the feature is implemented, then we can create two plugins ttdl-due-calendar1
and ttdl-due-calendar1
to handle these items.
!
./
to -
then prepend ttdl-
. According the todo.txt standard, it only limit the char :
.Thanks! It is clearer now. Yes, if ttdl-
prefix is added always, it cannot be an arbitrary binary. Though, some stuff needs to be explained a bit more.
ttdl list
? or ttdl list <special-option>
?ttdl
process all tags, or only those which have /
in their names? The latter case may make sense if we transform the text when running simple list
commandCorrect me, if I am wrong in my example (I assume that every "plugin" returns its entire argument with one or more fields changed):
todo.txt
: "Fix bug due:2019-10-10 /due:2019-11-11 /overdue:2019-11-18"/
is /due:2019-11
, so the first "plugin" is ttdl-due
and it gets the initial argument with description and the first tag: {"description": "Fix bug due:2019-10-10", "due": "2019-11-11"}
{"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11"}
ttdl-overdue
receives {"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11", "overdue": "2019-11-18"}
(or `{"description": "Fix bug due:2019-10-10", "due": "2019-11-11"}
?).{"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11", "overdue": "2019-Nov-18"}
ttdl
combines all tags from last returned JSON and a user sees on the screen: Fix bug due:2019-10-10 due:2019-Nov-11 overdue:2019-Nov-18
(please, note that all /
are removed as well).Thank you for your attention, I add some comments base on your comment, please correct me if I am wrong.
- When are external commands called? When running ttdl list? or ttdl list \<special-option>?
Both are OK for me.
- Should ttdl process all tags, or only those which have / in their names? The latter case may make sense if we transform the text when running simple list command
I think just process all tags start with !
can be used widely, which likes git style and vi style.
- What is "description" in your examples? The entire todo's text without tags or the text before the first tag?
From the todo.txt format standard, my understanding for the "description" is Review Tim's pull request
for the item x 2011-03-02 2011-03-01 Review Tim's pull request +TodoTxtTouch @github
, please correct me if I am wrong.
- From your example I understand that every "plugin" gets its own tag and all previous ones. But due to input and output are the same in examples, it is not clear what a "plugin" receives: just list of all original tags+values, or the result of the previous call with added tag for the current "tag"?
Please check Your example.
- Original todo in todo.txt: "Fix bug due:2019-10-10 /due:2019-11-11 /overdue:2019-11-18"
I would suggest use Fix bug due:2019-10-10 !due:2019-11-11 !overdue:2019-11-18
.
- First tag with / is /due:2019-11, so the first "plugin" is ttdl-due and it gets the initial argument with description and the first tag: {"description": "Fix bug due:2019-10-10", "due": "2019-11-11"}
I would suggest save all special tags in speicalTags
as a special tag can be named description
, so it will be {"description": "Fix bug", "speicalTags":[{"due":"2019-10-10"},{"!due": "2019-11-11"}]}
.
- Let's assume it returns {"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11"}
I assume the ttdl-due
is for changing the due time, so it will return {"description": "Fix bug", "speicalTags":[{"due":"2019-11-11"}]}
or {"description": "Fix bug", "speicalTags":[{"due":"2019-11-11"},{"!due": "2019-11-11"}]}
if we want to keep the tag from the command ttdl list
.
- We take the result, add the tag for the second "plugin. So, the second "plugin" ttdl-overdue receives {"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11", "overdue": "2019-11-18"} (or
`{"description": "Fix bug due:2019-10-10", "due": "2019-11-11"}
?).
Let's asset it returns {"description": "Fix bug", "speicalTags":[{"due":"2019-11-11"},{"!due": "2019-11-11"}]}
from step 3, so the second plugin ttdl-overdue
will receive {"description": "Fix bug", "speicalTags":[{"due":"2019-11-11"},{"!due": "2019-11-11"},{"!overdue":"2019-11-18"}]}
.
- The seconds returns {"description": "Fix bug due:2019-10-10", "due": "2019-Nov-11", "overdue": "2019-Nov-18"}
I assume the ttdl-overdue
aslo is for changing the due time, so it will return {"description": "Fix bug", "speicalTags":[{"due":"2019-11-18"},{"!due": "2019-11-11"}]}
if we don't want to keep the tag from the command ttdl list
.
- Since no "plugin" failed, ttdl combines all tags from last returned JSON and a user sees on the screen: Fix bug due:2019-10-10 due:2019-Nov-11 overdue:2019-Nov-18 (please, note that all / are removed as well).
It shows Fix bug due:2019-11-18 !due:2019-11-11
if the final result is from step 5.
If any "plugin" failed, it shows original todo line and prints an error to stderr
I agree with you.
Good idea about !
- I like it.
From the todo.txt format standard, my understanding for the "description" is Review Tim's pull request for the item x 2011-03-02 2011-03-01 Review Tim's pull request +TodoTxtTouch @github, please correct me if I am wrong.
I agree with you. The question was more about a case when tags are in the middle. But we can think of this case as of rare one and just take everything until the first tag.
The last questions (I hope it is the last one :) ):
What if every "plugin" will receive all the tags? instead of every "plugin" gets all previous tags and its own one? So, we can do this: generate JSON once, then pass it to plugin one by one, and every time pass to the next "plugin" the result of previous one. What we get at the end we use to construct the line for displaying.
Let me summarize the algorithm(assuming we create JSON once in the beginning):
I total agree with you, hope the custom way I was thinking you would like it.
What if every "plugin" will receive all the tags? instead of every "plugin" gets all previous tags and its own one? So, we can do this: generate JSON once, then pass it to plugin one by one, and every time pass to the next "plugin" the result of previous one. What we get at the end we use to construct the line for displaying.
Generate JSON once is easier, but it's better to keep the original sequence.
Generate JSON once is easier, but it's better to keep the original sequence.
Since `"speicalTags"`` is an array, all tags would be in the original sequence. The only difference is that the every plugin gets all the tags.
At last, I would highlight that the external commands calling from ttdl
should base on the lasted JSON, so for the item Fix bug due:2019-10-10 !due:2019-11-11 !overdue:2019-11-18
:
{"description": "Fix bug", "speicalTags":[{"due":"2019-10-10"},{"!due": "2019-11-11"},{"!overdue":"2019-11-18"}]}
to ttdl-due
;ttdl-due
changes due date and removes the !overdue
tag;ttdl
get the final result {"description": "Fix bug", speicalTags":[{"due":"2019-11-11"}]}
and won't call ttdl-overdue
.Interesting feature. In this case we have to track already executed plugins (to avoid a forever loop if, e.g, a plugin returns the list shuffled or reversed) and check the result to skip removed tags.
Another thing came to my mind: a config file needs one more option. I think plugins can be either binaries or scripts. In case of scripts ttdl
cannot just execute them(at least on Windows), so config should provide a name and options for shell to run commands. If config does not contain it, the shell should default to cmd.exe /c
in Windows, and to sh -cu
in other OS.
Ok, let's do it :)
By the way, since !
is used to detect plugins, do we still need to use /
that should be replaced with -
? Maybe we can use -
, e.g !tagp1-tagp2:value
instead of !tagp1/tagp2:value
? So, we can just build a plugin name as ttdl-
+tagName. Or /
must be in tag name?
In this case, we don’t need it.
Sent from my iPhone
On 12 Jan 2020, at 12:22, Vladimir Markelov notifications@github.com wrote:
By the way, since ! is used to detect plugins, do we still need to use / that should be replaced with -? Maybe we can use -, e.g !tagp1-tagp2:value instead of !tagp1/tagp2:value? So, we can just build a plugin name as ttdl-+tagName. Or / must be in tag name?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
Do you build TTDL from sources? Or you wait for crate.io to be updated?
I added the feature and tested it little on Windows(a new section "Custom formatting" appears in the README). So, I am not sure if it does what it was intended to do. That was why I have not created a new release and not updated the crate.
If you build from sources, please try the new version and share our experience. If you want to use cargo
and an updated crate, I'll refresh the crates as soon as I test the app on Linux and build both Windows binary and deb-package.
Great work! I've just built form source, everything is fine except tags are not used for the final display, for example, assume there is an item This is a test !due:2020-02-02
and the ttdl-due
returns {"description": "This is a test", "specialTags": [{"due":"2020-02-02"}]
, I would like it displays:
# D P Created Finished Due Threshold Spent Subject
-----------------------------------------------------------------
1 2020-02-02 This is a test
-----------------------------------------------------------------
1 todos (of 1 total)
But it actually displayed:
# D P Created Finished Due Threshold Spent Subject
-----------------------------------------------------------------
1 This is a test due:2020-02-02
-----------------------------------------------------------------
1 todos (of 1 total)
I see. That is because I call custom formatting when description is going to be printed. It is possible to allows anyone to rewrite any tag/column(except ID
one - it does not make sense and it is dangerous). But with limitation: because column widths are calculated beforehand, the custom valued would be truncated to already calculated column width.
And it brings another question: since any column can be customized, does it mean that a plugin must get not only simple tags, but also "due", "created", "priority" and so on? In this case I had to add them to tag list manually because underlining library I use removes standard tags from both todo description and tag list.
It is possible to allows anyone to rewrite any tag/column(except ID one - it does not make sense and it is dangerous). But with limitation: because column widths are calculated beforehand, the custom valued would be truncated to already calculated column width.
Yes, ID
definitely cannot be changed. I think it's OK truncate the final result.
And it brings another question: since any column can be customized, does it mean that a plugin must get not only simple tags, but also "due", "created", "priority" and so on? In this case I had to add them to tag list manually because underlining library I use removes standard tags from both todo description and tag list.
According the todo.txt standard, my understanding is the special tags like due
, t
and rec
belong to special tags, and priority
should be a normal property since it is not a tag, please correct me if i am wrong.
BTW, I updated the previous comment related the output from ttdl-due
which is not correct, please check, thanks!
Thanks for an example. I have not implemented replacing anything except description yet. I'll fix it.
Yes, you are right: due
is a special tag, while priority
is not. I confused them because the library I use removes due
from tag list as it does for priority
. We can pass priority, creation & finished dates, and done mark as optional
array. In this case even done mark x
can be customized as, e.g, √
. So, I can generate optional items and pass them in the same JSON.
@eugnma
I've updated the code. Changes:
due
is correctly displayed in its column, and it is removed from description(as standard one)optional
array(the same structure as specialTags
has) to JSON that contains current done
, pri
, created
, and finished
values. They can be modified, so you can, e.g, change signs x
or priority levels A
..Z
to any characters, or format create/finish dates like 10 Jan
You can try the new version. Meantime I need to refactor the code a bit (no changes in algorithm) and update README to describe new JSON field and customizing gothchas
I have just tried with the latest version, seems like the description is missed, not sure I did something wrong.
!
:$ cat todo.txt
This is a test due:2020-01-02
$ ttdl
# D P Created Finished Due Threshold Spent Subject
-----------------------------------------------------------------
1 2020-01-02
-----------------------------------------------------------------
1 todos (of 1 total)
!
:
$ cat todo.txt
This is a test !due:2020-01-02
$ cat /usr/local/bin/ttdl-due
#!/usr/bin/env sh
echo '{"description":"This is a test","specialTags":[{"due":"2020-02-02"}]}' $ ttdl
1 todos (of 1 total)
I'm sorry. It looks like you tried refactored code. Thank you! I found the bug: TTDL read all dates from "created", and because it was missing in result JSON it defaulted to value from original TODO.
Fixed in the latest sources:
Cool, it likes a magic!
Thanks!
It seems it is time to update docs and package on crates.io :)
Can I confirm is the JSON passed via stdin
to external plugins? I cannot get it from stdin
or parameters
.
It seems there was a bug in passing arguments to a plugin. It should be fixed in the latest sources. Testing a naive script that prints dates of the current year without YYYY part:
$ cat todo.txt
2020-01-13 fix bug #2 !cal:test
2019-12-20 2020-01-06 fix bug #1 !cal:test
$ cat ttdl-cal
#!/bin/sh
echo "$*" | sed 's/2020-//'
$ ./target/release/ttdl list
# D P Created Finished Due Threshold Spent Subject
-----------------------------------------------------------------
1 01-13 fix bug #2 !cal:test
2 01-06 2019-12-20 fix bug #1 !cal:test
-----------------------------------------------------------------
2 todos (of 2 total)
Thanks, I can get it from the first parameter now, but I would suggest pass the it via stdin as it easier for testing (e.g. piping).
echo '{"description":"This is a test","specialTags":[{"due":"2020-02-02"}]' | ttdl-plugin1 | ttdl-plugin2
I'll look into it. Passing an argument was easier to implement at first sight. But it appears that it has its drawbacks. Maybe using stdin
would be better.
I've changed interaction with plugins: now they must read from stdin - no argument provided in command line. On Windows it seems working.
Now I don't need to escape anything manually :), so it seems a better way
Currently, it is hard to customize for ttdl, I suggest that allow to rewrite the data before displaying by external commands via speical key/value tags, e.g. the item
This is an example tagpart1/tagpart2:value
, it will call the external commandttdl-tagpart1-tagpart2
to rewrite the item, is it possible?