switch back to zsh

I like `xonsh` and all, but integrating it with neovim without incurring
a major performance penalty is difficult to say the least. I think
switching back to `zsh` is my best option to solve this issue for now.
This commit is contained in:
cswimr 2025-02-04 11:39:40 -06:00
parent 184afebce1
commit 95ac8522db
Signed by: cswimr
GPG key ID: 0EC431A8DA8F8087
9 changed files with 362 additions and 14 deletions

View file

@ -4,8 +4,7 @@ Hi there! This repository contains my NixOS flake. This is mainly meant as a uti
## Notes
- This configuration offers [`xonsh`](https://xon.sh) as the default shell. You can change this in [`shell.nix`](https://www.coastalcommits.com/cswimr/flake/src/branch/master/nixos/shell.nix). This also includes a [`starship`](https://starship.rs) prompt.
- Currently, [`shell.nix`](https://www.coastalcommits.com/cswimr/flake/src/branch/master/nixos/shell.nix) contains a bandaid fix to make the `starship` prompt load properly. This will become unnecessary when [`github:NixOS/nixpkgs#359614`](https://github.com/NixOS/nixpkgs/pull/359614) is merged.
- This configuration offers [`zsh`](https://www.zsh.org) as the default shell. You can change this in [`shell.nix`](https://www.coastalcommits.com/cswimr/flake/src/branch/master/nixos/shell.nix). This also includes a [`starship`](https://starship.rs) prompt.
- The Tailscale configuration requires you to create a file at `/run/secrets/tailscale` with your Tailscale registration key. This is only required on first-time setup, and the file will automatically be removed after the next system restart.
- This repository manages secrets using [`sops-nix`](https://github.com/Mic92/sops-nix).
@ -13,7 +12,6 @@ Hi there! This repository contains my NixOS flake. This is mainly meant as a uti
This list contains a bunch of applications and tools that I use a lot. Some of these will have configs declared in this repository, while others may not.
- [xonsh](https://xon.sh) ([Module](https://www.coastalcommits.com/cswimr/flake/src/branch/master/nixos/shell.nix) | [Config](https://www.coastalcommits.com/cswimr/flake/src/branch/master/config/xonsh)): A Python-based shell that I use as my default shell. It's incredibly powerful, as all of its configuration is done in a superset of Python that shares the xonsh name. The main caveat is that it's slower than other shells, due to being written in Python. However, the power and flexibility it offers more than make up for this in my opinion.
- [uv](https://astral.sh/uv): So, I develop most of my projects with Python. I used to use a lot of tools like Poetry, pipx, and virtualenv. I had also heard of others like PDM and pyenv. uv does what those tools do, but better. It's effortless to use, and is so incredibly fast. Like, it's actually insane just how fast this tool is, compared to Poetry.
- [ruff](https://astral.sh/ruff): Again, as a primarily Python developer, I used to use pylint a lot. Unfortunately I do still have to, but only because ruff doesn't yet have feature comparability to pylint. However, it is blazingly fast, just like its brother uv. A codebase that takes plint about ~55 seconds to lint, takes ruff less than a second. It is kind of insane how fast this linter is, sometimes I don't know if it's working or not in my IDE just because it updates so fast.
- [neovim](https://neovim.io/) ([Module](https://www.coastalcommits.com/cswimr/flake/src/branch/master/nixos/nvim.nix)): A Vim-based text editor that I'm actually using to write this list!

View file

@ -2,6 +2,9 @@
programs.kitty = {
enable = true;
themeFile = "Catppuccin-Mocha";
shellIntegration = {
mode = "no-rc";
};
settings = {
# tab bar styling
tab_bar_min_tabs = 1;
@ -14,7 +17,7 @@
inactive_tab_foreground = "#1e1e2e";
inactive_tab_background = "#b4befe";
inactive_tab_font_style = "normal";
tab_title_template = "{title.removeprefix('/run/current-system/sw/bin/nix-shell-info | ')}{' ({})'.format(num_windows) if num_windows > 1 else ''}";
tab_title_template = "{title}{' ({})'.format(num_windows) if num_windows > 1 else ''}";
enabled_layouts = "grid, tall, stack";

View file

@ -10,7 +10,85 @@
any-nix-shell
];
users.defaultUserShell = pkgs.xonsh;
users.defaultUserShell = pkgs.zsh;
programs.zsh = {
enable = true;
enableBashCompletion = true;
enableCompletion = true;
autosuggestions.enable = true;
syntaxHighlighting.enable = true;
shellInit = # zsh
''
# Directory containing the Python scripts
SCRIPT_DIR="/etc/nixos/scripts/py"
# Ensure the directory exists
if [[ ! -d "$SCRIPT_DIR" ]]; then
echo "Directory $SCRIPT_DIR does not exist."
return 1
fi
# Register aliases for each .py file in the directory
for script in "$SCRIPT_DIR"/*.py; do
[[ -f "$script" ]] || continue # Skip if no .py files found
script_name="''${script##*/}" # Extract filename
alias_name="''${script_name%.py}" # Strip .py extension
alias "$alias_name"="\"$script\""
done
_edit() {
local args=("$@")
if [[ ''${#args[@]} -eq 0 ]]; then
args=(".")
fi
if [[ -n "$SSH_CONNECTION" ]]; then
command "$EDITOR" "''${args[@]}"
else
command "$VISUAL" "''${args[@]}"
fi
}
'';
shellAliases = {
ff = "fastfetch";
neofetch = "fastfetch";
nf = "fastfetch";
lg = "lazygit";
lad = "lazydocker";
clip = "wl-copy";
clp = "clip";
paste = "wl-paste";
cat = "bat";
git = "hub";
cc = "fj --host=https://www.coastalcommits.com --style=fancy";
cb = "fj --host https://codeberg.org --style=fancy";
eza = "--time-style=long-iso --icons=auto --hyperlink";
l = "eza -lhg";
la = "eza -lAh";
ll = "l";
ls = "eza";
lsa = "eza -lah";
tree = "eza --tree --git-ignore";
nixpkgs-update = "nix run ;--option extra-substituters 'https://nix-community.cachix.org/' --option extra-trusted-public-keys 'nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=' github:ryantm/nixpkgs-update --";
nixrc = "edit /etc/nixos";
taildrop = "tailscale file";
forgejo-runner = "act_runner";
runactions = "act_runner exec --default-actions-url=https://www.coastalcommits.com --gitea-instance=https://www.coastalcommits.com";
uvr = "uv run";
ns = "nix-shell";
edit = "_edit";
e = "edit";
c = "clear";
sudo = "sudo ";
s = "sudo";
};
histSize = 10000;
histFile = "$HOME/.zsh_history";
};
programs.xonsh =
let
bashcfg = config.programs.bash;

View file

@ -0,0 +1,49 @@
# SGR color constants
# rene-d 2018
# https://gist.github.com/rene-d/9e584a7dd2935d0f461904b9f2950007
class Colors:
"""ANSI color codes"""
BLACK = "\033[0;30m"
RED = "\033[0;31m"
GREEN = "\033[0;32m"
BROWN = "\033[0;33m"
BLUE = "\033[0;34m"
PURPLE = "\033[0;35m"
CYAN = "\033[0;36m"
LIGHT_GRAY = "\033[0;37m"
DARK_GRAY = "\033[1;30m"
LIGHT_RED = "\033[1;31m"
LIGHT_GREEN = "\033[1;32m"
YELLOW = "\033[1;33m"
LIGHT_BLUE = "\033[1;34m"
LIGHT_PURPLE = "\033[1;35m"
LIGHT_CYAN = "\033[1;36m"
LIGHT_WHITE = "\033[1;37m"
BOLD = "\033[1m"
FAINT = "\033[2m"
ITALIC = "\033[3m"
UNDERLINE = "\033[4m"
BLINK = "\033[5m"
NEGATIVE = "\033[7m"
CROSSED = "\033[9m"
END = "\033[0m"
# cancel SGR codes if we don't write to a terminal
if not __import__("sys").stdout.isatty():
for _ in dir():
if isinstance(_, str) and _[0] != "_":
locals()[_] = ""
else:
# set Windows console in VT mode
if __import__("platform").system() == "Windows":
kernel32 = __import__("ctypes").windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
del kernel32
if __name__ == "__main__":
for i in dir(Colors):
if i[0:1] != "_" and i != "END":
print("{:>16} {}".format(i, getattr(Colors, i) + i + Colors.END))

View file

@ -3,6 +3,50 @@ import subprocess
from pathlib import Path
from shutil import which
from common.colors import Colors as c
def format_link(link: str, text: str) -> str:
return f"\033]8;;{link}\033\\{text}\033]8;;\033\\"
def get_environment() -> dict[str, str]:
env = dict(os.environ)
env["DIRENV_DISABLE"] = "1"
return env
def run(
cmd: list[str],
cwd: Path = Path.cwd(),
exit_on_error: bool = True,
env: dict[str, str] | None = None,
**kwargs,
) -> subprocess.CompletedProcess:
if not env:
env = get_environment()
print(f"{c.GREEN}Running command: {c.PURPLE}'{' '.join(cmd)}'{c.END}")
if cwd != Path.cwd():
print(
f"{c.GREEN} 󱞩 in directory: {c.YELLOW}'{format_link(link='file://' + str(cwd), text=cwd)}'{c.END}"
)
result = subprocess.run(cmd, cwd=cwd, check=False, env=env, **kwargs)
if result.returncode != 0:
print(
f"{c.RED}Command exited with non-zero exit code {c.CYAN}{c.BOLD}{result.returncode}{c.END}"
)
if exit_on_error is True:
result.check_returncode()
else:
print(
f"{c.GREEN}Command exited with exit code {c.CYAN}{c.BOLD}{result.returncode}{c.END}"
)
return result
def notify(
application_name: str,
@ -30,7 +74,7 @@ def notify(
args.append(title)
args.append(message)
print(args)
subprocess.run(args)
run(cmd=args)
def read_secret_file(secret: str, home: bool = False) -> str:
@ -57,8 +101,8 @@ def does_desktop_entry_exist(desktop_entry: str, show_all_paths: bool = True) ->
entry_paths = []
if which("qtpaths"):
result = subprocess.run(
["qtpaths", "--paths", "ApplicationsLocation"],
result = run(
cmd=["qtpaths", "--paths", "ApplicationsLocation"],
stdout=subprocess.PIPE,
text=True,
)
@ -73,7 +117,7 @@ def does_desktop_entry_exist(desktop_entry: str, show_all_paths: bool = True) ->
if show_all_paths:
print(
f"Checking the following paths for {desktop_entry}:\n{entry_paths}\n{'-'*20}"
f"Checking the following paths for {desktop_entry}:\n{entry_paths}\n{'-' * 20}"
)
for entry_path in entry_paths:

0
scripts/py/edit.py Normal file
View file

View file

@ -8,7 +8,7 @@ import tempfile
from pathlib import Path
from shutil import which
from common.common import notify # type: ignore
from common.common import notify, run
from PySide6.QtGui import QImageWriter # type: ignore
@ -56,7 +56,7 @@ def spectacle_screenshot(
"--pointer",
"--copy-image",
"--output",
file_path,
str(file_path),
]
if record:
@ -65,7 +65,7 @@ def spectacle_screenshot(
command.append("--region")
try:
subprocess.run(command, check=True) # type: ignore
run(command)
except subprocess.CalledProcessError as e:
if Path(file_path).exists() and use_temp_file:
os.remove(file_path)
@ -78,7 +78,7 @@ def spectacle_screenshot(
try:
opts = [
"/etc/nixos/scripts/py/zipline.py",
file_path,
str(file_path),
"--application-name",
"Spectacle",
"--desktop-entry",
@ -86,7 +86,7 @@ def spectacle_screenshot(
]
if url:
opts.extend(["--url", url])
subprocess.run(opts) # type: ignore
run(cmd=opts) # type: ignore
finally:
if Path(file_path).exists() and use_temp_file:
os.remove(file_path)

135
scripts/py/upd.py Executable file
View file

@ -0,0 +1,135 @@
#! /usr/bin/env nix-shell
#! nix-shell /etc/nixos/scripts/nix/python.nix -i python
from argparse import ArgumentParser
from pathlib import Path
from socket import gethostname
from common.colors import Colors as c
from common.common import run
def _upd(
subcommand: str = "switch",
pull: bool = False,
lock: bool = False,
rewrite_hardware_configuration: bool = False,
purge_vscode_extensions: bool = False,
extra_args: list = [],
):
path = Path("/etc/nixos")
if subcommand not in ("switch", "boot", "test", "build-vm"):
raise ValueError(f"{subcommand} is not a valid subcommand!")
if path.exists():
files_to_delete = {
"Visual Studio Code user settings": ".config/Code/User/settings.json.bak",
"fontconfig": ".config/fontconfig/conf.d/10-hm-fonts.conf.bak",
}
if pull:
print(
f"{c.BLUE}Pulling {c.YELLOW}NixOS{c.BLUE} configuration from remote{c.END}"
)
run(["git", "pull"], cwd=path)
if lock:
print(f"{c.BLUE}Updating {c.YELLOW}Nix Flake{c.BLUE} lock file{c.END}")
run(["nix", "flake", "update", *extra_args], cwd=path)
if rewrite_hardware_configuration:
print(
f"{c.BLUE}Updating {c.YELLOW}NixOS{c.BLUE} hardware configuration file for {c.YELLOW}{gethostname()}{c.BLUE}{c.END}"
)
run(
[
"sudo",
"nixos-generate-config",
"--dir",
".",
],
cwd=path / "hosts",
)
print(
f"{c.BLUE}Deleting redundant {c.YELLOW}NixOS{c.BLUE} configuration file{c.END}"
)
run(["sudo", "rm", "configuration.nix"], cwd=path / "hosts")
print(
f"{c.BLUE}Moving {c.YELLOW}NixOS{c.BLUE} hardware configuration file{c.END}"
)
run(
[
"sudo",
"mv",
"hardware-configuration.nix",
"{hostname}.nix".format(hostname=gethostname()),
],
cwd=path / "hosts",
)
print(
f"{c.BLUE}Adding {c.YELLOW}NixOS{c.BLUE} hardware configuration file for {c.YELLOW}{gethostname()}{c.BLUE} to git{c.END}"
)
run(
["git", "add", "hosts/{hostname}.nix".format(hostname=gethostname())],
cwd=path,
)
for file_description, file_path in files_to_delete.items():
print(
f"{c.BLUE}Deleting {c.YELLOW}{file_description}{c.BLUE} backup file{c.END}"
)
run(["rm", file_path], exit_on_error=False, cwd="/home/cswimr")
if purge_vscode_extensions:
print(
f"{c.BLUE}Killing {c.YELLOW}Visual Studio Code{c.BLUE} processes{c.END}"
)
run(["killall", "code"], exit_on_error=False)
print(
f"{c.BLUE}Purging {c.YELLOW}Visual Studio Code{c.BLUE} extensions{c.END}"
)
run(["rm", "-rf", ".vscode/extensions"], cwd="/home/cswimr")
print(f"{c.BLUE}Rebuilding {c.YELLOW}NixOS{c.BLUE} configuration{c.END}")
# TODO: Remove --impure once the Starship module is merged - see ../../nixos/shell.nix for more information
extra_args.append("--impure")
if "--impure" in extra_args:
print(f"{c.RED}WARNING: The --impure flag is set!{c.END}")
run(["sudo", "nixos-rebuild", subcommand, *extra_args], cwd=path)
if __name__ == "__main__":
parser = ArgumentParser(
prog="upd.py",
description="Update your NixOS system via a convenient wrapper script.",
epilog="Example usage: upd.py",
)
parser.add_argument(
"--subcommand",
help="Which subcommand of `nixos-rebuild` to run.",
default="switch",
)
parser.add_argument(
"--pull",
help="If this is set, the script will run `git pull` in the flake directory before updating.",
action="store_true",
)
parser.add_argument(
"--lock",
help="If this is set, `nix flake update` will be ran before the system is updated.",
action="store_true",
)
parser.add_argument(
"--rewrite-hardware-configuration",
help="If this is set, `nixos-generate-config` will be ran before the system is updated.",
action="store_true",
)
parser.add_argument(
"--purge-vscode-extensions",
help="If this is set, extensions in the `~/.vscode/extensions` folder will be deleted before the system is updated.",
action="store_true",
)
args = parser.parse_args()
_upd(
subcommand=args.subcommand,
pull=args.pull,
lock=args.lock,
rewrite_hardware_configuration=args.rewrite_hardware_configuration,
purge_vscode_extensions=args.purge_vscode_extensions,
# extra_args = args.extra_args
)

41
scripts/py/vm.py Executable file
View file

@ -0,0 +1,41 @@
#! /usr/bin/env nix-shell
#! nix-shell /etc/nixos/scripts/nix/python.nix -i python
from argparse import ArgumentParser
from pathlib import Path
from common.colors import Colors as c
from common.common import run
def _vm(name: str = "nixpkgs", args: list = []):
if name == "nixpkgs":
args.extend(["-I", "nixpkgs=/bulk/home/cswimr/Projects/nixpkgs"])
path = Path(f"/etc/nixos/hosts/virtual-machines/{name}")
if path.exists():
if (path / "flake.nix").exists():
args.extend(["--flake", f"{path}#nixos"])
elif (path / "default.nix").exists():
args.extend(["-I", f"nixos-config={path}/default.nix", "--no-flake"])
print(f"{c.BLUE}Building virtual machine {c.YELLOW}{name}{c.END}")
run(["nixos-rebuild", "build-vm", *args], cwd=path)
print(f"{c.BLUE}Starting virtual vachine {c.YELLOW}{name}{c.END}")
run(["./result/bin/run-nixos-vm"], cwd=path)
print(
f"{c.BLUE}Virtual machine {c.YELLOW}{name} {c.BLUE}has {c.RED}stopped.{c.END}"
)
else:
raise FileNotFoundError(f"Virtual machine {name} does not exist.")
if __name__ == "__main__":
parser = ArgumentParser(
prog="vm.py",
description="Run a NixOS virtual machine from the system flake.",
epilog="Example usage: vm.py nixpkgs",
)
parser.add_argument("name", help="Which virtual machine to run.")
args = parser.parse_args()
_vm(name=args.name)