nikitabobko / AeroSpace

AeroSpace is an i3-like tiling window manager for macOS
https://nikitabobko.github.io/AeroSpace/guide
MIT License
8.18k stars 132 forks source link

Feature: shell-like combinators for conditional computation and sending several commands to server in a single batch #278

Open nikitabobko opened 5 months ago

nikitabobko commented 5 months ago

Currently it's impossible to consume stdout and exit codes of commands in toml config. One has to use exec-and-forget

alt-w = 'exec-and-forget aerospace workspace W --fail-if-noop || aerospace workspace-back-and-forth'
atl-tab = 'exec-and-forget aerospace list-workspaces --all | aerospace workspace next'

It's slow. Communicating with the server back and forth from CLI client can take additional 100ms which becomes noticeable. Even if we fix the slowness somehow, annoying flickering will still remain an issue

It'd be cool if AeroSpace supported basic shell combinators (||, &&, ;, ( ))

alt-w = 'workspace W || workspace-back-and-forth'
atl-tab = 'list-workspaces --all | workspace next'

That's a big feature that lays the foundation for a lot of things (basically the combinators allow programming custom logic):

Other subcommands that AeroSpace has to implement to make the feature complete:

Overall a lot issues can be fixed: #264 #60 #54 #174 (partially) #104 (partially) #107 (kinda) #150

Open question: doesn't it open a pandora box of own script programming language? It kinda does. I hope that people will never ask for loops

nikitabobko commented 3 months ago

Draft:

on-window-detected = '''
    if test %{app-bundle-id} == com.jetbrains.intellij.ce || test %{app-bundle-id} == com.jetbrains.intellij do
        move-workspace-to-monitor I # [I]de
    elif test %{app-bundle-id} == com.google.Chrome do
        move-node-to-workspace W # [W]eb browser
    elif test %{app-bundle-id} == com.apple.dt.Xcode do
        move-node-to-workspace X; exec-async 'echo hi!' # [X]code
    end
'''
nikitabobko commented 3 months ago

Since it's a custom language, it'd be good to be able to print AST (Abstract Syntax Tree) for better discoverability and debugging

$ aerospace eval --print-ast-and-exit '
if test %{app-bundle-id} == com.jetbrains.intellij.ce do
    move-workspace-to-monitor I
end

echo 'hi!'
'

IfBlock
    IfCondition
        Command
            ['test', '%{app-bundle-id}', '==', 'com.jetbrains.intellij.ce']
    IfThenBlock
        Command
            ['move-workspace-to-monitor', 'I']
Command
    ['echo', 'hi!']
jakenvac commented 3 months ago

I think this sounds like it would be an incredible addition to the project.

Have you thought about using existing embeddable scripting languages such as lua? I think this would be great for several reasons: (I'll use lua as an example here, but there other options)

This of course would come with some cons, too:


Edit: I've just found some incredibly well documented and up to date bindings for lua. Shocked it has so few stars. https://github.com/tomsci/LuaSwift

Edit 2: I don't know how I didn't think of this at first, but macos provides a great embeddable language in the form of JavaScriptCore. Part of apples webkit. It requires no third party dependencies and has a very easy to use swift/obj-c api.

Here's a very simple working code example, demonstrating just how easy it is to use.

import Foundation
import JavaScriptCore

let context = JSContext()

let addTwoNumbers: @convention(block) (Int, Int) -> Int = { num1, num2 in
    print("Adding two numbers: \(num1) + \(num2)")
    return num1 + num2
}

context?.setObject(addTwoNumbers, forKeyedSubscript: "addTwoNumbers" as NSString)

let jsScript = "addTwoNumbers(2, 3)"

if let result = context?.evaluateScript(jsScript) {
    print(result.toString() ?? "No result")
}
tobiasgiese commented 3 months ago

Have you thought about using existing embeddable scripting languages such as lua?

There is also a sketchybar lua plugin 🙂 https://github.com/FelixKratz/SbarLua

osolmaz commented 2 months ago

Just wanted up this

I currently use the following shortcuts, and the delay due to exec-and-forget feels significant

alt-p = 'exec-and-forget aerospace list-workspaces --monitor focused --empty no | aerospace workspace prev'
alt-n = 'exec-and-forget aerospace list-workspaces --monitor focused --empty no | aerospace workspace next'

As far as I've read here and in https://github.com/nikitabobko/AeroSpace/issues/264, this is supposed to help with that, no?

bioe007 commented 1 month ago

+1 to the lua idea and just adding something (possibly obvious) but several very powerful tiling wms in the linux space (i3 and awesomewm) have

I was around in the pre-lua awesome wm days and the syntax included shelling things out as described here - it was hairy stuff.

Lua's syntax for a basic aerospace config would be arguably simple than the current toml.

karadnik-flutterint commented 2 weeks ago

Hi there, noob question: Why not give the user opportunity to write a swift function instead? I guess, one obvious cons would be that not many people know swift, but still, if you want badly enough some feature, you will be able to stitch together a function.

jakenvac commented 1 week ago

@karadnik-flutterint you can already do this by creating a fork