diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82fc379 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dot-config/vim/view/ diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..e518e87 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,247 @@ +# Dotfiles Migration Checklist — Linux to macOS + +Tick the features you want to keep. Unticked items will **not** be ported. + +--- + +## Bash — Shell Options & Behavior + +- [x] Case-insensitive globbing (`nocaseglob`) +- [x] Append to history instead of overwriting (`histappend`) +- [x] Autocorrect typos in `cd` paths (`cdspell`) +- [x] `autocd` — type a directory name to `cd` into it +- [x] `globstar` — recursive globbing (`**/*.txt`) +- [x] `checkwinsize` — update terminal size after each command + +## Bash — History + +- [x] Unlimited history (`HISTSIZE=-1`) +- [x] Ignore duplicates and commands starting with space (`ignorespace:erasedups`) +- [x] Ignore common commands (`ls`, `cd`, `pwd`, `exit`, etc.) +- [x] Timestamps in history (`HISTTIMEFORMAT`) + +## Bash — Prompt + +- [x] Pure prompt theme (multiline, git branch, dirty/clean indicator, colored exit status) + +## Bash — SSH + +- [x] SSH hostname tab-completion from `~/.ssh/config` +- [x] Auto-start ssh-agent (NOTE: macOS has its own keychain agent — may not be needed) + +## Bash — GPG + +- [x] GPG-agent auto-start and TTY setup +- [x] GPG-agent as SSH agent (NOTE: macOS-specific paths needed) +- [x] GPG commit signing (git config) + +## Bash — Inputrc (Readline) + +- [x] Case-insensitive tab completion +- [x] Colored completion suggestions +- [x] Show-all-if-ambiguous (faster completion) +- [x] Up/Down arrow history search (search by prefix) +- [x] `Esc-s` to prefix command with `sudo` +- [x] `Esc-m` to open man page for command +- [x] Bracketed paste mode + +## Bash — Aliases: Navigation + +- [x] `..`, `...`, `....`, `.....` — quick parent directory navigation +- [x] `-` — go to previous directory +- [x] `dl` — cd to Downloads + +## Bash — Aliases: Shortcuts + +- [ ] `g` → `git` +- [ ] `h` → `history` +- [ ] `vi` → `vim` +- [x] `gs` → `git status -s` +- [x] `gl` → `git log (short)` +- [x] `k` → `kubectl` + +## Bash — Aliases: File Operations + +- [x] `rm` → `rm -i` (confirm before delete) +- [x] `cp` → `cp -i` (confirm before overwrite) +- [x] `mv` → `mv -i` (confirm before overwrite) +- [x] `untar` → `tar xvf` + +## Bash — Aliases: Listing + +- [x] `l` — long list with colors +- [x] `la` — long list including hidden files +- [x] `lsd` — list only directories +- [x] Colorized `grep`, `fgrep`, `egrep` + +## Bash — Aliases: Network + +- [x] `pubip` — show public IP via DNS lookup +- [ ] `localip` — show local IP address (NOTE: needs macOS adaptation) +- [ ] `sniff` — HTTP traffic sniffer via ngrep +- [ ] `httpdump` — HTTP traffic dump via tcpdump + +## Bash — Aliases: Clipboard + +- [x] `c` — trim newlines and copy to clipboard (NOTE: `wl-copy` → `pbcopy`) +- [x] `cwd` — copy working directory to clipboard +- [x] `pubkey` — copy public SSH key to clipboard +- [x] `prikey` — copy private SSH key to clipboard + +## Bash — Aliases: System + +- [x] `sudo` — enable aliases to be sudo'ed +- [ ] `week` — show current week number +- [ ] `timer` — simple stopwatch +- [x] `hosts` — edit /etc/hosts with vim +- [x] `afk` — lock screen (NOTE: `slock` → macOS lock command) +- [ ] `psc` — detailed process listing with cgroups +- [ ] `map` → `xargs -n1` + +## Bash — Aliases: Misc + +- [ ] `hd` — hex dump fallback +- [ ] `md5sum` / `sha1sum` — macOS fallbacks +- [ ] `urlencode` — URL-encode strings (NOTE: uses python2, needs update) + +## Bash — Aliases: Package Manager (Linux-specific) + +- [ ] `pac-search` — fzf-powered pacman search (NOTE: irrelevant on macOS, could adapt for brew) +- [ ] `pac-remove` — fzf-powered pacman remove (NOTE: irrelevant on macOS, could adapt for brew) + +## Bash — Functions: File/Directory + +- [x] `mkd` — create directory and cd into it +- [x] `tmpd` — create temp directory and cd into it +- [x] `targz` — create .tar.gz with best available compressor +- [x] `fs` — show file/directory sizes sorted +- [ ] `gz` — compare original vs gzipped size +- [x] `tre` — enhanced tree with colors, ignoring .git +- [ ] `v` — open vim (current dir if no args) +- [ ] `o` — open file/dir (NOTE: `xdg-open` → `open` on macOS) + +## Bash — Functions: Git + +- [x] `gdiff` — colored git diff for non-repo files +- [x] `repo` — open current repo in browser (NOTE: `xdg-open` → `open`) + +## Bash — Functions: Network/Web + +- [x] `digga` — enhanced DNS lookup +- [x] `getcertnames` — extract SSL certificate names from a domain +- [x] `isup` — check if a URL is online (NOTE: `notify-send` → `osascript`) +- [ ] `dataurl` — create base64 data URL from a file +- [ ] `gitio` — create git.io short URL (NOTE: git.io is discontinued) + +## Bash — Functions: Unicode + +- [ ] `escape` — UTF-8 encode a string +- [ ] `unidecode` — decode unicode escape sequences +- [ ] `codepoint` — get unicode code point of a character + +## Bash — Functions: Calculator + +- [x] `calc` — command-line calculator using bc + +## Bash — Functions: Go Development + +- [ ] `gostatic` — build Go static binary +- [ ] `gogo` — navigate to Go project in GOPATH +- [ ] `golistdeps` — list Go project dependencies + +## Bash — Functions: D-Bus (Linux-specific) + +- [ ] `dbs` — D-Bus session info (NOTE: does not exist on macOS) + +## Bash — Functions: Pet Snippets + +- [ ] `prev` — add previous command to pet snippet manager +- [ ] `pet-select` — search pet snippets (NOTE: requires `pet` tool) + +## Bash — Functions: Docker + +- [ ] `dcleanup` — remove stopped containers, dangling images +- [ ] `del_stopped` — remove a specific stopped container +- [ ] `relies_on` — ensure dependency containers are running +- [ ] Container wrappers (audacity, chrome, firefox, etc.) (NOTE: most are Linux/X11-specific) + +## Bash — Autocompletion + +- [x] Git completion +- [x] kubectl completion +- [x] fzf key-bindings and completion +- [ ] lxc completion +- [ ] flux completion + +## Bash — Exports/Environment + +- [x] `EDITOR=vim` +- [x] Colored man pages (LESS_TERMCAP variables) +- [x] `MANPAGER`, `LESS`, `LESSOPEN` config +- [x] `TODOTXT_DEFAULT_ACTION=ls` + +## Bash — PATH + +- [ ] Go paths (`GOPATH`, `GOBIN`) +- [ ] `~/.local/bin` +- [ ] Krew (kubectl plugin manager) + +--- + +## Git + +- [x] All aliases (l, s, d, di, p, pr, c, ca, go, graph, tags, branches, remotes, amend, credit, reb, fb, ft, fc, fm, dm, contributors, lg, mdiff, unreleased, up, undo, top, alias, squash, ignored, patchit) +- [x] Whitespace fix on apply +- [x] GPG commit signing +- [x] diff-so-fancy as pager (NOTE: needs `brew install diff-so-fancy`) +- [x] Custom excludesfile and attributesfile +- [x] Whitespace error detection +- [x] Auto-correct mistyped commands (`help.autocorrect = 1`) +- [x] SSH push instead of HTTPS for GitHub +- [x] Default branch = main +- [x] Color scheme (branch, diff, status) + +--- + +## Vim + +- [x] Core settings (autoindent, smart tabs, search highlighting, etc.) +- [x] Space as leader key +- [x] `jk` to escape insert mode +- [x] `;` mapped to `:` (skip shift for commands) +- [x] `j`/`k` navigate visual lines +- [x] `F2` paste toggle +- [x] `w!!` — sudo save +- [x] Tab key for bracket matching +- [x] Quick vimrc edit/reload (`ev`, `sv`) +- [x] Persistent undo across sessions +- [x] Backup and swap file configuration +- [x] Cursor line highlighting + +--- + +## macOS-specific (NEW — from today's setup) + +- [x] AeroSpace tiling window manager config +- [x] SketchyBar status bar config +- [x] JankyBorders window borders config +- [x] Ghostty terminal config +- [x] App launcher (choose-gui) scripts +- [x] Bitwarden integration script +- [x] GitHub integration script +- [x] Modifier switch script +- [x] Wallpaper + +--- + +## Install Script (NEW) + +The install script should handle: +- [x] Homebrew installation +- [x] Brew packages: aerospace, sketchybar, borders, ghostty, choose-gui, maccy, diff-so-fancy, vim, git, bash (newer version), fzf, tree, jq +- [x] Brew cask apps: maccy +- [x] JetBrainsMono Nerd Font installation +- [x] GNU Stow installation and linking +- [x] Bash as default shell (Homebrew bash, not macOS default) +- [x] Create vim backup/undo/swap directories +- [x] Start services (sketchybar, aerospace) diff --git a/dot-bash_profile b/dot-bash_profile new file mode 100644 index 0000000..4378166 --- /dev/null +++ b/dot-bash_profile @@ -0,0 +1,3 @@ +#!/bin/bash +# macOS opens login shells by default. Source .bashrc for all config. +[[ -r ~/.bashrc ]] && source ~/.bashrc diff --git a/dot-bashrc b/dot-bashrc index d12592e..0aa5cfa 100644 --- a/dot-bashrc +++ b/dot-bashrc @@ -1,15 +1,10 @@ #!/bin/bash # ~/.bashrc: executed by bash(1) for non-login shells. -# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) -# for examples +# macOS adaptation of Linux dotfiles # If not running interactively, don't do anything [[ $- != *i* ]] && return -# reset text properties -# see https://wiki.archlinux.org/index.php/Bash/Prompt_customization#Escapes_between_command_input_and_output -#trap 'tput sgr0' DEBUG - # Case-insensitive globbing (used in pathname expansion) shopt -s nocaseglob @@ -38,32 +33,21 @@ shopt -s checkwinsize grep -v "[?*]" | cut -d " " -f2 | \ tr ' ' '\n')" scp sftp ssh -# start the agent automatically and make sure that only one ssh-agent process runs at a time -if ! pgrep -u "$USER" ssh-agent > /dev/null; then - ssh-agent -t 1h > "$XDG_RUNTIME_DIR/ssh-agent.env" -fi -if [[ ! -f "$SSH_AUTH_SOCK" ]]; then - source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null +# ssh-agent: use macOS Keychain via ssh-add +# On macOS, ssh-agent is managed by launchd. Just ensure keys are added. +if [[ -z "$SSH_AUTH_SOCK" ]]; then + # Fallback: if SSH_AUTH_SOCK is somehow not set by launchd + export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh" fi -# enable programmable completion features (you don't need to enable -# this, if it's already enabled in /etc/bash.bashrc and /etc/profile -# sources /etc/bash.bashrc). -if ! shopt -oq posix; then - if [[ -f /usr/share/bash-completion/bash_completion ]]; then - # shellcheck source=/dev/null - . /usr/share/bash-completion/bash_completion - elif [[ -f /etc/bash_completion ]]; then - # shellcheck source=/dev/null - . /etc/bash_completion - fi -fi - -if [[ -d /etc/bash_completion.d ]]; then - for file in /etc/bash_completion.d/* ; do - # shellcheck source=/dev/null - source "$file" - done +# enable programmable completion features +# Use Homebrew's bash-completion if available +if [[ -r "/opt/homebrew/etc/profile.d/bash_completion.sh" ]]; then + # shellcheck source=/dev/null + . "/opt/homebrew/etc/profile.d/bash_completion.sh" +elif [[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]]; then + # shellcheck source=/dev/null + . "/usr/local/etc/profile.d/bash_completion.sh" fi # use a tty for gpg @@ -76,10 +60,10 @@ if ! pgrep -x -u "${USER}" gpg-agent >/dev/null 2>&1; then gpg-connect-agent updatestartuptty /bye >/dev/null fi -# Set SSH to use gpg-agent +# Set SSH to use gpg-agent (macOS path) unset SSH_AGENT_PID if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then - export SSH_AUTH_SOCK="/run/user/$UID/gnupg/S.gpg-agent.ssh" + export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh" fi # add alias for ssh to update the tty @@ -89,8 +73,7 @@ alias ssh="gpg-connect-agent updatestartuptty /bye >/dev/null; ssh" source ~/.config/bash/pure.sh # Load the shell dotfiles -#for file in ~/.{aliases,functions,dockerfunc,path,exports}; do -for file in ~/.config/bash/{aliases,autocompletion,functions,exports}; do +for file in ~/.config/bash/{path,aliases,autocompletion,functions,exports}; do if [[ -r "$file" ]] && [[ -f "$file" ]]; then # shellcheck source=/dev/null source "$file" diff --git a/dot-config/aerospace/aerospace.toml b/dot-config/aerospace/aerospace.toml new file mode 100644 index 0000000..8a98f18 --- /dev/null +++ b/dot-config/aerospace/aerospace.toml @@ -0,0 +1,184 @@ +# AeroSpace i3-like config +# ───────────────────────────────────────────────────────────── +# Modifier: 'alt' by default. +# To switch modifier, run: ~/.config/aerospace/switch-mod.sh +# WARNING: 'cmd' overrides macOS shortcuts (cmd-h, cmd-v, cmd-s, etc.) +# ───────────────────────────────────────────────────────────── +# Reference: https://github.com/i3/i3/blob/next/etc/config + +config-version = 2 + +# i3 phantom workspaces +persistent-workspaces = [] + +# Disable normalizations for i3 parity +enable-normalization-flatten-containers = false +enable-normalization-opposite-orientation-for-nested-containers = false + +# ── Startup ──────────────────────────────────────────────── +after-startup-command = [ + 'exec-and-forget borders active_color="glow(0xff00a2ff)" inactive_color=0x00565f89 width=4.0 style=round blacklist="System Settings,Finder"', +] + +# ── Callbacks ────────────────────────────────────────────── +on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] +on-focus-changed = ['move-mouse window-lazy-center'] + +# ── Gaps ─────────────────────────────────────────────────── +[gaps] +inner.horizontal = 4 +inner.vertical = 4 +outer.left = 4 +outer.bottom = 4 +outer.right = 4 +outer.top = 40 # Reserve space for SketchyBar (height 30 + offset 5 + padding 5) + +# ── Window rules ─────────────────────────────────────────── +# Assign apps to workspaces (like i3's 'assign') +[[on-window-detected]] +if.app-id = 'com.brave.Browser' +run = 'move-node-to-workspace 2' + +[[on-window-detected]] +if.app-id = 'com.tinyspeck.slackmacgap' +run = 'move-node-to-workspace 3' + +[[on-window-detected]] +if.app-id = 'net.whatsapp.WhatsApp' +run = 'move-node-to-workspace 3' + +[[on-window-detected]] +if.app-id = 'ru.keepcoder.Telegram' +run = 'move-node-to-workspace 3' + +# Float apps that work better floating +[[on-window-detected]] +if.app-id = 'com.apple.systempreferences' +run = 'layout floating' + +[[on-window-detected]] +if.app-id = 'com.apple.finder' +run = 'layout floating' + +[[on-window-detected]] +if.app-id = 'com.apple.calculator' +run = 'layout floating' + +# ── Monitor assignment ───────────────────────────────────── +# When a second monitor is connected: +# Workspaces 1-5 on main, 6-10 on secondary +[workspace-to-monitor-force-assignment] +1 = 'main' +2 = 'main' +3 = 'main' +4 = 'main' +5 = 'main' +6 = 'secondary' +7 = 'secondary' +8 = 'secondary' +9 = 'secondary' +10 = 'secondary' + +# ── Main keybindings ─────────────────────────────────────── +[mode.main.binding] + +# Launch terminal +# -n creates a new instance (needed to open on current workspace) +# Trade-off: each instance shows separately in cmd+tab +alt-enter = 'exec-and-forget open -na Ghostty' + +# Kill focused window +alt-shift-q = 'close' + +# Keybinding cheatsheet +alt-slash = 'exec-and-forget ~/.config/aerospace/cheatsheet.sh' + +# App launcher (dmenu-style via choose-gui) +alt-d = 'exec-and-forget ~/.config/aerospace/app-launcher.sh' + +# Bitwarden: search vault, copy password +alt-p = 'exec-and-forget ~/.config/aerospace/bitwarden.sh' + +# GitHub: PRs, issues, notifications +alt-g = 'exec-and-forget ~/.config/aerospace/github.sh' + +# Reload config +alt-shift-c = 'reload-config' + +# ── Focus (vim-style, wraps around) ──────────────────────── +alt-h = 'focus --boundaries-action wrap-around-the-workspace left' +alt-j = 'focus --boundaries-action wrap-around-the-workspace down' +alt-k = 'focus --boundaries-action wrap-around-the-workspace up' +alt-l = 'focus --boundaries-action wrap-around-the-workspace right' + +# ── Move windows ────────────────────────────────────────── +alt-shift-h = 'move left' +alt-shift-j = 'move down' +alt-shift-k = 'move up' +alt-shift-l = 'move right' + +# ── Monitors ────────────────────────────────────────────── +alt-comma = 'focus-monitor --wrap-around prev' +alt-period = 'focus-monitor --wrap-around next' +alt-shift-comma = 'move-node-to-monitor --wrap-around prev' +alt-shift-period = 'move-node-to-monitor --wrap-around next' + +# ── Split ───────────────────────────────────────────────── +# Using 'b' for horizontal since 'h' is focus-left +alt-b = 'split horizontal' +alt-v = 'split vertical' + +# ── Layout ──────────────────────────────────────────────── +alt-f = 'fullscreen' +alt-e = 'layout tiles horizontal vertical' # 'toggle split' in i3 +alt-shift-space = 'layout floating tiling' # 'floating toggle' in i3 + +# ── Scratchpad ──────────────────────────────────────────── +# Emulates i3 scratchpad using a hidden workspace 'S' +# alt+minus: send window to scratchpad +# alt+shift+minus: bring next scratchpad window here as floating +alt-minus = ['move-node-to-workspace S', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-minus = 'exec-and-forget ~/.config/aerospace/scratchpad.sh' + +# ── Workspaces ──────────────────────────────────────────── +# Each binding also notifies SketchyBar to update workspace indicators +alt-1 = ['workspace 1', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-2 = ['workspace 2', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-3 = ['workspace 3', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-4 = ['workspace 4', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-5 = ['workspace 5', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-6 = ['workspace 6', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-7 = ['workspace 7', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-8 = ['workspace 8', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-9 = ['workspace 9', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-0 = ['workspace 10', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] + +alt-shift-1 = ['move-node-to-workspace 1', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-2 = ['move-node-to-workspace 2', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-3 = ['move-node-to-workspace 3', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-4 = ['move-node-to-workspace 4', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-5 = ['move-node-to-workspace 5', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-6 = ['move-node-to-workspace 6', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-7 = ['move-node-to-workspace 7', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-8 = ['move-node-to-workspace 8', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-9 = ['move-node-to-workspace 9', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] +alt-shift-0 = ['move-node-to-workspace 10', 'exec-and-forget sketchybar --trigger aerospace_workspace_change'] + +# ── Resize mode ─────────────────────────────────────────── +alt-r = 'mode resize' + +[mode.resize.binding] +h = 'resize width -25' +j = 'resize height +25' +k = 'resize height -25' +l = 'resize width +25' +enter = 'mode main' +esc = 'mode main' + +# ── Environment ──────────────────────────────────────────── +# Fix PATH so exec-and-forget can find homebrew binaries +[exec] +inherit-env-vars = true + +[exec.env-vars] +PATH = '/usr/local/bin:/opt/homebrew/bin:${PATH}' diff --git a/dot-config/aerospace/app-launcher.sh b/dot-config/aerospace/app-launcher.sh new file mode 100755 index 0000000..df53d84 --- /dev/null +++ b/dot-config/aerospace/app-launcher.sh @@ -0,0 +1,36 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +# Build app list: regular apps + Brave profiles as separate entries +APPS=$(ls /Applications/ /System/Applications/ /System/Applications/Utilities/ 2>/dev/null \ + | grep '\.app$' \ + | sed 's/\.app$//' \ + | grep -v '^Brave Browser$' \ + | sort -u) + +# Add apps from non-standard locations +APPS=$(printf '%s\nFinder' "$APPS" | sort -u) + +# Add Brave profiles as separate entries +APPS=$(printf '%s\nBrave Browser (Franck)\nBrave Browser (Personal)' "$APPS" | sort -u) + +# Tokyonight colors: blue highlight, dark background +SELECTION=$(echo "$APPS" \ + | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "launch:") + +[ -z "$SELECTION" ] && exit 0 + +case "$SELECTION" in + "Brave Browser (Franck)") + open -na "Brave Browser" --args --profile-directory="Default" + ;; + "Brave Browser (Personal)") + open -na "Brave Browser" --args --profile-directory="Profile 1" + ;; + "Finder") + open -na /System/Library/CoreServices/Finder.app + ;; + *) + open -na "$SELECTION" + ;; +esac diff --git a/dot-config/aerospace/bitwarden.sh b/dot-config/aerospace/bitwarden.sh new file mode 100755 index 0000000..16348ad --- /dev/null +++ b/dot-config/aerospace/bitwarden.sh @@ -0,0 +1,69 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +# Check if session exists +if [ -z "$BW_SESSION" ] && [ -f "$HOME/.bw_session" ]; then + export BW_SESSION=$(cat "$HOME/.bw_session") +fi + +# Check vault status +STATUS=$(bw status 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])" 2>/dev/null) + +if [ "$STATUS" = "unauthenticated" ]; then + osascript -e 'display alert "Bitwarden" message "Not logged in. Run: bw login"' + exit 1 +fi + +if [ "$STATUS" = "locked" ]; then + # Prompt for master password via osascript + MASTER=$(osascript -e 'display dialog "Bitwarden Master Password:" default answer "" with hidden answer buttons {"Cancel","Unlock"} default button "Unlock"' -e 'text returned of result' 2>/dev/null) + [ -z "$MASTER" ] && exit 0 + BW_SESSION=$(bw unlock "$MASTER" --raw 2>/dev/null) + if [ -z "$BW_SESSION" ]; then + osascript -e 'display alert "Bitwarden" message "Failed to unlock vault."' + exit 1 + fi + export BW_SESSION + echo "$BW_SESSION" > "$HOME/.bw_session" + chmod 600 "$HOME/.bw_session" +fi + +# Sync and list items +bw sync --session "$BW_SESSION" 2>/dev/null + +# Get items and let user choose +ITEMS=$(bw list items --session "$BW_SESSION" 2>/dev/null | python3 -c " +import sys, json +items = json.load(sys.stdin) +for item in items: + name = item.get('name', '') + user = '' + if item.get('login'): + user = item['login'].get('username', '') or '' + if user: + print(f'{name} ({user})') + else: + print(name) +" 2>/dev/null) + +[ -z "$ITEMS" ] && exit 0 + +SELECTION=$(echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "bw:") + +[ -z "$SELECTION" ] && exit 0 + +# Extract name (strip username in parens) +SEARCH_NAME=$(echo "$SELECTION" | sed 's/ ([^)]*)//') + +# Get password for selected item +PASSWORD=$(bw list items --search "$SEARCH_NAME" --session "$BW_SESSION" 2>/dev/null | python3 -c " +import sys, json +items = json.load(sys.stdin) +if items and items[0].get('login') and items[0]['login'].get('password'): + print(items[0]['login']['password'], end='') +" 2>/dev/null) + +if [ -n "$PASSWORD" ]; then + echo -n "$PASSWORD" | pbcopy + osascript -e "display notification \"Password copied for: $SEARCH_NAME\" with title \"Bitwarden\"" +fi diff --git a/dot-config/aerospace/cheatsheet.sh b/dot-config/aerospace/cheatsheet.sh new file mode 100755 index 0000000..f1f105a --- /dev/null +++ b/dot-config/aerospace/cheatsheet.sh @@ -0,0 +1,23 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +CONFIG="$HOME/.config/aerospace/aerospace.toml" + +# Parse keybindings, clean up for display +grep -E '^alt[-+]' "$CONFIG" \ + | sed "s/ = \['/ → /; s/', '.*//; s/ = '/ → /; s/'$//" \ + | sed "s/ = '''/ → /; s/'''//" \ + | sed "s/'[[:space:]]*#.*//; s/'$//" \ + | sed 's/exec-and-forget //' \ + | sed 's|~/.config/aerospace/||' \ + | sed "s/osascript -e /Ghostty (new window)/" \ + | sed 's/--boundaries-action wrap-around-the-workspace //' \ + | sed 's/--wrap-around //' \ + | sed 's/move-node-to-workspace/move to ws/' \ + | sed 's/focus-monitor/focus monitor/' \ + | sed 's/move-node-to-monitor/move to monitor/' \ + | sed 's/layout floating tiling/toggle floating/' \ + | sed 's/layout tiles horizontal vertical/toggle split/' \ + | sort \ + | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 14 -n 30 -p "keys:" \ + > /dev/null diff --git a/dot-config/aerospace/github.sh b/dot-config/aerospace/github.sh new file mode 100755 index 0000000..a847f2e --- /dev/null +++ b/dot-config/aerospace/github.sh @@ -0,0 +1,61 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +# Check auth +if ! gh auth status &>/dev/null; then + osascript -e 'display alert "GitHub CLI" message "Not authenticated. Run: gh auth login"' + exit 1 +fi + +USERNAME=$(gh api user --jq '.login' 2>/dev/null) + +# Main menu +ACTION=$(printf "My PRs\nReview Requests\nMy Issues\nNotifications\nSearch Repos" \ + | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 10 -p "gh:") + +[ -z "$ACTION" ] && exit 0 + +case "$ACTION" in + "My PRs") + ITEMS=$(gh search prs --author="$USERNAME" --state=open --json repository,title,number --jq '.[] | "#\(.number) [\(.repository.name)] \(.title)"' 2>/dev/null) + [ -z "$ITEMS" ] && { osascript -e 'display notification "No open PRs" with title "GitHub"'; exit 0; } + SEL=$(echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "PRs:") + [ -z "$SEL" ] && exit 0 + NUM=$(echo "$SEL" | grep -oE '#[0-9]+' | tr -d '#') + REPO=$(echo "$SEL" | grep -oE '\[[^]]+\]' | tr -d '[]') + OWNER=$(gh search prs --author="$USERNAME" --state=open --json repository,number --jq ".[] | select(.number==$NUM) | .repository.nameWithOwner" 2>/dev/null | head -1) + [ -n "$OWNER" ] && open "https://github.com/$OWNER/pull/$NUM" + ;; + "Review Requests") + ITEMS=$(gh search prs --review-requested="$USERNAME" --state=open --json repository,title,number --jq '.[] | "#\(.number) [\(.repository.name)] \(.title)"' 2>/dev/null) + [ -z "$ITEMS" ] && { osascript -e 'display notification "No review requests" with title "GitHub"'; exit 0; } + SEL=$(echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "Reviews:") + [ -z "$SEL" ] && exit 0 + NUM=$(echo "$SEL" | grep -oE '#[0-9]+' | tr -d '#') + OWNER=$(gh search prs --review-requested="$USERNAME" --state=open --json repository,number --jq ".[] | select(.number==$NUM) | .repository.nameWithOwner" 2>/dev/null | head -1) + [ -n "$OWNER" ] && open "https://github.com/$OWNER/pull/$NUM" + ;; + "My Issues") + ITEMS=$(gh search issues --assignee="$USERNAME" --state=open --json repository,title,number --jq '.[] | "#\(.number) [\(.repository.name)] \(.title)"' 2>/dev/null) + [ -z "$ITEMS" ] && { osascript -e 'display notification "No open issues" with title "GitHub"'; exit 0; } + SEL=$(echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "Issues:") + [ -z "$SEL" ] && exit 0 + NUM=$(echo "$SEL" | grep -oE '#[0-9]+' | tr -d '#') + OWNER=$(gh search issues --assignee="$USERNAME" --state=open --json repository,number --jq ".[] | select(.number==$NUM) | .repository.nameWithOwner" 2>/dev/null | head -1) + [ -n "$OWNER" ] && open "https://github.com/$OWNER/issues/$NUM" + ;; + "Notifications") + ITEMS=$(gh api notifications --jq '.[] | "\(.subject.type): \(.subject.title)"' 2>/dev/null) + [ -z "$ITEMS" ] && { osascript -e 'display notification "No notifications" with title "GitHub"'; exit 0; } + echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "Notifs:" + open "https://github.com/notifications" + ;; + "Search Repos") + QUERY=$(echo "" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 1 -m -p "Search:") + [ -z "$QUERY" ] && exit 0 + ITEMS=$(gh search repos "$QUERY" --limit 15 --json fullName --jq '.[].fullName' 2>/dev/null) + [ -z "$ITEMS" ] && { osascript -e 'display notification "No results" with title "GitHub"'; exit 0; } + SEL=$(echo "$ITEMS" | choose -u -c 7aa2f7 -b 1a1b26 -f "JetBrainsMono Nerd Font" -s 16 -n 15 -p "Repos:") + [ -n "$SEL" ] && open "https://github.com/$SEL" + ;; +esac diff --git a/dot-config/aerospace/notify-sketchybar.sh b/dot-config/aerospace/notify-sketchybar.sh new file mode 100755 index 0000000..98d01ea --- /dev/null +++ b/dot-config/aerospace/notify-sketchybar.sh @@ -0,0 +1,3 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" +sketchybar --trigger aerospace_workspace_change diff --git a/dot-config/aerospace/scratchpad.sh b/dot-config/aerospace/scratchpad.sh new file mode 100755 index 0000000..92b51ac --- /dev/null +++ b/dot-config/aerospace/scratchpad.sh @@ -0,0 +1,47 @@ +#!/bin/bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +# Get the first window on the scratchpad workspace +WINDOW_ID=$(aerospace list-windows --workspace S --json 2>/dev/null | python3 -c " +import sys, json +windows = json.load(sys.stdin) +if windows: + print(windows[0]['window-id']) +" 2>/dev/null) + +if [ -z "$WINDOW_ID" ]; then + exit 0 +fi + +# Get app name for this window +APP_NAME=$(aerospace list-windows --workspace S --json 2>/dev/null | python3 -c " +import sys, json +windows = json.load(sys.stdin) +if windows: + print(windows[0]['app-name']) +" 2>/dev/null) + +# Get current workspace +CURRENT=$(aerospace list-workspaces --focused) + +# Move window to current workspace, make it floating, and focus it +aerospace move-node-to-workspace --window-id "$WINDOW_ID" "$CURRENT" +aerospace layout --window-id "$WINDOW_ID" floating +aerospace focus --window-id "$WINDOW_ID" + +# Center at ~25% of screen using AppleScript +osascript -e " +tell application \"System Events\" + set screenSize to {item 3, item 4} of (get bounds of window of desktop) + set winW to (item 1 of screenSize) / 2 + set winH to (item 2 of screenSize) / 2 + set winX to ((item 1 of screenSize) - winW) / 2 + set winY to ((item 2 of screenSize) - winH) / 2 + tell process \"$APP_NAME\" + set position of front window to {winX, winY} + set size of front window to {winW, winH} + end tell +end tell +" 2>/dev/null + +sketchybar --trigger aerospace_workspace_change diff --git a/dot-config/aerospace/switch-mod.sh b/dot-config/aerospace/switch-mod.sh new file mode 100755 index 0000000..4095d63 --- /dev/null +++ b/dot-config/aerospace/switch-mod.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Toggle AeroSpace modifier between alt and cmd +# Usage: ./switch-mod.sh (toggles) +# ./switch-mod.sh alt (switch to alt) +# ./switch-mod.sh cmd (switch to cmd) + +CONFIG="$HOME/.config/aerospace/aerospace.toml" + +# Detect current modifier +if grep -q '^alt-enter' "$CONFIG"; then + CURRENT="alt" +elif grep -q '^cmd-enter' "$CONFIG"; then + CURRENT="cmd" +else + echo "Could not detect current modifier" + exit 1 +fi + +# Determine target +if [ -n "$1" ]; then + TARGET="$1" +else + if [ "$CURRENT" = "alt" ]; then + TARGET="cmd" + else + TARGET="alt" + fi +fi + +if [ "$CURRENT" = "$TARGET" ]; then + echo "Already using '$TARGET' as modifier" + exit 0 +fi + +if [ "$TARGET" = "cmd" ]; then + echo "WARNING: Using 'cmd' will override macOS shortcuts (cmd-h, cmd-v, cmd-s, cmd-w, etc.)" + echo "" +fi + +# Swap modifier in keybindings (only lines starting with the modifier) +sed -i '' \ + -e "s/^${CURRENT}-/${TARGET}-/g" \ + -e "s/^# ${CURRENT}-/# ${TARGET}-/g" \ + "$CONFIG" + +echo "Switched modifier: $CURRENT -> $TARGET" +echo "Run 'aerospace reload-config' or press mod+shift+c to apply" diff --git a/dot-config/alacritty/alacritty.toml b/dot-config/alacritty/alacritty.toml deleted file mode 100644 index 7be7b34..0000000 --- a/dot-config/alacritty/alacritty.toml +++ /dev/null @@ -1,30 +0,0 @@ -[general] -live_config_reload = true - -import = [ - # uncomment the flavour you want below: - # "~/.config/alacritty/catppuccin-latte.toml" - # "~/.config/alacritty/catppuccin-frappe.toml" - "~/.config/alacritty/catppuccin-macchiato.toml" - # "~/.config/alacritty/catppuccin-mocha.toml" -] - -[cursor] -style = "Underline" - -[font] -normal = { family = "firacode", style = "Regular" } -bold = { family = "firacode", style = "Bold" } -italic = { family = "firacode", style = "Italic" } -size = 13 - -[selection] -save_to_clipboard = true - -[window] -opacity = 0.85 -padding = { x = 3, y = 3 } -dynamic_padding = true - -[env] -TERM = "xterm-256color" diff --git a/dot-config/alacritty/catppuccin-mocha.toml b/dot-config/alacritty/catppuccin-mocha.toml deleted file mode 100644 index 1dfe857..0000000 --- a/dot-config/alacritty/catppuccin-mocha.toml +++ /dev/null @@ -1,75 +0,0 @@ -[colors.primary] -background = "#1E1E2E" -foreground = "#CDD6F4" -dim_foreground = "#CDD6F4" -bright_foreground = "#CDD6F4" - -[colors.cursor] -text = "#1E1E2E" -cursor = "#F5E0DC" - -[colors.vi_mode_cursor] -text = "#1E1E2E" -cursor = "#B4BEFE" - -[colors.search.matches] -foreground = "#1E1E2E" -background = "#A6ADC8" - -[colors.search.focused_match] -foreground = "#1E1E2E" -background = "#A6E3A1" - -[colors.footer_bar] -foreground = "#1E1E2E" -background = "#A6ADC8" - -[colors.hints.start] -foreground = "#1E1E2E" -background = "#F9E2AF" - -[colors.hints.end] -foreground = "#1E1E2E" -background = "#A6ADC8" - -[colors.selection] -text = "#1E1E2E" -background = "#F5E0DC" - -[colors.normal] -black = "#45475A" -red = "#F38BA8" -green = "#A6E3A1" -yellow = "#F9E2AF" -blue = "#89B4FA" -magenta = "#F5C2E7" -cyan = "#94E2D5" -white = "#BAC2DE" - -[colors.bright] -black = "#585B70" -red = "#F38BA8" -green = "#A6E3A1" -yellow = "#F9E2AF" -blue = "#89B4FA" -magenta = "#F5C2E7" -cyan = "#94E2D5" -white = "#A6ADC8" - -[colors.dim] -black = "#45475A" -red = "#F38BA8" -green = "#A6E3A1" -yellow = "#F9E2AF" -blue = "#89B4FA" -magenta = "#F5C2E7" -cyan = "#94E2D5" -white = "#BAC2DE" - -[[colors.indexed_colors]] -index = 16 -color = "#FAB387" - -[[colors.indexed_colors]] -index = 17 -color = "#F5E0DC" diff --git a/dot-config/bash/aliases b/dot-config/bash/aliases index 157b6ab..a1bd520 100644 --- a/dot-config/bash/aliases +++ b/dot-config/bash/aliases @@ -1,10 +1,7 @@ #!/bin/bash -# https://github.com/jessfraz/dotfiles - -# Linux specific aliases -#alias pbcopy='xclip -selection clipboard' -#alias pbpaste='xclip -selection clipboard -o' +# macOS dotfiles - aliases +# Adapted from Linux dotfiles # Easier navigation: .., ..., ...., ....., ~ and - alias ..="cd .." @@ -15,32 +12,32 @@ alias -- -="cd -" # Shortcuts alias dl="cd ~/Downloads" -alias g="git" -alias h="history" -alias vi="vim" +# DISABLED: g→git (prefer explicit 'git' command) +#alias g="git" +# DISABLED: h→history +#alias h="history" +# DISABLED: vi→vim +#alias vi="vim" + +# git +alias gs="git s" +alias gl="git l" -# Safe rm +# k8s +alias k=kubectl + +# Safe file operations alias rm="rm -i" +alias cp='cp -i' +alias mv='mv -i' -# REVIEW -# enable color support of ls and also add handy aliases -if [ -x /usr/bin/dircolors ]; then - # shellcheck disable=SC2015 - test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" - #alias ll='ls -l --color=auto' - alias lla='ls -la --color=auto' - alias dir='dir --color=auto' - alias vdir='vdir --color=auto' - - alias grep='grep --color=auto' - alias fgrep='fgrep --color=auto' - alias egrep='egrep --color=auto' -fi +# untar +alias untar='tar xvf' # Detect which `ls` flavor is in use if ls --color > /dev/null 2>&1; then # GNU `ls` colorflag="--color" -else # OS X `ls` +else # macOS `ls` colorflag="-G" fi @@ -56,100 +53,56 @@ alias la="ls -laF ${colorflag}" # shellcheck disable=SC2139 alias lsd="ls -lF ${colorflag} | grep --color=never '^d'" -# Colorized cat -#alias cat='ccat --bg=dark' +# Colored grep +alias grep='grep --color=auto' +alias fgrep='fgrep --color=auto' +alias egrep='egrep --color=auto' -# Enable aliases to be sudo’ed +# Enable aliases to be sudo'ed alias sudo='sudo ' -# Get week number -alias week='date +%V' - -# Stopwatch -alias timer='echo "Timer started. Stop with Ctrl-D." && date && time cat && date' - # IP addresses alias pubip="dig +short myip.opendns.com @resolver1.opendns.com" -alias localip="ip address | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | grep -Eo '([0-9]*\.){3}[0-9]*'" -#alias ips="sudo ifconfig -a | grep -o 'inet6\? \(addr:\)\?\s\?\(\(\([0-9]\+\.\)\{3\}[0-9]\+\)\|[a-fA-F0-9:]\+\)' | awk '{ sub(/inet6? (addr:)? ?/, \"\"); print }'" - -# Flush Directory Service cache on OSX -#alias flush="dscacheutil -flushcache && killall -HUP mDNSResponder" +# DISABLED: localip (Linux-specific 'ip' command) +#alias localip="ipconfig getifaddr en0" +# DISABLED: sniff (Linux-specific interface) +#alias sniff="sudo ngrep -d 'en0' -t '^(GET|POST) ' 'tcp and port 80'" +# DISABLED: httpdump (Linux-specific interface) +#alias httpdump="sudo tcpdump -i en0 -n -s 0 -w - | grep -a -o -E \"Host\: .*|GET \/.*\"" -# View HTTP traffic -# could export the interface name or just not use it -alias sniff="sudo ngrep -d 'wlan0' -t '^(GET|POST) ' 'tcp and port 80'" -alias httpdump="sudo tcpdump -i wlan0 -n -s 0 -w - | grep -a -o -E \"Host\: .*|GET \/.*\"" +# Trim new lines and copy to clipboard (adapted: wl-copy → pbcopy) +alias c="tr -d '\n' | pbcopy" -# Canonical hex dump; some systems have this symlinked -command -v hd > /dev/null || alias hd="hexdump -C" +# copy working directory (adapted: wl-copy → pbcopy) +alias cwd='pwd | tr -d "\r\n" | pbcopy' -# OS X has no `md5sum`, so use `md5` as a fallback -command -v md5sum > /dev/null || alias md5sum="md5" +# Pipe my public key to my clipboard (adapted: wl-copy → pbcopy) +alias pubkey="more ~/.ssh/id_ed25519.pub | pbcopy | echo '=> Public key copied to pasteboard.'" -# OS X has no `sha1sum`, so use `shasum` as a fallback -command -v sha1sum > /dev/null || alias sha1sum="shasum" +# Pipe my private key to my clipboard (adapted: wl-copy → pbcopy) +alias prikey="more ~/.ssh/id_ed25519 | pbcopy | echo '=> Private key copied to pasteboard.'" -# Trim new lines and copy to clipboard -alias c="tr -d '\n' | wl-copy" - -# URL-encode strings -alias urlencode='python2 -c "import sys, urllib as ul; print ul.quote_plus(sys.argv[1]);"' - -# git -alias gs="git s" -alias gl="git l" - -# Merge PDF files -# Usage: `mergepdf -o output.pdf input{1,2,3}.pdf` -#alias mergepdf='/System/Library/Automator/Combine\ PDF\ Pages.action/Contents/Resources/join.py' - -# Intuitive map function -# For example, to list all directories that contain a certain file: -# find . -name .gitattributes | map dirname -alias map="xargs -n1" - -# One of @janmoesen’s ProTip™s -#for method in GET HEAD POST PUT DELETE TRACE OPTIONS; do -# # shellcheck disable=SC2139,SC2140 -# alias "$method"="lwp-request -m \"$method\"" -#done - -# Kill all the tabs in Chrome to free up memory -# [C] explained: http://www.commandlinefu.com/commands/view/402/exclude-grep-from-your-grepped-output-of-ps-alias-included-in-description -#alias chromekill="ps ux | grep '[C]hrome Helper --type=renderer' | grep -v extension-process | tr -s ' ' | cut -d ' ' -f2 | xargs kill" - -# service information of processes -alias psc='ps xawf -eo pid,user,cgroup,%mem,%cpu,args' - -# Lock the screen (when going AFK) -alias afk="slock" +# Lock the screen (adapted: slock → macOS lock screen) +alias afk="/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend" # vhosts alias hosts='sudo vim /etc/hosts' -# copy working directory -alias cwd='pwd | tr -d "\r\n" | wl-copy' - -# copy file interactive -alias cp='cp -i' - -# move file interactive -alias mv='mv -i' - -# untar -alias untar='tar xvf' - -# Pipe my public key to my clipboard. -alias pubkey="more ~/.ssh/id_ed25519.pub | wl-copy | echo '=> Public key copied to pasteboard.'" - -# Pipe my private key to my clipboard. -alias prikey="more ~/.ssh/id_ed25519 | wl-copy | echo '=> Private key copied to pasteboard.'" - -# k8s -alias k=kubectl - -# fzf -alias pac-search="pacman -Slq | fzf --multi --preview 'pacman -Si {1}' | xargs -ro sudo pacman -S" -alias pac-remove="pacman -Qq | fzf --multi --preview 'pacman -Qi {1}' | xargs -ro sudo pacman -Rns" - +# DISABLED: week - get week number +#alias week='date +%V' +# DISABLED: timer - stopwatch +#alias timer='echo "Timer started. Stop with Ctrl-D." && date && time cat && date' +# DISABLED: psc - service information of processes +#alias psc='ps xawf -eo pid,user,cgroup,%mem,%cpu,args' +# DISABLED: map - intuitive map function +#alias map="xargs -n1" +# DISABLED: hd - canonical hex dump +#command -v hd > /dev/null || alias hd="hexdump -C" +# DISABLED: md5sum/sha1sum fallbacks (not needed on macOS) +#command -v md5sum > /dev/null || alias md5sum="md5" +#command -v sha1sum > /dev/null || alias sha1sum="shasum" +# DISABLED: urlencode +#alias urlencode='python3 -c "import sys, urllib.parse; print(urllib.parse.quote_plus(sys.argv[1]));"' +# DISABLED: pac-search/pac-remove (Arch Linux pacman) +#alias pac-search="pacman -Slq | fzf --multi --preview 'pacman -Si {1}' | xargs -ro sudo pacman -S" +#alias pac-remove="pacman -Qq | fzf --multi --preview 'pacman -Qi {1}' | xargs -ro sudo pacman -Rns" diff --git a/dot-config/bash/autocompletion b/dot-config/bash/autocompletion index bb62c63..f4e723d 100644 --- a/dot-config/bash/autocompletion +++ b/dot-config/bash/autocompletion @@ -1,13 +1,32 @@ #!/bin/bash -source /usr/share/git/completion/git-completion.bash +# macOS dotfiles - autocompletion +# Adapted from Linux dotfiles -. <(kubectl completion bash) -complete -o default -F __start_kubectl k +# Git completion (Homebrew) +if [[ -r "/opt/homebrew/etc/bash_completion.d/git-completion.bash" ]]; then + source "/opt/homebrew/etc/bash_completion.d/git-completion.bash" +elif [[ -r "/usr/local/etc/bash_completion.d/git-completion.bash" ]]; then + source "/usr/local/etc/bash_completion.d/git-completion.bash" +fi -source /usr/share/fzf/key-bindings.bash -source /usr/share/fzf/completion.bash +# kubectl completion +if command -v kubectl &>/dev/null; then + . <(kubectl completion bash) + complete -o default -F __start_kubectl k +fi -. <(lxc completion bash) +# fzf completion and key-bindings (Homebrew) +if [[ -r "/opt/homebrew/opt/fzf/shell/key-bindings.bash" ]]; then + source "/opt/homebrew/opt/fzf/shell/key-bindings.bash" + source "/opt/homebrew/opt/fzf/shell/completion.bash" +elif [[ -r "/usr/local/opt/fzf/shell/key-bindings.bash" ]]; then + source "/usr/local/opt/fzf/shell/key-bindings.bash" + source "/usr/local/opt/fzf/shell/completion.bash" +fi -. <(flux completion bash) +# DISABLED: lxc completion +#. <(lxc completion bash) + +# DISABLED: flux completion +#. <(flux completion bash) diff --git a/dot-config/bash/bash_profile b/dot-config/bash/bash_profile deleted file mode 100644 index 24c1be4..0000000 --- a/dot-config/bash/bash_profile +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -# Load the shell dotfiles, and then some: -# * ~/.path can be used to extend `$PATH`. -# * add a ~/.extra file to use for other settings you don’t want to commit. -for file in ~/.{aliases,functions,dockerfunc,path,exports}; do - if [[ -r "$file" ]] && [[ -f "$file" ]]; then - # shellcheck source=/dev/null - source "$file" - fi -done -unset file - -# Load the completion files: -for file in ~/.autocompletion_functions/*; do - if [[ -r "$file" ]] && [[ -f "$file" ]]; then - # shellcheck source=/dev/null - source "$file" - fi -done -unset file - -# Case-insensitive globbing (used in pathname expansion) -shopt -s nocaseglob - -# Append to the Bash history file, rather than overwriting it -shopt -s histappend - -# Autocorrect typos in path names when using `cd` -shopt -s cdspell - -# Enable some Bash 4 features when possible: -# * `autocd`, e.g. `**/qux` will enter `./foo/bar/baz/qux` -# * Recursive globbing, e.g. `echo **/*.txt` -for option in autocd globstar; do - shopt -s "$option" 2> /dev/null -done - -# Add tab completion for SSH hostnames based on ~/.ssh/config -# ignoring wildcards -[[ -e "$HOME/.ssh/config" ]] && complete -o "default" \ - -o "nospace" \ - -W "$(grep "^Host" ~/.ssh/config | \ - grep -v "[?*]" | cut -d " " -f2 | \ - tr ' ' '\n')" scp sftp ssh - -# print a fortune when the terminal opens -#fortune -a -s | lolcat - -# Load RVM into a shell session *as a function* -#[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" - -# Start sway at login -#if [ -z "${WAYLAND_DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then -# exec sway -#fi - diff --git a/dot-config/bash/dockerfunc b/dot-config/bash/dockerfunc deleted file mode 100644 index af7b3e7..0000000 --- a/dot-config/bash/dockerfunc +++ /dev/null @@ -1,1118 +0,0 @@ -#!/bin/bash -# Bash wrappers for docker run commands - -export DOCKER_REPO_PREFIX=jess - -# -# Helper Functions -# -dcleanup(){ - local containers - containers=( $(docker ps -aq 2>/dev/null) ) - docker rm "${containers[@]}" 2>/dev/null - local volumes - volumes=( $(docker ps --filter status=exited -q 2>/dev/null) ) - docker rm -v "${volumes[@]}" 2>/dev/null - local images - images=( $(docker images --filter dangling=true -q 2>/dev/null) ) - docker rmi "${images[@]}" 2>/dev/null -} -del_stopped(){ - local name=$1 - local state - state=$(sudo docker inspect --format "{{.State.Running}}" "$name" 2>/dev/null) - - if [[ "$state" == "false" ]]; then - sudo docker rm "$name" - fi -} -relies_on(){ - for container in "$@"; do - local state - state=$(docker inspect --format "{{.State.Running}}" "$container" 2>/dev/null) - - if [[ "$state" == "false" ]] || [[ "$state" == "" ]]; then - echo "$container is not running, starting it for you." - $container - fi - done -} -# creates an nginx config for a local route -nginx_config(){ - server=$1 - route=$2 - - cat >"${HOME}/.nginx/conf.d/${server}.conf" <<-EOF - upstream ${server} { server ${route}; } - server { - server_name ${server}; - - location / { - proxy_pass http://${server}; - proxy_http_version 1.1; - proxy_set_header Upgrade \$http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host \$http_host; - proxy_set_header X-Forwarded-Proto \$scheme; - proxy_set_header X-Forwarded-For \$remote_addr; - proxy_set_header X-Forwarded-Port \$server_port; - proxy_set_header X-Request-Start \$msec; -} - } - EOF - - # restart nginx - docker restart nginx - - # add host to /etc/hosts - hostess add "$server" 127.0.0.1 - - # open browser - browser-exec "http://${server}" -} - -# -# Container Aliases -# -apt_file(){ - docker run --rm -it \ - --name apt-file \ - ${DOCKER_REPO_PREFIX}/apt-file -} -alias apt-file="apt_file" -audacity(){ - del_stopped audacity - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e QT_DEVICE_PIXEL_RATIO \ - --device /dev/snd \ - --group-add audio \ - --name audacity \ - ${DOCKER_REPO_PREFIX}/audacity -} -aws(){ - docker run -it --rm \ - -v "${HOME}/.aws:/root/.aws" \ - --log-driver none \ - --name aws \ - ${DOCKER_REPO_PREFIX}/awscli "$@" -} -az(){ - docker run -it --rm \ - -v "${HOME}/.azure:/root/.azure" \ - --log-driver none \ - --name azure \ - ${DOCKER_REPO_PREFIX}/azure-cli "$@" -} -bees(){ - docker run -it --rm \ - -e NOTARY_TOKEN \ - -v "${HOME}/.bees:/root/.bees" \ - -v "${HOME}/.boto:/root/.boto" \ - -v "${HOME}/.dev:/root/.ssh:ro" \ - --log-driver none \ - --name bees \ - ${DOCKER_REPO_PREFIX}/beeswithmachineguns "$@" -} -cadvisor(){ - docker run -d \ - --restart always \ - -v /:/rootfs:ro \ - -v /var/run:/var/run:rw \ - -v /sys:/sys:ro \ - -v /var/lib/docker/:/var/lib/docker:ro \ - -p 1234:8080 \ - --name cadvisor \ - google/cadvisor - - hostess add cadvisor "$(docker inspect --format '{{.NetworkSettings.Networks.bridge.IPAddress}}' cadvisor)" - browser-exec "http://cadvisor:8080" -} -cheese(){ - del_stopped cheese - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v "${HOME}/Pictures:/root/Pictures" \ - --device /dev/video0 \ - --device /dev/snd \ - --device /dev/dri \ - --name cheese \ - ${DOCKER_REPO_PREFIX}/cheese -} -chrome(){ - # add flags for proxy if passed - local proxy= - local map - local args=$* - if [[ "$1" == "tor" ]]; then - relies_on torproxy - - map="MAP * ~NOTFOUND , EXCLUDE torproxy" - proxy="socks5://torproxy:9050" - args="https://check.torproject.org/api/ip ${*:2}" - fi - - del_stopped chrome - - # one day remove /etc/hosts bind mount when effing - # overlay support inotify, such bullshit - docker run -d \ - --memory 3gb \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v "${HOME}/Downloads:/root/Downloads" \ - -v "${HOME}/Pictures:/root/Pictures" \ - -v "${HOME}/Torrents:/root/Torrents" \ - -v "${HOME}/.chrome:/data" \ - -v /dev/shm:/dev/shm \ - -v /etc/hosts:/etc/hosts \ - --security-opt seccomp:/etc/docker/seccomp/chrome.json \ - --device /dev/snd \ - --device /dev/dri \ - --device /dev/video0 \ - --device /dev/usb \ - --device /dev/bus/usb \ - --group-add audio \ - --group-add video \ - --name chrome \ - ${DOCKER_REPO_PREFIX}/chrome --user-data-dir=/data \ - --proxy-server="$proxy" \ - --host-resolver-rules="$map" "$args" - -} -consul(){ - del_stopped consul - - # check if we passed args and if consul is running - local state - state=$(docker inspect --format "{{.State.Running}}" consul 2>/dev/null) - if [[ "$state" == "true" ]] && [[ "$*" != "" ]]; then - docker exec -it consul consul "$@" - return 0 - fi - - docker run -d \ - --restart always \ - -v "${HOME}/.consul:/etc/consul.d" \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --net host \ - -e GOMAXPROCS=2 \ - --name consul \ - ${DOCKER_REPO_PREFIX}/consul agent \ - -bootstrap-expect 1 \ - -config-dir /etc/consul.d \ - -data-dir /data \ - -encrypt "$(docker run --rm ${DOCKER_REPO_PREFIX}/consul keygen)" \ - -ui-dir /usr/src/consul \ - -server \ - -dc neverland \ - -bind 0.0.0.0 - - hostess add consul "$(docker inspect --format '{{.NetworkSettings.Networks.bridge.IPAddress}}' consul)" - browser-exec "http://consul:8500" -} -dcos(){ - docker run -it --rm \ - -v "${HOME}/.dcos:/root/.dcos" \ - -v "$(pwd):/root/apps" \ - -w /root/apps \ - ${DOCKER_REPO_PREFIX}/dcos-cli "$@" -} -firefox(){ - del_stopped firefox - - sudo docker run -d \ - --memory 2gb \ - --net host \ - --cpuset-cpus 0 \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v "${HOME}/.firefox/cache:/root/.cache/mozilla" \ - -v "${HOME}/.firefox/mozilla:/root/.mozilla" \ - -v "${HOME}/Downloads:/root/Downloads" \ - -v "${HOME}/Pictures:/root/Pictures" \ - -v "${HOME}/Torrents:/root/Torrents" \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - --device /dev/snd \ - --device /dev/dri \ - --name firefox \ - ${DOCKER_REPO_PREFIX}/firefox2 "$@" - - # exit current shell - exit 0 -} -gcalcli(){ - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/.gcalcli/home:/home/gcalcli/home" \ - -v "${HOME}/.gcalcli/work/oauth:/home/gcalcli/.gcalcli_oauth" \ - -v "${HOME}/.gcalcli/work/gcalclirc:/home/gcalcli/.gcalclirc" \ - --name gcalcli \ - ${DOCKER_REPO_PREFIX}/gcalcli "$@" -} -dgcloud(){ - docker run --rm -it \ - -v "${HOME}/.gcloud:/root/.config/gcloud" \ - -v "${HOME}/.ssh:/root/.ssh:ro" \ - -v "$(which docker):/usr/bin/docker" \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --name gcloud \ - ${DOCKER_REPO_PREFIX}/gcloud "$@" -} -gimp(){ - del_stopped gimp - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v "${HOME}/Pictures:/root/Pictures" \ - -v "${HOME}/.gtkrc:/root/.gtkrc" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - --name gimp \ - ${DOCKER_REPO_PREFIX}/gimp -} -gitsome(){ - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - --name gitsome \ - --hostname gitsome \ - -v "${HOME}/.gitsomeconfig:/home/anon/.gitsomeconfig" \ - -v "${HOME}/.gitsomeconfigurl:/home/anon/.gitsomeconfigurl" \ - ${DOCKER_REPO_PREFIX}/gitsome -} -hollywood(){ - docker run --rm -it \ - --name hollywood \ - ${DOCKER_REPO_PREFIX}/hollywood -} -#htop(){ -# docker run --rm -it \ -# --pid host \ -# --net none \ -# --name htop \ -# ${DOCKER_REPO_PREFIX}/htop -#} -http(){ - docker run -t --rm \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --log-driver none \ - ${DOCKER_REPO_PREFIX}/httpie "$@" -} -imagemin(){ - local image=$1 - local extension="${image##*.}" - local filename="${image%.*}" - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/Pictures:/root/Pictures" \ - ${DOCKER_REPO_PREFIX}/imagemin sh -c "imagemin /root/Pictures/${image} > /root/Pictures/${filename}_min.${extension}" -} -irssi() { - del_stopped irssi - # relies_on notify_osd - - docker run --rm -it \ - --user root \ - -v "${HOME}/.irssi:/home/user/.irssi" \ - ${DOCKER_REPO_PREFIX}/irssi \ - chown -R user /home/user/.irssi - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/.irssi:/home/user/.irssi" \ - --read-only \ - --name irssi \ - ${DOCKER_REPO_PREFIX}/irssi -} -john(){ - local file - file=$(realpath "$1") - - docker run --rm -it \ - -v "${file}:/root/$(basename "${file}")" \ - ${DOCKER_REPO_PREFIX}/john "$@" -} -kernel_builder(){ - docker run --rm -it \ - -v /usr/src:/usr/src \ - --cpu-shares=512 \ - --name kernel-builder \ - ${DOCKER_REPO_PREFIX}/kernel-builder -} -keypassxc(){ - del_stopped keypassxc - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v /usr/share/X11/xkb:/usr/share/X11/xkb:ro \ - -e "DISPLAY=unix${DISPLAY}" \ - -v /etc/machine-id:/etc/machine-id:ro \ - --name keypassxc \ - ${DOCKER_REPO_PREFIX}/keepassxc -} -kvm(){ - del_stopped kvm - relies_on pulseaudio - - # modprobe the module - modprobe kvm - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v /run/libvirt:/var/run/libvirt \ - -e "DISPLAY=unix${DISPLAY}" \ - --link pulseaudio:pulseaudio \ - -e PULSE_SERVER=pulseaudio \ - --group-add audio \ - --name kvm \ - --privileged \ - ${DOCKER_REPO_PREFIX}/kvm -} -libreoffice(){ - del_stopped libreoffice - - sudo docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v "${HOME}/Downloads:/root/Documents" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - --name libreoffice \ - ${DOCKER_REPO_PREFIX}/libreoffice -} -lpass(){ - docker run --rm -it \ - -v "${HOME}/.lpass:/root/.lpass" \ - --name lpass \ - ${DOCKER_REPO_PREFIX}/lpass "$@" -} -lynx(){ - docker run --rm -it \ - --name lynx \ - ${DOCKER_REPO_PREFIX}/lynx "$@" -} -masscan(){ - docker run -it --rm \ - --log-driver none \ - --net host \ - --cap-add NET_ADMIN \ - --name masscan \ - ${DOCKER_REPO_PREFIX}/masscan "$@" -} -mpd(){ - del_stopped mpd - - # adding cap sys_admin so I can use nfs mount - # the container runs as a unpriviledged user mpd - docker run -d \ - --device /dev/snd \ - --cap-add SYS_ADMIN \ - -e MPD_HOST=/var/lib/mpd/socket \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/exports:/etc/exports:ro \ - -v "${HOME}/.mpd:/var/lib/mpd" \ - -v "${HOME}/.mpd.conf:/etc/mpd.conf" \ - --name mpd \ - ${DOCKER_REPO_PREFIX}/mpd -} -mutt(){ - # subshell so we dont overwrite variables - ( - local account=$1 - export IMAP_SERVER - export SMTP_SERVER - - if [[ "$account" == "riseup" ]]; then - export GMAIL=$MAIL_RISEUP - export GMAIL_NAME=$MAIL_RISEUP_NAME - export GMAIL_PASS=$MAIL_RISEUP_PASS - export GMAIL_FROM=$MAIL_RISEUP_FROM - IMAP_SERVER=mail.riseup.net - SMTP_SERVER=$IMAP_SERVER - fi - - docker run -it --rm \ - -e GMAIL \ - -e GMAIL_NAME \ - -e GMAIL_PASS \ - -e GMAIL_FROM \ - -e GPG_ID \ - -e IMAP_SERVER \ - -e SMTP_SERVER \ - -v "${HOME}/.gnupg:/home/user/.gnupg:ro" \ - -v /etc/localtime:/etc/localtime:ro \ - --name "mutt-${account}" \ - ${DOCKER_REPO_PREFIX}/mutt - ) -} -ncmpc(){ - del_stopped ncmpc - - docker run --rm -it \ - -v "${HOME}/.mpd/socket:/var/run/mpd/socket" \ - -e MPD_HOST=/var/run/mpd/socket \ - --name ncmpc \ - ${DOCKER_REPO_PREFIX}/ncmpc "$@" -} -neoman(){ - del_stopped neoman - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --device /dev/bus/usb \ - --device /dev/usb \ - --name neoman \ - ${DOCKER_REPO_PREFIX}/neoman -} -nes(){ - del_stopped nes - local game=$1 - - docker run -d \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --device /dev/dri \ - --device /dev/snd \ - --name nes \ - ${DOCKER_REPO_PREFIX}/nes "/games/${game}.rom" -} -netcat(){ - docker run --rm -it \ - --net host \ - ${DOCKER_REPO_PREFIX}/netcat "$@" -} -nginx(){ - del_stopped nginx - - docker run -d \ - --restart always \ - -v "${HOME}/.nginx:/etc/nginx" \ - --net host \ - --name nginx \ - nginx - - # add domain to hosts & open nginx - sudo hostess add jess 127.0.0.1 -} -nmap(){ - docker run --rm -it \ - --net host \ - ${DOCKER_REPO_PREFIX}/nmap "$@" -} -#notify_osd(){ -# del_stopped notify_osd -# -# docker run -d \ -# -v /etc/localtime:/etc/localtime:ro \ -# -v /tmp/.X11-unix:/tmp/.X11-unix \ -# --net none \ -# -v /etc \ -# -v /home/user/.dbus \ -# -v /home/user/.cache/dconf \ -# -e "DISPLAY=unix${DISPLAY}" \ -# --name notify_osd \ -# ${DOCKER_REPO_PREFIX}/notify-osd -#} -#alias notify-send=notify_send -#notify_send(){ -# relies_on notify_osd -# local args=${*:2} -# docker exec -i notify_osd notify-send "$1" "${args}" -#} -opensnitch(){ - del_stopped opensnitchd - del_stopped opensnitch - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - --net host \ - --cap-add NET_ADMIN \ - -v /etc/machine-id:/etc/machine-id:ro \ - -v /var/run/dbus:/var/run/dbus \ - -v /usr/share/dbus-1:/usr/share/dbus-1 \ - -v "/var/run/user/$(id -u):/var/run/user/$(id -u)" \ - -e DBUS_SESSION_BUS_ADDRESS \ - -e XAUTHORITY \ - -v "${HOME}/.Xauthority:$HOME/.Xauthority" \ - -v /tmp:/tmp \ - --name opensnitchd \ - ${DOCKER_REPO_PREFIX}/opensnitchd - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v /usr/share/X11:/usr/share/X11:ro \ - -v /usr/share/dbus-1:/usr/share/dbus-1 \ - -v /etc/machine-id:/etc/machine-id:ro \ - -v /var/run/dbus:/var/run/dbus \ - -v "/var/run/user/$(id -u):/var/run/user/$(id -u)" \ - -e DBUS_SESSION_BUS_ADDRESS \ - -e XAUTHORITY \ - -v "${HOME}/.Xauthority:$HOME/.Xauthority" \ - -e HOME \ - -e QT_DEVICE_PIXEL_RATIO \ - -e XDG_RUNTIME_DIR \ - -v /etc/passwd:/etc/passwd:ro \ - -v /etc/group:/etc/group:ro \ - -v /tmp:/tmp \ - -u "$(id -u)" -w "$HOME" \ - --net host \ - --name opensnitch \ - ${DOCKER_REPO_PREFIX}/opensnitch -} -pandoc(){ - local file=${*: -1} - local lfile - lfile=$(readlink -m "$(pwd)/${file}") - local rfile - rfile=$(readlink -m "/$(basename "$file")") - local args=${*:1:${#@}-1} - - docker run --rm \ - -v "${lfile}:${rfile}" \ - -v /tmp:/tmp \ - --name pandoc \ - ${DOCKER_REPO_PREFIX}/pandoc "${args}" "${rfile}" -} -pivman(){ - del_stopped pivman - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --device /dev/bus/usb \ - --device /dev/usb \ - --name pivman \ - ${DOCKER_REPO_PREFIX}/pivman -} -pms(){ - del_stopped pms - - docker run --rm -it \ - -v "${HOME}/.mpd/socket:/var/run/mpd/socket" \ - -e MPD_HOST=/var/run/mpd/socket \ - --name pms \ - ${DOCKER_REPO_PREFIX}/pms "$@" -} -pond(){ - del_stopped pond - relies_on torproxy - - docker run --rm -it \ - --net container:torproxy \ - --name pond \ - ${DOCKER_REPO_PREFIX}/pond -} -privoxy(){ - del_stopped privoxy - relies_on torproxy - - docker run -d \ - --restart always \ - --link torproxy:torproxy \ - -v /etc/localtime:/etc/localtime:ro \ - -p 8118:8118 \ - --name privoxy \ - ${DOCKER_REPO_PREFIX}/privoxy - - hostess add privoxy "$(docker inspect --format '{{.NetworkSettings.Networks.bridge.IPAddress}}' privoxy)" -} -pulseaudio(){ - del_stopped pulseaudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - --device /dev/snd \ - -p 4713:4713 \ - --restart always \ - --group-add audio \ - --name pulseaudio \ - ${DOCKER_REPO_PREFIX}/pulseaudio -} -rainbowstream(){ - docker run -it --rm \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/.rainbow_oauth:/root/.rainbow_oauth" \ - -v "${HOME}/.rainbow_config.json:/root/.rainbow_config.json" \ - --name rainbowstream \ - ${DOCKER_REPO_PREFIX}/rainbowstream -} -registrator(){ - del_stopped registrator - - docker run -d --restart always \ - -v /var/run/docker.sock:/tmp/docker.sock \ - --net host \ - --name registrator \ - gliderlabs/registrator consul: -} -remmina(){ - del_stopped remmina - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - -v "${HOME}/.remmina:/root/.remmina" \ - --name remmina \ - --net host \ - ${DOCKER_REPO_PREFIX}/remmina -} -ricochet(){ - del_stopped ricochet - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - -e QT_DEVICE_PIXEL_RATIO \ - --device /dev/dri \ - --name ricochet \ - ${DOCKER_REPO_PREFIX}/ricochet -} -rstudio(){ - del_stopped rstudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v "${HOME}/fastly-logs:/root/fastly-logs" \ - -v /dev/shm:/dev/shm \ - -e "DISPLAY=unix${DISPLAY}" \ - -e QT_DEVICE_PIXEL_RATIO \ - --device /dev/dri \ - --name rstudio \ - ${DOCKER_REPO_PREFIX}/rstudio -} -s3cmdocker(){ - del_stopped s3cmd - - docker run --rm -it \ - -e AWS_ACCESS_KEY="${DOCKER_AWS_ACCESS_KEY}" \ - -e AWS_SECRET_KEY="${DOCKER_AWS_ACCESS_SECRET}" \ - -v "$(pwd):/root/s3cmd-workspace" \ - --name s3cmd \ - ${DOCKER_REPO_PREFIX}/s3cmd "$@" -} -scudcloud(){ - del_stopped scudcloud - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v /etc/machine-id:/etc/machine-id:ro \ - -v /var/run/dbus:/var/run/dbus \ - -v "/var/run/user/$(id -u):/var/run/user/$(id -u)" \ - -e TERM \ - -e XAUTHORITY \ - -e DBUS_SESSION_BUS_ADDRESS \ - -e HOME \ - -e QT_DEVICE_PIXEL_RATIO \ - -v /etc/passwd:/etc/passwd:ro \ - -v /etc/group:/etc/group:ro \ - -u "$(whoami)" -w "$HOME" \ - -v "${HOME}/.Xauthority:$HOME/.Xauthority" \ - -v "${HOME}/.scudcloud:/home/jessie/.config/scudcloud" \ - --device /dev/snd \ - --name scudcloud \ - ${DOCKER_REPO_PREFIX}/scudcloud - - # exit current shell - exit 0 -} -shorewall(){ - del_stopped shorewall - - docker run --rm -it \ - --net host \ - --cap-add NET_ADMIN \ - --privileged \ - --name shorewall \ - ${DOCKER_REPO_PREFIX}/shorewall "$@" -} -skype(){ - del_stopped skype - relies_on pulseaudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --link pulseaudio:pulseaudio \ - -e PULSE_SERVER=pulseaudio \ - --security-opt seccomp:unconfined \ - --device /dev/video0 \ - --group-add video \ - --group-add audio \ - --name skype \ - ${DOCKER_REPO_PREFIX}/skype -} -slack(){ - del_stopped slack - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --device /dev/snd \ - --device /dev/dri \ - --device /dev/video0 \ - --group-add audio \ - --group-add video \ - -v "${HOME}/.slack:/root/.config/Slack" \ - --ipc="host" \ - --name slack \ - ${DOCKER_REPO_PREFIX}/slack "$@" -} -spotify(){ - del_stopped spotify - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e QT_DEVICE_PIXEL_RATIO \ - --security-opt seccomp:unconfined \ - --device /dev/snd \ - --device /dev/dri \ - --group-add audio \ - --group-add video \ - --name spotify \ - ${DOCKER_REPO_PREFIX}/spotify -} -ssh2john(){ - local file - file=$(realpath "$1") - - docker run --rm -it \ - -v "${file}:/root/$(basename "${file}")" \ - --entrypoint ssh2john \ - ${DOCKER_REPO_PREFIX}/john "$@" -} -steam(){ - del_stopped steam - relies_on pulseaudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/machine-id:/etc/machine-id:ro \ - -v /var/run/dbus:/var/run/dbus \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v "${HOME}/.steam:/home/steam" \ - -e "DISPLAY=unix${DISPLAY}" \ - --link pulseaudio:pulseaudio \ - -e PULSE_SERVER=pulseaudio \ - --device /dev/dri \ - --name steam \ - ${DOCKER_REPO_PREFIX}/steam -} -t(){ - docker run -t --rm \ - -v "${HOME}/.trc:/root/.trc" \ - --log-driver none \ - ${DOCKER_REPO_PREFIX}/t "$@" -} -tarsnap(){ - docker run --rm -it \ - -v "${HOME}/.tarsnaprc:/root/.tarsnaprc" \ - -v "${HOME}/.tarsnap:/root/.tarsnap" \ - -v "$HOME:/root/workdir" \ - ${DOCKER_REPO_PREFIX}/tarsnap "$@" -} -telnet(){ - docker run -it --rm \ - --log-driver none \ - ${DOCKER_REPO_PREFIX}/telnet "$@" -} -termboy(){ - del_stopped termboy - local game=$1 - - docker run --rm -it \ - --device /dev/snd \ - --name termboy \ - ${DOCKER_REPO_PREFIX}/nes "/games/${game}.rom" -} -tor(){ - del_stopped tor - - docker run -d \ - --net host \ - --name tor \ - ${DOCKER_REPO_PREFIX}/tor - - # set up the redirect iptables rules - sudo setup-tor-iptables - - # validate we are running through tor - browser-exec "https://check.torproject.org/" -} -torbrowser(){ - del_stopped torbrowser - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - --device /dev/snd \ - --name torbrowser \ - ${DOCKER_REPO_PREFIX}/tor-browser - - # exit current shell - exit 0 -} -tormessenger(){ - del_stopped tormessenger - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - --device /dev/snd \ - --name tormessenger \ - ${DOCKER_REPO_PREFIX}/tor-messenger - - # exit current shell - exit 0 -} -torproxy(){ - del_stopped torproxy - - docker run -d \ - --restart always \ - -v /etc/localtime:/etc/localtime:ro \ - -p 9050:9050 \ - --name torproxy \ - ${DOCKER_REPO_PREFIX}/tor-proxy - - hostess add torproxy "$(docker inspect --format '{{.NetworkSettings.Networks.bridge.IPAddress}}' torproxy)" -} -traceroute(){ - docker run --rm -it \ - --net host \ - ${DOCKER_REPO_PREFIX}/traceroute "$@" -} -transmission(){ - del_stopped transmission - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/Torrents:/transmission/download" \ - -v "${HOME}/.transmission:/transmission/config" \ - -p 9091:9091 \ - -p 51413:51413 \ - -p 51413:51413/udp \ - --name transmission \ - ${DOCKER_REPO_PREFIX}/transmission - - - hostess add transmission "$(docker inspect --format '{{.NetworkSettings.Networks.bridge.IPAddress}}' transmission)" - browser-exec "http://transmission:9091" -} -travis(){ - docker run -it --rm \ - -v "${HOME}/.travis:/root/.travis" \ - -v "$(pwd):/usr/src/repo:ro" \ - --workdir /usr/src/repo \ - --log-driver none \ - ${DOCKER_REPO_PREFIX}/travis "$@" -} -virsh(){ - relies_on kvm - - docker run -it --rm \ - -v /etc/localtime:/etc/localtime:ro \ - -v /run/libvirt:/var/run/libvirt \ - --log-driver none \ - --net container:kvm \ - ${DOCKER_REPO_PREFIX}/libvirt-client "$@" -} -virt_viewer(){ - relies_on kvm - - docker run -it --rm \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -v /run/libvirt:/var/run/libvirt \ - -e PULSE_SERVER=pulseaudio \ - --group-add audio \ - --log-driver none \ - --net container:kvm \ - ${DOCKER_REPO_PREFIX}/virt-viewer "$@" -} -alias virt-viewer="virt_viewer" -visualstudio(){ - del_stopped visualstudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --device /dev/dri \ - --name visualstudio \ - ${DOCKER_REPO_PREFIX}/vscode -} -alias vscode="visualstudio" -vlc(){ - del_stopped vlc - relies_on pulseaudio - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - -e GDK_SCALE \ - -e GDK_DPI_SCALE \ - -e QT_DEVICE_PIXEL_RATIO \ - --link pulseaudio:pulseaudio \ - -e PULSE_SERVER=pulseaudio \ - --group-add audio \ - --group-add video \ - -v "${HOME}/Torrents:/home/vlc/Torrents" \ - --device /dev/dri \ - --name vlc \ - ${DOCKER_REPO_PREFIX}/vlc -} -watchman(){ - del_stopped watchman - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/Downloads:/root/Downloads" \ - --name watchman \ - ${DOCKER_REPO_PREFIX}/watchman --foreground -} -weeslack(){ - del_stopped weeslack - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - -v "${HOME}/.weechat:/home/user/.weechat" \ - --name weeslack \ - ${DOCKER_REPO_PREFIX}/wee-slack -} -wireshark(){ - del_stopped wireshark - - docker run -d \ - -v /etc/localtime:/etc/localtime:ro \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e "DISPLAY=unix${DISPLAY}" \ - --cap-add NET_RAW \ - --cap-add NET_ADMIN \ - --net host \ - --name wireshark \ - ${DOCKER_REPO_PREFIX}/wireshark -} -wrk(){ - docker run -it --rm \ - --log-driver none \ - --name wrk \ - ${DOCKER_REPO_PREFIX}/wrk "$@" -} -ykman(){ - del_stopped ykpersonalize - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - --device /dev/usb \ - --device /dev/bus/usb \ - --name ykman \ - ${DOCKER_REPO_PREFIX}/ykman bash -} -ykpersonalize(){ - del_stopped ykpersonalize - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - --device /dev/usb \ - --device /dev/bus/usb \ - --name ykpersonalize \ - ${DOCKER_REPO_PREFIX}/ykpersonalize bash -} -yubico_piv_tool(){ - del_stopped yubico-piv-tool - - docker run --rm -it \ - -v /etc/localtime:/etc/localtime:ro \ - --device /dev/usb \ - --device /dev/bus/usb \ - --name yubico-piv-tool \ - ${DOCKER_REPO_PREFIX}/yubico-piv-tool bash -} -alias yubico-piv-tool="yubico_piv_tool" - -zoom(){ - del_stopped zoom - - sudo docker run -d \ - --net=host \ - --name zoom \ - -e DISPLAY=:0 \ - --device /dev/video0:/dev/video0 \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -v /dev/snd:/dev/snd \ - --privileged \ - -v /run/user/1000/pulse:/run/pulse \ - zoom -} - - -### -### Awesome sauce by @jpetazzo -### -if command -v "docker" &>/dev/null; then - command_not_found_handle () { - # Check if there is a container image with that name - if ! docker inspect --format '{{ .Author }}' "$1" >&/dev/null ; then - echo "$0: $1: command not found" - return - fi - - # Check that it's really the name of the image, not a prefix - if docker inspect --format '{{ .Id }}' "$1" | grep -q "^$1" ; then - echo "$0: $1: command not found" - return - fi - - docker run -ti -u "$(whoami)" -w "$HOME" \ - "$(env | cut -d= -f1 | awk '{print "-e", $1}')" \ - --device /dev/snd \ - -v /etc/passwd:/etc/passwd:ro \ - -v /etc/group:/etc/group:ro \ - -v /etc/localtime:/etc/localtime:ro \ - -v /home:/home \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - "${DOCKER_REPO_PREFIX}/${1}" "$@" - } -fi - diff --git a/dot-config/bash/exports b/dot-config/bash/exports index 60f07bd..a848ca7 100644 --- a/dot-config/bash/exports +++ b/dot-config/bash/exports @@ -1,8 +1,10 @@ #!/bin/bash +# macOS dotfiles - exports +# Adapted from Linux dotfiles + # Make vim the default editor -export EDITOR=/usr/bin/vim -#export TERMINAL="allacritty" +export EDITOR=vim # Do not truncate bash history export HISTSIZE=-1 @@ -12,14 +14,15 @@ export HISTCONTROL=ignorespace:erasedups export HISTIGNORE=" *:ls:cd:cd -:pwd:exit:date:* -h:pony:pony add *:pony update *:pony save *:pony ls:pony ls *" export HISTTIMEFORMAT="%F:%T" -# Prefer US English and use UTF-8 -#export LANG="en_US.UTF-8"; -#export LC_ALL="en_US.UTF-8"; - # Color for less and man export MANPAGER='less -s -M +Gg' export LESS="-R --RAW-CONTROL-CHARS" -export LESSOPEN="|lesspipe.sh %s" +# macOS: lesspipe.sh may be installed via Homebrew or may not exist +if command -v lesspipe.sh &>/dev/null; then + export LESSOPEN="|lesspipe.sh %s" +elif command -v lesspipe &>/dev/null; then + export LESSOPEN="|lesspipe %s" +fi export LESSCOLORIZER='bat' # man colors @@ -38,15 +41,4 @@ export LESS_TERMCAP_ZO=$(tput ssupm) export LESS_TERMCAP_ZW=$(tput rsupm) export GROFF_NO_SGR=1 -export DBUS_SESSION_BUS_ADDRESS=unix:path=/var/run/user/$(id -u)/bus - export TODOTXT_DEFAULT_ACTION=ls - -# hidpi for gtk apps -#export GDK_SCALE=2 -#export GDK_DPI_SCALE=0.5 -#export QT_DEVICE_PIXEL_RATIO=2 - -#export GIT_CONFIG=$HOME/.gitconfig_$HOSTNAME -#[[ -h ~/.gitconfig ]] || ln -s ~/.gitconfig_$HOSTNAME ~/.gitconfig - diff --git a/dot-config/bash/functions b/dot-config/bash/functions index 354708a..ddac990 100644 --- a/dot-config/bash/functions +++ b/dot-config/bash/functions @@ -1,5 +1,8 @@ #!/bin/bash +# macOS dotfiles - functions +# Adapted from Linux dotfiles + # Simple calculator calc() { local result="" @@ -44,7 +47,7 @@ targz() { tar -cvf "${tmpFile}" --exclude=".DS_Store" "${1}" || return 1 size=$( - stat -f"%z" "${tmpFile}" 2> /dev/null; # OS X `stat` + stat -f"%z" "${tmpFile}" 2> /dev/null; # macOS `stat` stat -c"%s" "${tmpFile}" 2> /dev/null # GNU `stat` ) @@ -71,154 +74,11 @@ fs() { du -shcx "$@" | sort -h } -# diff files with Git’s colored diff rather than /usr/bin/diff +# diff files with Git's colored diff rather than /usr/bin/diff gdiff() { git diff --no-index --color-words "$@" } -# Create a data URL from a file -dataurl() { - local mimeType - mimeType=$(file -b --mime-type "$1") - if [[ $mimeType == text/* ]]; then - mimeType="${mimeType};charset=utf-8" - fi - echo "data:${mimeType};base64,$(openssl base64 -in "$1" | tr -d '\n')" -} - -# Create a git.io short URL -gitio() { - curl -i https://git.io/ -F "url=${1}" -} - -## Start an HTTP server from a directory, optionally specifying the port -#server() { -# local port="${1:-8000}" -# sleep 1 && xdg-open "http://localhost:${port}/" & -# # Set the default Content-Type to `text/plain` instead of `application/octet-stream` -# # And serve everything as UTF-8 (although not technically correct, this doesn’t break anything for binary files) -# python2 -c $'import SimpleHTTPServer;\nmap = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map;\nmap[""] = "text/plain";\nfor key, value in map.items():\n\tmap[key] = value + ";charset=UTF-8";\nSimpleHTTPServer.test();' "$port" -#} - -# Compare original and gzipped file size -gz() { - local origsize - origsize=$(wc -c < "$1") - local gzipsize - gzipsize=$(gzip -c "$1" | wc -c) - local ratio - ratio=$(echo "$gzipsize * 100 / $origsize" | bc -l) - printf "orig: %d bytes\n" "$origsize" - printf "gzip: %d bytes (%2.2f%%)\n" "$gzipsize" "$ratio" -} - -## Syntax-highlight JSON strings or files -## Usage: `json '{"foo":42}'` or `echo '{"foo":42}' | json` -#json() { -# if [ -t 0 ]; then # argument -# python -mjson.tool <<< "$*" | pygmentize -l javascript -# else # pipe -# python -mjson.tool | pygmentize -l javascript -# fi -#} - -# Run `dig` and display the most useful info -digga() { - dig +nocmd "$1" any +multiline +noall +answer -} - -## Query Wikipedia via console over DNS -## that does not work anymore, see: -## https://dgl.cx/wikipedia-dns -#mwiki() { -# dig +short txt "$*".wp.dg.cx -#} - -# UTF-8-encode a string of Unicode symbols -escape() { - local args - args=( $(printf "%s" "$*" | xxd -p -c1 -u) ) - printf "\\\x%s" "${args[@]}" - # print a newline unless we’re piping the output to another program - if [ -t 1 ]; then - echo ""; # newline - fi -} - -# Decode \x{ABCD}-style Unicode escape sequences -unidecode() { - perl -e "binmode(STDOUT, ':utf8'); print \"$*\"" - # print a newline unless we’re piping the output to another program - if [ -t 1 ]; then - echo ""; # newline - fi -} - -# Get a character’s Unicode code point -codepoint() { - perl -e "use utf8; print sprintf('U+%04X', ord(\"$*\"))" - # print a newline unless we’re piping the output to another program - if [ -t 1 ]; then - echo ""; # newline - fi -} - -# Show all the names (CNs and SANs) listed in the SSL certificate -# for a given domain -getcertnames() { - if [ -z "${1}" ]; then - echo "ERROR: No domain specified." - return 1 - fi - - local domain="${1}" - echo "Testing ${domain}…" - echo ""; # newline - - local tmp - tmp=$(echo -e "GET / HTTP/1.0\nEOT" \ - | openssl s_client -connect "${domain}:443" 2>&1) - - if [[ "${tmp}" = *"-----BEGIN CERTIFICATE-----"* ]]; then - local certText - certText=$(echo "${tmp}" \ - | openssl x509 -text -certopt "no_header, no_serial, no_version, \ - no_signame, no_validity, no_issuer, no_pubkey, no_sigdump, no_aux") - echo "Common Name:" - echo ""; # newline - echo "${certText}" | grep "Subject:" | sed -e "s/^.*CN=//" - echo ""; # newline - echo "Subject Alternative Name(s):" - echo ""; # newline - echo "${certText}" | grep -A 1 "Subject Alternative Name:" \ - | sed -e "2s/DNS://g" -e "s/ //g" | tr "," "\n" | tail -n +2 - return 0 - else - echo "ERROR: Certificate not found." - return 1 - fi -} - -# `v` with no arguments opens the current directory in Vim, otherwise opens the -# given location -v() { - if [ $# -eq 0 ]; then - vim . - else - vim "$@" - fi -} - -# `o` with no arguments opens the current directory, otherwise opens the given -# location -o() { - if [ $# -eq 0 ]; then - xdg-open . > /dev/null 2>&1 - else - xdg-open "$@" > /dev/null 2>&1 - fi -} - # `tre` is a shorthand for `tree` with hidden files and color enabled, ignoring # the `.git` directory, listing directories first. The output gets piped into # `less` with options to preserve color and line numbers, unless the output is @@ -229,6 +89,7 @@ tre() { # Call from a local repo to open the repository on github/bitbucket in browser # Modified version of https://github.com/zeke/ghwd +# Adapted: xdg-open → open (macOS) repo() { # Figure out github repo base URL local base_url @@ -247,9 +108,6 @@ repo() { # Fix git@gitlab.com: URLs base_url=${base_url//git@gitlab\.com:/https:\/\/gitlab\.com\/} - # Fix git@github.rackspace.com: URLs - base_url=${base_url//git@github\.rackspace\.com:/https:\/\/github\.rackspace\.com\/} - # Validate that this folder is a git folder if ! git branch 2>/dev/null 1>&2 ; then echo "Not a git repo!" @@ -267,7 +125,6 @@ repo() { fi # Figure out current git branch - # git_where=$(command git symbolic-ref -q HEAD || command git name-rev --name-only --no-undefined --always HEAD) 2>/dev/null git_where=$(command git name-rev --name-only --no-undefined --always HEAD) 2>/dev/null # Remove cruft from branchname @@ -276,205 +133,149 @@ repo() { [[ $base_url == *bitbucket* ]] && tree="src" || tree="tree" url="$base_url/$tree/$branch$relative_path" - xdg-open "$url" &> /dev/null || (echo "Using $(type xdg-open) to open URL failed." && exit 1); + open "$url" &> /dev/null || (echo "Failed to open URL." && exit 1); } -# Get colors in manual pages -#man() { -# env \ -# LESS_TERMCAP_mb="$(printf '\e[1;31m')" \ -# LESS_TERMCAP_md="$(printf '\e[1;31m')" \ -# LESS_TERMCAP_me="$(printf '\e[0m')" \ -# LESS_TERMCAP_se="$(printf '\e[0m')" \ -# LESS_TERMCAP_so="$(printf '\e[1;44;33m')" \ -# LESS_TERMCAP_ue="$(printf '\e[0m')" \ -# LESS_TERMCAP_us="$(printf '\e[1;32m')" \ -# man "$@" -#} +# Run `dig` and display the most useful info +digga() { + dig +nocmd "$1" any +multiline +noall +answer +} +# Show all the names (CNs and SANs) listed in the SSL certificate +# for a given domain +getcertnames() { + if [ -z "${1}" ]; then + echo "ERROR: No domain specified." + return 1 + fi -## Use feh to nicely view images -#openimage() { -# feh --quiet --auto-zoom \ -# --borderless --geometry 1600x900 --scale-down \ -# --draw-filename --image-bg black "$@" -#} + local domain="${1}" + echo "Testing ${domain}…" + echo ""; # newline -# get dbus session -dbs() { - local t=$1 - if [[ -z "$t" ]]; then - local t="session" - fi + local tmp + tmp=$(echo -e "GET / HTTP/1.0\nEOT" \ + | openssl s_client -connect "${domain}:443" 2>&1) - dbus-send --$t --dest=org.freedesktop.DBus \ - --type=method_call --print-reply \ - /org/freedesktop/DBus org.freedesktop.DBus.ListNames + if [[ "${tmp}" = *"-----BEGIN CERTIFICATE-----"* ]]; then + local certText + certText=$(echo "${tmp}" \ + | openssl x509 -text -certopt "no_header, no_serial, no_version, \ + no_signame, no_validity, no_issuer, no_pubkey, no_sigdump, no_aux") + echo "Common Name:" + echo ""; # newline + echo "${certText}" | grep "Subject:" | sed -e "s/^.*CN=//" + echo ""; # newline + echo "Subject Alternative Name(s):" + echo ""; # newline + echo "${certText}" | grep -A 1 "Subject Alternative Name:" \ + | sed -e "2s/DNS://g" -e "s/ //g" | tr "," "\n" | tail -n +2 + return 0 + else + echo "ERROR: Certificate not found." + return 1 + fi } -# check if uri is up +# check if uri is up (adapted: notify-send → osascript) isup() { local uri=$1 if curl --silent --head --location "$uri" | grep -q "HTTP.*200"; then - notify-send --urgency=low "$uri is up" + osascript -e "display notification \"$uri is up\" with title \"isup\"" else - notify-send --urgency=critical "$uri is down" + osascript -e "display notification \"$uri is down\" with title \"isup\" sound name \"Basso\"" fi } -# build go static binary from root of project -gostatic(){ - local dir=$1 - local arg=$2 - - if [[ -z $dir ]]; then - dir=$(pwd) - fi - - local name - name=$(basename "$dir") - ( - cd "$dir" || exit - export GOOS=linux - echo "Building static binary for $name in $dir" - - case $arg in - "netgo") - set -x - go build -a \ - -tags 'netgo static_build' \ - -installsuffix netgo \ - -ldflags "-w" \ - -o "$name" . - ;; - "cgo") - set -x - CGO_ENABLED=1 go build -a \ - -tags 'cgo static_build' \ - -ldflags "-w -extldflags -static" \ - -o "$name" . - ;; - *) - set -x - CGO_ENABLED=0 go build -a \ - -installsuffix cgo \ - -ldflags "-w" \ - -o "$name" . - ;; - esac - ) -} +# DISABLED: gz - compare original and gzipped file size +#gz() { +# local origsize +# origsize=$(wc -c < "$1") +# local gzipsize +# gzipsize=$(gzip -c "$1" | wc -c) +# local ratio +# ratio=$(echo "$gzipsize * 100 / $origsize" | bc -l) +# printf "orig: %d bytes\n" "$origsize" +# printf "gzip: %d bytes (%2.2f%%)\n" "$gzipsize" "$ratio" +#} -# go to a folder easily in your gopath -gogo(){ - local d=$1 +# DISABLED: v - open current directory or given location in Vim +#v() { +# if [ $# -eq 0 ]; then +# vim . +# else +# vim "$@" +# fi +#} - if [[ -z $d ]]; then - echo "You need to specify a project name." - return 1 - fi +# DISABLED: o - open current directory or given location +#o() { +# if [ $# -eq 0 ]; then +# open . +# else +# open "$@" +# fi +#} - if [[ "$d" == github* ]]; then - d=$(echo "$d" | sed 's/.*\///') - fi - d=${d%/} +# DISABLED: dataurl - create a data URL from a file +#dataurl() { +# local mimeType +# mimeType=$(file -b --mime-type "$1") +# if [[ $mimeType == text/* ]]; then +# mimeType="${mimeType};charset=utf-8" +# fi +# echo "data:${mimeType};base64,$(openssl base64 -in "$1" | tr -d '\n')" +#} - # search for the project dir in the GOPATH - local path=( $(find "${GOPATH}/src" \( -type d -o -type l \) -iname "$d" | awk '{print length, $0;}' | sort -n | awk '{print $2}') ) +# DISABLED: gitio - create a git.io short URL +#gitio() { +# curl -i https://git.io/ -F "url=${1}" +#} - if [ "${path[0]}" == "" ] || [ "${path[*]}" == "" ]; then - echo "Could not find a directory named $d in $GOPATH" - echo "Maybe you need to 'go get' it ;)" - return 1 - fi +# DISABLED: escape - UTF-8-encode a string of Unicode symbols +#escape() { +# local args +# args=( $(printf "%s" "$*" | xxd -p -c1 -u) ) +# printf "\\\x%s" "${args[@]}" +# if [ -t 1 ]; then +# echo "" +# fi +#} - # enter the first path found - cd "${path[0]}" || return 1 -} +# DISABLED: unidecode - decode \x{ABCD}-style Unicode escape sequences +#unidecode() { +# perl -e "binmode(STDOUT, ':utf8'); print \"$*\"" +# if [ -t 1 ]; then +# echo "" +# fi +#} -golistdeps(){ - ( - if [[ ! -z "$1" ]]; then - gogo "$@" - fi +# DISABLED: codepoint - get a character's Unicode code point +#codepoint() { +# perl -e "use utf8; print sprintf('U+%04X', ord(\"$*\"))" +# if [ -t 1 ]; then +# echo "" +# fi +#} - go list -e -f '{{join .Deps "\n"}}' ./... | xargs go list -e -f '{{if not .Standard}}{{.ImportPath}}{{end}}' - ) -} +# DISABLED: gostatic - build go static binary +#gostatic(){ ... } -# add previous command to pet -prev() { - PREV=$(fc -lrn | head -n2 | tail -n1) - sh -c "pet new $(printf %q "$PREV")" -} +# DISABLED: gogo - go to a folder in GOPATH +#gogo(){ ... } -# search throug pet snippets -pet-select() { - BUFFER=$(pet search --query "$READLINE_LINE") - READLINE_LINE=$BUFFER - READLINE_POINT=${#BUFFER} -} +# DISABLED: golistdeps - list go dependencies +#golistdeps(){ ... } -## get the name of a x window -#xname(){ -# local window_id=$1 -# -# if [[ -z $window_id ]]; then -# echo "Please specifiy a window id, you find this with 'xwininfo'" -# -# return 1 -# fi -# -# local match_string='".*"' -# local match_qstring='"[^"\\]*(\\.[^"\\]*)*"' # NOTE: Adds 1 backreference -# -# # get the name -# xprop -id "$window_id" | \ -# sed -nr \ -# -e "s/^WM_CLASS\(STRING\) = ($match_qstring), ($match_qstring)$/instance=\1\nclass=\3/p" \ -# -e "s/^WM_WINDOW_ROLE\(STRING\) = ($match_qstring)$/window_role=\1/p" \ -# -e "/^WM_NAME\(STRING\) = ($match_string)$/{s//title=\1/; h}" \ -# -e "/^_NET_WM_NAME\(UTF8_STRING\) = ($match_qstring)$/{s//title=\1/; h}" \ -# -e "\${g; p}" -#} +# DISABLED: dbs - get dbus session (Linux-specific) +#dbs() { ... } -## run e.g. cvt 1024 768 to get the Modeline for the 1024x768 resolution -## 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz -## Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync -#rackspace_mons() { -# xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync -# xrandr --addmode DP1-1 "1920x1080_60.00" -# xrandr --addmode DP1-2 "1920x1080_60.00" -# xrandr --output eDP1 --auto --primary \ -# --output DP1-1 --mode 1920x1080_60.00 --above eDP1 \ -# --output DP1-2 --mode 1920x1080_60.00 --left-of DP1-1 -#} +# DISABLED: prev - add previous command to pet +#prev() { ... } -## first start of ssh-agent -#ssh_con() { -# local key_name=${1:-github} -# eval $(ssh-agent) -# ssh-add $HOME/.ssh/id_rsa_$key_name -#} +# DISABLED: pet-select - search through pet snippets +#pet-select() { ... } -## helper function to add virtual env info to PS1 -#function virtualenv_info(){ -# # Add virtual env name to the prompt if activated -# # (this requires the VIRTUAL_ENV_DISABLE_PROMPT=1 exported) -# [[ -n "$VIRTUAL_ENV" ]] && echo "(${VIRTUAL_ENV##*/}) " -#} -## used in .git-prompt-colors.sh -#VENV="\$(virtualenv_info)"; - -## helper function to add faws info to PS1 -#function faws_active_env() { -# if [[ -z $FAWS_CURRENT_TOKEN_EXPIRATION ]]; then -# return -# fi -# -# if [[ $FAWS_CURRENT_TOKEN_EXPIRATION -gt $(date +%s) ]]; then -# echo "[${FAWS_CURRENT_RACKSPACE_ACCOUNT} - ${FAWS_CURRENT_ACCOUNT_NAME}] " -# fi -#} -#FAWS="\$(faws_active_env)" +# DISABLED: Docker functions (dcleanup, del_stopped, relies_on, container wrappers) +# Not ported - use Docker Desktop on macOS diff --git a/dot-config/bash/path b/dot-config/bash/path index 8b7b5ae..bcc3db7 100644 --- a/dot-config/bash/path +++ b/dot-config/bash/path @@ -1,12 +1,22 @@ #!/bin/bash -# Golang -export GOPATH="$HOME/code/go" -export GOBIN="$HOME/code/go/bin" -export PATH="$PATH:$GOBIN" +# macOS dotfiles - PATH +# Adapted from Linux dotfiles -# Local -export PATH="$PATH:$HOME/.local/bin" +# Homebrew paths (Apple Silicon and Intel) +if [[ -d "/opt/homebrew/bin" ]]; then + export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH" +elif [[ -d "/usr/local/bin" ]]; then + export PATH="/usr/local/bin:/usr/local/sbin:$PATH" +fi -# Krew -export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" +# DISABLED: Go paths +#export GOPATH="$HOME/code/go" +#export GOBIN="$HOME/code/go/bin" +#export PATH="$PATH:$GOBIN" + +# DISABLED: ~/.local/bin +#export PATH="$PATH:$HOME/.local/bin" + +# DISABLED: Krew (kubectl plugin manager) +#export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" diff --git a/dot-config/bash/pure.sh b/dot-config/bash/pure.sh index 53eb9e1..00cdb96 100644 --- a/dot-config/bash/pure.sh +++ b/dot-config/bash/pure.sh @@ -1,11 +1,11 @@ # # Clean and minimalistic Bash prompt # Author: Artem Sapegin, sapegin.me -# +# # Inspired by: https://github.com/sindresorhus/pure & https://github.com/dreadatour/dotfiles/blob/master/.bash_profile # # Notes: -# - $local_username - username you don’t want to see in the prompt - can be defined in ~/.bashlocal : `local_username="admin"` +# - $local_username - username you don't want to see in the prompt - can be defined in ~/.bashlocal : `local_username="admin"` # - Colors ($RED, $GREEN) - defined in ../tilde/bash_profile.bash # diff --git a/dot-config/borders/bordersrc b/dot-config/borders/bordersrc new file mode 100755 index 0000000..d6dd9b1 --- /dev/null +++ b/dot-config/borders/bordersrc @@ -0,0 +1,14 @@ +#!/bin/bash + +# Tokyonight Night + Ghostty Blue Matrix +# Glow effect on active window, no border on inactive +options=( + style=round + width=4.0 + hidpi=off + active_color="glow(0xff00a2ff)" + inactive_color=0x00565f89 + blacklist="System Settings,Finder,Calculator" +) + +borders "${options[@]}" diff --git a/dot-config/brave-flags.conf b/dot-config/brave-flags.conf deleted file mode 100644 index 51bdd86..0000000 --- a/dot-config/brave-flags.conf +++ /dev/null @@ -1,2 +0,0 @@ ---enable-features=UseOzonePlatform ---ozone-platform=wayland diff --git a/dot-config/ghostty/config b/dot-config/ghostty/config new file mode 100644 index 0000000..19ca53e --- /dev/null +++ b/dot-config/ghostty/config @@ -0,0 +1,14 @@ +theme = Blue Matrix +background-opacity = 0.85 +copy-on-select = clipboard + +font-family = JetBrainsMono Nerd Font +font-size = 14 +cursor-style = bar +window-padding-x = 4 +window-padding-y = 4 +background-blur = true +mouse-hide-while-typing = true +clipboard-trim-trailing-spaces = true +window-decoration = auto +shell-integration = detect diff --git a/dot-config/git/config b/dot-config/git/config index 6468b92..c6a812d 100644 --- a/dot-config/git/config +++ b/dot-config/git/config @@ -1,7 +1,7 @@ [user] email = 7999713+kifbv@users.noreply.github.com name = Franck Ratier - signinkey = EDE94B703722EEBB + signingkey = C60B7E11827EC442 [alias] @@ -63,7 +63,7 @@ fm = "!f() { git log --pretty=format:'%C(yellow)%h %Cblue%ad %Creset%s%Cgreen [%cn] %Cred%d' --decorate --date=short --grep=$1; }; f" # Remove branches that have already been merged with master - # a.k.a. ‘delete merged’ + # a.k.a. 'delete merged' dm = "!git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d; git remote -v update -p" # List contributors with number of commits @@ -91,13 +91,10 @@ alias=!git config -l | grep ^alias | cut -c 7- | sort # from myles borins https://github.com/TheAlphaNerd/Dot-files/blob/master/.gitconfig - # github broke some workflow... this will make it less painful patchit = "!f() { echo $1.patch | sed s_pull/[0-9]*/commits_commit_ | xargs curl -L | git am --whitespace=fix; }; f" - # patchit = "!f() { curl -L $1.patch | git am --whitespace=fix; }; f" patchit-please = "!f() { echo $1.patch | sed s_pull/[0-9]*/commits_commit_ | xargs curl -L | git am -3 --whitespace=fix; }; f" ignored = ls-files --others --ignored --exclude-standard squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f" - # patchit-please = "!f() { curl -L $1.patch | git am -3 --whitespace=fix; }; f" [apply] @@ -110,10 +107,9 @@ [core] pager = diff-so-fancy | less --tabs=4 -RFX - #pager = delta - # Use custom `.gitignore` and `.gitattributes` - excludesfile = ~/.gitignore_global + # Use custom `.gitignore` (adapted path for XDG-style config) + excludesfile = ~/.config/git/ignore attributesfile = ~/.gitattributes # Treat spaces before tabs and all kinds of trailing whitespace as an error @@ -160,14 +156,7 @@ changed = green untracked = cyan -#[delta] -# navigate = true # use n and N to move between diff sections -# light = false # set to true if you're in a terminal w/ a light background color (e.g. the default macOS terminal) -# side-by-side = true - - [diff] - #colorMoved = default # delta option # Detect copies as well as renames renames = copies @@ -180,12 +169,8 @@ # Automatically correct and execute mistyped commands autocorrect = 1 -[interactive] - #diffFilter = delta --color-only # delta option - [merge] - #conflictstyle = diff3 # Include summaries of merged commits in newly created merge commit messages log = true @@ -213,12 +198,5 @@ insteadOf = "gist:" -# Uncomment if you want fetch to also get all github pull requests, this is rather -# large on big repos. -#[remote "origin"] - #fetch = +refs/pull/*/head:refs/remotes/origin/pull/* - [init] defaultBranch = main -[safe] - directory = /home/franck/github.com/armbian/build diff --git a/dot-config/git/ignore b/dot-config/git/ignore index ccd8748..c1909f7 100644 --- a/dot-config/git/ignore +++ b/dot-config/git/ignore @@ -1,3 +1,12 @@ +# macOS +.DS_Store +.AppleDouble +.LSOverride +Icon +._* +.Spotlight-V100 +.Trashes + # Linux trash folder which might appear on any partition or disk .Trash-* diff --git a/dot-config/sketchybar/items/battery.sh b/dot-config/sketchybar/items/battery.sh new file mode 100755 index 0000000..0414f3b --- /dev/null +++ b/dot-config/sketchybar/items/battery.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +COLOR="$CYAN" + +sketchybar --add item battery right \ + --set battery \ + update_freq=60 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.padding_right=10 \ + label.color="$COLOR" \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/power.sh" \ + --subscribe battery power_source_change diff --git a/dot-config/sketchybar/items/calendar.sh b/dot-config/sketchybar/items/calendar.sh new file mode 100755 index 0000000..064a191 --- /dev/null +++ b/dot-config/sketchybar/items/calendar.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +COLOR="$BLUE" + +sketchybar --add item calendar right \ + --set calendar update_freq=15 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.color="$COLOR" \ + label.padding_right=10 \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/calendar.sh" diff --git a/dot-config/sketchybar/items/clock.sh b/dot-config/sketchybar/items/clock.sh new file mode 100755 index 0000000..e3c2ceb --- /dev/null +++ b/dot-config/sketchybar/items/clock.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +COLOR="$MAGENTA" + +sketchybar --add item clock right \ + --set clock update_freq=1 \ + icon.padding_left=10 \ + icon.color="$COLOR" \ + icon="" \ + label.color="$COLOR" \ + label.padding_right=5 \ + label.width=78 \ + align=center \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=2 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/clock.sh" diff --git a/dot-config/sketchybar/items/cpu.sh b/dot-config/sketchybar/items/cpu.sh new file mode 100755 index 0000000..254eecf --- /dev/null +++ b/dot-config/sketchybar/items/cpu.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +COLOR="$YELLOW" + +sketchybar --add graph cpu right 40 \ + --set cpu \ + update_freq=3 \ + graph.color="$COLOR" \ + graph.fill_color=0x44e0af68 \ + graph.line_width=1 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.color="$COLOR" \ + label.width=45 \ + label.padding_right=10 \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/cpu.sh" diff --git a/dot-config/sketchybar/items/front_app.sh b/dot-config/sketchybar/items/front_app.sh new file mode 100755 index 0000000..cb092f4 --- /dev/null +++ b/dot-config/sketchybar/items/front_app.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +COLOR="$WHITE" + +sketchybar \ + --add item front_app left \ + --set front_app script="$PLUGIN_DIR/front_app.sh" \ + icon.drawing=off \ + background.height=26 \ + background.padding_left=15 \ + background.padding_right=10 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.corner_radius="$CORNER_RADIUS" \ + background.color="$BAR_COLOR" \ + label.color="$COLOR" \ + label.padding_left=10 \ + label.padding_right=10 \ + associated_display=active \ + --subscribe front_app front_app_switched diff --git a/dot-config/sketchybar/items/github.sh b/dot-config/sketchybar/items/github.sh new file mode 100755 index 0000000..3047967 --- /dev/null +++ b/dot-config/sketchybar/items/github.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +COLOR="$WHITE" + +sketchybar --add item github right \ + --set github \ + update_freq=60 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.color="$COLOR" \ + label.padding_right=10 \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + click_script="open https://github.com/notifications" \ + script="$PLUGIN_DIR/github.sh" diff --git a/dot-config/sketchybar/items/memory.sh b/dot-config/sketchybar/items/memory.sh new file mode 100755 index 0000000..a708749 --- /dev/null +++ b/dot-config/sketchybar/items/memory.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +COLOR="$RED" + +sketchybar --add graph memory right 40 \ + --set memory \ + update_freq=3 \ + graph.color="$COLOR" \ + graph.fill_color=0x44f7768e \ + graph.line_width=1 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.color="$COLOR" \ + label.width=45 \ + label.padding_right=10 \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/memory.sh" diff --git a/dot-config/sketchybar/items/spaces.sh b/dot-config/sketchybar/items/spaces.sh new file mode 100755 index 0000000..eea6d76 --- /dev/null +++ b/dot-config/sketchybar/items/spaces.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +source "$HOME/.config/sketchybar/variables.sh" # Loads all defined colors + +sketchybar --add item spacer.1 left \ + --set spacer.1 background.drawing=off \ + label.drawing=off \ + icon.drawing=off \ + width=10 + +for i in "${!SPACE_ICONS[@]}"; do + sid=$((i + 1)) + sketchybar --add space space.$sid left \ + --set space.$sid associated_space=$sid \ + label.drawing=off \ + icon.padding_left=10 \ + icon.padding_right=10 \ + background.padding_left=-5 \ + background.padding_right=-5 \ + script="$PLUGIN_DIR/space.sh" +done + +sketchybar --add item spacer.2 left \ + --set spacer.2 background.drawing=off \ + label.drawing=off \ + icon.drawing=off \ + width=5 + +sketchybar --add bracket spaces '/space.*/' \ + --set spaces background.border_width="$BORDER_WIDTH" \ + background.border_color="$RED" \ + background.corner_radius="$CORNER_RADIUS" \ + background.color="$BAR_COLOR" \ + background.height=26 \ + background.drawing=on + +sketchybar --add item separator left \ + \ + icon.font="$FONT:Regular:16.0" \ + background.padding_left=26 \ + background.padding_right=15 \ + label.drawing=off \ + associated_display=active \ + icon.color="$YELLOW" # --set separator icon= \ diff --git a/dot-config/sketchybar/items/spotify.sh b/dot-config/sketchybar/items/spotify.sh new file mode 100755 index 0000000..b94fe7a --- /dev/null +++ b/dot-config/sketchybar/items/spotify.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +COLOR="$ORANGE" + +sketchybar --add item spotify q \ + --set spotify \ + scroll_texts=on \ + icon=󰎆 \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + background.color="$BAR_COLOR" \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.padding_right=-5 \ + background.drawing=on \ + label.padding_right=10 \ + label.max_chars=20 \ + associated_display=active \ + updates=on \ + script="$PLUGIN_DIR/spotify.sh" \ + --subscribe spotify media_change diff --git a/dot-config/sketchybar/items/volume.sh b/dot-config/sketchybar/items/volume.sh new file mode 100755 index 0000000..77f746d --- /dev/null +++ b/dot-config/sketchybar/items/volume.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +COLOR="$GREEN" + +sketchybar \ + --add item sound right \ + --set sound \ + icon.color="$COLOR" \ + icon.padding_left=10 \ + label.color="$COLOR" \ + label.padding_right=10 \ + background.height=26 \ + background.corner_radius="$CORNER_RADIUS" \ + background.padding_right=5 \ + background.border_width="$BORDER_WIDTH" \ + background.border_color="$COLOR" \ + background.color="$BAR_COLOR" \ + background.drawing=on \ + script="$PLUGIN_DIR/sound.sh" \ + --subscribe sound volume_change diff --git a/dot-config/sketchybar/plugins/aerospace.sh b/dot-config/sketchybar/plugins/aerospace.sh new file mode 100755 index 0000000..6114acc --- /dev/null +++ b/dot-config/sketchybar/plugins/aerospace.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +source "$HOME/.config/sketchybar/variables.sh" + +# Get non-empty workspaces and focused workspace +NONEMPTY=$(aerospace list-workspaces --monitor all --empty no) +FOCUSED=$(aerospace list-workspaces --focused) + +for sid in $(seq 1 10); do + IS_NONEMPTY=false + IS_FOCUSED=false + + # Check if this workspace is non-empty + while IFS= read -r ws; do + if [ "$ws" = "$sid" ]; then + IS_NONEMPTY=true + break + fi + done <<< "$NONEMPTY" + + # Check if this workspace is focused + if [ "$FOCUSED" = "$sid" ]; then + IS_FOCUSED=true + IS_NONEMPTY=true # always show focused + fi + + if [ "$IS_NONEMPTY" = true ]; then + if [ "$IS_FOCUSED" = true ]; then + # Focused: animated highlight + sketchybar --animate tanh 10 --set space.$sid \ + drawing=on \ + background.drawing=on \ + background.color="$BLUE" \ + label.color="$BLACK" + else + # Non-empty but not focused: visible, dimmed + sketchybar --animate tanh 10 --set space.$sid \ + drawing=on \ + background.drawing=off \ + label.color="$WHITE" + fi + else + # Empty and not focused: hidden + sketchybar --set space.$sid drawing=off + fi +done diff --git a/dot-config/sketchybar/plugins/calendar.sh b/dot-config/sketchybar/plugins/calendar.sh new file mode 100755 index 0000000..328d994 --- /dev/null +++ b/dot-config/sketchybar/plugins/calendar.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +sketchybar --set "$NAME" icon="󰸗" label="$(date '+%a %d. %b')" diff --git a/dot-config/sketchybar/plugins/clock.sh b/dot-config/sketchybar/plugins/clock.sh new file mode 100755 index 0000000..69aa277 --- /dev/null +++ b/dot-config/sketchybar/plugins/clock.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +LABEL=$(date '+%H:%M:%S') +sketchybar --set "$NAME" label="$LABEL" diff --git a/dot-config/sketchybar/plugins/cpu.sh b/dot-config/sketchybar/plugins/cpu.sh new file mode 100755 index 0000000..08ac63f --- /dev/null +++ b/dot-config/sketchybar/plugins/cpu.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +CPU_ICON=$'\uf2db' +CPU_PERCENT=$(ps -A -o %cpu | awk '{s+=$1} END {s /= 8; printf "%.0f", s}') +CPU_DECIMAL=$(echo "$CPU_PERCENT" | awk '{printf "%.2f", $1 / 100}') + +sketchybar --set "$NAME" icon="$CPU_ICON" label="$(printf '%3s%%' "$CPU_PERCENT")" \ + --push "$NAME" "$CPU_DECIMAL" diff --git a/dot-config/sketchybar/plugins/front_app.sh b/dot-config/sketchybar/plugins/front_app.sh new file mode 100755 index 0000000..8f446a3 --- /dev/null +++ b/dot-config/sketchybar/plugins/front_app.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +case "$SENDER" in +"front_app_switched") + sketchybar --set "$NAME" label="$INFO" + ;; +esac diff --git a/dot-config/sketchybar/plugins/github.sh b/dot-config/sketchybar/plugins/github.sh new file mode 100755 index 0000000..09787d2 --- /dev/null +++ b/dot-config/sketchybar/plugins/github.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH" + +GH_ICON=$'\uf09b' + +COUNT=$(gh api notifications --jq 'length' 2>/dev/null) + +if [ -z "$COUNT" ] || [ "$COUNT" = "0" ]; then + sketchybar --set "$NAME" icon="$GH_ICON" label="0" icon.color=0xff565f89 label.color=0xff565f89 background.border_color=0xff565f89 +else + sketchybar --animate tanh 10 --set "$NAME" icon="$GH_ICON" label="$COUNT" icon.color=0xff7aa2f7 label.color=0xff7aa2f7 background.border_color=0xff7aa2f7 +fi diff --git a/dot-config/sketchybar/plugins/memory.sh b/dot-config/sketchybar/plugins/memory.sh new file mode 100755 index 0000000..699fea1 --- /dev/null +++ b/dot-config/sketchybar/plugins/memory.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +MEM_ICON=$'\U000F1632' + +# Calculate used memory from vm_stat (active + wired) / total +TOTAL=$(sysctl -n hw.memsize) +PAGESIZE=$(vm_stat | head -1 | grep -oE '[0-9]+') +read -r ACTIVE WIRED <<< $(vm_stat | awk -v ps="$PAGESIZE" ' + /Pages active/ {a=$3+0} + /Pages wired/ {w=$4+0} + END {printf "%d %d", a*ps, w*ps} +') + +USED_PERCENT=$(echo "$ACTIVE $WIRED $TOTAL" | awk '{printf "%.0f", ($1 + $2) / $3 * 100}') +MEM_DECIMAL=$(echo "$USED_PERCENT" | awk '{printf "%.2f", $1 / 100}') + +sketchybar --set "$NAME" icon="$MEM_ICON" label="$(printf '%3s%%' "$USED_PERCENT")" \ + --push "$NAME" "$MEM_DECIMAL" diff --git a/dot-config/sketchybar/plugins/power.sh b/dot-config/sketchybar/plugins/power.sh new file mode 100755 index 0000000..6d06a3c --- /dev/null +++ b/dot-config/sketchybar/plugins/power.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1) +CHARGING=$(pmset -g batt | grep 'AC Power') + +# Desktop / no battery: show plug icon +if [ "$PERCENTAGE" = "" ]; then + ICON=$'\uf1e6' + sketchybar --set "$NAME" icon="$ICON" label="AC" + exit 0 +fi + +case ${PERCENTAGE} in +9[0-9] | 100) + ICON=$'\uf240' + ;; +[6-8][0-9]) + ICON=$'\uf241' + ;; +[3-5][0-9]) + ICON=$'\uf242' + ;; +[1-2][0-9]) + ICON=$'\uf243' + ;; +*) ICON=$'\uf244' ;; +esac + +if [ "$CHARGING" != "" ]; then + ICON=$'\uf1e6' +fi + +sketchybar --set "$NAME" icon="$ICON" label="${PERCENTAGE}%" diff --git a/dot-config/sketchybar/plugins/sound.sh b/dot-config/sketchybar/plugins/sound.sh new file mode 100755 index 0000000..3a6f295 --- /dev/null +++ b/dot-config/sketchybar/plugins/sound.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +VOLUME=$(osascript -e "output volume of (get volume settings)") +MUTED=$(osascript -e "output muted of (get volume settings)") + +if [ "$MUTED" != "false" ]; then + ICON=$'\uf6a9' + VOLUME=0 +else + case ${VOLUME} in + 100) ICON=$'\uf028' ;; + [5-9]*) ICON=$'\uf028' ;; + [0-9]*) ICON=$'\uf027' ;; + *) ICON=$'\uf028' ;; + esac +fi + +sketchybar -m \ + --set "$NAME" icon=$ICON \ + --set "$NAME" label="$VOLUME%" diff --git a/dot-config/sketchybar/plugins/space.sh b/dot-config/sketchybar/plugins/space.sh new file mode 100755 index 0000000..79eac86 --- /dev/null +++ b/dot-config/sketchybar/plugins/space.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +source "$HOME/.config/sketchybar/variables.sh" # Loads all defined colors + +SPACE_CLICK_SCRIPT="yabai -m space --focus $SID 2>/dev/null" + +if [ "$SELECTED" = "true" ]; then + sketchybar --animate tanh 5 --set "$NAME" \ + icon.color="$RED" \ + icon="${SPACE_ICONS[$SID - 1]}" \ + click_script="$SPACE_CLICK_SCRIPT" +else + sketchybar --animate tanh 5 --set "$NAME" \ + icon.color="$COMMENT" \ + icon="${SPACE_ICONS[$SID - 1]}" \ + click_script="$SPACE_CLICK_SCRIPT" +fi diff --git a/dot-config/sketchybar/plugins/spotify.sh b/dot-config/sketchybar/plugins/spotify.sh new file mode 100755 index 0000000..d0dbc33 --- /dev/null +++ b/dot-config/sketchybar/plugins/spotify.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +STATE="$(echo "$INFO" | jq -r '.state')" +APP="$(echo "$INFO" | jq -r '.app')" + +if [ "$STATE" = "playing" ] && [ "$APP" == "Spotify" ]; then + MEDIA="$(echo "$INFO" | jq -r '.title + " - " + .artist')" + sketchybar --set "$NAME" label="$MEDIA" drawing=on +else + sketchybar --set "$NAME" drawing=off +fi diff --git a/dot-config/sketchybar/sketchybarrc b/dot-config/sketchybar/sketchybarrc new file mode 100755 index 0000000..63059fd --- /dev/null +++ b/dot-config/sketchybar/sketchybarrc @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +source "$HOME/.config/sketchybar/variables.sh" + +# ── AeroSpace workspace items ────────────────────────────── +sketchybar --add event aerospace_workspace_change + +for sid in $(seq 1 10); do + sketchybar --add item space.$sid left \ + --subscribe space.$sid aerospace_workspace_change \ + --set space.$sid \ + background.color="$BLUE" \ + background.corner_radius="$CORNER_RADIUS" \ + background.height=20 \ + background.drawing=off \ + drawing=off \ + label="$sid" \ + label.color="$COMMENT" \ + label.font="$FONT:Bold:13.0" \ + label.padding_left=8 \ + label.padding_right=8 \ + updates=on \ + click_script="aerospace workspace $sid" \ + script="$CONFIG_DIR/plugins/aerospace.sh $sid" +done + +# ── General bar settings ─────────────────────────────────── +sketchybar --bar height=30 \ + color="$BAR_COLOR" \ + shadow="$SHADOW" \ + position=top \ + sticky=on \ + padding_right=0 \ + padding_left=3 \ + corner_radius="$CORNER_RADIUS" \ + y_offset=5 \ + margin=5 \ + blur_radius=20 \ + notch_width=200 \ + --default updates=when_shown \ + icon.font="$FONT:Bold:13.5" \ + icon.color="$ICON_COLOR" \ + icon.padding_left="$PADDINGS" \ + icon.padding_right="$PADDINGS" \ + label.font="$FONT:Bold:13.0" \ + label.color="$LABEL_COLOR" \ + label.padding_left="$PADDINGS" \ + label.padding_right="$PADDINGS" \ + background.padding_right="$PADDINGS" \ + background.padding_left="$PADDINGS" \ + popup.background.border_width=1 \ + popup.background.corner_radius=11 \ + popup.background.border_color="$POPUP_BORDER_COLOR" \ + popup.background.color="$POPUP_BACKGROUND_COLOR" \ + popup.background.shadow.drawing="$SHADOW" + +# Left +source "$ITEM_DIR/front_app.sh" + +# Center (of notch) +source "$ITEM_DIR/spotify.sh" + +# Right +source "$ITEM_DIR/clock.sh" +source "$ITEM_DIR/calendar.sh" +source "$ITEM_DIR/battery.sh" +source "$ITEM_DIR/volume.sh" +source "$ITEM_DIR/cpu.sh" +source "$ITEM_DIR/memory.sh" +source "$ITEM_DIR/github.sh" + + +#################### Finalizing Setup #################### + +sketchybar --hotload true +sketchybar --update + +echo "sketchybar configuration loaded.." diff --git a/dot-config/sketchybar/variables.sh b/dot-config/sketchybar/variables.sh new file mode 100644 index 0000000..4b8e0af --- /dev/null +++ b/dot-config/sketchybar/variables.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env sh + +# Color Palette +# Tokyonight Night +BLACK=0xff24283b +WHITE=0xffa9b1d6 +MAGENTA=0xffbb9af7 +BLUE=0xff7aa2f7 +CYAN=0xff7dcfff +GREEN=0xff9ece6a +YELLOW=0xffe0af68 +ORANGE=0xffff9e64 +RED=0xfff7768e +BAR_COLOR=0xd9101116 +COMMENT=0xff565f89 + +TRANSPARENT=0x00000000 + +# General bar colors +ICON_COLOR=$WHITE # Color of all icons +LABEL_COLOR=$WHITE # Color of all labels + +CONFIG_DIR="$HOME/.config/sketchybar" +ITEM_DIR="$HOME/.config/sketchybar/items" +PLUGIN_DIR="$HOME/.config/sketchybar/plugins" + +FONT="JetBrainsMono Nerd Font" + +PADDINGS=3 + +POPUP_BORDER_WIDTH=2 +POPUP_CORNER_RADIUS=11 +POPUP_BACKGROUND_COLOR=$BLACK +POPUP_BORDER_COLOR=$COMMENT + +CORNER_RADIUS=15 +BORDER_WIDTH=2 + +SHADOW=on diff --git a/dot-config/sway/config b/dot-config/sway/config deleted file mode 100644 index 265ce62..0000000 --- a/dot-config/sway/config +++ /dev/null @@ -1,266 +0,0 @@ -# Read `man 5 sway` for a complete reference. - -### Variables -# -# Logo key. Use Mod1 for Alt. -set $mod Mod4 -# Home row direction keys, like vim -set $left h -set $down j -set $up k -set $right l -# Your preferred terminal emulator -set $term alacritty -# Background images -#set $bgi1 /usr/share/backgrounds/sway/ryan-gosling-drive-movie.jpg -#set $bgi2 /usr/share/backgrounds/sway/EndCredits2560x1600-16bit.png -#set $bgi3 /usr/share/backgrounds/sway/tron.jpg -set $bgi4 /usr/share/backgrounds/sway/forest.jpg -#set $bgi5 /usr/share/backgrounds/sway/forest.jpg -# EndCredits bg image -set $lock_screen swaylock --ignore-empty-password \ - --scaling fill --image $bgi4 \ - --font Hack --font-size 12 --daemonize -# Your preferred application launcher -set $menu wofi --show=drun --lines=5 --prompt="" -# Get the names of the outputs by running: swaymsg -t get_outputs -set $dell34 DP-1 -set $laptop eDP-1 -# Nothing there at the moment -include /etc/sway/config-vars.d/* - - -### Window settings -# -# small border around windows -gaps inner 6 -smart_gaps on -smart_borders no_gaps -# small border just to identify active window more easily -default_border pixel 3 -#default_border none - -### Short lived GUIs to be opened floating -# -# audio controls -for_window [app_id="pavucontrol"] floating enable - -### Output configuration -# -# Wallpaper -output * bg $bgi4 fill -# -# Monitor configs -output $dell34 resolution 3440x1440 position 0,0 -output $laptop resolution 1920x1080 position 3440,0 -# -# Watch closed laptop lid -# This will turn on/off the laptop lid when it is opened/closed -bindswitch --reload --locked lid:on output $laptop disable -bindswitch --reload --locked lid:off output $laptop enable -# -# This will lock your screen after 300 seconds of inactivity, then turn off -# your displays after another 300 seconds, and turn your screens back on when -# resumed. It will also lock your screen before your computer goes to sleep. -# -#exec_always swayidle -w \ -# timeout 300 '$lock_screen' \ -# timeout 900 'swaymsg "output * dpms off"' \ -# resume 'swaymsg "output * dpms on"' \ -# before-sleep '$lock_screen' - -### Input configuration -# -# You can get the names of your inputs by running: swaymsg -t get_inputs -# Read `man 5 sway-input` for more information about this section. -# -input type:touchpad { - natural_scroll enabled - click_method clickfinger - tap enabled - tap_button_map lrm -} - -#input type:keyboard { -# xkb_layout gb -# xkb_variant intl -#} - -input identifier:"21558:24672:Tokyo_Keyboard_Tokyo60" { - xkb_layout us - xkb_variant intl -} - -### Key bindings -# -# Basics: -# - # Start a terminal - bindsym $mod+Return exec $term - - # Kill focused window - bindsym $mod+Shift+q kill - - # Start your launcher - bindsym $mod+d exec $menu - - # Drag floating windows by holding down $mod and left mouse button. - # Resize them with right mouse button + $mod. - # Despite the name, also works for non-floating windows. - # Change normal to inverse to use left mouse button for resizing and right - # mouse button for dragging. - floating_modifier $mod normal - - # Reload the configuration file - bindsym $mod+Shift+c reload - - # Exit sway (logs you out of your Wayland session) - # from https://github.com/fosskers/dotfiles/blob/master/sway/config - # swaynag config in .config/swaynag/config - bindsym $mod+Shift+e exec swaynag -t tron -m 'Aperture clear?' -B 'Exit the Grid.' 'swaymsg exit' - - # Lock screen - bindsym $mod+Shift+z exec $lock_screen -# -# Moving around: -# - # Move your focus around - bindsym $mod+$left focus left - bindsym $mod+$down focus down - bindsym $mod+$up focus up - bindsym $mod+$right focus right - - # Move the focused window with the same, but add Shift - bindsym $mod+Shift+$left move left - bindsym $mod+Shift+$down move down - bindsym $mod+Shift+$up move up - bindsym $mod+Shift+$right move right -# -# Workspaces: -# - # Switch to workspace - bindsym $mod+1 workspace number 1 - bindsym $mod+2 workspace number 2 - bindsym $mod+3 workspace number 3 - bindsym $mod+4 workspace number 4 - bindsym $mod+5 workspace number 5 - bindsym $mod+6 workspace number 6 - bindsym $mod+7 workspace number 7 - bindsym $mod+8 workspace number 8 - bindsym $mod+9 workspace number 9 - bindsym $mod+0 workspace number 10 - # Move focused container to workspace - bindsym $mod+Shift+1 move container to workspace number 1 - bindsym $mod+Shift+2 move container to workspace number 2 - bindsym $mod+Shift+3 move container to workspace number 3 - bindsym $mod+Shift+4 move container to workspace number 4 - bindsym $mod+Shift+5 move container to workspace number 5 - bindsym $mod+Shift+6 move container to workspace number 6 - bindsym $mod+Shift+7 move container to workspace number 7 - bindsym $mod+Shift+8 move container to workspace number 8 - bindsym $mod+Shift+9 move container to workspace number 9 - bindsym $mod+Shift+0 move container to workspace number 10 - # Note: workspaces can have any name you want, not just numbers. - # We just use 1-10 as the default. - - bindsym $mod+m move workspace to output right -# -# Layout stuff: -# - # You can "split" the current object of your focus with - # $mod+b or $mod+v, for horizontal and vertical splits - # respectively. - bindsym $mod+b splith - bindsym $mod+v splitv - - # Toggle between stacking/tabbed/splith/splitv - bindsym $mod+x layout toggle tabbed splith - - # Switch the current container between different layout styles - #bindsym $mod+s layout stacking - #bindsym $mod+w layout tabbed - #bindsym $mod+e layout toggle split - - # Make the current focus fullscreen - bindsym $mod+f fullscreen - - # Toggle the current focus between tiling and floating mode - bindsym $mod+Shift+space floating toggle - - # Swap focus between the tiling area and the floating area - bindsym $mod+space focus mode_toggle - - # Move focus to the parent container - bindsym $mod+a focus parent -# -# Scratchpad: -# - # Sway has a "scratchpad", which is a bag of holding for windows. - # You can send windows there and get them back later. - - # Move the currently focused window to the scratchpad - bindsym $mod+Shift+minus move scratchpad - - # Show the next scratchpad window or hide the focused scratchpad window. - # If there are multiple scratchpad windows, this command cycles through them. - bindsym $mod+minus scratchpad show -# -# Keyboard keys -# - bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% - bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% - bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle - bindsym XF86MonBrightnessUp exec backlight_control +10 - bindsym XF86MonBrightnessDown exec backlight_control -10 - -# -# Screenshots -# - # Screenshot part of screen and copy to clipboard - bindsym $mod+g exec slurp | grim -g - - | wl-copy - -# -# Resizing containers: -# -bindsym $mod+r mode "resize" -mode "resize" { - # left will shrink the containers width - # right will grow the containers width - # up will shrink the containers height - # down will grow the containers height - bindsym $left resize shrink width 10px - bindsym $down resize grow height 10px - bindsym $up resize shrink height 10px - bindsym $right resize grow width 10px - - # Return to default mode - bindsym Return mode "default" - bindsym Escape mode "default" -} -# -# Status Bar: -# -# Read `man 5 sway-bar` for more information about this section. -bar { - swaybar_command waybar -} - -# TO FIX -# Power management commands -# Black background screen (TODO: backlight off) -#set $mode_system System (l) lock, (e) logout, (s) suspend, (r) reboot, (p) poweroff -#bindsym $mod+p mode "$mode_system" -#mode "$mode_system" { -# bindsym l exec --no-startup-id $lock_screen, mode "default" -# bindsym e exec --no-startup-id sway-msg exit, mode "default" -# bindsym s exec --no-startup-id $lock_screen && systemctl suspend, mode "default" -# #bindsym h exec --no-startup-id $lock_screen && systemctl hibernate, mode "default" -# bindsym r exec --no-startup-id systemctl reboot, mode "default" -# bindsym p exec --no-startup-id systemctl poweroff, mode "default" -# -# # back to normal: Enter or Escape -# bindsym Return mode "default" -# bindsym Escape mode "default" -#} - -include /etc/sway/config.d/* diff --git a/dot-config/swaynag/config b/dot-config/swaynag/config deleted file mode 100644 index 7f8a1e4..0000000 --- a/dot-config/swaynag/config +++ /dev/null @@ -1,8 +0,0 @@ -edge=top - -[tron] -border-bottom=8FD4FF -border-bottom-size=1 -border=8FD4FF -button-border-size=1 -button-dismiss-gap=0 diff --git a/dot-config/vim/vimrc b/dot-config/vim/vimrc index 97e2ed5..af92b85 100644 --- a/dot-config/vim/vimrc +++ b/dot-config/vim/vimrc @@ -1,99 +1,9 @@ -set nocompatible - -" ================= PLUGINS -" -" To install vim-plug itself: -" -" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ -" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim -" -" Specify a directory for plugins (for Neovim: ~/.local/share/nvim/plugged) -"call plug#begin('~/.vim/plugged') -" -"" Alignment, usually with ga or ga -"" There's also godlygeek/tabular -"Plug 'junegunn/vim-easy-align' -"" -"" Git wrapper, see http://vimcasts.org/blog/2011/05/the-fugitive-series/ -"Plug 'tpope/vim-fugitive' -" -"" Comment stuff out, usually with gc or gc -"Plug 'tpope/vim-commentary' -" -"" Record session with :Obsess, delete it with :Obsess!, restart a session by -"" sourcing it (:source Session.vim) or directly with vim -S -"Plug 'tpope/vim-obsession' -" -"" enable repeating supported plugin maps with "." -"Plug 'tpope/vim-repeat' -" -"" Helps to end certain structures automatically (e.g. Ruby: do..end) -"Plug 'tpope/vim-endwise' -" -"" Insert or delete brackets, parens, quotes in pair -"Plug 'jiangmiao/auto-pairs' -" -"" Sort a range of text, usually with gs or gs, works on -"" single line too (comma separated sorting) -"Plug 'christoomey/vim-sort-motion' -" -"" Start screen with recent files and sessions -"Plug 'mhinz/vim-startify' -" -"" Better JSON highlighting -"Plug 'elzr/vim-json' -" -"" Display indentation with thin vertical lines (check the conceal setting) -"Plug 'Yggdroot/indentLine' -" -"" Show a git diff in the margin (see github for usage) -"Plug 'airblade/vim-gitgutter' -" -"" Lots of colorscheme in one plugin, use colorscheme in vimrc or as a -"" command -"Plug 'flazz/vim-colorschemes' -"Plug 'Reewr/vim-monokai-phoenix' -""Plug 'altercation/vim-colors-solarized' -" -"" Go development plugin + snippets -"Plug 'fatih/vim-go', { 'do': ':GoInstallBinaries' } -""Plug 'SirVer/ultisnips' -" -"" HCL formating with :HclFmt (requires go get github.com/fatih/hclfmt) -""Plug 'fatih/vim-hclfmt' -" -"" Keyword completion -"Plug 'Shougo/neocomplete' -" -"" Whitespace highlighting -"Plug 'ntpeters/vim-better-whitespace' -" -"" Multiple selections, use * for a starter -"Plug 'terryma/vim-multiple-cursors' -" -"" Fuzzy file, buffer etc finder -""Plug 'ctrlpvim/ctrlp.vim' -" -"" Press F8 to change the colorscheme -""Plug 'felixhummel/setcolors.vim' -" -"" Some colorscheme I might install at some point... -""Plug 'ayu-theme/ayu-vim' -""Plug 'dikiaap/minimalist' -" -"" Status bar (see github for configuration) -""Plug 'vim-airline/vim-airline' -""Plug 'vim-airline/vim-airline-themes' -" -"" Show diff level of parentheses -"Plug 'luochen1990/rainbow' -" -"" Initialize plugin system -"call plug#end() +" When vimrc lives in ~/.config/vim/, packpath doesn't include ~/.vim +" Add it so native pack/ plugins are found +set packpath^=~/.vim " ================= SETTINGS " -" Some settings from tpope/vim-sensible if has('autocmd') filetype plugin indent on endif @@ -101,14 +11,12 @@ if has('syntax') && !exists('g:syntax_on') syntax enable endif -" Use :help 'option' to see the documentation for the given option. - set autoindent set backspace=indent,eol,start set complete-=i set smarttab set hlsearch - +set incsearch set nrformats-=octal if !has('nvim') && &ttimeoutlen == -1 @@ -116,8 +24,7 @@ if !has('nvim') && &ttimeoutlen == -1 set ttimeoutlen=100 endif -set incsearch -" Use to clear the highlighting of :set hlsearch. +" Use to clear search highlighting if maparg('', 'n') ==# '' nnoremap :nohlsearch=has('diff')?'diffupdate':'' endif @@ -160,158 +67,97 @@ if !empty(&viminfo) endif set sessionoptions-=options -" Allow color schemes to do bright colors without forcing bold. +" Allow color schemes to do bright colors without forcing bold if &t_Co == 8 && $TERM !~# '^linux\|^Eterm' set t_Co=16 endif +" ================= LEADER & MAPPINGS +" " Change mapleader from \ to let mapleader=" " -" Use F2 to toggle between paste/nopaste -set pastetoggle= - " Toggle show/hide invisible chars nnoremap i :set list! - -" Allow saving of files as sudo when I forgot to start vim using sudo. +" Allow saving of files as sudo when I forgot to start vim using sudo cmap w!! w !sudo tee > /dev/null % -" Steve Losh -set ttyfast -set undofile -"very magic pattern matching (more similar to Perl regex) +" Very magic pattern matching (more similar to Perl regex) nnoremap / /\v vnoremap / /\v -"go to matching sign with instead of % + +" Go to matching sign with instead of % nnoremap % vnoremap % -"go up/down by screen line instead of file line + +" Go up/down by screen line instead of file line nnoremap j gj nnoremap k gk -" Personal preferences -"colorscheme monokai-phoenix -" yolo -set noswapfile -" set cursorline on active window -set cursorline -au WinLeave * set nocursorline -au WinEnter * set cursorline -" don't reach for escape, capslocks,... key to exit insert mode +" Don't reach for escape key to exit insert mode inoremap jk + " I don't use ; nnoremap ; : -"nnoremap : ; -"modify and source .vimrc easily + +" Modify and source vimrc easily nnoremap ev :e $MYVIMRC nnoremap sv :source $MYVIMRC -"re-open at same position -au BufWinLeave * mkview -au BufWinEnter * silent loadview - -"" ================= PLUGIN SETTINGS -"" -"" ================= EasyAlign -"" Start interactive EasyAlign in visual mode (e.g. vipga) -"xmap ga (EasyAlign) -"" Start interactive EasyAlign for a motion/text object (e.g. gaip) -"nmap ga (EasyAlign) -" -"" ================= NeoComplete -"" Disable AutoComplPop. -"let g:acp_enableAtStartup = 0 -"" Use neocomplete. -"let g:neocomplete#enable_at_startup = 1 -"" Use smartcase. -"let g:neocomplete#enable_smart_case = 1 -"" Set minimum syntax keyword length. -"let g:neocomplete#sources#syntax#min_keyword_length = 3 -" -"" Define dictionary. -"let g:neocomplete#sources#dictionary#dictionaries = { -" \ 'default' : '', -" \ 'vimshell' : $HOME.'/.vimshell_hist', -" \ 'scheme' : $HOME.'/.gosh_completions' -" \ } -" -"" Define keyword. -"if !exists('g:neocomplete#keyword_patterns') -" let g:neocomplete#keyword_patterns = {} -"endif -"let g:neocomplete#keyword_patterns['default'] = '\h\w*' -" -"" Plugin key-mappings. -"inoremap neocomplete#undo_completion() -"inoremap neocomplete#complete_common_string() -" -"" Recommended key-mappings. -"" : close popup and save indent. -"inoremap =my_cr_function() -"function! s:my_cr_function() -" return (pumvisible() ? "\" : "" ) . "\" -" " For no inserting key. -" "return pumvisible() ? "\" : "\" -"endfunction -"" : completion. -"inoremap pumvisible() ? "\" : "\" -"" , : close popup and delete backword char. -"inoremap neocomplete#smart_close_popup()."\" -"inoremap neocomplete#smart_close_popup()."\" -"" Close popup by . -""inoremap pumvisible() ? "\" : "\" -" -"" AutoComplPop like behavior. -""let g:neocomplete#enable_auto_select = 1 -" -"" Shell like behavior(not recommended). -""set completeopt+=longest -""let g:neocomplete#enable_auto_select = 1 -""let g:neocomplete#disable_auto_complete = 1 -""inoremap pumvisible() ? "\" : "\\" -" -"" Enable omni completion. -"autocmd FileType css setlocal omnifunc=csscomplete#CompleteCSS -""autocmd FileType html,markdown setlocal omnifunc=htmlcomplete#CompleteTags -"autocmd FileType javascript setlocal omnifunc=javascriptcomplete#CompleteJS -"autocmd FileType python setlocal omnifunc=pythoncomplete#Complete -"autocmd FileType xml setlocal omnifunc=xmlcomplete#CompleteTags -" -"" Enable heavy omni completion. -"if !exists('g:neocomplete#sources#omni#input_patterns') -" let g:neocomplete#sources#omni#input_patterns = {} -"endif -""let g:neocomplete#sources#omni#input_patterns.php = '[^. \t]->\h\w*\|\h\w*::' -""let g:neocomplete#sources#omni#input_patterns.c = '[^.[:digit:] *\t]\%(\.\|->\)' -""let g:neocomplete#sources#omni#input_patterns.cpp = '[^.[:digit:] *\t]\%(\.\|->\)\|\h\w*::' -" -"" For perlomni.vim setting. -"" https://github.com/c9s/perlomni.vim -"let g:neocomplete#sources#omni#input_patterns.perl = '\h\w*->\h\w*\|\h\w*::' -" -"" ================= Vim-JSON -"" Do not conceal json -"let g:vim_json_syntax_conceal = 0 + +" ================= PREFERENCES " -"" ================= Vim-GitGutter -"" Check github for more settings and usage -"set updatetime=300 -"nmap gh GitGutterNextHunk +set noswapfile +set cursorline +au WinLeave * set nocursorline +au WinEnter * set cursorline + +" Colorscheme +set termguicolors +let g:tokyonight_style = 'night' +let g:tokyonight_enable_italic = 1 +silent! colorscheme tokyonight + +" Transparent background (let terminal opacity show through) +highlight Normal guibg=NONE ctermbg=NONE +highlight NonText guibg=NONE ctermbg=NONE +highlight EndOfBuffer guibg=NONE ctermbg=NONE + +" ================= PLUGIN SETTINGS " -"" ================= rainbow -"" Activate rainbow parentheses -"let g:rainbow_active = 1 +" --- GitGutter +set updatetime=300 +nmap gh (GitGutterNextHunk) +nmap gH (GitGutterPrevHunk) + +" --- fzf.vim +" Requires fzf to be installed (brew install fzf) +set rtp+=/usr/local/opt/fzf +set rtp+=/opt/homebrew/opt/fzf +nnoremap f :Files +nnoremap b :Buffers +nnoremap r :Rg +nnoremap l :Lines -" Backups, undos, and swap files -"----------------------------------------------------------------------------- -" Save your backups to a less annoying place than the current directory. +" --- Commentary (gc or gcc for current line) +" No config needed, works out of the box + +" --- Surround (cs"' to change, ds" to delete, ysiw" to add) +" No config needed, works out of the box + +" --- Fugitive +nnoremap gs :Git +nnoremap gd :Gdiffsplit +nnoremap gb :Git blame +nnoremap gl :Git log --oneline + +" ================= BACKUPS & UNDO +" +" Save backups to a less annoying place than the current directory set backupdir-=. set backupdir+=~/.vim/backup,/tmp set backup -" Prevent backups from overwriting each other. The naming is weird, -" since I'm using the 'backupext' variable to append the path. -" So the file '/home/docwhat/.vimrc' becomes '.vimrc%home%docwhat~' +" Prevent backups from overwriting each other if has('autocmd') augroup MyBackupGroup autocmd! @@ -319,23 +165,18 @@ if has('autocmd') augroup END endif -" Save your swp files to a less annoying place than the current directory. +" Save swp files to a less annoying place set directory=~/.vim/swp,/tmp -" viminfo stores the the state of your previous editing session +" Persistent undo across sessions if exists('+undofile') - " undofile - This allows you to use undos after exiting and restarting set undodir=~/.vim/undo,/tmp set undofile - set undolevels=1000 " maximum number of changes that can be undone - set undoreload=10000 " maximum number lines to save for undo on a buffer reload + set undolevels=1000 + set undoreload=10000 endif -" When editing a file, always jump to the last known cursor position. -" Don't do it when the position is invalid or when inside an event handler -" (happens when dropping a file on gvim). -" Also don't do it when the mark is in the first line, that is the default -" position when opening a file. +" Jump to last known cursor position when reopening a file if has('autocmd') augroup MyLastCursor autocmd! @@ -346,3 +187,58 @@ if has('autocmd') augroup END endif +" ================= DISABLED PLUGINS (previously used with vim-plug) +" +" To install any of these with native packages: +" cd ~/.vim/pack/plugins/start +" git clone --depth 1 https://github.com/.git +" +" junegunn/vim-easy-align — alignment with ga +" tpope/vim-obsession — session management (:Obsess) +" tpope/vim-repeat — enable . repeat for plugin maps +" tpope/vim-endwise — auto-close do..end, if..endif +" jiangmiao/auto-pairs — auto-close brackets/quotes +" christoomey/vim-sort-motion — sort with gs +" mhinz/vim-startify — start screen with recent files +" elzr/vim-json — better JSON highlighting +" Yggdroot/indentLine — show indent guides +" ntpeters/vim-better-whitespace — highlight trailing whitespace +" luochen1990/rainbow — rainbow parentheses + +" ================= CHEATSHEET +" +" Navigation: +" j/k move by screen line (not file line) +" gf open file under cursor +" Ctrl+w f open file under cursor in split +" Tab jump to matching bracket (instead of %) +" Ctrl+L clear search highlighting +" * search word under cursor +" +" Leader (): +" f fzf: find files +" b fzf: find buffers +" r fzf: ripgrep search +" l fzf: search lines +" i toggle invisible characters +" ev edit vimrc in split +" sv source (reload) vimrc +" gs git status (fugitive) +" gd git diff split (fugitive) +" gb git blame (fugitive) +" gl git log (fugitive) +" +" Plugins: +" gcc comment/uncomment line (commentary) +" gc comment/uncomment selection (commentary) +" cs"' change surrounding " to ' (surround) +" ds" delete surrounding " (surround) +" ysiw" add " around word (surround) +" gh next git hunk (gitgutter) +" gH prev git hunk (gitgutter) +" +" Other: +" jk exit insert mode (instead of Esc) +" ; command mode (instead of :) +" :w!! save as sudo +" / search with very magic (perl-like regex) diff --git a/dot-config/waybar/config b/dot-config/waybar/config deleted file mode 100644 index e8d1d50..0000000 --- a/dot-config/waybar/config +++ /dev/null @@ -1,55 +0,0 @@ -{ - "layer": "top", - "position": "bottom", - "height": 24, - "margin-left": 5, - "margin-right": 5, - "margin-top": 5, - "modules-left": ["sway/workspaces"], - "modules-center": [], - "modules-right": ["network", "temperature", "cpu", "memory", "battery", "pulseaudio", "clock"], - "sway/workspaces": { - "disable-scroll": true, - "disable-click": true, - }, - "tray": { - "spacing": 10, - }, - "clock": { - "format": "{:%A %e %B %R}" - }, - "cpu": { - "format": " {usage}%" - }, - "memory": { - "format": " {}%" - }, - "temperature": { - "critical-threshold": 75, - "format": " {temperatureC}°C" - }, - "battery": { - "bat": "BAT0", - "full-at": 95, - "states": { - "good": 95, - "warning": 30, - "critical": 15 - }, - "format": "{icon} {capacity}%", - "format-icons": ["", "", "", "", ""] - }, - "network": { - "format-wifi": " {essid}", - "format-disconnected": "⚠ Disconnected" - }, - "pulseaudio": { - "format": "{icon} {volume}%", - "format-muted": "", - "format-icons": { - "headphones": "", - "default": ["", ""] - }, - "on-click": "pavucontrol" - }, -} diff --git a/dot-config/waybar/style.css b/dot-config/waybar/style.css deleted file mode 100644 index 7241f71..0000000 --- a/dot-config/waybar/style.css +++ /dev/null @@ -1,91 +0,0 @@ -* { - font-family: "Ubuntu Nerd Font"; - font-size: 13px; - min-height: 0; -} - -window#waybar { - background: transparent; - /* background: black; */ - /* background: rgba(40, 44, 52, 0.85); */ - color: white; - border: 1px solid #8fd4ff; - border-radius: 6px; -} - -#window { - font-family: "Ubuntu"; -} - -#workspaces button.focused { - color: #8fd4ff; - border: 1px solid #8fd4ff; - border-radius: 6px; -} - -#workspaces button:hover { - background-color: #8fd4ff; - border: 1px solid #8fd4ff; - border-radius: 6px; -} - -#workspaces button { - color: grey; -} - -#tray, -#temperature, -#clock, -#battery, -#cpu, -#memory, -#network, -#pulseaudio { - padding: 0 5px; - margin-right: 5px; - margin-top: 5px; - margin-bottom: 5px; -} - -#temperature.critical { - color: #b62d66; -} - -#battery icon { - color: #b62d66; -} - -#battery.charging { - border-bottom: 1px dotted #8fd4ff; -} - -@keyframes blink { - to { - background-color: #8fd4ff; - color: black; - } -} - -#battery.warning:not(.charging) { - color: white; - animation-name: blink; - animation-duration: 2s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; - border-radius: 5px; -} - -#battery.warning:not(.charging) { - color: white; - animation-name: blink; - animation-duration: 1s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; - border-radius: 5px; -} - -#network.disconnected { - color: #b62d66; -} diff --git a/dot-config/wofi/style.css b/dot-config/wofi/style.css deleted file mode 100644 index 4d738e1..0000000 --- a/dot-config/wofi/style.css +++ /dev/null @@ -1,54 +0,0 @@ -window { - margin: 5px; - border: 1px solid #8fd4ff; - border-radius: 10px; - background-color: rgba(44, 62, 80, 0.8); - /* background: transparent; */ - /* background: transparent; */ -} - -#input { - margin: 5px; - background: transparent; - color: white; - /* border: 2px solid blue; */ - /* background-color: blue; */ -} - -#inner-box { - margin: 5px; - /* border: 2px solid yellow; */ - /* background-color: yellow; */ -} - -#outer-box { - margin: 5px; - /* border: 2px solid green; */ - border: 2px transparent; - /* background-color: green; */ -} - -#scroll { - margin: 5px; - /* border: 2px solid orange; */ - /* background-color: orange; */ -} - -#text { - margin: 5px; - color: white; - /* border: 2px solid cyan; */ - /* background-color: cyan; */ -} - -#entry:selected { - background-color: rgba(0, 0, 0, 0); - /* text-decoration: underline; */ - /* text-decoration-color: white; */ -} - -#text:selected { - /* background-color: red; */ - text-decoration: underline; - text-decoration-color: white; -} diff --git a/dot-inputrc b/dot-inputrc index 3837d20..0e1bcae 100644 --- a/dot-inputrc +++ b/dot-inputrc @@ -1,6 +1,4 @@ # see: https://wiki.archlinux.org/title/Readline -# -$include /etc/inputrc # i'm just used to it... set editing-mode emacs @@ -35,6 +33,3 @@ set completion-map-case on # faster completion set show-all-if-ambiguous on - -# search through pet snippets (see also .functions file) -#bind -x '"\C-x\C-r": pet-select' diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..9b0d8c8 --- /dev/null +++ b/install.sh @@ -0,0 +1,304 @@ +#!/bin/bash +set -euo pipefail + +# ───────────────────────────────────────────────────────────── +# macOS dotfiles bootstrap script +# Run from the dotfiles repo root: +# cd ~/GitHub/kifbv/dotfiles && ./install.sh +# ───────────────────────────────────────────────────────────── + +DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WALLPAPER_URL="https://w.wallhaven.cc/full/0p/wallhaven-0p7e83.jpg" +WALLPAPER_PATH="$HOME/Pictures/wallpaper-cyberpunk.jpg" + +echo "==> macOS dotfiles installer" +echo " Dotfiles directory: $DOTFILES_DIR" +echo "" + +# ── User identity ──────────────────────────────────────── +echo "==> Configure git identity" +read -rp " Full name: " GIT_NAME +read -rp " Email: " GIT_EMAIL +echo "" + +# ── Homebrew ────────────────────────────────────────────── +if ! command -v brew &>/dev/null; then + echo "==> Installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + # Add Homebrew to PATH for this session + if [[ -d "/opt/homebrew/bin" ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -d "/usr/local/bin" ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi +else + echo "==> Homebrew already installed" +fi + +echo "==> Updating Homebrew..." +brew update + +# ── Brew formulae ───────────────────────────────────────── +echo "==> Installing brew formulae..." +FORMULAE=( + bash + git + vim + stow + fzf + tree + jq + gnupg + diff-so-fancy + pinentry-mac + gh + bitwarden-cli + wget +) + +for formula in "${FORMULAE[@]}"; do + if brew list "$formula" &>/dev/null; then + echo " $formula already installed" + else + echo " Installing $formula..." + brew install "$formula" + fi +done + +# ── Brew casks ──────────────────────────────────────────── +echo "==> Installing brew casks..." +CASKS=( + nikitabobko/tap/aerospace + ghostty + maccy +) + +for cask in "${CASKS[@]}"; do + cask_name=$(basename "$cask") + # Check if already installed via brew or if the app exists in /Applications + # Using awk instead of ${var^} because on a fresh Mac this script runs + # under /bin/bash (3.2) which doesn't support parameter case modification + app_name=$(echo "$cask_name" | awk '{print toupper(substr($0,1,1)) substr($0,2)}').app + if brew list --cask "$cask_name" &>/dev/null 2>&1 || brew list "$cask" &>/dev/null 2>&1; then + echo " $cask_name already installed (via brew)" + elif ls /Applications/ | grep -qi "^${cask_name}" 2>/dev/null; then + echo " $cask_name already installed (found in /Applications)" + else + echo " Installing $cask_name..." + brew install --cask "$cask" 2>/dev/null || brew install "$cask" + fi +done + +# ── Brew services (taps for sketchybar, borders) ───────── +echo "==> Installing sketchybar and borders..." +if ! brew list sketchybar &>/dev/null; then + brew install FelixKratz/formulae/sketchybar +else + echo " sketchybar already installed" +fi + +if ! brew list borders &>/dev/null; then + brew install FelixKratz/formulae/borders +else + echo " borders already installed" +fi + +if ! brew list choose-gui &>/dev/null; then + brew install choose-gui +else + echo " choose-gui already installed" +fi + +# ── Font ────────────────────────────────────────────────── +echo "==> Installing JetBrainsMono Nerd Font..." +if brew list --cask font-jetbrains-mono-nerd-font &>/dev/null 2>&1; then + echo " Font already installed" +else + brew install --cask font-jetbrains-mono-nerd-font +fi + +# ── Set Homebrew bash as default shell ──────────────────── +BREW_BASH="" +if [[ -x "/opt/homebrew/bin/bash" ]]; then + BREW_BASH="/opt/homebrew/bin/bash" +elif [[ -x "/usr/local/bin/bash" ]]; then + BREW_BASH="/usr/local/bin/bash" +fi + +if [[ -n "$BREW_BASH" ]]; then + if ! grep -q "$BREW_BASH" /etc/shells; then + echo "==> Adding $BREW_BASH to /etc/shells..." + echo "$BREW_BASH" | sudo tee -a /etc/shells >/dev/null + fi + if [[ "$SHELL" != "$BREW_BASH" ]]; then + echo "==> Setting $BREW_BASH as default shell..." + chsh -s "$BREW_BASH" + else + echo "==> Homebrew bash already set as default shell" + fi +fi + +# ── Stow ────────────────────────────────────────────────── +echo "==> Running stow to create symlinks..." +cd "$DOTFILES_DIR" + +# Remove any existing conflicting files/symlinks before stowing +# (only the ones stow would create) +CONFLICTS=( + "$HOME/.bashrc" + "$HOME/.inputrc" +) +for f in "${CONFLICTS[@]}"; do + if [[ -f "$f" && ! -L "$f" ]]; then + echo " Backing up existing $f to ${f}.bak" + mv "$f" "${f}.bak" + fi +done + +stow --dotfiles --target "$HOME" . + +# ── Git identity ───────────────────────────────────────── +echo "==> Configuring git identity..." +git config --global user.name "$GIT_NAME" +git config --global user.email "$GIT_EMAIL" + +# ── Vim setup ───────────────────────────────────────────── +echo "==> Setting up Vim..." +mkdir -p "$HOME/.vim/backup" +mkdir -p "$HOME/.vim/undo" +mkdir -p "$HOME/.vim/swp" + +# Install plugins via native pack (vim 8+) +VIM_PLUGINS=( + "tpope/vim-commentary" + "tpope/vim-surround" + "tpope/vim-fugitive" + "airblade/vim-gitgutter" + "junegunn/fzf.vim" + "ghifarit53/tokyonight-vim" +) +mkdir -p "$HOME/.vim/pack/plugins/start" +for plugin in "${VIM_PLUGINS[@]}"; do + plugin_name=$(basename "$plugin") + if [[ -d "$HOME/.vim/pack/plugins/start/$plugin_name" ]]; then + echo " $plugin_name already installed" + else + echo " Installing $plugin_name..." + git clone --depth 1 "https://github.com/$plugin.git" "$HOME/.vim/pack/plugins/start/$plugin_name" 2>/dev/null + fi +done +# Remove old vimrc if it exists (vim 9+ reads from ~/.config/vim/vimrc) +if [[ -f "$HOME/.vimrc" && ! -L "$HOME/.vimrc" ]]; then + echo " Backing up old ~/.vimrc to ~/.vimrc.bak" + mv "$HOME/.vimrc" "$HOME/.vimrc.bak" +fi + +# ── GPG setup ──────────────────────────────────────────── +echo "==> Setting up GPG..." +mkdir -p "$HOME/.gnupg" +chmod 700 "$HOME/.gnupg" +# Configure pinentry-mac for GPG passphrase prompts +if [[ ! -f "$HOME/.gnupg/gpg-agent.conf" ]]; then + echo "pinentry-program $(command -v pinentry-mac)" > "$HOME/.gnupg/gpg-agent.conf" + echo " Created gpg-agent.conf with pinentry-mac" +else + echo " gpg-agent.conf already exists" +fi + +# ── SSH key ─────────────────────────────────────────────── +echo "==> Setting up SSH key..." +if [[ -f "$HOME/.ssh/id_ed25519" ]]; then + echo " SSH key already exists" +else + echo " Generating new ed25519 SSH key..." + mkdir -p "$HOME/.ssh" + chmod 700 "$HOME/.ssh" + ssh-keygen -t ed25519 -C "$GIT_EMAIL" -f "$HOME/.ssh/id_ed25519" -N "" + cat >> "$HOME/.ssh/config" << SSHEOF +Host github.com + IdentityFile ~/.ssh/id_ed25519 + AddKeysToAgent yes +SSHEOF + chmod 600 "$HOME/.ssh/config" + echo " SSH key generated. Add to GitHub with: gh ssh-key add ~/.ssh/id_ed25519.pub --title \"$(hostname -s)\"" +fi + +# ── GPG key ────────────────────────────────────────────── +echo "==> Setting up GPG key..." +if gpg --list-secret-keys 2>/dev/null | grep -q sec; then + echo " GPG key already exists" +else + echo " Generating new GPG key..." + gpg --batch --gen-key </dev/null | grep sec | head -1 | awk -F'/' '{print $2}' | awk '{print $1}') + if [[ -n "$GPG_KEY_ID" ]]; then + # Update git config with new key ID + git config --file "$DOTFILES_DIR/dot-config/git/config" user.signingkey "$GPG_KEY_ID" + echo " GPG key generated: $GPG_KEY_ID" + echo " Add to GitHub with: gpg --armor --export $GPG_KEY_ID | gh gpg-key add -" + fi +fi + +# ── Make scripts executable ─────────────────────────────── +echo "==> Making scripts executable..." +chmod +x "$DOTFILES_DIR/dot-config/aerospace/"*.sh +chmod +x "$DOTFILES_DIR/dot-config/sketchybar/sketchybarrc" +chmod +x "$DOTFILES_DIR/dot-config/sketchybar/plugins/"*.sh +chmod +x "$DOTFILES_DIR/dot-config/sketchybar/items/"*.sh +chmod +x "$DOTFILES_DIR/dot-config/borders/bordersrc" +chmod +x "$DOTFILES_DIR/install.sh" + +# ── Start services ──────────────────────────────────────── +echo "==> Starting services..." +if brew services list | grep -q "sketchybar.*started"; then + echo " sketchybar already running, restarting..." + brew services restart sketchybar +else + echo " Starting sketchybar..." + brew services start sketchybar +fi + +# ── Wallpaper ───────────────────────────────────────────── +echo "==> Downloading wallpaper..." +mkdir -p "$(dirname "$WALLPAPER_PATH")" +if [[ ! -f "$WALLPAPER_PATH" ]]; then + curl -fsSL "$WALLPAPER_URL" -o "$WALLPAPER_PATH" && \ + echo " Wallpaper saved to $WALLPAPER_PATH" || \ + echo " Warning: Failed to download wallpaper" +else + echo " Wallpaper already exists at $WALLPAPER_PATH" +fi + +# Try to set wallpaper via osascript +if [[ -f "$WALLPAPER_PATH" ]]; then + osascript -e "tell application \"System Events\" to tell every desktop to set picture to \"$WALLPAPER_PATH\"" 2>/dev/null && \ + echo " Wallpaper set successfully" || \ + echo " Note: Set wallpaper manually from $WALLPAPER_PATH" +fi + +# ── Done ────────────────────────────────────────────────── +echo "" +echo "==> Installation complete!" +echo "" +echo " Next steps:" +echo " 1. Restart your terminal (or run: exec bash)" +echo " 2. Log in to GitHub CLI: gh auth login" +echo " 3. Add SSH key to GitHub: gh ssh-key add ~/.ssh/id_ed25519.pub --title \"$(hostname -s)\"" +echo " 4. Add GPG key to GitHub: gpg --armor --export \$(git config user.signingkey) | gh gpg-key add -" +echo " 5. Log in to Bitwarden CLI: bw login" +echo " 6. Grant Accessibility permissions to AeroSpace in System Settings" +echo " 7. Grant Accessibility permissions to SketchyBar in System Settings" +echo ""