mclear-tools / tabspaces

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] two projects with same name are considered as one workspace

abougouffa opened this issue · comments

Hello @mclearc

The issue I've reported previously in #38 is raising again, I think after this commit a260cd8.

I think the idea behind the above commit is good (no duplicate tabs for the same project unless intended). However, it fails to distinguishes (given it uses only tab names) between two projects with the same name (with different paths), and two instances of the same project (with the same path).

tabspaces/tabspaces.el

Lines 402 to 409 in beab193

(defun tabspaces--generate-unique-tab-name (base-name existing-names)
"Generate a unique tab name based on BASE-NAME and the list of EXISTING-NAMES."
(let ((new-name base-name)
(count 1))
(while (member new-name existing-names)
(setq new-name (format "%s<%d>" base-name count))
(setq count (1+ count)))
new-name))

I think it would be more logical to store (somehow) the absolute path for each project of each tab. I don't know if there is an obvious way to add tab-local variables (like buffer local with defvar-local and setq-local), but I think this is the right way to do it (instead of relaying only on tab names).

commented

hi @abougouffa

I think change this line's and to or can solve your first problem

(tab-name (if (and (member project-root-name existing-tab-names) prefix)

- (tab-name (if (and (member project-root-name existing-tab-names) prefix) 
+ (tab-name (if (or (member project-root-name existing-tab-names) prefix) 

As for the second question, I think this is as design. You can always open as many instances for one project. (I think it's more like a feature rather than a bug.)

If we want to solve it, we had to store the project's path and tab-bar's name to one place, which may break the current architecture. I'm afraid it will be a huge refactor, since this package mainly uses tab-bar, for each session it stores buffer instead of project's meta. Would like to see what the author thought...

Thanks for both your input -- I'm really not inclined to go far beyond the way in which tabspaces leverages built-in functionality. The and/or switch isn't going to work for some people, since that change was motivated by someone not wanting to create a new workspace automatically if there is already one that exists. I'm happy to hear ideas here but I want to keep the code (1) as simple as possible; (2) closely connected with built-in functionality.

commented

The and/or switch isn't going to work for some people, since that
change was motivated by someone not wanting to create a new
workspace automatically if there is already one that exists.

Oh, I see. So the first problem abougouffa issued should not be
considered as a bug, because it's designed to behave like this:

             +------------------+
             |open a new project|
             +------------------+
                      |
                      |
                check tab name
                      |
                      |
                      /\
       there is non  /  \  there is already one
                    /    \
                   /      \
               create    switch

If we want to create a new workspace for a existing tab-name, we
should use a prefix to achieve it, am I right?

Consider the following scenes:

  1. I already opened .emacs.d workspace, but I forgot it, so I open a
    new one:

    M-x tabspaces-open-or-create-project-and-workspace ~/.emacs.d

    In this condition, we should switch to the existed one instead of
    creating a new one.

  2. I opened a foo workspace, now I want to check another one's foo
    project:

    M-x tabspaces-open-or-create-project-and-workspace ~/foo

    In this condition, we should create a new one instead of switch to
    the existed foo one. To achieve this, we should use a C-u.

I want to keep the code (1) as simple as possible; (2) closely
connected with built-in functionality.

Same, I switched from eyebrowse to here, and it works really well
with me. Thanks for your work!

@mclearc @dalugm Thank you both for your responsiveness.

I understand the rational behind keeping tabspaces simple, and I adhere to that perfectly.

However, @dalugm, the issue I'm trying to expose here is relevant when you have two separate projects under two different paths. For example:

~/workspace/project1/ci
~/workspace/project2/ci

Here the two ci repos are completely independent.

So, M-x tabspaces-open-or-create-project-and-workspace ~/workspace/project1/ci creates a tab named ci.

Now, I need to open another workspace (tab) for the second project ~/workspace/project2/ci, for example, to copy some config to the project1/ci.

In this case, M-x tabspaces-open-or-create-project-and-workspace ~/workspace/project2/ci will switch to tab ci instead of creating a new one (because it is another project).

I understand that, if we want to solve this issue correctly, we need to store more data about the created tabs besides the tab name, which indeed can introduces some additional hacks that aren't standard in Emacs, hence, I've asked if there is a builtin way to store per-tab variables (compared to buffer-local variables).

I will try to advice the tabspaces--generate-unique-tab-name in my config to fix this, if I end up with something that isn't too hackish, I will open a PR!

Thanks again

commented

In this case, M-x tabspaces-open-or-create-project-and-workspace ~/workspace/project2/ci will switch to tab ci instead of creating
a new one (because it is another project).

Yes, this is as design, to create a new one, you should

C-u M-x tabspaces-open-or-create-project-and-workspace ~/workspace/project2/ci

However, this requires you to remember whether you had created a same name project.

IMO change the and to or in the condition is a better choice...

I have this happen a lot when I open ~/system-configuration and /ssh:raspi:system-configuration tabspaces and use C-x p e.

@ParetoOptimalDev, yep, the same here, sometimes I do changes on the wrong side, willing to change on remote but actually writing in the local project. Then I start questioning why it is not working 🥲 😄

This bites me a lot too. Did you have any success modifying your config @abougouffa?

I also have to switch between projects that have the same project-root-name. i.e. I'm using git worktrees a lot, so all my projects have a "develop" and "master" directories where the worktrees are checked out, which I can't open at the same time because the "project-root-name" is the same in both projects:

~/src/project1/develop
~/src/project2/develop

For now, as a workaround I just overrode tabspaces-open-or-create-project-and-workspace completely in order to include the full path (project) in the tab-name instead of just the project-root-name. I don't mind the long names, because I always have the tabs hidden anyway. I use tabspaces kind of like tmux in that sense. I don't know if this introduces any bugs in some edge cases, but from some quick test it at least does what I want, which is to open each git project directory in its own tab and quickly switch between them, maintaining their own individual window layouts.

It would have been nice if the tab name was generated by a function we could customize with our own version for more flexibility. I'm not sure what the best course of action is. I'm very new to Emacs and not very familiar with Elisp to contribute a PR, otherwise I would have been happy to do so.

As I said above -- it's difficult for me to come up with a way to deal with this that isn't going to cause trouble in other cases or build out complexity and independence from built-in functionality (a lot of what goes on behind the scenes is simply coming from tab-bar). If I get a block of time I will try to come up with some options.

@abougouffa @martinbaillie @aronne @ParetoOptimalDev I have push a new branch with a possible fix: https://github.com/mclear-tools/tabspaces/tree/distinct-tab-names

Basically, I've added a new variable that gives the option of including the parent directory in the tab name. Will you all please let me know if that is a satisfactory resolution of your issues?

Hi @mclearc! Thank you for your responsiveness!

Well, I would say that it won't be enough to assume that the parent directory is distinct. I tried with two projects under:

  • /path/to/project1/src/git_repo
  • /path/to/project2/src/git_repo

As you see, in the example, src/git_repo is not a unique name, although it is a different project under a different directory!

I see that this issue is a bit complex, I've started to write a fix just after opening this issue, but I lost track of it. I think I was coding in the repo cloned locally by straight.el, so I lost it when I've run straight-pull-all. It was just an early PoC.

My idea was to keep in memory an alist of opened tabs with their associated project paths. Then, when I open a project as a workspace, I check whether it belongs to the opened tabs (by checking the project path). If yes, I switch to that tab, otherwise, I check if the tab name conflicts with any of the opened ones, and in that case, I rename both conflicting tabs like this:

  • /path/to/project1/src/git_repo -> tab git_repo (project1/src)
  • /path/to/project2/src/git_repo -> tab git_repo (project2/src)

The overall code wasn't that complex (as I remember), and didn't introduce any non-built-in dependencies (only project.el and vc.el were used as I remember).

Thanks @abougouffa -- I've pushed a test version of an alist. Right now it takes the new (duplicate named) tab and appends a number. But it stores the paths and changes tabs/projects correctly. Let me know if you had something further in mind.

https://github.com/mclear-tools/tabspaces/tree/tab-path-alist

Actually -- just pushed a commit (7c5b3c3) to make dupe tabs append the grandparent/parent dirs. I don't think I want to make this default for all tabs though (or maybe have it be an opt in variable). But let me know

@mclearc Wow, what a quick fix!

Thank your for your patience,

I will test it as soon as I get access to my laptop and I'll let you know!

Thanks again!

Hi @mclearc

I just gave the tab-path-alist branch a try and it works perfectly!

I tried it on the same example above and now I have:

  • /path/to/project1/src/git_repo -> tab git_repo
  • /path/to/project2/src/git_repo -> tab git_repo (project2/src)

I would like though to have the first tab git_repo renamed to git_repo (project1/src) when the second one is opened. However, it is already much better than before! Thanks!

ok great @abougouffa -- I've implemented a name change for the old dir as well as the newly opened one and merged the branch. Thanks for your feedback!

Closed by c21f28b

Hi @mclearc ,

Just to let you know that c21f28b fixes all my issues!

I tried with two local projects, and on remote and local projects and it is working perfectly!

Thank you so much for your help and for your responsiveness!