mirror of
https://github.com/andwati/dotfiles.git
synced 2026-10-18 11:02:53 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67fff22a05
|
||
|
|
71d06b8c41
|
||
|
|
51496a99e7
|
||
|
|
ad4c79ab26
|
||
|
|
ee9745e322
|
||
|
|
6ca122c090
|
||
|
|
3a88e736d7
|
||
|
|
1049ec63df
|
||
|
|
f4d64fc8ed
|
||
|
|
97087ae79e
|
||
|
|
5a9efe5e5a
|
||
|
|
3145c6968b
|
||
|
|
6d44016cda
|
||
|
|
5da9d952ca
|
||
|
|
79ffebb1de
|
||
|
|
d9517de823
|
||
|
|
344a400b20
|
||
|
|
e5f3bd56a7
|
||
|
|
e3a4c4d9fb
|
||
|
|
7883a71a4c | ||
|
|
67d0202c12 | ||
|
|
9fe219a209 | ||
|
|
391ba10516 | ||
|
|
9d3f45a821
|
||
|
|
20df614d54
|
||
|
|
9370afd396
|
||
|
|
a48be5af09
|
||
|
|
bcfb1ce883
|
@@ -1,2 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
*.swp
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 Ian Andwati
|
Copyright (c) 2023 Ian Andwati
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,139 +1,52 @@
|
|||||||
# dotfiles
|
# dotfiles
|
||||||
|
|
||||||
My configuration files, plus a modular installer for the tools I use on a
|
My configuration files that keep me from flipping a table after logging in.
|
||||||
fresh Ubuntu box (targeting 26.04). Everything installs from each vendor's
|
|
||||||
official source — apt repos with their real signing keys, or their official
|
|
||||||
install scripts/tarballs. No PPAs of unclear provenance, no snaps unless the
|
|
||||||
vendor's own instructions use one (Ubuntu's own default snaps are actively
|
|
||||||
replaced — see `desnap.sh` below).
|
|
||||||
|
|
||||||
## Quick start
|
## Setup
|
||||||
|
|
||||||
On a fresh Ubuntu install:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git clone <this-repo> ~/dotfiles
|
|
||||||
cd ~/dotfiles
|
|
||||||
./bootstrap.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
That will:
|
|
||||||
|
|
||||||
1. Install `stow`, `zsh`, `curl`, `git`.
|
|
||||||
2. Symlink the dotfiles (`zsh/`, `git/`, `tmux/`, `vscode/`) into `$HOME` with
|
|
||||||
GNU Stow.
|
|
||||||
3. Prompt once for your git name/email/signing key, saved to
|
|
||||||
`~/.gitconfig.local` (gitignored — never committed, so this repo stays
|
|
||||||
shareable).
|
|
||||||
4. Set zsh as your default shell.
|
|
||||||
5. Run `install/install.sh`, which shows a checklist (see below) of every
|
|
||||||
tool to install.
|
|
||||||
|
|
||||||
Open a new shell afterwards (or `exec zsh`) to pick up PATH changes.
|
|
||||||
|
|
||||||
## Picking what to install
|
|
||||||
|
|
||||||
Run interactively with no arguments and `install/install.sh` shows a
|
|
||||||
`whiptail` checklist — space to toggle, enter to confirm. Everything's
|
|
||||||
checked by default; uncheck what you don't want. If `whiptail` isn't
|
|
||||||
available it's installed automatically; if that's not possible either it
|
|
||||||
falls back to a plain numbered prompt.
|
|
||||||
|
|
||||||
Non-interactive options:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./bootstrap.sh nvm node pnpm docker # only these modules (+ base deps)
|
|
||||||
./install/install.sh --list # list all module names
|
|
||||||
./install/install.sh --except discord,slack,spotify
|
|
||||||
./install/install.sh --all # skip the checklist, install everything
|
|
||||||
./install/install.sh --dry-run # show what would run without doing it
|
|
||||||
```
|
|
||||||
|
|
||||||
`--dry-run` works with any of the above (`--dry-run --all`,
|
|
||||||
`--dry-run nvm docker`, ...) and also works on `bootstrap.sh` and
|
|
||||||
`desnap.sh`.
|
|
||||||
|
|
||||||
## Resilience: a failed module doesn't kill the run
|
|
||||||
|
|
||||||
Every module runs in its own subshell with `errexit` on. If a command in a
|
|
||||||
module fails partway through, that module's own changes (packages
|
|
||||||
installed, repos added, directories created, group memberships granted —
|
|
||||||
whatever it called `rollback_push` for) are unwound in reverse order, the
|
|
||||||
failure is recorded, and the **next module still runs**. At the end you get
|
|
||||||
a summary of what succeeded and what failed, and the script exits nonzero
|
|
||||||
only if something actually failed. Every module is also idempotent — safe
|
|
||||||
to re-run individually or all together.
|
|
||||||
|
|
||||||
## What gets installed
|
|
||||||
|
|
||||||
| Category | Tools |
|
|
||||||
|---|---|
|
|
||||||
| System | apt mirror benchmarking, `~/.ssh`/`~/.gnupg` permission fixes, eza/ripgrep |
|
|
||||||
| JS/TS runtimes | nvm, node (via nvm, LTS), pnpm, deno, bun |
|
|
||||||
| Python | pyenv, pipx, pipenv, poetry, uv |
|
|
||||||
| Systems languages | go, rust (rustup), zig + zls |
|
|
||||||
| Dev tooling | VS Code (+ your extensions/settings, mirrored to Cursor), Cursor, GitHub CLI (`gh`), Docker Engine |
|
|
||||||
| Apps | Chrome, Firefox, Discord, Slack, Postman, JetBrains Toolbox, mpv, Spotify, Telegram, Signal, ProtonVPN, OneDrive (abraunegg) |
|
|
||||||
| Desktop | GNOME Tweaks, Extension Manager, AppIndicator support |
|
|
||||||
| Misc | Wakatime API key setup |
|
|
||||||
|
|
||||||
## Layout
|
|
||||||
|
|
||||||
```
|
```
|
||||||
bootstrap.sh entrypoint: stows dotfiles, then runs install/install.sh
|
sudo pacman -S stow # or your distro's equivalent
|
||||||
desnap.sh standalone: purges snapd, replaces default snaps with apt/Flatpak
|
git clone https://github.com/andwati/dotfiles ~/dev/dotfiles
|
||||||
install/
|
~/dev/dotfiles/install.sh
|
||||||
lib.sh shared shell helpers (apt/repo/rollback/profile-line helpers)
|
|
||||||
install.sh module runner — TUI checklist, dry-run, rollback, summary
|
|
||||||
modules/*.sh one file per tool, each defines install_<name>()
|
|
||||||
zsh/ git/ tmux/ vscode/ stow packages — mirror their target layout under $HOME
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To add a new tool: drop a new `install/modules/<name>.sh` defining
|
Each top-level directory is a [GNU Stow](https://www.gnu.org/software/stow/)
|
||||||
`install_<name>()`, and add `<name>` (+ a description) to `ALL_MODULES` /
|
package mirroring `$HOME` (e.g. `zsh/.zshrc` -> `~/.zshrc`). `install.sh`
|
||||||
`MODULE_DESC` in `install/install.sh`.
|
clones oh-my-zsh plus the theme/plugins `.zshrc` expects (powerlevel10k,
|
||||||
|
zsh-autosuggestions, zsh-syntax-highlighting, zsh-history-substring-search,
|
||||||
|
zsh-completions, you-should-use), then stows the `zsh`, `gnupg`, `git`,
|
||||||
|
`ghostty`, `kde`, `nvim`, and `vscode` packages to link everything in, backing
|
||||||
|
up any conflicting real files it finds first (e.g. oh-my-zsh's own
|
||||||
|
freshly-installed `.zshrc`).
|
||||||
|
|
||||||
## desnap.sh
|
To add a new package: create a top-level dir shaped like `$HOME` (e.g.
|
||||||
|
`git/.gitconfig`), then add a `stow_package <name>` call in `install.sh`.
|
||||||
|
|
||||||
Purges snapd entirely and pins it out of apt so it can't come back on
|
`gpg-agent.conf` caches your GPG passphrase for 8 hours (24h hard cap)
|
||||||
upgrade. Before removing anything it works out, per installed snap, whether
|
instead of the 10-minute default, so signed commits don't re-prompt
|
||||||
there's a real replacement:
|
constantly, and uses `pinentry-qt` for a native dialog instead of a
|
||||||
|
terminal prompt.
|
||||||
|
|
||||||
- Snaps we already have an official-source module for (Firefox) get that
|
Not installed by the script — grab these separately if a fresh machine needs
|
||||||
module.
|
them: `nvm`, `pyenv`, `bun`, `pnpm`, `deno`, `rustup`, `docker`, `fzf`,
|
||||||
- Known default-Ubuntu snaps with a plain apt equivalent (Thunderbird,
|
`zoxide`, and a Nerd Font (JetBrains Mono Nerd Font) set as your terminal font.
|
||||||
snap-store → gnome-software) get that apt package.
|
|
||||||
- GNOME/core runtime snaps (content-only, no user-facing app) are skipped.
|
|
||||||
- Anything else gets Flatpak + Flathub set up and is listed at the end so
|
|
||||||
you can `flatpak search`/`install` it yourself, rather than guessing an
|
|
||||||
app id.
|
|
||||||
|
|
||||||
Destructive and asks for confirmation (`-y`/`--yes` to skip the prompt);
|
## Everforest theme
|
||||||
supports `--dry-run` to preview the plan first.
|
|
||||||
|
|
||||||
```sh
|
The desktop is themed with [Everforest](https://github.com/sainnhe/everforest)
|
||||||
./desnap.sh --dry-run
|
(dark, medium; background `#2b3339`):
|
||||||
./desnap.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
- `kde` — `Everforest` color scheme, wallpaper, and the lock screen wallpaper
|
||||||
|
(`kscreenlockerrc`). Select the scheme in System Settings > Colors.
|
||||||
|
- `ghostty` — `everforest-dark` theme with background opacity and blur (needs
|
||||||
|
KWin's Blur effect on Plasma).
|
||||||
|
- `nvim` — LazyVim with `neanias/everforest-nvim` (transparent background) and
|
||||||
|
LSP for zig, python, typescript, rust, go, c and c++.
|
||||||
|
- `vscode` — user `settings.json` (Everforest Dark via the
|
||||||
|
`reesew.everforest-theme` extension).
|
||||||
|
- `chrome/everforest` — not stowed. Open `chrome://extensions`, enable
|
||||||
|
Developer mode, and Load unpacked on that folder.
|
||||||
|
|
||||||
- `mirrors` benchmarks official Ubuntu mirrors (speed + a freshness check on
|
The Plasma Login Manager screen is root-owned and can't be stowed: pick the
|
||||||
`Last-Modified`) and rewrites apt's sources to the fastest one — handles
|
wallpaper and sync colors in System Settings > Login Screen after changing the
|
||||||
both the legacy `sources.list` and the 24.04+/26.04 deb822
|
scheme. Firefox uses the Everforest Dark Medium theme from addons.mozilla.org.
|
||||||
`ubuntu.sources` format. Runs early so the rest of the install benefits.
|
|
||||||
`security.ubuntu.com` is left alone on purpose.
|
|
||||||
- `firefox` removes the transitional apt stub / snap package first and pins
|
|
||||||
Mozilla's official apt repo, since stock Ubuntu ships Firefox as a snap.
|
|
||||||
- `docker`, `onedrive` each check whether their upstream repo has packages
|
|
||||||
for the running Ubuntu codename/version yet and fall back to the most
|
|
||||||
recent known-supported one if it's too new (relevant right after a fresh
|
|
||||||
26.04 install).
|
|
||||||
- `vscode` installs every extension listed in `vscode/extensions.txt`
|
|
||||||
(exported with `code --list-extensions`) and mirrors `settings.json` to
|
|
||||||
Cursor via symlink, so both stay in sync from one source of truth.
|
|
||||||
- `wakatime` prompts once for your API key and writes `~/.wakatime.cfg`
|
|
||||||
(chmod 600); leave the prompt blank to skip.
|
|
||||||
- Tool PATH/init lines are appended idempotently to the end of `zsh/.zshrc`
|
|
||||||
by `profile_add` in `install/lib.sh` — re-running a module never
|
|
||||||
duplicates a line.
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
export DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
# shellcheck source=install/lib.sh
|
|
||||||
source "$DOTFILES_DIR/install/lib.sh"
|
|
||||||
|
|
||||||
DRY_RUN=0
|
|
||||||
for a in "$@"; do
|
|
||||||
if [[ "$a" == "--dry-run" ]]; then DRY_RUN=1; fi
|
|
||||||
done
|
|
||||||
export DRY_RUN
|
|
||||||
|
|
||||||
STOW_PACKAGES=(zsh git tmux vscode)
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == "1" ]]; then
|
|
||||||
log "[dry-run] would install base packages: stow zsh curl git"
|
|
||||||
log "[dry-run] would stow: ${STOW_PACKAGES[*]} -> \$HOME"
|
|
||||||
else
|
|
||||||
log "installing base packages"
|
|
||||||
apt_install stow zsh curl git
|
|
||||||
|
|
||||||
log "stowing dotfiles from $DOTFILES_DIR"
|
|
||||||
stow -v -t "$HOME" -d "$DOTFILES_DIR" "${STOW_PACKAGES[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == "1" ]]; then
|
|
||||||
log "[dry-run] would prompt for git identity + signing key -> ~/.gitconfig.local"
|
|
||||||
elif [[ ! -f "$HOME/.gitconfig.local" ]]; then
|
|
||||||
read -rp "git user.name: " git_name
|
|
||||||
read -rp "git user.email [[email protected]]: " git_email
|
|
||||||
git_email="${git_email:-andwatiian@gmail.com}"
|
|
||||||
read -rp "git signing key (GPG key id) [1F20FED0AA05B0DA]: " git_signkey
|
|
||||||
git_signkey="${git_signkey:-1F20FED0AA05B0DA}"
|
|
||||||
{
|
|
||||||
echo "[user]"
|
|
||||||
echo " name = $git_name"
|
|
||||||
echo " email = $git_email"
|
|
||||||
if [[ -n "$git_signkey" ]]; then echo " signingkey = $git_signkey"; fi
|
|
||||||
} > "$HOME/.gitconfig.local"
|
|
||||||
ok "wrote $HOME/.gitconfig.local"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == "1" ]]; then
|
|
||||||
if [[ "$SHELL" != *zsh* ]]; then log "[dry-run] would set default shell to zsh"; fi
|
|
||||||
elif [[ "$SHELL" != *zsh* ]]; then
|
|
||||||
log "setting zsh as default shell"
|
|
||||||
chsh -s "$(command -v zsh)" "$USER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "running tool installer"
|
|
||||||
"$DOTFILES_DIR/install/install.sh" "$@"
|
|
||||||
|
|
||||||
ok "all done — open a new shell (or 'exec zsh') to pick up PATH changes"
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Cached Theme.pak
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Everforest Dark",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "Everforest dark theme matching the desktop palette (bg #2b3339).",
|
||||||
|
"theme": {
|
||||||
|
"colors": {
|
||||||
|
"frame": [35, 42, 46],
|
||||||
|
"frame_inactive": [35, 42, 46],
|
||||||
|
"frame_incognito": [30, 35, 38],
|
||||||
|
"frame_incognito_inactive": [30, 35, 38],
|
||||||
|
"toolbar": [43, 51, 57],
|
||||||
|
"toolbar_text": [211, 198, 170],
|
||||||
|
"toolbar_button_icon": [167, 192, 128],
|
||||||
|
"tab_text": [211, 198, 170],
|
||||||
|
"tab_background_text": [133, 146, 137],
|
||||||
|
"bookmark_text": [211, 198, 170],
|
||||||
|
"button_background": [52, 63, 68],
|
||||||
|
"omnibox_background": [52, 63, 68],
|
||||||
|
"omnibox_text": [211, 198, 170],
|
||||||
|
"background_tab": [35, 42, 46],
|
||||||
|
"background_tab_inactive": [35, 42, 46],
|
||||||
|
"ntp_background": [43, 51, 57],
|
||||||
|
"ntp_text": [211, 198, 170],
|
||||||
|
"ntp_link": [167, 192, 128],
|
||||||
|
"ntp_header": [61, 72, 77]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
export DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
# shellcheck source=install/lib.sh
|
|
||||||
source "$DOTFILES_DIR/install/lib.sh"
|
|
||||||
|
|
||||||
DRY_RUN=0
|
|
||||||
ASSUME_YES=0
|
|
||||||
for a in "$@"; do
|
|
||||||
case "$a" in
|
|
||||||
--dry-run) DRY_RUN=1 ;;
|
|
||||||
-y|--yes) ASSUME_YES=1 ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if ! has_cmd snap; then
|
|
||||||
ok "snapd not installed, nothing to do"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
mapfile -t snaps < <(snap list 2>/dev/null | awk 'NR>1 {print $1}')
|
|
||||||
|
|
||||||
if [[ ${#snaps[@]} -eq 0 ]]; then
|
|
||||||
log "no snaps installed"
|
|
||||||
else
|
|
||||||
log "snaps currently installed: ${snaps[*]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# snapd's own bundled core/bare snaps can't be removed while anything else
|
|
||||||
# depends on them, so they're removed last, in their own pass, below.
|
|
||||||
core_snaps=(snapd core core18 core20 core22 core24 bare)
|
|
||||||
|
|
||||||
# Known default-Ubuntu snaps mapped to their real, official-source
|
|
||||||
# replacement: an existing dotfiles module (reused so it stays one source of
|
|
||||||
# truth), a plain apt package, or "skip" for snap-only infra with no
|
|
||||||
# user-facing equivalent. Anything not listed here that isn't a GNOME/core
|
|
||||||
# runtime snap falls back to Flatpak/Flathub instead of a guessed package.
|
|
||||||
declare -A SNAP_REPLACEMENTS=(
|
|
||||||
[firefox]="module:firefox"
|
|
||||||
[thunderbird]="apt:thunderbird"
|
|
||||||
[snap-store]="apt:gnome-software"
|
|
||||||
[snapd-desktop-integration]="skip"
|
|
||||||
[gtk-common-themes]="skip"
|
|
||||||
)
|
|
||||||
|
|
||||||
_replacement_for() {
|
|
||||||
local snap="$1"
|
|
||||||
if [[ -n "${SNAP_REPLACEMENTS[$snap]:-}" ]]; then
|
|
||||||
echo "${SNAP_REPLACEMENTS[$snap]}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
case "$snap" in
|
|
||||||
gnome-*|core*|bare) echo "skip" ;;
|
|
||||||
*) echo "unmapped" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -a to_remove=() modules_to_run=() apt_pkgs=() unmapped=()
|
|
||||||
for s in "${snaps[@]}"; do
|
|
||||||
case " ${core_snaps[*]} " in *" $s "*) continue ;; esac
|
|
||||||
to_remove+=("$s")
|
|
||||||
|
|
||||||
action=$(_replacement_for "$s")
|
|
||||||
case "$action" in
|
|
||||||
module:*) modules_to_run+=("${action#module:}") ;;
|
|
||||||
apt:*) apt_pkgs+=("${action#apt:}") ;;
|
|
||||||
skip) : ;;
|
|
||||||
unmapped) unmapped+=("$s") ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == "1" ]]; then
|
|
||||||
log "[dry-run] would remove: ${to_remove[*]:-<none>} (plus core/base snaps)"
|
|
||||||
log "[dry-run] would purge snapd and pin /etc/apt/preferences.d/nosnap.pref"
|
|
||||||
if [[ ${#modules_to_run[@]} -gt 0 ]]; then
|
|
||||||
log "[dry-run] would reinstall via existing modules: ${modules_to_run[*]}"
|
|
||||||
fi
|
|
||||||
if [[ ${#apt_pkgs[@]} -gt 0 ]]; then
|
|
||||||
log "[dry-run] would reinstall via apt: ${apt_pkgs[*]}"
|
|
||||||
fi
|
|
||||||
if [[ ${#unmapped[@]} -gt 0 ]]; then
|
|
||||||
log "[dry-run] no apt equivalent for: ${unmapped[*]} — would set up Flatpak/Flathub instead"
|
|
||||||
fi
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$ASSUME_YES" != "1" ]]; then
|
|
||||||
warn "this removes ALL snap packages, purges snapd, and blocks it from ever being reinstalled by apt."
|
|
||||||
read -rp "continue? [y/N] " reply
|
|
||||||
[[ "$reply" =~ ^[Yy]$ ]] || { log "aborted"; exit 1; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
for s in "${to_remove[@]}"; do
|
|
||||||
log "removing snap: $s"
|
|
||||||
sudo snap remove --purge "$s" || warn "failed to remove $s, continuing"
|
|
||||||
done
|
|
||||||
for s in "${core_snaps[@]}"; do
|
|
||||||
if snap list "$s" >/dev/null 2>&1; then
|
|
||||||
log "removing snap: $s"
|
|
||||||
sudo snap remove --purge "$s" || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
log "purging snapd"
|
|
||||||
sudo apt-get purge -y snapd
|
|
||||||
sudo rm -rf /var/cache/snapd/ "$HOME/snap"
|
|
||||||
|
|
||||||
log "pinning snapd out of apt so it can't come back on upgrade"
|
|
||||||
sudo tee /etc/apt/preferences.d/nosnap.pref >/dev/null <<'EOF'
|
|
||||||
Package: snapd
|
|
||||||
Pin: release a=*
|
|
||||||
Pin-Priority: -10
|
|
||||||
EOF
|
|
||||||
|
|
||||||
for m in "${modules_to_run[@]}"; do
|
|
||||||
log "installing $m from its official source (snap replacement)"
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "$DOTFILES_DIR/install/modules/$m.sh"
|
|
||||||
"install_${m//-/_}"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ${#apt_pkgs[@]} -gt 0 ]]; then
|
|
||||||
log "installing apt replacements: ${apt_pkgs[*]}"
|
|
||||||
apt_install "${apt_pkgs[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#unmapped[@]} -gt 0 ]]; then
|
|
||||||
warn "no apt equivalent known for: ${unmapped[*]} — setting up Flatpak/Flathub so you can still get them"
|
|
||||||
ensure_flatpak
|
|
||||||
warn "search/install with: flatpak search <name> && flatpak install flathub <app-id>"
|
|
||||||
for s in "${unmapped[@]}"; do
|
|
||||||
warn " - $s"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
ok "desnapped — snapd is purged and pinned out, replacements installed from apt/official sources"
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
theme = everforest-dark
|
||||||
|
background-opacity = 0.85
|
||||||
|
background-blur = true
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
palette = 0=#475258
|
||||||
|
palette = 1=#e67e80
|
||||||
|
palette = 2=#a7c080
|
||||||
|
palette = 3=#dbbc7f
|
||||||
|
palette = 4=#7fbbb3
|
||||||
|
palette = 5=#d699b6
|
||||||
|
palette = 6=#83c092
|
||||||
|
palette = 7=#d3c6aa
|
||||||
|
palette = 8=#859289
|
||||||
|
palette = 9=#e67e80
|
||||||
|
palette = 10=#a7c080
|
||||||
|
palette = 11=#dbbc7f
|
||||||
|
palette = 12=#7fbbb3
|
||||||
|
palette = 13=#d699b6
|
||||||
|
palette = 14=#83c092
|
||||||
|
palette = 15=#9da9a0
|
||||||
|
background = #2b3339
|
||||||
|
foreground = #d3c6aa
|
||||||
|
cursor-color = #d3c6aa
|
||||||
|
cursor-text = #2b3339
|
||||||
|
selection-background = #543a48
|
||||||
|
selection-foreground = #d3c6aa
|
||||||
+59
-20
@@ -1,24 +1,63 @@
|
|||||||
[core]
|
[user]
|
||||||
editor = vim
|
name = andwati
|
||||||
excludesfile = ~/.gitignore_global
|
email = [email protected]
|
||||||
|
signingkey = 1F20FED0AA05B0DA
|
||||||
[init]
|
|
||||||
defaultBranch = main
|
|
||||||
|
|
||||||
[pull]
|
|
||||||
rebase = false
|
|
||||||
|
|
||||||
[alias]
|
|
||||||
st = status
|
|
||||||
co = checkout
|
|
||||||
br = branch
|
|
||||||
lg = log --oneline --graph --decorate --all
|
|
||||||
|
|
||||||
[commit]
|
[commit]
|
||||||
gpgsign = true
|
gpgsign = true
|
||||||
|
|
||||||
[tag]
|
[tag]
|
||||||
gpgSign = true
|
gpgSign = true
|
||||||
|
[init]
|
||||||
[include]
|
defaultBranch = main
|
||||||
path = ~/.gitconfig.local
|
[color]
|
||||||
|
ui = true
|
||||||
|
[core]
|
||||||
|
filemode = false
|
||||||
|
autocrlf = input
|
||||||
|
[credential "https://android.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://aomedia.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://beto-core.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://boringssl.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://chromium.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://chrome-internal.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://dawn.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://pdfium.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://quiche.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://skia.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://swiftshader.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
[credential "https://webrtc.googlesource.com"]
|
||||||
|
helper =
|
||||||
|
helper = luci
|
||||||
|
useHttpPath = yes
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
*.swp
|
|
||||||
node_modules/
|
|
||||||
.env
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
default-cache-ttl 86400
|
||||||
|
max-cache-ttl 604800
|
||||||
|
pinentry-program /usr/bin/pinentry-qt
|
||||||
Executable
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Bootstraps dotfiles on a new machine: installs oh-my-zsh + the custom
|
||||||
|
# theme/plugins .zshrc expects, then symlinks packages into $HOME via
|
||||||
|
# GNU Stow (each top-level dir is a package mirroring $HOME, e.g.
|
||||||
|
# zsh/.zshrc -> ~/.zshrc). Add a new package by adding a new top-level dir.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
|
||||||
|
|
||||||
|
command -v stow >/dev/null || {
|
||||||
|
echo "GNU Stow is required: sudo pacman -S stow (or your distro's equivalent)" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
clone_if_missing() {
|
||||||
|
local url="$1" dst="$2"
|
||||||
|
[ -d "$dst" ] || git clone --depth=1 "$url" "$dst"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d "$HOME/.oh-my-zsh" ]; then
|
||||||
|
echo "Installing oh-my-zsh..."
|
||||||
|
RUNZSH=no CHSH=no KEEP_ZSHRC=yes sh -c \
|
||||||
|
"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
clone_if_missing https://github.com/romkatv/powerlevel10k.git "$ZSH_CUSTOM/themes/powerlevel10k"
|
||||||
|
clone_if_missing https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
|
||||||
|
clone_if_missing https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
|
||||||
|
clone_if_missing https://github.com/zsh-users/zsh-history-substring-search "$ZSH_CUSTOM/plugins/zsh-history-substring-search"
|
||||||
|
clone_if_missing https://github.com/zsh-users/zsh-completions "$ZSH_CUSTOM/plugins/zsh-completions"
|
||||||
|
clone_if_missing https://github.com/MichaelAquilina/zsh-you-should-use "$ZSH_CUSTOM/plugins/you-should-use"
|
||||||
|
|
||||||
|
# Stow refuses to link over a real (non-symlink) file, so move any
|
||||||
|
# conflicting pre-existing file aside first (e.g. the .zshrc oh-my-zsh's
|
||||||
|
# own installer just wrote above).
|
||||||
|
stow_package() {
|
||||||
|
local pkg="$1" f rel target
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
rel="${f#"$DOTFILES_DIR/$pkg/"}"
|
||||||
|
target="$HOME/$rel"
|
||||||
|
if [ -L "$target" ]; then
|
||||||
|
rm "$target"
|
||||||
|
elif [ -e "$target" ]; then
|
||||||
|
mkdir -p "$(dirname "$target")"
|
||||||
|
mv "$target" "$target.bak.$(date +%s)"
|
||||||
|
echo "Backed up existing $target"
|
||||||
|
fi
|
||||||
|
done < <(find "$DOTFILES_DIR/$pkg" -type f -print0)
|
||||||
|
stow --dir="$DOTFILES_DIR" --target="$HOME" --restow "$pkg"
|
||||||
|
echo "Stowed $pkg"
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$HOME/.gnupg" && chmod 700 "$HOME/.gnupg"
|
||||||
|
|
||||||
|
stow_package zsh
|
||||||
|
stow_package gnupg
|
||||||
|
stow_package git
|
||||||
|
stow_package ghostty
|
||||||
|
stow_package kde
|
||||||
|
stow_package nvim
|
||||||
|
stow_package vscode
|
||||||
|
gpgconf --kill gpg-agent 2>/dev/null || true
|
||||||
|
|
||||||
|
cat <<'EOF'
|
||||||
|
|
||||||
|
Done. This does NOT install (grab these separately if missing):
|
||||||
|
- nvm, pyenv, bun, pnpm, deno, rustup, docker, fzf, zoxide
|
||||||
|
- ghostty, neovim (+ fd, lazygit, tree-sitter-cli, wl-clipboard), VS Code
|
||||||
|
- Colloid Everforest GTK/icon themes (AUR: colloid-everforest-gtk-theme-git,
|
||||||
|
colloid-everforest-theme-git)
|
||||||
|
- a Nerd Font (JetBrains Mono Nerd Font) — set it as your terminal's font
|
||||||
|
|
||||||
|
Start a new shell to pick everything up: exec zsh
|
||||||
|
EOF
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
MODULES_DIR="$SCRIPT_DIR/modules"
|
|
||||||
export DOTFILES_DIR="${DOTFILES_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
||||||
# shellcheck source=lib.sh
|
|
||||||
source "$SCRIPT_DIR/lib.sh"
|
|
||||||
trap 'rm -f "$(_apt_marker)"' EXIT
|
|
||||||
|
|
||||||
ALL_MODULES=(
|
|
||||||
00-base mirrors perms cli-tools
|
|
||||||
nvm node pnpm deno bun
|
|
||||||
pyenv pipx pipenv poetry uv
|
|
||||||
vscode cursor ghcli docker go rust zig
|
|
||||||
chrome discord slack firefox postman jetbrains-toolbox mpv spotify telegram signal protonvpn onedrive
|
|
||||||
gnome wakatime
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -A MODULE_DESC=(
|
|
||||||
[00-base]="core apt packages (curl, git, build-essential, jq, stow, ...)"
|
|
||||||
[mirrors]="benchmark + switch apt to the fastest fresh Ubuntu mirror"
|
|
||||||
[perms]="fix ~/.ssh and ~/.gnupg permissions"
|
|
||||||
[cli-tools]="eza, ripgrep + shell aliases"
|
|
||||||
[nvm]="Node Version Manager"
|
|
||||||
[node]="Node.js LTS (via nvm)"
|
|
||||||
[pnpm]="pnpm package manager"
|
|
||||||
[deno]="Deno runtime"
|
|
||||||
[bun]="Bun runtime"
|
|
||||||
[pyenv]="Python version manager"
|
|
||||||
[pipx]="pipx (isolated python CLI installs)"
|
|
||||||
[pipenv]="pipenv (via pipx)"
|
|
||||||
[poetry]="Poetry python packaging"
|
|
||||||
[uv]="uv python package/venv manager"
|
|
||||||
[vscode]="VS Code + your extensions/settings (mirrors to Cursor too)"
|
|
||||||
[cursor]="Cursor editor (official AppImage)"
|
|
||||||
[ghcli]="GitHub CLI (gh)"
|
|
||||||
[docker]="Docker Engine + compose plugin"
|
|
||||||
[go]="Go toolchain"
|
|
||||||
[rust]="Rust (rustup)"
|
|
||||||
[zig]="Zig + zls (language server)"
|
|
||||||
[chrome]="Google Chrome"
|
|
||||||
[discord]="Discord"
|
|
||||||
[slack]="Slack (Flathub)"
|
|
||||||
[firefox]="Firefox (Mozilla apt repo, not snap)"
|
|
||||||
[postman]="Postman"
|
|
||||||
[jetbrains-toolbox]="JetBrains Toolbox"
|
|
||||||
[mpv]="mpv media player"
|
|
||||||
[spotify]="Spotify"
|
|
||||||
[telegram]="Telegram Desktop"
|
|
||||||
[signal]="Signal Desktop"
|
|
||||||
[protonvpn]="ProtonVPN (official GNOME app)"
|
|
||||||
[onedrive]="OneDrive client (abraunegg, official OBS repo)"
|
|
||||||
[gnome]="GNOME Tweaks, Extension Manager, AppIndicator support"
|
|
||||||
[wakatime]="Wakatime API key setup"
|
|
||||||
)
|
|
||||||
|
|
||||||
SUMMARY_OK=()
|
|
||||||
SUMMARY_FAILED=()
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage: $(basename "$0") [module ...]
|
|
||||||
$(basename "$0") --list
|
|
||||||
$(basename "$0") --except mod1,mod2
|
|
||||||
$(basename "$0") --dry-run [module ...]
|
|
||||||
$(basename "$0") --all | --no-tui
|
|
||||||
|
|
||||||
With no arguments on an interactive terminal, shows a checklist (whiptail)
|
|
||||||
to pick which modules to install. Pass --all/--no-tui to skip the checklist
|
|
||||||
and install everything, or name modules explicitly.
|
|
||||||
|
|
||||||
A module failing does not abort the run: its own changes are rolled back,
|
|
||||||
the failure is recorded, and the next module runs. Exit status is nonzero
|
|
||||||
if anything failed. Every module is idempotent — safe to re-run.
|
|
||||||
|
|
||||||
Modules:
|
|
||||||
$(printf ' %-20s %s\n' $(for m in "${ALL_MODULES[@]}"; do printf '%s\n%s\n' "$m" "${MODULE_DESC[$m]:-}"; done))
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
list_modules() { printf '%s\n' "${ALL_MODULES[@]}"; }
|
|
||||||
|
|
||||||
ensure_whiptail() {
|
|
||||||
if has_cmd whiptail; then return 0; fi
|
|
||||||
log "installing whiptail for the selection menu"
|
|
||||||
apt_update_once
|
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y whiptail
|
|
||||||
}
|
|
||||||
|
|
||||||
tui_select_modules() {
|
|
||||||
if ! ensure_whiptail || ! has_cmd whiptail; then
|
|
||||||
warn "whiptail unavailable, falling back to a plain prompt"
|
|
||||||
plain_select_modules
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local -a items=()
|
|
||||||
local m
|
|
||||||
for m in "${ALL_MODULES[@]}"; do
|
|
||||||
items+=("$m" "${MODULE_DESC[$m]:-}" "ON")
|
|
||||||
done
|
|
||||||
|
|
||||||
local choices
|
|
||||||
choices=$(whiptail --title "dotfiles installer" --checklist \
|
|
||||||
"Space to toggle, Enter to confirm, Esc to cancel" 24 78 16 \
|
|
||||||
"${items[@]}" 3>&1 1>&2 2>&3) || { warn "selection cancelled"; return 1; }
|
|
||||||
|
|
||||||
eval "local -a selected=($choices)"
|
|
||||||
printf '%s\n' "${selected[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
plain_select_modules() {
|
|
||||||
echo "Select modules (space-separated numbers, or 'all'):" >&2
|
|
||||||
local i=1 m
|
|
||||||
for m in "${ALL_MODULES[@]}"; do
|
|
||||||
printf ' %2d) %-20s %s\n' "$i" "$m" "${MODULE_DESC[$m]:-}" >&2
|
|
||||||
i=$((i + 1))
|
|
||||||
done
|
|
||||||
read -rp "> " reply
|
|
||||||
if [[ "$reply" == "all" || -z "$reply" ]]; then
|
|
||||||
printf '%s\n' "${ALL_MODULES[@]}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
local -a out=()
|
|
||||||
local n
|
|
||||||
for n in $reply; do
|
|
||||||
[[ "$n" =~ ^[0-9]+$ ]] || continue
|
|
||||||
out+=("${ALL_MODULES[$((n - 1))]}")
|
|
||||||
done
|
|
||||||
printf '%s\n' "${out[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_module() {
|
|
||||||
local slug="$1"
|
|
||||||
local file="$MODULES_DIR/${slug}.sh"
|
|
||||||
local fn="install_${slug//-/_}"
|
|
||||||
|
|
||||||
if [[ ! -f "$file" ]]; then
|
|
||||||
err "unknown module: $slug"
|
|
||||||
SUMMARY_FAILED+=("$slug")
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${DRY_RUN:-0}" == "1" ]]; then
|
|
||||||
log "[dry-run] would install: $slug — ${MODULE_DESC[$slug]:-}"
|
|
||||||
SUMMARY_OK+=("$slug (dry-run)")
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "installing $slug"
|
|
||||||
|
|
||||||
# Run in a subshell so a failing command genuinely aborts the module
|
|
||||||
# (errexit) instead of limping on to the next line. Note: `if ( ... );
|
|
||||||
# then` or `( ... ) || ...` would silently defeat -e here — bash suspends
|
|
||||||
# errexit for the *whole* tested command, including inside a nested
|
|
||||||
# subshell, even if that subshell re-sets -e itself. The subshell must run
|
|
||||||
# as a genuinely unconditional statement, under a `set +e` bracket so its
|
|
||||||
# own nonzero exit doesn't also kill the outer script, with $? captured
|
|
||||||
# right after and -e restored immediately.
|
|
||||||
set +e
|
|
||||||
(
|
|
||||||
set -Eeuo pipefail
|
|
||||||
trap 'rollback_run' ERR
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "$file"
|
|
||||||
rollback_reset
|
|
||||||
"$fn"
|
|
||||||
)
|
|
||||||
local status=$?
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ $status -eq 0 ]]; then
|
|
||||||
ok "$slug done"
|
|
||||||
SUMMARY_OK+=("$slug")
|
|
||||||
else
|
|
||||||
err "$slug failed — its changes were rolled back"
|
|
||||||
SUMMARY_FAILED+=("$slug")
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
print_summary() {
|
|
||||||
echo
|
|
||||||
log "summary"
|
|
||||||
if [[ ${#SUMMARY_OK[@]} -gt 0 ]]; then printf ' ok: %s\n' "${SUMMARY_OK[*]}"; fi
|
|
||||||
if [[ ${#SUMMARY_FAILED[@]} -gt 0 ]]; then printf ' failed: %s\n' "${SUMMARY_FAILED[*]}"; fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local -a explicit=() except=()
|
|
||||||
local dry_run=0 force_all=0
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-h|--help) usage; exit 0 ;;
|
|
||||||
--list) list_modules; exit 0 ;;
|
|
||||||
--dry-run) dry_run=1; shift ;;
|
|
||||||
--all|--no-tui) force_all=1; shift ;;
|
|
||||||
--except)
|
|
||||||
IFS=',' read -ra except <<< "${2:-}"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
err "unknown flag: $1"; usage; exit 1 ;;
|
|
||||||
*) explicit+=("$1"); shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
export DRY_RUN=$dry_run
|
|
||||||
|
|
||||||
local -a targets=()
|
|
||||||
local m s skipped
|
|
||||||
if [[ ${#except[@]} -gt 0 ]]; then
|
|
||||||
for m in "${ALL_MODULES[@]}"; do
|
|
||||||
skipped=0
|
|
||||||
for s in "${except[@]}"; do
|
|
||||||
if [[ "$m" == "$s" ]]; then skipped=1; fi
|
|
||||||
done
|
|
||||||
[[ $skipped -eq 1 ]] || targets+=("$m")
|
|
||||||
done
|
|
||||||
elif [[ ${#explicit[@]} -gt 0 ]]; then
|
|
||||||
targets=("${explicit[@]}")
|
|
||||||
elif [[ $force_all -eq 0 && -t 0 && -t 1 ]]; then
|
|
||||||
local tui_out
|
|
||||||
if ! tui_out=$(tui_select_modules); then
|
|
||||||
err "no modules selected"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
mapfile -t targets <<< "$tui_out"
|
|
||||||
else
|
|
||||||
targets=("${ALL_MODULES[@]}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#targets[@]} -eq 0 ]]; then
|
|
||||||
warn "nothing selected"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local -a ordered=(00-base)
|
|
||||||
for m in "${targets[@]}"; do
|
|
||||||
[[ "$m" == "00-base" ]] || ordered+=("$m")
|
|
||||||
done
|
|
||||||
|
|
||||||
for m in "${ordered[@]}"; do
|
|
||||||
run_module "$m"
|
|
||||||
done
|
|
||||||
|
|
||||||
print_summary
|
|
||||||
[[ ${#SUMMARY_FAILED[@]} -eq 0 ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
-111
@@ -1,111 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Shared helpers sourced by install.sh, bootstrap.sh, desnap.sh, and every
|
|
||||||
# module in install/modules/.
|
|
||||||
|
|
||||||
C_RESET=$'\033[0m'; C_BLUE=$'\033[1;34m'; C_GREEN=$'\033[1;32m'; C_YELLOW=$'\033[1;33m'; C_RED=$'\033[1;31m'
|
|
||||||
|
|
||||||
log() { printf '%s==>%s %s\n' "$C_BLUE" "$C_RESET" "$*"; }
|
|
||||||
ok() { printf '%s ok%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
|
|
||||||
warn() { printf '%s warn%s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; }
|
|
||||||
err() { printf '%s !!%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; }
|
|
||||||
|
|
||||||
has_cmd() { command -v "$1" >/dev/null 2>&1; }
|
|
||||||
|
|
||||||
deb_arch() { dpkg --print-architecture; }
|
|
||||||
ubuntu_codename() { . /etc/os-release; echo "$VERSION_CODENAME"; }
|
|
||||||
|
|
||||||
# Each module now runs in its own subshell (see run_module in install.sh),
|
|
||||||
# so a plain shell variable can't track "already updated" across modules —
|
|
||||||
# it'd reset every time. Use a marker file scoped to this whole run ($$ is
|
|
||||||
# stable across subshells) instead; apt_invalidate removes it when a repo
|
|
||||||
# changes so the next apt_install re-syncs.
|
|
||||||
_apt_marker() { echo "/tmp/.dotfiles-apt-updated.$$"; }
|
|
||||||
|
|
||||||
apt_update_once() {
|
|
||||||
local marker
|
|
||||||
marker=$(_apt_marker)
|
|
||||||
if [[ ! -f "$marker" ]]; then
|
|
||||||
sudo apt-get update -qq
|
|
||||||
touch "$marker"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
apt_invalidate() { rm -f "$(_apt_marker)"; }
|
|
||||||
|
|
||||||
# apt_install <pkg...> — installs packages and, for any package that wasn't
|
|
||||||
# already present, registers a rollback that removes it again. Packages the
|
|
||||||
# user already had are left alone on rollback.
|
|
||||||
apt_install() {
|
|
||||||
apt_update_once
|
|
||||||
local -a new_pkgs=()
|
|
||||||
local p
|
|
||||||
for p in "$@"; do
|
|
||||||
dpkg -s "$p" >/dev/null 2>&1 || new_pkgs+=("$p")
|
|
||||||
done
|
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"
|
|
||||||
if [[ ${#new_pkgs[@]} -gt 0 ]]; then
|
|
||||||
rollback_push "sudo DEBIAN_FRONTEND=noninteractive apt-get remove -y ${new_pkgs[*]}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ensure_flatpak — installs flatpak (+ GNOME Software integration when
|
|
||||||
# running GNOME) and adds the Flathub remote system-wide. Shared by any
|
|
||||||
# module that prefers a verified Flathub app id over a vendor's own apt repo.
|
|
||||||
ensure_flatpak() {
|
|
||||||
apt_install flatpak
|
|
||||||
if has_cmd gnome-shell; then
|
|
||||||
apt_install gnome-software-plugin-flatpak
|
|
||||||
fi
|
|
||||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
|
||||||
}
|
|
||||||
|
|
||||||
# apt_add_repo <list-name> <keyring-path> <key-url> <repo-line>
|
|
||||||
# Registers a signed apt repo the way every vendor's official install docs do
|
|
||||||
# it (dearmor the key into /etc/apt/keyrings or similar, write a .list file),
|
|
||||||
# forces the next apt_install to refresh package lists, and registers a
|
|
||||||
# rollback that removes the repo + keyring again.
|
|
||||||
apt_add_repo() {
|
|
||||||
local list_name="$1" keyring="$2" key_url="$3" repo_line="$4"
|
|
||||||
sudo install -d -m 0755 "$(dirname "$keyring")"
|
|
||||||
curl -fsSL "$key_url" | sudo gpg --dearmor --yes -o "$keyring"
|
|
||||||
sudo chmod a+r "$keyring"
|
|
||||||
echo "$repo_line" | sudo tee "/etc/apt/sources.list.d/${list_name}.list" >/dev/null
|
|
||||||
rollback_push "sudo rm -f '/etc/apt/sources.list.d/${list_name}.list' '$keyring'"
|
|
||||||
apt_invalidate
|
|
||||||
}
|
|
||||||
|
|
||||||
add_line_once() {
|
|
||||||
local file="$1" line="$2"
|
|
||||||
mkdir -p "$(dirname "$file")"
|
|
||||||
touch "$file"
|
|
||||||
grep -qxF "$line" "$file" || printf '%s\n' "$line" >> "$file"
|
|
||||||
}
|
|
||||||
|
|
||||||
# profile_add <line> — idempotently append a PATH/init line to ~/.zshrc so
|
|
||||||
# re-running a module never duplicates it. Not rollback-tracked: a stray
|
|
||||||
# export pointing at a directory that got rolled back is inert, not broken.
|
|
||||||
profile_add() { add_line_once "$HOME/.zshrc" "$1"; }
|
|
||||||
|
|
||||||
# --- transactional rollback -------------------------------------------------
|
|
||||||
#
|
|
||||||
# Each module gets a fresh rollback stack (see run_module in install.sh).
|
|
||||||
# Anything a module does that should be undone if a *later* command in the
|
|
||||||
# same module fails should call rollback_push with a shell command string.
|
|
||||||
# On success the stack is simply discarded; on failure it's run in reverse.
|
|
||||||
|
|
||||||
ROLLBACK_ACTIONS=()
|
|
||||||
|
|
||||||
rollback_reset() { ROLLBACK_ACTIONS=(); }
|
|
||||||
rollback_push() { ROLLBACK_ACTIONS+=("$1"); }
|
|
||||||
|
|
||||||
rollback_run() {
|
|
||||||
local i
|
|
||||||
for (( i=${#ROLLBACK_ACTIONS[@]}-1; i>=0; i-- )); do
|
|
||||||
warn "rollback: ${ROLLBACK_ACTIONS[$i]}"
|
|
||||||
eval "${ROLLBACK_ACTIONS[$i]}" || true
|
|
||||||
done
|
|
||||||
ROLLBACK_ACTIONS=()
|
|
||||||
}
|
|
||||||
|
|
||||||
track_new_dir() { rollback_push "rm -rf '$1'"; }
|
|
||||||
track_new_sudo_dir() { rollback_push "sudo rm -rf '$1'"; }
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
install_00_base() {
|
|
||||||
if ! grep -qi ubuntu /etc/os-release 2>/dev/null; then
|
|
||||||
warn "this installer targets Ubuntu; continuing anyway"
|
|
||||||
fi
|
|
||||||
apt_install \
|
|
||||||
curl wget git ca-certificates gnupg lsb-release jq \
|
|
||||||
software-properties-common apt-transport-https \
|
|
||||||
build-essential unzip xz-utils stow
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_bun() {
|
|
||||||
if has_cmd bun; then ok "bun already installed"; return; fi
|
|
||||||
track_new_dir "$HOME/.bun"
|
|
||||||
NO_MODIFY_PATH=1 bash -c "$(curl -fsSL https://bun.sh/install)"
|
|
||||||
profile_add 'export BUN_INSTALL="$HOME/.bun"'
|
|
||||||
profile_add 'export PATH="$BUN_INSTALL/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
install_chrome() {
|
|
||||||
if has_cmd google-chrome-stable; then
|
|
||||||
ok "chrome already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local deb
|
|
||||||
deb=$(mktemp --suffix=.deb)
|
|
||||||
curl -fsSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o "$deb"
|
|
||||||
apt_update_once
|
|
||||||
sudo apt-get install -y "$deb"
|
|
||||||
rm -f "$deb"
|
|
||||||
rollback_push "sudo apt-get remove -y google-chrome-stable"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
install_cli_tools() {
|
|
||||||
apt_install eza ripgrep
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
install_cursor() {
|
|
||||||
if [[ -x /opt/cursor/cursor.AppImage ]]; then
|
|
||||||
ok "cursor already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_install libfuse2
|
|
||||||
|
|
||||||
local appimage
|
|
||||||
appimage=$(mktemp --suffix=.AppImage)
|
|
||||||
curl -fsSL https://downloader.cursor.sh/linux/appImage/x64 -o "$appimage"
|
|
||||||
chmod +x "$appimage"
|
|
||||||
|
|
||||||
track_new_sudo_dir /opt/cursor
|
|
||||||
sudo mkdir -p /opt/cursor
|
|
||||||
sudo mv "$appimage" /opt/cursor/cursor.AppImage
|
|
||||||
sudo ln -sf /opt/cursor/cursor.AppImage /usr/local/bin/cursor
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/cursor"
|
|
||||||
|
|
||||||
sudo tee /usr/share/applications/cursor.desktop >/dev/null <<'EOF'
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=Cursor
|
|
||||||
Exec=/opt/cursor/cursor.AppImage --no-sandbox %U
|
|
||||||
Icon=cursor
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Development;
|
|
||||||
EOF
|
|
||||||
rollback_push "sudo rm -f /usr/share/applications/cursor.desktop"
|
|
||||||
|
|
||||||
# Reuses vscode.sh's mirror step to symlink settings + install the same
|
|
||||||
# extensions into the newly-installed Cursor.
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "${DOTFILES_DIR:?}/install/modules/vscode.sh"
|
|
||||||
_vscode_mirror_cursor
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_deno() {
|
|
||||||
if has_cmd deno; then ok "deno already installed"; return; fi
|
|
||||||
track_new_dir "$HOME/.deno"
|
|
||||||
curl -fsSL https://deno.land/install.sh | sh
|
|
||||||
profile_add 'export DENO_INSTALL="$HOME/.deno"'
|
|
||||||
profile_add 'export PATH="$DENO_INSTALL/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
install_discord() {
|
|
||||||
if has_cmd discord; then ok "discord already installed"; return; fi
|
|
||||||
local deb
|
|
||||||
deb=$(mktemp --suffix=.deb)
|
|
||||||
curl -fsSL 'https://discord.com/api/download?platform=linux&format=deb' -o "$deb"
|
|
||||||
apt_update_once
|
|
||||||
sudo apt-get install -y "$deb"
|
|
||||||
rm -f "$deb"
|
|
||||||
rollback_push "sudo apt-get remove -y discord"
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
install_docker() {
|
|
||||||
if has_cmd docker; then ok "docker already installed"; return; fi
|
|
||||||
apt_install ca-certificates curl
|
|
||||||
|
|
||||||
local codename
|
|
||||||
codename=$(ubuntu_codename)
|
|
||||||
if ! curl -fsSL -o /dev/null "https://download.docker.com/linux/ubuntu/dists/${codename}/Release"; then
|
|
||||||
warn "Docker has no repo for '${codename}' yet, falling back to 'noble' (24.04)"
|
|
||||||
codename=noble
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_add_repo docker /etc/apt/keyrings/docker.asc \
|
|
||||||
https://download.docker.com/linux/ubuntu/gpg \
|
|
||||||
"deb [arch=$(deb_arch) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${codename} stable"
|
|
||||||
apt_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
||||||
|
|
||||||
sudo usermod -aG docker "$USER"
|
|
||||||
rollback_push "sudo gpasswd -d '$USER' docker"
|
|
||||||
warn "log out/in (or run 'newgrp docker') for docker group membership to take effect"
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
install_firefox() {
|
|
||||||
if [[ -f /etc/apt/preferences.d/mozilla ]]; then
|
|
||||||
ok "firefox (deb) already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "removing snap firefox / transitional apt stub in favor of Mozilla's official apt repo"
|
|
||||||
sudo apt-get remove -y firefox 2>/dev/null || true
|
|
||||||
sudo snap remove firefox 2>/dev/null || true
|
|
||||||
|
|
||||||
apt_add_repo mozilla /etc/apt/keyrings/packages.mozilla.org.asc \
|
|
||||||
https://packages.mozilla.org/apt/repo-signing-key.gpg \
|
|
||||||
"deb [signed-by=/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main"
|
|
||||||
|
|
||||||
printf 'Package: *\nPin: origin packages.mozilla.org\nPin-Priority: 1000\n' \
|
|
||||||
| sudo tee /etc/apt/preferences.d/mozilla >/dev/null
|
|
||||||
rollback_push "sudo rm -f /etc/apt/preferences.d/mozilla"
|
|
||||||
|
|
||||||
apt_install firefox
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_ghcli() {
|
|
||||||
if has_cmd gh; then ok "gh already installed"; return; fi
|
|
||||||
apt_add_repo github-cli /etc/apt/keyrings/githubcli-archive-keyring.gpg \
|
|
||||||
https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
||||||
"deb [arch=$(deb_arch) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main"
|
|
||||||
apt_install gh
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
install_gnome() {
|
|
||||||
if ! has_cmd gnome-shell; then
|
|
||||||
warn "gnome-shell not found; skipping (not running GNOME?)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_install gnome-tweaks gnome-shell-extension-manager dconf-editor \
|
|
||||||
gnome-shell-extension-appindicator
|
|
||||||
|
|
||||||
if has_cmd gnome-extensions; then
|
|
||||||
gnome-extensions enable [email protected] 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
ok "log out/in for the AppIndicator extension to take full effect (tray icons for Discord/Slack/Signal etc.)"
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
install_go() {
|
|
||||||
local latest
|
|
||||||
latest=$(curl -fsSL 'https://go.dev/VERSION?m=text' | head -n1)
|
|
||||||
|
|
||||||
if has_cmd go && go version | grep -q "$latest"; then
|
|
||||||
ok "go already at $latest"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local arch
|
|
||||||
case "$(uname -m)" in
|
|
||||||
x86_64) arch=amd64 ;;
|
|
||||||
aarch64) arch=arm64 ;;
|
|
||||||
*) err "unsupported arch $(uname -m)"; return 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
local tarball="/tmp/${latest}.linux-${arch}.tar.gz"
|
|
||||||
curl -fsSL "https://go.dev/dl/${latest}.linux-${arch}.tar.gz" -o "$tarball"
|
|
||||||
|
|
||||||
local backup=""
|
|
||||||
if [[ -d /usr/local/go ]]; then
|
|
||||||
backup="/usr/local/go.bak.$$"
|
|
||||||
sudo mv /usr/local/go "$backup"
|
|
||||||
rollback_push "sudo rm -rf /usr/local/go; sudo mv '$backup' /usr/local/go"
|
|
||||||
else
|
|
||||||
rollback_push "sudo rm -rf /usr/local/go"
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo tar -C /usr/local -xzf "$tarball"
|
|
||||||
rm -f "$tarball"
|
|
||||||
if [[ -n "$backup" ]]; then sudo rm -rf "$backup"; fi
|
|
||||||
|
|
||||||
profile_add 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
install_jetbrains_toolbox() {
|
|
||||||
if [[ -x /opt/jetbrains-toolbox/jetbrains-toolbox ]]; then
|
|
||||||
ok "jetbrains toolbox already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local url tarball extract_dir
|
|
||||||
url=$(curl -fsSL 'https://data.services.jetbrains.com/products/releases?code=TBA&latest=true&type=release' \
|
|
||||||
| jq -r '.TBA[0].downloads.linux.link')
|
|
||||||
|
|
||||||
tarball=$(mktemp --suffix=.tar.gz)
|
|
||||||
curl -fsSL "$url" -o "$tarball"
|
|
||||||
extract_dir=$(mktemp -d)
|
|
||||||
tar -xzf "$tarball" -C "$extract_dir" --strip-components=1
|
|
||||||
rm -f "$tarball"
|
|
||||||
|
|
||||||
sudo rm -rf /opt/jetbrains-toolbox
|
|
||||||
track_new_sudo_dir /opt/jetbrains-toolbox
|
|
||||||
sudo mv "$extract_dir" /opt/jetbrains-toolbox
|
|
||||||
sudo ln -sf /opt/jetbrains-toolbox/jetbrains-toolbox /usr/local/bin/jetbrains-toolbox
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/jetbrains-toolbox"
|
|
||||||
|
|
||||||
ok "run 'jetbrains-toolbox' once to finish setup; it installs its own desktop entry"
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
install_mirrors() {
|
|
||||||
local codename
|
|
||||||
codename=$(ubuntu_codename)
|
|
||||||
|
|
||||||
local candidates
|
|
||||||
candidates=$(curl -fsSL --max-time 5 https://mirrors.ubuntu.com/mirrors.txt) || {
|
|
||||||
err "could not fetch the official Ubuntu mirror list"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
log "benchmarking mirrors for speed + freshness (this takes a few seconds)"
|
|
||||||
|
|
||||||
local best_url="" best_time="" url resp t last_modified age_hours checked=0
|
|
||||||
while IFS= read -r url; do
|
|
||||||
if [[ -z "$url" || "$url" == \#* ]]; then continue; fi
|
|
||||||
if [[ $checked -ge 12 ]]; then break; fi
|
|
||||||
checked=$((checked + 1))
|
|
||||||
|
|
||||||
resp=$(curl -o /dev/null -sD - --max-time 3 -w '\n%{time_total}' "${url}dists/${codename}/Release" 2>/dev/null) || continue
|
|
||||||
if [[ -z "$resp" ]]; then continue; fi
|
|
||||||
|
|
||||||
t=$(tail -n1 <<< "$resp")
|
|
||||||
if [[ -z "$t" ]]; then continue; fi
|
|
||||||
|
|
||||||
last_modified=$(grep -i '^Last-Modified:' <<< "$resp" | head -n1 | cut -d' ' -f2- | tr -d '\r')
|
|
||||||
if [[ -n "$last_modified" ]]; then
|
|
||||||
age_hours=$(( ($(date +%s) - $(date -d "$last_modified" +%s 2>/dev/null || echo 0)) / 3600 ))
|
|
||||||
if [[ $age_hours -gt 72 ]]; then continue; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$best_time" ]] || awk -v a="$t" -v b="$best_time" 'BEGIN{exit !(a<b)}'; then
|
|
||||||
best_time="$t"
|
|
||||||
best_url="$url"
|
|
||||||
fi
|
|
||||||
done <<< "$candidates"
|
|
||||||
|
|
||||||
if [[ -z "$best_url" ]]; then
|
|
||||||
warn "no mirror passed the speed/freshness check, leaving apt sources untouched"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
ok "fastest fresh mirror: $best_url (${best_time}s)"
|
|
||||||
_mirrors_apply "$best_url"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Rewrites whichever apt sources format is in use to point at the chosen
|
|
||||||
# mirror. Ubuntu 24.04+ (and 26.04) default to the deb822
|
|
||||||
# /etc/apt/sources.list.d/ubuntu.sources file; older installs still use the
|
|
||||||
# one-line-per-entry /etc/apt/sources.list. security.ubuntu.com is left
|
|
||||||
# alone on purpose — security updates stay on Canonical's own CDN.
|
|
||||||
_mirrors_apply() {
|
|
||||||
local mirror="${1%/}"
|
|
||||||
local deb822="/etc/apt/sources.list.d/ubuntu.sources"
|
|
||||||
local legacy="/etc/apt/sources.list"
|
|
||||||
local target="" backup=""
|
|
||||||
|
|
||||||
if [[ -f "$deb822" ]]; then
|
|
||||||
target="$deb822"
|
|
||||||
elif [[ -f "$legacy" ]] && grep -q archive.ubuntu.com "$legacy"; then
|
|
||||||
target="$legacy"
|
|
||||||
else
|
|
||||||
warn "no recognized apt sources file found, skipping"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
backup="${target}.bak.$$"
|
|
||||||
sudo cp "$target" "$backup"
|
|
||||||
rollback_push "sudo mv '$backup' '$target'; apt_invalidate"
|
|
||||||
sudo sed -i -E "s#https?://[a-zA-Z0-9.-]*archive\.ubuntu\.com/ubuntu#${mirror}#g" "$target"
|
|
||||||
|
|
||||||
apt_invalidate
|
|
||||||
if ! apt_update_once; then
|
|
||||||
err "apt update failed against $mirror"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo rm -f "$backup"
|
|
||||||
ok "apt now points at $mirror"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
install_mpv() {
|
|
||||||
apt_install mpv
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
install_node() {
|
|
||||||
export NVM_DIR="$HOME/.nvm"
|
|
||||||
if [[ ! -s "$NVM_DIR/nvm.sh" ]]; then
|
|
||||||
err "nvm not found; run the nvm module first"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
# shellcheck disable=SC1091
|
|
||||||
\. "$NVM_DIR/nvm.sh"
|
|
||||||
|
|
||||||
nvm install --lts
|
|
||||||
nvm alias default 'lts/*'
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
install_nvm() {
|
|
||||||
export NVM_DIR="$HOME/.nvm"
|
|
||||||
|
|
||||||
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
|
|
||||||
ok "nvm already installed"
|
|
||||||
else
|
|
||||||
local version installer
|
|
||||||
version=$(curl -fsSL https://api.github.com/repos/nvm-sh/nvm/releases/latest | jq -r .tag_name)
|
|
||||||
installer=$(mktemp)
|
|
||||||
curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${version}/install.sh" -o "$installer"
|
|
||||||
track_new_dir "$NVM_DIR"
|
|
||||||
# PROFILE=/dev/null: we manage PATH/init lines ourselves via profile_add below.
|
|
||||||
PROFILE=/dev/null bash "$installer"
|
|
||||||
rm -f "$installer"
|
|
||||||
fi
|
|
||||||
|
|
||||||
profile_add 'export NVM_DIR="$HOME/.nvm"'
|
|
||||||
profile_add '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"'
|
|
||||||
profile_add '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"'
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
install_onedrive() {
|
|
||||||
if has_cmd onedrive; then
|
|
||||||
ok "onedrive already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local version repo_base
|
|
||||||
version=$(. /etc/os-release; echo "$VERSION_ID")
|
|
||||||
repo_base="https://download.opensuse.org/repositories/home:/npreining:/debian-ubuntu-onedrive/xUbuntu_${version}"
|
|
||||||
|
|
||||||
if ! curl -fsSL -o /dev/null "${repo_base}/Release"; then
|
|
||||||
warn "onedrive's OBS repo has no build for Ubuntu ${version} yet, falling back to 24.04"
|
|
||||||
version="24.04"
|
|
||||||
repo_base="https://download.opensuse.org/repositories/home:/npreining:/debian-ubuntu-onedrive/xUbuntu_${version}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_add_repo onedrive /etc/apt/keyrings/onedrive.gpg \
|
|
||||||
"${repo_base}/Release.key" \
|
|
||||||
"deb ${repo_base}/ ./"
|
|
||||||
apt_install onedrive
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
install_perms() {
|
|
||||||
if [[ -d "$HOME/.ssh" ]]; then
|
|
||||||
chmod 700 "$HOME/.ssh"
|
|
||||||
find "$HOME/.ssh" -maxdepth 1 -type f ! -name '*.pub' -exec chmod 600 {} +
|
|
||||||
find "$HOME/.ssh" -maxdepth 1 -type f -name '*.pub' -exec chmod 644 {} +
|
|
||||||
if [[ -f "$HOME/.ssh/config" ]]; then chmod 600 "$HOME/.ssh/config"; fi
|
|
||||||
if [[ -f "$HOME/.ssh/authorized_keys" ]]; then chmod 600 "$HOME/.ssh/authorized_keys"; fi
|
|
||||||
if [[ -f "$HOME/.ssh/known_hosts" ]]; then chmod 644 "$HOME/.ssh/known_hosts"; fi
|
|
||||||
ok "fixed ~/.ssh permissions"
|
|
||||||
else
|
|
||||||
warn "~/.ssh not found, skipping"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -d "$HOME/.gnupg" ]]; then
|
|
||||||
chmod 700 "$HOME/.gnupg"
|
|
||||||
find "$HOME/.gnupg" -type d -exec chmod 700 {} +
|
|
||||||
find "$HOME/.gnupg" -type f -exec chmod 600 {} +
|
|
||||||
ok "fixed ~/.gnupg permissions"
|
|
||||||
else
|
|
||||||
warn "~/.gnupg not found, skipping"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
install_pipenv() {
|
|
||||||
if ! has_cmd pipx; then
|
|
||||||
err "pipx not found; run the pipx module first"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if pipx list --short 2>/dev/null | grep -q '^pipenv '; then
|
|
||||||
ok "pipenv already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
pipx install pipenv
|
|
||||||
rollback_push "pipx uninstall pipenv"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
install_pipx() {
|
|
||||||
apt_install pipx
|
|
||||||
profile_add 'export PATH="$HOME/.local/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_pnpm() {
|
|
||||||
if has_cmd pnpm; then ok "pnpm already installed"; return; fi
|
|
||||||
track_new_dir "$HOME/.local/share/pnpm"
|
|
||||||
curl -fsSL https://get.pnpm.io/install.sh | sh -
|
|
||||||
profile_add 'export PNPM_HOME="$HOME/.local/share/pnpm"'
|
|
||||||
profile_add 'case ":$PATH:" in *":$PNPM_HOME:"*) ;; *) export PATH="$PNPM_HOME:$PATH" ;; esac'
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_poetry() {
|
|
||||||
if has_cmd poetry; then ok "poetry already installed"; return; fi
|
|
||||||
track_new_dir "$HOME/.local/share/pypoetry"
|
|
||||||
rollback_push "rm -f '$HOME/.local/bin/poetry'"
|
|
||||||
curl -sSL https://install.python-poetry.org | python3 -
|
|
||||||
profile_add 'export PATH="$HOME/.local/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
install_postman() {
|
|
||||||
if [[ -x /opt/Postman/Postman ]]; then ok "postman already installed"; return; fi
|
|
||||||
|
|
||||||
local tarball
|
|
||||||
tarball=$(mktemp --suffix=.tar.gz)
|
|
||||||
curl -fsSL https://dl.pstmn.io/download/latest/linux_64 -o "$tarball"
|
|
||||||
track_new_sudo_dir /opt/Postman
|
|
||||||
sudo tar -xzf "$tarball" -C /opt
|
|
||||||
rm -f "$tarball"
|
|
||||||
sudo ln -sf /opt/Postman/Postman /usr/local/bin/postman
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/postman /usr/share/applications/postman.desktop"
|
|
||||||
|
|
||||||
sudo tee /usr/share/applications/postman.desktop >/dev/null <<'EOF'
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=Postman
|
|
||||||
Exec=/opt/Postman/Postman %U
|
|
||||||
Icon=/opt/Postman/app/resources/app/assets/icon.png
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Development;
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
install_protonvpn() {
|
|
||||||
if dpkg -s proton-vpn-gnome-desktop >/dev/null 2>&1; then
|
|
||||||
ok "protonvpn already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local list_url deb_name deb
|
|
||||||
list_url="https://repo.protonvpn.com/debian/dists/stable/main/binary-all/"
|
|
||||||
deb_name=$(curl -fsSL "$list_url" | grep -oE 'protonvpn-stable-release_[0-9.]+_all\.deb' | sort -V | tail -n1)
|
|
||||||
|
|
||||||
if [[ -z "$deb_name" ]]; then
|
|
||||||
err "could not find the protonvpn-stable-release package on repo.protonvpn.com"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
deb=$(mktemp --suffix=.deb)
|
|
||||||
curl -fsSL "${list_url}${deb_name}" -o "$deb"
|
|
||||||
apt_update_once
|
|
||||||
sudo apt-get install -y "$deb"
|
|
||||||
rm -f "$deb"
|
|
||||||
rollback_push "sudo apt-get remove -y protonvpn-stable-release"
|
|
||||||
|
|
||||||
apt_invalidate
|
|
||||||
apt_install proton-vpn-gnome-desktop
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
install_pyenv() {
|
|
||||||
apt_install make build-essential libssl-dev zlib1g-dev libbz2-dev \
|
|
||||||
libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev \
|
|
||||||
xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
|
|
||||||
|
|
||||||
if [[ -d "$HOME/.pyenv" ]]; then
|
|
||||||
ok "pyenv already installed"
|
|
||||||
else
|
|
||||||
track_new_dir "$HOME/.pyenv"
|
|
||||||
curl -fsSL https://pyenv.run | bash
|
|
||||||
fi
|
|
||||||
|
|
||||||
profile_add 'export PYENV_ROOT="$HOME/.pyenv"'
|
|
||||||
profile_add 'export PATH="$PYENV_ROOT/bin:$PATH"'
|
|
||||||
profile_add 'eval "$(pyenv init - zsh)"'
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_rust() {
|
|
||||||
if has_cmd rustc; then ok "rust already installed"; return; fi
|
|
||||||
track_new_dir "$HOME/.cargo"
|
|
||||||
track_new_dir "$HOME/.rustup"
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
|
||||||
profile_add '. "$HOME/.cargo/env"'
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_signal() {
|
|
||||||
if has_cmd signal-desktop; then ok "signal already installed"; return; fi
|
|
||||||
apt_add_repo signal-xenial /usr/share/keyrings/signal-desktop-keyring.gpg \
|
|
||||||
https://updates.signal.org/desktop/apt/keys.asc \
|
|
||||||
"deb [arch=amd64 signed-by=/usr/share/keyrings/signal-desktop-keyring.gpg] https://updates.signal.org/desktop/apt xenial main"
|
|
||||||
apt_install signal-desktop
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
install_slack() {
|
|
||||||
if flatpak list --app 2>/dev/null | grep -q com.slack.Slack; then
|
|
||||||
ok "slack already installed"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
ensure_flatpak
|
|
||||||
sudo flatpak install -y flathub com.slack.Slack
|
|
||||||
rollback_push "sudo flatpak uninstall -y com.slack.Slack"
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
install_spotify() {
|
|
||||||
if has_cmd spotify; then ok "spotify already installed"; return; fi
|
|
||||||
apt_add_repo spotify /etc/apt/trusted.gpg.d/spotify.gpg \
|
|
||||||
https://download.spotify.com/debian/pubkey_6224F9941A8AA6D1.gpg \
|
|
||||||
"deb http://repository.spotify.com stable non-free"
|
|
||||||
apt_install spotify-client
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
install_telegram() {
|
|
||||||
if [[ -x /opt/Telegram/Telegram ]]; then ok "telegram already installed"; return; fi
|
|
||||||
|
|
||||||
local tarball
|
|
||||||
tarball=$(mktemp --suffix=.tar.xz)
|
|
||||||
curl -fsSL https://telegram.org/dl/desktop/linux -o "$tarball"
|
|
||||||
track_new_sudo_dir /opt/Telegram
|
|
||||||
sudo tar -xJf "$tarball" -C /opt
|
|
||||||
rm -f "$tarball"
|
|
||||||
sudo ln -sf /opt/Telegram/Telegram /usr/local/bin/telegram
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/telegram /usr/share/applications/telegram.desktop"
|
|
||||||
|
|
||||||
sudo tee /usr/share/applications/telegram.desktop >/dev/null <<'EOF'
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=Telegram
|
|
||||||
Exec=/opt/Telegram/Telegram -- %u
|
|
||||||
Icon=/opt/Telegram/telegram.svg
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Network;InstantMessaging;
|
|
||||||
MimeType=x-scheme-handler/tg;
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
install_uv() {
|
|
||||||
if has_cmd uv; then ok "uv already installed"; return; fi
|
|
||||||
rollback_push "rm -f '$HOME/.local/bin/uv' '$HOME/.local/bin/uvx'"
|
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
||||||
profile_add 'export PATH="$HOME/.local/bin:$PATH"'
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
install_vscode() {
|
|
||||||
if has_cmd code; then
|
|
||||||
ok "vscode already installed"
|
|
||||||
else
|
|
||||||
apt_add_repo vscode /etc/apt/keyrings/packages.microsoft.gpg \
|
|
||||||
https://packages.microsoft.com/keys/microsoft.asc \
|
|
||||||
"deb [arch=$(deb_arch) signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main"
|
|
||||||
apt_install code
|
|
||||||
fi
|
|
||||||
|
|
||||||
_vscode_install_extensions code
|
|
||||||
_vscode_mirror_cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
# Installs every extension id listed in vscode/extensions.txt (exported from
|
|
||||||
# this machine with `code --list-extensions`) into whichever editor binary
|
|
||||||
# is passed — reused for both `code` and `cursor` since Cursor is a VS Code
|
|
||||||
# fork that reads the same extension id format.
|
|
||||||
_vscode_install_extensions() {
|
|
||||||
local bin="$1"
|
|
||||||
local list="${DOTFILES_DIR:?}/vscode/extensions.txt"
|
|
||||||
has_cmd "$bin" || return 0
|
|
||||||
[[ -f "$list" ]] || return 0
|
|
||||||
|
|
||||||
local installed
|
|
||||||
installed=$("$bin" --list-extensions 2>/dev/null || true)
|
|
||||||
|
|
||||||
local ext
|
|
||||||
while IFS= read -r ext; do
|
|
||||||
if [[ -z "$ext" || "$ext" == \#* ]]; then continue; fi
|
|
||||||
if grep -qxF "$ext" <<< "$installed"; then continue; fi
|
|
||||||
log "$bin: installing extension $ext"
|
|
||||||
"$bin" --install-extension "$ext" --force >/dev/null 2>&1 || warn "$bin: failed to install $ext"
|
|
||||||
done < "$list"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cursor reads ~/.config/Cursor/User/settings.json the same way VS Code
|
|
||||||
# reads ~/.config/Code/User/settings.json. Symlinking it to the (stowed)
|
|
||||||
# Code settings keeps both in sync from one source of truth in this repo.
|
|
||||||
_vscode_mirror_cursor() {
|
|
||||||
local src="$HOME/.config/Code/User/settings.json"
|
|
||||||
local dest_dir="$HOME/.config/Cursor/User"
|
|
||||||
[[ -f "$src" ]] || return 0
|
|
||||||
|
|
||||||
mkdir -p "$dest_dir"
|
|
||||||
if [[ ! -e "$dest_dir/settings.json" ]]; then
|
|
||||||
ln -sf "$src" "$dest_dir/settings.json"
|
|
||||||
ok "mirrored VS Code settings to Cursor"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if has_cmd cursor; then _vscode_install_extensions cursor; fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
install_wakatime() {
|
|
||||||
local cfg="$HOME/.wakatime.cfg"
|
|
||||||
|
|
||||||
if grep -q '^api_key' "$cfg" 2>/dev/null; then
|
|
||||||
ok "wakatime already configured in $cfg"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local key
|
|
||||||
read -rsp "Wakatime API key (leave blank to skip): " key
|
|
||||||
echo
|
|
||||||
if [[ -z "$key" ]]; then
|
|
||||||
warn "no key entered, skipping wakatime setup"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local fresh=0
|
|
||||||
[[ -f "$cfg" ]] || fresh=1
|
|
||||||
|
|
||||||
if [[ -f "$cfg" ]]; then
|
|
||||||
grep -v '^api_key' "$cfg" > "${cfg}.tmp" 2>/dev/null || true
|
|
||||||
mv "${cfg}.tmp" "$cfg"
|
|
||||||
if grep -q '^\[settings\]' "$cfg"; then
|
|
||||||
sed -i "/^\[settings\]/a api_key = ${key}" "$cfg"
|
|
||||||
else
|
|
||||||
{ echo "[settings]"; echo "api_key = ${key}"; cat "$cfg"; } > "${cfg}.tmp"
|
|
||||||
mv "${cfg}.tmp" "$cfg"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
printf '[settings]\napi_key = %s\n' "$key" > "$cfg"
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod 600 "$cfg"
|
|
||||||
if [[ $fresh -eq 1 ]]; then rollback_push "rm -f '$cfg'"; fi
|
|
||||||
ok "wrote $cfg"
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
install_zig() {
|
|
||||||
local index latest
|
|
||||||
index=$(curl -fsSL https://ziglang.org/download/index.json)
|
|
||||||
latest=$(jq -r 'keys[]' <<< "$index" | grep -v '^master$' | sort -V | tail -n1)
|
|
||||||
|
|
||||||
if has_cmd zig && zig version 2>/dev/null | grep -qx "$latest"; then
|
|
||||||
ok "zig already at $latest"
|
|
||||||
else
|
|
||||||
local url tarball extract_dir
|
|
||||||
url=$(jq -r --arg v "$latest" '.[$v]["x86_64-linux"].tarball' <<< "$index")
|
|
||||||
tarball=$(mktemp --suffix=.tar.xz)
|
|
||||||
curl -fsSL "$url" -o "$tarball"
|
|
||||||
|
|
||||||
extract_dir=$(mktemp -d)
|
|
||||||
tar -xJf "$tarball" -C "$extract_dir" --strip-components=1
|
|
||||||
rm -f "$tarball"
|
|
||||||
|
|
||||||
sudo rm -rf /opt/zig
|
|
||||||
track_new_sudo_dir /opt/zig
|
|
||||||
sudo mv "$extract_dir" /opt/zig
|
|
||||||
sudo ln -sf /opt/zig/zig /usr/local/bin/zig
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/zig"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_zig_install_zls
|
|
||||||
}
|
|
||||||
|
|
||||||
# zls (the Zig language server) is versioned against a specific zig build;
|
|
||||||
# zigtools' own select-version API returns the right zls release for
|
|
||||||
# whatever zig version is currently installed.
|
|
||||||
_zig_install_zls() {
|
|
||||||
if ! has_cmd zig; then return 0; fi
|
|
||||||
|
|
||||||
local zig_version resp url
|
|
||||||
zig_version=$(zig version)
|
|
||||||
resp=$(curl -fsSL "https://releases.zigtools.org/v1/zls/select-version?zig_version=${zig_version}&compatibility=only-runtime")
|
|
||||||
url=$(jq -r '.["x86_64-linux"].tarball // empty' <<< "$resp" 2>/dev/null)
|
|
||||||
|
|
||||||
if [[ -z "$url" ]]; then
|
|
||||||
warn "no matching zls build for zig $zig_version, skipping"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -x /opt/zls/zls ]]; then
|
|
||||||
local current
|
|
||||||
current=$(/opt/zls/zls --version 2>/dev/null || echo "")
|
|
||||||
if [[ "$current" == *"$zig_version"* ]]; then
|
|
||||||
ok "zls already matches zig $zig_version"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tarball extract_dir
|
|
||||||
tarball=$(mktemp --suffix=.tar.xz)
|
|
||||||
curl -fsSL "$url" -o "$tarball"
|
|
||||||
extract_dir=$(mktemp -d)
|
|
||||||
tar -xJf "$tarball" -C "$extract_dir"
|
|
||||||
rm -f "$tarball"
|
|
||||||
|
|
||||||
sudo rm -rf /opt/zls
|
|
||||||
track_new_sudo_dir /opt/zls
|
|
||||||
sudo mv "$extract_dir" /opt/zls
|
|
||||||
sudo ln -sf /opt/zls/zls /usr/local/bin/zls
|
|
||||||
rollback_push "sudo rm -f /usr/local/bin/zls"
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Daemon]
|
||||||
|
Autolock=false
|
||||||
|
LockOnResume=false
|
||||||
|
Timeout=0
|
||||||
|
|
||||||
|
[Greeter]
|
||||||
|
WallpaperPlugin=org.kde.image
|
||||||
|
|
||||||
|
[Greeter][Wallpaper][org.kde.image][General]
|
||||||
|
Image=file:///home/ian/.local/share/wallpapers/everforest/1-tree-tops.webp
|
||||||
|
PreviewImage=file:///home/ian/.local/share/wallpapers/everforest/1-tree-tops.webp
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
[ColorEffects:Disabled]
|
||||||
|
Color=47,56,62
|
||||||
|
ColorAmount=0.75
|
||||||
|
ColorEffect=3
|
||||||
|
ContrastAmount=0.65
|
||||||
|
ContrastEffect=0
|
||||||
|
IntensityAmount=0.1
|
||||||
|
IntensityEffect=0
|
||||||
|
|
||||||
|
[ColorEffects:Inactive]
|
||||||
|
ChangeSelectionColor=true
|
||||||
|
Color=47,56,62
|
||||||
|
ColorAmount=0.47500000000000003
|
||||||
|
ColorEffect=2
|
||||||
|
ContrastAmount=0.1
|
||||||
|
ContrastEffect=0
|
||||||
|
Enable=true
|
||||||
|
IntensityAmount=0.1
|
||||||
|
IntensityEffect=0
|
||||||
|
|
||||||
|
[Colors:Button]
|
||||||
|
BackgroundAlternate=64,69,82
|
||||||
|
BackgroundNormal=55,66,71
|
||||||
|
DecorationFocus=167,192,128
|
||||||
|
DecorationHover=167,192,128
|
||||||
|
ForegroundActive=167,192,128
|
||||||
|
ForegroundInactive=122,132,120
|
||||||
|
ForegroundLink=127,187,179
|
||||||
|
ForegroundNegative=230,126,128
|
||||||
|
ForegroundNeutral=219,188,127
|
||||||
|
ForegroundNormal=211,198,170
|
||||||
|
ForegroundPositive=141,161,1
|
||||||
|
ForegroundVisited=214,153,182
|
||||||
|
|
||||||
|
[Colors:Complementary]
|
||||||
|
BackgroundNormal=42,46,50
|
||||||
|
|
||||||
|
[Colors:Selection]
|
||||||
|
BackgroundAlternate=147,178,89
|
||||||
|
BackgroundNormal=167,192,128
|
||||||
|
DecorationFocus=167,192,128
|
||||||
|
DecorationHover=167,192,128
|
||||||
|
ForegroundActive=47,56,62
|
||||||
|
ForegroundInactive=122,132,120
|
||||||
|
ForegroundLink=127,187,179
|
||||||
|
ForegroundNegative=230,126,128
|
||||||
|
ForegroundNeutral=219,188,127
|
||||||
|
ForegroundNormal=47,56,62
|
||||||
|
ForegroundPositive=141,161,1
|
||||||
|
ForegroundVisited=214,153,182
|
||||||
|
|
||||||
|
[Colors:Tooltip]
|
||||||
|
BackgroundAlternate=47,52,63
|
||||||
|
BackgroundNormal=55,66,71
|
||||||
|
DecorationFocus=167,192,128
|
||||||
|
DecorationHover=167,192,128
|
||||||
|
ForegroundActive=167,192,128
|
||||||
|
ForegroundInactive=122,132,120
|
||||||
|
ForegroundLink=127,187,179
|
||||||
|
ForegroundNegative=230,126,128
|
||||||
|
ForegroundNeutral=219,188,127
|
||||||
|
ForegroundNormal=211,198,170
|
||||||
|
ForegroundPositive=141,161,1
|
||||||
|
ForegroundVisited=214,153,182
|
||||||
|
|
||||||
|
[Colors:View]
|
||||||
|
BackgroundAlternate=55,66,71
|
||||||
|
BackgroundNormal=43,51,57
|
||||||
|
DecorationFocus=167,192,128
|
||||||
|
DecorationHover=167,192,128
|
||||||
|
ForegroundActive=167,192,128
|
||||||
|
ForegroundInactive=122,132,120
|
||||||
|
ForegroundLink=127,187,179
|
||||||
|
ForegroundNegative=230,126,128
|
||||||
|
ForegroundNeutral=219,188,127
|
||||||
|
ForegroundNormal=211,198,170
|
||||||
|
ForegroundPositive=141,161,1
|
||||||
|
ForegroundVisited=214,153,182
|
||||||
|
|
||||||
|
[Colors:Window]
|
||||||
|
BackgroundAlternate=55,66,71
|
||||||
|
BackgroundNormal=47,56,62
|
||||||
|
DecorationFocus=167,192,128
|
||||||
|
DecorationHover=167,192,128
|
||||||
|
ForegroundActive=167,192,128
|
||||||
|
ForegroundInactive=122,132,120
|
||||||
|
ForegroundLink=127,187,179
|
||||||
|
ForegroundNegative=230,126,128
|
||||||
|
ForegroundNeutral=219,188,127
|
||||||
|
ForegroundNormal=211,198,170
|
||||||
|
ForegroundPositive=141,161,1
|
||||||
|
ForegroundVisited=214,153,182
|
||||||
|
|
||||||
|
[General]
|
||||||
|
ColorScheme=Everforest
|
||||||
|
Name=Everforest
|
||||||
|
shadeSortColumn=true
|
||||||
|
|
||||||
|
[KDE]
|
||||||
|
contrast=4
|
||||||
|
|
||||||
|
[WM]
|
||||||
|
activeBackground=47,56,62
|
||||||
|
activeBlend=47,56,62
|
||||||
|
activeForeground=211,198,170
|
||||||
|
inactiveBackground=47,56,62
|
||||||
|
inactiveBlend=47,56,62
|
||||||
|
inactiveForeground=122,132,120
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
tt.*
|
||||||
|
.tests
|
||||||
|
doc/tags
|
||||||
|
debug
|
||||||
|
.repro
|
||||||
|
foo.*
|
||||||
|
*.log
|
||||||
|
data
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"neodev": {
|
||||||
|
"library": {
|
||||||
|
"enabled": true,
|
||||||
|
"plugins": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"neoconf": {
|
||||||
|
"plugins": {
|
||||||
|
"lua_ls": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- bootstrap lazy.nvim, LazyVim and your plugins
|
||||||
|
require("config.lazy")
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"LazyVim": { "branch": "main", "commit": "999700997f72227187d49d8b92667183dc7fc809" },
|
||||||
|
"blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" },
|
||||||
|
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
|
||||||
|
"catppuccin": { "branch": "main", "commit": "edefef779ab08ce1a4a404713e3012b0d202bd35" },
|
||||||
|
"clangd_extensions.nvim": { "branch": "main", "commit": "78c2ecd659d54972be17aa6ba2deac3c53223b80" },
|
||||||
|
"conform.nvim": { "branch": "master", "commit": "016802de402556da54c36bd7359b441266b01cdd" },
|
||||||
|
"crates.nvim": { "branch": "main", "commit": "7039bc1d130e424232a7aa64ceddb170a154ff5b" },
|
||||||
|
"everforest-nvim": { "branch": "main", "commit": "a0e9edc57379e8feafc6ba207c26dbb12fc1b6d8" },
|
||||||
|
"flash.nvim": { "branch": "main", "commit": "5f0f270fdc7c5b0c21d903ee85b9cb06f2ac636a" },
|
||||||
|
"friendly-snippets": { "branch": "main", "commit": "b4d01b0fdf3c9a549961c2f9ffe8dc09be166219" },
|
||||||
|
"gitsigns.nvim": { "branch": "main", "commit": "851a051e2bd2caba97e23314c68d69f1b1cf5d19" },
|
||||||
|
"grug-far.nvim": { "branch": "main", "commit": "11595bf747edc270bce2069d1020502ad4ae56cf" },
|
||||||
|
"lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
|
||||||
|
"lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" },
|
||||||
|
"lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" },
|
||||||
|
"mason-lspconfig.nvim": { "branch": "main", "commit": "b3298993d55fa194279b5eb9dbfb3a43da65cadf" },
|
||||||
|
"mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" },
|
||||||
|
"mini.ai": { "branch": "main", "commit": "c2c4278beb759aa24b9506f56a67186a6cc2209c" },
|
||||||
|
"mini.icons": { "branch": "main", "commit": "f642e3ba8c12afbc8f32f6d77ef6597eac56786f" },
|
||||||
|
"mini.pairs": { "branch": "main", "commit": "b1c5a726921b7a8c9321e9a7a208aa0571de5810" },
|
||||||
|
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
|
||||||
|
"nui.nvim": { "branch": "main", "commit": "10fc361835c856ba4233ef5ea135b919bf3dce97" },
|
||||||
|
"nvim-lint": { "branch": "master", "commit": "3d55c8f67c6ae5c15e1042571e107c7a3d5c5f4e" },
|
||||||
|
"nvim-lspconfig": { "branch": "master", "commit": "33497f4930d40f28a465d38a763a00fc6902c658" },
|
||||||
|
"nvim-treesitter": { "branch": "main", "commit": "e289100ff98969e118c702199d88b764ce9e7fdf" },
|
||||||
|
"nvim-treesitter-textobjects": { "branch": "main", "commit": "5c7b0263797dfd1bd6202f2b219f3b53a80b2187" },
|
||||||
|
"nvim-ts-autotag": { "branch": "main", "commit": "d7220b55e16ed3c04e88086256def5d282429493" },
|
||||||
|
"persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" },
|
||||||
|
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
|
||||||
|
"rustaceanvim": { "branch": "main", "commit": "a968f5133b8b24f481de12f08cd79420d1ace559" },
|
||||||
|
"snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" },
|
||||||
|
"todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
|
||||||
|
"tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" },
|
||||||
|
"trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
|
||||||
|
"ts-comments.nvim": { "branch": "main", "commit": "a59d6092213447450191122c9346f309161504cb" },
|
||||||
|
"venv-selector.nvim": { "branch": "main", "commit": "cc4bb3975de8835291f9bb45889e96c6b2795fc4" },
|
||||||
|
"which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extras": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"install_version": 8,
|
||||||
|
"news": {
|
||||||
|
"NEWS.md": "11866"
|
||||||
|
},
|
||||||
|
"version": 8
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- Autocmds are automatically loaded on the VeryLazy event
|
||||||
|
-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua
|
||||||
|
--
|
||||||
|
-- Add any additional autocmds here
|
||||||
|
-- with `vim.api.nvim_create_autocmd`
|
||||||
|
--
|
||||||
|
-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults)
|
||||||
|
-- e.g. vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell")
|
||||||
|
|
||||||
|
-- enter terminal mode whenever a terminal buffer is focused
|
||||||
|
vim.api.nvim_create_autocmd({ "TermOpen", "BufEnter", "WinEnter" }, {
|
||||||
|
group = vim.api.nvim_create_augroup("term_autoinsert", { clear = true }),
|
||||||
|
pattern = "term://*",
|
||||||
|
callback = function()
|
||||||
|
vim.cmd("startinsert")
|
||||||
|
end,
|
||||||
|
})
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Keymaps are automatically loaded on the VeryLazy event
|
||||||
|
-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua
|
||||||
|
-- Add any additional keymaps here
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||||
|
if not (vim.uv or vim.loop).fs_stat(lazypath) then
|
||||||
|
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
|
||||||
|
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
|
||||||
|
if vim.v.shell_error ~= 0 then
|
||||||
|
vim.api.nvim_echo({
|
||||||
|
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
|
||||||
|
{ out, "WarningMsg" },
|
||||||
|
{ "\nPress any key to exit..." },
|
||||||
|
}, true, {})
|
||||||
|
vim.fn.getchar()
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vim.opt.rtp:prepend(lazypath)
|
||||||
|
|
||||||
|
require("lazy").setup({
|
||||||
|
spec = {
|
||||||
|
-- add LazyVim and import its plugins
|
||||||
|
{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
|
||||||
|
-- language support (LSP, treesitter, formatters, debuggers)
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.zig" },
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.python" },
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.typescript" },
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.rust" },
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.go" },
|
||||||
|
{ import = "lazyvim.plugins.extras.lang.clangd" },
|
||||||
|
-- import/override with your plugins
|
||||||
|
{ import = "plugins" },
|
||||||
|
},
|
||||||
|
defaults = {
|
||||||
|
-- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.
|
||||||
|
-- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.
|
||||||
|
lazy = false,
|
||||||
|
-- It's recommended to leave version=false for now, since a lot the plugin that support versioning,
|
||||||
|
-- have outdated releases, which may break your Neovim install.
|
||||||
|
version = false, -- always use the latest git commit
|
||||||
|
-- version = "*", -- try installing the latest stable version for plugins that support semver
|
||||||
|
},
|
||||||
|
install = { colorscheme = { "tokyonight", "habamax" } },
|
||||||
|
checker = {
|
||||||
|
enabled = true, -- check for plugin updates periodically
|
||||||
|
notify = false, -- notify on update
|
||||||
|
}, -- automatically check for plugin updates
|
||||||
|
performance = {
|
||||||
|
rtp = {
|
||||||
|
-- disable some rtp plugins
|
||||||
|
disabled_plugins = {
|
||||||
|
"gzip",
|
||||||
|
-- "matchit",
|
||||||
|
-- "matchparen",
|
||||||
|
-- "netrwPlugin",
|
||||||
|
"tarPlugin",
|
||||||
|
"tohtml",
|
||||||
|
"tutor",
|
||||||
|
"zipPlugin",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Options are automatically loaded before lazy.nvim startup
|
||||||
|
-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua
|
||||||
|
-- Add any additional options here
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
return {
|
||||||
|
{
|
||||||
|
"neanias/everforest-nvim",
|
||||||
|
lazy = false,
|
||||||
|
priority = 1000,
|
||||||
|
config = function()
|
||||||
|
require("everforest").setup({
|
||||||
|
background = "medium",
|
||||||
|
transparent_background_level = 2,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"LazyVim/LazyVim",
|
||||||
|
opts = {
|
||||||
|
colorscheme = "everforest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 2
|
||||||
|
column_width = 120
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
GITHUB_USERNAME="andwati"
|
||||||
|
DESTINATION_FOLDER=~/dev
|
||||||
|
|
||||||
|
# Define colors
|
||||||
|
GREEN="\e[32m"
|
||||||
|
BLUE="\e[34m"
|
||||||
|
RED="\e[31m"
|
||||||
|
RESET="\e[0m"
|
||||||
|
|
||||||
|
clone_repositories() {
|
||||||
|
local parent_dir=$1
|
||||||
|
local repo_name=$2
|
||||||
|
|
||||||
|
# Clone the repository using GitHub CLI
|
||||||
|
echo -e "${BLUE}Cloning repository: $repo_name${RESET}"
|
||||||
|
if gh repo clone "$GITHUB_USERNAME/$repo_name" "$parent_dir/$repo_name"; then
|
||||||
|
echo -e "${GREEN}Successfully cloned: $repo_name${RESET}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to clone: $repo_name${RESET}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Move into the cloned repository folder
|
||||||
|
cd "$parent_dir/$repo_name" || exit
|
||||||
|
|
||||||
|
# If there are submodules, initialize and update them
|
||||||
|
if [ -f ".gitmodules" ]; then
|
||||||
|
echo -e "${BLUE}Initializing and updating submodules for: $repo_name${RESET}"
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
# Ensure the destination folder exists
|
||||||
|
mkdir -p "$DESTINATION_FOLDER"
|
||||||
|
|
||||||
|
# Fetch the list of repositories for the user using GitHub CLI, including private and public repos
|
||||||
|
echo -e "${BLUE}Fetching repositories for user: $GITHUB_USERNAME${RESET}"
|
||||||
|
repos=$(gh repo list "$GITHUB_USERNAME" --visibility public --limit 100 --json name -q '.[].name')
|
||||||
|
private_repos=$(gh repo list "$GITHUB_USERNAME" --visibility private --limit 100 --json name -q '.[].name')
|
||||||
|
|
||||||
|
# Combine public and private repositories
|
||||||
|
repos="$repos $private_repos"
|
||||||
|
|
||||||
|
# Initialize progress variables
|
||||||
|
total_repos=$(echo "$repos" | wc -w)
|
||||||
|
count=0
|
||||||
|
|
||||||
|
# Loop through each repository and clone it
|
||||||
|
for repo in $repos; do
|
||||||
|
count=$((count + 1))
|
||||||
|
echo -e "${BLUE}Progress: [$count/$total_repos]${RESET}"
|
||||||
|
clone_repositories "$DESTINATION_FOLDER" "$repo"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "${GREEN}Cloning complete! ${RESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
set -g mouse on
|
|
||||||
set -g history-limit 10000
|
|
||||||
set -g base-index 1
|
|
||||||
setw -g pane-base-index 1
|
|
||||||
setw -g mode-keys vi
|
|
||||||
set -g status-style bg=black,fg=white
|
|
||||||
set -g status-right '%Y-%m-%d %H:%M'
|
|
||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"workbench.colorTheme": "Everforest Dark",
|
||||||
|
"workbench.productIconTheme": "material-product-icons",
|
||||||
|
"workbench.iconTheme": "material-icon-theme",
|
||||||
|
"editor.fontFamily": "'JetBrainsMono Nerd Font','Droid Sans Mono', monospace",
|
||||||
|
"workbench.browser.searchEngine": "google",
|
||||||
|
"workbench.browser.openLocalhostLinks": false,
|
||||||
|
"diffEditor.renderSideBySide": true,
|
||||||
|
"diffEditor.useInlineViewWhenSpaceIsLimited": true,
|
||||||
"json.schemaDownload.trustedDomains": {
|
"json.schemaDownload.trustedDomains": {
|
||||||
"https://biomejs.dev": true,
|
"https://biomejs.dev": true,
|
||||||
"https://developer.microsoft.com/json-schemas/": true,
|
"https://developer.microsoft.com/json-schemas/": true,
|
||||||
@@ -7,52 +15,9 @@
|
|||||||
"https://raw.githubusercontent.com/devcontainers/spec/": true,
|
"https://raw.githubusercontent.com/devcontainers/spec/": true,
|
||||||
"https://raw.githubusercontent.com/microsoft/vscode/": true,
|
"https://raw.githubusercontent.com/microsoft/vscode/": true,
|
||||||
"https://schemastore.azurewebsites.net/": true,
|
"https://schemastore.azurewebsites.net/": true,
|
||||||
"https://turbo.build": true,
|
|
||||||
"https://turborepo.dev": true,
|
|
||||||
"https://ui.shadcn.com": true,
|
|
||||||
"https://www.schemastore.org/": true
|
"https://www.schemastore.org/": true
|
||||||
},
|
},
|
||||||
"claudeCode.preferredLocation": "panel",
|
"python.analysis.typeCheckingMode": "strict",
|
||||||
"git.confirmSync": false,
|
|
||||||
"diffEditor.renderSideBySide": false,
|
|
||||||
"git.autofetch": true,
|
"git.autofetch": true,
|
||||||
"git.enableSmartCommit": true,
|
"git.confirmSync": false
|
||||||
"files.autoSave": "onFocusChange",
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"gitlens.ai.model": "vscode",
|
|
||||||
"gitlens.ai.vscode.model": "copilot:gpt-4.1",
|
|
||||||
"security.allowedUNCHosts": [
|
|
||||||
"wsl.localhost"
|
|
||||||
],
|
|
||||||
"diffEditor.ignoreTrimWhitespace": true,
|
|
||||||
"redhat.telemetry.enabled": false,
|
|
||||||
"explorer.confirmDelete": false,
|
|
||||||
"chat.viewSessions.orientation": "stacked",
|
|
||||||
"snyk.securityAtInception.autoConfigureSnykMcpServer": true,
|
|
||||||
"snyk.securityAtInception.executionFrequency": "On Code Generation",
|
|
||||||
"snyk.yesWelcomeNotification": false,
|
|
||||||
"diffEditor.maxComputationTime": 0,
|
|
||||||
|
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "biomejs.biome"
|
|
||||||
},
|
|
||||||
"workbench.colorTheme": "GitHub Dark",
|
|
||||||
"workbench.iconTheme": "material-icon-theme",
|
|
||||||
"workbench.productIconTheme": "material-product-icons",
|
|
||||||
"workbench.editor.enablePreview": false,
|
|
||||||
"cSpell.enabledNotifications": {
|
|
||||||
"Lines too Long": false,
|
|
||||||
"Average Word Length too Long": false,
|
|
||||||
"Maximum Word Length Exceeded": false
|
|
||||||
},
|
|
||||||
"editor.fontFamily": "'Monaspace Argon NF','Droid Sans Mono', monospace",
|
|
||||||
"terminal.integrated.fontFamily": "'Monaspace Argon NF'",
|
|
||||||
"cSpell.userWords": [
|
|
||||||
"Mikro"
|
|
||||||
],
|
|
||||||
"editor.foldingImportsByDefault": true,
|
|
||||||
"js/ts.updateImportsOnFileMove.enabled": "always",
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
ahmadalli.vscode-nginx-conf
|
|
||||||
alexcvzz.vscode-sqlite
|
|
||||||
angular.ng-template
|
|
||||||
anthropic.claude-code
|
|
||||||
biomejs.biome
|
|
||||||
bradlc.vscode-tailwindcss
|
|
||||||
catppuccin.catppuccin-vsc
|
|
||||||
charliermarsh.ruff
|
|
||||||
dart-code.dart-code
|
|
||||||
dart-code.flutter
|
|
||||||
davidanson.vscode-markdownlint
|
|
||||||
dbaeumer.vscode-eslint
|
|
||||||
donjayamanne.githistory
|
|
||||||
dsznajder.es7-react-js-snippets
|
|
||||||
eamodio.gitlens
|
|
||||||
esbenp.prettier-vscode
|
|
||||||
expo.vscode-expo-tools
|
|
||||||
github.github-vscode-theme
|
|
||||||
github.vscode-github-actions
|
|
||||||
github.vscode-pull-request-github
|
|
||||||
golang.go
|
|
||||||
llvm-vs-code-extensions.lldb-dap
|
|
||||||
mechatroner.rainbow-csv
|
|
||||||
mermaidchart.vscode-mermaid-chart
|
|
||||||
mhutchie.git-graph
|
|
||||||
ms-azuretools.vscode-containers
|
|
||||||
ms-azuretools.vscode-docker
|
|
||||||
ms-kubernetes-tools.vscode-kubernetes-tools
|
|
||||||
ms-python.black-formatter
|
|
||||||
ms-python.debugpy
|
|
||||||
ms-python.python
|
|
||||||
ms-python.vscode-pylance
|
|
||||||
ms-python.vscode-python-envs
|
|
||||||
ms-toolsai.jupyter
|
|
||||||
ms-toolsai.jupyter-keymap
|
|
||||||
ms-toolsai.jupyter-renderers
|
|
||||||
ms-toolsai.vscode-jupyter-cell-tags
|
|
||||||
ms-toolsai.vscode-jupyter-slideshow
|
|
||||||
ms-vscode-remote.remote-containers
|
|
||||||
ms-vscode.cmake-tools
|
|
||||||
ms-vscode.cpp-devtools
|
|
||||||
ms-vscode.cpptools
|
|
||||||
ms-vscode.cpptools-extension-pack
|
|
||||||
ms-vscode.cpptools-themes
|
|
||||||
ms-vscode.makefile-tools
|
|
||||||
ms-vscode.powershell
|
|
||||||
ms-vscode.vscode-chat-customizations-evaluations
|
|
||||||
njpwerner.autodocstring
|
|
||||||
njqdev.vscode-python-typehint
|
|
||||||
nuxtr.nuxtr-vscode
|
|
||||||
openai.chatgpt
|
|
||||||
phplasma.csv-to-table
|
|
||||||
pkief.material-icon-theme
|
|
||||||
pkief.material-product-icons
|
|
||||||
prisma.prisma
|
|
||||||
redhat.java
|
|
||||||
redhat.vscode-yaml
|
|
||||||
redis.redis-for-vscode
|
|
||||||
ritwickdey.liveserver
|
|
||||||
rust-lang.rust-analyzer
|
|
||||||
samuelcolvin.jinjahtml
|
|
||||||
shakram02.bash-beautify
|
|
||||||
snyk-security.snyk-vulnerability-scanner
|
|
||||||
streetsidesoftware.code-spell-checker
|
|
||||||
tamasfe.even-better-toml
|
|
||||||
tomoki1207.pdf
|
|
||||||
twxs.cmake
|
|
||||||
usernamehw.errorlens
|
|
||||||
vadimcn.vscode-lldb
|
|
||||||
vscjava.vscode-gradle
|
|
||||||
vscjava.vscode-java-debug
|
|
||||||
vscjava.vscode-java-dependency
|
|
||||||
vscjava.vscode-java-pack
|
|
||||||
vscjava.vscode-java-test
|
|
||||||
vscjava.vscode-maven
|
|
||||||
vue.volar
|
|
||||||
wakatime.vscode-wakatime
|
|
||||||
+1841
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
|
eval "$(pyenv init --path)"
|
||||||
|
|
||||||
|
# Created by `pipx` on 2026-07-26 14:32:10
|
||||||
|
export PATH="$PATH:/home/ian/.local/bin"
|
||||||
|
|
||||||
|
|
||||||
|
# Added by Antigravity CLI installer
|
||||||
|
export PATH="/home/ian/.local/bin:$PATH"
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
alias ls='eza'
|
|
||||||
alias ll='eza -lah'
|
|
||||||
alias la='eza -a'
|
|
||||||
alias lt='eza --tree'
|
|
||||||
alias grep='rg'
|
|
||||||
alias gs='git status'
|
|
||||||
alias gd='git diff'
|
|
||||||
alias gco='git checkout'
|
|
||||||
alias dc='docker compose'
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
. "$HOME/.cargo/env"
|
||||||
+195
-10
@@ -1,15 +1,200 @@
|
|||||||
HISTFILE="$HOME/.zsh_history"
|
# Add deno completions to search path
|
||||||
HISTSIZE=50000
|
if [[ ":$FPATH:" != *":/home/ian/.zsh/completions:"* ]]; then export FPATH="/home/ian/.zsh/completions:$FPATH"; fi
|
||||||
SAVEHIST=50000
|
# Enable Powerlevel10k instant prompt. Must stay close to the top of ~/.zshrc.
|
||||||
setopt HIST_IGNORE_DUPS SHARE_HISTORY EXTENDED_HISTORY INC_APPEND_HISTORY
|
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
|
||||||
|
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
|
||||||
|
fi
|
||||||
|
|
||||||
autoload -Uz compinit && compinit
|
# Add deno completions to search path
|
||||||
|
if [[ ":$FPATH:" != *":$HOME/.zsh/completions:"* ]]; then export FPATH="$HOME/.zsh/completions:$FPATH"; fi
|
||||||
|
# If you come from bash you might have to change your $PATH.
|
||||||
|
# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH
|
||||||
|
|
||||||
export EDITOR="vim"
|
# Path to your Oh My Zsh installation.
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
export ZSH="$HOME/.oh-my-zsh"
|
||||||
|
|
||||||
[[ -f "$HOME/.zsh_aliases" ]] && source "$HOME/.zsh_aliases"
|
# Set name of the theme to load --- if set to "random", it will
|
||||||
|
# load a random theme each time Oh My Zsh is loaded, in which case,
|
||||||
|
# to know which specific one was loaded, run: echo $RANDOM_THEME
|
||||||
|
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
|
||||||
|
ZSH_THEME="powerlevel10k/powerlevel10k"
|
||||||
|
|
||||||
PROMPT='%F{blue}%~%f %(?.%F{green}.%F{red})❯%f '
|
# Set list of themes to pick from when loading at random
|
||||||
|
# Setting this variable when ZSH_THEME=random will cause zsh to load
|
||||||
|
# a theme from this variable instead of looking in $ZSH/themes/
|
||||||
|
# If set to an empty array, this variable will have no effect.
|
||||||
|
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
|
||||||
|
|
||||||
# --- devenv installers (managed by install/lib.sh profile_add, appended below) ---
|
# Uncomment the following line to use case-sensitive completion.
|
||||||
|
# CASE_SENSITIVE="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to use hyphen-insensitive completion.
|
||||||
|
# Case-sensitive completion must be off. _ and - will be interchangeable.
|
||||||
|
# HYPHEN_INSENSITIVE="true"
|
||||||
|
|
||||||
|
# Uncomment one of the following lines to change the auto-update behavior
|
||||||
|
# zstyle ':omz:update' mode disabled # disable automatic updates
|
||||||
|
# zstyle ':omz:update' mode auto # update automatically without asking
|
||||||
|
# zstyle ':omz:update' mode reminder # just remind me to update when it's time
|
||||||
|
|
||||||
|
# Uncomment the following line to change how often to auto-update (in days).
|
||||||
|
# zstyle ':omz:update' frequency 13
|
||||||
|
|
||||||
|
# Uncomment the following line if pasting URLs and other text is messed up.
|
||||||
|
# DISABLE_MAGIC_FUNCTIONS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to disable colors in ls.
|
||||||
|
# DISABLE_LS_COLORS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to disable auto-setting terminal title.
|
||||||
|
# DISABLE_AUTO_TITLE="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to enable command auto-correction.
|
||||||
|
# ENABLE_CORRECTION="true"
|
||||||
|
|
||||||
|
# Uncomment the following line to display red dots whilst waiting for completion.
|
||||||
|
# You can also set it to another string to have that shown instead of the default red dots.
|
||||||
|
# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f"
|
||||||
|
# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765)
|
||||||
|
# COMPLETION_WAITING_DOTS="true"
|
||||||
|
|
||||||
|
# Uncomment the following line if you want to disable marking untracked files
|
||||||
|
# under VCS as dirty. This makes repository status check for large repositories
|
||||||
|
# much, much faster.
|
||||||
|
# DISABLE_UNTRACKED_FILES_DIRTY="true"
|
||||||
|
|
||||||
|
# Uncomment the following line if you want to change the command execution time
|
||||||
|
# stamp shown in the history command output.
|
||||||
|
# You can set one of the optional three formats:
|
||||||
|
# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
|
||||||
|
# or set a custom format using the strftime function format specifications,
|
||||||
|
# see 'man strftime' for details.
|
||||||
|
# HIST_STAMPS="mm/dd/yyyy"
|
||||||
|
|
||||||
|
# Would you like to use another custom folder than $ZSH/custom?
|
||||||
|
# ZSH_CUSTOM=/path/to/new-custom-folder
|
||||||
|
|
||||||
|
# Which plugins would you like to load?
|
||||||
|
# Standard plugins can be found in $ZSH/plugins/
|
||||||
|
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
|
||||||
|
# Example format: plugins=(rails git textmate ruby lighthouse)
|
||||||
|
# Add wisely, as too many plugins slow down shell startup.
|
||||||
|
plugins=(
|
||||||
|
git sudo extract archlinux docker docker-compose fzf
|
||||||
|
zsh-completions you-should-use
|
||||||
|
zsh-autosuggestions zsh-syntax-highlighting zsh-history-substring-search
|
||||||
|
)
|
||||||
|
|
||||||
|
source $ZSH/oh-my-zsh.sh
|
||||||
|
|
||||||
|
# To customize the prompt, run `p10k configure` or edit ~/.p10k.zsh.
|
||||||
|
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
|
||||||
|
|
||||||
|
# Up/Down arrows filter history by what's already typed, not just cycle it.
|
||||||
|
bindkey '^[[A' history-substring-search-up
|
||||||
|
bindkey '^[[B' history-substring-search-down
|
||||||
|
|
||||||
|
# zoxide: smarter `cd` that learns frequently/recently used directories.
|
||||||
|
command -v zoxide >/dev/null && eval "$(zoxide init zsh)"
|
||||||
|
|
||||||
|
# User configuration
|
||||||
|
|
||||||
|
# Needed for gpg-agent to prompt on the right terminal when pinentry falls
|
||||||
|
# back to a tty (e.g. pinentry-curses); harmless no-op with pinentry-qt.
|
||||||
|
export GPG_TTY=$(tty)
|
||||||
|
|
||||||
|
# export MANPATH="/usr/local/man:$MANPATH"
|
||||||
|
|
||||||
|
# You may need to manually set your language environment
|
||||||
|
# export LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
# Preferred editor for local and remote sessions
|
||||||
|
# if [[ -n $SSH_CONNECTION ]]; then
|
||||||
|
# export EDITOR='vim'
|
||||||
|
# else
|
||||||
|
# export EDITOR='nvim'
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# Compilation flags
|
||||||
|
# export ARCHFLAGS="-arch $(uname -m)"
|
||||||
|
|
||||||
|
# Set personal aliases, overriding those provided by Oh My Zsh libs,
|
||||||
|
# plugins, and themes. Aliases can be placed here, though Oh My Zsh
|
||||||
|
# users are encouraged to define aliases within a top-level file in
|
||||||
|
# the $ZSH_CUSTOM folder, with .zsh extension. Examples:
|
||||||
|
# - $ZSH_CUSTOM/aliases.zsh
|
||||||
|
# - $ZSH_CUSTOM/macos.zsh
|
||||||
|
# For a full list of active aliases, run `alias`.
|
||||||
|
#
|
||||||
|
# Example aliases
|
||||||
|
# alias zshconfig="mate ~/.zshrc"
|
||||||
|
# alias ohmyzsh="mate ~/.oh-my-zsh"
|
||||||
|
|
||||||
|
# eza: colourful, icon-rich listings that stay clean when piped.
|
||||||
|
alias ls='eza --color=auto --icons=auto --hyperlink=auto --group-directories-first'
|
||||||
|
alias l='eza -lah --git --color-scale=all --color=auto --icons=auto --hyperlink=auto --group-directories-first'
|
||||||
|
alias ll='eza -lh --git --color-scale=all --color=auto --icons=auto --hyperlink=auto --group-directories-first'
|
||||||
|
alias la='eza -lAh --git --color-scale=all --color=auto --icons=auto --hyperlink=auto --group-directories-first'
|
||||||
|
alias lt='eza --tree --level=2 --color=auto --icons=auto --hyperlink=auto --group-directories-first'
|
||||||
|
|
||||||
|
# nvm: the lazy-load stub (wrapper functions deferring to a helper that
|
||||||
|
# sourced nvm.sh on first real use) was unreliable in some non-interactive
|
||||||
|
# shell contexts, where the wrapper could run without the helper function
|
||||||
|
# being defined yet. Sourcing eagerly costs 300-700ms on shell startup but
|
||||||
|
# always works.
|
||||||
|
export NVM_DIR="$HOME/.nvm"
|
||||||
|
() {
|
||||||
|
# oh-my-zsh sets extendedglob, which breaks nvm's `lts/*`-style alias
|
||||||
|
# globs and silently kills auto-activation of the default version.
|
||||||
|
# local_options scopes this to the anonymous function, restoring the
|
||||||
|
# prior setting once nvm.sh is sourced.
|
||||||
|
setopt local_options no_extended_glob
|
||||||
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
|
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lazy-load pyenv's shell integration (~130-150ms here). Shims are
|
||||||
|
# already on PATH via .zprofile, so `python`/`pip` work immediately
|
||||||
|
# without this; it's only needed for `pyenv shell/activate/...` and
|
||||||
|
# completions, which this loads for real on first actual `pyenv` call.
|
||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
|
pyenv() {
|
||||||
|
unfunction pyenv
|
||||||
|
eval "$(command pyenv init - zsh)"
|
||||||
|
pyenv "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# bun completions
|
||||||
|
[ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun"
|
||||||
|
|
||||||
|
# bun
|
||||||
|
export BUN_INSTALL="$HOME/.bun"
|
||||||
|
export PATH="$BUN_INSTALL/bin:$PATH"
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
export PNPM_HOME="/home/ian/.local/share/pnpm"
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$PNPM_HOME/bin:"*) ;;
|
||||||
|
*) export PATH="$PNPM_HOME/bin:$PATH" ;;
|
||||||
|
esac
|
||||||
|
# pnpm end
|
||||||
|
[ -s "$HOME/.deno/env" ] && . "$HOME/.deno/env"
|
||||||
|
|
||||||
|
# Created by `pipx` on 2026-07-26 14:32:10
|
||||||
|
export PATH="$PATH:/home/ian/.local/bin"
|
||||||
|
. "/home/ian/.deno/env"
|
||||||
|
|
||||||
|
# Java (Amazon Corretto 21) and Android SDK, for Android Studio / Gradle builds.
|
||||||
|
export JAVA_HOME="/usr/lib/jvm/java-21-amazon-corretto"
|
||||||
|
export ANDROID_HOME="$HOME/Android/Sdk"
|
||||||
|
export PATH="$JAVA_HOME/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH"
|
||||||
|
|
||||||
|
|
||||||
|
# Added by Antigravity CLI installer
|
||||||
|
export PATH="/home/ian/.local/bin:$PATH"
|
||||||
|
|
||||||
|
# Resend CLI
|
||||||
|
export PATH="$HOME/.resend/bin:$PATH"
|
||||||
|
|
||||||
|
export PATH="/home/ian/depot_tools:$PATH"
|
||||||
|
|||||||
Reference in New Issue
Block a user