czottmann / obsidian-mononote

An Obsidian plugin that ensures each note occupies only one tab. If a note is already open, its existing tab will be focussed instead of opening the same file in the current tab.
https://obsidian.md/plugins?id=zottmann
MIT License
89 stars 2 forks source link

[FR] Don't close tabs, but switch focus #18

Closed FynnFreyer closed 2 months ago

FynnFreyer commented 7 months ago

When I have a note opened already in a background tab, and then try to open this note via the quick switcher it closes the foreground note. I would feel like just switching tabs would be preferrable.

Tab closing instead of switching

This is a matter of opinion obviously, and the default behaviour would also discard the active note, but this would for example enable quick and easy navigation between open tabs via the quick switcher.

czottmann commented 7 months ago

Hi @FynnFreyer, thanks for the ticket!

This is a matter of opinion obviously, and the default behaviour would also discard the active note, but this would for example enable quick and easy navigation between open tabs via the quick switcher.

I concur, and I'd love to implement it but AFAICT there's no event Mononote could hook into to learn about the quick switcher use. Meaning, to the best of my knowledge Obsidian doesn't signal that the quick switcher does anything, Mononote can only react to the change in the active tab but doesn't see how it came to be.

I'll keep the ticket open, as it's a valid feature request (plus I'd love to make it happen), maybe someone more knowledgeable than me might chime in, or maybe I'll have an epiphany at some point.

FynnFreyer commented 7 months ago

Hey @czottmann, no worries, thanks for making this plugin =D

[...] there's no event Mononote could hook into [...], Mononote can only react to the change in the active tab

Yes, that's tricky =/

Just generating ideas here, but caveat emptor: they might be bad =) (I don't know my way around the Obsidian-API or TypeScript)

I think it's possible, to use Workspace.getLastOpenFiles to find out which file lost focus. Then one would need to check whether this one was open in the current pane and if it was, but it's not anymore, restore it and only afterwards switch to the duplicate note.

If we open a new tab, and the old one is still there, we can check that it's still there. If it isn't, we could restore it. The problem is, that if it isn't there, we might have just come from another window, or a popover.

To alleviate that, one could probably do the bookkeeping internally (shudder) and keep a reference to the last focused file, which is updated on changes, using Workspace.getActiveViewOfType or some such. Then, when the focus changes, you know which view lost focus, and can even recognize if that's due to a popover or another window (assuming that a View/Leaf can find out where it is). (Could this even allow for #16 without breaking hover editor?)

Seems like a lot, but might be worth it. I'll sleep it over, and if you're interested, and I find the time (soon™) I'd put some effort in detailing and maybe even implementing this.

5HT2 commented 7 months ago

I'd really love this as an option / default, I found this through the https://github.com/scambier/obsidian-no-dupe-leaves plugin (which only seems to affect clicking a link, not the Quick Switcher feature in Obsidian), I almost exclusively use quick switchers to navigate opened windows / apps OS-wide, as well as different files and terminal tabs elsewhere, as it reduces mouse strain from nerve damage in my hands, and currently in order to avoid opening a duplicate note with the quick switcher I need to

  1. Look at my opened tabs to see if I already have it opened 2a. Ctrl T if I don't → Use Quick Switcher 3b. If I do, use arrow keys / other navigation shortcuts to switch to that note

This plugin is wonderful in that it avoids the duplication behavior with the quick switcher, but unfortunately replacing the current window is somewhat disruptive (even if avoidable by doing Ctrl T → Quick Switcher → use mononote), I think this feature would be very helpful :)

czottmann commented 7 months ago

Thanks, people, I appreciate the input! I will see what I can do but it might take a bit, as Mononote is not my priority right now.

FynnFreyer commented 7 months ago

I will see what I can do but [...] Mononote is not my priority right now

As I said, I'd be willing to detail and implement this and send a PR. It might take a while, but will happen eventually, because I want this for myself

czottmann commented 7 months ago

@FynnFreyer Feel free to give it a shot! I believe it can be solved by checking the history of the newly activated tab, and if there is history, instead of closing it before focussing the already existing note, we could go back one step. Just from the top of my head…

Tejeev commented 5 months ago

Thank you @czottmann! This addon is a great help and I think if we can get something like what you described in the last comment, that would be a great solution. Here's hoping Obsidian has a way for that when someone gets the time to try it.
Not pushing for a more speedy release but wanted to +1 the RFE and also show my appreciation :)

Tejeev commented 4 months ago

