Archiving completion menu should highlight current session
mindstream-archive (default: C-c , a) pulls up a completion menu containing all active anonymous sessions, but it doesn't appear to be sorted in any particular way. It should at a minimum show the current session (if we happen to be in a buffer contained in a mindstream session) at the top, and it would be nice if the whole list were also sorted by recency.
A first attempt at this didn't seem to have any effect:
modified mindstream-util.el
@@ -211,7 +211,8 @@ This is simply the name of the containing folder."
(defun mindstream--session-dir (&optional buffer)
"The repo base path containing BUFFER."
- (mindstream-backend-root buffer))
+ (abbreviate-file-name
+ (mindstream-backend-root buffer)))
(defun mindstream--get-containing-dir (file &optional full)
"Get the name of the directory containing FILE.
modified mindstream.el
@@ -436,7 +436,11 @@ present, otherwise, it creates a new one and enters it."
The session is expected to be anonymous - it does not make sense to
archive saved sessions."
(interactive (list (completing-read "Which session? "
- (mindstream--list-anonymous-sessions))))
+ (mindstream--list-anonymous-sessions)
+ nil
+ t
+ nil
+ 'mindstream-session-history)))
(let ((template (mindstream--template-used session)))
(mindstream--archive session
template)))
I used abbreviate-file-name so that the history variable mindstream-session-history and the result of calling (mindstream--list-anonymous-sessions) contain what appear to be the same values (although the former contains additional values not present in the latter), since without it, the former uses ~ while the latter uses absolute paths like /Users/.... But the completion menu does not change, and it's still sorted in some random order, and the current / most recent session is not selected or at the top.
Completion is a dark art as far as I am concerned, and it will take more time to understand. In the meantime, @nobiot , in case you have any insights 🙂
Happy to have a look. What’s the scenario? I don’t archive sessions. What does archiving do?
Archiving (C-c , a) simply moves an anonymous session to the archive path.
The archive is a path on disk that has the same structure as the anonymous path. It was introduced to distinguish between "active" and "inactive" sessions and thereby allow some UX flexibility, including having these sessions persist across Emacs restarts.
With the default customizations, we don't typically need to manually archive sessions (it happens automatically), but if you have mindstream-persist set to true, you would need to manually archive sessions when you're done with them, to prevent them from being opened the next time you restart Emacs. Another scenario is if you also have mindstream-unique set to false, then there could be multiple active sessions per template, and you may want to archive sessions individually when you're done, to keep things tidy. The docs also explain a bit more.
Oh! Thank you. This is new to me. I will try and also read the manual.
@countvajhula , for sorting, I think all you need is to add sorting logic to mindstream--list-anonymous-sessions to return a sorted list. I believe you can do this by looking at their underlying file name (directory name?) and sort it by modified date or access date (I don't think you can easily get the creation date across different OSs).
For initial value, you can pass the "current anonymous session" to the INIT-INPUT arg of completing-read. It can be nil, so I think you can have a function to see if the current buffer is an anonymous session (I guess you can use mindstream-anonymous-session-p, right?).
Something like this can be used.
(defun files-sort-by-modified-time (file-a file-b)
(let ((time-a (file-attribute-modification-time (file-attributes file-a)))
(time-b (file-attribute-modification-time (file-attributes file-b))))
(time-less-p time-b
time-a)))
(defun files-sort-by-access-time (file-a file-b)
(let ((time-a (file-attribute-access-time (file-attributes file-a)))
(time-b (file-attribute-access-time (file-attributes file-b))))
(time-less-p time-b
time-a)))
@nobiot I just got back from travels in Mexico and am returning to work 🗿. Thank you for this, I'll try it next week!
Travelling to Mexico sounds great! Please take your time to adjust :)
That sounds like a good way to do it!
I was able to make some progress but I don't totally understand some aspects.
Initially, I made the change to use sorting in mindstream--list-anonymous-sessions:
(defun mindstream--list-anonymous-sessions ()
"List anonymous session paths."
(let ((sessions nil))
(mindstream--for-all-buffers
(lambda ()
(when (mindstream-anonymous-session-p)
(push (mindstream--session-dir (current-buffer))
sessions))))
- (seq-uniq sessions)))
+ (sort (seq-uniq sessions) #'files-sort-by-modified-time)))
But even though the sorting was working correctly, the final order shown in the completion menu was always the same:
I'm not sure what the order here is as it doesn't seem to be alphabetical.
However, after modifying mindstream-archive:
(interactive (list (completing-read "Which session? "
- (mindstream--list-anonymous-sessions))))
+ (mindstream--list-anonymous-sessions)
+ nil
+ t
+ nil
+ 'mindstream-session-history)))
... it now correctly reflects the sort order of the list in the displayed results.
So it only works if we provide a "history" variable, I guess? That's totally fine if so, I just found this surprising since we're providing a list to completing-read whose sort order seems to be ignored conditionally based on whether a history variable is indicated or not... I dunno. Maybe I'm overcomplicating it?
In any case, thank you so much. This is definitely an improvement. There is still one issue:
With the above changes, it now correctly sorts sessions in terms of when they were last modified, e.g. when a file in that session was last saved. But say we have multiple open anonymous sessions and that session A was most recently saved. If we then visit a buffer in session B and then try to archive that session while visiting that buffer, we would like session B to be at the top of the list as it is the most recently visited. But "last modified" and "last access" seem to be filesystem operations that are not aware of Emacs visiting these files using switch-buffer, and so C-c , a still shows A at the top even though we are currently visiting B.
A simple fix could be to just manually add the current session to the front of the sorted list:
(defun mindstream--list-anonymous-sessions ()
"List anonymous session paths."
(let ((sessions nil))
(mindstream--for-all-buffers
(lambda ()
(when (mindstream-anonymous-session-p)
(push (mindstream--session-dir (current-buffer))
sessions))))
- (sort (seq-uniq sessions) #'files-sort-by-modified-time)))
+ (let ((sessions (sort (seq-uniq sessions)
+ #'files-sort-by-modified-time)))
+ (when (mindstream-session-p)
+ (let ((this-session (mindstream--session-dir)))
+ (setq sessions
+ (cons this-session
+ (remove this-session
+ sessions)))))
+ sessions)))
Do you think that's a good way to do it, or do you have a better idea?