Skip to content

Commit

Permalink
Enable argument interpolation for command mappings
Browse files Browse the repository at this point in the history
Closes #61
  • Loading branch information
JonnyHaystack committed Nov 16, 2019
1 parent 33f7d61 commit 4b00667
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 25 deletions.
58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A simple but flexible solution to saving and restoring i3 workspaces
* [Requirements](#requirements)
* [Installation](#installation)
* [Usage](#usage)
* [Configuration](#configuration)
* [Configuration](#configuration)
* [Contributing](#contributing)
* [Contributors](#contributors)
* [License](#license)
Expand Down Expand Up @@ -323,12 +323,12 @@ Example of usage with the second configuration:

[![Example of usage with the second configuration](https://i.imgur.com/mi9Uml8.gif)](https://gfycat.com/selfreliantdarkkoodoo)

### Configuration
## Configuration

The config file should be located at `~/.config/i3-resurrect/config.json`.
A default config file will be created when you first run i3-resurrect.

#### Window command mappings
### Window command mappings

In the case of a window where the process `cmdline` is not the same as the
command you must run to launch that program, you can add an explicit window
Expand Down Expand Up @@ -363,17 +363,18 @@ if it also matches a certain title:
```
{
...
"window_command_mappings": [
...
{
"class": "Some-program",
},
{
"class": "Some-program",
"title": "Main window's title"
}
...
]
"window_command_mappings": [
...
{
"class": "Some-program"
},
{
"class": "Some-program",
"title": "Main window's title",
"command": ["some-program", "arg1", "arg2"]
}
...
]
...
}
```
Expand All @@ -382,7 +383,32 @@ Hint:
If you need to find out a window's class/instance, type `xprop | grep WM_CLASS`
in a terminal and then click on the desired window.

#### Terminals
#### Argument interpolation

You can also interpolate arguments from the actual process's cmdline into a
custom command mapping using Python format specifiers. For example:

Command mapping:
```
{
...
"window_command_mappings": [
...
{
"class": "Code",
"command": "code -n {1}"
}
...
]
...
}
```

Actual cmdline: `['code', '/path/to/file.txt']`

Resulting command that gets saved: `code -n /path/to/file.txt`

### Terminals

For terminal emulator windows, we must get the working directory from the
first subprocess (usually this will be your shell) instead of the window's root
Expand Down Expand Up @@ -410,7 +436,7 @@ Some examples are included in the default config. If you would like me to add
more command mappings or terminals to the default config, please open an issue
for it.

#### Per window swallow criteria
### Per window swallow criteria

It is also possible to configure swallow criteria on a per window basis, which
will override the criteria set by the `--swallow` command line parameter.
Expand Down
25 changes: 19 additions & 6 deletions i3_resurrect/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,31 @@ def get_window_command(window_properties, cmdline):

# Find the mapping that gets the highest score.
current_score = 0
best_match = None
for rule in window_command_mappings:
# Calculate score.
score = calc_rule_match_score(rule, window_properties)

if score > current_score:
current_score = score
if 'command' not in rule:
command = []
elif isinstance(rule['command'], list):
command = rule['command']
else:
command = shlex.split(rule['command'])
best_match = rule

# If no match found, just use the original cmdline.
if best_match is None:
return command

try:
if 'command' not in best_match:
command = []
elif isinstance(best_match['command'], list):
command = [arg.format(*cmdline) for arg in best_match['command']]
else:
command = shlex.split(best_match['command'].format(*cmdline))
except IndexError:
util.eprint('IndexError occurred while processing command mapping:\n'
f' Mapping: {best_match}\n'
f' Process cmdline: {cmdline}')

return command


Expand Down
20 changes: 17 additions & 3 deletions tests/test_programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ def test_get_window_command(monkeypatch):
'command': 'run_program1'
},
{
'title': 'Some arbitrary title'
'title': 'Some arbitrary title',
},
{
'class': 'Program4',
'command': 'run_program4 {1}'
}
],
},
Expand All @@ -27,7 +31,7 @@ def test_get_window_command(monkeypatch):
# Test class + title mapping.
program1_main = {
'class': 'Program1',
'title': 'Main window title'
'title': 'Main window title',
}
assert programs.get_window_command(program1_main, ['program1']) == [
'run_program1',
Expand All @@ -36,7 +40,7 @@ def test_get_window_command(monkeypatch):
# Test class only mapping.
program1_secondary = {
'class': 'Program1',
'title': 'Blah random title'
'title': 'Blah random title',
}
assert programs.get_window_command(program1_secondary, ['program1']) == []

Expand All @@ -53,3 +57,13 @@ def test_get_window_command(monkeypatch):
'title': 'Some arbitrary title',
}
assert programs.get_window_command(program3, ['program3']) == []

# Test cmdline arg interpolation.
program4 = {
'class': 'Program4',
'title': 'Blah random title',
}
assert programs.get_window_command(
program4,
['/opt/Program4/program4', '/tmp/test.txt'],
) == ['run_program4', '/tmp/test.txt']

0 comments on commit 4b00667

Please sign in to comment.