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 49422edc20c99d40968dc7cef96a719277bd519f

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)"
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'
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# -----------------------------------------------------------------------------
71clear_history() {
72 case "$1" in
73 claude)
74 if [ -d "$HOME/.claude/projects" ]; then
75 rm -rf "$HOME/.claude/projects"/*
76 echo "Claude project history/cache cleared."
77 fi
78 ;;
79
80 *)
81 # 1. Truncate the file
82 : > "$HISTFILE"
83
84 # 2. Clear RAM by briefly setting history size to 0
85 # This is the most reliable way to clear Zsh RAM without hanging
86 local old_histsize=$HISTSIZE
87 HISTSIZE=0
88 HISTSIZE=$old_histsize
89
90 echo "Shell history cleared."
91 ;;
92 esac
93}
94
95# -----------------------------------------------------------------------------
96# Function: claude (Includes --yolo and clear shortcuts)
97# -----------------------------------------------------------------------------
98claude() {
99 # Shortcut for clearing cache
100 if [[ "$1" == "clear" ]]; then
101 clear_history claude
102 return 0
103 fi
104
105 # Check if binary exists
106 if ! whence -p claude >/dev/null 2>&1; then
107 printf "Error: 'claude' CLI is not installed or not in your PATH.\n" >&2
108 return 1
109 fi
110
111 # Handle --yolo mode
112 if [[ "$1" == "--yolo" ]]; then
113 shift
114 command claude --dangerously-skip-permissions "$@"
115 return $?
116 fi
117
118 command claude "$@"
119}
120
121# -----------------------------------------------------------------------------
122# Function: create (Efficiently create file + parent dirs)
123# -----------------------------------------------------------------------------
124create() {
125 if ! command -v install >/dev/null 2>&1; then
126 printf "Error: 'install' coreutil is not available.\n" >&2
127 return 1
128 fi
129
130 if [ $# -eq 0 ]; then
131 printf "Usage: create <file> [file ...]\n" >&2
132 return 2
133 fi
134
135 for p in "$@"; do
136 # Expand tilde manually if shell doesn't
137 [[ "$p" == "~/"* ]] && p="${HOME}/${p#\~/}"
138
139 if [ -z "$p" ] || [ "$p" = "/" ]; then
140 printf "create: refusing to operate on '%s'\n" "$p" >&2
141 continue
142 fi
143
144 if [ -e "$p" ]; then
145 printf "create: '%s' already exists. Skipping.\n" "$p" >&2
146 continue
147 fi
148
149 if install -D /dev/null "$p"; then
150 echo "Created '$p'"
151 fi
152 done
153}
154
155# -----------------------------------------------------------------------------
156# Function: check_port
157# -----------------------------------------------------------------------------
158check_port() {
159 local PORT=$1
160 if [ -z "$PORT" ]; then
161 printf "Usage: check_port <port_number>\n" >&2
162 return 1
163 fi
164
165 if [[ "$OSTYPE" == "darwin"* ]]; then
166 lsof -i :"$PORT" || echo "Port $PORT is FREE"
167 else
168 sudo ss -tulnp | grep ":$PORT " || echo "Port $PORT is FREE"
169 fi
170}
171
172# -----------------------------------------------------------------------------
173# Function: append_path (Adds to session PATH if exists)
174# -----------------------------------------------------------------------------
175append_path() {
176 local dir="$1"
177 if [ -d "$dir" ]; then
178 case ":$PATH:" in
179 *":$dir:"*) ;;
180 *) PATH="$PATH:$dir" ;;
181 esac
182 elif [ "${SUPPRESS_WARNINGS:-0}" -ne 1 ]; then
183 echo "Warning: $dir does not exist." >&2
184 fi
185}
186
187# -----------------------------------------------------------------------------
188# Function: add_path_to_config (Fixed awk/sed injection)
189# -----------------------------------------------------------------------------
190add_path_to_config() {
191 local new_path="$1"
192 local config_file="$HOME/.bashrc"
193 [[ "$SHELL" == *"zsh"* ]] && config_file="$HOME/.zshrc"
194
195 if [ -z "$new_path" ]; then
196 printf "Usage: add_path_to_config <directory>\n" >&2
197 return 1
198 fi
199
200 new_path="${new_path/#\~/$HOME}"
201
202 if [ ! -d "$new_path" ]; then
203 printf "Warning: '%s' does not exist. Add anyway? (y/N) " "$new_path"
204 read -r REPLY
205 [[ ! $REPLY =~ ^[Yy]$ ]] && return 1
206 fi
207
208 # Check if already exists in file
209 if grep -Fq "append_path \"$new_path\"" "$config_file"; then
210 printf "Notice: Already in %s.\n" "$config_file"
211 return 0
212 fi
213
214 # Robust Injection: Use sed to insert before export PATH or just append
215 if grep -q "^export PATH" "$config_file"; then
216 sed -i.bak "/^export PATH/i append_path \"$new_path\"" "$config_file"
217 else
218 echo "append_path \"$new_path\"" >> "$config_file"
219 echo "export PATH" >> "$config_file"
220 fi
221
222 printf "✅ Success: Added to %s\n" "$config_file"
223 append_path "$new_path" && export PATH
224}
pathrc Raw
1# =============================================================================
2# ENVIRONMENT & PATH CONFIGURATION
3# =============================================================================
4
5# 1. Source functions first
6if [ -f "$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/Flutter/bin"
19append_path "/Applications/Espanso.app/Contents/MacOS"
20
21# Finalize PATH
22export 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 [[ -s "$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 [[ -s "$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 [[ -s "$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"
25export OPENAI_BASE_URL="https://gateway.ai.cloudflare.com/v1/9a71825e3842e918e0dff9ad84f50484/codex-gateway/openai"
26
27# ==========================================
28# OH MY ZSH
29# ==========================================
30if [[ -s "$HOME/.oh-my-zsh/oh-my-zsh.sh" ]]; then
31 source "$HOME/.oh-my-zsh/oh-my-zsh.sh"
32else
33 echo "Warning: Oh My Zsh not found or is empty."
34fi
35
36# ==========================================
37# NVM (Node Version Manager)
38# ==========================================
39export NVM_DIR="$HOME/.nvm"
40[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
41[ -s "$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"
5ZSH_THEME="spaceship"
6
7SPACESHIP_PROMPT_ORDER=( user dir git exec_time line_sep jobs exit_code char )
8SPACESHIP_USER_SHOW=always
9SPACESHIP_PROMPT_SEPARATE_LINE=true
10SPACESHIP_PROMPT_ADD_NEWLINE=true
11SPACESHIP_CHAR_SYMBOL="❯"
12SPACESHIP_CHAR_SUFFIX=" "
13
14plugins=(git zsh-syntax-highlighting zsh-autosuggestions)
15
16# =============================================================================
17# 2. THIRD-PARTY INITIALIZATION (SDKMAN, NVM, Oh My Zsh)
18# =============================================================================
19[[ -s "$HOME/.sourcerc" ]] && source "$HOME/.sourcerc"
20
21# =============================================================================
22# 3. CUSTOM OVERRIDES (Functions must load before Path Management)
23# =============================================================================
24[[ -s "$HOME/.func" ]] && source "$HOME/.func"
25
26# =============================================================================
27# 4. PATH MANAGEMENT (Relies on append_path from .func)
28# =============================================================================
29[[ -s "$HOME/.pathrc" ]] && source "$HOME/.pathrc"
30
31# =============================================================================
32# 5. ALIASES (Loaded dead last so YOUR code always wins over Oh My Zsh)
33# =============================================================================
34[[ -s "$HOME/.alias" ]] && source "$HOME/.alias"
35