@lifehaschanged re-opening the last closed tab after switching still loses prior history iiuc. I prefer the workaround @czottmann proposed, though I can see why it's maybe not the best, as you might end up with tabs on pages you didn't remember why you had open. Any solution that loses history is pointless to me. Another alternative might be that when it notices a new tab opening to a page that is already open, the addon closes the new tab and goes to the existing one, rather than the other way around, or just goes to the existing tab rather than even opening a new one (I think the former is more possible here?)

czottmann commented 4 months ago

Thanks for all the input, folks, really appreciate it. Sorry about the absence, but this here is a side project, and I need to make money to pay rent, so those projects get higher priority. 🤷🏻‍♂️


I took some time to dive deeper into how Obsidian handles things, and I'm at a loss at how to proceed. Before I proceed with the distilled version of what I found out, let's recap: Mononote can only react to events triggered by Obsidian, namely the active-leaf-changed event. There's no "before" hook here, i.e. the event is always triggered after the fact. AFAICT there's no other event besides (maybe?) file-open that emits a signal that the currently focussed tab was changed.

Now going back to the original example, simplified: We have two tabs, T1 w/ note N1, and T2 w/ note N2. N1 contains a link to N2. Clicking that link should focus T2 (N2), but T1 shouldn't close but go back in history, effectively show N1 again.

Tricky. I've experimented with checking the history of the currently open tab (T1), and if there is back history, keeping the tab open instead of closing it, and going back. Calling workspaceLeaf.history.back() etc., however, does two things:

The latter has the effect that the just-focussed tab doesn't remain in focus, plus now there's yet another active-leaf-changed event, starting a new cycle with a race condition on top.

To be honest, again, I'm at a loss about where to go from here. I'm open to suggestions.

linear[bot] commented 4 months ago

ZCO-388 Check for history before closing a tab

lifehaschanged commented 4 months ago

Why can't everything stay as it is, and when a link is clicked, only a new empty tab is opened before switching to the other targeted tab? This way, only the empty tab would be closed, leaving the other one intact. I can already test this in Obsidian with the current Mononote setting: when I switch from an empty tab to another tab, only the empty tab is closed. It would just require inserting Obsidian's internal command for a new tab before the actual tab switch.

jamie9090 commented 3 months ago

I would love this as well. Hopefully Obsidian implements directly! Obsidian workspaces can become so messy.

czottmann commented 2 months ago

@lifehaschanged

Why can't everything stay as it is, and when a link is clicked, only a new empty tab is opened before switching to the other targeted tab? This way, only the empty tab would be closed, leaving the other one intact. I can already test this in Obsidian with the current Mononote setting: when I switch from an empty tab to another tab, only the empty tab is closed. It would just require inserting Obsidian's internal command for a new tab before the actual tab switch.

In order to open a new tab, Mononote would need to know when to open that new tab. It's a reactive plugin, and only listens to notifications that Obsidian is sending out. And there's no notification for "Obsidian is about to open a link" that we could hook into. The app does its thing, and then, when it's done doing that, sends out a notification "I've focussed a tab", including the pointer to the tab. There's also a "I've opened a file" notification (which includes a pointer to the opened file, but none to the tab that holds the file).

And Mononote mustn't cram anything into Obsidian's own source code, there be dragons, not to mention it'd be rude AF ;)

czottmann commented 2 months ago

A short update: I'm currently rewriting the whole internal logic.

I've ditched the idea of closing any superfluous tabs, which makes the whole process a lot less brittle. Instead, when a tab (T1) gets activated/focussed, all its siblings are tested for T1's displayed note. If any tabs are found, the oldest (T2) is activated/focussed while T1 will return to its previous note. If there is no previous note, T1 is closed.

The app's event loops are chock-full of possible race conditions and surprises. For example, when a tab's active-leaf-change event is sent out, the tab's history isn't updated yet. 😐 (Something I hadn't realized before.) And going back in a tab's history will trigger another active-leaf-change event which Mononote has to ignore. So… complexity.

Anyway, it's working quite well right now but as we all know, the devil's in the edge cases. 😉 I'll run some more tests later, fingers crossed!

czottmann commented 2 months ago

Fixed/implemented in Release 1.2.1. Let me know if it isn't, please!

kvenn commented 2 months ago

Works like a dream. You rock @czottmann 🙏

jamie9090 commented 2 months ago

Wow amazing - thank you.

On Thu, Jun 20, 2024 at 23:46:58, Kyle Venn @.***> wrote:

Works like a dream. You rock @czottmann https://github.com/czottmann 🙏

— Reply to this email directly, view it on GitHub https://github.com/czottmann/obsidian-mononote/issues/18#issuecomment-2181019734, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQTI3XA7CP2L53CVV3IRPRTZIL2PFAVCNFSM6AAAAABB7GWTICVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBRGAYTSNZTGQ . You are receiving this because you commented.Message ID: @.***>