Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ba70ea8
format: auto-formatted per luaformat config. Functions folded with 's…
AdamWagner Aug 2, 2020
6edc81b
WIP: Working toward addressing #8 in stackline/query.lua, which repla…
AdamWagner Aug 2, 2020
261a0d1
WIP: basic working state with lots of cruft to clean up and edge case…
AdamWagner Aug 4, 2020
fd0ed5a
Bring over some changes from #13
AdamWagner Aug 6, 2020
4436d40
Bring over indicator styling improvements from #13
AdamWagner Aug 6, 2020
0a93122
Move self.colorOpts into Window:drawIndicator() so that the latter ca…
AdamWagner Aug 6, 2020
a6a4dd3
A small bit of much-needed cleanup
AdamWagner Aug 6, 2020
719379b
Basic functionality working well. Parameterized display options. Indi…
AdamWagner Aug 7, 2020
d8c88fa
Fixed issue where only 1 of N stacks responded to focus events. Moved…
AdamWagner Aug 7, 2020
cb92957
Workaround hammerspoon bug (https://github.com/Hammerspoon/hammerspoo…
AdamWagner Aug 7, 2020
1e5a14b
Fold Window:getScreenSide()
AdamWagner Aug 9, 2020
bb4caa8
Modifying existing indicators on focus change is MUCH faster than des…
AdamWagner Aug 9, 2020
b46916e
Cleanup (one of the) utils.lua files
AdamWagner Aug 9, 2020
db7eac9
Add a status update to readme describing recent changes
AdamWagner Aug 10, 2020
e095747
Included a bunch of cleanup/reorg changes missed in last commit
AdamWagner Aug 11, 2020
02d9758
Fix path to dash shell (again)
AdamWagner Aug 11, 2020
413adea
Add hs._asm.undocumented.spaces dependency
AdamWagner Aug 12, 2020
7f83b52
Remove unused StackConfig:handleSignal() method (it needs to be avail…
AdamWagner Aug 12, 2020
610226d
Cleanup comments & delete unused bluclass.lua
AdamWagner Aug 12, 2020
408cac5
Don't use hs._asm.undocumented.spaces. Uncomment window.filter.notInC…
AdamWagner Aug 12, 2020
587ebbf
Fill gap left behind by hs._asm.undocumented.spaces with hs.spaces.wa…
AdamWagner Aug 13, 2020
c364bc7
Increase threshold in window:getSide() to fix issue w/ large yabai pa…
AdamWagner Aug 13, 2020
b2ce16a
Cleanup comments in query.lua
AdamWagner Aug 13, 2020
0a1f8eb
Removed hs._asm.undocumented.spaces from list of dependencies
AdamWagner Aug 13, 2020
a8ab9ed
Delete unused utils, consolidate utils into single file.
AdamWagner Aug 15, 2020
c30e855
Track stack focus state, indicate last-focused window in unfocused st…
AdamWagner Aug 16, 2020
c4bef7f
Merge pull request #20 from AdamWagner/chore-cleanup-utils
AdamWagner Aug 16, 2020
db32689
Fix misleading comment
AdamWagner Aug 16, 2020
59cd9f7
Remove garbage characters in comment
AdamWagner Aug 16, 2020
ca991cd
Fix error stackline/window.lua:95: attempt to perform arithmetic on a…
AdamWagner Aug 21, 2020
b94605b
Remove completed TODO comments, try to keep TODO comments on single l…
AdamWagner Aug 21, 2020
dc07bb6
Enable keybindings in init.lua by returning stackConfig & stackManage…
AdamWagner Aug 21, 2020
741b27d
Fix https://github.com/AdamWagner/stackline/issues/21 - Limit stack l…
AdamWagner Aug 21, 2020
937f319
Fix merge conflicts, create folder for development notes, update readme.
AdamWagner Aug 22, 2020
cdd8cba
Update version to 0.1.50
AdamWagner Aug 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 47 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,38 @@
![stackline-logo](assets/stackline-github-banner@2x.png)
<p>
<img alt="Version" src="https://img.shields.io/badge/version-0.1.01-blue.svg?cacheSeconds=2592000" />
<img alt="Version" src="https://img.shields.io/badge/version-0.1.50-blue.svg?cacheSeconds=2592000" />
<a href="#" target="_blank">
<img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" />
</a>
</p>

> Visualize yabai window stacks on macOS. Works with yabai & hammerspoon.

## ⚠️ WARNING: THIS IS A PROOF-OF-CONCEPT
## ⚠️ ~~WARNING: THIS IS A PROOF-OF-CONCEPT~~ (it's more like an 'alpha' now!)

Currently, [stackline](https://github.com/AdamWagner/stackline) is a proof-of-concept for visualizing the total number and status of stacked windows. Feel free to try it out and open [issues](https://github.com/AdamWagner/stackline/issues) / PRs, but using stackline full-time is not recommended (yet).
My humble thanks to all who have been suffering through error-ridden setup instructions, spinning fans, flickering UI, and crashes. I'm happy to say that I _think_ this branch fixes enough of these issues that it _should_ be reasonable for actual use ;-)

There is much crucial fuctionality that is either missing or broken. For example, stack indicators do not refresh when:
As before, if you notice something that's off, or could be better, please open an issue (or a PR!).

1. the tree is rotated or mirrored
2. updating padding or gap values
3. a stacked window is warped out of the stack
4. app icons are toggled on/off
---

## What is stackline & why do I need it?

## What is stackline & why would I want to use it?

Consider a browser window with many tabs.

A tabbed user interface consists of a collection of windows that occupy the same screen space. Only _one_ tabbed window may be visible at any given time, and it's the user's job to specify the 'active' window.

To enable this task, tabbed interfaces provide visual indicators for each tab, each occupying much less space than the tab it references, which enables all indicators to be visible at all times. Each indicator _identifies the contents of a window_ & _communicates its position relative to the active window_.

A 'stack' provides a generalized subset of the functionality provided by tabbed user interfaces: it enables multiple to windows to occupy the same screen space, and provides mechanisms to navigate its member windows. It also provides mechanisms to add & remove windows from the stack.
Tabbed interfaces provide visual indicators for each tab. The indicators are relatively small, so they can be visible at all times. Each indicator _identifies the contents of a window_ & _communicates its position relative to the active window_.

Critically for stackline, a 'stack' does not provide the visual indicators necessary to identify how many windows belong to a stack or understand the relative position of the active window within the stack.
A 'stack' provides a generalized subset of a tabbed UI: it enables multiple to windows to occupy the same screen space, and provides mechanisms to navigate its member windows. It also provides mechanisms to add & remove windows from the stack.

Stacks are a recent addition (June 2020) to the (_excellent!_) macOS tiling window manager [koekeishiya/yabai,](https://github.com/koekeishiya/yabai,) and visualization UI is not yet in-the-box.

Enter stackline, which adds non-obtrusive visual indicators to yabai's stacking functionality.
Enter stackline, which adds non-obtrusive visual indicators to yabai'e 's stacking functionality.

![stackline-demo](assets/stackline-demo.gif)


## Getting started with stackline

**Prerequisites**
Expand All @@ -47,11 +42,9 @@ Enter stackline, which adds non-obtrusive visual indicators to yabai's stacking
3. https://github.com/stedolan/jq (`brew install jq`)


You're free to bind yabai commands using your favorite key remapper tool
(skhd, karabiner elements, and even hammerspoon are all viable options).
You're free to bind yabai commands using your favorite key remapper tool (skhd, karabiner elements, and even hammerspoon are all viable options).

That said, you're _probably_ using https://github.com/koekeishiya/skhd. If so,
now is a good time to map keys for navigating and manipulating yabai stacks.
That said, you're _probably_ using https://github.com/koekeishiya/skhd. If so, now is a good time to map keys for navigating and manipulating yabai stacks.

```sh
# Focus window up/down in stack
Expand All @@ -70,7 +63,6 @@ cmd + ctrl - right : yabai -m window east --stack $(yabai -m query --windows --w

1. Clone the repo into ~/.hammerspoon/stackline
2. Install the hammerspoon cli tool
3. Add signals to ~/.yabairc

#### 1. Clone the repo into ~/.hammerspoon/stackline

Expand All @@ -80,7 +72,7 @@ git clone https://github.com/AdamWagner/stackline.git ~/.hammerspoon/stackline

# Make stackline run when hammerspoon launches
cd ~/.hammerspoon
echo 'require "stackline.stackline.core"' >> init.lua
echo 'local stackline = require "stackline.stackline.stackline"' >> init.lua
```

Now your `~/.hammerspoon` directory should look like this:
Expand Down Expand Up @@ -114,39 +106,6 @@ Confirm that `hs` is now available:
/usr/local/bin/hs
```

#### 3. Add signals to ~/.yabairc

Add signals to `~/.yabairc`:

```sh
STACKLINE_EVENTS="\
application_activated \
application_front_switched \
application_hidden \
application_launched \
application_terminated \
application_visible \
window_created \
window_deminimized \
window_focused \
window_minimized \
window_resized"

yabai -m signal --add \
event="window_destroyed" \
label="stackline_window_destroyed" \
action="echo ':window_destroyed' | /usr/local/bin/hs -m stackline-events"

for event in $STACKLINE_EVENTS
do
yabai -m signal --add \
event="$event" \
label="stackline_$event" \
app!="Hammerspoon" \
action="echo ':$event' | /usr/local/bin/hs -m stackline-events"
done
```

### RETRO? GO! FIDO? GO! GUIDANCE…

We're almost there!
Expand All @@ -170,6 +129,7 @@ Did the terminal window expand to cover the area previously occupied by Safari?
![stackline setup 01](assets/stackline-setup-01@2x.png)

The default stack indicator style is a "pill" as seen ↑

To toggle icons:

```sh
Expand All @@ -180,33 +140,59 @@ To toggle icons:

Image (and feature!) courtesy of [@alin23](https://github.com/alin23).


#### Keybindings

If you use `shkd`, you can bind a key combo to toggle icons `~/.skhdrc` file using the hammerspoon cli we installed earlier.

```sh
# if this doesn't work, try using the absolute path to the hammerspoon cli: /usr/local/bin/hs
shift + alt - b : echo ":toggle_icons:1" | hs -m stackline-config
```

Alternatively, you can control stackline by accessing the instance directly via Hammerspoon.

For example, to bind a key combo to toggle icons, you could add the following to your `~/.hammerspoon/init.lua` file, _after_ requiring the stackline module & assigning a local variable `stackline`:

```lua
local stackline = require "stackline.stackline.stackline" -- you should already have this line ;-)

-- bind alt+ctrl+t to toggle stackline icons
hs.hotkey.bind({'alt', 'ctrl'}, 't', function()
stackline.manager:toggleIcons()
end)
```

## Help us get to v1.0.0!

Give a ⭐️ if you think (a fully functional version of) stackline would be useful!
Give a ⭐️ if you think (a more fully-featured version of) stackline would be useful!


## Thanks to contributors!

All are welcome (actually, _please_ help us, 🤣️)! Feel free to dive in by opening an [issue](https://github.com/AdamWagner/stackline/issues/new) or submitting a PR.

[@AdamWagner](https://github.com/AdamWagner) wrote the initial proof-of-concept (POC) for stackline.

[@alin23](https://github.com/alin23), initially proposed the [concept for stackline here](https://github.com/koekeishiya/yabai/issues/203#issuecomment-652948362) and encouraged [@AdamWagner](https://github.com/AdamWagner) to share this mostly-broken POC publicly.
[@alin23(https://github.com/alin23), initially proposed the [concept for stackline here](https://github.com/koekeishiya/yabai/issues/203#issuecomment-652948362) and encouraged [@AdamWagner](https://github.com/AdamWagner) to share the mostly-broken proof-of-concept publicly. Since then, [@alin23](https://github.com/alin23) dramatically improved upon the initial proof-of-concept with https://github.com/AdamWagner/stackline/pull/13, has some pretty whiz-bang functionality on deck with https://github.com/AdamWagner/stackline/pull/17, and has been a great thought partner/reviewer.

- After [@alin23](https://github.com/alin23)'s https://github.com/AdamWagner/stackline/pull/13, stackline sucks a lot less.
[@zweck](https://github.com/zweck), who, [in the same thread](https://github.com/koekeishiya/yabai/issues/203#issuecomment-656780281), got the gears turning about how [@alin23](gh-alin23)'s idea could be implemented and _also_ urged Adam to share his POC.

Thanks to [@johnallen3d](https://github.com/johnallen3d) for being one the first folks to install stackline, and for identifying several mistakes & gaps in the setup instructions.
[@johnallen3d](https://github.com/johnallen3d) for being one the first folks to install stackline, and for identifying several mistakes & gaps in the setup instructions.

[@zweck](https://github.com/zweck), who, [in the same thread](https://github.com/koekeishiya/yabai/issues/203#issuecomment-656780281), got the gears turning about how [@alin23](gh-alin23)'s idea could be implemented and _also_ urged Adam to share his POC.
[@AdamWagner](https://github.com/AdamWagner) wrote the initial proof-of-concept (POC) for stackline.

### …on the shoulders of giants

Thanks to [@koekeishiya](gh-koekeishiya) without whom the _wonderful_ [yabai](https://github.com/koekeishiya/yabai) would not exist, and projects like this would have no reason to exist.

Similarly, thanks to [@dominiklohmann](https://github.com/dominiklohmann), who has helped _so many people_ make chunkwm/yabai "do the thing" they want and provides great feedback on new and proposed yabai features.

Finally, thanks to [@cmsj](https://github.com/cmsj), [@asmagill](https://github.com/asmagill), and all of the contributors to [hammerspoon](https://github.com/Hammerspoon/hammerspoon) for opening up macOS APIs to all of us!
Thanks to [@cmsj](https://github.com/cmsj), [@asmagill](https://github.com/asmagill), and all of the contributors to [hammerspoon](https://github.com/Hammerspoon/hammerspoon) for making macOS APIs accessible to the rest of us!

Thanks to the creators & maintainers of the lua utility libaries [underscore.lua](https://github.com/mirven/underscore.lua), [lume.lua](https://github.com/rxi/lume), and [self.lua](https://github.com/M1que4s/self).

## License & attribution

stackline is licensed under the [&nearr;&nbsp;MIT&nbsp;License](stackline-license), the same license used by [yabai](https://github.com/koekeishiya/yabai/blob/master/LICENSE.txt) and [hammerspoon](https://github.com/Hammerspoon/hammerspoon/blob/master/LICENSE).

MIT is a simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code.
Expand Down
5 changes: 5 additions & 0 deletions bin/yabai-get-stack-idx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/dash

/usr/local/bin/yabai -m query --windows --space \
| /usr/local/bin/jq --raw-output --compact-output --monochrome-output 'map({"\(.id)": .["stack-index"]}) | reduce .[] as $item ({}; . + $item)'

57 changes: 0 additions & 57 deletions bin/yabai-get-stacks

This file was deleted.

71 changes: 71 additions & 0 deletions notes.md → dev-notes/general-dev-notes.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# stackline development notes

## Inspiration
[hhtwm/init.lua](https//github.com/szymonkaliski/hhtwm/blob/master/hhtwm/init.lua)

Probably the best source of inspo, esp. the module.cache = {…} implementation.

[megalithic/window.lua](https://github.com/megalithic/dotfiles/blob/master/hammerspoon/hammerspoon.symlink/ext/window.lua)

- [/utils/wm/window-handlers.lua](https://github.com/megalithic/dotfiles/blob/master/hammerspoon/hammerspoon.symlink/utils/wm/window-handlers.lua)
- [/utils/wm/init.lua](https://github.com/megalithic/dotfiles/blob/master/hammerspoon/hammerspoon.symlink/utils/wm/init.lua)

[window_set.lua](https://github.com/macrael/panes/blob/master/Panes.spoon/window_set.lua)

Seems similar to what I'm doing, but it didn't run w/ SpoonInstall so I haven't used it yet

See how they manage window indicators:
Expand All @@ -25,6 +34,68 @@ See how they manage window indicators:
- [colorboard.lua](https://github.com/CommandPost/CommandPost/blob/develop/src/plugins/finalcutpro/touchbar/widgets/colorboard.lua): CommandPost Colorboard The opposite of above, this is *complicated*! Lots of state management, but not sure how applicable it is for me.
- [statuslets.lua](https://github.com/cmsj/hammerspoon-config/blob/master/statuslets.lua): statuslets


## Debugging

Debugging utils for lua

- https://github.com/renatomaia/loop-debugging

## Caching & queing

[pyericz/LuaWorkQueue](https://github.com/pyericz/LuaWorkQueue/tree/master/src)
A work queue implementation written in Lua.

[darkwark/queue-lua](https://github.com/darkwark/queue-lua)
Queue implementation for Lua and PICO-8
Newer (2020)

[hewenning/Lua-Container](https://github.com/hewenning/Lua-Container/blob/master/Container.lua)
🌏 Implement various containers, stack, queue, priority queue, heap, A* algorithms, etc. through Lua.

[KurtLoeffler/Lua_CachePool](https://github.com/KurtLoeffler/Lua_CachePool)
A lua library for creating pools of cached objects.


## Working with async in Hammerspoon

`hs.task` is async. There are 2 ways to deal with this:

1. `hs.timer.waitUntil(pollingCallback, func)`
2. `hs.task.new(…):start():waitUntilUNex()`

The 1st polls a callback to check if the expected result of the async task has
materialized.
The 2nd makes `hs.task` synchronous.

The docs strongly discourage use of the 2nd approach, but as long as there isn't
background work that could be done while waiting (there isn't in the use case
I'm thinking of), then it should be slightly _faster_ than polling since the
callback will fire immediately when the task completes. It also saves the cycles
needed to poll in the first place.

```lua
-- Wait until the win.stackIdx is set from async shell script
hs.task.new("/usr/local/bin/dash", function(_code, stdout, stderr)
callback(stdout)
end, {cmd, args}):start():waitUntilExit()

-- NOTE: timer.waitUntil is like 'await' in javascript
hs.timer.waitUntil(winIdxIsSet, function() return data end)

-- Checker func to confirm that win.stackIdx is set
-- For hs.timer.waitUntil
-- NOTE: Temporarily using hs.task:waitUntilExit() to accomplish the
-- same thing
function winIdxIsSet()
if win.stackIdx ~= nil then
return true
end
end
```



## Using hs.canvas

Yet another project has a similar take:
Expand Down
1 change: 1 addition & 0 deletions dev-notes/luarocks-reqs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
luarocks install moses
Loading