|
#!/bin/bash |
|
set -euo pipefail |
|
|
|
# ===================================== |
|
# Setup Ubuntu WSL |
|
# Installs development environment + dotfiles configuration |
|
# Platform: Windows Subsystem for Linux (WSL 2) |
|
# Tested on: Ubuntu 26.04/24.04 |
|
# ===================================== |
|
|
|
echo "========================================" |
|
echo " Setup Ubuntu WSL" |
|
echo "========================================" |
|
echo "" |
|
|
|
# Colors for output |
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
YELLOW='\033[1;33m' |
|
BLUE='\033[0;34m' |
|
NC='\033[0m' |
|
|
|
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } |
|
log_warn() { echo -e "${YELLOW}[SKIP]${NC} $1"; } |
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; } |
|
log_step() { echo -e "\n${BLUE}[$1/18]${NC} $2"; } |
|
|
|
# Trap to show where script failed |
|
trap 'log_error "Script failed at line $LINENO. Command: $BASH_COMMAND"; exit 1' ERR |
|
|
|
usage() { |
|
cat <<EOF |
|
Usage: ${0##*/} [ options ] .... |
|
|
|
EOF |
|
|
|
} |
|
|
|
# Helper to check if a command exists |
|
command_exists() { |
|
command -v "$1" &> /dev/null |
|
} |
|
|
|
# Check if running in WSL |
|
if ! grep -qEi "(Microsoft|WSL)" /proc/version &> /dev/null; then |
|
log_warn "This doesn't appear to be WSL. This script is optimized for WSL." |
|
read -p "Continue anyway? (y/N) " -n 1 -r |
|
echo |
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then |
|
exit 1 |
|
fi |
|
fi |
|
|
|
# Parse dotfiles directory argument |
|
DOTFILES_DIR="" |
|
if [ -n "${1:-}" ]; then |
|
DOTFILES_DIR="$(cd "$1" && pwd)" |
|
if [ ! -d "$DOTFILES_DIR" ]; then |
|
log_error "Dotfiles directory not found: $1" |
|
exit 1 |
|
fi |
|
log_info "Will use dotfiles from: $DOTFILES_DIR" |
|
else |
|
log_warn "No dotfiles directory provided. Will create default configs." |
|
log_info "Usage: $0 <path-to-dotfiles-directory>" |
|
fi |
|
|
|
echo "" |
|
log_info "This will install and configure:" |
|
log_info " • System packages (via apt)" |
|
log_info " • Programming languages (Python, Java, Go, Rust, Ruby, Lua, Node.js)" |
|
log_info " • Tmux with custom widgets and TPM" |
|
log_info " • Neovim with plugins" |
|
log_info " • Zsh with oh-my-zsh and PowerLevel10k" |
|
log_info " • Dotfiles configuration (if provided)" |
|
echo "" |
|
|
|
read -p "Continue? (y/N) " -n 1 -r |
|
echo |
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then |
|
exit 1 |
|
fi |
|
|
|
log_step 1 "Fixing locale..." |
|
if locale -a 2>/dev/null | grep -q "en_US.utf8"; then |
|
log_warn "Locale already configured" |
|
else |
|
sudo sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen |
|
sudo locale-gen |
|
log_info "Locale configured" |
|
fi |
|
|
|
export LANG=en_US.UTF-8 |
|
export LC_ALL=en_US.UTF-8 |
|
|
|
log_step 2 "Updating system..." |
|
sudo apt update -y |
|
sudo apt upgrade -y |
|
|
|
log_step 3 "Installing base developer tools..." |
|
TOOLS="curl wget unzip zip git build-essential software-properties-common gnupg ripgrep fd-find fzf tree htop bc xclip bat lsd git-delta jq" |
|
MISSING_TOOLS="" |
|
|
|
for tool in $TOOLS; do |
|
if ! dpkg -l | grep -q "^ii $tool "; then |
|
MISSING_TOOLS="$MISSING_TOOLS $tool" |
|
fi |
|
done |
|
|
|
if [ -n "$MISSING_TOOLS" ]; then |
|
sudo apt install -y $MISSING_TOOLS |
|
log_info "Installed:$MISSING_TOOLS" |
|
else |
|
log_warn "All base tools already installed" |
|
fi |
|
|
|
# Create symlinks for Ubuntu-named packages |
|
mkdir -p ~/.local/bin |
|
if [ ! -e ~/.local/bin/fd ] && [ -e /usr/bin/fdfind ]; then |
|
ln -sf /usr/bin/fdfind ~/.local/bin/fd |
|
log_info "Created fd symlink" |
|
fi |
|
if [ ! -e ~/.local/bin/bat ] && [ -e /usr/bin/batcat ]; then |
|
ln -sf /usr/bin/batcat ~/.local/bin/bat |
|
log_info "Created bat symlink" |
|
fi |
|
|
|
log_step 4 "Installing Python 3..." |
|
if command_exists python3; then |
|
log_warn "Python3 already installed: $(python3 --version)" |
|
else |
|
sudo apt install -y python3 python3-pip python3-venv |
|
log_info "Python3 installed" |
|
fi |
|
|
|
# Install pynvim if not present |
|
if python3 -c "import pynvim" 2>/dev/null; then |
|
log_warn "pynvim already installed" |
|
else |
|
# Use apt instead of pip for Ubuntu 24.04+ (PEP 668) |
|
if dpkg -l | grep -q "^ii python3-pynvim "; then |
|
log_warn "pynvim already installed via apt" |
|
else |
|
sudo apt install -y python3-pynvim |
|
log_info "pynvim installed via apt" |
|
fi |
|
fi |
|
|
|
log_step 5 "Installing Java 11, 17, 21 via SDKMAN..." |
|
export SDKMAN_DIR="$HOME/.sdkman" |
|
|
|
if [ -d "$SDKMAN_DIR" ]; then |
|
log_warn "SDKMAN already installed" |
|
else |
|
log_info "Installing SDKMAN..." |
|
curl -s "https://get.sdkman.io" | bash |
|
fi |
|
|
|
# Source SDKMAN |
|
if [[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]]; then |
|
set +u |
|
export SDKMAN_OFFLINE_MODE=false |
|
source "$SDKMAN_DIR/bin/sdkman-init.sh" |
|
fi |
|
|
|
# Install Java versions |
|
install_java() { |
|
local version=$1 |
|
if sdk list java 2>/dev/null | grep -q "${version}.*-tem.*installed"; then |
|
log_warn "Java $version already installed" |
|
else |
|
log_info "Installing Java $version..." |
|
yes | sdk install java "${version}-tem" || true |
|
fi |
|
} |
|
|
|
install_java "11.0.25" |
|
install_java "17.0.13" |
|
install_java "21.0.5" |
|
|
|
sdk default java 21.0.5-tem 2>/dev/null || true |
|
set -u |
|
|
|
log_info "Java: $(java --version 2>&1 | head -1)" |
|
|
|
log_step 6 "Installing Go..." |
|
if command_exists go; then |
|
log_warn "Go already installed: $(go version)" |
|
else |
|
sudo apt install -y golang-go |
|
log_info "Go installed: $(go version)" |
|
fi |
|
|
|
log_step 7 "Installing Rust..." |
|
if [ -d "$HOME/.cargo" ] && command_exists cargo; then |
|
log_warn "Rust already installed: $(cargo --version)" |
|
else |
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y |
|
export PATH="$HOME/.cargo/bin:$PATH" |
|
log_info "Rust installed: $(cargo --version)" |
|
fi |
|
|
|
log_step 8 "Installing Ruby and Lua..." |
|
if command_exists ruby; then |
|
log_warn "Ruby already installed: $(ruby --version)" |
|
else |
|
sudo apt install -y ruby-full |
|
log_info "Ruby installed" |
|
fi |
|
|
|
if command_exists lua5.4; then |
|
log_warn "Lua already installed: $(lua5.4 -v 2>&1)" |
|
else |
|
sudo apt install -y lua5.4 liblua5.4-dev luarocks |
|
log_info "Lua installed" |
|
fi |
|
|
|
log_step 9 "Installing Node.js and TypeScript..." |
|
export NVM_DIR="$HOME/.nvm" |
|
|
|
if [ -d "$NVM_DIR" ]; then |
|
log_warn "nvm already installed" |
|
else |
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash |
|
log_info "nvm installed" |
|
fi |
|
|
|
# Source nvm |
|
if [ -s "$NVM_DIR/nvm.sh" ]; then |
|
set +u |
|
\. "$NVM_DIR/nvm.sh" |
|
set -u |
|
fi |
|
|
|
if command_exists node; then |
|
log_warn "Node.js already installed: $(node --version)" |
|
else |
|
set +u |
|
nvm install --lts |
|
nvm use --lts |
|
set -u |
|
log_info "Node.js installed: $(node --version)" |
|
fi |
|
|
|
if command_exists tsc; then |
|
log_warn "TypeScript already installed: $(tsc --version)" |
|
else |
|
npm install -g typescript typescript-language-server |
|
log_info "TypeScript installed" |
|
fi |
|
|
|
log_step 10 "Installing Zsh and Oh-My-Zsh..." |
|
if command_exists zsh; then |
|
log_warn "Zsh already installed: $(zsh --version)" |
|
else |
|
sudo apt install -y zsh |
|
log_info "Zsh installed" |
|
fi |
|
|
|
# Install Oh-My-Zsh |
|
if [ -d "$HOME/.oh-my-zsh" ]; then |
|
log_warn "Oh-My-Zsh already installed" |
|
else |
|
log_info "Installing Oh-My-Zsh..." |
|
if [ -f "$HOME/.zshrc" ]; then |
|
cp "$HOME/.zshrc" "$HOME/.zshrc.pre-oh-my-zsh" |
|
log_info "Backed up existing .zshrc" |
|
fi |
|
RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended |
|
log_info "Oh-My-Zsh installed" |
|
fi |
|
|
|
# Install Powerlevel10k theme |
|
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" |
|
if [ -d "$ZSH_CUSTOM/themes/powerlevel10k" ]; then |
|
log_warn "Powerlevel10k already installed" |
|
else |
|
log_info "Installing Powerlevel10k..." |
|
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$ZSH_CUSTOM/themes/powerlevel10k" |
|
log_info "Powerlevel10k installed" |
|
fi |
|
|
|
# Install zsh-autosuggestions |
|
if [ -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then |
|
log_warn "zsh-autosuggestions already installed" |
|
else |
|
log_info "Installing zsh-autosuggestions..." |
|
git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions" |
|
log_info "zsh-autosuggestions installed" |
|
fi |
|
|
|
# Install zsh-syntax-highlighting |
|
if [ -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]; then |
|
log_warn "zsh-syntax-highlighting already installed" |
|
else |
|
log_info "Installing zsh-syntax-highlighting..." |
|
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" |
|
log_info "zsh-syntax-highlighting installed" |
|
fi |
|
|
|
log_step 11 "Installing Tmux and TPM..." |
|
if command_exists tmux; then |
|
log_warn "Tmux already installed: $(tmux -V)" |
|
else |
|
sudo apt install -y tmux |
|
log_info "Tmux installed" |
|
fi |
|
|
|
# Install TPM |
|
if [ -d "$HOME/.tmux/plugins/tpm" ]; then |
|
log_warn "TPM already installed" |
|
else |
|
log_info "Installing TPM..." |
|
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm |
|
log_info "TPM installed" |
|
fi |
|
|
|
log_step 12 "Installing Neovim..." |
|
NVIM_VERSION="v0.11.5" |
|
NVIM_ARCHIVE="nvim-linux-x86_64.tar.gz" |
|
NVIM_DIR="nvim-linux-x86_64" |
|
|
|
if command_exists nvim; then |
|
CURRENT_VERSION=$(nvim --version | head -1 | awk '{print $2}') |
|
if [ "$CURRENT_VERSION" = "$NVIM_VERSION" ]; then |
|
log_warn "Neovim already installed: $CURRENT_VERSION" |
|
else |
|
log_info "Upgrading Neovim from $CURRENT_VERSION to $NVIM_VERSION" |
|
cd /tmp |
|
curl -LO "https://github.com/neovim/neovim/releases/download/${NVIM_VERSION}/${NVIM_ARCHIVE}" |
|
sudo rm -rf /opt/${NVIM_DIR} |
|
sudo tar -C /opt -xzf ${NVIM_ARCHIVE} |
|
sudo ln -sf /opt/${NVIM_DIR}/bin/nvim /usr/local/bin/nvim |
|
rm -f ${NVIM_ARCHIVE} |
|
fi |
|
else |
|
cd /tmp |
|
curl -LO "https://github.com/neovim/neovim/releases/download/${NVIM_VERSION}/${NVIM_ARCHIVE}" |
|
sudo rm -rf /opt/${NVIM_DIR} |
|
sudo tar -C /opt -xzf ${NVIM_ARCHIVE} |
|
sudo ln -sf /opt/${NVIM_DIR}/bin/nvim /usr/local/bin/nvim |
|
rm -f ${NVIM_ARCHIVE} |
|
log_info "Neovim installed: $(nvim --version | head -1)" |
|
fi |
|
|
|
log_step 13 "Setting up dotfiles configuration..." |
|
if [ -n "$DOTFILES_DIR" ]; then |
|
# Use provided dotfiles directory |
|
log_info "Using dotfiles from: $DOTFILES_DIR" |
|
|
|
# Backup existing configs |
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S) |
|
|
|
if [ -f "$HOME/.zshrc" ]; then |
|
cp "$HOME/.zshrc" "$HOME/.zshrc.backup.$TIMESTAMP" |
|
log_info "Backed up .zshrc" |
|
fi |
|
|
|
if [ -f "$HOME/.tmux.conf" ]; then |
|
cp "$HOME/.tmux.conf" "$HOME/.tmux.conf.backup.$TIMESTAMP" |
|
log_info "Backed up .tmux.conf" |
|
fi |
|
|
|
if [ -f "$HOME/.gitconfig" ]; then |
|
cp "$HOME/.gitconfig" "$HOME/.gitconfig.backup.$TIMESTAMP" |
|
log_info "Backed up .gitconfig" |
|
fi |
|
|
|
# Link dotfiles |
|
if [ -f "$DOTFILES_DIR/zsh/zshrc" ]; then |
|
ln -sf "$DOTFILES_DIR/zsh/zshrc" "$HOME/.zshrc" |
|
log_info "Linked .zshrc" |
|
fi |
|
|
|
if [ -f "$DOTFILES_DIR/zsh/p10k.zsh" ]; then |
|
ln -sf "$DOTFILES_DIR/zsh/p10k.zsh" "$HOME/.p10k.zsh" |
|
log_info "Linked .p10k.zsh" |
|
fi |
|
|
|
if [ -f "$DOTFILES_DIR/tmux/tmux.conf" ]; then |
|
ln -sf "$DOTFILES_DIR/tmux/tmux.conf" "$HOME/.tmux.conf" |
|
log_info "Linked .tmux.conf" |
|
fi |
|
|
|
if [ -f "$DOTFILES_DIR/git/gitconfig" ]; then |
|
ln -sf "$DOTFILES_DIR/git/gitconfig" "$HOME/.gitconfig" |
|
log_info "Linked .gitconfig" |
|
fi |
|
|
|
# Copy tmux custom widgets if they exist |
|
if [ -d "$DOTFILES_DIR/tmux/.tmux/custom-widgets" ]; then |
|
cp -r "$DOTFILES_DIR/tmux/.tmux/custom-widgets" "$HOME/.tmux/" |
|
log_info "Copied tmux custom widgets" |
|
fi |
|
|
|
# Copy cheatsheets |
|
if [ -d "$DOTFILES_DIR/cheatsheets" ]; then |
|
for cheatsheet in "$DOTFILES_DIR/cheatsheets"/*; do |
|
if [ -f "$cheatsheet" ]; then |
|
cp "$cheatsheet" "$HOME/.$(basename "$cheatsheet")" |
|
fi |
|
done |
|
log_info "Copied cheatsheets" |
|
fi |
|
|
|
# Neovim config |
|
if [ -d "$DOTFILES_DIR/nvim/nvim" ]; then |
|
if [ -d "$HOME/.config/nvim" ]; then |
|
log_warn "Neovim config already exists. Skipping." |
|
log_info "Dotfiles neovim config available at: $DOTFILES_DIR/nvim/nvim" |
|
else |
|
mkdir -p "$HOME/.config" |
|
ln -sf "$DOTFILES_DIR/nvim/nvim" "$HOME/.config/nvim" |
|
log_info "Linked neovim config" |
|
fi |
|
fi |
|
|
|
else |
|
# Create minimal default configs |
|
log_info "Creating default configuration files..." |
|
|
|
# Create minimal .zshrc if doesn't exist |
|
if [ ! -f "$HOME/.zshrc" ]; then |
|
cat > ~/.zshrc << 'ZSHEOF' |
|
|
|
# Locale settings |
|
export LANG=en_US.UTF-8 |
|
export LC_ALL=en_US.UTF-8 |
|
|
|
# Aliases |
|
alias ll='ls -la --color=auto' |
|
alias v='nvim' |
|
alias vim='nvim' |
|
alias t='tmux' |
|
alias python='python3' |
|
|
|
# Enable Powerlevel10k instant prompt |
|
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then |
|
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" |
|
fi |
|
|
|
# Oh My Zsh |
|
export ZSH="$HOME/.oh-my-zsh" |
|
ZSH_THEME="powerlevel10k/powerlevel10k" |
|
plugins=(git docker kubectl npm node zsh-autosuggestions zsh-syntax-highlighting) |
|
source $ZSH/oh-my-zsh.sh |
|
|
|
# Powerlevel10k |
|
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh |
|
|
|
# PATH |
|
export PATH="$HOME/.local/bin:$PATH" |
|
export PATH="/opt/nvim-linux64/bin:$PATH" |
|
|
|
# SDKMAN |
|
export SDKMAN_DIR="$HOME/.sdkman" |
|
[[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]] && source "$SDKMAN_DIR/bin/sdkman-init.sh" |
|
|
|
# Rust |
|
export PATH="$HOME/.cargo/bin:$PATH" |
|
|
|
# nvm |
|
export NVM_DIR="$HOME/.nvm" |
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" |
|
ZSHEOF |
|
log_info "Created default .zshrc" |
|
fi |
|
fi |
|
|
|
log_step "13b" "Creating Linux-compatible tmux widgets..." |
|
WIDGETS_DIR="$HOME/.tmux/custom-widgets" |
|
mkdir -p "$WIDGETS_DIR" |
|
|
|
# CPU Widget - uses /proc/stat (Linux) |
|
if [ ! -f "$WIDGETS_DIR/cpu-widget.sh" ] || grep -q "top -l" "$WIDGETS_DIR/cpu-widget.sh" 2>/dev/null; then |
|
cat > "$WIDGETS_DIR/cpu-widget.sh" << 'CPUEOF' |
|
#!/bin/bash |
|
# Tokyo Night CPU Widget for Linux/WSL |
|
|
|
# Get CPU usage from /proc/stat (two samples, 0.5s apart) |
|
read -r _ user1 nice1 system1 idle1 iowait1 irq1 softirq1 steal1 _ < /proc/stat |
|
sleep 0.5 |
|
read -r _ user2 nice2 system2 idle2 iowait2 irq2 softirq2 steal2 _ < /proc/stat |
|
|
|
total1=$((user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1 + steal1)) |
|
total2=$((user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + steal2)) |
|
idle_diff=$((idle2 + iowait2 - idle1 - iowait1)) |
|
total_diff=$((total2 - total1)) |
|
|
|
if [ "$total_diff" -gt 0 ]; then |
|
cpu_usage=$(( (total_diff - idle_diff) * 100 / total_diff )) |
|
else |
|
cpu_usage=0 |
|
fi |
|
|
|
# Color based on usage (Tokyo Night) |
|
if [ "$cpu_usage" -lt 50 ]; then |
|
color="#a6e3a1" # green |
|
elif [ "$cpu_usage" -lt 80 ]; then |
|
color="#f9e2af" # yellow |
|
else |
|
color="#f38ba8" # red |
|
fi |
|
|
|
echo "#[fg=${color},bg=#1a1b26] CPU ${cpu_usage}% " |
|
CPUEOF |
|
chmod +x "$WIDGETS_DIR/cpu-widget.sh" |
|
log_info "Created CPU widget (Linux)" |
|
else |
|
log_warn "CPU widget already exists" |
|
fi |
|
|
|
# RAM Widget - uses free (Linux) |
|
if [ ! -f "$WIDGETS_DIR/ram-widget.sh" ] || grep -q "vm_stat\|1e1e2e" "$WIDGETS_DIR/ram-widget.sh" 2>/dev/null; then |
|
cat > "$WIDGETS_DIR/ram-widget.sh" << 'RAMEOF' |
|
#!/bin/bash |
|
# Tokyo Night RAM Widget for Linux/WSL |
|
|
|
# Get RAM usage |
|
ram_percent=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}') |
|
|
|
# Color based on usage (Tokyo Night) |
|
if [ "$ram_percent" -lt 60 ]; then |
|
color="#a6e3a1" # green |
|
elif [ "$ram_percent" -lt 80 ]; then |
|
color="#f9e2af" # yellow |
|
else |
|
color="#f38ba8" # red |
|
fi |
|
|
|
echo "#[fg=${color},bg=#1a1b26] RAM ${ram_percent}% " |
|
RAMEOF |
|
chmod +x "$WIDGETS_DIR/ram-widget.sh" |
|
log_info "Created RAM widget (Linux)" |
|
else |
|
log_warn "RAM widget already exists" |
|
fi |
|
|
|
# Network Widget - uses /proc/net/dev (Linux) |
|
if [ ! -f "$WIDGETS_DIR/network-widget.sh" ] || grep -q "ifconfig\|1e1e2e" "$WIDGETS_DIR/network-widget.sh" 2>/dev/null; then |
|
cat > "$WIDGETS_DIR/network-widget.sh" << 'NETEOF' |
|
#!/bin/bash |
|
# Tokyo Night Network Speed Widget for Linux/WSL |
|
|
|
# Get default network interface |
|
DEFAULT_INTERFACE=$(ip route 2>/dev/null | grep '^default' | awk '{print $5}' | head -n1) |
|
|
|
if [ -z "$DEFAULT_INTERFACE" ]; then |
|
DEFAULT_INTERFACE=$(ip link show 2>/dev/null | grep -E "state UP" | head -n1 | awk -F': ' '{print $2}') |
|
fi |
|
|
|
if [ -z "$DEFAULT_INTERFACE" ]; then |
|
echo "#[fg=#89b4fa,bg=#1a1b26] offline " |
|
exit 0 |
|
fi |
|
|
|
# Read current bytes from /proc/net/dev |
|
read_bytes() { |
|
awk -v iface="$DEFAULT_INTERFACE:" '$1 == iface {print $2, $10}' /proc/net/dev |
|
} |
|
|
|
current=$(read_bytes) |
|
rx_bytes=$(echo "$current" | awk '{print $1}') |
|
tx_bytes=$(echo "$current" | awk '{print $2}') |
|
|
|
if [ -z "$rx_bytes" ] || [ -z "$tx_bytes" ]; then |
|
echo "#[fg=#89b4fa,bg=#1a1b26] offline " |
|
exit 0 |
|
fi |
|
|
|
# Cache file for previous values |
|
CACHE_FILE="/tmp/tmux_network_cache" |
|
|
|
if [ -f "$CACHE_FILE" ]; then |
|
read -r prev_rx prev_tx prev_time < "$CACHE_FILE" |
|
else |
|
prev_rx=$rx_bytes |
|
prev_tx=$tx_bytes |
|
prev_time=$(date +%s) |
|
fi |
|
|
|
current_time=$(date +%s) |
|
time_diff=$((current_time - prev_time)) |
|
[ "$time_diff" -eq 0 ] && time_diff=1 |
|
|
|
# Calculate speeds |
|
rx_speed=$(( (rx_bytes - prev_rx) / time_diff )) |
|
tx_speed=$(( (tx_bytes - prev_tx) / time_diff )) |
|
|
|
# Ensure non-negative |
|
[ "$rx_speed" -lt 0 ] && rx_speed=0 |
|
[ "$tx_speed" -lt 0 ] && tx_speed=0 |
|
|
|
# Format bytes to human readable |
|
format_speed() { |
|
local bytes=$1 |
|
if [ "$bytes" -lt 1024 ]; then |
|
echo "${bytes}B/s" |
|
elif [ "$bytes" -lt 1048576 ]; then |
|
echo "$((bytes / 1024))K/s" |
|
else |
|
echo "$((bytes / 1048576))M/s" |
|
fi |
|
} |
|
|
|
rx_formatted=$(format_speed $rx_speed) |
|
tx_formatted=$(format_speed $tx_speed) |
|
|
|
echo "#[fg=#89b4fa,bg=#1a1b26] ↓${rx_formatted} ↑${tx_formatted} " |
|
|
|
# Save current values |
|
echo "$rx_bytes $tx_bytes $current_time" > "$CACHE_FILE" |
|
NETEOF |
|
chmod +x "$WIDGETS_DIR/network-widget.sh" |
|
log_info "Created Network widget (Linux)" |
|
else |
|
log_warn "Network widget already exists" |
|
fi |
|
|
|
# Date-time widget |
|
if [ ! -f "$WIDGETS_DIR/date-time-widget.sh" ]; then |
|
cat > "$WIDGETS_DIR/date-time-widget.sh" << 'DTEOF' |
|
#!/bin/bash |
|
echo "$(date +'%a %b %d %H:%M')" |
|
DTEOF |
|
chmod +x "$WIDGETS_DIR/date-time-widget.sh" |
|
log_info "Created Date-Time widget" |
|
fi |
|
|
|
# Window name widget |
|
if [ ! -f "$WIDGETS_DIR/window-name.sh" ]; then |
|
cat > "$WIDGETS_DIR/window-name.sh" << 'WNEOF' |
|
#!/bin/bash |
|
path="$1" |
|
cmd="$2" |
|
# Show last 2 path segments |
|
short_path=$(echo "$path" | awk -F'/' '{if(NF>2) print $(NF-1)"/"$NF; else print $0}') |
|
echo "$short_path" |
|
WNEOF |
|
chmod +x "$WIDGETS_DIR/window-name.sh" |
|
log_info "Created Window-Name widget" |
|
fi |
|
|
|
# Git branch widget |
|
if [ ! -f "$WIDGETS_DIR/git-branch-widget.sh" ]; then |
|
cat > "$WIDGETS_DIR/git-branch-widget.sh" << 'GBEOF' |
|
#!/bin/bash |
|
path="$1" |
|
if [ -d "$path/.git" ] || git -C "$path" rev-parse --git-dir > /dev/null 2>&1; then |
|
branch=$(git -C "$path" symbolic-ref --short HEAD 2>/dev/null || git -C "$path" rev-parse --short HEAD 2>/dev/null) |
|
if [ -n "$branch" ]; then |
|
echo " ⎇ $branch" |
|
fi |
|
fi |
|
GBEOF |
|
chmod +x "$WIDGETS_DIR/git-branch-widget.sh" |
|
log_info "Created Git-Branch widget" |
|
fi |
|
|
|
log_step 14 "Updating .bashrc..." |
|
if ! grep -q '# >>> ubuntu-in-windows-setup >>>' "$HOME/.bashrc" 2>/dev/null; then |
|
cat >> ~/.bashrc << 'EOF' |
|
|
|
# >>> ubuntu-in-windows-setup >>> |
|
export LANG=en_US.UTF-8 |
|
export LC_ALL=en_US.UTF-8 |
|
export PATH="$HOME/.local/bin:$PATH" |
|
export PATH="/opt/nvim-linux64/bin:$PATH" |
|
|
|
# SDKMAN |
|
export SDKMAN_DIR="$HOME/.sdkman" |
|
[[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]] && source "$SDKMAN_DIR/bin/sdkman-init.sh" |
|
|
|
# Rust |
|
export PATH="$HOME/.cargo/bin:$PATH" |
|
|
|
# nvm |
|
export NVM_DIR="$HOME/.nvm" |
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" |
|
|
|
# Aliases |
|
alias vim='nvim' |
|
alias python='python3' |
|
alias t='tmux' |
|
# <<< ubuntu-in-windows-setup <<< |
|
EOF |
|
log_info "Updated .bashrc" |
|
else |
|
log_warn ".bashrc already configured" |
|
fi |
|
|
|
|
|
log_step 15 "Verifying installations..." |
|
verify_install() { |
|
local name=$1 |
|
local check=$2 |
|
if eval "$check"; then |
|
log_info "$name: OK" |
|
else |
|
log_warn "$name: Not found (optional)" |
|
fi |
|
} |
|
|
|
verify_install "Oh-My-Zsh" "[ -d '$HOME/.oh-my-zsh' ]" |
|
verify_install "Powerlevel10k" "[ -d '$HOME/.oh-my-zsh/custom/themes/powerlevel10k' ]" |
|
verify_install "TPM" "[ -d '$HOME/.tmux/plugins/tpm' ]" |
|
verify_install "Neovim" "command_exists nvim" |
|
verify_install "Tmux" "command_exists tmux" |
|
verify_install "Zsh" "command_exists zsh" |
|
|
|
log_step 16 "Setting zsh as default shell..." |
|
if [ "$SHELL" = "$(which zsh)" ]; then |
|
log_warn "Zsh is already the default shell" |
|
else |
|
# Set zsh as default shell |
|
if command -v chsh >/dev/null 2>&1; then |
|
sudo chsh -s "$(which zsh)" "$USER" 2>/dev/null || chsh -s "$(which zsh)" 2>/dev/null || log_warn "Could not set zsh as default shell. Run manually: chsh -s \$(which zsh)" |
|
if [ $? -eq 0 ]; then |
|
log_info "Zsh set as default shell (restart terminal to take effect)" |
|
fi |
|
else |
|
log_warn "chsh command not found. Zsh installed but not set as default." |
|
fi |
|
fi |
|
|
|
echo "" |
|
echo "========================================" |
|
echo " Installation Complete!" |
|
echo "========================================" |
|
echo "" |
|
echo "Languages Installed:" |
|
echo " Python: $(python3 --version 2>&1)" |
|
echo " Java: $(java --version 2>&1 | head -1)" |
|
echo " Go: $(go version 2>&1)" |
|
echo " Rust: $(cargo --version 2>&1)" |
|
echo " Ruby: $(ruby --version 2>&1)" |
|
echo " Lua: $(lua5.4 -v 2>&1)" |
|
echo " Node: $(node --version 2>&1)" |
|
echo " TypeScript: $(tsc --version 2>&1)" |
|
echo "" |
|
echo "Tools Installed:" |
|
echo " Neovim: $(nvim --version 2>&1 | head -1)" |
|
echo " Tmux: $(tmux -V 2>&1)" |
|
echo " Zsh: $(zsh --version 2>&1)" |
|
echo "" |
|
echo "Next Steps:" |
|
echo " 1. Close and reopen your terminal (zsh is now your default shell)" |
|
echo " 2. Configure PowerLevel10k: p10k configure" |
|
echo " 3. Start tmux: tmux new-session -s main" |
|
echo " 4. In tmux, press Ctrl+a then Shift+I to install plugins" |
|
echo "" |