HTTPD BusyWait
Welcome to the HTTPD BusyWait documentation.
Overview
This project provides an HTTP server configuration for handling busy-wait scenarios.
Getting Started
To get started with development:
- Clone the repository
- Review the configuration files
- Build and run the container
Development
Add your development notes and documentation here.
Favorite Settings
File: env/Linux/.bashrc
# this is for mac
export BASH_SILENCE_DEPRECATION_WARNING=1
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
# source ~/devdir/env/Linux/devdir
# Source terminal enhancements
if [ -f ~/devdir/env/Linux/terminal_enhancements.sh ]; then
source ~/devdir/env/Linux/terminal_enhancements.sh
fi
File: env/Linux/.profile
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
File: env/Linux/.tmux.conf
#
# Reload (for testing)
# tmux source-file ~/DevDir/Linux/.tmux.conf
#
# List all key bindings
# tmux lsk, or tmux list-keys
# ------------------------------------------------------------------
# GOAL:
# ALT+Arrow to move between panes
# ALT+F to maximize pane
# Mouse works
#
# Hacking Notes:
# On MAC, use Karabiner to swap command and option. then use karabinear to map ALT+F
#
# NOTE : copy and paste
#
# Windows Terminal is very smart in integrating clipboards. Things tend to "just work"
# so I see no reason for much expansion
#
# On unix there is standard OCS52 that provides a way to escape strings
# going across SSH that signals to the terminal to place the text into
# the local systems clipboard. How this all fits together is still
# confusing to me, but if you run 'tmux info | grep Ms', on the remote
# machine you can know if its setup
#
# on Mac (iTerm) and Linux, make sure to use CTRL+SHIFT+{C, V} to copy, in both cases
# the system clipboards should be integrated
set -g mouse on
bind-key -T prefix \\ split-window -h -c "#{pane_current_path}"
bind-key -T prefix - split-window -v -c "#{pane_current_path}"
# bind-key syntax changed in 2.4 -- selection / copy / paste
if-shell -b '[ "$(uname)" == "Darwin" ]' {
set-option -s set-clipboard on
}
if-shell -b '[ "$(uname)" != "Darwin" ]' {
# On Linux, use xclip to copy to clipboard
set-option -s set-clipboard on
set -as terminal-features ',rxvt-unicode-256color:clipboard'
}
bind -n C-Left select-pane -L
bind -n C-Right select-pane -R
bind -n C-Up select-pane -U
bind -n C-Down select-pane -D
bind -n C-/ resize-pane -Z
bind -n C-f resize-pane -Z
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
bind -n M-/ resize-pane -Z
bind -n M-f resize-pane -Z
unbind -T prefix 0
unbind -T prefix 1
unbind -T prefix 2
unbind -T prefix 3
unbind -T prefix 4
unbind -T prefix 5
unbind -T prefix 6
unbind -T prefix 7
unbind -T prefix 8
unbind -T prefix 9
# unbind -T root MouseDown1Status # Commented out to allow mouse clicks on window tabs
unbind -T root M-0
unbind -T root M-1
unbind -T root M-2
unbind -T root M-3
unbind -T root M-4
unbind -T root M-5
unbind -T root M-6
unbind -T root M-7
unbind -T root M-8
unbind -T root M-9
unbind -T root C-0
unbind -T root C-1
unbind -T root C-2
unbind -T root C-3
unbind -T root C-4
unbind -T root C-5
unbind -T root C-6
unbind -T root C-7
unbind -T root C-8
unbind -T root C-9
# Unbind all Control + Function keys
unbind -T root C-F1
unbind -T root C-F2
unbind -T root C-F3
unbind -T root C-F4
unbind -T root C-F5
unbind -T root C-F6
unbind -T root C-F7
unbind -T root C-F8
unbind -T root C-F9
unbind -T root C-F10
unbind -T root C-F11
unbind -T root C-F12
# Unbind all Meta/Alt + Function keys
unbind -T root M-F1
unbind -T root M-F2
unbind -T root M-F3
unbind -T root M-F4
unbind -T root M-F5
unbind -T root M-F6
unbind -T root M-F7
unbind -T root M-F8
unbind -T root M-F9
unbind -T root M-F10
unbind -T root M-F11
unbind -T root M-F12
# Use Function keys with CTRL to switch between windows
bind -n M-F1 select-window -t :=1
bind -n M-F2 select-window -t :=2
bind -n M-F3 select-window -t :=3
bind -n M-F4 select-window -t :=4
bind -n M-F5 select-window -t :=5
bind -n M-F6 select-window -t :=6
bind -n M-F7 select-window -t :=7
bind -n M-F8 select-window -t :=8
bind -n M-F9 select-window -t :=9
bind -n M-F10 select-window -t :=0
bind -n C-= new-window
bind -n C-- confirm-before -p "Kill window #W? (y/n)" kill-window
bind -n C-r command-prompt -I "#W" { rename-window "%%" }
# Removed M-<number> bindings in favor of function keys
bind -n M-= new-window
bind -n M-- confirm-before -p "Kill window #W? (y/n)" kill-window
bind -n M-r command-prompt -I "#W" { rename-window "%%" }
set-option -g renumber-windows on
# Start numbering windows at 1 instead of 0
set -g base-index 1
# Enable true color support
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
# Visual bell/activity
set -g visual-activity off
set -g visual-bell off
set -g visual-silence off
setw -g monitor-activity on
set -g bell-action none
# Clock mode
set -g clock-mode-colour '#6495ed'
set -g clock-mode-style 24
# Messages
set -g message-style 'fg=#ffffff,bg=#1e3a5f,bold'
set -g message-command-style 'fg=#b8d4ff,bg=#1e3a5f'
# Status bar configuration
set -g status on
set -g status-interval 2
set -g status-position bottom
set -g status-justify left
set -g status-style 'fg=#9db4d1,bg=#0a1929'
set -g status-left-length 40
set -g status-right-length 80
# Window status formats with navy blue theme
set -g window-status-separator ' '
set -g window-status-format '#[fg=#0a1929,bg=#1e3a5f]#{?#{==:#I,1},#[fg=#ff6b6b],#{?#{==:#I,2},#[fg=#ffd700],#{?#{==:#I,3},#[fg=#00ff00],#{?#{==:#I,4},#[fg=#00ffff],#{?#{==:#I,5},#[fg=#ff00ff],#{?#{==:#I,6},#[fg=#ffb347],#{?#{==:#I,7},#[fg=#87ceeb],#{?#{==:#I,8},#[fg=#98fb98],#{?#{==:#I,9},#[fg=#dda0dd],#[fg=#f0e68c]}}}}}}}}}#[bg=#1e3a5f,bold] #I #[fg=#5a6e88]│ #[fg=#8ba3c1]#W#F #[fg=#1e3a5f,bg=#0a1929]'
set -g window-status-current-format '#[fg=#0a1929,bg=#2c4f7c]#{?#{==:#I,1},#[fg=#ff6b6b],#{?#{==:#I,2},#[fg=#ffd700],#{?#{==:#I,3},#[fg=#00ff00],#{?#{==:#I,4},#[fg=#00ffff],#{?#{==:#I,5},#[fg=#ff00ff],#{?#{==:#I,6},#[fg=#ffb347],#{?#{==:#I,7},#[fg=#87ceeb],#{?#{==:#I,8},#[fg=#98fb98],#{?#{==:#I,9},#[fg=#dda0dd],#[fg=#f0e68c]}}}}}}}}}#[bg=#2c4f7c,bold] #I #[fg=#ffffff]▶ #[fg=#ffffff,bold]#W#F #[fg=#2c4f7c,bg=#0a1929]'
# Window status styles
set -g window-status-style 'fg=#7b92b0,bg=#1e3a5f'
set -g window-status-current-style 'fg=#ffffff,bg=#6495ed,bold'
set -g window-status-activity-style 'fg=#ffd700,bg=#2c4f7c,bold,blink'
set -g window-status-bell-style 'fg=#ff6b6b,bg=#2c4f7c,bold,blink'
set -g window-status-last-style 'fg=#87ceeb,bg=#1e3a5f,italics'
# Pane borders with navy theme - enhanced visibility
set -g pane-border-style 'fg=#4a6fa5,bg=#0a1929'
set -g pane-active-border-style 'fg=#87ceeb,bg=#0a1929,bold'
set -g pane-border-lines heavy
set -g pane-border-indicators colour
set -g pane-border-status top
set -g pane-border-format ' #{?pane_active,#[fg=#87ceeb bold]● , }#P: #{pane_current_command} '
# Mode colors (selection)
set -g mode-style 'fg=#ffffff,bg=#4169e1,bold'
set -g copy-mode-match-style 'fg=#000033,bg=#87ceeb'
set -g copy-mode-current-match-style 'fg=#ffffff,bg=#6495ed,bold'
File: env/Linux/ConfigureGnome.sh
#!/bin/bash
# GNOME Configuration Script
# Combines all GNOME settings, sorted and organized by category
# Works on both Ubuntu and Fedora distributions
# Check for required command line argument
if [ $# -eq 0 ]; then
echo "Usage: $0 --ubuntu | --fedora"
echo " --ubuntu : Configure for Ubuntu"
echo " --fedora : Configure for Fedora"
exit 1
fi
# Parse command line argument
DISTRO=""
case "$1" in
--ubuntu)
DISTRO="ubuntu"
echo "Configuring for Ubuntu..."
;;
--fedora)
DISTRO="fedora"
echo "Configuring for Fedora..."
;;
*)
echo "Error: Invalid argument '$1'"
echo "Usage: $0 --ubuntu | --fedora"
echo " --ubuntu : Configure for Ubuntu"
echo " --fedora : Configure for Fedora"
exit 1
;;
esac
# Backup current settings before making changes
echo "Backing up current GNOME settings..."
for schema in $(gsettings list-schemas); do gsettings list-recursively $schema
done > gnome-settings-backup-$(date +%Y%m%d-%H%M%S).txt
# Install required extensions
echo "Installing GNOME Shell extension preferences..."
if [[ "$DISTRO" == "ubuntu" ]]; then
sudo apt install -y gnome-shell-extension-prefs
elif [[ "$DISTRO" == "fedora" ]]; then
sudo dnf install -y gnome-extensions-app gnome-shell-extension-common
fi
# ========================================
# Dash to Dock Extension Settings
# ========================================
# Set dock icon size to 36 pixels
gsettings set org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 36
# Keep dock fixed in position (don't auto-hide)
gsettings set org.gnome.shell.extensions.dash-to-dock dock-fixed true
# Don't extend dock to full height of screen
gsettings set org.gnome.shell.extensions.dash-to-dock extend-height false
# Show different apps on each workspace
gsettings set org.gnome.shell.extensions.dash-to-dock isolate-workspaces true
# Hide trash icon from dock
gsettings set org.gnome.shell.extensions.dash-to-dock show-trash false
# ========================================
# Desktop and Peripherals Settings
# ========================================
# Enable natural scrolling for touchpad (reverse scroll direction)
gsettings set org.gnome.desktop.peripherals.touchpad natural-scroll true
# ========================================
# Window Management Settings
# ========================================
# Window title bar button layout: app menu on left, minimize/maximize/close on right
gsettings set org.gnome.desktop.wm.preferences button-layout appmenu:minimize,maximize,close
# ========================================
# Keyboard Shortcuts - Application Switching
# ========================================
# Disable default application switching (groups windows by app)
gsettings set org.gnome.desktop.wm.keybindings switch-applications "[]"
gsettings set org.gnome.desktop.wm.keybindings switch-applications-backward "[]"
# Enable window switching (cycles through individual windows)
gsettings set org.gnome.desktop.wm.keybindings switch-windows "['<Alt>Tab', '<Super>Tab']"
gsettings set org.gnome.desktop.wm.keybindings switch-windows-backward "['<Alt><Shift>Tab', '<Super><Shift>Tab']"
# ========================================
# Keyboard Shortcuts - Workspace Navigation
# ========================================
# Direct workspace switching with Super+number keys
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 "['<Super>1']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-2 "['<Super>2']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-3 "['<Super>3']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-4 "['<Super>4']"
# Disabled workspace navigation settings (kept for reference)
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up "['<Primary><Super>Up']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down "['<Primary><Super>Down']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Primary><Super>Up']"
#gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right "['<Primary><Super>Down']"
# ========================================
# Keyboard Shortcuts - Dialogs
# ========================================
# Disable panel run dialog (Alt+F2 command dialog)
gsettings set org.gnome.desktop.wm.keybindings panel-run-dialog "[]"
# Disable window close shortcut (Alt+F4)
gsettings set org.gnome.desktop.wm.keybindings close "[]"
# ========================================
# Media Keys and Screenshots
# ========================================
# Set screenshot area selection shortcut to Shift+Super+S (like Windows)
#gsettings set org.gnome.settings-daemon.plugins.media-keys area-screenshot-clip "['<Shift><Super>s']"
# ========================================
# Shell Settings
# ========================================
# Show only current workspace apps in app switcher
gsettings set org.gnome.shell.app-switcher current-workspace-only true
gsettings set org.gnome.desktop.wm.keybindings unmaximize "['<Super>Down']"
gsettings set org.gnome.desktop.wm.keybindings cycle-group "[]"
File: env/Linux/InstallLinux
#!/bin/bash
# Script to install and configure Linux development environment for Ubuntu and Fedora
# Parse command line arguments
DISTRO=""
SIGNAL_FLAG=false
DOTNET_FLAG=false
PKGS_FULL_CONSOLE_FLAG=false
PKGS_SHELL_FLAG=false
PKGS_DEV_FLAG=false
STARSHIP_FLAG=false
LAZYGIT_FLAG=false
TAILSCALE_FLAG=false
CLAUDE_FLAG=false
GHOSTTY_FLAG=false
VSCODE_FLAG=false
BEYONDCOMPARE_FLAG=false
PKGS_FULL_GRAPHICAL_FLAG=false
BAZEL_FLAG=false
while [[ $# -gt 0 ]]; do
case $1 in
--ubuntu)
if [ -n "$DISTRO" ]; then
echo "Error: Cannot specify both --ubuntu and --fedora"
exit 1
fi
DISTRO="ubuntu"
shift
;;
--fedora)
if [ -n "$DISTRO" ]; then
echo "Error: Cannot specify both --ubuntu and --fedora"
exit 1
fi
DISTRO="fedora"
shift
;;
--full_dev)
SIGNAL_FLAG=true
TAILSCALE_FLAG=true
VSCODE_FLAG=true
STARSHIP_FLAG=true
DOTNET_FLAG=true
BEYONDCOMPARE_FLAG=true
PKGS_FULL_CONSOLE_FLAG=true
PKGS_DEV_FLAG=true
PKGS_SHELL_FLAG=true
LAZYGIT_FLAG=true
BAZEL_FLAG=true
shift
;;
--claude)
CLAUDE_FLAG=true
shift
;;
--signal)
SIGNAL_FLAG=true
shift
;;
--dotnet)
DOTNET_FLAG=true
shift
;;
--pkgs_full_console)
PKGS_FULL_CONSOLE_FLAG=true
PKGS_DEV_FLAG=true
PKGS_SHELL_FLAG=true
shift
;;
--pkgs_full_graphical)
PKGS_FULL_GRAPHICAL_FLAG=true
GHOSTTY_FLAG=true
SIGNAL_INSTALLED=true
BEYONDCOMPARE_FLAG=true
VSCODE_FLAG=true
shift
;;
--pkgs_shell)
PKGS_SHELL_FLAG=true
shift
;;
--pkgs_dev)
PKGS_SHELL_FLAG=true
PKGS_DEV_FLAG=true
CLAUDE_FLAG=true
LAZYGIT_FLAG=true
STARSHIP_FLAG=true
shift
;;
--starship)
STARSHIP_FLAG=true
shift
;;
--lazygit)
LAZYGIT_FLAG=true
shift
;;
--tailscale)
TAILSCALE_FLAG=true
shift
;;
--ghostty)
GHOSTTY_FLAG=true
shift
;;
--VSCode)
VSCODE_FLAG=true
shift
;;
--beyondcompare)
BEYONDCOMPARE_FLAG=true
shift
;;
--bazel)
BAZEL_FLAG=true
shift
;;
-h|--help|-\?|--\?)
echo "Usage: $0 --ubuntu|--fedora [OPTIONS]"
echo ""
echo "Install and configure Linux development environment"
echo ""
echo "Required:"
echo " --ubuntu Configure for Ubuntu distribution"
echo " --fedora Configure for Fedora distribution"
echo ""
echo "Options:"
echo " -h, --help, -? Show this help message and exit"
echo " --full_dev Install full_dev set (Signal, Tailscale, Ghostty, VSCode)"
echo " --claude Install Claude (Fedora only)"
echo " --signal Install Signal Desktop application"
echo " --dotnet Install .NET SDK and tools"
echo " --pkgs_full_console Install full console packages (includes shell and dev packages)"
echo " --pkgs_full_graphical Install graphical applications (meld, prusa-slicer, openscad, gimp, inkscape, wireshark, freecad, libreoffice, zen)"
echo " --pkgs_shell Install minimal development packages (nano, tmux, curl)"
echo " --pkgs_dev Install developer packages (python, vim, putty, net-tools, mosh)"
echo " --starship Install Starship prompt"
echo " --lazygit Install LazyGit terminal UI for Git"
echo " --tailscale Install Tailscale VPN"
echo " --ghostty Install Ghostty terminal emulator (Fedora only)"
echo " --VSCode Install Visual Studio Code (Fedora only)"
echo " --beyondcompare Install Beyond Compare"
echo " --bazel Install Bazel build system"
exit 0
;;
*)
# Unknown option
shift
;;
esac
done
# Check if distro was specified
if [ -z "$DISTRO" ]; then
echo "Error: You must specify either --ubuntu or --fedora"
echo "Run $0 --help for usage information"
exit 1
fi
echo "Starting $DISTRO environment setup..."
echo "Data label: $DATA_LABEL"
# Check if --pkgs_shell flag was set
if [ "$PKGS_SHELL_FLAG" = true ]; then
echo "Installing minimal development packages..."
if [ "$DISTRO" = "ubuntu" ]; then
# Update package repositories for Ubuntu
sudo apt update
# Install minimal packages (nano, tmux, curl)
sudo apt-get install -y \
curl \
git \
mosh \
nano \
neovim \
tmux \
zip \
procps-ng
elif [ "$DISTRO" = "fedora" ]; then
# Update package repositories for Fedora
sudo dnf check-update
# Install minimal packages (nano, tmux, curl)
sudo dnf install -y \
bind-utils \
curl \
git \
mercurial \
mosh \
nano \
neovim \
tmux \
zip \
procps-ng
fi
fi
# Check if --pkgs_dev flag was set
if [ "$PKGS_DEV_FLAG" = true ]; then
echo "Installing developer packages..."
if [ "$DISTRO" = "ubuntu" ]; then
# Update package repositories for Ubuntu
sudo apt update
# Install developer packages
sudo apt-get install -y \
autoconf \
autotools-dev \
bless \
build-essential \
clang \
cmake \
gdb \
git-delta \
graphviz \
imhex \
libglib2.0-dev \
net-tools \
netcat \
pandoc \
putty-tools \
python3-venv \
tig \
weechat
elif [ "$DISTRO" = "fedora" ]; then
# Update package repositories for Fedora
sudo dnf check-update
# Install developer packages
sudo dnf install -y \
autoconf \
automake \
bless \
clang \
cmake \
gcc \
gcc-c++ \
gdb \
git-delta \
glib2-devel \
glib2-static \
libstdc++-static \
glibc-static \
graphviz \
imhex \
make \
net-tools \
netcat \
pandoc \
putty \
python3-virtualenv \
tig \
weechat
fi
fi
# Check if --pkgs_full_console flag was set
if [ "$PKGS_FULL_CONSOLE_FLAG" = true ]; then
echo "Installing full console packages..."
if [ "$DISTRO" = "ubuntu" ]; then
# Update package repositories for Ubuntu
sudo apt update
# Install all packages via apt-get (sorted alphabetically)
sudo apt-get install -y \
baobab \
bat \
bpfcc-tools \
fastfetch \
htop \
neofetch \
network-manager \
ntp \
podman \
rdiff-backup \
xclip
elif [ "$DISTRO" = "fedora" ]; then
# Update package repositories for Fedora
sudo dnf check-update
# Install all packages via dnf (sorted alphabetically)
sudo dnf install -y \
baobab \
bat \
bcc-tools \
chrony \
fastfetch \
htop \
NetworkManager \
podman \
rdiff-backup \
xclip
fi
fi
# Check if --pkgs_full_graphical flag was set
if [ "$PKGS_FULL_GRAPHICAL_FLAG" = true ]; then
echo "Installing full graphical packages..."
if [ "$DISTRO" = "ubuntu" ]; then
# Update package repositories for Ubuntu
sudo apt update
# Install graphical packages via apt-get (sorted alphabetically)
sudo apt-get install -y \
freecad \
gimp \
inkscape \
libreoffice \
meld \
openscad \
qownnotes \
wireshark
# Install PrusaSlicer - check if already installed
if ! command -v prusa-slicer &> /dev/null; then
echo "Installing PrusaSlicer..."
# PrusaSlicer may need to be installed via AppImage or snap
sudo snap install prusa-slicer || {
echo "PrusaSlicer snap not found, trying AppImage method..."
wget -O ~/PrusaSlicer.AppImage https://github.com/prusa3d/PrusaSlicer/releases/latest/download/PrusaSlicer-version-linux-x64.AppImage
chmod +x ~/PrusaSlicer.AppImage
echo "PrusaSlicer AppImage downloaded to ~/PrusaSlicer.AppImage"
}
fi
elif [ "$DISTRO" = "fedora" ]; then
# Update package repositories for Fedora
sudo dnf check-update
# Install graphical packages via dnf (sorted alphabetically)
sudo dnf install -y \
gimp \
inkscape \
libreoffice \
meld \
openscad \
qownnotes \
wireshark
# Install PrusaSlicer - check if already installed
if ! command -v prusa-slicer &> /dev/null; then
echo "Installing PrusaSlicer..."
# Try to install via dnf first
sudo dnf install -y prusa-slicer || {
echo "PrusaSlicer not found in repositories, trying AppImage method..."
wget -O ~/PrusaSlicer.AppImage https://github.com/prusa3d/PrusaSlicer/releases/latest/download/PrusaSlicer-version-linux-x64.AppImage
chmod +x ~/PrusaSlicer.AppImage
echo "PrusaSlicer AppImage downloaded to ~/PrusaSlicer.AppImage"
}
fi
fi
fi
# Check if --lazygit flag was set
if [ "$LAZYGIT_FLAG" = true ]; then
echo "Installing LazyGit..."
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*')
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
tar xf lazygit.tar.gz lazygit
sudo install lazygit -D -t /usr/local/bin/
fi
# Check if --starship flag was set
if [ "$STARSHIP_FLAG" = true ]; then
echo "Installing Starship prompt..."
curl -sS https://starship.rs/install.sh | sh
fi
# Check if --tailscale flag was set
if [ "$TAILSCALE_FLAG" = true ]; then
if command -v tailscale &> /dev/null; then
echo "Tailscale is already installed."
else
echo "Installing Tailscale VPN..."
curl -fsSL https://tailscale.com/install.sh | sh
echo "Tailscale installed. Run 'sudo tailscale up' to connect."
fi
fi
# Check if --ghostty flag was set (Fedora only)
if [ "$GHOSTTY_FLAG" = true ] && [ "$DISTRO" = "fedora" ]; then
if command -v ghostty &> /dev/null; then
echo "Ghostty terminal emulator is already installed."
else
echo "Building Ghostty terminal emulator from source..."
# Install build dependencies
echo "Installing build dependencies..."
sudo dnf install gtk4-devel gtk4-layer-shell-devel zig libadwaita-devel blueprint-compiler gettext
# Create temporary build directory
set -e
BUILD_DIR=$(mktemp -d)
cd "$BUILD_DIR"
# Clone Ghostty repository
echo "Cloning Ghostty repository..."
git clone https://github.com/ghostty-org/ghostty.git
cd ghostty
git checkout v1.2.0
# Build + /Install Ghostty
echo "Installing Ghostty..."
zig build -p $HOME/.local -Doptimize=ReleaseFast
mkdir -p "${HOME}/.local/share/applications"
OUTPUT_FILE="${HOME}/.local/share/applications/com.mitchellh.ghostty.desktop"
echo "[Desktop Entry]" > $OUTPUT_FILE
echo "Name=Ghostty" >> $OUTPUT_FILE
echo "Type=Application" >> $OUTPUT_FILE
echo "Comment=A terminal emulator" >> $OUTPUT_FILE
echo "Exec=${HOME}/.local/bin/ghostty" >> $OUTPUT_FILE
echo "Icon=com.mitchellh.ghostty" >> $OUTPUT_FILE
echo "Categories=System;TerminalEmulator;" >> $OUTPUT_FILE
echo "Keywords=terminal;tty;pty;" >> $OUTPUT_FILE
echo "StartupNotify=true" >> $OUTPUT_FILE
echo "Terminal=false" >> $OUTPUT_FILE
echo "Actions=new-window;" >> $OUTPUT_FILE
echo "X-GNOME-UsesNotifications=true" >> $OUTPUT_FILE
echo "X-TerminalArgExec=-e" >> $OUTPUT_FILE
echo "X-TerminalArgTitle=--title=" >> $OUTPUT_FILE
echo "X-TerminalArgAppId=--class=" >> $OUTPUT_FILE
echo "X-TerminalArgDir=--working-directory=" >> $OUTPUT_FILE
echo "X-TerminalArgHold=--wait-after-command" >> $OUTPUT_FILE
echo "[Desktop Action new-window]" >> $OUTPUT_FILE
echo "Name=New Window" >> $OUTPUT_FILE
echo "Exec=${HOME}/.local/bin/ghostty" >> $OUTPUT_FILE
chmod +x $OUTPUT_FILE
echo "Ghostty terminal emulator built and installed successfully!"
fi
elif [ "$GHOSTTY_FLAG" = true ] && [ "$DISTRO" = "ubuntu" ]; then
echo "Warning: Ghostty installation is only supported on Fedora"
fi
# Check if --VSCode flag was set (Fedora only)
if [ "$VSCODE_FLAG" = true ] && [ "$DISTRO" = "fedora" ]; then
if command -v code &> /dev/null; then
echo "Visual Studio Code is already installed."
else
echo "Installing Visual Studio Code..."
# Import the Microsoft GPG key
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
# Add the VSCode repository
echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/vscode.repo > /dev/null
# Update package cache and install VSCode
sudo dnf check-update
sudo dnf install -y code
echo "Visual Studio Code installed successfully!"
fi
elif [ "$VSCODE_FLAG" = true ] && [ "$DISTRO" = "ubuntu" ]; then
echo "Warning: VSCode installation via this script is only supported on Fedora"
fi
# Check if --dotnet flag was set
if [ "$DOTNET_FLAG" = true ]; then
# Install .NET SDK using the install script
wget https://dot.net/v1/dotnet-install.sh
chmod +x ./dotnet-install.sh
./dotnet-install.sh -c Current
./dotnet-install.sh -c LTS
./dotnet-install.sh --channel 8.0
# Configure .NET environment variables
export DOTNET_ROOT=$HOME/.dotnet
export PATH=$PATH:$DOTNET_ROOT
export PATH=$PATH:$DOTNET_ROOT/tools
# Install .NET global tools
dotnet tool install --global PowerShell
dotnet tool install --global git-credential-manager
fi
# Check if --signal flag was set
if [ "$SIGNAL_FLAG" = true ]; then
SIGNAL_INSTALLED=false
if [ "$DISTRO" = "ubuntu" ]; then
# Check if Signal is installed via apt
if dpkg -l | grep -q signal-desktop; then
SIGNAL_INSTALLED=true
fi
elif [ "$DISTRO" = "fedora" ]; then
# Check if Signal is installed via flatpak
if flatpak list | grep -q org.signal.Signal; then
SIGNAL_INSTALLED=true
fi
fi
if [ "$SIGNAL_INSTALLED" = true ]; then
echo "Signal Desktop is already installed."
else
echo "Installing Signal Desktop..."
if [ "$DISTRO" = "ubuntu" ]; then
# 1. Install our official public software signing key:
wget -O- https://updates.signal.org/desktop/apt/keys.asc | gpg --dearmor > signal-desktop-keyring.gpg
cat signal-desktop-keyring.gpg | sudo tee /usr/share/keyrings/signal-desktop-keyring.gpg > /dev/null
# 2. Add our repository to your list of repositories:
wget -O signal-desktop.sources https://updates.signal.org/static/desktop/apt/signal-desktop.sources
cat signal-desktop.sources | sudo tee /etc/apt/sources.list.d/signal-desktop.sources > /dev/null
# 3. Update your package database and install Signal:
sudo apt update && sudo apt install -y signal-desktop
elif [ "$DISTRO" = "fedora" ]; then
# Signal provides a Flatpak which is the recommended way for Fedora
sudo dnf install -y flatpak
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y flathub org.signal.Signal
fi
fi
fi
# Check if --claude flag was set (Fedora only)
if [ "$CLAUDE_FLAG" = true ]; then
echo "Installing Claude..."
curl -fsSL https://claude.ai/install.sh | bash
fi
# Check if --beyondcompare flag was set
if [ "$BEYONDCOMPARE_FLAG" = true ]; then
echo "Installing Beyond Compare..."
if [ "$DISTRO" = "ubuntu" ]; then
# Download and install Beyond Compare for Ubuntu
wget https://www.scootersoftware.com/bcompare-4.4.7.28397_amd64.deb
sudo apt install -y ./bcompare-4.4.7.28397_amd64.deb
rm bcompare-4.4.7.28397_amd64.deb
elif [ "$DISTRO" = "fedora" ]; then
# Download and install Beyond Compare for Fedora
wget https://www.scootersoftware.com/bcompare-4.4.7.28397.x86_64.rpm
sudo rpm --import https://www.scootersoftware.com/RPM-GPG-KEY-scootersoftware
sudo yum install -y ./bcompare-4.4.7.28397.x86_64.rpm
rm bcompare-4.4.7.28397.x86_64.rpm
fi
echo "Beyond Compare installed successfully!"
fi
# Check if --bazel flag was set
if [ "$BAZEL_FLAG" = true ]; then
if command -v bazel &> /dev/null; then
echo "Bazel is already installed."
else
echo "Installing Bazel build system..."
# Detect architecture
ARCH=$(uname -m)
case $ARCH in
x86_64)
BAZEL_ARCH="amd64"
;;
aarch64|arm64)
BAZEL_ARCH="arm64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
# Create ~/.local/bin if it doesn't exist
mkdir -p ~/.local/bin
# Install Bazelisk (recommended Bazel launcher) to user directory
echo "Installing Bazelisk for $ARCH architecture to ~/.local/bin..."
wget -O ~/.local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${BAZEL_ARCH}
chmod +x ~/.local/bin/bazel
echo "Bazel (via Bazelisk) installed successfully to ~/.local/bin/bazel"
fi
fi
echo "$DISTRO environment setup complete!"
File: env/Linux/devdir
#!/bin/bash
echo "DevDir Script!"
# ========================================
# PATH Management
# ========================================
# Add a directory to PATH if it exists
add_to_path() {
if [ $# -ne 1 ]; then
echo "Error: add_to_path requires exactly 1 argument (directory path)"
return 1
fi
local dir="$1"
# Check if directory exists
if [ -d "$dir" ]; then
# Check if directory is already in PATH
if [[ ":$PATH:" != *":$dir:"* ]]; then
export PATH="$dir:$PATH"
echo "Added '$dir' to PATH"
else
echo "Directory '$dir' is already in PATH"
fi
else
echo -e "\033[0;31mError: Directory '$dir' does not exist\033[0m"
echo "Press any key to continue..."
read -n 1 -s -r
fi
}
#
# We will shortly decide if we're running as part of an interactive shell, or on behalf of a script
#
# Run a (very) limited number of commands each time
#
# Add common directories to PATH
# add_to_path ~/.local/bin/tools
add_to_path ~/.local/bin
add_to_path ~/.dotnet
add_to_path ~/devdir/Tools/Containers/Scripts
# GIT
git config --global user.name "Chris Gray"
git config --global user.email "chgray@gmail.com"
# Only run if this is an interactive shell
case $- in
*i*) ;;
*) return 2>/dev/null || echo "skipping devdir, not interactive"; exit 0 ;;
esac
# Silently exit if running in VSCode
if [ "$TERM_PROGRAM" = "vscode" ]; then
echo "SKipping devdir setup, we're running on VSCODE"
return
fi
# Check if nvim config exists, if not clone it
if [ ! -d "${XDG_CONFIG_HOME:-$HOME/.config}"/nvim ]; then
git clone https://github.com/chgray/nvim.git "${XDG_CONFIG_HOME:-$HOME/.config}"/nvim
fi
refresh_file() {
# Check if exactly 2 arguments are provided
if [ $# -ne 2 ]; then
echo "Error: refresh_file requires exactly 2 arguments (source and destination)"
return 1
fi
local source="$2"
local destination="$1"
# Check if source file exists
if [ ! -f "$source" ]; then
echo "Error: Source file '$source' does not exist"
return 0
fi
# If destination doesn't exist, no need to compare
if [ ! -f "$destination" ]; then
echo "Destination file '$destination' does not exist. Nothing to refresh."
cp "$source" "$destination"
return 0
fi
# Compare files
if ! cmp -s "$source" "$destination"; then
echo "Files differ. Do you want to overwrite '$destination' with '$source'? (y/n)"
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
cp "$source" "$destination"
echo "File '$destination' has been refreshed from '$source'"
else
echo "File refresh cancelled"
fi
else
echo "Files are identical. No refresh needed."
fi
}
# ========================================
# Alias Management
# ========================================
# Create conditional aliases based on command availability
setup_editor_aliases() {
# Alias vim and vi to nvim if nvim is installed
if command -v nvim &> /dev/null; then
alias vim='nvim'
alias vi='nvim'
echo "Aliased vim and vi to nvim"
fi
}
# ========================================
# Terminal Configuration
# ========================================
# Configure terminal settings
configure_terminal() {
# Ghostty configuration
if [ ! -d $HOME/.config/ghostty/ ]; then
mkdir -p $HOME/.config/ghostty/
fi
refresh_file "$HOME/.config/ghostty/config" "$HOME/devdir/env/Mac/ghostty.config"
# Tmux configuration
refresh_file $HOME/.tmux.conf $HOME/devdir/env/Linux/.tmux.conf
tmux source $HOME/.tmux.conf 2>/dev/null
# Starship prompt configuration if installed
if command -v starship &> /dev/null; then
# Set up starship configuration
if [ ! -d $HOME/.config ]; then
mkdir -p $HOME/.config
fi
refresh_file "$HOME/.config/starship.toml" "$HOME/devdir/env/Linux/starship.toml"
# Initialize starship for bash
eval "$(starship init bash)"
echo "Starship prompt initialized"
fi
}
# ========================================
# Tmux Session Management
# ========================================
# Select and attach to a tmux session with a text-based menu (tmux only)
tmux_only_selection() {
# Check if tmux is installed
if ! command -v tmux &> /dev/null; then
echo "tmux is not installed on this system"
return 1
fi
# Check if we're already in a tmux session
if [ -n "$TMUX" ]; then
echo "Already in a tmux session"
return 0
fi
# Get list of tmux sessions
local sessions=$(tmux list-sessions 2>/dev/null)
# If no sessions exist, create a new one
if [ -z "$sessions" ]; then
echo "No tmux sessions found. Creating new session..."
tmux new-session
return 0
fi
# Display menu
echo "========================================="
echo "Available tmux sessions:"
echo "========================================="
# Parse and display sessions with numbers
local session_names=()
local counter=0
while IFS= read -r line; do
# Extract session name (first field before the colon)
local session_name=$(echo "$line" | cut -d: -f1)
session_names+=("$session_name")
echo " [$counter] $line"
((counter++))
done <<< "$sessions"
echo " [n] Create new session"
echo " [q] Quit without attaching"
echo "========================================="
# Prompt for selection
local choice
while true; do
read -p "Select a session (0-$((${#session_names[@]}-1)), n, or q): " choice
# Handle quit
if [[ "$choice" == "q" ]] || [[ "$choice" == "Q" ]]; then
echo "Exiting without attaching to a session"
return 0
fi
# Handle new session
if [[ "$choice" == "n" ]] || [[ "$choice" == "N" ]]; then
echo "Creating new tmux session..."
tmux new-session
return 0
fi
# Handle numeric selection
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 0 ] && [ "$choice" -lt "${#session_names[@]}" ]; then
local selected_session="${session_names[$choice]}"
echo "Attaching to session: $selected_session"
tmux attach-session -t "$selected_session"
return 0
else
echo "Invalid selection. Please try again."
fi
done
}
# Unified session selection - combines tmux sessions and SSH hosts
session_selection() {
# Check if we're already in a tmux session
if [ -n "$TMUX" ]; then
echo "Already in a tmux session"
return 0
fi
# Check if tmux is installed
local tmux_available=false
if command -v tmux &> /dev/null; then
tmux_available=true
fi
# Get list of tmux sessions if tmux is available
local tmux_sessions=""
if [ "$tmux_available" = true ]; then
tmux_sessions=$(tmux list-sessions 2>/dev/null)
fi
# Get list of SSH hosts
local ssh_hosts=$(parse_known_hosts 2>/dev/null)
# If no tmux sessions and no ssh hosts, create new tmux session
if [ -z "$tmux_sessions" ] && [ -z "$ssh_hosts" ]; then
if [ "$tmux_available" = true ]; then
echo "No tmux sessions or SSH hosts found. Creating new tmux session..."
tmux new-session
return 0
else
echo "No tmux or SSH hosts available"
return 0
fi
fi
# Display unified menu
echo "========================================="
echo "Session Selection"
echo "========================================="
local options=()
local option_types=()
local counter=0
# Add tmux sessions
if [ -n "$tmux_sessions" ]; then
echo "TMUX Sessions:"
while IFS= read -r line; do
local session_name=$(echo "$line" | cut -d: -f1)
options+=("$session_name")
option_types+=("tmux")
echo " [$counter] [TMUX] $line"
((counter++))
done <<< "$tmux_sessions"
echo ""
fi
# Add SSH hosts
if [ -n "$ssh_hosts" ]; then
echo "SSH Hosts:"
while IFS= read -r host; do
options+=("$host")
option_types+=("ssh")
echo " [$counter] [SSH] $host"
((counter++))
done <<< "$ssh_hosts"
echo ""
fi
# Add action options
echo "Actions:"
if [ "$tmux_available" = true ]; then
echo " [n] Create new tmux session"
fi
echo " [m] Manual SSH entry"
echo " [q] Quit without connecting"
echo "========================================="
# Prompt for selection
local choice
while true; do
read -p "Select (0-$((${#options[@]}-1)), $([ "$tmux_available" = true ] && echo "n, ")m, or q): " choice
# Handle quit
if [[ "$choice" == "q" ]] || [[ "$choice" == "Q" ]]; then
echo "Exiting without connecting"
return 0
fi
# Handle new tmux session
if [[ "$choice" == "n" ]] || [[ "$choice" == "N" ]]; then
if [ "$tmux_available" = true ]; then
echo "Creating new tmux session..."
tmux new-session
return 0
else
echo "tmux is not available"
continue
fi
fi
# Handle manual SSH entry
if [[ "$choice" == "m" ]] || [[ "$choice" == "M" ]]; then
read -p "Enter hostname or user@hostname: " manual_host
if [ -n "$manual_host" ]; then
clear
echo "Connecting to $manual_host..."
SKIP_TMUX=1 NO_TMUX=1 ssh "$manual_host"
return 0
else
echo "No hostname entered"
continue
fi
fi
# Handle numeric selection
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 0 ] && [ "$choice" -lt "${#options[@]}" ]; then
local selected_option="${options[$choice]}"
local selected_type="${option_types[$choice]}"
if [ "$selected_type" = "tmux" ]; then
echo "Attaching to tmux session: $selected_option"
tmux attach-session -t "$selected_option"
return 0
elif [ "$selected_type" = "ssh" ]; then
clear
echo "Connecting to SSH host: $selected_option"
SKIP_TMUX=1 NO_TMUX=1 ssh "$selected_option"
return 0
fi
else
echo "Invalid selection. Please try again."
fi
done
}
# Launch tmux if not already in a session
launch_tmux() {
# Skip tmux if SKIP_TMUX or NO_TMUX environment variable is set
if [ -n "$SKIP_TMUX" ] || [ -n "$NO_TMUX" ]; then
echo "Skipping tmux (SKIP_TMUX or NO_TMUX is set)"
return 0
fi
if [ -z "$TMUX" ]; then
session_selection
fi
}
# ========================================
# SSH Host Management
# ========================================
# Parse known_hosts file and extract unique hostnames
parse_known_hosts() {
local known_hosts_file="$HOME/.ssh/known_hosts"
# Check if known_hosts exists
if [ ! -f "$known_hosts_file" ]; then
echo "No known_hosts file found at $known_hosts_file"
return 1
fi
# Extract hostnames from known_hosts
# Handle various formats:
# - hostname ssh-rsa ...
# - [hostname]:port ssh-rsa ...
# - hostname,ip ssh-rsa ...
# Using sed/grep for BSD compatibility (macOS)
local hosts=$(cat "$known_hosts_file" | \
awk '{print $1}' | \
sed 's/,.*//' | \
sed 's/\[//g' | \
sed 's/\]:[0-9]*//g' | \
grep -v '^|' | \
sort -u)
echo "$hosts"
}
# Select and connect to an SSH host with a text-based menu
ssh_host_selection() {
echo "========================================="
echo "SSH Host Selection"
echo "========================================="
# Get list of known hosts
local hosts=$(parse_known_hosts)
if [ -z "$hosts" ]; then
echo "No hosts found in ~/.ssh/known_hosts"
echo "Press any key to continue..."
read -n 1 -s -r
return 1
fi
# Display menu
echo "Available SSH hosts from ~/.ssh/known_hosts:"
echo "-----------------------------------------"
# Parse and display hosts with numbers
local host_list=()
local counter=0
while IFS= read -r host; do
host_list+=("$host")
echo " [$counter] $host"
((counter++))
done <<< "$hosts"
echo " [m] Manual entry (enter hostname)"
echo " [q] Quit without connecting"
echo "========================================="
# Prompt for selection
local choice
while true; do
read -p "Select a host (0-$((${#host_list[@]}-1)), m, or q): " choice
# Handle quit
if [[ "$choice" == "q" ]] || [[ "$choice" == "Q" ]]; then
echo "Exiting without connecting"
return 0
fi
# Handle manual entry
if [[ "$choice" == "m" ]] || [[ "$choice" == "M" ]]; then
read -p "Enter hostname or user@hostname: " manual_host
if [ -n "$manual_host" ]; then
echo "Connecting to $manual_host..."
SKIP_TMUX=1 NO_TMUX=1 ssh "$manual_host"
return 0
else
echo "No hostname entered"
continue
fi
fi
# Handle numeric selection
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 0 ] && [ "$choice" -lt "${#host_list[@]}" ]; then
local selected_host="${host_list[$choice]}"
echo "Connecting to $selected_host..."
SKIP_TMUX=1 NO_TMUX=1 ssh "$selected_host"
return 0
else
echo "Invalid selection. Please try again."
fi
done
}
# Create an alias for quick access
alias sshq='ssh_host_selection'
# ========================================
# macOS-specific Functions
# ========================================
# Function for macOS-specific operations
mac_only_function() {
# Karabiner keyboard customization
if [ ! -d ~/.config/karabiner ]; then
mkdir -p ~/.config/karabiner
fi
defaults export com.lwouis.alt-tab-macos ~/devdir/env/Mac/Alt-Tab.defaults
defaults export Com.pilotmoon.scroll-reverser ~/devdir/env/Mac/Scroll-Reverser.defaults
refresh_file "$HOME/.config/karabiner/karabiner.json" "$HOME/devdir/env/Mac/karabiner.json"
# Add VSCode command line tool to PATH
if [ -d "/Applications/Visual Studio Code.app/Contents/Resources/app/bin" ]; then
export PATH="/Applications/Visual Studio Code.app/Contents/Resources/app/bin:$PATH"
fi
}
# Only call the function on macOS (Darwin)
if [[ "$(uname)" == "Darwin" ]]; then
mac_only_function
# Configure ls with color on macOS
export CLICOLOR=1
export LSCOLORS=GxFxCxDxBxegedabagaced
alias ls='ls -G'
alias ll='ls -alFG'
alias la='ls -AG'
alias l='ls -CFG'
fi
configure_terminal
setup_editor_aliases
launch_tmux
# Using bash script to check updates and create tmux window if needed
~/devdir/env/Linux/_check_devdir_updates.sh &
# Configure difftool to use nvim for side-by-side diffs
if command -v nvim &> /dev/null; then
git config --global diff.tool nvim
git config --global difftool.nvim.cmd 'nvim -d -c "wincmd l" -c "wincmd h" "$LOCAL" "$REMOTE" -c "set nofoldenable" -c "set diffopt+=iwhite,algorithm:histogram,filler"'
git config --global difftool.prompt false
git config --global alias.dt 'difftool'
echo "Git difftool configured to use nvim with side-by-side view"
fi
# Display system info with fastfetch if available
if command -v fastfetch &> /dev/null; then
fastfetch --structure "Title:Separator:OS:Host:Kernel:Uptime:Shell:Display:CPU:GPU:Memory:Disk:LocalIp:Battery" --logo small --separator-string "─"
fi
# clear
File: env/Linux/starship.toml
"$schema" = 'https://starship.rs/config-schema.json'
# Clean minimal prompt with better spacing
add_newline = true
# Minimal format - directory, git info, then prompt on new line
format = '''\[$directory\]($status)
$character'''
# Subtle prompt characters
[character]
disabled = false
success_symbol = '[›](dim green)'
error_symbol = '[›](dim yellow)'
# Clean directory display
[directory]
disabled = false
format = '[$path]($style)'
style = 'cyan'
truncation_length = 0
truncate_to_repo = false
truncation_symbol = '…/'
home_symbol = '~'
# Minimal git branch
[git_branch]
disabled = false
format = ' [$symbol$branch]($style)'
symbol = ''
style = 'purple'
# Clean git status indicators
[git_status]
disabled = false
format = '([$all_status$ahead_behind]($style))'
style = 'dim white'
conflicted = '='
ahead = '⇡'
behind = '⇣'
diverged = '⇕'
untracked = '?'
stashed = '$'
modified = '!'
staged = '+'
renamed = '»'
deleted = '✘'
# Gentle error status - only show on failure
[status]
disabled = false
symbol = ''
success_symbol = ''
format = '[\[$symbol errno=$status msg=$common_meaning$signal_name$maybe_int\]]($style) '
map_symbol = true
File: env/Mac/.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
source ~/devdir/env/Linux/devdir
File: env/Mac/.profile
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
File: env/Mac/.zshrc
File: env/Mac/ghostty.config
# ghostty +list-keybinds
keybind = alt+left=unbind
keybind = alt+right=unbind
keybind = cmd+1=unbind
keybind = cmd+2=unbind
keybind = cmd+3=unbind
keybind = cmd+4=unbind
keybind = cmd+5=unbind
keybind = cmd+6=unbind
keybind = cmd+7=unbind
keybind = cmd+8=unbind
keybind = cmd+9=unbind
keybind = cmd+n=unbind
keybind = cmd+k=unbind
keybind = alt+0=unbind
keybind = alt+1=unbind
keybind = alt+2=unbind
keybind = alt+3=unbind
keybind = alt+4=unbind
keybind = alt+5=unbind
keybind = alt+6=unbind
keybind = alt+7=unbind
keybind = alt+8=unbind
keybind = alt+9=unbind
keybind = alt+kp_0=unbind
keybind = alt+kp_1=unbind
keybind = alt+kp_2=unbind
keybind = alt+kp_3=unbind
keybind = alt+kp_4=unbind
keybind = alt+kp_5=unbind
keybind = alt+kp_6=unbind
keybind = alt+kp_7=unbind
keybind = alt+kp_8=unbind
keybind = alt+kp_9=unbind
keybind = alt+f1=unbind
keybind = alt+f2=unbind
keybind = alt+f3=unbind
keybind = alt+f4=unbind
keybind = alt+f5=unbind
keybind = alt+f6=unbind
keybind = alt+f7=unbind
keybind = alt+f8=unbind
keybind = alt+f9=unbind
keybind = alt+f10=unbind
keybind = alt+f11=unbind
keybind = alt+f12=unbind
keybind = alt+n=unbind
keybind = alt+k=unbind
keybind = super+plus=unbind
keybind = super+minus=unbind
keybind = super+equal=unbind
keybind = ctrl+plus=unbind
keybind = ctrl+minus=unbind
keybind = ctrl+equal=unbind
keybind = ctrl+zero=unbind
keybind = ctrl+plus=unbind
keybind = super+shift+plus=increase_font_size:1
keybind = super+shift+minus=decrease_font_size:1
theme = Rapture
# theme = BlueDolphin
# Empty values reset the configuration to the default value
font-family = "Monaco"
# Ensure proper terminal capabilities for tmux
term = xterm-256color
# Background image settings
background-opacity = 0.99
background-blur-radius = 40
# background-image "/Users/chrisgray/DevDir/EnvironmentTweaks/Tennessee.jpg"
File: env/Mac/karabiner.json
{
"profiles": [
{
"complex_modifications": {
"rules": [
{
"description": "EXTERNAL KEYBOARD : scroll_lock<-->fn mapping",
"manipulators": [
{
"from": {
"key_code": "scroll_lock",
"modifiers": { "optional": ["any"] }
},
"to": [{ "key_code": "fn" }],
"type": "basic"
}
]
},
{
"description": "X_Window Manager : {max, dock left, dock right, etc}",
"manipulators": [
{
"from": {
"key_code": "up_arrow",
"modifiers": { "mandatory": ["left_control", "fn"] }
},
"to": [
{
"key_code": "f",
"modifiers": ["left_control", "fn"]
}
],
"type": "basic"
},
{
"from": {
"key_code": "down_arrow",
"modifiers": { "mandatory": ["left_control", "fn"] }
},
"to": [
{
"key_code": "c",
"modifiers": ["left_control", "fn"]
}
],
"type": "basic"
}
]
},
{
"description": "[Ghostty] TMUX",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "f",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "f",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "left_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "left_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "right_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "right_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "up_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "up_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "down_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "down_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "1",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "1",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "2",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "2",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "3",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "3",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "4",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "4",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "5",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "5",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "6",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "6",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "7",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "7",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "8",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "8",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "9",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "9",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "0",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "0",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "k",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "r",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "r",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "equal_sign",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "equal_sign",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "hyphen",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "hyphen",
"modifiers": ["left_control"]
}
],
"type": "basic"
}
]
},
{
"description": "[iTerm] TMUX",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "f",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "f",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "left_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "left_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "right_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "right_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "up_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "up_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "down_arrow",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "down_arrow",
"modifiers": ["left_option"]
}
],
"type": "basic"
}
]
},
{
"description": "[iTerm] CMD+Space (launch)",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$",
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "spacebar",
"modifiers": { "mandatory": ["left_option"] }
},
"to": [
{
"key_code": "spacebar",
"modifiers": ["left_command"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.googlecode.iterm2$",
"^com.mitchellh.ghostty"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "spacebar",
"modifiers": { "mandatory": ["left_option"] }
},
"to": [
{
"key_code": "spacebar",
"modifiers": ["left_command"]
}
],
"type": "basic"
}
]
},
{
"description": "Chrome : control-f (find) only",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.google.Chrome$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "f",
"modifiers": { "mandatory": ["left_control"] }
},
"to": [
{
"key_code": "f",
"modifiers": ["left_command"]
}
],
"type": "basic"
}
]
},
{
"description": "RDP: map command and option back to themselves; no-op",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.microsoft.rdc.macos"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.microsoft.rdc.macos"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }],
"type": "basic"
}
]
},
{
"description": "RDP : Windows switching (ALT-TAB)",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.microsoft.rdc.macos"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "tab",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "tab",
"modifiers": ["left_option"]
}
],
"type": "basic"
},
{
"from": {
"key_code": "caps_lock",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "tab",
"modifiers": ["left_command"]
}
],
"type": "basic"
}
]
},
{
"description": "VSCODE: flip control and command",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.microsoft.VSCode$"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_control" },
"to": [{ "key_code": "left_command" }],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.microsot.VSCode$"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_control" }],
"type": "basic"
}
]
},
{
"description": "Screenshots : always copy into cliboard, not desktop (file)",
"manipulators": [
{
"from": {
"key_code": "4",
"modifiers": { "mandatory": ["left_command", "left_shift"] }
},
"to": [
{
"key_code": "4",
"modifiers": ["left_control", "left_shift", "left_command"]
}
],
"type": "basic"
}
]
},
{
"description": "PARALLELS : Windows switching (ALT-TAB)",
"enabled": false,
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "tab",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "tab",
"modifiers": ["left_option"]
}
],
"type": "basic"
}
]
},
{
"description": "[PARLLELS] OPTION<-->CMD SWAP - (dont foreget to disable parallels mappings by using 'generic' profile",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_command" },
"to": [{ "key_code": "left_option" }],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": { "key_code": "left_option" },
"to": [{ "key_code": "left_command" }],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "spacebar",
"modifiers": { "mandatory": ["left_option"] }
},
"to": [
{
"key_code": "spacebar",
"modifiers": ["left_command"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "spacebar",
"modifiers": { "mandatory": ["left_option"] }
},
"to": [
{
"key_code": "spacebar",
"modifiers": ["left_command"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "1",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "1",
"modifiers": ["left_control"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "2",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "2",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "3",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "3",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "4",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "4",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "5",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "5",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "6",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "6",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "7",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "7",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "8",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "8",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "9",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "9",
"modifiers": ["left_alt"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com.parallels.desktop.console$"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "0",
"modifiers": { "mandatory": ["left_command"] }
},
"to": [
{
"key_code": "0",
"modifiers": ["left_alt"]
}
],
"type": "basic"
}
]
}
]
},
"name": "Default profile",
"selected": true,
"virtual_hid_keyboard": { "keyboard_type_v2": "ansi" }
}
]
}