Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions .github/workflows/shellcheck.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
# This is a basic workflow to help you get started with Actions

name: ShellCheck

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: ["main"]
pull_request:
branches: ["main"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
shellcheck:
name: Shellcheck
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
Expand Down
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Secrets and local config (never commit)
.zshrc.local
*.local
.env
.envrc
.envrc.local
__pycache__/
node_modules/
.node_version

# Compiled
*.elc

Expand Down
179 changes: 179 additions & 0 deletions bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#!/usr/bin/env bash
# bootstrap.sh — One-command dotfiles setup with feature selection
# Usage: bash bootstrap.sh [--all | --module <name> | --list | --non-interactive]
set -euo pipefail

DOTFILES_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export DOTFILES_ROOT

# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/lib.sh"
# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/core.sh"
# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/shell.sh"
# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/dev.sh"
# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/node.sh"
# shellcheck disable=SC1091
. "${DOTFILES_ROOT}/modules/docker.sh"

# ── Feature registry ───────────────────────────────────────────────────────────
FEATURE_NAMES=("core" "shell" "dev" "node" "docker")
FEATURE_LABELS=(
"Core Tools zsh, tmux, lsd, emacs, htop, neofetch, yazi"
"Shell starship, fzf, zoxide, atuin"
"Dev Tools gh, ripgrep, direnv, bat, delta, fd, jq, lazygit"
"Node.js fnm + Node LTS + commitizen"
"Docker Docker CE + Docker Compose"
)
# Default: core/shell/dev ON, node/docker OFF
FEATURE_SELECTED=(1 1 1 0 0)

# ── Banner ─────────────────────────────────────────────────────────────────────
print_banner() {
detect_os
printf "\n"
printf "${BOLD}╔══════════════════════════════════════════════════════════════╗${RESET}\n"
printf "${BOLD}║ dotfiles bootstrap — long-910/dotfiles ║${RESET}\n"
printf "${BOLD}╚══════════════════════════════════════════════════════════════╝${RESET}\n"
printf " OS: ${GREEN}%s${RESET} Package manager: ${GREEN}%s${RESET}\n\n" "$OS" "$PKG_MGR"
}

# ── Interactive menu ───────────────────────────────────────────────────────────
print_menu() {
printf " ${BOLD}機能ブロック選択 / Feature Selection${RESET}\n"
printf " %s\n" "────────────────────────────────────────────────────────────"
local i=0
for name in "${FEATURE_NAMES[@]}"; do
local mark=" "
[ "${FEATURE_SELECTED[$i]}" = "1" ] && mark="x"
printf " [%s] %d. %s\n" "$mark" "$((i+1))" "${FEATURE_LABELS[$i]}"
i=$((i + 1))
done
printf " %s\n" "────────────────────────────────────────────────────────────"
printf " 番号で切替 / [a]全選択 / [n]全解除 / [Enter]インストール / [q]終了\n"
printf " > "
}

run_menu() {
while true; do
printf "\033[2J\033[H" # clear screen
print_banner
print_menu
read -r input

case "$input" in
q|Q|quit|exit)
info "Aborted."
exit 0
;;
a|A)
FEATURE_SELECTED=(1 1 1 1 1)
;;
n|N)
FEATURE_SELECTED=(0 0 0 0 0)
;;
"")
break
;;
*)
# Toggle by number(s)
# shellcheck disable=SC2086
for tok in $input; do
if printf '%s' "$tok" | grep -qE '^[1-5]$'; then
local idx=$((tok - 1))
if [ "${FEATURE_SELECTED[$idx]}" = "1" ]; then
FEATURE_SELECTED[$idx]=0
else
FEATURE_SELECTED[$idx]=1
fi
fi
done
;;
esac
done
}

# ── Install selected features ──────────────────────────────────────────────────
install_selected() {
local i=0
for name in "${FEATURE_NAMES[@]}"; do
if [ "${FEATURE_SELECTED[$i]}" = "1" ]; then
case "$name" in
core) install_core ;;
shell) install_shell ;;
dev) install_dev ;;
node) install_node ;;
docker) install_docker ;;
esac
fi
i=$((i + 1))
done
}

# ── CLI argument handling ──────────────────────────────────────────────────────
list_modules() {
printf "Available modules:\n"
local i=0
for name in "${FEATURE_NAMES[@]}"; do
printf " %s — %s\n" "$name" "${FEATURE_LABELS[$i]}"
i=$((i + 1))
done
}

# ── Main ───────────────────────────────────────────────────────────────────────
main() {
detect_os

case "${1:-}" in
--all)
FEATURE_SELECTED=(1 1 1 1 1)
print_banner
install_selected
;;
--module)
local mod="${2:-}"
if [ -z "$mod" ]; then
error "--module requires a name. Use --list for available modules."
exit 1
fi
print_banner
FEATURE_SELECTED=(0 0 0 0 0)
local i=0
for name in "${FEATURE_NAMES[@]}"; do
[ "$name" = "$mod" ] && FEATURE_SELECTED[$i]=1
i=$((i + 1))
done
install_selected
;;
--list)
list_modules
exit 0
;;
--non-interactive)
print_banner
install_selected
;;
"")
print_banner
run_menu
install_selected
;;
*)
error "Unknown option: ${1}"
printf "Usage: %s [--all | --module <name> | --list | --non-interactive]\n" "$0"
exit 1
;;
esac

