GithubHelp home page GithubHelp logo

Comments (5)

kpritam avatar kpritam commented on August 26, 2024 6

I am using following scripts to manage spaces between windows:

  1. when stacked, add left padding 40px
  2. When not stacked, use 8px padding

yabairc

yabai -m signal --add event=window_created action="~/.config/yabai/refresh.sh"
yabai -m signal --add event=window_destroyed action="~/.config/yabai/refresh.sh"

refresh.sh

#!/usr/bin/env bash

number_of_windows=$(yabai -m query --windows --space | ~/.nix-profile/bin/jq 'length')
number_of_stacked=$(yabai -m query --windows --space | ~/.nix-profile/bin/jq -c 'map(select(."stack-index" != 0)) | length')

padding=8
lpadding=40

[[ "$number_of_windows" -eq 1 ]] && padding=0
[[ "$number_of_stacked" = 0 ]] && lpadding=$padding

yabai -m config --space mouse top_padding $padding
yabai -m config --space mouse bottom_padding $padding
yabai -m config --space mouse left_padding $lpadding
yabai -m config --space mouse right_padding $padding
yabai -m config --space mouse window_gap $padding

from stackline.

basbebe avatar basbebe commented on August 26, 2024 1

this works also for the current focused window – independent of where the mouse is at the point:

#!/usr/bin/env sh

number_of_windows=$(yabai -m query --windows --space | /usr/local/bin/jq 'length')
number_of_stacked=$(yabai -m query --windows --space | /usr/local/bin/jq -c 'map(select(."stack-index" != 0)) | length')
currspace=$(yabai -m query --spaces --space | /usr/local/bin/jq '.index')

padding=8
spadding=40

[[ "$number_of_windows" -eq 1 ]] && padding=0
[[ "$number_of_stacked" = 0 ]] && spadding=$padding

yabai -m config --space "$currspace" top_padding $padding
yabai -m config --space "$currspace" bottom_padding $padding
yabai -m config --space "$currspace" left_padding $spadding
yabai -m config --space "$currspace" right_padding $spadding
yabai -m config --space "$currspace" window_gap $padding

from stackline.

AdamWagner avatar AdamWagner commented on August 26, 2024

@jzelner I've definitely had this same thought!

I'm still working on refactoring for testability. I don't quite see the light at the end of the tunnel yet, but hope to be able to wrap this up shortly after the new year.

In parallel, I've been day-dreaming about rewriting stackline using a state-machine-esque component model:

  • Add a base component class that
    • has a registerHandler method that accepts an onChange function to be called with the old/new state whenever the component's state changes
    • uses lua's metamethod magic to automatically call all registered onChange handlers whenever the component's state changes (inspired by https://github.com/Phrogz/notifitable, but I was able to implement the desired behavior in a much simpler way)
  • Rewrite stackmanager stack, window, and indicator classes as subclasses of component
  • Simplify the scarily complicated logic here using rules inspired by state machines. (Of all the ideas so far, this has the highest risk of failing to meet expectations. I'm kind of assuming / hoping that reliable/omnipresent onChange handlers will make it possible to simplify that mess)
  • Expose a public API for end-users to easily register onSomethingChange handlers that perform an action when a) stackline state changes or b) key window management events (such as switching the active space) occur.

Let's tie that ramble together with your idea:

I think that the changes above would make it trivial to implement your suggestion:

  • On space change:
    • if stack length is zero, execute yabai command to set left & right padding to X
    • otherwise, execute yabai command to set left & right padding to stackling.config.appearance.size + X

Since waiting is no fun, below is a snippet that you can place in your ~/.hammerspoon/init.lua file to get an idea how this might work.

The result is pretty janky, but it should give you an idea.

If you're constantly switching spaces (like I am), the window jitter this causes isn't worth the extra real estate on spaces that don't have any stacked windows. You might be able to minimize the jank by independently maintaining state (e.g., {spaceHasStacks = { 1 = false, 2 = true, 3 = false}) that's only updated when necessary. I'm not even sure that would help much: I don't think yabai supports per-space padding, so you'll still need to call out to yabai when changing to a space with hasStack value that differs from the previous space.

local function yabai(cmd)
    local output

    -- NOTE: requires string:split() defined at /stackline/lib/utils.lua:16
    local args = cmd:split(' ')

    hs.task.new(
        stackline.config:get('paths.yabai'),
        function(_, stdOut) output = stdOut end,
        args
    ):start():waitUntilExit()

    return output
end

local function sidePadding(val)
    yabai(string.format('-m config left_padding %s', val))
    yabai(string.format('-m config right_padding %s', val))
end

-- See https://www.hammerspoon.org/docs/hs.spaces.watcher.html
hs.spaces.watcher.new(function()

    -- Set space padding for each case
    -- 'big' is dynamically determined based on current size of stack indicators
    -- NOTE: Assumes `showIcons = true`. Should probably factor out function
    -- that dynamically determines indicator width:/stackline/stackline/window.lua:45
    local small = 10
    local big = stackline.config:get('appearance.size') + small

    if stackline.manager then -- ensure stackline is initiated

        -- Hack: we need to wait ~0.5s before updating padding to ensure that
        --     stackline state has finished updating. Otherwise, we'll set the new
        --     space's padding based on whether the *previous* space had stacks ☹️
        -- The appropriate delay will depend on your personal system's speed.
        hs.timer.doAfter(0.4, function()

            -- Get number of stacks on current space
            -- Remember that running this on space change without a delay gives us outdated data
            local stackCount = #stackline.manager:get()

            -- DEBUG: uncomment to show notification w/ # of stacks on space change
            -- local msg = string.format('This space has %s stacks', stackCount)
            -- hs.notify.show('stackline', msg, '')

            -- Set the appropriate padding
            sidePadding(stackCount > 0 and big or small)
        end)
    end
end):start()

