diff --git a/bash/.bashrc.d/fonts.bash b/bash/.bashrc.d/fonts.bash new file mode 100644 index 0000000..45a59c6 --- /dev/null +++ b/bash/.bashrc.d/fonts.bash @@ -0,0 +1,33 @@ +# Ensure Fira Code is available for terminal apps (fontconfig) +_fonts_stamp="${XDG_STATE_HOME:-$HOME/.local/state}/fira-code-fonts" +_fonts_dir="$HOME/.local/share/fonts/FiraCode" + +if ! fc-list 2>/dev/null | grep -qi 'fira code'; then + if [[ -f "$_fonts_stamp" ]] && compgen -G "$_fonts_dir/*.ttf" >/dev/null; then + fc-cache -f "$HOME/.local/share/fonts" 2>/dev/null + elif command -v dnf &>/dev/null; then + if sudo dnf install -y fira-code-fonts &>/dev/null; then + fc-cache -f 2>/dev/null + mkdir -p "${_fonts_stamp%/*}" + touch "$_fonts_stamp" + fi + fi + + if ! fc-list 2>/dev/null | grep -qi 'fira code' \ + && command -v curl &>/dev/null && command -v unzip &>/dev/null; then + mkdir -p "$_fonts_dir" + _fonts_tmp=$(mktemp -d) + if curl -fsSL "https://github.com/tonsky/FiraCode/releases/download/6.2/Fira_Code_v6.2.zip" \ + -o "$_fonts_tmp/FiraCode.zip" \ + && unzip -qo "$_fonts_tmp/FiraCode.zip" -d "$_fonts_tmp" \ + && cp -f "$_fonts_tmp/ttf/"*.ttf "$_fonts_dir/"; then + fc-cache -f "$HOME/.local/share/fonts" 2>/dev/null + mkdir -p "${_fonts_stamp%/*}" + touch "$_fonts_stamp" + fi + rm -rf "$_fonts_tmp" + unset _fonts_tmp + fi +fi + +unset _fonts_stamp _fonts_dir \ No newline at end of file diff --git a/bash/.bashrc.d/vscode.bash b/bash/.bashrc.d/vscode.bash new file mode 100644 index 0000000..a74803d --- /dev/null +++ b/bash/.bashrc.d/vscode.bash @@ -0,0 +1,6 @@ +# VS Code extension install helper +vscode-ext-install() { + bash "${HOME}/dotfiles/vscode-server/install-vscode-extensions.sh" "$@" +} + +alias vscode-ext-list='vscode-ext-install --list' \ No newline at end of file diff --git a/vscode-server/.vscode-server/data/Machine/settings.json b/vscode-server/.vscode-server/data/Machine/settings.json new file mode 100644 index 0000000..7be2e83 --- /dev/null +++ b/vscode-server/.vscode-server/data/Machine/settings.json @@ -0,0 +1,56 @@ +{ + "workbench.editor.useModal": "off", + "workbench.settings.editor": "json", + "workbench.settings.useSplitJSON": false, + "editor.fontFamily": "Fira Code", + "editor.fontSize": 11, + "editor.fontLigatures": true, + "terminal.integrated.fontFamily": "Fira Code", + "terminal.integrated.profiles.linux": { + "grok": { + "path": "${userHome}/.grok/bin/grok", + "icon": "sparkle" + }, + }, + "terminal.integrated.defaultProfile.linux": "bash", + "workbench.iconTheme": "vscode-icons", + "files.exclude": { + "**/__pycache__": true, + "**/.DS_Store": true, + "**/.git": true, + "**/.hg": true, + "**/.svn": true, + "**/CVS": true + }, + "search.exclude": { + "**/__pycache__": true, + "**/.DS_Store": true, + "**/.git": true, + "**/.hg": true, + "**/.svn": true, + "**/CVS": true, + "**/.grok": true, + "**/.grok/worktrees": true, + "**/.grok/sessions": true, + "**/.grok/logs": true, + "**/.cursor": true, + "**/.cline": true, + "**/.continue": true, + "**/.aider*": true, + "**/.codex": true, + "**/.windsurf": true, + "**/.codeium": true, + "**/.roo": true, + "**/.openclaw": true, + "**/.factory": true, + "**/.augment": true + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": false + }, + "ruff.lineLength": 128, + "git.blame.editorDecoration.enabled": true, + "git.blame.editorDecoration.template": "${subject}, ${authorName} (${authorDateAgo})", + "git.blame.statusBarItem.enabled": true, +} \ No newline at end of file diff --git a/vscode-server/extensions.txt b/vscode-server/extensions.txt new file mode 100644 index 0000000..9dc0bd8 --- /dev/null +++ b/vscode-server/extensions.txt @@ -0,0 +1,23 @@ +# VS Code extensions (one ID per line; # comments allowed) +# Install: bash ~/dotfiles/vscode-server/install-vscode-extensions.sh + +# Remote / WSL (from settings) +ms-vscode-remote.remote-wsl +ms-python.python +ms-python.debugpy +ms-python.vscode-python-envs +charliermarsh.ruff +redhat.vscode-yaml +redhat.vscode-xml +ms-toolsai.jupyter +ms-toolsai.jupyter-renderers +ms-toolsai.vscode-jupyter-cell-tags +ms-toolsai.vscode-jupyter-slideshow + +# UI +vscode-icons-team.vscode-icons + +# Optional (uncomment if you use them) +# GitHub.copilot +# GitHub.copilot-chat +# formulahendry.acp-client \ No newline at end of file diff --git a/vscode-server/install-fira-code-fonts.sh b/vscode-server/install-fira-code-fonts.sh new file mode 100644 index 0000000..ab0d647 --- /dev/null +++ b/vscode-server/install-fira-code-fonts.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Fedora / WSL Linux +if command -v dnf >/dev/null 2>&1; then + sudo dnf install -y fira-code-fonts + fc-cache -f +fi + +# Windows user fonts (when running under WSL) +if [[ -d /mnt/c/Users ]]; then + win_fonts="/mnt/c/Users/${USER}/AppData/Local/Microsoft/Windows/Fonts" + if [[ ! -d "$win_fonts" ]]; then + win_fonts="/mnt/c/Users/${USER}/AppData/Local/Microsoft/Windows/Fonts" + fi + tmp=$(mktemp -d) + curl -sL "https://github.com/tonsky/FiraCode/releases/download/6.2/Fira_Code_v6.2.zip" -o "$tmp/FiraCode.zip" + unzip -q "$tmp/FiraCode.zip" -d "$tmp" + cp -f "$tmp/ttf/"*.ttf "$win_fonts/" + rm -rf "$tmp" + echo "Installed Fira Code to $win_fonts" +fi \ No newline at end of file diff --git a/vscode-server/install-vscode-extensions.sh b/vscode-server/install-vscode-extensions.sh new file mode 100644 index 0000000..b507194 --- /dev/null +++ b/vscode-server/install-vscode-extensions.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +EXT_FILE="${SCRIPT_DIR}/extensions.txt" +TARGET="remote" +FORCE=0 + +usage() { + cat <<'EOF' +Usage: install-vscode-extensions.sh [options] + +Install VS Code extensions from extensions.txt. + +Options: + --local Install to Windows VS Code only + --remote Install to WSL remote VS Code (default) + --both Install to both local Windows and WSL remote + --list Print installed extension IDs (remote by default) + --export Write installed IDs to extensions.txt + --file PATH Use a different extension list file + --force Reinstall even if already present + -h, --help Show this help + +Examples: + bash install-vscode-extensions.sh + bash install-vscode-extensions.sh --both + bash install-vscode-extensions.sh --list + bash install-vscode-extensions.sh --export +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --local) TARGET="local" ;; + --remote) TARGET="remote" ;; + --both) TARGET="both" ;; + --list) TARGET="list" ;; + --export) TARGET="export" ;; + --file) shift; EXT_FILE="${1:?missing path for --file}" ;; + --force) FORCE=1 ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;; + esac + shift +done + +find_code_cli() { + if command -v code >/dev/null 2>&1; then + command -v code + return 0 + fi + local candidate + for candidate in /mnt/c/Users/*/AppData/Local/Programs/Microsoft\ VS\ Code/bin/code; do + if [[ -f "$candidate" ]]; then + echo "$candidate" + return 0 + fi + done + return 1 +} + +remote_args() { + if [[ -n "${WSL_DISTRO_NAME:-}" ]]; then + printf '%s\0%s\0' --remote "wsl+${WSL_DISTRO_NAME,,}" + fi +} + +run_code() { + "$CODE_CLI" "$@" +} + +list_extensions() { + local scope=$1 + local -a args=(--list-extensions) + if [[ "$scope" == "remote" ]]; then + local -a remote=() + while IFS= read -r -d '' arg; do + remote+=("$arg") + done < <(remote_args) + if [[ ${#remote[@]} -eq 0 ]]; then + echo "No WSL distro detected for remote listing." >&2 + return 1 + fi + args+=("${remote[@]}") + fi + run_code "${args[@]}" +} + +install_extensions() { + local scope=$1 + local -a remote=() + if [[ "$scope" == "remote" ]]; then + while IFS= read -r -d '' arg; do + remote+=("$arg") + done < <(remote_args) + if [[ ${#remote[@]} -eq 0 ]]; then + echo "No WSL distro detected; skipping remote install." >&2 + return 0 + fi + fi + + local line id installed=0 skipped=0 failed=0 + while IFS= read -r line || [[ -n "$line" ]]; do + line="${line%%#*}" + line="${line//[[:space:]]/}" + [[ -z "$line" ]] && continue + id="$line" + + if [[ "$FORCE" -eq 0 ]] && list_extensions "$scope" | grep -Fxq "$id"; then + echo "skip [$scope] $id" + skipped=$((skipped + 1)) + continue + fi + + echo "install [$scope] $id" + if [[ "$scope" == "remote" ]]; then + if run_code --install-extension "$id" "${remote[@]}" --force; then + installed=$((installed + 1)) + else + echo "failed [$scope] $id" >&2 + failed=$((failed + 1)) + fi + elif run_code --install-extension "$id" --force; then + installed=$((installed + 1)) + else + echo "failed [$scope] $id" >&2 + failed=$((failed + 1)) + fi + done < "$EXT_FILE" + + echo "done [$scope]: installed=$installed skipped=$skipped failed=$failed" + [[ "$failed" -eq 0 ]] +} + +CODE_CLI=$(find_code_cli) || { + echo "VS Code CLI not found. Install VS Code and ensure 'code' is on PATH." >&2 + exit 1 +} + +case "$TARGET" in + list) + list_extensions remote + ;; + export) + list_extensions remote > "$EXT_FILE" + echo "Wrote $(wc -l < "$EXT_FILE" | tr -d ' ') extensions to $EXT_FILE" + ;; + local) + install_extensions local + ;; + remote) + install_extensions remote + ;; + both) + install_extensions local + install_extensions remote + ;; +esac \ No newline at end of file