dotfiles

My dotfiles and configs
git clone https://git.dasho.dev/dotfiles.git
Log | Files | Refs | README

commit f8d61dd49e2499a7c80091876e7bb3f051a866cb
Author: Dasho <git@dasho.dev>
Date:   Tue, 27 Jan 2026 06:17:54 +0000

Early Dotfile Fun

Diffstat:
A.gitignore | 2++
ABrewfile | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AJustfile | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME.md | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/backup | 14++++++++++++++
Abin/backup-secrets | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/bootstrap | 46++++++++++++++++++++++++++++++++++++++++++++++
Abin/restore-secrets | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/wizard | 1038+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abrew/leaves.txt | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig/direnv/direnvrc | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig/git/config | 22++++++++++++++++++++++
Aconfig/nvim/init.lua | 353+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig/redbrick/config.toml | 40++++++++++++++++++++++++++++++++++++++++
Azsh/secrets.zsh | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Azsh/zshrc | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 2402 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +private +password diff --git a/Brewfile b/Brewfile @@ -0,0 +1,179 @@ +tap "antoniorodr/lexy" +tap "charmbracelet/tap" +tap "danielgatis/imgcat" +tap "steipete/tap" +# Clone of cat(1) with syntax highlighting and Git integration +brew "bat" +# Draw boxes around text +brew "boxes" +# GNU compiler collection +brew "gcc" +# Resource monitor. C++ version and continuation of bashtop and bpytop +brew "btop" +# Statistics utility to count lines of code +brew "cloc" +# Securely send things from one computer to another +brew "croc" +# Load/unload environment variables based on $PWD +brew "direnv" +# Perl lib for reading and writing EXIF metadata +brew "exiftool" +# Modern, maintained replacement for ls +brew "eza" +# Command-line fuzzy finder written in Go +brew "fzf" +# Open-source, cross-platform JavaScript runtime environment +brew "node" +# Interact with Google Gemini AI models from the command-line +brew "gemini-cli" +# GitHub command-line tool +brew "gh" +# Render markdown on the CLI +brew "glow" +# Open source programming language to build simple/reliable/efficient software +brew "go" +# Tool for glamorous shell scripts +brew "gum" +# CLI email client written in Rust +brew "himalaya" +# Tools and libraries to manipulate images in select formats +brew "imagemagick" +# Modular IRC client +brew "irssi" +# Handy way to save and run project-specific commands +brew "just" +# Rainbows and unicorns in your console! +brew "lolcat" +# Securely transfers data between computers +brew "magic-wormhole" +# CLI tool for saving complete web pages as a single HTML file +brew "monolith" +# Fast, highly customisable system info script +brew "neofetch" +# Ambitious Vim-fork focused on extensibility and agility +brew "neovim" +# General-purpose speech recognition model +brew "openai-whisper" +# Search tool like grep and The Silver Searcher +brew "ripgrep" +# AI coding agent, built for the terminal +brew "opencode" +# Password manager +brew "pass" +# Animated pipes terminal screensaver +brew "pipes-sh" +# Send emails from your terminal +brew "pop" +# Hook preloader +brew "proxychains-ng" +# Run a command when files change +brew "reflex" +# Safe, concurrent, practical language +brew "rust" +# Spreadsheet program for the terminal, using ncurses +brew "sc-im" +# 7-Zip is a file archiver with a high compression ratio +brew "sevenzip" +# Editor of encrypted files +brew "sops" +# Fast, collaborative live terminal sharing over the web +brew "sshx" +# Tool Command Language +brew "tcl-tk" +# Terminal multiplexer +brew "tmux" +# Anonymizing overlay network for TCP +brew "tor", restart_service: :changed +# Use SOCKS-friendly applications with Tor +brew "torsocks" +# Command-line tool for sharing terminal over the web +brew "ttyd" +# Command-line unarchiving tools supporting multiple formats +brew "unar" +# Extremely fast Python package installer and resolver, written in Rust +brew "uv" +# Your CLI home video recorder +brew "vhs" +# Extensible IRC client +brew "weechat" +# Pluggable terminal workspace, with terminal multiplexer as the base feature +brew "zellij" +# Shell extension to navigate your filesystem faster +brew "zoxide" +# UNIX shell (command interpreter) +brew "zsh" +# CLI tool that fetches programming tutorials from "Learn X in Y Minutes" directly into your terminal. +brew "antoniorodr/lexy/lexy" +# A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal. +brew "charmbracelet/tap/crush" +# AI on the command line +brew "charmbracelet/tap/mods" +# A personal key value store πŸ›Ό +brew "charmbracelet/tap/skate" +# A tasty, self-hostable Git server for the command line🍦 +brew "charmbracelet/tap/soft-serve" +# The SSH directory +brew "charmbracelet/tap/wishlist" +# Display images and gifs in your terminal +brew "danielgatis/imgcat/imgcat" +# Grep the GIF. Stick the landing +brew "steipete/tap/gifgrep" +# Google CLI for Gmail, Calendar, Drive, and Contacts +brew "steipete/tap/gogcli" +# Send and read iMessage / SMS from the terminal +brew "steipete/tap/imsg" +cask "font-monaspace" +cask "font-ubuntu-nerd-font" +vscode "benjaminbenais.copilot-theme" +vscode "bmewburn.vscode-intelephense-client" +vscode "github.copilot" +vscode "github.copilot-chat" +vscode "github.remotehub" +vscode "golang.go" +vscode "ms-azuretools.vscode-containers" +vscode "ms-python.debugpy" +vscode "ms-python.python" +vscode "ms-python.vscode-pylance" +vscode "ms-python.vscode-python-envs" +vscode "ms-toolsai.jupyter" +vscode "ms-toolsai.jupyter-keymap" +vscode "ms-toolsai.jupyter-renderers" +vscode "ms-toolsai.vscode-jupyter-cell-tags" +vscode "ms-toolsai.vscode-jupyter-slideshow" +vscode "ms-vscode-remote.remote-containers" +vscode "ms-vscode-remote.remote-ssh" +vscode "ms-vscode-remote.remote-ssh-edit" +vscode "ms-vscode-remote.remote-wsl" +vscode "ms-vscode-remote.vscode-remote-extensionpack" +vscode "ms-vscode.azure-repos" +vscode "ms-vscode.cmake-tools" +vscode "ms-vscode.cpptools" +vscode "ms-vscode.cpptools-extension-pack" +vscode "ms-vscode.cpptools-themes" +vscode "ms-vscode.makefile-tools" +vscode "ms-vscode.remote-explorer" +vscode "ms-vscode.remote-repositories" +vscode "ms-vscode.remote-server" +vscode "openai.chatgpt" +vscode "rust-lang.rust-analyzer" +go "github.com/air-verse/air" +go "golang.org/x/tools/gopls" +go "github.com/golang-migrate/migrate/v4/cmd/migrate" +go "github.com/cespare/reflex" +go "github.com/sqlc-dev/sqlc/cmd/sqlc" +go "honnef.co/go/tools/cmd/staticcheck" +cargo "cross" +cargo "freenet" +flatpak "app.zen_browser.zen" +flatpak "chat.simplex.simplex" +flatpak "com.discordapp.Discord" +flatpak "com.protonvpn.www" +flatpak "com.vivaldi.Vivaldi" +flatpak "io.github.celluloid_player.Celluloid" +flatpak "io.github.flattool.Warehouse" +flatpak "io.github.peazip.PeaZip" +flatpak "io.github.picocrypt.Picocrypt" +flatpak "it.mijorus.smile" +flatpak "org.gimp.GIMP" +flatpak "org.kiwix.desktop" +flatpak "org.telegram.desktop" diff --git a/Justfile b/Justfile @@ -0,0 +1,91 @@ +# Justfile +# ------------------------------------------------------------------------------ +# Dotfiles + secrets workflow +# +# Quick start: +# just bootstrap +# just backup +# just backup-secrets +# +# Notes: +# - This repo is intended to be cloned to: ~/.dotfiles +# - Encrypted archives should be committed ONLY to a private remote +# ------------------------------------------------------------------------------ + +default := "help" + +dotdir := env_var_or_default("DOTFILES_DIR", "~/.dotfiles") +private_dir := "private" + +help: + @echo "" + @echo "Dotfiles & Secrets Commands" + @echo "--------------------------" + @echo "wizard πŸ§™ Interactive wizard for all operations (recommended!)" + @echo "bootstrap Install Homebrew (if needed), brew bundle install, link configs." + @echo "backup Update Brewfile and brew/leaves.txt from current machine." + @echo "backup-secrets Create encrypted archive (GPG/SSH/age/Skate) into private/." + @echo "restore-secrets A Decrypt and restore from archive A." + @echo "link Symlink dotfiles into expected locations (~/.zshrc, ~/.config/direnv/, etc)." + @echo "check Verify core tools exist (direnv, skate, age, just)." + @echo "" + @echo "When to use:" + @echo "- RECOMMENDED: just wizard (interactive, guided experience)" + @echo "- On a NEW machine: just bootstrap && just restore-secrets private/keys-YYYYMMDD.tar.gz.age" + @echo "- After changes: just backup && git commit" + @echo "- Periodically: just backup-secrets && git commit (private repo!)" + @echo "" + +check: + @command -v direnv >/dev/null 2>&1 || (echo "Missing: direnv" && exit 1) + @command -v skate >/dev/null 2>&1 || (echo "Missing: skate" && exit 1) + @command -v age >/dev/null 2>&1 || (echo "Missing: age" && exit 1) + @command -v just >/dev/null 2>&1 || (echo "Missing: just" && exit 1) + @echo "OK" + +# πŸ§™ Interactive wizard - the magical way to manage dotfiles +wizard: + @zsh {{justfile_directory()}}/bin/wizard + +# Alias for wizard +w: wizard +easy: wizard + +# Link configs into expected locations. +link: + @mkdir -p ~/.config/direnv + @mkdir -p ~/.config/git + @mkdir -p ~/.config/nvim + @mkdir -p ~/.config/redbrick + + @ln -snf {{justfile_directory()}}/zsh/zshrc ~/.zshrc + @echo "Linked ~/.zshrc" + @ln -snf {{justfile_directory()}}/config/direnv/direnvrc ~/.config/direnv/direnvrc + @echo "Linked ~/.config/direnv/direnvrc" + @ln -snf {{justfile_directory()}}/config/git/config ~/.gitconfig + @echo "Linked ~/.gitconfig" + @ln -snf {{justfile_directory()}}/config/git/config ~/.config/git/config + @echo "Linked ~/.config/git/config" + @ln -snf {{justfile_directory()}}/config/nvim/init.lua ~/.config/nvim/init.lua + @echo "Linked ~/.config/nvim/init.lua" + @ln -snf {{justfile_directory()}}/config/redbrick ~/.config/redbrick + @echo "Linked ~/.config/redbrick/*" + @echo "Linked all dotfiles." + +# Full new-machine setup. +bootstrap: + @bash {{justfile_directory()}}/bin/bootstrap + +# Update Brewfile + leaves list. +backup: + @bash {{justfile_directory()}}/bin/backup + +# Create encrypted backup archive in private/ +backup-secrets: + @mkdir -p {{justfile_directory()}}/{{private_dir}} + @bash {{justfile_directory()}}/bin/backup-secrets + +# Restore from an encrypted archive +restore-secrets archive: + @bash {{justfile_directory()}}/bin/restore-secrets {{archive}} + diff --git a/README.md b/README.md @@ -0,0 +1,56 @@ +# πŸ§™ Dasho's Dotfiles + +My personal dotfiles, managed by a magical interactive wizard. + +This repository contains my personal configuration for `zsh`, `git`, `nvim`, and other tools. It's designed to be portable and easy to set up on any new machine. + +> **Pro tip**: My single init.lua file for Neovim is [here](config/nvim/init.lua) and it is awesome. I personally really like the look of it and it is very fast, yet inuitive for newer users. + +## Quick Start + +The easiest way to use this repository is with the interactive wizard. It handles everything from initial setup to backups and git operations. + +Just a warning though, it can be a little broken now and then. I might improve it soon but if you want to, feel free to open an issue or PR! + +```bash +# Clone the repo (if you haven't already) +git clone <your-repo-url> ~/.dotfiles +cd ~/.dotfiles + +# Run the wizard! +just wizard +``` + +The wizard will guide you through: +- **Bootstrapping** a new machine (installing Homebrew, packages, etc.) +- **Backing up** installed packages and secrets. +- **Restoring** secrets from an encrypted archive. +- **Linking** all configuration files to their correct locations. +- **Managing** this git repository with a friendly UI. + +## πŸ” Secrets Management + +This repository has a built-in workflow for securely managing sensitive files like GPG keys, SSH keys, and other credentials using `age` encryption. + +### How it Works + +1. **Backup (`just wizard` -> `Backup secrets`)**: + - The `backup-secrets` script gathers credentials from common locations: + - GPG keys (`~/.gnupg`) + - SSH keys (`~/.ssh`) + - `age` identities (`~/.config/age/keys.txt`) + - `skate` database entries + - Oh-My-Zsh custom configurations (`~/.oh-my-zsh/custom`) + - It bundles them into a `tar.gz` archive. + - It encrypts this archive using `age` into a file like `private/keys-YYYYMMDD.tar.gz.age`. + +2. **Storage**: + - The encrypted archive is saved in the `private/` directory. + - **⚠️ IMPORTANT**: The `private/` directory is intended to be committed to a **private Git repository only**. Do not expose your encrypted secrets on a public repository. + +3. **Restore (`just wizard` -> `Restore secrets`)**: + - The `restore-secrets` script prompts you to choose an archive from the `private/` directory. + - It decrypts the archive using your `age` identity. + - It restores the files to their original locations on the new machine. + +This system allows you to safely version control your secrets and easily provision a new machine with all your configurations and credentials. diff --git a/bin/backup b/bin/backup @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +mkdir -p "$ROOT/brew" + +if command -v brew >/dev/null 2>&1; then + brew bundle dump --force --describe --file "$ROOT/Brewfile" + brew leaves > "$ROOT/brew/leaves.txt" + echo "Wrote Brewfile and brew/leaves.txt" +else + echo "brew not found; skipping Brewfile dump" >&2 +fi + diff --git a/bin/backup-secrets b/bin/backup-secrets @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +OUT="${1:-$ROOT/private/keys-$(date +%Y%m%d).tar.gz.age}" +mkdir -p "$(dirname "$OUT")" + +TMP="$(mktemp -d)" +echo "Using temporary directory: $TMP" +trap 'rm -rf "$TMP"' EXIT + +mkdir -p "$TMP/gpg" "$TMP/ssh" "$TMP/age" "$TMP/skate" "$TMP/omz" + +# --- GPG export --- +if command -v gpg >/dev/null 2>&1; then + gpg --export --armor > "$TMP/gpg/public-keys.asc" || true + gpg --export-secret-keys --armor > "$TMP/gpg/secret-keys.asc" || true + gpg --export-ownertrust > "$TMP/gpg/ownertrust.txt" || true +fi + +# --- SSH backup (selected files) --- +if [[ -d "$HOME/.ssh" ]]; then + rsync -a \ + --include='config' \ + --include='known_hosts' \ + --include='id_*' \ + --exclude='*' \ + "$HOME/.ssh/" "$TMP/ssh/" || true +fi + +# --- AGE identities (common locations) --- +for f in \ + "$HOME/.config/age/keys.txt" \ + "$HOME/.config/age/key.txt" \ + "$HOME/.config/age/age.key" \ + "$HOME/key.txt" \ + "$HOME/age.key" +do + [[ -f "$f" ]] && cp -p "$f" "$TMP/age/" +done + +# --- Skate export (JSONL; values base64) --- +if command -v skate >/dev/null 2>&1; then + python3 - <<'PY' > "$TMP/skate/skate.jsonl" +import base64, json, subprocess +def sh(*cmd): + return subprocess.check_output(list(cmd)) +dbs = sh("skate","list-dbs").decode().splitlines() +for db in dbs: + keys = sh("skate","list","-k",f"{db}").decode().splitlines() + for k in keys: + v = sh("skate","get",f"{k}{db}") + print(json.dumps({"db": db, "key": k, "b64": base64.b64encode(v).decode()})) +PY +fi + +# --- Oh-My-Zsh custom configs --- +if [[ -d "$HOME/.oh-my-zsh/custom" ]]; then + echo "Backing up Oh-My-Zsh custom configs..." + rsync -a "$HOME/.oh-my-zsh/custom/" "$TMP/omz/custom/" || true +fi + +# --- Encrypt archive --- +echo "Creating encrypted archive: $OUT" +if [[ -n "${AGE_RECIPIENT:-}" ]]; then + tar -C "$TMP" -czf - . | age -r "$AGE_RECIPIENT" -o "$OUT" +else + tar -C "$TMP" -czf - . | age -p -o "$OUT" +fi + +echo "Wrote: $OUT" + diff --git a/bin/bootstrap b/bin/bootstrap @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DOT="$HOME/.dotfiles" + +mkdir -p "$HOME/.config/direnv" +mkdir -p "$HOME/.config/nvim" +mkdir -p "$HOME/.config/redbrick" +mkdir -p "$HOME/.config/git" + +# Install Homebrew if missing +if ! command -v brew >/dev/null 2>&1; then + echo "Installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + # Make brew available in this script run + if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -x /usr/local/bin/brew ]]; then + eval "$(/usr/local/bin/brew shellenv)" + elif [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + fi +fi + +# Install packages +if [[ -f "$ROOT/Brewfile" ]]; then + echo "Installing Brewfile packages..." + brew bundle install --file "$ROOT/Brewfile" +else + echo "No Brewfile found; skipping brew bundle install" >&2 +fi + +# Symlink configs +echo "Linking configs..." +ln -snf "$ROOT/zsh/zshrc" "$HOME/.zshrc" +ln -snf "$ROOT/zsh/secret.zsh" "$DOT/zsh/secret.zsh" 2>/dev/null || true +ln -snf "$ROOT/config/direnv/direnvrc" "$HOME/.config/direnv/direnvrc" +ln -snf "$ROOT/config/git/config" "$HOME/.gitconfig" +ls -snf "$ROOT/config/git/config" "$HOME/.config/git/config" 2>/dev/null || true +ln -snf "$ROOT/config/nvim/init.lua" "$HOME/.config/nvim/init.lua" +ln -snf "$ROOT/config/redbrick" "$HOME/.config/redbrick" 2>/dev/null || true + +echo "Bootstrap complete. Restart your shell." + diff --git a/bin/restore-secrets b/bin/restore-secrets @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +ARCHIVE="${1:?Usage: restore-secrets path/to/keys-YYYYMMDD.tar.gz.age}" + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +age -d "$ARCHIVE" | tar -xz -C "$TMP" + +# GPG restore +if command -v gpg >/dev/null 2>&1 && [[ -f "$TMP/gpg/secret-keys.asc" ]]; then + gpg --import "$TMP/gpg/public-keys.asc" 2>/dev/null || true + gpg --import "$TMP/gpg/secret-keys.asc" + [[ -f "$TMP/gpg/ownertrust.txt" ]] && gpg --import-ownertrust "$TMP/gpg/ownertrust.txt" || true +fi + +# SSH restore +if [[ -d "$TMP/ssh" ]]; then + mkdir -p "$HOME/.ssh" + rsync -a "$TMP/ssh/" "$HOME/.ssh/" + chmod 700 "$HOME/.ssh" + chmod 600 "$HOME/.ssh"/id_* 2>/dev/null || true + chmod 644 "$HOME/.ssh"/*.pub 2>/dev/null || true +fi + +# AGE restore +if [[ -d "$TMP/age" ]]; then + mkdir -p "$HOME/.config/age" + rsync -a "$TMP/age/" "$HOME/.config/age/" + chmod 700 "$HOME/.config/age" + chmod 600 "$HOME/.config/age"/* 2>/dev/null || true +fi + +# Skate restore +if command -v skate >/dev/null 2>&1 && [[ -f "$TMP/skate/skate.jsonl" ]]; then + python3 - "$TMP" <<'PY' +import base64, json, subprocess, sys, pathlib +tmp = pathlib.Path(sys.argv[1]) +path = tmp / "skate" / "skate.jsonl" +for line in path.read_text().splitlines(): + rec = json.loads(line) + val = base64.b64decode(rec["b64"]) + subprocess.check_call(["skate","set",f'{rec["key"]}@{rec["db"]}'], input=val) +PY +fi + +# Oh-My-Zsh custom configs restore +if [[ -d "$TMP/omz/custom" ]]; then + echo "Restoring Oh-My-Zsh custom configs..." + mkdir -p "$HOME/.oh-my-zsh/custom" + rsync -a "$TMP/omz/custom/" "$HOME/.oh-my-zsh/custom/" +fi + +echo "Restore complete." + diff --git a/bin/wizard b/bin/wizard @@ -0,0 +1,1038 @@ +#!/usr/bin/env zsh +# Dasho's Dotfiles Wizard πŸ§™ +# A magical, self-contained interactive wizard for managing dotfiles +# Works on fresh Linux/macOS systems with just internet access + +set -eo pipefail + +# Color Palette (Soft Gradients & Pastels) +# ---------------------------------------- +# 183 - Soft Lavender (headers, prompts) +# 219 - Light Pink (selected items, cursor) +# 147 - Muted Purple (list items) +# 117 - Pale Cyan (info messages) +# 114 - Soft Green (success messages) +# 210 - Coral (error messages) +# 222 - Peach (warnings) +# 242 - Warm Gray (subtle text) + +# Colors for fallback (before gum is available) +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +MAGENTA='\033[0;35m' +CYAN='\033[0;36m' +BOLD='\033[1m' +RESET='\033[0m' + +# Paths +SCRIPT_DIR="$(cd "$(dirname "${(%):-%x}")" && pwd)" +ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +PRIVATE_DIR="$ROOT/private" + +# ============================================================================ +# SELF-BOOTSTRAP: Install wizard dependencies +# ============================================================================ + +has_command() { + command -v "$1" >/dev/null 2>&1 +} + +install_homebrew() { + echo "${BLUE}πŸ“¦ Installing Homebrew...${RESET}" + if [[ "$OSTYPE" == "darwin"* ]]; then + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -x /usr/local/bin/brew ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi + else + # Linux + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + if [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + fi + fi +} + +wizard_bootstrap() { + echo "${MAGENTA}${BOLD}" + echo "╔════════════════════════════════════════════════════════════╗" + echo "β•‘ β•‘" + echo "β•‘ πŸ§™ Dasho's Dotfiles Wizard πŸ§™ β•‘" + echo "β•‘ β•‘" + echo "β•‘ Making magic happen on your machine... β•‘" + echo "β•‘ β•‘" + echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" + echo "${RESET}" + echo "" + echo "${CYAN}Checking for wizard dependencies...${RESET}" + echo "" + + # Check/install Homebrew first + if ! has_command brew; then + echo "${YELLOW}⚠️ Homebrew not found. Installing...${RESET}" + install_homebrew + else + echo "${GREEN}βœ“${RESET} Homebrew" + fi + + # Install essential tools + local tools=("gum" "glow" "age" "jq") + local to_install=() + + for tool in "${tools[@]}"; do + if ! has_command "$tool"; then + echo "${YELLOW}⚠️ $tool not found${RESET}" + to_install+=("$tool") + else + echo "${GREEN}βœ“${RESET} $tool" + fi + done + + if [[ ${#to_install[@]} -gt 0 ]]; then + echo "" + echo "${BLUE}πŸ“¦ Installing missing tools: ${to_install[*]}${RESET}" + brew install "${to_install[@]}" + echo "" + echo "${GREEN}βœ“ All wizard dependencies installed!${RESET}" + else + echo "" + echo "${GREEN}βœ“ All wizard dependencies present!${RESET}" + fi + + echo "" + sleep 1 +} + +# ============================================================================ +# GUM-POWERED UI HELPERS +# ============================================================================ + +show_header() { + clear + gum style \ + --border double \ + --border-foreground 183 \ + --padding "1 2" \ + --margin "1 0" \ + --align center \ + --foreground 219 \ + "πŸ§™ Dasho's Dotfiles Wizard πŸ§™" \ + "" \ + "Your magical companion for dotfiles mastery" +} + +show_success() { + gum style \ + --foreground 114 \ + "βœ“ $1" +} + +show_error() { + gum style \ + --foreground 210 \ + "βœ— $1" +} + +show_info() { + gum style \ + --foreground 117 \ + "β„Ή $1" +} + +spinner_run() { + local title="$1" + shift + gum spin --spinner dot --title "$title" -- "$@" +} + +wait_for_key() { + gum style --foreground 242 --italic "Press any key to continue..." + read -k1 -s + return 0 +} + +confirm() { + command gum confirm \ + --prompt.foreground 183 \ + --selected.foreground 219 \ + "$@" +} + +# ============================================================================ +# ERROR HANDLING WITH RETRY/SKIP OPTIONS +# ============================================================================ + +handle_error() { + local error_msg="$1" + local context="$2" + + show_error "$error_msg" + echo "" + + gum style --foreground 183 --italic "What would you like to do?" + + local choice=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "β†’ " \ + "πŸ”„ Retry" \ + "⏭️ Skip and continue" \ + "πŸ›‘ Exit wizard" \ + "πŸ“‹ Show error details") + + case "$choice" in + *Retry*) + return 0 + ;; + *Skip*) + show_info "Skipping: $context" + sleep 1 + return 1 + ;; + *Exit*) + echo "" + gum style --foreground 9 "Exiting wizard. See you next time! πŸ‘‹" + exit 1 + ;; + *details*) + gum style --foreground 8 "$context" + echo "" + wait_for_key + handle_error "$error_msg" "$context" + return $? + ;; + esac +} + +safe_run() { + local description="$1" + shift + + local output + local exit_code + + while true; do + output=$("$@" 2>&1) && exit_code=0 || exit_code=$? + + if [[ $exit_code -eq 0 ]]; then + return 0 + else + if handle_error "$description failed" "$output"; then + continue # Retry + else + return 1 # Skip + fi + fi + done +} + +# ============================================================================ +# CORE OPERATIONS +# ============================================================================ + +run_bootstrap() { + show_header + gum style --foreground 183 --bold "πŸš€ Bootstrap: Fresh Machine Setup" + echo "" + + gum style --foreground 183 "This will install Homebrew (if needed), install packages from Brewfile," + gum style --foreground 183 "and link all your dotfiles to the right places." + echo "" + + if ! confirm "Ready to bootstrap this machine?"; then + return + fi + + echo "" + spinner_run "Installing Homebrew if needed..." bash "$ROOT/bin/bootstrap" + + if [[ $? -eq 0 ]]; then + echo "" + show_success "Bootstrap completed successfully!" + echo "" + gum style --foreground 222 "⚠️ Remember to restart your shell or run: source ~/.zshrc" + else + safe_run "Bootstrap" bash "$ROOT/bin/bootstrap" + fi + + echo "" + wait_for_key +} + +run_backup() { + show_header + gum style --foreground 183 --bold "πŸ’Ύ Backup: Save Brewfile & Package List" + echo "" + + gum style --foreground 183 "Updates Brewfile and brew/leaves.txt with currently installed packages." + echo "" + + if ! confirm "Run backup now?"; then + return + fi + + echo "" + spinner_run "Backing up Brewfile and brew leaves..." bash "$ROOT/bin/backup" + + echo "" + show_success "Backup completed!" + + if has_command glow && [[ -f "$ROOT/Brewfile" ]]; then + echo "" + if confirm "View the updated Brewfile?"; then + glow "$ROOT/Brewfile" -p + fi + fi + + echo "" + wait_for_key +} + +run_backup_secrets() { + show_header + gum style --foreground 183 --bold "πŸ” Backup Secrets: Encrypt GPG/SSH/Age/Skate/Oh-My-Zsh" + echo "" + + gum style --foreground 183 "Creates an encrypted archive with:" + gum style --foreground 147 " β€’ GPG keys" + gum style --foreground 147 " β€’ SSH keys and config" + gum style --foreground 147 " β€’ Age identities" + gum style --foreground 147 " β€’ Skate database" + gum style --foreground 147 " β€’ Oh-My-Zsh custom configs" + echo "" + + local default_name="keys-$(date +%Y%m%d).tar.gz.age" + local archive_name=$(gum input \ + --placeholder "$default_name" \ + --prompt "Archive name: " \ + --value "$default_name" \ + --prompt.foreground 183 \ + --cursor.foreground 219) + + [[ -z "$archive_name" ]] && archive_name="$default_name" + + local archive_path="$PRIVATE_DIR/$archive_name" + + echo "" + spinner_run "Creating encrypted backup..." bash "$ROOT/bin/backup-secrets" "$archive_path" + + echo "" + show_success "Secrets backed up to: $archive_name" + + echo "" + wait_for_key +} + +run_restore_secrets() { + show_header + gum style --foreground 183 --bold "πŸ”“ Restore Secrets: Decrypt & Restore" + echo "" + + if [[ ! -d "$PRIVATE_DIR" ]] || [[ -z "$(ls -A "$PRIVATE_DIR"/*.age 2>/dev/null)" ]]; then + show_error "No encrypted archives found in $PRIVATE_DIR" + echo "" + wait_for_key + return + fi + + local archives=($(ls "$PRIVATE_DIR"/*.age 2>/dev/null)) + + if [[ ${#archives[@]} -eq 0 ]]; then + show_error "No .age archives found" + echo "" + wait_for_key + return + fi + + gum style --foreground 183 "Select an archive to restore:" + echo "" + + local selected=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "β†’ " \ + "${archives[@]##*/}") + local archive_path="$PRIVATE_DIR/$selected" + + echo "" + gum style --foreground 222 "⚠️ This will restore GPG, SSH, Age, Skate, and Oh-My-Zsh configs" + + if ! confirm "Restore from $selected?"; then + return + fi + + echo "" + spinner_run "Restoring secrets..." bash "$ROOT/bin/restore-secrets" "$archive_path" + + echo "" + show_success "Secrets restored successfully!" + + echo "" + wait_for_key +} + +run_link() { + show_header + gum style --foreground 183 --bold "πŸ”— Link: Symlink Dotfiles" + echo "" + + gum style --foreground 183 "Creates symlinks for:" + gum style --foreground 147 " β€’ ~/.zshrc" + gum style --foreground 147 " β€’ ~/.config/direnv/direnvrc" + gum style --foreground 147 " β€’ ~/.gitconfig" + gum style --foreground 147 " β€’ ~/.config/nvim/init.lua" + gum style --foreground 147 " β€’ ~/.config/redbrick/*" + echo "" + + if ! confirm "Create/update symlinks?"; then + return + fi + + echo "" + + mkdir -p "$HOME/.config/direnv" + mkdir -p "$HOME/.config/git" + mkdir -p "$HOME/.config/nvim" + mkdir -p "$HOME/.config/redbrick" + + ln -snf "$ROOT/zsh/zshrc" "$HOME/.zshrc" && show_success "Linked ~/.zshrc" + ln -snf "$ROOT/config/direnv/direnvrc" "$HOME/.config/direnv/direnvrc" && show_success "Linked direnvrc" + ln -snf "$ROOT/config/git/config" "$HOME/.gitconfig" && show_success "Linked gitconfig" + ln -snf "$ROOT/config/nvim/init.lua" "$HOME/.config/nvim/init.lua" && show_success "Linked nvim config" + ln -snf "$ROOT/config/redbrick" "$HOME/.config/redbrick" && show_success "Linked redbrick config" + + echo "" + show_success "All dotfiles linked!" + + echo "" + wait_for_key +} + +run_check() { + show_header + gum style --foreground 183 --bold "πŸ” Check: Verify Dependencies" + echo "" + + local tools=("direnv" "skate" "age" "just" "brew" "gum" "glow" "git" "zsh") + local missing=() + + for tool in "${tools[@]}"; do + if has_command "$tool"; then + show_success "$tool" + else + show_error "$tool (missing)" + missing+=("$tool") + fi + done + + echo "" + + if [[ ${#missing[@]} -eq 0 ]]; then + gum style --foreground 10 --bold "✨ All dependencies present! You're all set!" + else + gum style --foreground 222 "Missing tools: ${missing[*]}" + echo "" + if confirm "Install missing tools via Homebrew?"; then + echo "" + spinner_run "Installing missing tools..." brew install "${missing[@]}" + echo "" + show_success "Tools installed!" + fi + fi + + echo "" + wait_for_key +} + +# ============================================================================ +# GIT OPERATIONS +# ============================================================================ + +check_git_repo() { + if ! git -C "$ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + show_header + show_error "Not a git repository" + gum style --foreground 147 "The directory $ROOT is not a git repository." + gum style --foreground 147 "Please initialize a repository first." + echo "" + if confirm "Initialize a new git repository here?"; then + git -C "$ROOT" init + show_success "Git repository initialized at $ROOT" + fi + echo "" + wait_for_key + return 1 + fi + return 0 +} + +git_menu() { + if ! check_git_repo; then + return + fi + + while true; do + show_header + gum style --foreground 183 --bold "🌳 Git Operations" + echo "" + + local choice=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "β†’ " \ + "πŸ“Š Status" \ + "πŸ’Ύ Commit changes" \ + "πŸ”„ Sync (pull + push)" \ + "⬆️ Push" \ + "⬇️ Pull" \ + "πŸ”§ Configure remote" \ + "πŸ”‘ GitHub authentication" \ + "← Back to main menu") + + case "$choice" in + *Status*) + git_status + ;; + *Commit*) + git_commit + ;; + *Sync*) + git_sync + ;; + *Push*) + git_push + ;; + *Pull*) + git_pull + ;; + *remote*) + git_configure_remote + ;; + *authentication*) + github_auth + ;; + *Back*) + break + ;; + esac + done +} + +git_status() { + show_header + gum style --foreground 183 --bold "πŸ“Š Git Status" + echo "" + + cd "$ROOT" + git status + + echo "" + wait_for_key +} + +git_commit() { + show_header + gum style --foreground 183 --bold "πŸ’Ύ Commit Changes" + echo "" + + cd "$ROOT" + + local status_output=$(git status --porcelain) + + if [[ -z "$status_output" ]]; then + show_info "No changes to commit" + echo "" + wait_for_key + return + fi + + echo "Changed files:" + git status --short + echo "" + + if ! confirm "Stage all changes?"; then + show_info "Commit cancelled" + echo "" + wait_for_key + return + fi + + git add -A + + echo "" + local commit_msg=$(gum input \ + --placeholder "Enter commit message" \ + --prompt "Message: " \ + --prompt.foreground 183 \ + --cursor.foreground 219) + + if [[ -z "$commit_msg" ]]; then + show_error "Commit message required" + echo "" + wait_for_key + return + fi + + echo "" + spinner_run "Committing changes..." git commit -m "$commit_msg" + + echo "" + show_success "Changes committed!" + + echo "" + if confirm "Push to remote?"; then + git_push + else + wait_for_key + fi +} + +git_sync() { + show_header + gum style --foreground 183 --bold "πŸ”„ Sync: Pull + Push" + echo "" + + cd "$ROOT" + + # Check if remote is configured + if ! git remote get-url origin >/dev/null 2>&1; then + show_error "No remote repository configured" + gum style --foreground 147 "Configure a remote first in the Git menu." + echo "" + wait_for_key + return + fi + + if spinner_run "Pulling from remote..." git pull 2>&1; then + show_success "Pulled successfully" + else + echo "" + show_error "Git pull failed" + gum style --foreground 147 "Check your internet connection and authentication." + echo "" + wait_for_key + return + fi + + echo "" + + local status_output=$(git status --porcelain) + + if [[ -n "$status_output" ]]; then + gum style --foreground 222 "You have uncommitted changes." + if confirm "Commit and push?"; then + git_commit + return + fi + fi + + if spinner_run "Pushing to remote..." git push 2>&1; then + echo "" + show_success "Synced successfully!" + else + echo "" + show_error "Git push failed" + gum style --foreground 147 "Check your authentication and permissions." + echo "" + wait_for_key + return + fi + + echo "" + wait_for_key +} + +git_push() { + show_header + gum style --foreground 183 --bold "⬆️ Push to Remote" + echo "" + + cd "$ROOT" + + # Check if remote is configured + if ! git remote get-url origin >/dev/null 2>&1; then + show_error "No remote repository configured" + gum style --foreground 147 "Configure a remote first in the Git menu." + echo "" + wait_for_key + return + fi + + if spinner_run "Pushing to remote..." git push 2>&1; then + echo "" + show_success "Pushed successfully!" + else + echo "" + show_error "Git push failed" + gum style --foreground 147 "Check authentication and permissions." + echo "" + wait_for_key + return + fi + + echo "" + wait_for_key +} + +git_pull() { + show_header + gum style --foreground 183 --bold "⬇️ Pull from Remote" + echo "" + + cd "$ROOT" + + # Check if remote is configured + if ! git remote get-url origin >/dev/null 2>&1; then + show_error "No remote repository configured" + gum style --foreground 147 "Configure a remote first in the Git menu." + echo "" + wait_for_key + return + fi + + if spinner_run "Pulling from remote..." git pull 2>&1; then + echo "" + show_success "Pulled successfully!" + else + echo "" + show_error "Git pull failed" + gum style --foreground 147 "Check your internet connection and authentication." + echo "" + wait_for_key + return + fi + + echo "" + wait_for_key +} + +git_configure_remote() { + show_header + gum style --foreground 183 --bold "πŸ”§ Configure Git Remote" + echo "" + + cd "$ROOT" + + local current_remote=$(git remote get-url origin 2>/dev/null || echo "") + + if [[ -n "$current_remote" ]]; then + gum style "Current remote: $current_remote" + echo "" + else + show_info "No remote configured" + echo "" + fi + + local action=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "β†’ " \ + "βž• Add/Update remote" \ + "πŸ—‘οΈ Remove remote" \ + "← Back") + + case "$action" in + *Add*) + echo "" + local remote_url=$(gum input \ + --placeholder "https://github.com/username/repo.git" \ + --prompt "Remote URL: " \ + --prompt.foreground 183 \ + --cursor.foreground 219) + + if [[ -z "$remote_url" ]]; then + show_error "Remote URL required" + else + if [[ -n "$current_remote" ]]; then + git remote set-url origin "$remote_url" + else + git remote add origin "$remote_url" + fi + show_success "Remote configured: $remote_url" + fi + ;; + *Remove*) + git remote remove origin 2>/dev/null + show_success "Remote removed" + ;; + esac + + echo "" + wait_for_key +} + +github_auth() { + show_header + gum style --foreground 183 --bold "πŸ”‘ GitHub Authentication" + echo "" + + gum style --foreground 183 "Choose authentication method:" + echo "" + + local method=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "β†’ " \ + "🌐 Device flow (browser)" \ + "πŸ”‘ Personal Access Token" \ + "πŸ“‹ Check current auth" \ + "← Back") + + case "$method" in + *Device*) + github_device_flow + ;; + *Token*) + github_token_setup + ;; + *Check*) + github_check_auth + ;; + esac +} + +github_device_flow() { + show_header + gum style --foreground 183 --bold "🌐 GitHub Device Flow Authentication" + echo "" + + if ! has_command gh; then + gum style --foreground 222 "GitHub CLI (gh) not found" + echo "" + if confirm "Install GitHub CLI?"; then + spinner_run "Installing gh..." brew install gh + echo "" + else + return + fi + fi + + # Check if GITHUB_TOKEN is set + if [[ -n "${GITHUB_TOKEN:-}" ]]; then + show_info "GITHUB_TOKEN environment variable is set" + echo "" + gum style --foreground 147 "GitHub CLI will use this token automatically." + gum style --foreground 147 "To use device flow instead, unset GITHUB_TOKEN first:" + gum style --foreground 242 " unset GITHUB_TOKEN" + echo "" + wait_for_key + return + fi + + gum style --foreground 183 "This will open GitHub in your browser for authentication." + echo "" + + if ! confirm "Continue?"; then + return + fi + + echo "" + + if gh auth login 2>&1; then + echo "" + show_success "Authentication complete!" + + echo "" + if confirm "Configure git to use gh credentials?"; then + gh auth setup-git 2>/dev/null && show_success "Git configured to use gh credentials" || show_info "Git already configured" + fi + else + local gh_exit=$? + echo "" + show_error "GitHub authentication failed" + gum style --foreground 147 "You may already be authenticated, or there was a network issue." + echo "" + fi + + echo "" + wait_for_key +} + +github_token_setup() { + show_header + gum style --foreground 183 --bold "πŸ”‘ GitHub Personal Access Token Setup" + echo "" + + gum style --foreground 183 "To create a token:" + gum style --foreground 147 " 1. Go to: https://github.com/settings/tokens" + gum style --foreground 147 " 2. Click 'Generate new token (classic)'" + gum style --foreground 147 " 3. Select scopes: repo, workflow, write:packages" + gum style --foreground 147 " 4. Generate and copy the token" + echo "" + + if ! confirm "Have you created a token?"; then + return + fi + + echo "" + local token=$(gum input \ + --password \ + --placeholder "ghp_..." \ + --prompt "Token: " \ + --prompt.foreground 183 \ + --cursor.foreground 219) + + if [[ -z "$token" ]]; then + show_error "Token required" + echo "" + wait_for_key + return + fi + + # Store in git config + cd "$ROOT" + local remote_url=$(git remote get-url origin 2>/dev/null || echo "") + + if [[ -z "$remote_url" ]]; then + show_error "No git remote configured. Please configure remote first." + else + # Update URL to use token + if [[ "$remote_url" =~ ^https://github.com/ ]]; then + local new_url=$(echo "$remote_url" | sed "s|https://github.com/|https://${token}@github.com/|") + git remote set-url origin "$new_url" + show_success "Token configured for this repository" + else + show_error "Remote is not an HTTPS GitHub URL" + fi + fi + + echo "" + wait_for_key +} + +github_check_auth() { + show_header + gum style --foreground 183 --bold "πŸ“‹ GitHub Authentication Status" + echo "" + + if has_command gh; then + gh auth status + else + show_info "GitHub CLI not installed" + fi + + echo "" + echo "Git config:" + git config --get user.name && show_success "Name: $(git config --get user.name)" || show_error "No user.name set" + git config --get user.email && show_success "Email: $(git config --get user.email)" || show_error "No user.email set" + + echo "" + wait_for_key +} + +# ============================================================================ +# INSTALL OH-MY-ZSH +# ============================================================================ + +install_omz() { + show_header + gum style --foreground 183 --bold "🎨 Install Oh-My-Zsh" + echo "" + + if [[ -d "$HOME/.oh-my-zsh" ]]; then + show_info "Oh-My-Zsh already installed" + echo "" + wait_for_key + return + fi + + gum style --foreground 183 "This will install Oh-My-Zsh with recommended settings." + echo "" + + if ! confirm "Install Oh-My-Zsh?"; then + return + fi + + echo "" + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + + echo "" + show_success "Oh-My-Zsh installed!" + + echo "" + wait_for_key +} + +# ============================================================================ +# MAIN MENU +# ============================================================================ + +main_menu() { + while true; do + show_header + + echo "" + gum style --foreground 183 --italic "What magical task shall we perform today?" + echo "" + + local choice=$(gum choose \ + --cursor.foreground 219 \ + --selected.foreground 183 \ + --cursor "✨ " \ + --height 12 \ + "πŸš€ Bootstrap (fresh machine setup)" \ + "πŸ’Ύ Backup (Brewfile & packages)" \ + "πŸ” Backup secrets (GPG/SSH/Age/Skate/OMZ)" \ + "πŸ”“ Restore secrets" \ + "πŸ”— Link dotfiles" \ + "πŸ” Check dependencies" \ + "🌳 Git operations" \ + "🎨 Install Oh-My-Zsh" \ + "πŸšͺ Exit") + + case "$choice" in + *Bootstrap*) + run_bootstrap + ;; + *"Backup ("*) + run_backup + ;; + *"Backup secrets"*) + run_backup_secrets + ;; + *Restore*) + run_restore_secrets + ;; + *Link*) + run_link + ;; + *Check*) + run_check + ;; + *Git*) + git_menu + ;; + *Oh-My-Zsh*) + install_omz + ;; + *Exit*) + clear + gum style \ + --foreground 219 \ + --align center \ + --padding "1 2" \ + --border rounded \ + --border-foreground 183 \ + "✨ Thank you for using Dasho's Dotfiles Wizard! ✨" \ + "" \ + "May your configs be ever in your favor! πŸ§™" + echo "" + exit 0 + ;; + esac + done +} + +# ============================================================================ +# ENTRY POINT +# ============================================================================ + +# First-time bootstrap of wizard itself +wizard_bootstrap + +# Launch main menu +main_menu diff --git a/brew/leaves.txt b/brew/leaves.txt @@ -0,0 +1,60 @@ +antoniorodr/lexy/lexy +bat +boxes +btop +charmbracelet/tap/crush +charmbracelet/tap/mods +charmbracelet/tap/skate +charmbracelet/tap/soft-serve +charmbracelet/tap/wishlist +cloc +croc +danielgatis/imgcat/imgcat +direnv +exiftool +eza +fzf +gemini-cli +gh +glow +go +gum +himalaya +imagemagick +irssi +just +liblqr +libraw +librsvg +libultrahdr +lolcat +magic-wormhole +monolith +neofetch +neovim +openai-whisper +opencode +pass +pipes-sh +pop +proxychains-ng +reflex +rust +sc-im +sevenzip +sops +sshx +steipete/tap/gifgrep +steipete/tap/gogcli +steipete/tap/imsg +tmux +tor +torsocks +tree-sitter +unar +uv +vhs +weechat +zellij +zoxide +zsh diff --git a/config/direnv/direnvrc b/config/direnv/direnvrc @@ -0,0 +1,67 @@ +# direnv/direnvrc +# ----------------------------------------------------------------------------- +# direnv helpers for loading secrets from Skate. +# +# In your project's .envrc: +# use_secrets dev GITHUB_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY +# +# Resolution order (per variable): +# 1) repo.<repo-slug>.<env> (only if inside a git repo) +# 2) global.<env> +# +# If a variable is missing, direnv will fail the load (safe default). +# ----------------------------------------------------------------------------- + +_secrets_repo_slug() { + local top remote slug + + top="$(git -C "$PWD" rev-parse --show-toplevel 2>/dev/null)" || return 1 + remote="$(git -C "$top" remote get-url origin 2>/dev/null || echo "$top")" + + # normalize + trim + remote="${remote%.git}" + remote="${remote#git@}" + remote="${remote#https://}" + remote="${remote#http://}" + remote="${remote/:/\/}" # ssh form host:owner/repo -> host/owner/repo + + slug="${remote//\//_}" # slashes -> underscores + slug="$(printf '%s' "$slug" | tr -c 'A-Za-z0-9_.-' '_' )" + + # remove any trailing underscores that can come from hidden chars/newlines + slug="${slug%%_}" + # Finally, change all double underscores to single underscores + slug="${slug//__/_}" + + printf '%s\n' "$slug" +} + +use_secrets() { + local env="${1:-dev}" + shift || true + + command -v skate >/dev/null 2>&1 || { log_error "Missing: skate"; return 1; } + + local global_db="global.${env}" + local repo_db="" + + if git -C "$PWD" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + local slug + slug="$(_secrets_repo_slug 2>/dev/null)" && repo_db="repo.${slug}.${env}" + fi + + local var val + for var in "$@"; do + if [ -n "$repo_db" ] && val="$(skate get "${var}@${repo_db}" 2>/dev/null)"; then + export "$var=$val" + continue + fi + if val="$(skate get "${var}@${global_db}" 2>/dev/null)"; then + export "$var=$val" + continue + fi + log_error "Missing secret: ${var} (looked in ${repo_db:-<no-repo-db>} then ${global_db})" + return 1 + done +} + diff --git a/config/git/config b/config/git/config @@ -0,0 +1,22 @@ +[user] + name = Dasho + email = git@dasho.dev + signingkey = ~/.ssh/id_ed25519.pub + +[core] + compression = 9 + whitespace = error + preloadindex = true + excludesfile = ~/.gitignore + +[commit] + gpgsign = true + +[gpg] + format = ssh + +[init] + defaultBranch = main + +[url "git@github.com:"] + insteadOf = https://github.com/ diff --git a/config/nvim/init.lua b/config/nvim/init.lua @@ -0,0 +1,353 @@ +-- Neovim init.lua + +-- Basic options +vim.opt.number = true -- enable absolute line numbers +vim.opt.relativenumber = true -- enable relative line numbers +vim.opt.clipboard = "unnamedplus" -- use system clipboard +vim.opt.mouse = "a" -- enable mouse +vim.opt.termguicolors = true -- true color support +vim.opt.signcolumn = "yes" -- always show signcolumn +vim.opt.showmode = false -- don't show mode (we use statusline) +vim.opt.cursorline = true -- highlight current line +vim.opt.hidden = true -- allow buffer switching without saving + +-- Indentation +vim.opt.expandtab = true -- spaces instead of tabs +vim.opt.shiftwidth = 2 -- size of an indent +vim.opt.tabstop = 2 -- number of spaces tabs count for +vim.opt.softtabstop = 2 -- spaces when hitting <Tab> + +-- Searching +vim.opt.ignorecase = true -- ignore case +vim.opt.smartcase = true -- unless uppercase present +vim.opt.incsearch = true -- incremental search +vim.opt.hlsearch = false -- no persistent highlight + +-- Splits & Windows +vim.opt.splitbelow = true -- horizontal splits go below +vim.opt.splitright = true -- vertical splits go right +vim.opt.equalalways = true -- auto-resize splits + +-- Backups & Undo +vim.opt.backup = false +vim.opt.writebackup = false +vim.opt.swapfile = false +vim.opt.undofile = true -- enable persistent undo +vim.opt.undodir = vim.fn.stdpath('state') .. '/undo' + +-- Timing +vim.opt.updatetime = 300 -- faster CursorHold +vim.opt.timeoutlen = 500 -- faster mapped sequences + +-- Leader Key +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' + +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim' +if not vim.loop.fs_stat(lazypath) then + vim.fn.system({ + 'git', 'clone', '--filter=blob:none', + 'https://github.com/folke/lazy.nvim.git', + '--branch=stable', lazypath, + }) +end +vim.opt.rtp:prepend(lazypath) + +-- Plugin setup +require('lazy').setup({ + -- lazy.nvim manager + { 'folke/lazy.nvim', version = '*' }, + + -- Lualine statusline + { + 'nvim-lualine/lualine.nvim', + event = 'VeryLazy', + dependencies = { 'kyazdani42/nvim-web-devicons', opt = true }, + config = function() + require('lualine').setup { + options = { + icons_enabled = true, + theme = 'auto', + component_separators = { left = 'ξ‚±', right = 'ξ‚³' }, + section_separators = { left = 'ξ‚°', right = 'ξ‚²' }, + }, + sections = { + lualine_a = {'mode'}, + lualine_b = {'branch', 'diff', 'diagnostics'}, + lualine_c = {'filename'}, + lualine_x = {'encoding', 'fileformat', 'filetype'}, + lualine_y = {'progress'}, + lualine_z = {'location'}, + }, + } + end, + }, + { + "zbirenbaum/copilot.lua", + event = "VeryLazy", + config = function() + require("copilot").setup({ + suggestion = { + enabled = true, + auto_trigger = true, + accept = false, + }, + panel = { + enabled = false + }, + filetypes = { + markdown = true, + help = true, + html = true, + javascript = true, + typescript = true, + ["*"] = true + }, + }) + + vim.keymap.set("i", '<Tab>', function() + if require("copilot.suggestion").is_visible() then + require("copilot.suggestion").accept() + else + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Tab>", true, false, true), "n", false) + end + end, { + silent = true, + }) + end, + }, + -- Telescope fuzzy finder + { + 'nvim-telescope/telescope.nvim', + cmd = 'Telescope', + dependencies = { 'nvim-lua/plenary.nvim' }, + config = function() + require('telescope').setup { + defaults = { + layout_strategy = 'flex', + file_ignore_patterns = {'node_modules'} + } + } + end, + }, + + -- File explorer + { + 'nvim-tree/nvim-tree.lua', + cmd = { 'NvimTreeToggle', 'NvimTreeFocus' }, + dependencies = { 'kyazdani42/nvim-web-devicons' }, + config = function() + require('nvim-tree').setup { + view = { width = 30 }, + update_focused_file = { enable = true }, + } + end, + }, + + -- Treesitter for syntax + { + 'nvim-treesitter/nvim-treesitter', + build = ':TSUpdate', + event = { 'BufReadPost', 'BufNewFile' }, + config = function() + require('nvim-treesitter.configs').setup { + ensure_installed = { 'lua', 'python', 'javascript', 'go', 'rust' }, + highlight = { enable = true }, + indent = { enable = true }, + } + end, + }, + + -- Mason LSP installer + { 'williamboman/mason.nvim', cmd = 'Mason', config = true }, + { + 'williamboman/mason-lspconfig.nvim', + dependencies = 'neovim/nvim-lspconfig', + config = function() + require('mason-lspconfig').setup { + ensure_installed = { 'pyright', 'ts_ls', 'lua_ls' }, + automatic_enable = false, + } + vim.lsp.config('lua_ls', { + settings = { + Lua = { + runtime = { version = 'LuaJIT' }, + diagnostics = { globals = {'vim'} }, + workspace = { library = vim.api.nvim_get_runtime_file('', true) }, + telemetry = { enable = false }, + }, + }, + }) + vim.lsp.enable({ 'pyright', 'ts_ls', 'lua_ls' }) + end, + }, + + -- Completion + { + 'hrsh7th/nvim-cmp', + event = 'InsertEnter', + dependencies = { + 'hrsh7th/cmp-nvim-lsp', 'hrsh7th/cmp-path', + 'L3MON4D3/LuaSnip', 'saadparwaiz1/cmp_luasnip', + }, + config = function() + local cmp = require('cmp') + cmp.setup { + snippet = { expand = function(args) require('luasnip').lsp_expand(args.body) end }, + sources = cmp.config.sources({{ name = 'nvim_lsp' },{ name = 'path' },{ name = 'luasnip' }}), + } + end, + }, + + -- Git signs + { + 'lewis6991/gitsigns.nvim', + event = 'BufReadPre', + config = function() require('gitsigns').setup {} end, + }, + + -- Autopairs + { + 'windwp/nvim-autopairs', + event = 'InsertEnter', + config = function() require('nvim-autopairs').setup {} end, + }, + + -- Commenting + { + 'numToStr/Comment.nvim', + keys = { + { '<Leader>/', function() require('Comment.api').toggle.linewise.current() end, desc = 'Toggle comment (line)' }, + { '<Leader>/', '<Esc><cmd>lua require("Comment.api").toggle.blockwise(vim.fn.visualmode())<CR>', mode = 'v', desc = 'Toggle comment (block)' }, + }, + config = function() + require('Comment').setup({ + -- Add any custom config here; these are the defaults: + padding = true, -- add a space b/w comment and line + sticky = true, -- cursor stays put + mappings = { + basic = false, -- disable builtin mappings because we're using our own + extra = false, + }, + toggler = { + line = '<Leader>/', -- won't be set by default since basic=false + block = '<Leader>/', -- same here + }, + }) + end, + }, + + + -- Which-key + { + 'folke/which-key.nvim', + event = 'VeryLazy', + config = function() require('which-key').setup {} end, + }, + + -- Bufferline + { + 'akinsho/bufferline.nvim', + event = 'BufWinEnter', + dependencies = 'kyazdani42/nvim-web-devicons', + config = function() + require('bufferline').setup { options = { separator_style = 'thick' } } + end, + }, + + -- Hop + { + 'phaazon/hop.nvim', + branch = 'v2', + keys = { 'f', 'F', 't', 'T' }, + config = function() require('hop').setup {} end, + }, + + { + 'akinsho/toggleterm.nvim', -- terminal toggling plugin + version = '*', + keys = { { '<Leader>t', '<cmd>ToggleTerm<CR>', desc = 'Toggle floating terminal' } }, + opts = { + size = 20, -- height of split if not floating + open_mapping = [[<Leader>t]], -- map <Leader>t to toggle + direction = 'float', -- open as floating window + float_opts = { + border = 'curved', -- single, double, rounded, curved, or none + winblend = 0, + width = function() return math.floor(vim.o.columns * 0.8) end, + height = function() return math.floor(vim.o.lines * 0.8) end, + -- row and col will center the float + row = 0.5, + col = 0.5, + }, + -- hide line numbers and start in insert mode + hide_numbers = true, + start_in_insert= true, + persist_size = true, + }, + config = function(_, opts) + require('toggleterm').setup(opts) -- apply settings + end, + }, +}) + +local map = vim.keymap.set +local opts = { silent = true, noremap = true } + +-- Better window navigation +map('n', '<Leader>h', '<C-w>h', { desc = 'Move to left split', unpack(opts) }) +map('n', '<Leader>j', '<C-w>j', { desc = 'Move to below split', unpack(opts) }) +map('n', '<Leader>k', '<C-w>k', { desc = 'Move to above split', unpack(opts) }) +map('n', '<Leader>l', '<C-w>l', { desc = 'Move to right split', unpack(opts) }) + +-- Resize splits with arrows +map('n', '<Leader><Up>', ':resize -2<CR>', { desc = 'Decrease split height', unpack(opts) }) +map('n', '<Leader><Down>', ':resize +2<CR>', { desc = 'Increase split height', unpack(opts) }) +map('n', '<Leader><Left>', ':vertical resize -2<CR>', { desc = 'Decrease split width', unpack(opts) }) +map('n', '<Leader><Right>', ':vertical resize +2<CR>', { desc = 'Increase split width', unpack(opts) }) + +-- Buffer navigation +map('n', '<Leader>bn', ':bnext<CR>', { desc = 'Next buffer', unpack(opts) }) +map('n', '<Leader>bp', ':bprevious<CR>', { desc = 'Previous buffer', unpack(opts) }) +map('n', '<Leader>bc', ':bdelete<CR>', { desc = 'Close buffer', unpack(opts) }) + +-- Quick save & quit +map('n', '<Leader>w', ':write<CR>', { desc = 'Save current file', unpack(opts) }) +map('n', '<Leader>q', ':quit<CR>', { desc = 'Quit current window', unpack(opts) }) +map('n', '<Leader>WQ', ':wqall<CR>', { desc = 'Save all and quit', unpack(opts) }) + +-- Move lines up/down in visual mode +map('v', '<Leader>j', ":m '>+1<CR>gv=gv", { desc = 'Move selection down', unpack(opts) }) +map('v', '<Leader>k', ":m '<-2<CR>gv=gv", { desc = 'Move selection up', unpack(opts) }) + +-- Yank to system clipboard +map('n', '<Leader>y', '"+y', { desc = 'Yank to system clipboard', unpack(opts) }) +map('v', '<Leader>y', '"+y', { desc = 'Yank selection to system clipboard', unpack(opts) }) +map('n', '<Leader>Y', '"+Y', { desc = 'Yank entire line to clipboard', unpack(opts) }) + +-- Paste over visual selection without losing register +map('v', '<Leader>p', '"_dP', { desc = 'Paste over selection', unpack(opts) }) + +-- Clear search highlights +map('n', '<Leader>c', ':nohlsearch<CR>', { desc = 'Clear search highlights',unpack(opts) }) + +-- Quick Telescope pickers +map('n', '<Leader>ff', '<cmd>Telescope find_files<CR>', { desc = 'Find files', unpack(opts) }) +map('n', '<Leader>fg', '<cmd>Telescope live_grep<CR>', { desc = 'Live grep', unpack(opts) }) +map('n', '<Leader>fb', '<cmd>Telescope buffers<CR>', { desc = 'List open buffers', unpack(opts) }) +map('n', '<Leader>fh', '<cmd>Telescope help_tags<CR>', { desc = 'Find help tags', unpack(opts) }) + +-- Toggle NvimTree +map('n', '<Leader>e', ':NvimTreeToggle<CR>', { desc = 'Toggle file explorer', unpack(opts) }) + +-- Make ESC faster (jk/ kj in insert mode) +map('i', 'jk', '<Esc>', { desc = 'Exit insert mode', unpack(opts) }) +map('i', 'kj', '<Esc>', { desc = 'Exit insert mode', unpack(opts) }) + +-- Quick comment toggling (using Comment.nvim) +-- map('n', '<Leader>/', '<cmd>CommentToggle<CR>', opts) +-- map('v', '<Leader>/', '<esc><cmd>CommentToggle<CR>', opts) + + +-- End of init.lua diff --git a/config/redbrick/config.toml b/config/redbrick/config.toml @@ -0,0 +1,40 @@ +# Redbrick config. +# +# For a complete list of available options, +# please visit https://redbrick.chat/configuration/ + +[servers.404] +nickname = "Dasho" +nick_password_file = "~/.config/redbrick/404/password" +server = "irc.4-0-4.io" +port = 6667 +channels = ["#chat", "#general", "#help", "#redbrick"] +use_tls = false + +[servers.404.sasl.plain] +username = "Dasho" +password_file = "~/.config/redbrick/404/password" + +[servers.test-404] +nickname = "Dasho" +nick_password_file = "~/.config/redbrick/404/password" +server = "127.0.0.1" +port = 6667 +channels = ["#test"] +use_tls = false + +[servers.bhc] +nickname = "Dasho" +nick_password_file = "~/.config/redbrick/bhc/password" +server = "blkhatjxlrvc5aevqzz5t6kxldayog6jlx5h7glnu44euzongl4fh5ad.onion" +port = 6667 +channels = ["#lobby", "#staff"] +use_tls = false + +[servers.cheshire] +nickname = "Dasho" +nick_password_file = "~/.config/redbrick/cheshire/password" +server = "34vnln24rlakgbk6gpityvljieayyw7q4bhdbbgs6zp2v5nbh345zgad.onion" +port = 6667 +channels =["#chucky"] +use_tls = false diff --git a/zsh/secrets.zsh b/zsh/secrets.zsh @@ -0,0 +1,119 @@ +# ---------------------------- Secret Management ------------------------------ + +# direnv integration (must be in interactive shells) +if command -v direnv >/dev/null 2>&1; then + eval "$(direnv hook zsh)" +fi + +# ----------------------------------------------------------------------------- +# Secret helpers for Skate + gum. +# +# Usage: +# secret [-g] [-e env] KEY +# - By default: uses repo scope if inside a git repo, otherwise global. +# - -g forces global scope. +# - -e chooses an environment name (default: dev). +# +# secret-get [-e env] KEY +# - Prints the secret to stdout. +# - Resolution order: repo DB first (if in a repo), then global DB. +# +# Notes: +# - Skate stores items as: KEY@DB +# - DBs are named like: +# global.<env> +# repo.<repo-slug>.<env> +# ----------------------------------------------------------------------------- + +_secrets_repo_slug() { + local top remote slug + top="$(git -C "$PWD" rev-parse --show-toplevel 2>/dev/null)" || return 1 + remote="$(git -C "$top" remote get-url origin 2>/dev/null || echo "$top")" + + remote="${remote%.git}" + remote="${remote#git@}" + remote="${remote#https://}" + remote="${remote#http://}" + remote="${remote/:/\/}" + + slug="${remote//\//_}" + slug="${slug//[^A-Za-z0-9_.-]/_}" + slug="${slug%%_}" # strip trailing underscore + # Finally change all double underscores to single + slug="${slug//__/_}" + + print -r -- "$slug" +} + +_secrets_db_global() { print -r -- "global.$1"; } + +_secrets_db_repo() { + local env="$1" slug + slug="$(_secrets_repo_slug)" || return 1 + print -r -- "repo.${slug}.${env}" +} + +secret() { + emulate -L zsh + setopt localoptions pipefail + + local env="dev" scope="auto" + local OPTIND=1 opt + while getopts ":ge:" opt; do + case "$opt" in + g) scope="global" ;; + e) env="$OPTARG" ;; + *) echo "Usage: secret [-g] [-e env] KEY" >&2; return 1 ;; + esac + done + shift $((OPTIND-1)) + + local key="$1" + [[ -z "$key" ]] && { echo "Usage: secret [-g] [-e env] KEY" >&2; return 1; } + + command -v skate >/dev/null 2>&1 || { echo "Missing: skate" >&2; return 1; } + command -v gum >/dev/null 2>&1 || { echo "Missing: gum" >&2; return 1; } + + local db + if [[ "$scope" == "global" ]]; then + db="$(_secrets_db_global "$env")" + else + db="$(_secrets_db_repo "$env" 2>/dev/null)" || db="$(_secrets_db_global "$env")" + fi + + local value + value="$(gum input --password --prompt "Enter secret for $key ($db): ")" || return 1 + printf "\n" >&2 + [[ -z "$value" ]] && { echo "Empty value, aborting." >&2; return 1; } + + skate set "${key}@${db}" "$value" + echo "Stored ${key}@${db}" +} + +secret-get() { + emulate -L zsh + setopt localoptions pipefail + + local env="dev" + local OPTIND=1 opt + while getopts ":e:" opt; do + case "$opt" in + e) env="$OPTARG" ;; + *) echo "Usage: secret-get [-e env] KEY" >&2; return 1 ;; + esac + done + shift $((OPTIND-1)) + + local key="$1" + [[ -z "$key" ]] && { echo "Usage: secret-get [-e env] KEY" >&2; return 1; } + command -v skate >/dev/null 2>&1 || { echo "Missing: skate" >&2; return 1; } + + local repo_db global_db val + repo_db="$(_secrets_db_repo "$env" 2>/dev/null)" || repo_db="" + global_db="$(_secrets_db_global "$env")" + + if [[ -n "$repo_db" ]] && val="$(skate get "${key}@${repo_db}" 2>/dev/null)"; then + print -r -- "$val"; return 0 + fi + skate get "${key}@${global_db}" +} diff --git a/zsh/zshrc b/zsh/zshrc @@ -0,0 +1,187 @@ +# direnv integration (must be in interactive shells) +if command -v direnv >/dev/null 2>&1; then + eval "$(direnv hook zsh)" +fi + +# Secret helpers +if [[ -f "$HOME/.dotfiles/zsh/secrets.zsh" ]]; then + source "$HOME/.dotfiles/zsh/secrets.zsh" +fi + +# Path to your Oh My Zsh installation. +export ZSH_DISABLE_COMPFIX=true +export ZSH="$HOME/.oh-my-zsh" +eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" +#Set name of the theme to load --- if set to "random", it will +# load a random theme each time Oh My Zsh is loaded, in which case, +# to know which specific one was loaded, run: echo $RANDOM_THEME +# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes +ZSH_THEME="robbyrussell" + +# Uncomment one of the following lines to change the auto-update behavior +# zstyle ':omz:update' mode disabled # disable automatic updates +# zstyle ':omz:update' mode auto # update automatically without asking + zstyle ':omz:update' mode reminder # just remind me to update when it's time + +# Uncomment the following line to change how often to auto-update (in days). + zstyle ':omz:update' frequency 1 + +# Uncomment the following line if pasting URLs and other text is messed up. +# DISABLE_MAGIC_FUNCTIONS="true" + +# Uncomment the following line to disable colors in ls. +# DISABLE_LS_COLORS="true" + +# Uncomment the following line to disable auto-setting terminal title. +# DISABLE_AUTO_TITLE="true" + +# Uncomment the following line to enable command auto-correction. +# ENABLE_CORRECTION="true" + +# Uncomment the following line to display red dots whilst waiting for completion. +# You can also set it to another string to have that shown instead of the default red dots. +# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f" +# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765) +# COMPLETION_WAITING_DOTS="true" + +# Uncomment the following line if you want to disable marking untracked files +# under VCS as dirty. This makes repository status check for large repositories +# much, much faster. +# DISABLE_UNTRACKED_FILES_DIRTY="true" + +# Uncomment the following line if you want to change the command execution time +# stamp shown in the history command output. +# You can set one of the optional three formats: +# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" +# or set a custom format using the strftime function format specifications, +# see 'man strftime' for details. +# HIST_STAMPS="mm/dd/yyyy" + +# Would you like to use another custom folder than $ZSH/custom? +# ZSH_CUSTOM=/path/to/new-custom-folder + +# Which plugins would you like to load? +# Standard plugins can be found in $ZSH/plugins/ +# Custom plugins may be added to $ZSH_CUSTOM/plugins/ +# Example format: plugins=(rails git textmate ruby lighthouse) +# Add wisely, as too many plugins slow down shell startup. +plugins=(fzf git) + +source $ZSH/oh-my-zsh.sh + +# User configuration + +# export MANPATH="/usr/local/man:$MANPATH" + +# You may need to manually set your language environment +# export LANG=en_US.UTF-8 + +# Preferred editor for local and remote sessions +# if [[ -n $SSH_CONNECTION ]]; then +# export EDITOR='vim' +# else +# export EDITOR='nvim' +# fi + +# Compilation flags +# export ARCHFLAGS="-arch $(uname -m)" + +# Set personal aliases, overriding those provided by Oh My Zsh libs, +# plugins, and themes. Aliases can be placed here, though Oh My Zsh +# users are encouraged to define aliases within a top-level file in +# the $ZSH_CUSTOM folder, with .zsh extension. Examples: +# - $ZSH_CUSTOM/aliases.zsh +# - $ZSH_CUSTOM/macos.zsh +# For a full list of active aliases, run `alias`. +# +# Example aliases +# alias zshconfig="mate ~/.zshrc" +# alias ohmyzsh="mate ~/.oh-my-zsh" +autoload -U compinit; compinit +eval "$(zoxide init zsh)" + +export EDITOR='nvim' +# Aliases +## -- File Navigation -- +alias cd="z" +alias ci="zi" +alias ls="eza --icons" + +## -- Applications -- +alias e="nvim" +alias dotedit="chezmoi edit" +alias dotfiles="chezmoi" +alias ..="cd .." +alias ...="cd ../.." + +alias bhcli="/home/dasho/dev/bhcli-new/target/release/bhcli --refresh-rate 2 -m" +alias bhcli2="/home/dasho/dev/bhcli-new/target/release/bhcli --refresh-rate 2 --url http://blkh4ylofapg42tj6ht565klld5i42dhjtysvsnnswte4xt4uvnfj5qd.onion -m" +alias 404="/home/dasho/dev/bhcli-new/target/release/bhcli --refresh-rate 2 --url https://4-0-4.io/chat/min" +alias 404tor="/home/dasho/dev/bhcli-new/target/release/bhcli --refresh-rate 2 --url http://4o4o4hn4hsujpnbsso7tqigujuokafxys62thulbk2k3mf46vq22qfqd.onion/chat/min" +alias tb="cd /home/dasho/Downloads/tor-browser && ./start-tor-browser.desktop" + +alias -s md="glow" +alias -s py="$EDITOR" +alias -s txt="bat" +alias -s log="bat" +alias -s json="bat" +alias -s xml="bat" +alias -s csv="bat" +alias -s yml="$EDITOR" +alias -s yaml="$EDITOR" +alias -s html="$EDITOR" +alias -s js="$EDITOR" +alias -s css="$EDITOR" +# alias -s sh="$EDITOR" +# alias -s zsh="$EDITOR" +alias -s conf="bat" +alias -s toml="bat" +alias -s rs="$EDITOR" +alias -s go="$EDITOR" +alias -s c="$EDITOR" +alias -s cpp="$EDITOR" +alias -s h="$EDITOR" +alias -s hpp="$EDITOR" +alias -s mov="open" +alias -s mp4="open" +alias -s mkv="open" +alias -s jpg="open" +alias -s png="open" +alias -s gif="open" + +alias -g NE="2>/dev/null" +alias -g ND=">/dev/null" +alias -g NULL=">/dev/null 2>1" +alias -g F="| fzf" +alias -g T="| tail" +alias -g JQ="| jq" +alias -g G="| grep" +alias -g L="| less" +alias -g H="| head" + +# Source and export variables from ~/.env +if [ -f ~/.env ]; then + set -a + source ~/.env + set +a +fi +export PATH=$HOME/.local/bin:$PATH +export PATH="$HOME/.config/emacs/bin:$PATH" +export PATH="$HOME/Applications/halloy/bin:$PATH" + +chpwd() { + ls +} + +clear_buffer_screen() { + zle clear-screen +} +zle -N clear_buffer_screen +bindkey '^Xl' clear_buffer_screen + +# --- Auto-start Zellij for interactive shells --- +# if [[ -o interactive ]] && [[ -z "$ZELLIJ" ]] && command -v zellij >/dev/null 2>&1; then + # Attach to "main" if it exists, otherwise create it + # exec zellij attach --create main +# fi +# --- End Auto-start Zellij ---