There might be a better way. Would love to hear any ideas you might have, @jzelner

from stackline.

blefevre avatar blefevre commented on August 26, 2024

FYI Yabai does support per-space padding so you can adjust the sidePadding function of your script to:

local function sidePadding(val)
    local space = hs.json.decode(yabai('-m query --spaces --space'))
    local space_index = space['index']
    yabai(string.format('-m config --space %s left_padding %s', space_index, val))
    yabai(string.format('-m config --space %s right_padding %s', space_index, val))
end

This gets pretty good results, only downside I see is the required half a second delay.

from stackline.

AJAYK-01 avatar AJAYK-01 commented on August 26, 2024

@jzelner I've definitely had this same thought!

I'm still working on refactoring for testability. I don't quite see the light at the end of the tunnel yet, but hope to be able to wrap this up shortly after the new year.

In parallel, I've been day-dreaming about rewriting stackline using a state-machine-esque component model:

  • Add a base component class that

    • has a registerHandler method that accepts an onChange function to be called with the old/new state whenever the component's state changes
    • uses lua's metamethod magic to automatically call all registered onChange handlers whenever the component's state changes (inspired by https://github.com/Phrogz/notifitable, but I was able to implement the desired behavior in a much simpler way)
  • Rewrite stackmanager stack, window, and indicator classes as subclasses of component

  • Simplify the scarily complicated logic here using rules inspired by state machines. (Of all the ideas so far, this has the highest risk of failing to meet expectations. I'm kind of assuming / hoping that reliable/omnipresent onChange handlers will make it possible to simplify that mess)

  • Expose a public API for end-users to easily register onSomethingChange handlers that perform an action when a) stackline state changes or b) key window management events (such as switching the active space) occur.

Let's tie that ramble together with your idea:

I think that the changes above would make it trivial to implement your suggestion:

  • On space change:

    • if stack length is zero, execute yabai command to set left & right padding to X
    • otherwise, execute yabai command to set left & right padding to stackling.config.appearance.size + X

Since waiting is no fun, below is a snippet that you can place in your ~/.hammerspoon/init.lua file to get an idea how this might work.

The result is pretty janky, but it should give you an idea.

If you're constantly switching spaces (like I am), the window jitter this causes isn't worth the extra real estate on spaces that don't have any stacked windows. You might be able to minimize the jank by independently maintaining state (e.g., {spaceHasStacks = { 1 = false, 2 = true, 3 = false}) that's only updated when necessary. I'm not even sure that would help much: I don't think yabai supports per-space padding, so you'll still need to call out to yabai when changing to a space with hasStack value that differs from the previous space.

local function yabai(cmd)
    local output

    -- NOTE: requires string:split() defined at /stackline/lib/utils.lua:16
    local args = cmd:split(' ')

    hs.task.new(
        stackline.config:get('paths.yabai'),
        function(_, stdOut) output = stdOut end,
        args
    ):start():waitUntilExit()

    return output
end

local function sidePadding(val)
    yabai(string.format('-m config left_padding %s', val))
    yabai(string.format('-m config right_padding %s', val))
end

-- See https://www.hammerspoon.org/docs/hs.spaces.watcher.html
hs.spaces.watcher.new(function()

    -- Set space padding for each case
    -- 'big' is dynamically determined based on current size of stack indicators
    -- NOTE: Assumes `showIcons = true`. Should probably factor out function
    -- that dynamically determines indicator width:/stackline/stackline/window.lua:45
    local small = 10
    local big = stackline.config:get('appearance.size') + small

    if stackline.manager then -- ensure stackline is initiated

        -- Hack: we need to wait ~0.5s before updating padding to ensure that
        --     stackline state has finished updating. Otherwise, we'll set the new
        --     space's padding based on whether the *previous* space had stacks ☹️
        -- The appropriate delay will depend on your personal system's speed.
        hs.timer.doAfter(0.4, function()

            -- Get number of stacks on current space
            -- Remember that running this on space change without a delay gives us outdated data
            local stackCount = #stackline.manager:get()

            -- DEBUG: uncomment to show notification w/ # of stacks on space change
            -- local msg = string.format('This space has %s stacks', stackCount)
            -- hs.notify.show('stackline', msg, '')

            -- Set the appropriate padding
            sidePadding(stackCount > 0 and big or small)
        end)
    end
end):start()

There might be a better way. Would love to hear any ideas you might have, @jzelner

Hey, I was wondering if there was a way to just add a top padding in the stack column, as most of the time it's just the window control buttons being blocked. I don't really want a big left padding as my screen is not very big.

image

Thanks for this cool project btw!!

from stackline.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.