xmonad-contrib icon indicating copy to clipboard operation
xmonad-contrib copied to clipboard

Multi-workspace projects/scopes

Open ivanbrennan opened this issue 5 years ago • 11 comments

Problem Description

A project defined by X.A.DynamicProjects or X.A.TopicSpace is limited to a single workspace. I often want to treat a group of workspaces as a scope, constraining workspace cycling and status-bar display to a particular scope.

For example, if I have workspaces A B C D E, I can define a "personal" scope spanning A B and a "work" scope spanning C D. When the "personal" scope is active, my statusbar shows A B and workspace cycling is limited to those workspaces. Switching to the "work" scope behaves similarly, for C D. Switching to unscoped makes all workspaces accessible.

Tmux has a concept of "sessions" that works like this. Each session has an independent set of workspaces (or rather, "windows", in tmux terminology), and you can easily switch between sessions. This provides a nice way to group related workspaces into independent units and choose which unit you want to work with.

I looked into X.A.DynamicWorkspaceGroups, but its group represents a set of simultaneously visible workspaces on a multi-screen setup, as opposed to a set of workspaces that a given screen can cycle through.

Solution

I'm interested in implementing this, but I'm not sure how best to do it. I'd be interested to hear anyone's thoughts/suggestions.

After reading through X.A.DynamicWorkspaceGroups, X.A.DynamicProjects, and X.L.IndependentScreens, I started sketching something out, using ExtensibleState to keep track of which scopes have been defined, activated, etc.

newtype WorkScope = WorkScope { unWorkScope :: !(Set WorkspaceId) }

type WorkScopeName = String

newtype ScopeSets = ScopeSets
  { workScopes   :: !(Map WorkScopeName WorkScope),
    activeScopes :: !(Map ScreenId WorkScopeName) -- TODO: track which workspace is displayed?
  }
  deriving (Typeable, Read, Show)

instance ExtensionClass WorkScopes where
  initialValue = WorkScopes mempty
  extensionType = PersistentExtension

It looks like there's a fair amount of state to keep track of and several edge-cases to consider (e.g. workspaces being renamed/removed, selecting a scope that's active on another screen, ...), so I haven't really settled on how to model it or keep state in sync (maybe using a layout modifier?).

Another approach I'm considering would attach a Maybe WorkScopeName to a workspace, and scoping would involve filtering workspaces based on the relevant scope. I suspect this would be more reliable than my initial Map-based idea, since it wouldn't need to update state any time a workspace is removed or renamed. And X.L.WorkspaceDir provides an example of how to use a layout modifier to attach metadata to a workspace. If we wanted to allow a workspace to be a member of multiple scopes, the Maybe WorkScopeName could instead be a Set WorkScopeName.

Checklist

ivanbrennan avatar Sep 27 '20 14:09 ivanbrennan

If we wanted to allow a workspace to be a member of multiple scopes

That's definitely a feature I would want :)

jeyj0 avatar Nov 18 '20 10:11 jeyj0

And X.L.WorkspaceDir provides an example of how to use a layout modifier to attach metadata to a workspace.

Unfortunately it doesn't provide a way to read that metadata. But I'm working on that, specifically to provide a way to read the dir out of WorkspaceDir, see https://github.com/xmonad/xmonad-contrib/pull/398#issuecomment-723937287. The Typeable changes required are merged to xmonad/xmonad-contrib, ale the latest prototype of InspectLayoutModifier is here: https://github.com/liskin/xmonad-contrib/commit/77c1821ed6e70668f02e0f5f28e11262209d0ded. I think I'll just need to add a few (overlapping 🙁) instanes and some documentation and we might be good to go.

And I feel like I could use this feature as well! I now have 11 workspaces, 6 of which are related to a project that is currently on hold while I'm hacking on xmonad. Would be awesome to be able to hide those somehow. I'm a bit afraid that this will need to be wired into quite a lot of various places, but we can figure something out!

liskin avatar Nov 18 '20 11:11 liskin

Hi, I've been working on something similar to this for my personal use. Here's the module if anyone is still interested. I'm somewhat of a haskell newbie and the module is a work in progress, so keep that in mind when looking at the code. I've been using this for 2 weeks now and it's good enough for me.

Feel free to message me if you have any suggestions 🙂.

mislavzanic avatar Feb 10 '23 15:02 mislavzanic

Thanks @mislavzanic, I for one am still very interested in this feature. Regretfully, I haven't looked into it for a while, but this is a good reason to revisit it.

ivanbrennan avatar Feb 10 '23 17:02 ivanbrennan

@liskin Is there anything I could help with to get InspectLayout ready for a PR?

Experimenting in my config, I was able to make use of your Inspect module, defining a simple layout modifier that attaches metadata to a workspace and using inspectWorkspace to read that data.

ivanbrennan avatar Feb 19 '23 22:02 ivanbrennan

@ivanbrennan If you help me with the docs (TODOs) in https://github.com/liskin/xmonad-contrib/commits/layout-inspect, specifically https://github.com/liskin/xmonad-contrib/commit/07dd2194196603a7465ae4f51fc6ef57645add15, then a PR can definitely be opened. I've been burned out lately so my initiative is limited, but you're right that this one doesn't need much additional work to be generally usable.

liskin avatar Feb 23 '23 09:02 liskin

@ivanbrennan I would love to help out, so don't hesitate to contact me.

mislavzanic avatar Feb 23 '23 11:02 mislavzanic

@liskin @mislavzanic Thanks! I'll take a look at those TODOs.

I'm just starting to play around with possible implementations of workspace scopes. At the moment, I'm grouping workspaces into layers, so rather than 1, 2, ..., 9 I have (1_1, 1_2, ..., 1_9), (2_1, 2_2, ..., 2_9), ..., and tracking which layer is considered currently active.

I just came across XMonad.Actions.WorkspaceCursors, which looks very powerful (and cleanly implemented) and could be used to implement such layers.

I haven't yet explored dynamic layer manipulation or naming layers, but plan to do so -- thanks @mislavzanic for sharing the Profiles idea.

ivanbrennan avatar Feb 23 '23 17:02 ivanbrennan

Anybody still interested in this? I've been using my extension for about a year.. There may be some details that need to be discussed, but it's working pretty nicely.

If anybody is interested in using it feel free to ping me.

mislavzanic avatar Feb 13 '24 17:02 mislavzanic

There's been some interest expressed on the IRC channel recently. In any case, contrib is always open to new submissions. 😀

geekosaur avatar Feb 13 '24 17:02 geekosaur

Ok, I'll start working on a PR then. Will need a couple of days to tidy up and write the documentation.
Hope to be done by end of the week.

mislavzanic avatar Feb 14 '24 16:02 mislavzanic