# Always append the sourcing block to ~/.zshrc
setup_zshrc_sourcing

printf "\n"
success "Bootstrap complete!"
printf "\n Run: ${BOLD}source ~/.zshrc${RESET} to apply changes in your current shell.\n\n"
}

main "$@"
27 changes: 27 additions & 0 deletions config/atuin/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# config/atuin/config.toml — Atuin shell history configuration

# Search mode: fuzzy matching
search_mode = "fuzzy"

# Keybinding style: emacs (consistent with .zshrc bindkey -e)
keymap_mode = "emacs"

# Filter mode: search all history (not just current session/directory)
filter_mode = "global"
filter_mode_shell_up_key_binding = "global"

# Do not sync automatically (opt-in sync only)
auto_sync = false
sync_frequency = "0"

# Show stats in search UI
show_preview = true

# Inline mode (results below current line, not full-screen)
inline_height = 20

# Style
style = "compact"

# Exit immediately on unique match with Enter
exit_mode = "return-original"
104 changes: 104 additions & 0 deletions config/starship.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# config/starship.toml — Starship prompt configuration
# Two-line prompt matching existing .zshrc style

format = """
$username\
$hostname\
[┌──(](bold green)$username[@](bold green)$hostname[)─[](bold green)$directory[$git_branch$git_status](bold green)[]\n](bold green)\
$git_state\
$nodejs$python$rust$golang\
$cmd_duration\
$line_break\
[└─](bold green)$character"""

# Prompt character
[character]
success_symbol = "[❯](bold blue)"
error_symbol = "[❯](bold red)"
vimcmd_symbol = "[❮](bold green)"

# Directory
[directory]
style = "bold reset"
truncation_length = 4
truncate_to_repo = true
format = "[$path]($style)[$read_only]($read_only_style)"

# Username — show only in SSH sessions
[username]
show_always = false
format = "[$user]($style)"
style_user = "bold blue"

# Hostname — show only in SSH sessions
[hostname]
ssh_only = true
format = "[@$hostname]($style)"
style = "bold blue"

# Git branch
[git_branch]
format = " [$symbol$branch(:$remote_branch)]($style)"
style = "bold purple"
symbol = " "

# Git status
[git_status]
format = "[$all_status$ahead_behind]($style) "
style = "bold red"
conflicted = "⚡"
ahead = "⇡${count}"
behind = "⇣${count}"
diverged = "⇡${ahead_count}⇣${behind_count}"
untracked = "?"
modified = "!"
staged = "+"
renamed = "»"
deleted = "✘"

# Git state (rebase, merge, etc.)
[git_state]
format = "[$state($progress_current/$progress_total)]($style) "
style = "bold yellow"

# Node.js — show only when relevant files present
[nodejs]
format = "[ $version]($style) "
style = "bold green"
detect_files = ["package.json", ".nvmrc", ".node-version"]
detect_folders = ["node_modules"]
detect_extensions = ["js", "mjs", "cjs", "ts"]

# Python — show only when relevant
[python]
format = "[ $version]($style) "
style = "bold yellow"
detect_extensions = ["py"]
detect_files = ["requirements.txt", "pyproject.toml", "setup.py", "Pipfile"]

# Rust
[rust]
format = "[ $version]($style) "
style = "bold red"
detect_extensions = ["rs"]
detect_files = ["Cargo.toml"]

# Go
[golang]
format = "[ $version]($style) "
style = "bold cyan"
detect_extensions = ["go"]
detect_files = ["go.mod"]

# Command duration — show for commands > 2s
[cmd_duration]
min_time = 2000
format = "[ $duration]($style) "
style = "bold yellow"

# Disable modules we don't use
[package]
disabled = true

[time]
disabled = true
28 changes: 28 additions & 0 deletions dotfiles/.gitmessage
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# <type>(<scope>): <subject>
# |←----- 50 chars max -------------------------------------------→|
#
# Types:
# feat A new feature
# fix A bug fix
# docs Documentation only changes
# style Formatting, missing semicolons (no logic change)
# refactor Code change that is neither fix nor feature
# test Adding or updating tests
# chore Build process, dependency updates, tooling
# perf Performance improvements
# ci CI/CD configuration changes
# build Build system changes
#
# Scope (optional): component or area affected (e.g., auth, api, ui)
#
# Subject: imperative mood, lowercase, no period at end
#
# ── Body (optional, 72 chars/line) ────────────────────────────────────────────
#
# Explain WHY the change was made and what problem it solves.
# Not HOW (the code shows that).
#
# ── Footer (optional) ─────────────────────────────────────────────────────────
#
# Reference issues: Closes #123, Fixes #456
# Breaking changes: BREAKING CHANGE: <description>
11 changes: 11 additions & 0 deletions dotfiles/.zshrc
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,14 @@ function yy() {
fi
rm -f -- "$tmp"
}

# === dotfiles modular config ===
# Load per-tool configs from ~/.zshrc.d/ (added by bootstrap.sh)
if [ -d "$HOME/.zshrc.d" ]; then
for _f in "$HOME/.zshrc.d"/*.zsh; do
[ -r "$_f" ] && . "$_f"
done
unset _f
fi
# Load machine-specific / secret config (never committed)
[ -f "$HOME/.zshrc.local" ] && . "$HOME/.zshrc.local"
Loading
Loading