set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
STAMP="$(date +%Y%m%d-%H%M%S)"
CONFIGS=(nvim yazi kitty)
TS_PARSERS="'bash','c','cpp','diff','lua','luadoc','query','vim','vimdoc','html','css','scss','javascript','typescript','tsx','jsdoc','json','json5','yaml','toml','graphql','regex','markdown','markdown_inline','python','rust'"
SKIP_PACKAGES=0
MODE=link
for arg in "$@"; do
case "$arg" in
--skip-packages) SKIP_PACKAGES=1 ;;
--copy) MODE=copy ;;
-h | --help)
sed -n '2,9p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
echo "Неизвестный аргумент: $arg (см. --help)" >&2
exit 1
;;
esac
done
if [ -t 1 ]; then
B=$'\e[1m' G=$'\e[32m' Y=$'\e[33m' R=$'\e[31m' C=$'\e[36m' N=$'\e[0m'
else
B='' G='' Y='' R='' C='' N=''
fi
step() { printf '\n%s==>%s %s%s%s\n' "$C" "$N" "$B" "$*" "$N"; }
ok() { printf ' %s✓%s %s\n' "$G" "$N" "$*"; }
warn() { printf ' %s!%s %s\n' "$Y" "$N" "$*"; }
die() {
printf '%sОшибка:%s %s\n' "$R" "$N" "$*" >&2
exit 1
}
case "$(uname -s)" in
Darwin) OS=macos ;;
Linux)
if [ -f /etc/arch-release ] || command -v pacman >/dev/null 2>&1; then
OS=arch
else
die "поддерживаются только macOS и Arch Linux (и производные: EndeavourOS, Manjaro, CachyOS)"
fi
;;
*) die "неподдерживаемая система: $(uname -s)" ;;
esac
printf '%sСборка neovim + yazi + kitty%s — %s, режим: %s\n' "$B" "$N" "$OS" "$MODE"
install_macos() {
if ! command -v brew >/dev/null 2>&1; then
step "Установка Homebrew"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ -x /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
fi
step "Пакеты и шрифты (brew bundle)"
brew bundle --file="$REPO/packages/Brewfile"
ok "пакеты установлены"
}
install_lilex_linux() {
local dir="$HOME/.local/share/fonts/Lilex"
if fc-list 2>/dev/null | grep -qi 'Lilex'; then
ok "шрифт Lilex уже установлен"
return
fi
step "Шрифт Lilex (GitHub mishamyrt/Lilex)"
local tmp
tmp="$(mktemp -d)"
curl -fsSL -o "$tmp/Lilex.zip" https://github.com/mishamyrt/Lilex/releases/latest/download/Lilex.zip
unzip -q "$tmp/Lilex.zip" -d "$tmp/Lilex"
mkdir -p "$dir"
find "$tmp/Lilex" -name '*.ttf' -exec cp {} "$dir/" \;
[ -n "$(ls -A "$dir")" ] || find "$tmp/Lilex" -name '*.otf' -exec cp {} "$dir/" \;
rm -rf "$tmp"
fc-cache -f "$dir" >/dev/null
ok "Lilex установлен в $dir"
}
install_arch() {
step "Пакеты (pacman)"
grep -vE '^\s*(#|$)' "$REPO/packages/arch.txt" | sudo pacman -S --needed --noconfirm -
ok "пакеты установлены"
install_lilex_linux
}
if [ "$SKIP_PACKAGES" -eq 1 ]; then
step "Пакеты: пропущено (--skip-packages)"
else
"install_$OS"
fi
for cmd in nvim yazi git; do
command -v "$cmd" >/dev/null 2>&1 || die "не найден '$cmd' — установи пакеты (запусти без --skip-packages)"
done
step "Конфиги → $CONFIG_HOME"
mkdir -p "$CONFIG_HOME"
for name in "${CONFIGS[@]}"; do
src="$REPO/config/$name"
dst="$CONFIG_HOME/$name"
if [ -L "$dst" ] && [ "$(readlink "$dst")" = "$src" ]; then
ok "$name: уже подключён"
continue
fi
if [ -e "$dst" ] || [ -L "$dst" ]; then
mv "$dst" "$dst.bak-$STAMP"
warn "$name: старый конфиг сохранён в $dst.bak-$STAMP"
fi
if [ "$MODE" = link ]; then
ln -s "$src" "$dst"
ok "$name: симлинк $dst → $src"
else
cp -R "$src" "$dst"
ok "$name: скопирован в $dst"
fi
done
step "Интеграция в shell (функция y, zoxide, EDITOR=nvim)"
MARK="# neovim_yazi_settings"
LINE="[ -f \"$REPO/shell/shellrc.sh\" ] && . \"$REPO/shell/shellrc.sh\" $MARK"
rc_files=()
[ -f "$HOME/.zshrc" ] || [ "$(basename "${SHELL:-}")" = zsh ] && rc_files+=("$HOME/.zshrc")
[ -f "$HOME/.bashrc" ] || [ "$(basename "${SHELL:-}")" = bash ] && rc_files+=("$HOME/.bashrc")
for rc in "${rc_files[@]}"; do
touch "$rc"
if grep -qF "$MARK" "$rc"; then
grep -vF "$MARK" "$rc" >"$rc.tmp" && mv "$rc.tmp" "$rc"
fi
printf '\n%s\n' "$LINE" >>"$rc"
ok "подключено в $rc"
done
step "Плагины Neovim (lazy.nvim, версии из lazy-lock.json)"
LOCK="$CONFIG_HOME/nvim/lazy-lock.json"
LOCK_SAVED="$(mktemp)"
cp "$LOCK" "$LOCK_SAVED"
nvim --headless '+Lazy! install' +qa
cp "$LOCK_SAVED" "$LOCK"
nvim --headless '+Lazy! restore' +qa
cp "$LOCK_SAVED" "$LOCK"
rm -f "$LOCK_SAVED"
ok "плагины установлены"
step "LSP-серверы и форматтеры (Mason) — может занять несколько минут"
nvim --headless '+MasonToolsInstallSync' +qa
nvim --headless '+MasonInstall codelldb' +qa >/dev/null ok "Mason: инструменты установлены"
step "Парсеры Treesitter"
nvim --headless "+lua require('nvim-treesitter').install({ $TS_PARSERS }):wait(600000)" +qa
ok "парсеры установлены"
printf '\n%s%sГотово!%s\n' "$G" "$B" "$N"
cat <<EOF
• Перезапусти терминал (или: source ~/.zshrc)
• Открой kitty — шрифт Lilex и тема Kanagawa уже настроены
• nvim — редактор (проверка: :checkhealth)
• y — файловый менеджер yazi
• Шпаргалка по Neovim: $REPO/config/nvim/COMMANDS.md
EOF