Created
March 17, 2026 13:13
-
-
Save crsayen/f5fc53fd1fc8f9a3153580a861b57bab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ghostty-setup.sh | |
| # Replicates Ghostty + zsh configuration (Warp-like experience) | |
| # Safe to re-run: checks before installing/overwriting | |
| set -e | |
| echo "==> Checking for Homebrew..." | |
| if ! command -v brew &>/dev/null; then | |
| echo "Homebrew not found. Install it first: https://brew.sh" | |
| exit 1 | |
| fi | |
| # ─── Packages ────────────────────────────────────────────────────────────────── | |
| echo "==> Installing packages..." | |
| brew install --quiet \ | |
| ghostty \ | |
| fzf \ | |
| zsh-autosuggestions \ | |
| zsh-syntax-highlighting \ | |
| zsh-completions \ | |
| pyenv \ | |
| starship \ | |
| thefuck | |
| # Install Iosevka Nerd Font | |
| brew install --quiet --cask font-iosevka-nerd-font | |
| # Fix insecure zsh-completions directory permissions | |
| chmod go-w "$(brew --prefix)/share" | |
| chmod -R go-w "$(brew --prefix)/share/zsh" | |
| # ─── fzf-tab ─────────────────────────────────────────────────────────────────── | |
| echo "==> Installing fzf-tab..." | |
| if [[ ! -d ~/.zsh/fzf-tab ]]; then | |
| git clone https://github.com/Aloxaf/fzf-tab ~/.zsh/fzf-tab | |
| else | |
| echo " fzf-tab already installed, skipping." | |
| fi | |
| # ─── Ghostty config ──────────────────────────────────────────────────────────── | |
| echo "==> Writing Ghostty config..." | |
| mkdir -p ~/.config/ghostty | |
| cat > ~/.config/ghostty/config << 'EOF' | |
| # Shell integration - enables prompt markers, title updates, cursor shape changes | |
| shell-integration = zsh | |
| shell-integration-features = cursor,sudo,title | |
| # Option key as Alt - enables word-movement (Option+Left/Right) like a text editor | |
| macos-option-as-alt = true | |
| # Font - using Iosevka Nerd Font | |
| font-family = IosevkaNFM | |
| font-size = 14 | |
| # Colors — Catppuccin Mocha palette on black background | |
| background = #000000 | |
| foreground = #ffffff | |
| cursor-color = #f5e0dc | |
| selection-background = #6d28d9 | |
| selection-foreground = #ffffff | |
| # ANSI palette (0-7 normal, 8-15 bright) | |
| palette = 0=#45475a | |
| palette = 1=#f38ba8 | |
| palette = 2=#a6e3a1 | |
| palette = 3=#f9e2af | |
| palette = 4=#89b4fa | |
| palette = 5=#cba6f7 | |
| palette = 6=#89dceb | |
| palette = 7=#cdd6f4 | |
| palette = 8=#585b70 | |
| palette = 9=#f38ba8 | |
| palette = 10=#a6e3a1 | |
| palette = 11=#f9e2af | |
| palette = 12=#89b4fa | |
| palette = 13=#cba6f7 | |
| palette = 14=#89dceb | |
| palette = 15=#a6adc8 | |
| # Hide the folder proxy icon in the title bar | |
| macos-titlebar-proxy-icon = hidden | |
| # Window padding for readability | |
| window-padding-x = 8 | |
| window-padding-y = 8 | |
| # Clipboard | |
| clipboard-read = allow | |
| clipboard-write = allow | |
| # Keep the window open when the shell exits (useful for seeing errors) | |
| quit-after-last-window-closed = true | |
| # Cmd+Shift+Left/Right: send escape sequences for "select to line start/end" | |
| # zsh binds these to _select-to-bol / _select-to-eol | |
| keybind = super+shift+left=text:\x1b[1;6D | |
| keybind = super+shift+right=text:\x1b[1;6C | |
| EOF | |
| # ─── Starship config ─────────────────────────────────────────────────────────── | |
| echo "==> Writing Starship config..." | |
| mkdir -p ~/.config | |
| cat > ~/.config/starship.toml << 'EOF' | |
| # Starship prompt — Warp-style layout with Catppuccin Mocha colors | |
| # Line 1: runtime · directory · git branch+status · duration | |
| # Line 2: ❯ (input) | |
| format = """ | |
| $nodejs\ | |
| $python\ | |
| $conda\ | |
| $directory\ | |
| $git_branch\ | |
| $git_status\ | |
| $cmd_duration\ | |
| $line_break\ | |
| $character""" | |
| [nodejs] | |
| symbol = "" | |
| format = "[$version]($style) " | |
| style = "green" | |
| detect_files = ["package.json", ".nvmrc", ".node-version"] | |
| [directory] | |
| truncation_length = 4 | |
| truncate_to_repo = true | |
| style = "blue" | |
| format = "[$path]($style) " | |
| [git_branch] | |
| symbol = "" | |
| format = "[git:($branch)]($style) " | |
| style = "bold magenta" | |
| [git_status] | |
| ahead = "↑${count}" | |
| behind = "↓${count}" | |
| diverged = "↕" | |
| conflicted = "!" | |
| untracked = "" | |
| stashed = "" | |
| modified = "" | |
| staged = "" | |
| renamed = "" | |
| deleted = "" | |
| format = "[$ahead_behind$conflicted]($style)" | |
| style = "yellow" | |
| [python] | |
| symbol = "" | |
| pyenv_version_name = true | |
| style = "cyan" | |
| format = "[$version]($style) " | |
| [conda] | |
| symbol = "" | |
| style = "cyan" | |
| format = "[$environment]($style) " | |
| [cmd_duration] | |
| min_time = 0 | |
| style = "bright-black" | |
| format = "[(${duration})]($style) " | |
| [character] | |
| success_symbol = "[❯](bold white)" | |
| error_symbol = "[❯](bold red)" | |
| EOF | |
| # ─── .zshrc ──────────────────────────────────────────────────────────────────── | |
| echo "==> Writing ~/.zshrc..." | |
| cat > ~/.zshrc << 'ZSHRC' | |
| export PATH="$HOME/.local/bin:$PATH" | |
| # ─── pyenv ──────────────────────────────────────────────────────────────────── | |
| export PYENV_ROOT="$HOME/.pyenv" | |
| export PATH="$PYENV_ROOT/bin:$PATH" | |
| eval "$(pyenv init -)" | |
| # ─── Completions ────────────────────────────────────────────────────────────── | |
| FPATH="$(brew --prefix)/share/zsh-completions:$(brew --prefix)/share/zsh/site-functions:$FPATH" | |
| autoload -Uz compinit | |
| if [[ -n ~/.zcompdump(#qN.mh+24) ]]; then | |
| compinit | |
| else | |
| compinit -C | |
| fi | |
| # Completion styling (set before fzf-tab loads) | |
| zstyle ':completion:*' menu no | |
| zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' | |
| zstyle ':completion:*:descriptions' format '[%d]' | |
| # ─── fzf (load before fzf-tab so fzf-tab can wrap the right widget) ─────────── | |
| export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border' | |
| source "$(brew --prefix)/opt/fzf/shell/completion.zsh" | |
| # fzf-tab: replaces Tab completion menu with fzf popup | |
| # Must load: after compinit + fzf/completion.zsh, but before autosuggestions | |
| source ~/.zsh/fzf-tab/fzf-tab.plugin.zsh | |
| zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls -1 -G $realpath' | |
| zstyle ':fzf-tab:complete:*' fzf-flags --height=60% | |
| # ─── Autosuggestions & syntax highlighting (after fzf-tab) ──────────────────── | |
| source "$(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh" | |
| ZSH_AUTOSUGGEST_STRATEGY=(history completion) | |
| ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' | |
| source "$(brew --prefix)/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" | |
| # fzf key bindings: Ctrl+R (history), Ctrl+T (files), Option+C (cd) | |
| source "$(brew --prefix)/opt/fzf/shell/key-bindings.zsh" | |
| # ─── ls colors ──────────────────────────────────────────────────────────────── | |
| export CLICOLOR=1 | |
| export LSCOLORS=ExGxFxDxCxegedabagacad | |
| # ─── History ────────────────────────────────────────────────────────────────── | |
| HISTFILE=~/.zsh_history | |
| HISTSIZE=50000 | |
| SAVEHIST=50000 | |
| setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE HIST_REDUCE_BLANKS EXTENDED_HISTORY | |
| # ─── Editor-like keybindings (emacs mode) ───────────────────────────────────── | |
| bindkey -e | |
| zle_highlight=(region:bg=#6d28d9,fg=#ffffff) | |
| bindkey '^[[1;3D' backward-word # Option+Left | |
| bindkey '^[[1;3C' forward-word # Option+Right | |
| bindkey '^[b' backward-word | |
| bindkey '^[f' forward-word | |
| bindkey '^[^?' backward-kill-word # Option+Backspace | |
| bindkey '^[d' kill-word # Option+Delete | |
| bindkey '^[[H' beginning-of-line | |
| bindkey '^[[F' end-of-line | |
| bindkey '^[OH' beginning-of-line | |
| bindkey '^[OF' end-of-line | |
| bindkey '^[[1;5D' backward-word # Ctrl+Left | |
| bindkey '^[[1;5C' forward-word # Ctrl+Right | |
| # Keyboard selection | |
| _select-backward-word() { (( REGION_ACTIVE )) || zle set-mark-command; zle backward-word; REGION_ACTIVE=1 } | |
| _select-forward-word() { (( REGION_ACTIVE )) || zle set-mark-command; zle forward-word; REGION_ACTIVE=1 } | |
| _select-to-bol() { (( REGION_ACTIVE )) || zle set-mark-command; zle beginning-of-line; REGION_ACTIVE=1 } | |
| _select-to-eol() { (( REGION_ACTIVE )) || zle set-mark-command; zle end-of-line; REGION_ACTIVE=1 } | |
| _select-backward-char() { (( REGION_ACTIVE )) || zle set-mark-command; zle backward-char; REGION_ACTIVE=1 } | |
| _select-forward-char() { (( REGION_ACTIVE )) || zle set-mark-command; zle forward-char; REGION_ACTIVE=1 } | |
| zle -N _select-backward-word | |
| zle -N _select-forward-word | |
| zle -N _select-to-bol | |
| zle -N _select-to-eol | |
| zle -N _select-backward-char | |
| zle -N _select-forward-char | |
| bindkey '^[[1;4D' _select-backward-word # Option+Shift+Left | |
| bindkey '^[[1;4C' _select-forward-word # Option+Shift+Right | |
| bindkey '^[[1;2D' _select-backward-char # Shift+Left | |
| bindkey '^[[1;2C' _select-forward-char # Shift+Right | |
| bindkey '^[[1;6D' _select-to-bol # Cmd+Shift+Left | |
| bindkey '^[[1;6C' _select-to-eol # Cmd+Shift+Right | |
| _delete-or-kill-region() { | |
| if (( REGION_ACTIVE )); then zle kill-region | |
| else zle delete-char; fi | |
| } | |
| _backspace-or-kill-region() { | |
| if (( REGION_ACTIVE )); then zle kill-region | |
| else zle backward-delete-char; fi | |
| } | |
| zle -N _delete-or-kill-region | |
| zle -N _backspace-or-kill-region | |
| bindkey '^[[3~' _delete-or-kill-region # Delete key | |
| bindkey '^?' _backspace-or-kill-region # Backspace | |
| autoload -Uz up-line-or-beginning-search down-line-or-beginning-search | |
| zle -N up-line-or-beginning-search | |
| zle -N down-line-or-beginning-search | |
| bindkey '^[[A' up-line-or-beginning-search | |
| bindkey '^[[B' down-line-or-beginning-search | |
| bindkey '^[OA' up-line-or-beginning-search | |
| bindkey '^[OB' down-line-or-beginning-search | |
| autoload -Uz edit-command-line | |
| zle -N edit-command-line | |
| bindkey '^X^E' edit-command-line # Ctrl+X Ctrl+E: open line in $EDITOR | |
| # ─── thefuck ────────────────────────────────────────────────────────────────── | |
| eval "$(thefuck --alias)" | |
| # ─── Starship prompt ────────────────────────────────────────────────────────── | |
| eval "$(starship init zsh)" | |
| ZSHRC | |
| # Clear stale completion cache | |
| rm -f ~/.zcompdump* | |
| echo "" | |
| echo "Done! Open Ghostty and you're set." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment