Open jmriego opened 4 years ago
I suppose another option would be a v
or V
mapping to start a selection but that would require the tasks you want to modify to be next to each other
Multi-task operations have been on my wish list for awhile.
It's not something I have time to implement now, but I'd be happy to look at a PR for it.
I do suspect the implementation will be a lot trickier than you may imagine. Adjusting the interface to display multiple selections and operate on multiple tasks will likely involve some fairly major refactors, and a poor implementation would likely be pretty buggy.
I can imagine! That's why I mentioned several methods that could potentially work. As you said, there's the interface part with also changes in the highlighting. You have to think about multiple types of changes and running task commands that you don't know what could affect... So I think the easiest method would probably be the dot, but what do you think? I might have time to have a look at the code if that makes sense
The dot would probably be a good start. I still think that might have some dragons in it, but conceptually, "store last action, repeat when told" seems fairly straightforward.
Also, I think even if we start here, adding the multiple highlighting later wouldn't conflict, it would just be another usable method.
Since bulk-editing is also a feature I'd really like to be able to use from within vit I've had a little look at the code. Here's some ideas, would love to hear some feedback before I go forward and actually implement anything:
task
's interface for bulk editing is simply task <filter> <command> ...
, so in terms of the complexity of operations like modify
, delete
, start
, stop
etc. it doesn't matter whether the <filter>
is a single uuid (that's the only use case invoked by vit operations at the moment), a space-separated list of uuids, or a logical filter expression. I'd therefore suggest working towards refactoring the existing editing operations to also process lists of tasks or filter expressions and pass them on to the already existing single self.execute_command(['task', ...])
command. This would mainly be around here in the code, where the commands would have to look at other arguments passed in data
to see whether the command target is really just one uuid, or something else (although some code like for done
might also be in the TaskListModel
?):
https://github.com/vit-project/vit/blob/62273a260db5e2594ed46c6531a0c35fa85dea03/vit/application.py#L358-L370
Since bulk-editing is a pretty advanced feature I think it's also more useful to first focus on scriptability, UI implementations can always be added later. In particular I'm thinking about a "bulk-edit all tasks in current view" use case, which really only requires information about (1) what the default filter of the current report+context is and (2) what other custom filters were applied on top of that within vit. I know I can already implement the former using a custom variable replacement that invokes task
to find out the relevant filters, but the latter needs access to vit's runtime application variables. I'd therefore propose to add support for (something like) the following variable replacements to vit:
{REPORT_FILTER}
(possibly also {CONTEXT_FILTER}
?){EXTRA_FILTER}
(replaced by the application's self.extra_filters
){VIEW_FILTER}
(this one's simply ({REPORT_FILTER}) and ({EXTRA_FILTER})
)With these two things in mind I think there could be a nice 3-step roadmap, each of which provides new functionality that builds/relies on the previous ones:
:!rw task {VIEW_FILTER} modify ...
task
operation that supports bulk editing, add a TASK_*_BULK
action to the already existing ones, making sure that vit's underlying task
invocation functions support filter expressions and task-list targets
https://github.com/vit-project/vit/blob/62273a260db5e2594ed46c6531a0c35fa85dea03/vit/application.py#L737-L784_BULK
commandsI'd be keen to get some work done on this (especially step 1) soon, so let me know what you think!
@kevinstadler on first read, this sounds like a solid plan. I'm a little concerned about ripping out the tasklib stuff and replacing it with direct calls to the task binary -- it's been so long since I coded that, I can't remember what the specific advantages were when using tasklib. I'm sure there were some ;)
At the same time, it's always felt clunky to me to have that hybrid model of tasklib/task binary. If we went the route you're proposing, perhaps we should expunge tasklib (at least for all the write operations).
If you want to take a crack at the PR, I'll commit the time to review and offer suggestions/improvements. I agree that having this feature would be a big plus, and I don't have the time to code it. As long as the code is clean and maintainable, we can get it in.
Thanks for working on this!
I did not read the details, but would it make sense to add the under-the-hood work to tasklib? Is the library still maintained? It seems these features might be useful to other Taskwarrior tools that rely on tasklib. I don't know anything about it though so perhaps it is inherently out of the scope of tasklib.
Regarding the interface, two tools that I've used as inspiration for working on vit are mutt and ranger. Multiline (non-consecutive) selections are more natural in those two tools than in Vim so their interfaces might provide some good inspiration.
Again, thanks for your time on this! It is a feature that has been requested by a lot of users over the years and no one has dared to jump down the rabbit hole :)
I did not read the details, but would it make sense to add the under-the-hood work to tasklib?
The problem with that is that the task binary is so darn flexible. I think it's going to be a challenge to account for all that we want to support only using tasklib. The project is still maintained, so it might be worth filing a ticket to see what the dev says.
The problem with that is that the task binary is so darn flexible. I think it's going to be a challenge to account for all that we want to support only using tasklib. The project is still maintained, so it might be worth filing a ticket to see what the dev says.
Ah that is good to know. Thanks. Sounds like it might be one of those "sure that's the nice thing to do in theory but in practice it makes things a lot more complicated" things.
Hey guys,
just randomly chiming in here, but I'm wondering if you want to jump on a call to discuss this? I wrote like ~70% of tasklib
and if my memory serves me right, it covers a pretty broad range of use cases. I am using it quite successfully in taskwiki
.
I didn't even realise that tasklib
was being used, as the modify
command that I looked at already executes task
directly via the application's self.execute_command()
(same as at least 6 other commands, in particular undo
, sync
, edit
, info
, add
and context
). I wonder if the choice not to go through tasklib
for these was the fact that many of them are quite complex so that their failure might require interactive prompting, which is then automatically handled by task
?
Unless you want to make a push towards passing modify through tasklib
as well, the current code:
https://github.com/vit-project/vit/blob/62273a260db5e2594ed46c6531a0c35fa85dea03/vit/application.py#L361
can already support bulk-editing via any of the following minimal changes:
metadata['uuid']
metadata['uuid']
instead of just a single uuid
uuid
arguments between 'task'
and 'modify'
(I think all arguments just get joined with spaces for execution anyway)@tbabej @kevinstadler I'm game to jump on a call to discuss the best implementation.
Again, it's been so long since I built those pieces, I cannot recall the precise reasoning. I do remember that I tried to use tasklib
as much as possible, and where I couldn't figure out how to use it, I fell back to the task
binary directly.
I'm a little concerned about scope creep if we elect to run everything through tasklib
. I guess it depends how hard that is, I haven't studied that code enough to have an opinion.
Just to point out that any decision to change operation execution from task
to tasklib
is independent of the present multiple-task-modification issue, as the current implementation already supports batch operations (at least for modify
). The biggest part of step 2 (adding TASK_*_BULK
operations) concerns how command arguments should be represented within vit. If it turns out that tasklib
is an option for batch modification as well, then the actual external execution can still be swapped in/out without affecting vit's internal processing of batch modifications.
I've had a go at streamlining access to all current filter information within vit and providing access to them via keybinding replacements. I wasn't 100% sure about naming conventions in the codebase, so please have a look and let me know if it looks alright to you so far!
After #290 is merged, it will actually be possible to achieve @jmriego's use case by means of a workaround that uses a tag (say selected
) for marking tasks as selected, then filtering the view for all +selected
tasks before calling {ACTION_TASK_MODIFY_ALL}
:
[keybinding]
# select/de-select tasks by applying a `selected` tag (assumes default m = {ACTION_TASK_MODIFY} to work)
n = m+selected<Enter>
N = m-selected<Enter>
# could use a nice chunky `tag.selected.label = ✓` to visually mark selected tasks
# bind bulk modification to some key, just so it can be used by the actual command below
@ = {ACTION_TASK_MODIFY_ALL}
# prompt modification of all +selected tasks (assumes default f = {ACTION_REPORT_FILTER} to work)
M = f+selected<Enter>@-selected<Space>
Note that the above will also apply to any +selected
tasks which were hidden from view because of extra filters that were active at the time of hitting M
. Because {ACTION_REPORT_FILTER}
overrides (rather than appends to) the extra filters, to be absolutely accurate one would still require access to the current extra filter information through variable replacement (see #289), then use the following:
M = f({REPORT_FILTER_EXTRA}) +selected<Enter>@-selected<Space>
This hadn't occurred to me, and is a brilliant use of the existing tools.
Have a look at my proposal in https://github.com/vit-project/vit/issues/291 -- I think this could be fairly easy to implement, solve this issue more elegantly, and offer other benefits in the future.
At first, Thank you for doing good job, and I've used vit everyday. I implemented about multi-select operation.In my opinion, I think I want to use more simple method in this issue.
https://github.com/yukiohmiya/vit/tree/feature/multiple_select
I implemented this multi-select operation by following flow.
v
command. Add selected task_id
to bulk_id
list.v
, Delete selected task_id
from bulk_id
list.ESC
key, Clear all bulk_id
list.bulk_id
list after :!rw task
whne you push t
command.This implementation works well in my environment. I want to hear your opinion.
Tanks.
thanks a lot @yukiohmiya ! This looks really promising
Some feedback I can think of:
When I use the {bulk_id} in a mapping for some reason it seems to be using the id instead of the uuid. Even in your video you get something like :!rw task 4 5
instead of !rw task abd-1234-abc def-4567-dfe
which would be safer
Also, do you think instead of creating {BULK_ID}
it would make sense to make {TASK_UUID}
have the value of the bulk list if there's a multiple selection or the current row if not? That way I can use the same mapping for both multi and single selection
@jmriego Thanks for your feedback!!
I use buld_id
because I want to display command more simply and I don't know difference task id
from uuid
. I realized maintainer use uuid in vit source code now.
I agree with your idea using uuid and {TASK_UUID}. I'm going to update my code.
Hi,
I was about to ask about the possibilities of adding this feature to vit, and I see people have already done some work on this. I was wondering if this feature plan was still alive...
Thanks again for this great tool, and all the work from the maintainer and contributors to make it even better !
@lyndhurst https://github.com/vit-project/vit/pull/290 was the main thrust of this feature request, and if you read that issue, you'll see it got hung up on some key naming/convention decisions.
Someone will need to pick up that PR and continue it pushing it forward if we want to see this in.
Thank you for the pointer, I am going to read it carefully so I will hopefully understand the issue better.
Hi! First of all, thank you for your hard work. I found out very recently about vit and I find it amazing. I can't believe it's not a lot more popular between the Taskwarrior tools!
I was trying to make changes in multiple tasks at the same time and was wondering if there's some way of doing this.
The two ways I would think of are similar as what you would do in vim:
mt
and then you run a command that would affect all of them. This should also work for when you have mappings that use the task UUID and would run them multiple times with a different UUID each.
mapping that will repeat the previous action. In my opinion itt would also have to work for things like:!rw task ....
so it would be a bit different of the same mapping in vim that don't include:commands
.Does this sounds like something that could be added? Thanks!