-from gi.repository import Gtk
+# nix-env-apps: Manage declarative nix-env with a GUI
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, version 3.
+
import os
import subprocess
+from typing import Any, Callable
import gi
gi.require_version("Gtk", "4.0")
+from gi.repository import Gtk # nopep8 pylint: disable=wrong-import-position
-def on_edit(_):
+def on_edit(_: Any) -> None:
config_dir = os.path.join(
os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
'nixpkgs',
os.makedirs(config_dir, exist_ok=True)
config_file = os.path.join(config_dir, 'userPackages.nix')
try:
- with open(config_file, mode="x") as f:
+ with open(config_file, mode="x", encoding='utf-8') as f:
f.write('''final: prev: {
userPackages = final.buildEnv {
name = "userPackages";
- paths = (with final; [
+ paths = with final; [
subprocess.run(['xdg-open', config_file], check=True)
-def try_exec_terminal(terminal, args):
+def try_exec_terminal(terminal: str, args: list[str]) -> None:
try:
os.execvp(terminal, [terminal] + args)
except FileNotFoundError:
pass
-def on_apply(_):
+def on_apply(_: Any) -> None:
command = ['nix-env', '-riA', 'nixos.userPackages']
command_string = ' '.join(command)
- close_string = ''' && read -p "SUCCESS: Press ENTER to close this window" || read -p "FAILURE: Press ENTER to close this window"'''
+ close_string = (
+ ''' && read -p "SUCCESS: Press ENTER to close this window"''' +
+ ''' || read -p "FAILURE: Press ENTER to close this window"''')
# This should be a simple `xdg-terminal` invocation, but as of 2025,
# xdg-terminal is extremely broken in Gnome:
# * It doesn't cause a terminal window to appear
os.execvp(command[0], command)
-def on_activate(app):
+def make_button(label: str, action: Callable[[Any], None]) -> Gtk.Button:
+ button = Gtk.Button(label=label)
+ button.connect('clicked', action)
+ button.set_margin_top(10)
+ button.set_margin_start(10)
+ button.set_margin_end(10)
+ button.set_margin_bottom(10)
+ return button
+
+
+def on_activate(app: Gtk.Application) -> None:
win = Gtk.ApplicationWindow(application=app)
+ win.set_title('Apps')
box = Gtk.Box()
box.set_orientation(Gtk.Orientation.VERTICAL)
- edit = Gtk.Button(label="Edit Configuration")
- apply = Gtk.Button(label="Apply Configuration")
- edit.connect('clicked', on_edit)
- apply.connect('clicked', on_apply)
+ edit = make_button("Edit Configuration", on_edit)
+ apply = make_button("Apply Configuration", on_apply)
box.append(edit)
box.append(apply)
win.set_child(box)
win.present()
-def main():
+def main() -> None:
app = Gtk.Application(application_id='net.chkno.nix-env-apps')
app.connect('activate', on_activate)
app.run(None)