Allow multiple programs at once with a config file.
This commit is contained in:
parent
ec8bb73d1c
commit
089fc6fe22
3 changed files with 83 additions and 9 deletions
20
README.md
20
README.md
|
@ -2,6 +2,26 @@
|
||||||
|
|
||||||
Launch a program and move it to the correct workspace.
|
Launch a program and move it to the correct workspace.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- **simple:** `i3toolwait simple ...`
|
||||||
|
- **config:** `i3toolwait config ...`
|
||||||
|
|
||||||
|
### Simple
|
||||||
|
|
||||||
|
Run only one program.
|
||||||
|
|
||||||
|
### Config
|
||||||
|
|
||||||
|
Run multiple programs by specifying a yaml list of the form:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
- filter: <your filter>
|
||||||
|
workspace: <target workspace>
|
||||||
|
program: <program to execute>
|
||||||
|
```
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
Use the makefile: `INSTALL_BASE=/usr/local/ make install` or install all dependencies
|
Use the makefile: `INSTALL_BASE=/usr/local/ make install` or install all dependencies
|
||||||
|
|
63
i3toolwait
63
i3toolwait
|
@ -6,9 +6,15 @@ import functools
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import yaml
|
||||||
import click
|
import click
|
||||||
import i3ipc
|
import i3ipc
|
||||||
|
|
||||||
|
try:
|
||||||
|
from yaml import CSafeLoader as SafeLoader
|
||||||
|
except ImportError:
|
||||||
|
from yaml import SafeLoader
|
||||||
|
|
||||||
class Expression:
|
class Expression:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
@ -263,25 +269,37 @@ def parse(s: str) -> Expression:
|
||||||
return build_expression(tokens)
|
return build_expression(tokens)
|
||||||
|
|
||||||
|
|
||||||
def window_new(filter, *, workspace, debug):
|
def window_new(configs, debug):
|
||||||
def callback(ipc, e):
|
def callback(ipc, e):
|
||||||
assert e.change == 'new'
|
assert e.change == 'new'
|
||||||
if debug:
|
if debug:
|
||||||
print(json.dumps(e.ipc_data))
|
print(json.dumps(e.ipc_data))
|
||||||
|
for i, cfg in enumerate(configs):
|
||||||
|
filter = cfg['filter']
|
||||||
|
workspace = cfg['workspace']
|
||||||
if filter.reduce(e.ipc_data):
|
if filter.reduce(e.ipc_data):
|
||||||
container_id = e.ipc_data['container']['id']
|
container_id = e.ipc_data['container']['id']
|
||||||
|
ipc.command(f'for_window [con_id="{container_id}"] focus')
|
||||||
ipc.command(f'for_window [con_id="{container_id}"] move container to workspace {workspace}')
|
ipc.command(f'for_window [con_id="{container_id}"] move container to workspace {workspace}')
|
||||||
|
configs.pop(i)
|
||||||
|
if not configs:
|
||||||
ipc.main_quit()
|
ipc.main_quit()
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
@click.command()
|
@click.group()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option('--debug', '-d', default=False, is_flag=True, help="Enable debug mode, will log ipc dictionary.")
|
||||||
|
def main(ctx, debug):
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
ctx.obj['DEBUG'] = debug
|
||||||
|
|
||||||
|
@main.command()
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@click.option('--filter', '-f', default='True', help="A filter expression for the raw ipc dictionary.")
|
@click.option('--filter', '-f', default='True', help="A filter expression for the raw ipc dictionary.")
|
||||||
@click.option('--debug', '-d', default=False, is_flag=True, help="Enable debug mode, will log ipc dictionary.")
|
|
||||||
@click.option('--timeout', '-t', default=3000, help="Wait time for a window to appear (and match) in milliseconds.")
|
@click.option('--timeout', '-t', default=3000, help="Wait time for a window to appear (and match) in milliseconds.")
|
||||||
@click.option('--workspace', '-w', required=True, help="The workspace to move to.")
|
@click.option('--workspace', '-w', required=True, help="The workspace to move to.")
|
||||||
@click.argument('program', nargs=-1)
|
@click.argument('program', nargs=-1)
|
||||||
def main(ctx, filter, debug, timeout, workspace, program):
|
def simple(ctx, filter, timeout, workspace, program):
|
||||||
"""
|
"""
|
||||||
Start a program and move it's created window to the desired i3 workspace.
|
Start a program and move it's created window to the desired i3 workspace.
|
||||||
|
|
||||||
|
@ -290,17 +308,52 @@ def main(ctx, filter, debug, timeout, workspace, program):
|
||||||
0 on success,
|
0 on success,
|
||||||
1 when no window has been found.
|
1 when no window has been found.
|
||||||
"""
|
"""
|
||||||
|
debug = ctx.obj['DEBUG']
|
||||||
filter = parse(filter)
|
filter = parse(filter)
|
||||||
program = ' '.join(program)
|
program = ' '.join(program)
|
||||||
|
|
||||||
|
configs=[
|
||||||
|
{
|
||||||
|
"filter": filter,
|
||||||
|
"workspace": workspace,
|
||||||
|
},
|
||||||
|
]
|
||||||
ipc = i3ipc.Connection()
|
ipc = i3ipc.Connection()
|
||||||
ipc.on('window::new', window_new(filter, workspace=workspace, debug=debug))
|
ipc.on('window::new', window_new(configs, debug=debug))
|
||||||
ipc.command(f'exec {program}')
|
ipc.command(f'exec {program}')
|
||||||
started_at = time.monotonic_ns() // (1000*1000)
|
started_at = time.monotonic_ns() // (1000*1000)
|
||||||
ipc.main(timeout=timeout / 1000)
|
ipc.main(timeout=timeout / 1000)
|
||||||
total_time = time.monotonic_ns() // (1000*1000) - started_at
|
total_time = time.monotonic_ns() // (1000*1000) - started_at
|
||||||
ctx.exit(int(total_time >= timeout))
|
ctx.exit(int(total_time >= timeout))
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
@click.option('--timeout', '-t', default=3000, help="Wait time for a window to appear (and match) in milliseconds.")
|
||||||
|
@click.option('--configs', '-c', default='-', type=click.File('r'), help="A list of startup programs in json")
|
||||||
|
@click.argument('program', nargs=-1)
|
||||||
|
def config(ctx, timeout, configs, program):
|
||||||
|
"""
|
||||||
|
Start a program and move it's created window to the desired i3 workspace.
|
||||||
|
|
||||||
|
\b
|
||||||
|
Exist status:
|
||||||
|
0 on success,
|
||||||
|
1 when no window has been found.
|
||||||
|
"""
|
||||||
|
debug = ctx.obj['DEBUG']
|
||||||
|
program = ' '.join(program)
|
||||||
|
configs = yaml.load(configs, Loader=SafeLoader)
|
||||||
|
|
||||||
|
ipc = i3ipc.Connection()
|
||||||
|
ipc.on('window::new', window_new(configs, debug=debug))
|
||||||
|
|
||||||
|
for cfg in configs:
|
||||||
|
cfg['filter'] = parse(cfg['filter'])
|
||||||
|
ipc.command(f'exec {cfg["program"]}')
|
||||||
|
started_at = time.monotonic_ns() // (1000*1000)
|
||||||
|
ipc.main(timeout=timeout / 1000)
|
||||||
|
total_time = time.monotonic_ns() // (1000*1000) - started_at
|
||||||
|
ctx.exit(int(total_time >= timeout))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
click
|
click
|
||||||
i3ipc
|
i3ipc
|
||||||
|
pyyaml
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue