Last active 2 weeks ago

Cross-platform Zsh setup scripts and managed dotfiles with Oh My Zsh framework, Starship prompt, aliases, functions, and path configuration.

Revision 00097cf0c3aec329a3e3be76a57456657da3ea25

README.md Raw

Bash Script Installer for Zsh

The "Bash Script Installer" simplifies the setup of Zsh.

Zsh

Ubuntu

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/zsh_ubuntu.sh)"

WSL

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/zsh_wsl.sh)"

MacOS

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/zsh_macos.sh)"

Configuration

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD/config.sh)"
alias Raw
1# =============================================================================
2# OS-SPECIFIC ALIASES
3# =============================================================================
4if [[ "$OSTYPE" == "linux-gnu"* ]] && command -v apt-get >/dev/null 2>&1; then
5 # Linux Only System update & cleanup
6 alias uu='sudo apt-get update && \
7 sudo apt-get upgrade -y && \
8 sudo apt-get full-upgrade -y && \
9 sudo apt-get autoremove -y && \
10 sudo apt-get autoclean -y && \
11 sudo apt-get clean'
12elif [[ "$OSTYPE" == "darwin"* ]]; then
13 # macOS Only
14 alias flushdns='sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder'
15fi
16
17# =============================================================================
18# UNIVERSAL GIT ALIASES (Fixed: Removed broken "$@" from aliases)
19# =============================================================================
20alias gph='git push'
21alias gco='git checkout'
22alias gbh='git branch'
23alias gmt='git commit'
24alias gpl='git pull'
25alias grb='git rebase'
26alias grt='git reset'
27alias gst='git status'
28alias grmrf='git checkout -- . && git clean -fd'
config.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# Configuration
5GIST_RAW_BASE="https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
6CONFIG_FILES=(
7 ".alias"
8 ".func"
9 ".pathrc"
10 ".sourcerc"
11 ".vimrc"
12 ".zshrc"
13)
14
15echo "Starting configuration download..."
16
17for f in "${CONFIG_FILES[@]}"; do
18 # Remove the leading dot for the URL path
19 remote_name="${f#.}"
20 url="$GIST_RAW_BASE/$remote_name"
21 target="$HOME/$f"
22
23 echo "Downloading $f..."
24
25 # Use -f to fail silently on server errors, -s for silent, -L to follow redirects
26 if curl -fsSL "$url" -o "$target"; then
27 echo "Successfully updated $target"
28 else
29 echo "Error: Failed to download $f from $url" >&2
30 fi
31done
32
33echo "Done! All configuration files have been replaced."
func Raw
1# =============================================================================
2# CUSTOM FUNCTIONS
3# =============================================================================
4
5# -----------------------------------------------------------------------------
6# Function: clip (Cross-platform clipboard)
7# -----------------------------------------------------------------------------
8clip() {
9 local cmd
10 local args=()
11
12 if command -v pbcopy >/dev/null 2>&1; then
13 cmd="pbcopy" # macOS
14 elif grep -qi "microsoft" /proc/version 2>/dev/null && command -v clip.exe >/dev/null 2>&1; then
15 cmd="clip.exe" # WSL
16 elif [ "$XDG_SESSION_TYPE" = "wayland" ] && command -v wl-copy >/dev/null 2>&1; then
17 cmd="wl-copy" # Linux Wayland
18 elif command -v xclip >/dev/null 2>&1; then
19 cmd="xclip" # Linux X11 (Fallback 1)
20 args=("-selection" "clipboard")
21 elif command -v xsel >/dev/null 2>&1; then
22 cmd="xsel" # Linux X11 (Fallback 2)
23 args=("--clipboard" "--input")
24 else
25 printf "Error: No supported clipboard utility found.\n" >&2
26 return 1
27 fi
28
29 if [ $# -gt 0 ]; then
30 if [ -f "$1" ]; then
31 "$cmd" "${args[@]}" < "$1"
32 echo "Copied contents of '$1' to clipboard."
33 else
34 printf "Error: File '%s' not found.\n" "$1" >&2
35 return 1
36 fi
37 else
38 "$cmd" "${args[@]}"
39 fi
40}
41
42# -----------------------------------------------------------------------------
43# Function: open_file (Cross-platform file/directory opener)
44# -----------------------------------------------------------------------------
45open_file() {
46 local target="${1:-.}"
47
48 if [[ "$OSTYPE" == "darwin"* ]]; then
49 command open "$target"
50 elif grep -qi "microsoft" /proc/version 2>/dev/null; then
51 if command -v wslpath >/dev/null 2>&1 && command -v explorer.exe >/dev/null 2>&1; then
52 explorer.exe "$(wslpath -w "$target")"
53 else
54 printf "Error: 'wslpath' or 'explorer.exe' not found.\n" >&2
55 return 1
56 fi
57 elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
58 if command -v xdg-open >/dev/null 2>&1; then
59 xdg-open "$target"
60 else
61 printf "Error: 'xdg-open' not found.\n" >&2
62 return 1
63 fi
64 fi
65}
66alias open='open_file'
67
68# -----------------------------------------------------------------------------
69# Function: clear_history (Supports shell and Claude)
70# -----------------------------------------------------------------------------
71# -----------------------------------------------------------------------------
72# Function: clear_history (Supports shell and Claude)
73# -----------------------------------------------------------------------------
74clear_history() {
75 case "$1" in
76 claude)
77 if [ -d "$HOME/.claude/projects" ]; then
78 # Use 'yes' to skip prompts and -f to ignore non-existent files
79 yes | rm -rf "$HOME/.claude/projects"/*
80 echo "Claude project history/cache cleared."
81 fi
82 ;;
83
84 *)
85 # 1. Truncate the file
86 : > "$HISTFILE"
87
88 # 2. Clear RAM by briefly setting history size to 0
89 local old_histsize=$HISTSIZE
90 HISTSIZE=0
91 HISTSIZE=$old_histsize
92
93 echo "Shell history cleared."
94 ;;
95 esac
96}
97
98# -----------------------------------------------------------------------------
99# Function: claude (Includes --yolo and clear shortcuts)
100# -----------------------------------------------------------------------------
101claude() {
102 # Shortcut for clearing cache
103 if [[ "$1" == "clear" ]]; then
104 clear_history claude
105 return 0
106 fi
107
108 # Check if binary exists
109 if ! whence -p claude >/dev/null 2>&1; then
110 printf "Error: 'claude' CLI is not installed or not in your PATH.\n" >&2
111 return 1
112 fi
113
114 # Handle --yolo mode
115 if [[ "$1" == "--yolo" ]]; then
116 shift
117 command claude --dangerously-skip-permissions "$@"
118 return $?
119 fi
120
121 command claude "$@"
122}
123
124# -----------------------------------------------------------------------------
125# Function: create (Efficiently create file + parent dirs)
126# -----------------------------------------------------------------------------
127create() {
128 if ! command -v install >/dev/null 2>&1; then
129 printf "Error: 'install' coreutil is not available.\n" >&2
130 return 1
131 fi
132
133 if [ $# -eq 0 ]; then
134 printf "Usage: create <file> [file ...]\n" >&2
135 return 2
136 fi
137
138 for p in "$@"; do
139 # Expand tilde manually if shell doesn't
140 [[ "$p" == "~/"* ]] && p="${HOME}/${p#\~/}"
141
142 if [ -z "$p" ] || [ "$p" = "/" ]; then
143 printf "create: refusing to operate on '%s'\n" "$p" >&2
144 continue
145 fi
146
147 if [ -e "$p" ]; then
148 printf "create: '%s' already exists. Skipping.\n" "$p" >&2
149 continue
150 fi
151
152 if install -D /dev/null "$p"; then
153 echo "Created '$p'"
154 fi
155 done
156}
157
158# -----------------------------------------------------------------------------
159# Function: check_port
160# -----------------------------------------------------------------------------
161check_port() {
162 local PORT=$1
163 if [ -z "$PORT" ]; then
164 printf "Usage: check_port <port_number>\n" >&2
165 return 1
166 fi
167
168 if [[ "$OSTYPE" == "darwin"* ]]; then
169 lsof -i :"$PORT" || echo "Port $PORT is FREE"
170 else
171 sudo ss -tulnp | grep ":$PORT " || echo "Port $PORT is FREE"
172 fi
173}
174
175# -----------------------------------------------------------------------------
176# Function: append_path (Adds to session PATH if exists)
177# -----------------------------------------------------------------------------
178append_path() {
179 local dir="$1"
180 if [ -d "$dir" ]; then
181 case ":$PATH:" in
182 *":$dir:"*) ;;
183 *) PATH="$PATH:$dir" ;;
184 esac
185 elif [ "${SUPPRESS_WARNINGS:-0}" -ne 1 ]; then
186 echo "Warning: $dir does not exist." >&2
187 fi
188}
189
190# -----------------------------------------------------------------------------
191# Function: add_path_to_config (Fixed awk/sed injection)
192# -----------------------------------------------------------------------------
193add_path_to_config() {
194 local new_path="$1"
195 local config_file="$HOME/.bashrc"
196 [[ "$SHELL" == *"zsh"* ]] && config_file="$HOME/.zshrc"
197
198 if [ -z "$new_path" ]; then
199 printf "Usage: add_path_to_config <directory>\n" >&2
200 return 1
201 fi
202
203 new_path="${new_path/#\~/$HOME}"
204
205 if [ ! -d "$new_path" ]; then
206 printf "Warning: '%s' does not exist. Add anyway? (y/N) " "$new_path"
207 read -r REPLY
208 [[ ! $REPLY =~ ^[Yy]$ ]] && return 1
209 fi
210
211 # Check if already exists in file
212 if grep -Fq "append_path \"$new_path\"" "$config_file"; then
213 printf "Notice: Already in %s.\n" "$config_file"
214 return 0
215 fi
216
217 # Robust Injection: Use sed to insert before export PATH or just append
218 if grep -q "^export PATH" "$config_file"; then
219 sed -i.bak "/^export PATH/i append_path \"$new_path\"" "$config_file"
220 else
221 echo "append_path \"$new_path\"" >> "$config_file"
222 echo "export PATH" >> "$config_file"
223 fi
224
225 printf "✅ Success: Added to %s\n" "$config_file"
226 append_path "$new_path" && export PATH
227}
pathrc Raw
1# =============================================================================
2# ENVIRONMENT & PATH CONFIGURATION
3# =============================================================================
4
5# 1. Source functions first
6if [[ -f "$HOME/.func" && -r "$HOME/.func" ]]; then
7 source "$HOME/.func"
8fi
9
10# 2. Define Root Variables
11export DOTNET_ROOT="$HOME/.dotnet"
12
13# 3. PATH INITIALIZATION
14# -----------------------------------------------------------------------------
15append_path "$HOME/.local/bin"
16append_path "$DOTNET_ROOT"
17append_path "$DOTNET_ROOT/tools"
18append_path "$HOME/.opencode/bin"
19append_path "$HOME/Flutter/bin"
20
21# macOS specific paths
22if [[ "$OSTYPE" == "darwin"* ]]; then
23 append_path "/Applications/Espanso.app/Contents/MacOS"
24fi
25
26# Finalize PATH
27export PATH
sourcerc Raw
1# =============================================================================
2# FILE: ~/.sourcerc
3# Description: Initializes third-party package managers and Oh My Zsh.
4# =============================================================================
5
6# Source the custom environment setup file if it exists and is not empty
7if [[ -f "$HOME/.local/bin/env" && -r "$HOME/.local/bin/env" ]]; then
8 source "$HOME/.local/bin/env"
9fi
10
11# Source the SDKMAN initialization script if it exists and is not empty
12if [[ -f "$HOME/.sdkman/bin/sdkman-init.sh" && -r "$HOME/.sdkman/bin/sdkman-init.sh" ]]; then
13 source "$HOME/.sdkman/bin/sdkman-init.sh"
14fi
15
16# Source the NVM initialization script if it exists and is not empty
17if [[ -f "$HOME/.nvm/nvm.sh" && -r "$HOME/.nvm/nvm.sh" ]]; then
18 source "$HOME/.nvm/nvm.sh"
19fi
20
21# =============================================================================
22# CLAUDE CODE / AI GATEWAY
23# =============================================================================
24export ANTHROPIC_BASE_URL="https://gateway.ai.cloudflare.com/v1/9a71825e3842e918e0dff9ad84f50484/claude-code-gateway/anthropic"
25
26# =============================================================================
27# OH MY ZSH
28# =============================================================================
29if [[ -f "$HOME/.oh-my-zsh/oh-my-zsh.sh" && -r "$HOME/.oh-my-zsh/oh-my-zsh.sh" ]]; then
30 source "$HOME/.oh-my-zsh/oh-my-zsh.sh"
31else
32 echo "Warning: Oh My Zsh not found or is empty."
33fi
34
35# =============================================================================
36# GOOGLE CLOUD SDK
37# =============================================================================
38if [[ -f "$HOME/google-cloud-sdk/path.zsh.inc" ]]; then
39 source "$HOME/google-cloud-sdk/path.zsh.inc"
40fi
41
42if [[ -f "$HOME/google-cloud-sdk/completion.zsh.inc" ]]; then
43 source "$HOME/google-cloud-sdk/completion.zsh.inc"
44fi
45
46# =============================================================================
47# NVM (Node Version Manager)
48# =============================================================================
49export NVM_DIR="$HOME/.nvm"
50
51[[ -f "$NVM_DIR/nvm.sh" && -r "$NVM_DIR/nvm.sh" ]] && \. "$NVM_DIR/nvm.sh"
52[[ -f "$NVM_DIR/bash_completion" && -r "$NVM_DIR/bash_completion" ]] && \. "$NVM_DIR/bash_completion"
vimrc Raw
1" Enable line numbers
2set number
3
4" Enable relative line numbers
5set relativenumber
6
7" Enable syntax highlighting
8syntax on
9
10" Set colorscheme
11colorscheme slate
12
13" Enable file type detection and plugins
14filetype plugin indent on
15
16" Set the tab width to 4 spaces
17set tabstop=4
18set shiftwidth=4
19set expandtab
20
21" Enable auto-indentation
22set autoindent
23set smartindent
24
25" Highlight current line
26set cursorline
27
28" Show matching parentheses
29set showmatch
30
31" Enable line wrapping
32set wrap
33
34" Enable mouse support
35set mouse=a
36
37" Enable clipboard access
38set clipboard=unnamedplus
39
40" Disable swap file
41set noswapfile
42
43" Enable incremental search
44set incsearch
45
46" Ignore case in search
47set ignorecase
48
49" Override ignorecase if search contains capital letters
50set smartcase
51
52" Display line and column number of the cursor position
53set ruler
54
55" Set the status line at the bottom
56set laststatus=2
57
58" Show command in bottom bar
59set showcmd
60
61" Set command height
62set cmdheight=2
63
64" Set history lines
65set history=1000
66
67" Disable backup file
68set nobackup
69
70" Enable persistent undo
71set undofile
72
73" Set maximum number of undo levels
74set undolevels=1000
75
76" Set undo directory
77if has("persistent_undo")
78 silent !mkdir ~/.vim/undodir > /dev/null 2>&1
79 set undodir=~/.vim/undodir
80endif
81
82" Set search highlighting
83set hlsearch
84
85" Enable visual bell
86set visualbell
87
88" Set default file encoding
89set encoding=utf-8
90
91" Set the leader key to space
92let mapleader = " "
93
94" Map <Leader>w to save the file
95nnoremap <Leader>w :w<CR>
96
97" Map <Leader>q to quit
98nnoremap <Leader>q :q<CR>
99
100" Map <Leader>x to save and quit
101nnoremap <Leader>x :wq<CR>
102
103" Enable folding
104set foldmethod=syntax
105set foldlevelstart=99
106
107" Enable line wrapping at 80 characters
108set textwidth=80
109set colorcolumn=80
110
111" Add some basic key mappings
112" Map jj to escape insert mode
113inoremap jj <Esc>
114
115" Map <Leader>n to toggle line numbers
116nnoremap <Leader>n :set number!<CR>
117
118" Map <Leader>r to toggle relative line numbers
119nnoremap <Leader>r :set relativenumber!<CR>
120
121" Configure plugins (if you use a plugin manager like vim-plug)
122" Example with vim-plug:
123" call plug#begin('~/.vim/plugged')
124" Plug 'tpope/vim-sensible'
125" Plug 'preservim/nerdtree'
126" Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
127" Plug 'airblade/vim-gitgutter'
128" call plug#end()
129
130" NERDTree key mappings
131" nnoremap <C-n> :NERDTreeToggle<CR>
132
133" Enable automatic hard wrapping at textwidth (80 chars)
134set formatoptions+=t " Auto-wrap text using textwidth
135set formatoptions+=c " Auto-wrap comments using textwidth
136set formatoptions+=r " Continue comments when pressing Enter
137set formatoptions+=o " Continue comments when using 'o' or 'O'
138set formatoptions+=q " Allow formatting of comments with 'gq'
139set formatoptions+=n " Recognize numbered lists
140set formatoptions+=l " Don't break lines that were already long
141
142" Enable syntax highlighting
143syntax on
144
145" Increase memory limit for complex syntax parsing (Prevents E363)
146set maxmempattern=20000
zsh_macos.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# CONFIG
20# =============================
21GIST_RAW_BASE="https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
22
23CONFIG_FILES=(
24 ".alias"
25 ".func"
26 ".pathrc"
27 ".sourcerc"
28 ".vimrc"
29 ".zshrc"
30)
31
32# =============================
33# REQUIREMENTS
34# =============================
35check_requirements() {
36 if [[ $EUID -eq 0 ]]; then
37 err "Do not run as root on macOS"
38 exit 1
39 fi
40}
41
42# =============================
43# INSTALLATION FUNCTIONS
44# =============================
45install_oh_my_zsh() {
46 if [[ -d "$HOME/.oh-my-zsh" ]]; then
47 ok "Oh My Zsh already installed"
48 return
49 fi
50
51 log "Installing Oh My Zsh..."
52 RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
53 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
54 ok "Oh My Zsh installed"
55}
56
57install_plugins() {
58 log "Installing plugins..."
59 local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins"
60 mkdir -p "$dir"
61
62 [[ -d "$dir/zsh-autosuggestions" ]] || \
63 git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions"
64
65 [[ -d "$dir/zsh-syntax-highlighting" ]] || \
66 git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting"
67
68 ok "Plugins installed"
69}
70
71install_theme() {
72 log "Installing Spaceship theme..."
73 local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes"
74 local dir="$themes/spaceship-prompt"
75
76 mkdir -p "$themes"
77 [[ -d "$dir" ]] || \
78 git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1
79
80 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme"
81 ok "Theme installed"
82}
83
84download_configs() {
85 log "Downloading custom config files..."
86 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
87 mkdir -p "$backup"
88
89 for f in "${CONFIG_FILES[@]}"; do
90 # Strip the leading dot for the download URL
91 local remote_file="${f#.}"
92 local url="$GIST_RAW_BASE/$remote_file"
93 local target="$HOME/$f"
94 local tmp="${target}.tmp.$$"
95
96 if [[ -f "$target" ]]; then
97 cp "$target" "$backup/"
98 fi
99
100 log "Fetching $remote_file -> $f ..."
101 if curl -fsSL "$url" -o "$tmp"; then
102 mv "$tmp" "$target"
103 else
104 rm -f "$tmp"
105 warn "Failed to download $remote_file"
106 fi
107 done
108
109 ok "Configs downloaded (Backup at $backup)"
110}
111
112update_zshrc() {
113 local zshrc="$HOME/.zshrc"
114 log "Checking .zshrc..."
115
116 if [[ ! -f "$zshrc" ]]; then
117 warn ".zshrc not found. Run option 5 first."
118 return 1
119 fi
120
121 ok ".zshrc already comes from the managed gist."
122 ok "Load order is built in: .sourcerc -> .func -> .pathrc -> .alias"
123}
124
125switch_shell() {
126 log "Starting Zsh session..."
127 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
128 echo "----------------------------------------"
129 zsh -l
130 echo "----------------------------------------"
131 ok "Returned from Zsh session"
132}
133
134# =============================
135# INTERACTIVE MENU
136# =============================
137show_menu() {
138 echo "==========================================="
139 echo "macOS Zsh Setup - Choose what to do"
140 echo "==========================================="
141 echo " 0) Run ALL steps (1-7)"
142 echo " 1) Install Oh My Zsh"
143 echo " 2) Install plugins (autosuggestions, syntax highlighting)"
144 echo " 3) Install Spaceship theme"
145 echo " 4) Download custom configs (~/.alias, .func, .vimrc, etc.)"
146 echo " 5) Check ~/.zshrc load order"
147 echo " 6) Switch to Zsh (Temporary Sub-shell)"
148 echo " 7) Quit"
149 echo "==========================================="
150}
151
152run_choices() {
153 local input
154 read -p "Select: " input
155 input="${input//,/ }"
156
157 local -a to_run=()
158 local -a to_exclude=()
159
160 for item in $input; do
161 if [[ "$item" == !* ]]; then
162 to_exclude+=("${item:1}")
163 elif [[ "$item" == "0" ]]; then
164 to_run+=(1 2 3 4 5 6)
165 else
166 to_run+=("$item")
167 fi
168 done
169
170 if [[ ${#to_run[@]} -gt 0 ]]; then
171 for choice in "${to_run[@]}"; do
172 local skip=false
173
174 if [[ ${#to_exclude[@]} -gt 0 ]]; then
175 for ex in "${to_exclude[@]}"; do
176 if [[ "$choice" == "$ex" ]]; then
177 skip=true
178 break
179 fi
180 done
181 fi
182
183 $skip && continue
184
185 case "$choice" in
186 1) install_oh_my_zsh ;;
187 2) install_plugins ;;
188 3) install_theme ;;
189 4) download_configs ;;
190 5) update_zshrc ;;
191 6) switch_shell ;;
192 7) exit 0 ;;
193 *) warn "Skipping invalid option: $choice" ;;
194 esac
195 echo
196 done
197 fi
198}
199
200# =============================
201# MAIN
202# =============================
203main() {
204 check_requirements
205 while true; do
206 show_menu
207 run_choices
208 read -p "Do you want to run more options? (y/n): " again
209 [[ "$again" =~ ^[Yy]$ ]] || break
210 done
211 ok "macOS configuration complete!"
212}
213
214main "$@"
zsh_ubuntu.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# FLAGS & CONFIG
20# =============================
21SKIP_PACKAGES=false
22SKIP_SHELL_CHANGE=false
23INSTALL_HOMEBREW=false
24
25GIST_RAW_BASE="https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
26CONFIG_FILES=(
27 ".alias"
28 ".func"
29 ".pathrc"
30 ".sourcerc"
31 ".vimrc"
32 ".zshrc"
33)
34
35# =============================
36# OS DETECTION
37# =============================
38detect_os() {
39 if [ -f /etc/os-release ]; then
40 . /etc/os-release
41 echo "$ID"
42 else
43 echo "unknown"
44 fi
45}
46
47# =============================
48# REQUIREMENTS
49# =============================
50check_requirements() {
51 if [[ $EUID -eq 0 ]]; then
52 err "Do not run as root"
53 exit 1
54 fi
55 if ! command -v sudo >/dev/null 2>&1; then
56 err "sudo required"
57 exit 1
58 fi
59}
60
61# =============================
62# INSTALLATION FUNCTIONS
63# =============================
64update_system() {
65 $SKIP_PACKAGES && return
66 log "Updating system..."
67 sudo apt-get update -y
68 sudo apt-get upgrade -y
69 ok "System updated"
70}
71
72install_packages() {
73 $SKIP_PACKAGES && return
74 log "Installing core packages..."
75 sudo apt-get install -y \
76 zsh git vim curl wget unzip zip build-essential xz-utils
77 ok "Packages installed"
78}
79
80set_timezone() {
81 log "Setting timezone to Asia/Singapore..."
82 sudo timedatectl set-timezone Asia/Singapore
83 ok "Timezone set to Asia/Singapore"
84}
85
86install_homebrew() {
87 ! $INSTALL_HOMEBREW && return
88 command -v brew >/dev/null 2>&1 && ok "Homebrew already installed" && return
89 log "Installing Homebrew..."
90 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
91 ok "Homebrew installed"
92}
93
94configure_shell() {
95 $SKIP_SHELL_CHANGE && return
96 log "Changing default shell to zsh..."
97 local zsh_path
98 zsh_path="$(command -v zsh)"
99 grep -qx "$zsh_path" /etc/shells || echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
100 chsh -s "$zsh_path"
101 ok "Shell changed (requires logout/login to take effect)"
102}
103
104install_oh_my_zsh() {
105 [[ -d "$HOME/.oh-my-zsh" ]] && ok "Oh My Zsh already installed" && return
106 log "Installing Oh My Zsh..."
107 RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
108 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
109 ok "Oh My Zsh installed"
110}
111
112install_plugins() {
113 log "Installing plugins..."
114 local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins"
115 mkdir -p "$dir"
116 [[ -d "$dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions"
117 [[ -d "$dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting"
118 ok "Plugins installed"
119}
120
121install_theme() {
122 log "Installing Spaceship theme..."
123 local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes"
124 local dir="$themes/spaceship-prompt"
125 mkdir -p "$themes"
126 [[ -d "$dir" ]] || git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1
127 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme"
128 ok "Theme installed"
129}
130
131download_configs() {
132 log "Downloading custom config files..."
133 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
134 mkdir -p "$backup"
135
136 for f in "${CONFIG_FILES[@]}"; do
137 # Strip the leading dot for the download URL
138 local remote_file="${f#.}"
139 local url="$GIST_RAW_BASE/$remote_file"
140 local target="$HOME/$f"
141 local tmp="${target}.tmp.$$"
142
143 if [[ -f "$target" ]]; then
144 cp "$target" "$backup/"
145 fi
146
147 log "Fetching $remote_file -> $f ..."
148 if curl -fsSL "$url" -o "$tmp"; then
149 mv "$tmp" "$target"
150 else
151 rm -f "$tmp"
152 warn "Failed to download $remote_file"
153 fi
154 done
155
156 ok "Configs downloaded (Backup at $backup)"
157}
158
159update_zshrc() {
160 local zshrc="$HOME/.zshrc"
161 log "Checking .zshrc..."
162
163 if [[ ! -f "$zshrc" ]]; then
164 warn ".zshrc not found. Run option 9 first."
165 return 1
166 fi
167
168 ok ".zshrc already comes from the managed gist."
169 ok "Load order is built in: .sourcerc -> .func -> .pathrc -> .alias"
170}
171
172switch_shell() {
173 log "Starting Zsh session..."
174 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
175 echo "----------------------------------------"
176 zsh -l
177 echo "----------------------------------------"
178 ok "Returned from Zsh session"
179}
180
181# =============================
182# INTERACTIVE MENU
183# =============================
184show_menu() {
185 echo "==========================================="
186 echo "Zsh Installer - Choose what to do"
187 echo "==========================================="
188 echo " 0) Run ALL steps (1-11)"
189 echo " 1) Update system packages"
190 echo " 2) Install core packages (zsh, git, vim, etc.)"
191 echo " 3) Set Timezone (Asia/Singapore)"
192 echo " 4) Install Homebrew"
193 echo " 5) Configure shell (chsh - sets default shell)"
194 echo " 6) Install Oh My Zsh"
195 echo " 7) Install plugins (autosuggestions, syntax highlighting)"
196 echo " 8) Install Spaceship theme"
197 echo " 9) Download custom configs (~/.alias, .vimrc, etc.)"
198 echo "10) Check ~/.zshrc load order"
199 echo "11) Switch to Zsh (Temporary Sub-shell)"
200 echo "12) Quit"
201 echo "==========================================="
202}
203
204run_choices() {
205 local input
206 read -p "Select: " input
207 input="${input//,/ }"
208
209 local -a to_run=()
210 local -a to_exclude=()
211
212 for item in $input; do
213 if [[ "$item" == !* ]]; then
214 to_exclude+=("${item:1}")
215 elif [[ "$item" == "0" ]]; then
216 to_run+=(1 2 3 4 5 6 7 8 9 10 11)
217 else
218 to_run+=("$item")
219 fi
220 done
221
222 for choice in "${to_run[@]}"; do
223 local skip=false
224
225 for ex in "${to_exclude[@]}"; do
226 if [[ "$choice" == "$ex" ]]; then
227 skip=true
228 break
229 fi
230 done
231
232 $skip && continue
233
234 case "$choice" in
235 1) update_system ;;
236 2) install_packages ;;
237 3) set_timezone ;;
238 4) install_homebrew ;;
239 5) configure_shell ;;
240 6) install_oh_my_zsh ;;
241 7) install_plugins ;;
242 8) install_theme ;;
243 9) download_configs ;;
244 10) update_zshrc ;;
245 11) switch_shell ;;
246 12) log "Exiting..."; exit 0 ;;
247 *) warn "Skipping invalid option: $choice" ;;
248 esac
249 echo
250 done
251}
252
253# =============================
254# MAIN
255# =============================
256main() {
257 check_requirements
258 while true; do
259 show_menu
260 run_choices
261 read -p "Do you want to run more options? (y/n): " again
262 [[ "$again" =~ ^[Yy]$ ]] || break
263 done
264 ok "Zsh installation/configuration complete!"
265}
266
267main "$@"
zsh_wsl.sh Raw
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# FLAGS & CONFIG
20# =============================
21SKIP_PACKAGES=false
22SKIP_SHELL_CHANGE=false
23INSTALL_HOMEBREW=false
24
25GIST_RAW_BASE="https://opengist.rmrf.online/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
26CONFIG_FILES=(
27 ".alias"
28 ".func"
29 ".pathrc"
30 ".sourcerc"
31 ".vimrc"
32 ".zshrc"
33)
34
35# =============================
36# PLATFORM DETECTION
37# =============================
38detect_os() {
39 if [ -f /etc/os-release ]; then
40 . /etc/os-release
41 echo "$ID"
42 else
43 echo "unknown"
44 fi
45}
46
47is_wsl() {
48 grep -qi "microsoft" /proc/version 2>/dev/null
49}
50
51# =============================
52# REQUIREMENTS
53# =============================
54check_requirements() {
55 if [[ $EUID -eq 0 ]]; then
56 err "Do not run as root"
57 exit 1
58 fi
59 if ! command -v sudo >/dev/null 2>&1; then
60 err "sudo required"
61 exit 1
62 fi
63 if ! is_wsl; then
64 err "This installer is intended for WSL"
65 exit 1
66 fi
67}
68
69# =============================
70# INSTALLATION FUNCTIONS
71# =============================
72update_system() {
73 $SKIP_PACKAGES && return
74 log "Updating system..."
75 sudo apt-get update -y
76 sudo apt-get upgrade -y
77 ok "System updated"
78}
79
80install_packages() {
81 $SKIP_PACKAGES && return
82 log "Installing core packages..."
83 sudo apt-get install -y \
84 zsh git vim curl wget unzip zip build-essential xz-utils
85 ok "Packages installed"
86}
87
88set_timezone() {
89 log "Checking timezone configuration..."
90 if command -v timedatectl >/dev/null 2>&1 && timedatectl status >/dev/null 2>&1; then
91 sudo timedatectl set-timezone Asia/Singapore
92 ok "Timezone set to Asia/Singapore"
93 return
94 fi
95
96 warn "Skipping timezone change: timedatectl is not available in this WSL environment"
97}
98
99install_homebrew() {
100 ! $INSTALL_HOMEBREW && return
101 command -v brew >/dev/null 2>&1 && ok "Homebrew already installed" && return
102 log "Installing Homebrew..."
103 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
104 ok "Homebrew installed"
105}
106
107configure_shell() {
108 $SKIP_SHELL_CHANGE && return
109 log "Changing default shell to zsh..."
110 local zsh_path
111 zsh_path="$(command -v zsh)"
112 grep -qx "$zsh_path" /etc/shells || echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
113 chsh -s "$zsh_path"
114 ok "Shell changed (open a new WSL session for it to take effect)"
115}
116
117install_oh_my_zsh() {
118 [[ -d "$HOME/.oh-my-zsh" ]] && ok "Oh My Zsh already installed" && return
119 log "Installing Oh My Zsh..."
120 RUNZSH=no CHSH=no KEEP_ZSHRC=yes \
121 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
122 ok "Oh My Zsh installed"
123}
124
125install_plugins() {
126 log "Installing plugins..."
127 local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins"
128 mkdir -p "$dir"
129 [[ -d "$dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions"
130 [[ -d "$dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting"
131 ok "Plugins installed"
132}
133
134install_theme() {
135 log "Installing Spaceship theme..."
136 local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes"
137 local dir="$themes/spaceship-prompt"
138 mkdir -p "$themes"
139 [[ -d "$dir" ]] || git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1
140 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme"
141 ok "Theme installed"
142}
143
144download_configs() {
145 log "Downloading custom config files..."
146 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
147 mkdir -p "$backup"
148
149 for f in "${CONFIG_FILES[@]}"; do
150 # Strip the leading dot for the download URL
151 local remote_file="${f#.}"
152 local url="$GIST_RAW_BASE/$remote_file"
153 local target="$HOME/$f"
154 local tmp="${target}.tmp.$$"
155
156 if [[ -f "$target" ]]; then
157 cp "$target" "$backup/"
158 fi
159
160 log "Fetching $remote_file -> $f ..."
161 if curl -fsSL "$url" -o "$tmp"; then
162 mv "$tmp" "$target"
163 else
164 rm -f "$tmp"
165 warn "Failed to download $remote_file"
166 fi
167 done
168
169 ok "Configs downloaded (Backup at $backup)"
170}
171
172update_zshrc() {
173 local zshrc="$HOME/.zshrc"
174 log "Checking .zshrc..."
175
176 if [[ ! -f "$zshrc" ]]; then
177 warn ".zshrc not found. Run option 9 first."
178 return 1
179 fi
180
181 ok ".zshrc already comes from the managed gist."
182 ok "Load order is built in: .sourcerc -> .func -> .pathrc -> .alias"
183}
184
185switch_shell() {
186 log "Starting Zsh session..."
187 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
188 echo "----------------------------------------"
189 zsh -l
190 echo "----------------------------------------"
191 ok "Returned from Zsh session"
192}
193
194# =============================
195# INTERACTIVE MENU
196# =============================
197show_menu() {
198 echo "==========================================="
199 echo "WSL Zsh Installer - Choose what to do"
200 echo "==========================================="
201 echo " 0) Run ALL steps (1-11)"
202 echo " 1) Update system packages"
203 echo " 2) Install core packages (zsh, git, vim, etc.)"
204 echo " 3) Set Timezone (best effort)"
205 echo " 4) Install Homebrew"
206 echo " 5) Configure shell (chsh - sets default shell)"
207 echo " 6) Install Oh My Zsh"
208 echo " 7) Install plugins (autosuggestions, syntax highlighting)"
209 echo " 8) Install Spaceship theme"
210 echo " 9) Download custom configs (~/.alias, .vimrc, etc.)"
211 echo "10) Check ~/.zshrc load order"
212 echo "11) Switch to Zsh (Temporary Sub-shell)"
213 echo "12) Quit"
214 echo "==========================================="
215}
216
217run_choices() {
218 local input
219 read -p "Select: " input
220 input="${input//,/ }"
221
222 local -a to_run=()
223 local -a to_exclude=()
224
225 for item in $input; do
226 if [[ "$item" == !* ]]; then
227 to_exclude+=("${item:1}")
228 elif [[ "$item" == "0" ]]; then
229 to_run+=(1 2 3 4 5 6 7 8 9 10 11)
230 else
231 to_run+=("$item")
232 fi
233 done
234
235 for choice in "${to_run[@]}"; do
236 local skip=false
237
238 for ex in "${to_exclude[@]}"; do
239 if [[ "$choice" == "$ex" ]]; then
240 skip=true
241 break
242 fi
243 done
244
245 $skip && continue
246
247 case "$choice" in
248 1) update_system ;;
249 2) install_packages ;;
250 3) set_timezone ;;
251 4) install_homebrew ;;
252 5) configure_shell ;;
253 6) install_oh_my_zsh ;;
254 7) install_plugins ;;
255 8) install_theme ;;
256 9) download_configs ;;
257 10) update_zshrc ;;
258 11) switch_shell ;;
259 12) log "Exiting..."; exit 0 ;;
260 *) warn "Skipping invalid option: $choice" ;;
261 esac
262 echo
263 done
264}
265
266# =============================
267# MAIN
268# =============================
269main() {
270 check_requirements
271 while true; do
272 show_menu
273 run_choices
274 read -p "Do you want to run more options? (y/n): " again
275 [[ "$again" =~ ^[Yy]$ ]] || break
276 done
277 ok "WSL Zsh installation/configuration complete!"
278}
279
280main "$@"
zshrc Raw
1# =============================================================================
2# 1. ZSH THEME & PLUGINS (Must be defined before Oh My Zsh loads)
3# =============================================================================
4export ZSH="$HOME/.oh-my-zsh"
5
6source_if_readable() {
7 local file="$1"
8 if [[ -f "$file" && -r "$file" ]]; then
9 source "$file"
10 fi
11}
12
13ZSH_THEME="spaceship"
14
15SPACESHIP_PROMPT_ORDER=(
16 time # Time stamps section
17 user # Username section
18 dir # Current directory section
19 git # Git section (git_branch + git_status)
20 node # Node.js section
21 dotnet # .NET section
22 java # Java section
23 kotlin # Kotlin section
24 ruby # Ruby section
25 xcode # Xcode section
26 swift # Swift section
27 golang # Go section
28 docker # Docker section
29 venv # virtualenv section
30 line_sep # Line break
31 char # Prompt character
32)
33
34SPACESHIP_USER_SHOW=always
35SPACESHIP_PROMPT_SEPARATE_LINE=true
36SPACESHIP_PROMPT_ADD_NEWLINE=true
37SPACESHIP_CHAR_SYMBOL="❯"
38SPACESHIP_CHAR_SUFFIX=" "
39SPACESHIP_DOCKER_CONTEXT_SHOW=false
40
41if [[ $(uname) == "Darwin" ]]; then
42 #  is the Apple logo in Nerd Fonts
43 SPACESHIP_USER_SUFFIX="%F{cyan} [  ]%f "
44elif [[ $(uname) == "Linux" ]]; then
45 #  is the Ubuntu logo in Nerd Fonts
46 SPACESHIP_USER_SUFFIX="%F{yellow} [  ]%f "
47else
48 SPACESHIP_USER_SUFFIX=" "
49fi
50
51plugins=(git zsh-syntax-highlighting zsh-autosuggestions)
52
53# Initialize Oh My Zsh (Crucial for themes and plugins to work)
54source_if_readable "$ZSH/oh-my-zsh.sh"
55
56# =============================================================================
57# 2. THIRD-PARTY INITIALIZATION (SDKMAN, NVM, Oh My Zsh)
58# =============================================================================
59source_if_readable "$HOME/.sourcerc"
60
61# =============================================================================
62# 3. CUSTOM OVERRIDES (Functions must load before Path Management)
63# =============================================================================
64source_if_readable "$HOME/.func"
65
66# =============================================================================
67# 4. PATH MANAGEMENT (Relies on append_path from .func)
68# =============================================================================
69source_if_readable "$HOME/.pathrc"
70
71# =============================================================================
72# 5. ALIASES (Loaded dead last so YOUR code always wins over Oh My Zsh)
73# =============================================================================
74source_if_readable "$HOME/.alias"
75