Ohmyi3
Ohmyi3 provides a dynamic template engine for your i3 configs providing variable
and conditional driven i3 settings.
Ideal for those that use i3 on many of their systems and want to maintain a single
global repository that morphs to each computers environment based on hostname, user
and any other dynamic variable.
Features
- Single
~/.config/ohmyi3/config.py
to dynamic variables to i3 configs
- One set of configs morphs based on your hostname, desktop environment or any variable you care to define.
- Uses python jinja2 templates to add variables and conditions to your i3 [or any] configs
- Plugins and hooks allow you to control all aspects of your system from a single config
- Not only can you template dynamic i3 configs, but you can also:
- Template alacritty, polybar, nitrogen, feh and anything else...its all python and jinja2, limitless
- Powered by https://github.com/uvicore/framework
Installation
pipx install ohmyi3
- Initialize a fresh ohmyi3 config. This creates a
~/.config/ohmyi3
and
populates it with a good set of defaults you can work with.
i3ctl init
-
Modify the stock ~/.config/ohmyi3/config.d/*
i3 configs to suit your needs.
Add any *.conf
file you want. They are all picked up in alphabetical order.
-
The theme
variable picks the theme from ~/.config/ohmyi3/themes
folder.
Bring your own themes.
-
NOTICE: Review and modify stock ~/.config/ohmyi3/config.py
configuration. This is
just a stock example. DO NOT run it as is. You need to tune this to fit your
system. All of the variables defined in that file will be available as jinja2
variables when templating i3 and the rest of your system.
Pay special attention to the after_generate
hooks. You will want to comment
those out and use them as needed. To review the plugin code see the
~/.config/ohmyi3/plugins
directory. Plugins are very simple system
modification scripts. Please review and write your own to suit your needs.
-
Once you have tuned your variables, you can see the resulting dictionary
i3ctl info
- If you like all the variables, and have used the plugins with caution
you can now run the generator to template
~/.config/ohmyi3/config.d/*
i3 configs
which will output a new i3 file to ~/.config/i3/config
(it WILL save a backup
to that same folder before it overrides a new file)
i3ctl generate
Example CLI Output
:: Generating new i3 config using ohmyi3 ::
+ Firing user defined before_generate hook
* Backing up /home/mreschke/.config/i3/config to /home/mreschke/.config/i3/backup-2023-04-20_17-36-41
- Appending /home/mreschke/.files/configs/i3/config.d/00-header.conf
- Appending /home/mreschke/.files/configs/i3/config.d/05-system.conf
- Appending /home/mreschke/.files/configs/i3/config.d/10-autostart.conf
- Appending /home/mreschke/.files/configs/i3/config.d/15-borders.conf
- Appending /home/mreschke/.files/configs/i3/config.d/20-navigation.conf
- Appending /home/mreschke/.files/configs/i3/config.d/80-applications.conf
- Appending /home/mreschke/.files/configs/i3/config.d/85-windows.conf
- Appending /home/mreschke/.files/configs/i3/config.d/90-gaps.conf
* Appending THEME pink
* Copying /home/mreschke/.files/configs/i3/themes/i3status.conf to /home/mreschke/.config/i3status/config
+ Firing user defined after_generate hook
> Plugin Nitrogen: nitrogen --save --set-zoom-fill /home/mreschke/Wallpaper/De/budgie.jpg > /dev/null 2>&1
> Plugin Archey3: sed -i 's/archey3.*/archey3 -c magenta/g' ~/.zshrc
> Plugin Archey3: sed -i 's/archey3.*/archey3 -c magenta/g' ~/.bashrc
> Plugin Polybar: Templating /home/mreschke/.files/configs/polybar/qpanels/panel/deepin.j2.ini
> Plugin Alacritty: Templating /home/mreschke/.files/configs/alacritty/alacritty.j2.yml
Done!
New /home/mreschke/.config/i3/config generated!
Please reload i3!
Most Basic Example
If your ~/.config/ohmyi3/config.py
looked like this
...
def config():
host = util.hostname()
theme = 'archlinux'
...
And you had only a single file ~/config/ohmyi3/config.d/01-test.conf
# My dynamic i3 config
Your hostname is {{ host }}
{% if host == 'sunjaro' %}
Add i3 configs specifically for {{ host }}
{% endif %}
I love the {{ theme }} theme
After running i3ctl generate
, your final ~/.config/i3/config
would look like this
# My dynamic i3 config
Your hostname is sunjaro
Add i3 configs specifically for sunjaro
I love the archlinux theme
Sample the Power
~/.config/ohmyi3/config.py
import uvicore
from ohmyi3 import util
from uvicore.typing import Dict
from uvicore.configuration import env
from uvicore.support.dumper import dump, dd
from ohmyi3.util import set, gather, path, plugin
def config():
"""Ohmyi3 variables for configuring and templating i3"""
host = util.hostname()
user = util.loggedinuser()
ohmyi3_path = uvicore.config('ohmyi3.config_path')
paths = set({
'ohmyi3': path(ohmyi3_path),
'ohmyi3_configd': path([ohmyi3_path, 'config.d']),
'ohmyi3_themes': path([ohmyi3_path, 'themes']),
'i3': path('~/.config/i3'),
'i3status': path('~/.config/i3status'),
'alacritty': path('~/.config/alacritty'),
'polybar': path('~/.config/polybar'),
})
os = set('manjaro', host, {
'p14s': 'lmde',
})
net_interface = set('enp11s0', host, {
'p15': 'enp11s0',
'p53': 'wlp0s20f3',
'deajaro': 'wlp2s0',
})
has_battery = set(True, host, {
'sunjaro': False,
'p53': True,
'p15': True,
'p14s': True,
})
battery_device = set('BAT0')
backlight_device = set('intel_backlight')
desktop = set('i3', host, {
'sunjaro': 'kde',
'p53': 'i3',
'p15': 'i3',
})
desktop_tools = set('kde', host, {
'deajaro': 'xfce'
})
i3_gaps = set(True, host, {
'p14s': False
})
i3_restart = set('~/.files/scripts/i3ctl-dev generate && i3-msg restart', host, {
'deajaro': 'i3ctl generate && i3-msg restart',
'p14s': '/home/mreschke/.pyenv/shims/i3ctl generate && i3-msg restart',
})
wallpaper_base = set('~/Wallpaper', host, {
'sunjaro': '~/Pictures/Wallpaper',
'p53': '~/Pictures/Wallpaper',
})
theme = set('manjaro', host, {
'sunjaro': 'manjaro',
'p53': 'manjaro',
'p15': 'amber',
'p14s': 'manjaro',
})
themes = set({
'amber': {
'color': '#EF5B1A',
'archey3': 'yellow',
},
'archlinux': {
'color': '#1793D1',
'archey3': 'blue',
'wallpaper': 'De/budgie.jpg',
},
'manjaro': {
'color': '#106E5C',
'archey3': 'green',
'wallpaper': 'De/deepin.jpg',
},
'pink': {
'color': '#b41474',
'archey3': 'magenta',
'wallpaper': 'De/deepin.jpg',
},
},
host, {
}
)
polybar = set({
'enabled': True,
'theme': 'qpanels',
'subtheme': 'deepin'
}, host, {
'p14s': {'enabled': False},
})
rofi = set({
'launcher': f'~/.config/polybar/{polybar.theme}/scripts/launcher.sh --{polybar.subtheme}',
'powermenu': f'~/.config/polybar/{polybar.theme}/scripts/powermenu.sh --{polybar.subtheme}',
}, host, {
'p14s': {'launcher': 'rofi -show drun'}
})
alacritty = set({
'font_size': '9.0',
}, host, {
'p15': {'font_size': '8.0'}
})
font = set('xft:URWGothic-Book 9')
tasktray = set({
'enabled': True,
'position': 'right',
})
bar = set({
'enabled': False,
'cmd': 'i3bar --transparency',
'status_cmd': 'i3status',
'position': 'bottom',
'font': 'xft:URWGothic-Book 8',
'mode': 'dock',
'hidden_state': 'hide',
'modifier': 'none',
},
desktop != 'i3', {
'mode': 'hide'
},
host, {
'p15': {'position': 'top'},
'p14s': {'enabled': True},
},
)
apps = set({
'terminal': 'alacritty',
'webbrowser': 'firefox',
'webbrowser2': 'chromium',
'dmenu': set(path('~/.files/scripts/dmenu-run-blue'),
theme, {'manjaro': path('~/.files/scripts/dmenu-run-green')
}),
'htop': 'htop',
'bashtop': 'bashtop',
'codeeditor': 'code',
'screenlock': 'blurlock',
'powermanager': 'xfce4-power-manager',
'powermanagersettings': 'xfce4-power-manager-settings',
'spotify': 'spotify',
'networkeditor': 'nm-connection-editor',
},
desktop_tools=='kde', {
'filemanager': 'dolphin',
'calculator': 'kcalc',
'settings': 'systemsettings',
'taskmanager': 'ksysguard',
'screenshot': 'spectacle',
'colorpicker': 'kcolorchooser',
'notepad': 'kate',
},
desktop_tools=='xfce', {
'filemanager': 'thunar',
'calculator': 'galculator',
'settings': 'xfce4-settings-manager',
'taskmanager': 'xfce4-taskmanager',
'notepad': 'mousepad',
},
desktop_tools=='gnome', {
'filemanager': 'nautilus',
'terminal': 'gnome-terminal',
'calculator': 'gnome-calculator',
})
autostart = set({
'session': set(None, desktop=='i3' and desktop_tools=='xfce', 'exec --no-startup-id xfsettingsd --replace'),
'locker': set(None, desktop=='i3', 'exec_always --no-startup-id xss-lock -- blurlock'),
'polkit': set(None, desktop=='i3', 'exec --no-startup-id /usr/lib/polkit-kde-authentication-agent-1'),
'screen': set(None, desktop=='i3', 'exec --no-startup-id ~/.screenlayout/screen-laptop.sh'),
'powerman': set(None, desktop=='i3', 'exec_always --no-startup-id ' + apps.powermanager),
'bar': set(None, desktop=='i3' and polybar.enabled, 'exec_always --no-startup-id ~/.config/polybar/launch.sh --' + polybar.theme),
'wallpaper': 'exec_always --no-startup-id nitrogen --restore',
'compositor': 'exec_always --no-startup-id picom --config ~/.config/picom/picom.conf -b',
'keyboard': 'exec_always --no-startup-id xset r rate 250 50',
'alttab': 'exec_always --no-startup-id "alttab -w 1 -s 1 -bw 0 -fg \'' + themes[theme].color + '\' -bg \'#0E2229\' -frame \'' + themes[theme].color + '\' -t 128x150 -i 127x64"',
},
tasktray.enabled and desktop=='i3', {
'matray': set(None, os=='manjaro', 'exec --no-startup-id matray'),
'clipman': set('exec --no-startup-id clipit --daemon'),
'netman': set('exec --no-startup-id nm-applet'),
'volume': set('exec --no-startup-id volumeicon'),
},
)
volume = set({
'up': 'amixer -D pulse sset Master 5%+',
'down': 'amixer -D pulse sset Master 5%-',
'mute': 'amixer -D pulse set Master 1+ toggle',
'mixer': 'pavucontrol',
})
media = set({
'play_pause': 'playerctl play-pause',
'next': 'playerctl next',
'previous': 'playerctl previous',
})
brightness = set({
'up': 'brightnessctl -q set 3%+',
'down': 'brightnessctl --min-val=2 -q set 3%-',
})
_vars = gather(locals())
plugins = set({
'nitrogen': plugin('nitrogen.Nitrogen')(_vars),
'archey3': plugin('archey3.Archey3')(_vars),
'polybar': plugin('polybar.Polybar')(_vars),
'alacritty': plugin('alacritty.Alacritty')(_vars),
})
return gather(locals())
async def before_generate(config):
"""This hook fires before the new i3 config is generated"""
util.shell('killall alttab')
async def after_generate(config):
"""This hook fires after the new i3 config is generated"""
Example Info Output
All variables defined in your ~/.config/ohmyi3/config.py
will be available as
a nice SuperDict
to the jinja2 templating engine and used to dynamically control
i3 (and anything else).
Example output from the example config.py
above on my host named p15
i3ctl info
:: Ohmyi3 User Configuration ::
Dict({
'host': 'p15',
'user': 'mreschke',
'ohmyi3_path': '~/.config/ohmyi3',
'paths': Dict({
'ohmyi3': '/home/mreschke/.files/configs/i3',
'ohmyi3_configd': '/home/mreschke/.files/configs/i3/config.d',
'ohmyi3_themes': '/home/mreschke/.files/configs/i3/themes',
'i3': '/home/mreschke/.config/i3',
'i3status': '/home/mreschke/.config/i3status',
'alacritty': '/home/mreschke/.files/configs/alacritty',
'polybar': '/home/mreschke/.files/configs/polybar'
}),
'os': 'manjaro',
'net_interface': 'enp11s0',
'has_battery': True,
'battery_device': 'BAT0',
'backlight_device': 'intel_backlight',
'desktop': 'i3',
'desktop_tools': 'kde',
'i3_gaps': True,
'i3_restart': '~/.files/scripts/i3ctl-dev generate && i3-msg restart',
'wallpaper_base': '~/Wallpaper',
'theme': 'amber',
'themes': Dict({
'amber': Dict({'color': '#EF5B1A', 'archey3': 'yellow'}),
'archlinux': Dict({
'color': '#1793D1',
'archey3': 'blue',
'wallpaper': 'De/budgie.jpg'
}),
'manjaro': Dict({
'color': '#106E5C',
'archey3': 'green',
'wallpaper': 'De/deepin.jpg'
}),
'pink': Dict({
'color': '#b41474',
'archey3': 'magenta',
'wallpaper': 'De/deepin.jpg'
})
}),
'polybar': Dict({
'enabled': True,
'theme': 'qpanels',
'subtheme': 'deepin'
}),
'rofi': Dict({
'launcher': '~/.config/polybar/qpanels/scripts/launcher.sh --deepin',
'powermenu': '~/.config/polybar/qpanels/scripts/powermenu.sh --deepin'
}),
'alacritty': Dict({'font_size': '8.0'}),
'font': 'xft:URWGothic-Book 9',
'tasktray': Dict({'enabled': True, 'position': 'right'}),
'bar': Dict({
'enabled': False,
'cmd': 'i3bar --transparency',
'status_cmd': 'i3status',
'position': 'top',
'font': 'xft:URWGothic-Book 8',
'mode': 'dock',
'hidden_state': 'hide',
'modifier': 'none'
}),
'apps': Dict({
'terminal': 'alacritty',
'webbrowser': 'firefox',
'webbrowser2': 'chromium',
'dmenu': '/home/mreschke/.files/scripts/dmenu-run-blue',
'htop': 'htop',
'bashtop': 'bashtop',
'codeeditor': 'code',
'screenlock': 'blurlock',
'powermanager': 'xfce4-power-manager',
'powermanagersettings': 'xfce4-power-manager-settings',
'spotify': 'spotify',
'networkeditor': 'nm-connection-editor',
'filemanager': 'dolphin',
'calculator': 'kcalc',
'settings': 'systemsettings',
'taskmanager': 'ksysguard',
'screenshot': 'spectacle',
'colorpicker': 'kcolorchooser',
'notepad': 'kate'
}),
'autostart': Dict({
'session': None,
'locker': 'exec_always --no-startup-id xss-lock -- blurlock',
'polkit': 'exec --no-startup-id /usr/lib/polkit-kde-authentication-agent-1',
'screen': 'exec --no-startup-id ~/.screenlayout/screen-laptop.sh',
'powerman': 'exec_always --no-startup-id xfce4-power-manager',
'bar': 'exec_always --no-startup-id ~/.config/polybar/launch.sh --qpanels',
'wallpaper': 'exec_always --no-startup-id nitrogen --restore',
'compositor': 'exec_always --no-startup-id picom --config ~/.config/picom/picom.conf -b',
'keyboard': 'exec_always --no-startup-id xset r rate 250 50',
'alttab':
"exec_always --no-startup-id \"alttab -w 1 -s 1 -bw 0 -fg '#EF5B1A' -bg '#0E2229' -frame '#EF5B1A' -t 128x150 "
"-i 127x64\"",
'matray': 'exec --no-startup-id matray',
'clipman': 'exec --no-startup-id clipit --daemon',
'netman': 'exec --no-startup-id nm-applet',
'volume': 'exec --no-startup-id volumeicon'
}),
'volume': Dict({
'up': 'amixer -D pulse sset Master 5%+',
'down': 'amixer -D pulse sset Master 5%-',
'mute': 'amixer -D pulse set Master 1+ toggle',
'mixer': 'pavucontrol'
}),
'media': Dict({
'play_pause': 'playerctl play-pause',
'next': 'playerctl next',
'previous': 'playerctl previous'
}),
'brightness': Dict({'up': 'brightnessctl -q set 3%+', 'down': 'brightnessctl --min-val=2 -q set 3%-'}),
'plugins': Dict({
'nitrogen': <plugins.nitrogen.nitrogen.Nitrogen object at 0x7f1b2ed359f0>,
'archey3': <plugins.archey3.archey3.Archey3 object at 0x7f1b2ed35960>,
'polybar': <plugins.polybar.polybar.Polybar object at 0x7f1b2ed35ae0>,
'alacritty': <plugins.alacritty.alacritty.Alacritty object at 0x7f1b2ed35930>
})
})