Last active
August 26, 2026 10:07
-
-
Save johnny-official/81031f044d2f5df0198e073aa75a11ce to your computer and use it in GitHub Desktop.
setup-ide.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Recommended: download first, then execute (safer than curl | bash): | |
| # curl -fL "https://gist.githubusercontent.com/johnny-official/81031f044d2f5df0198e073aa75a11ce/raw/gistfile1.txt?v=$(date +%s)" -o /tmp/johnny-dev-bootstrap.sh \ | |
| # && bash /tmp/johnny-dev-bootstrap.sh | |
| set -u | |
| VERSION="2026.08.26" | |
| # Optional controls: | |
| # JOHNNY_INSTALL_SHELL_TOOLS=0 -> skip apt package installation | |
| # JOHNNY_INSTALL_OH_MY_ZSH=0 -> skip Oh My Zsh installation | |
| INSTALL_SHELL_TOOLS="${JOHNNY_INSTALL_SHELL_TOOLS:-1}" | |
| INSTALL_OH_MY_ZSH="${JOHNNY_INSTALL_OH_MY_ZSH:-1}" | |
| # Do not run the entire bootstrap through sudo. The script elevates only the | |
| # package-manager commands that actually require root privileges. | |
| if [ "$(id -u)" -eq 0 ] \n && [ -n "${SUDO_USER:-}" ] \n && [ "${SUDO_USER:-}" != "root" ] | |
| then | |
| printf '[ERROR] Run this bootstrap as your normal user, not with sudo.\n' >&2 | |
| printf '[ERROR] The script will use sudo only when packages need installing.\n' >&2 | |
| exit 1 | |
| fi | |
| HOME_DIR="${HOME:-}" | |
| if [ -z "$HOME_DIR" ]; then | |
| HOME_DIR="$(getent passwd "$(id -u)" 2>/dev/null | cut -d: -f6)" | |
| fi | |
| if [ -z "$HOME_DIR" ] || [ ! -d "$HOME_DIR" ]; then | |
| printf '[ERROR] Cannot determine HOME directory.\n' >&2 | |
| exit 1 | |
| fi | |
| XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME_DIR/.config}" | |
| XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME_DIR/.local/share}" | |
| TMP_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t johnny-dev)" | |
| SETTINGS_TEMPLATE="$TMP_DIR/settings.json" | |
| trap 'rm -rf "$TMP_DIR"' EXIT INT TERM | |
| ok() { | |
| printf '[OK] %s\n' "$*" | |
| } | |
| info() { | |
| printf '[INFO] %s\n' "$*" | |
| } | |
| warn() { | |
| printf '[WARN] %s\n' "$*" >&2 | |
| } | |
| printf '\n' | |
| printf '========================================\n' | |
| printf ' Johnny Dev Bootstrap %s\n' "$VERSION" | |
| printf '========================================\n' | |
| printf '\n' | |
| printf 'User : %s\n' "$(id -un 2>/dev/null || printf unknown)" | |
| printf 'Home : %s\n' "$HOME_DIR" | |
| printf 'Shell: %s\n' "${SHELL:-unknown}" | |
| printf '\n' | |
| # ============================================================================= | |
| # 1. COMMON EDITOR SETTINGS | |
| # ============================================================================= | |
| cat > "$SETTINGS_TEMPLATE" <<'JSON' | |
| { | |
| "php.suggest.basic": false, | |
| "java.errors.incompleteClasspath.severity": "ignore", | |
| "liveServer.settings.donotShowInfoMsg": true, | |
| "editor.mouseWheelZoom": true, | |
| "editor.formatOnSave": true, | |
| "editor.formatOnPaste": true, | |
| "editor.formatOnType": false, | |
| "editor.minimap.enabled": false, | |
| "editor.stickyScroll.enabled": true, | |
| "editor.smoothScrolling": true, | |
| "editor.cursorSmoothCaretAnimation": "on", | |
| "editor.cursorBlinking": "smooth", | |
| "editor.lineNumbers": "on", | |
| "editor.renderWhitespace": "selection", | |
| "editor.bracketPairColorization.enabled": true, | |
| "editor.guides.bracketPairs": true, | |
| "editor.guides.indentation": true, | |
| "editor.guides.highlightActiveIndentation": true, | |
| "editor.tabSize": 4, | |
| "editor.insertSpaces": true, | |
| "editor.detectIndentation": true, | |
| "editor.trimAutoWhitespace": true, | |
| "editor.largeFileOptimizations": true, | |
| "editor.linkedEditing": true, | |
| "editor.hover.delay": 300, | |
| "files.autoSave": "off", | |
| "files.trimTrailingWhitespace": true, | |
| "files.insertFinalNewline": true, | |
| "files.trimFinalNewlines": true, | |
| "files.watcherExclude": { | |
| "**/.git/objects/**": true, | |
| "**/.git/subtree-cache/**": true, | |
| "**/node_modules/**": true, | |
| "**/__pycache__/**": true, | |
| "**/.pytest_cache/**": true, | |
| "**/.ruff_cache/**": true, | |
| "**/.mypy_cache/**": true, | |
| "**/.venv/**": true, | |
| "**/venv/**": true, | |
| "**/dist/**": true, | |
| "**/build/**": true, | |
| "**/.next/**": true, | |
| "**/coverage/**": true | |
| }, | |
| "search.exclude": { | |
| "**/.git": true, | |
| "**/node_modules": true, | |
| "**/__pycache__": true, | |
| "**/.pytest_cache": true, | |
| "**/.ruff_cache": true, | |
| "**/.mypy_cache": true, | |
| "**/.venv": true, | |
| "**/venv": true, | |
| "**/dist": true, | |
| "**/build": true, | |
| "**/.next": true, | |
| "**/coverage": true | |
| }, | |
| "[python]": { | |
| "editor.defaultFormatter": "charliermarsh.ruff", | |
| "editor.formatOnSave": true, | |
| "editor.formatOnPaste": false, | |
| "editor.codeActionsOnSave": { | |
| "source.fixAll.ruff": "explicit", | |
| "source.organizeImports.ruff": "explicit" | |
| } | |
| }, | |
| "[javascript]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[javascriptreact]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[typescript]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[typescriptreact]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[json]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[jsonc]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[html]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[css]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[scss]": { | |
| "editor.tabSize": 2, | |
| "editor.formatOnSave": true | |
| }, | |
| "[php]": { | |
| "editor.tabSize": 4, | |
| "editor.formatOnSave": true | |
| } | |
| } | |
| JSON | |
| # ============================================================================= | |
| # 2. MERGE SETTINGS SAFELY | |
| # ============================================================================= | |
| merge_settings() { | |
| target="$1" | |
| mkdir -p "$(dirname "$target")" 2>/dev/null || { | |
| warn "Cannot create: $(dirname "$target")" | |
| return 1 | |
| } | |
| # New file | |
| if [ ! -s "$target" ]; then | |
| cp "$SETTINGS_TEMPLATE" "$target" 2>/dev/null || { | |
| warn "Cannot write: $target" | |
| return 1 | |
| } | |
| ok "Settings -> $target" | |
| return 0 | |
| fi | |
| # Keep one backup | |
| backup="$target.johnny-backup" | |
| if [ ! -e "$backup" ]; then | |
| cp "$target" "$backup" 2>/dev/null || true | |
| fi | |
| # Merge existing JSON if Python is available | |
| if command -v python3 >/dev/null 2>&1; then | |
| if python3 - "$target" "$SETTINGS_TEMPLATE" 2>/dev/null <<'PY' | |
| import json | |
| import sys | |
| from pathlib import Path | |
| old_path = Path(sys.argv[1]) | |
| new_path = Path(sys.argv[2]) | |
| with old_path.open(encoding="utf-8") as f: | |
| old = json.load(f) | |
| with new_path.open(encoding="utf-8") as f: | |
| new = json.load(f) | |
| def merge(a, b): | |
| for key, value in b.items(): | |
| if ( | |
| isinstance(value, dict) | |
| and isinstance(a.get(key), dict) | |
| ): | |
| merge(a[key], value) | |
| else: | |
| a[key] = value | |
| return a | |
| merged = merge(old, new) | |
| tmp = old_path.with_suffix( | |
| old_path.suffix + ".johnny-tmp" | |
| ) | |
| with tmp.open( | |
| "w", | |
| encoding="utf-8" | |
| ) as f: | |
| json.dump( | |
| merged, | |
| f, | |
| indent=4, | |
| ensure_ascii=False | |
| ) | |
| f.write("\n") | |
| tmp.replace(old_path) | |
| PY | |
| then | |
| ok "Merged settings -> $target" | |
| return 0 | |
| fi | |
| warn "Existing settings is JSONC/non-standard:" | |
| warn "$target" | |
| warn "Backup saved -> $backup" | |
| if cp "$SETTINGS_TEMPLATE" "$target" 2>/dev/null; then | |
| ok "Replaced settings -> $target" | |
| return 0 | |
| fi | |
| return 1 | |
| fi | |
| # No Python available | |
| warn "python3 not found." | |
| warn "Backup saved -> $backup" | |
| if cp "$SETTINGS_TEMPLATE" "$target" 2>/dev/null; then | |
| ok "Settings -> $target" | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| # ============================================================================= | |
| # 3. APPLY TO COMMON IDE LOCATIONS | |
| # ============================================================================= | |
| info "Applying editor settings..." | |
| SETTINGS_PATHS=" | |
| $HOME_DIR/.theia/settings.json | |
| $HOME_DIR/.theia-blueprint/settings.json | |
| $XDG_CONFIG_HOME/Code/User/settings.json | |
| $XDG_CONFIG_HOME/Code - Insiders/User/settings.json | |
| $XDG_CONFIG_HOME/VSCodium/User/settings.json | |
| $XDG_DATA_HOME/code-server/User/settings.json | |
| $HOME_DIR/.vscode-remote/data/Machine/settings.json | |
| $HOME_DIR/.openvscode-server/data/Machine/settings.json | |
| " | |
| settings_ok=0 | |
| while IFS= read -r target | |
| do | |
| [ -n "$target" ] || continue | |
| if merge_settings "$target"; then | |
| settings_ok=$((settings_ok + 1)) | |
| fi | |
| done <<EOF | |
| $SETTINGS_PATHS | |
| EOF | |
| # ============================================================================= | |
| # 4. SHELL TOOLING + SAFE PRIVILEGE ESCALATION | |
| # ============================================================================= | |
| run_privileged() { | |
| if [ "$(id -u)" -eq 0 ]; then | |
| "$@" | |
| return $? | |
| fi | |
| if command -v sudo >/dev/null 2>&1; then | |
| sudo "$@" | |
| return $? | |
| fi | |
| warn "Root privileges are required for: $*" | |
| warn "sudo was not found; skipping this privileged step." | |
| return 1 | |
| } | |
| install_shell_dependencies() { | |
| if [ "$INSTALL_SHELL_TOOLS" != "1" ]; then | |
| info "Shell package installation disabled by JOHNNY_INSTALL_SHELL_TOOLS=$INSTALL_SHELL_TOOLS" | |
| return 0 | |
| fi | |
| if ! command -v apt-get >/dev/null 2>&1; then | |
| warn "apt-get not found; skipping automatic installation of zsh/git/curl/bash-completion." | |
| return 0 | |
| fi | |
| packages=() | |
| command -v zsh >/dev/null 2>&1 || packages+=(zsh) | |
| command -v git >/dev/null 2>&1 || packages+=(git) | |
| command -v curl >/dev/null 2>&1 || packages+=(curl) | |
| if [ ! -r /usr/share/bash-completion/bash_completion ] \ | |
| && [ ! -r /etc/bash_completion ] | |
| then | |
| packages+=(bash-completion) | |
| fi | |
| if [ "${#packages[@]}" -eq 0 ]; then | |
| ok "Shell dependencies already installed" | |
| return 0 | |
| fi | |
| info "Installing shell dependencies: ${packages[*]}" | |
| if ! run_privileged apt-get update; then | |
| warn "apt-get update failed; shell dependency installation was skipped." | |
| return 1 | |
| fi | |
| if ! run_privileged env DEBIAN_FRONTEND=noninteractive \ | |
| apt-get install -y "${packages[@]}" | |
| then | |
| warn "Could not install one or more shell dependencies." | |
| return 1 | |
| fi | |
| ok "Shell dependencies installed" | |
| } | |
| install_oh_my_zsh() { | |
| omz_dir="$HOME_DIR/.oh-my-zsh" | |
| if [ "$INSTALL_OH_MY_ZSH" != "1" ]; then | |
| info "Oh My Zsh installation disabled by JOHNNY_INSTALL_OH_MY_ZSH=$INSTALL_OH_MY_ZSH" | |
| return 0 | |
| fi | |
| if [ -r "$omz_dir/oh-my-zsh.sh" ] && [ -d "$omz_dir/.git" ]; then | |
| ok "Oh My Zsh already installed -> $omz_dir" | |
| return 0 | |
| fi | |
| if [ -e "$omz_dir" ]; then | |
| warn "Path exists but does not look like a valid Oh My Zsh installation:" | |
| warn "$omz_dir" | |
| warn "Leaving it untouched for safety." | |
| return 1 | |
| fi | |
| if ! command -v git >/dev/null 2>&1; then | |
| warn "git is unavailable; cannot install Oh My Zsh." | |
| return 1 | |
| fi | |
| info "Installing Oh My Zsh from the official Git repository..." | |
| omz_tmp="$TMP_DIR/oh-my-zsh" | |
| if git clone --depth=1 \ | |
| https://github.com/ohmyzsh/ohmyzsh.git \ | |
| "$omz_tmp" \ | |
| && mv "$omz_tmp" "$omz_dir" | |
| then | |
| ok "Oh My Zsh -> $omz_dir" | |
| return 0 | |
| fi | |
| warn "Oh My Zsh installation failed; no existing config was overwritten." | |
| return 1 | |
| } | |
| install_shell_dependencies || true | |
| install_oh_my_zsh || true | |
| # ============================================================================= | |
| # 5. MANAGED SHELL CONFIGURATION | |
| # ============================================================================= | |
| strip_managed_block() { | |
| rc="$1" | |
| [ -f "$rc" ] || : > "$rc" | |
| backup="$rc.johnny-backup" | |
| if [ -s "$rc" ] && [ ! -e "$backup" ]; then | |
| cp -p "$rc" "$backup" 2>/dev/null \ | |
| || warn "Could not create shell backup: $backup" | |
| fi | |
| begin_count="$(grep -c '^### JOHNNY_DEV_BEGIN$' "$rc" 2>/dev/null || true)" | |
| end_count="$(grep -c '^### JOHNNY_DEV_END$' "$rc" 2>/dev/null || true)" | |
| if [ "$begin_count" -ne "$end_count" ]; then | |
| warn "Managed shell markers are unbalanced in: $rc" | |
| warn "Leaving the file untouched. Backup (if needed): $backup" | |
| return 1 | |
| fi | |
| tmp="$TMP_DIR/$(basename "$rc").clean" | |
| if ! awk ' | |
| $0 == "### JOHNNY_DEV_BEGIN" { | |
| skip=1 | |
| next | |
| } | |
| $0 == "### JOHNNY_DEV_END" { | |
| skip=0 | |
| next | |
| } | |
| !skip { | |
| } | |
| ' "$rc" > "$tmp" | |
| then | |
| warn "Could not parse shell config: $rc" | |
| return 1 | |
| fi | |
| if ! cat "$tmp" > "$rc"; then | |
| warn "Could not update shell config: $rc" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # ============================================================================= | |
| # 6. BASH | |
| # ============================================================================= | |
| configure_bash() { | |
| rc="$HOME_DIR/.bashrc" | |
| strip_managed_block "$rc" || return 1 | |
| cat >> "$rc" <<'BASHRC' | |
| ### JOHNNY_DEV_BEGIN | |
| # ----------------------------------------------------------------------------- | |
| # PATH | |
| # ----------------------------------------------------------------------------- | |
| export PATH="$HOME/.local/bin:$PATH" | |
| # ----------------------------------------------------------------------------- | |
| # PROMPT | |
| # Example: [user: project]$ | |
| # ----------------------------------------------------------------------------- | |
| export PS1="[\[\033[01;32m\]\u\[\033[00m\]: \[\033[01;34m\]\W\[\033[00m\]]\$ " | |
| # ----------------------------------------------------------------------------- | |
| # HISTORY | |
| # ----------------------------------------------------------------------------- | |
| export HISTSIZE=5000 | |
| export HISTFILESIZE=10000 | |
| export HISTCONTROL=ignoreboth:erasedups | |
| shopt -s histappend 2>/dev/null || true | |
| # ----------------------------------------------------------------------------- | |
| # COMMON ALIASES | |
| # ----------------------------------------------------------------------------- | |
| alias ll='ls -alF' | |
| alias la='ls -A' | |
| alias l='ls -CF' | |
| alias ..='cd ..' | |
| alias ...='cd ../..' | |
| alias c='clear' | |
| alias cls='clear' | |
| # ----------------------------------------------------------------------------- | |
| # KUBERNETES CLI | |
| # ----------------------------------------------------------------------------- | |
| alias k=kubectl | |
| # Load distro-provided bash-completion when available. | |
| if [ -r /usr/share/bash-completion/bash_completion ]; then | |
| . /usr/share/bash-completion/bash_completion | |
| elif [ -r /etc/bash_completion ]; then | |
| . /etc/bash_completion | |
| fi | |
| # kubectl completion is enabled only when kubectl exists. | |
| if command -v kubectl >/dev/null 2>&1; then | |
| source <(kubectl completion bash 2>/dev/null) || true | |
| if declare -F __start_kubectl >/dev/null 2>&1; then | |
| complete -o default -F __start_kubectl k 2>/dev/null || true | |
| fi | |
| fi | |
| ### JOHNNY_DEV_END | |
| BASHRC | |
| ok "Bash -> $rc" | |
| } | |
| configure_bash || true | |
| # ============================================================================= | |
| # 7. ZSH + OH MY ZSH | |
| # ============================================================================= | |
| configure_zsh() { | |
| rc="$HOME_DIR/.zshrc" | |
| strip_managed_block "$rc" || return 1 | |
| # Respect an existing user-managed Oh My Zsh source line. If none exists, | |
| # the managed block will source the installation created above. | |
| omz_already_sourced=0 | |
| if grep -Eq '^[[:space:]]*(source|\.)[[:space:]].*oh-my-zsh\.sh' "$rc" 2>/dev/null; then | |
| omz_already_sourced=1 | |
| fi | |
| cat >> "$rc" <<'ZSHRC' | |
| ### JOHNNY_DEV_BEGIN | |
| # ----------------------------------------------------------------------------- | |
| # PATH | |
| # ----------------------------------------------------------------------------- | |
| export PATH="$HOME/.local/bin:$PATH" | |
| ZSHRC | |
| if [ "$omz_already_sourced" -eq 0 ]; then | |
| cat >> "$rc" <<'ZSHRC' | |
| # ----------------------------------------------------------------------------- | |
| # OH MY ZSH | |
| # ----------------------------------------------------------------------------- | |
| if [ -r "$HOME/.oh-my-zsh/oh-my-zsh.sh" ]; then | |
| export ZSH="$HOME/.oh-my-zsh" | |
| source "$ZSH/oh-my-zsh.sh" | |
| fi | |
| ZSHRC | |
| fi | |
| cat >> "$rc" <<'ZSHRC' | |
| # ----------------------------------------------------------------------------- | |
| # COMPLETION | |
| # ----------------------------------------------------------------------------- | |
| # Ensure compdef exists even when Oh My Zsh is not loaded. | |
| if ! whence compdef >/dev/null 2>&1; then | |
| autoload -Uz compinit | |
| compinit -i | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # KUBERNETES CLI | |
| # ----------------------------------------------------------------------------- | |
| alias k=kubectl | |
| if command -v kubectl >/dev/null 2>&1; then | |
| source <(kubectl completion zsh 2>/dev/null) || true | |
| if whence compdef >/dev/null 2>&1; then | |
| compdef __start_kubectl k 2>/dev/null || true | |
| fi | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # PROMPT | |
| # Example: [user: project]$ | |
| # Keep this after Oh My Zsh so the bootstrap prompt wins over a theme. | |
| # ----------------------------------------------------------------------------- | |
| PROMPT='[%F{green}%n%f: %F{blue}%1~%f]$ ' | |
| # ----------------------------------------------------------------------------- | |
| # HISTORY | |
| # ----------------------------------------------------------------------------- | |
| HISTFILE="$HOME/.zsh_history" | |
| HISTSIZE=5000 | |
| SAVEHIST=10000 | |
| setopt APPEND_HISTORY 2>/dev/null || true | |
| setopt HIST_IGNORE_ALL_DUPS 2>/dev/null || true | |
| # ----------------------------------------------------------------------------- | |
| # COMMON ALIASES | |
| # ----------------------------------------------------------------------------- | |
| alias ll='ls -alF' | |
| alias la='ls -A' | |
| alias l='ls -CF' | |
| alias ..='cd ..' | |
| alias ...='cd ../..' | |
| alias c='clear' | |
| alias cls='clear' | |
| ### JOHNNY_DEV_END | |
| ZSHRC | |
| ok "Zsh -> $rc" | |
| } | |
| if command -v zsh >/dev/null 2>&1; then | |
| configure_zsh || true | |
| else | |
| warn "zsh is unavailable; .zshrc was not changed." | |
| fi | |
| # ============================================================================= | |
| # 8. EXTENSIONS | |
| # ============================================================================= | |
| EXTENSIONS=" | |
| charliermarsh.ruff | |
| oderwat.indent-rainbow | |
| " | |
| extension_ok=0 | |
| extension_fail=0 | |
| extension_cli_summary="none" | |
| # ============================================================================= | |
| # 9. TRY ALL SUPPORTED EXTENSION CLIs | |
| # ============================================================================= | |
| try_install_extension() { | |
| ext="$1" | |
| # ------------------------------------------------------------------------- | |
| # VS Code / code-server / VSCodium / OpenVSCode Server | |
| # ------------------------------------------------------------------------- | |
| for candidate in \ | |
| code \ | |
| code-server \ | |
| codium \ | |
| openvscode-server | |
| do | |
| if ! command -v "$candidate" >/dev/null 2>&1; then | |
| continue | |
| fi | |
| cli="$(command -v "$candidate")" | |
| info "Trying $candidate for $ext" | |
| # Already installed? | |
| if "$cli" --list-extensions 2>/dev/null \ | |
| | grep -Fxiq "$ext" | |
| then | |
| ok "Extension already installed via $candidate: $ext" | |
| extension_cli_summary="$candidate" | |
| return 0 | |
| fi | |
| # Install | |
| if "$cli" \ | |
| --install-extension "$ext" \ | |
| >/dev/null 2>&1 | |
| then | |
| ok "Installed via $candidate: $ext" | |
| extension_cli_summary="$candidate" | |
| return 0 | |
| fi | |
| done | |
| # ------------------------------------------------------------------------- | |
| # Theia CLI | |
| # ------------------------------------------------------------------------- | |
| if command -v theia >/dev/null 2>&1 \ | |
| && theia --help 2>&1 \ | |
| | grep -q -- '--install-plugin' | |
| then | |
| cli="$(command -v theia)" | |
| info "Trying Theia for $ext" | |
| if "$cli" \ | |
| --install-plugin "$ext" \ | |
| >/dev/null 2>&1 | |
| then | |
| ok "Installed via Theia: $ext" | |
| extension_cli_summary="theia" | |
| return 0 | |
| fi | |
| fi | |
| return 1 | |
| } | |
| # ============================================================================= | |
| # 10. INSTALL EXTENSIONS | |
| # ============================================================================= | |
| installer_found=0 | |
| for candidate in \ | |
| code \ | |
| code-server \ | |
| codium \ | |
| openvscode-server \ | |
| theia | |
| do | |
| if command -v "$candidate" >/dev/null 2>&1; then | |
| installer_found=1 | |
| break | |
| fi | |
| done | |
| for ext in $EXTENSIONS | |
| do | |
| if try_install_extension "$ext"; then | |
| extension_ok=$((extension_ok + 1)) | |
| else | |
| warn "Could not auto-install extension: $ext" | |
| extension_fail=$((extension_fail + 1)) | |
| fi | |
| done | |
| if [ "$installer_found" -eq 0 ]; then | |
| warn "No supported extension CLI found." | |
| warn "Editor settings and terminal were still configured." | |
| warn "Extensions may need to be installed from the IDE Extensions UI." | |
| fi | |
| # ============================================================================= | |
| # 11. FINAL REPORT | |
| # ============================================================================= | |
| printf '\n' | |
| printf '========================================\n' | |
| printf ' Setup complete\n' | |
| printf '========================================\n' | |
| printf '\n' | |
| printf 'Settings targets : %s written/merged\n' \ | |
| "$settings_ok" | |
| printf 'Shell : configured\n' | |
| if [ "$extension_cli_summary" != "none" ]; then | |
| printf 'Extension CLI : %s\n' \ | |
| "$extension_cli_summary" | |
| else | |
| printf 'Extension CLI : unavailable/failed\n' | |
| fi | |
| printf 'Extensions : %s OK, %s failed\n' \ | |
| "$extension_ok" \ | |
| "$extension_fail" | |
| printf '\n' | |
| printf 'Configured editor behavior:\n' | |
| printf ' - Ctrl + Mouse Wheel zoom\n' | |
| printf ' - Ctrl+S saves + formats when formatter exists\n' | |
| printf ' - Ruff format/fix/import on save when Ruff extension exists\n' | |
| printf ' - Minimap disabled\n' | |
| printf ' - Sticky scroll enabled\n' | |
| printf ' - Smooth scrolling enabled\n' | |
| printf ' - Bracket and indentation guides enabled\n' | |
| printf ' - Dependency/cache folders excluded from watchers\n' | |
| printf ' - Dependency/cache folders excluded from search\n' | |
| printf ' - Trailing whitespace removed on save\n' | |
| printf ' - Final newline automatically inserted\n' | |
| printf '\n' | |
| printf 'Terminal:\n' | |
| printf ' [user: current-folder]$\n' | |
| printf '\n' | |
| printf 'If the currently-open browser IDE does not hot-reload settings,\n' | |
| printf 'refresh the browser tab once.\n' | |
| printf '\n' | |
| printf 'Load the updated shell config now with:\n' | |
| printf ' Bash: exec bash\n' | |
| if command -v zsh >/dev/null 2>&1; then | |
| printf ' Zsh : exec zsh\n' | |
| printf '\n' | |
| printf 'The default login shell was NOT changed automatically.\n' | |
| printf 'If you intentionally want Zsh as the default, run once:\n' | |
| printf ' chsh -s "$(command -v zsh)"\n' | |
| fi | |
| printf '\n' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment