alot icon indicating copy to clipboard operation
alot copied to clipboard

alot refreshes search list during execution of command list

Open MacGyverNL opened this issue 10 years ago • 7 comments

I want to be able to delete mail, and I also want to be able to undelete mail and have it marked as undeleted so that I can check them and process them later. In order to have those tags mutually exclusive, I have added the following to my .config/alot/config:

[bindings]
    [[search]]
        delete = "tag deleted; untag undeleted,unread,inbox;"
        insert = "tag undeleted; untag deleted;"

Now, in normal conditions, this works. But I have also redefined

initial_command = search tag:inbox AND NOT tag:killed AND NOT tag:deleted

and

[bindings]
    I = search tag:inbox AND NOT tag:killed AND NOT tag:deleted

Now, this together makes that whenever I press delete on a selected mail in the initial search, it gets tagged deleted, the search gets updated which makes this mail disappear and the next mail selected, and then that next mail gets untagged undeleted, unread, inbox, making it disappear as well. This was not what I was expecting to happen.

In my opinion, the expected behaviour for this should always be to keep the same mail selected while executing the commands, so I would propose to only refresh the search after complete execution of a command list. I realize that people could want to have command lists which update the search halfway inbetween, but in these cases they could just insert a refresh command at the desired locations.

[edit: fixed name of config file]

MacGyverNL avatar May 29 '15 07:05 MacGyverNL

Quoting Pol Van Aubel (2015-05-29 08:38:55)

I want to be able to delete mail, and I also want to be able to undelete mail and have it marked as undeleted so that I can check them and process them later. In order to have those tags mutually exclusive, I have added the following to my .notmuch-config:

alot config you mean?

In my opinion, the expected behaviour for this should always be to keep the same mail selected while executing the commands, so I would propose to only refresh the search after complete execution of a command list. I realize that people could want to have command lists which update the search halfway inbetween, but in these cases they could just insert a refresh command at the desired locations.

The thing is that the refresh-command will actually rebuild all widgets in the buffer, and since the focus position is a property of these widgets, it will be lost. But yea: it'd be good to "fix" this behaviour of refresh..

pazz avatar May 29 '15 08:05 pazz

Or add another command like refresh-search in the search context and leave refresh as-is.

MacGyverNL avatar May 29 '15 09:05 MacGyverNL

Going through my old stuff. I thought that maybe --no-flush would allow me to implement this as a pipeline that does not refresh until the final command. However, it turns out that a sequence of tags and untags --no-flush has the exact same behaviour, because upon flush they are handled one by one, and each operation passes the search with thread ID to notmuch. So any command in the sequence that makes it drop from the search, effectively prevents proper application of queued commands.

i.e.

DEBUG:globals:CMDLINE: untag --no-flush deleted
DEBUG:ui:search command string: "untag --no-flush deleted"
DEBUG:__init__:mode:search got commandline "untag --no-flush deleted"
DEBUG:__init__:ARGS: ['untag', '--no-flush', 'deleted']
DEBUG:__init__:cmd parms {'flush': False, 'allmessages': False, 'tags': 'deleted', 'action': 'remove'}
DEBUG:search:all? False
DEBUG:search:q: (tag:deleted) AND thread:000000000001cfea
<snip command input>
DEBUG:globals:CMDLINE: tag --no-flush inbox
DEBUG:ui:search command string: "tag --no-flush inbox"
DEBUG:__init__:mode:search got commandline "tag --no-flush inbox"
DEBUG:__init__:ARGS: ['tag', '--no-flush', 'inbox']
DEBUG:__init__:cmd parms {'flush': False, 'allmessages': False, 'tags': 'inbox', 'action': 'add'}
DEBUG:search:all? False
DEBUG:search:q: (tag:deleted) AND thread:000000000001cfea
DEBUG:ui:Got key (['$'], [36])
DEBUG:ui:cmdline: 'flush; refresh'
DEBUG:ui:search command string: "flush"
DEBUG:__init__:mode:search got commandline "flush"
DEBUG:__init__:ARGS: ['flush']
DEBUG:__init__:cmd parms {}
DEBUG:manager:write-out item: ('untag', None, '(tag:deleted) AND thread:000000000001cfea', ['deleted'])
DEBUG:manager:cmd created
DEBUG:manager:got write lock
DEBUG:manager:got atomic
DEBUG:manager:ended atomic
DEBUG:manager:ended atomic
DEBUG:manager:closed db
DEBUG:manager:flush finished
DEBUG:manager:write-out item: ('tag', None, '(tag:deleted) AND thread:000000000001cfea', ['inbox'])
DEBUG:manager:cmd created
DEBUG:manager:got write lock
DEBUG:manager:got atomic
DEBUG:manager:ended atomic
DEBUG:manager:ended atomic
DEBUG:manager:closed db
DEBUG:manager:flush finished
DEBUG:globals:flush complete

The tag "inbox" is never applied to messages in the thread, because no messages match the notmuch query anymore. Even though it now doesn't accidentally apply the commands to messages in the wrong thread, it also won't apply them to the right thread. This is very unintuitive.

Unfortunately, there's no easy fix I can think of: applying commands directly to all messages that show up in a thread:numeric-id selection would ignore the search and thus apply to all messages in a thread.

MacGyverNL avatar Oct 28 '19 17:10 MacGyverNL

Yes I agree with you that this is not intuitive, and (only) explicit refreshes of the search results would be nice (defaul key bindings could include these at the end). It seems that there should be two refreshes really: one for the search result, and another for the screen content. Because somehow, tagging/untagging should be reflected in the tag widgets attached to what you are editing.

pazz avatar Nov 02 '19 16:11 pazz

Just as a side note: I am aware that "programming" with alot's command sequences is really ugly and not at all at the level of say vimscript. My original intent was to simply do everything non-trivial in python hooks, which can then be bound to keys via the call command.

pazz avatar Nov 02 '19 16:11 pazz

Is there a workaround for this issue? I'm currently testing an extension I've made to afew to synchronize a tag set with a maildir folder hierarchy. As long as I set tags with 'notmuch tag...' it works quite well. But I need to be able to add and remove tags from the message. From the above, I gather that keeping selected message stable through a sequence of commands is complex. If there is no workaround for that, I could add a single command to add and remove tags as a transaction. Similar to the 'notmuch tag +tag1 -tag2' syntax. Though to be consistent with the existing tag lists, I would use a comma separated list.

naegling avatar Nov 19 '21 15:11 naegling

Sorry, totally missed this. The current setup I have is --no-flush, but a bit differently set up.

At some point I started using the --no-flush argument to tag and untag in the search view, with an explicit keybind to flush all operations and refresh the view. The reason for that was entirely different: I was on slow spinning rust which meant every flush-and-refresh operation took seconds. This was not working well for me.

Turned out that delaying the refresh until all flushes have proceeded seems to do what I wanted, without me realizing that.

So my current settings are

[bindings]
        $ = flush; refresh
        [[search]]
                insert = "tag --no-flush undeleted; untag --no-flush deleted;"
                delete = "tag --no-flush deleted; untag --no-flush undeleted,unread,inbox;"

But it's still an ugly hack and I will quite happily switch to your applytags proposal in #1592 to collapse the tagging operations into one.

MacGyverNL avatar Sep 14 '22 13:09 MacGyverNL