Skip to content

Commit fbf6545

Browse files
committed
feat: safari tweaks, auto titles, bash 3.2 compat, UX fixes
- Safari tweaks with DuckDuckGo default search engine - Auto terminal titles from breadcrumb stack, removed all manual set_title - App Store fallback to open store page on mas install failure - Homebrew TTY fix, human-readable bundle titles, silent skip for installed bundles - Spicetify/marketplace: Spotify install & quit checks, auto-install marketplace - FastFetch merged into single setup flow - Editor menu offers brew install instead of empty config dir - Claude Code repositioned in Customize menu, section comment cleanup - Fira Code Nerd Font check before Shell Full Setup - Microsoft Defender menu item hidden when not installed - Tweaks exit to main menu after applying - bash 3.2 compat: negative array index, ${var^}, set -u empty arrays - Removed dead mas parsing from brew.sh
1 parent c59a9e7 commit fbf6545

21 files changed

Lines changed: 273 additions & 166 deletions

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
# Changelog
22

3+
## 26.04.6
4+
5+
### New
6+
7+
- **Safari tweaks** — DuckDuckGo as default search engine via `SearchProviderShortName`
8+
- **App Store fallback** — when `mas install` fails, offers to open App Store page for the app
9+
- **Fira Code check** — Shell Full Setup checks for FiraCode Nerd Font before installing, offers brew install if missing
10+
- **Editor brew install** — when editor not found, offers to install via Homebrew instead of creating empty config dir
11+
12+
### Changed
13+
14+
- **Terminal titles** — removed all manual `set_title` calls; `crumb_push`/`crumb_pop` now auto-update terminal title from breadcrumb stack (`macrift › Apps › Homebrew`)
15+
- **Homebrew installer** — passes `< /dev/tty` to fix `stdin is not a TTY` error; removed noisy `✓ Homebrew installed` message
16+
- **Brew bundle titles** — human-readable names in multiselect (`Communication` instead of `Brewfile.comm`); installed count moved into box title
17+
- **Brew empty bundles** — silently skips fully-installed bundles instead of showing empty "press enter" screen
18+
- **Spicetify flow** — checks Spotify is installed and closed before applying; `spicetify backup apply` no longer crashes on `set -e`
19+
- **Marketplace restore** — auto-installs marketplace without asking; checks Spotify is closed; renamed menu item to "Restore marketplace settings"
20+
- **FastFetch** — merged Install + Apply config into single `setup_fastfetch` flow
21+
- **Customize menu** — Claude Code moved between Code Editor and Dock Layout
22+
- **Microsoft Defender** — menu item hidden when Defender not installed
23+
- **Tweaks flow** — exits to main menu after applying instead of looping back to category select
24+
- **`mas` parsing** — removed dead mas code from `brew.sh`; App Store apps handled exclusively by `appstore.sh`
25+
- **Claude Code comments** — replaced `# ── Section ──────` decorators with plain `# Section`
26+
27+
### Fixed
28+
29+
- **bash 3.2 compat**`${arr[-1]}``${arr[${#arr[@]}-1]}`, `${var^}``tr` uppercase
30+
- **`set -u` crashes** — empty array expansion guarded throughout `brew.sh` (`new_labels`, `clean_lines`, `mas_install_lines`)
31+
- **`$label` collision**`install_bundle` loop variable `label` no longer overwrites the function parameter
32+
33+
---
34+
335
## 26.04.5
436

537
### New

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
Fresh Mac → full setup in minutes.
3030

31-
- **See before you touch** — tweak wizard with per-item skip, apply, or reset. 60+ tweaks across 7 categories, all audited
31+
- **See before you touch** — tweak wizard with per-item skip, apply, or reset. 60+ tweaks across 8 categories, all audited
3232
- **83 curated packages** — 7 Homebrew bundles + Mac App Store, installed via multi-select
3333
- **12 bundled configs** — terminal profiles, shell aliases, Catppuccin theme, editor settings, dock layout — ready to apply
3434
- **Profile save/restore** — save your entire setup (Brewfile, macOS defaults, dotfiles, editor settings, iTerm2, dock layout, Raycast) to Desktop, Documents, or iCloud Drive and restore it anywhere
@@ -76,9 +76,9 @@ git clone https://github.com/emylfy/macrift.git ~/.macrift && ~/.macrift/macrift
7676

7777
| | Feature | What it does |
7878
| :-- | :--------------------- | :-------------------------------------------------------------------------- |
79-
| ⚙️ | **System Tweaks** | Dock, Finder, Keyboard, Trackpad, Screenshots, Hot Corners, Misc |
79+
| ⚙️ | **System Tweaks** | Dock, Finder, Safari, Keyboard, Trackpad, Screenshots, Hot Corners, Misc |
8080
| 📦 | **Apps & Packages** | 7 Homebrew bundles, Mac App Store, Spotify, .brewbak backup |
81-
| 🎨 | **Customize** | Profile, Terminal, Shell, Editor, Dock Layout, Wallpapers |
81+
| 🎨 | **Customize** | Profile, Terminal, Shell, Editor, Claude Code, Dock Layout, Wallpapers |
8282
| 🛡️ | **Security & Privacy** | Security status, hostname, DNS benchmark, hardening presets |
8383
| 🧹 | **Cleanup** | System cleanup via Mole — caches, logs, leftovers |
8484

@@ -90,6 +90,7 @@ Tweak wizard with per-item skip, apply, or reset to system default. Batch apply
9090
| :--------------- | :----------------------------------------------------------------------------- |
9191
| Dock | Autohide, tile size, animation speed, minimize effect, Spaces, recents |
9292
| Finder | Show hidden files & extensions, path bar, POSIX title, list view, no .DS_Store, quit menu, spring folders |
93+
| Safari | DuckDuckGo as default search engine |
9394
| Keyboard & Text | Key repeat speed, press-and-hold, auto-correct, smart substitutions |
9495
| Trackpad & Mouse | Tap to click, tracking speed, right-click, three-finger drag, drag windows anywhere |
9596
| Screenshots | Format, save location, shadow, date in filename |

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
26.04.5
1+
26.04.6

apps/appstore.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ appstore_menu() {
55
crumb_push "App Store"
66
while true; do
77
clear
8-
set_title "macrift > app store"
8+
99
local choice
1010
choice=$(show_menu "App Store" \
1111
"Install from list" \
@@ -110,6 +110,9 @@ install_appstore() {
110110
log_ok "${new_labels[$i]} installed"
111111
else
112112
log_warn "Failed: ${new_labels[$i]}"
113+
if confirm "Open App Store page?"; then
114+
open "macappstore://apps.apple.com/app/id${new_ids[$i]}"
115+
fi
113116
fi
114117
fi
115118
done

apps/brew.sh

Lines changed: 76 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ brew_menu() {
1212
crumb_push "Homebrew"
1313
while true; do
1414
clear
15-
set_title "macrift > brew"
15+
1616
local choice
1717
choice=$(show_menu "Homebrew" \
1818
"Development" \
@@ -29,13 +29,13 @@ brew_menu() {
2929
"Back")
3030

3131
case "$choice" in
32-
1) install_bundle "Brewfile.dev" ;;
33-
2) install_bundle "Brewfile.utils" ;;
34-
3) install_bundle "Brewfile.browsers" ;;
35-
4) install_bundle "Brewfile.comm" ;;
36-
5) install_bundle "Brewfile.media" ;;
37-
6) install_bundle "Brewfile.games" ;;
38-
7) install_bundle "Brewfile.fonts" ;;
32+
1) install_bundle "Brewfile.dev" "Development" ;;
33+
2) install_bundle "Brewfile.utils" "Utilities" ;;
34+
3) install_bundle "Brewfile.browsers" "Browsers" ;;
35+
4) install_bundle "Brewfile.comm" "Communication" ;;
36+
5) install_bundle "Brewfile.media" "Media" ;;
37+
6) install_bundle "Brewfile.games" "Games" ;;
38+
7) install_bundle "Brewfile.fonts" "Fonts" ;;
3939
8) install_all_bundles ;;
4040
9) brewbak_menu ;;
4141
0) break ;;
@@ -49,7 +49,7 @@ brewbak_menu() {
4949
crumb_push "Backup"
5050
while true; do
5151
clear
52-
set_title "macrift > brew > backup"
52+
5353
local choice
5454
choice=$(show_menu "Backup (.brewbak)" \
5555
"Import from .brewbak" \
@@ -68,6 +68,7 @@ brewbak_menu() {
6868

6969
install_bundle() {
7070
local brewfile="$1"
71+
local label="${2:-$brewfile}"
7172
local path="$MACRIFT_DIR/config/$brewfile"
7273

7374
if [[ ! -f "$path" ]]; then
@@ -97,36 +98,20 @@ install_bundle() {
9798
continue
9899
fi
99100
had_items=true
100-
local name="" label=""
101+
local name=""
101102
if [[ "$line" =~ ^brew[[:space:]]+\"([^\"]+)\" ]]; then
102103
name="${BASH_REMATCH[1]}"
103-
label="$name"
104104
elif [[ "$line" =~ ^cask[[:space:]]+\"([^\"]+)\" ]]; then
105105
name="${BASH_REMATCH[1]}"
106-
label="$name"
107-
elif [[ "$line" =~ ^mas[[:space:]]+\"([^\"]+)\",[[:space:]]*id:[[:space:]]*([0-9]+) ]]; then
108-
name="${BASH_REMATCH[1]}"
109-
local mas_id="${BASH_REMATCH[2]}"
110-
label="$name"
111-
if mas list 2>/dev/null | awk '{print $1}' | grep -qx "$mas_id"; then
112-
installed_count=$((installed_count + 1))
113-
else
114-
new_lines+=("$line")
115-
new_labels+=("$label")
116-
fi
117-
continue
118106
else
119107
continue
120108
fi
121109
if echo "$installed" | grep -qxF "$name"; then
122-
# For casks, verify the .app actually exists in /Applications
123110
if [[ "$line" =~ ^cask ]]; then
124-
# || true prevents set -e from triggering if find exits non-zero
125111
app_path=$(find "$(brew --prefix)/Caskroom"/"$name" -name "*.app" -maxdepth 3 2>/dev/null | head -1) || true
126112
if [[ -n "$app_path" ]]; then
127113
appname=$(basename "$app_path")
128114
if [[ ! -e "/Applications/$appname" ]]; then
129-
# Registered in brew but .app is missing — queue for silent reinstall
130115
broken_casks+=("$name")
131116
continue
132117
fi
@@ -135,33 +120,56 @@ install_bundle() {
135120
installed_count=$((installed_count + 1))
136121
else
137122
new_lines+=("$line")
138-
new_labels+=("$label")
123+
new_labels+=("$name")
139124
fi
140125
done < "$path"
141126

142-
# Clean up separators: remove leading, trailing, and consecutive
143-
local clean_lines=() clean_labels=()
144-
local prev_sep=true
145-
for ((i=0; i<${#new_labels[@]}; i++)); do
146-
if [[ "${new_labels[$i]}" == "---" ]]; then
147-
$prev_sep && continue
148-
prev_sep=true
149-
else
150-
prev_sep=false
127+
# Nothing new — handle broken casks if any, otherwise skip silently
128+
if [[ ! ${new_labels[*]+x} || ${#new_labels[@]} -eq 0 ]]; then
129+
if [[ ${broken_casks[*]+x} && ${#broken_casks[@]} -gt 0 ]]; then
130+
log_warn "${#broken_casks[@]} app(s) are missing from Applications"
131+
for cask in "${broken_casks[@]}"; do
132+
printf ' %b· %s%b\n' "$DIM" "$cask" "$RESET"
133+
done
134+
printf "\n"
135+
if [[ "$MACRIFT_DRY_RUN" != true ]] && confirm "Fix them now?"; then
136+
local cask_idx=0
137+
for cask in "${broken_casks[@]}"; do
138+
((cask_idx++))
139+
show_progress "$cask_idx" "${#broken_casks[@]}" "$cask"
140+
if brew reinstall --cask "$cask" &>/dev/null; then
141+
log_ok "$cask reinstalled"
142+
else
143+
log_warn "Failed to reinstall $cask"
144+
fi
145+
done
146+
fi
147+
wait_enter
151148
fi
152-
clean_lines+=("${new_lines[$i]}")
153-
clean_labels+=("${new_labels[$i]}")
154-
done
155-
# Remove trailing separator
156-
while [[ ${#clean_labels[@]} -gt 0 && "${clean_labels[-1]}" == "---" ]]; do
157-
unset 'clean_lines[-1]'
158-
unset 'clean_labels[-1]'
159-
done
160-
new_lines=("${clean_lines[@]}")
161-
new_labels=("${clean_labels[@]}")
149+
return 0
150+
fi
162151

163-
if [[ $installed_count -gt 0 ]]; then
164-
log_ok "$installed_count already installed"
152+
# Clean up separators: remove leading, trailing, and consecutive
153+
if [[ ${#new_labels[@]} -gt 0 ]]; then
154+
local clean_lines=() clean_labels=()
155+
local prev_sep=true
156+
for ((i=0; i<${#new_labels[@]}; i++)); do
157+
if [[ "${new_labels[$i]}" == "---" ]]; then
158+
$prev_sep && continue
159+
prev_sep=true
160+
else
161+
prev_sep=false
162+
fi
163+
clean_lines+=("${new_lines[$i]}")
164+
clean_labels+=("${new_labels[$i]}")
165+
done
166+
# Remove trailing separator
167+
while [[ ${#clean_labels[@]} -gt 0 && "${clean_labels[${#clean_labels[@]}-1]}" == "---" ]]; do
168+
unset "clean_lines[${#clean_lines[@]}-1]"
169+
unset "clean_labels[${#clean_labels[@]}-1]"
170+
done
171+
new_lines=(${clean_lines[@]+"${clean_lines[@]}"})
172+
new_labels=(${clean_labels[@]+"${clean_labels[@]}"})
165173
fi
166174

167175
# Handle missing apps separately — ask user once, then fix silently
@@ -205,8 +213,10 @@ install_bundle() {
205213
fi
206214

207215
# Multiselect for new packages only
216+
local ms_title="$label"
217+
[[ $installed_count -gt 0 ]] && ms_title="$label · $installed_count installed"
208218
local selected
209-
selected=$(show_multiselect "$brewfile" "${new_labels[@]}")
219+
selected=$(show_multiselect "$ms_title" "${new_labels[@]}")
210220

211221
if [[ -z "$selected" ]]; then
212222
return 0
@@ -216,15 +226,10 @@ install_bundle() {
216226
local tmp
217227
tmp=$(mktemp /tmp/macrift_brew_XXXXXX)
218228

219-
local mas_install_lines=()
220229
for ((i=0; i<${#new_labels[@]}; i++)); do
221230
[[ "${new_labels[$i]}" == "---" ]] && continue
222231
if echo "$selected" | grep -qxF "${new_labels[$i]}"; then
223-
if [[ "${new_lines[$i]}" =~ ^mas[[:space:]] ]]; then
224-
mas_install_lines+=("${new_lines[$i]}")
225-
else
226-
echo "${new_lines[$i]}" >> "$tmp"
227-
fi
232+
echo "${new_lines[$i]}" >> "$tmp"
228233
fi
229234
done
230235

@@ -233,11 +238,6 @@ install_bundle() {
233238
[[ -s "$tmp" ]] && while IFS= read -r line; do
234239
printf ' %b· %s%b\n' "$DIM" "$line" "$RESET"
235240
done < "$tmp"
236-
for mas_line in "${mas_install_lines[@]}"; do
237-
if [[ "$mas_line" =~ ^mas[[:space:]]+\"([^\"]+)\" ]]; then
238-
printf ' %b· %s (App Store)%b\n' "$DIM" "${BASH_REMATCH[1]}" "$RESET"
239-
fi
240-
done
241241
rm -f "$tmp"
242242
wait_enter
243243
return 0
@@ -251,27 +251,6 @@ install_bundle() {
251251
fi
252252
rm -f "$tmp"
253253

254-
local mas_idx=0 mas_total=${#mas_install_lines[@]}
255-
for mas_line in "${mas_install_lines[@]}"; do
256-
((mas_idx++))
257-
if [[ "$mas_line" =~ ^mas[[:space:]]+\"([^\"]+)\",[[:space:]]*id:[[:space:]]*([0-9]+) ]]; then
258-
local mas_name="${BASH_REMATCH[1]}"
259-
local mas_id="${BASH_REMATCH[2]}"
260-
[[ $mas_total -gt 1 ]] && show_progress "$mas_idx" "$mas_total" "$mas_name"
261-
local mas_out
262-
if mas_out=$(mas install "$mas_id" 2>&1); then
263-
log_ok "$mas_name installed"
264-
elif echo "$mas_out" | grep -qi "Redownload Unavailable"; then
265-
log_warn "$mas_name: not purchased with this account — opening App Store"
266-
open "https://apps.apple.com/app/id$mas_id"
267-
all_ok=false
268-
else
269-
log_warn "Failed to install $mas_name"
270-
all_ok=false
271-
fi
272-
fi
273-
done
274-
275254
if $all_ok; then
276255
log_ok "All packages installed"
277256
else
@@ -280,14 +259,29 @@ install_bundle() {
280259
wait_enter
281260
}
282261

262+
_bundle_label() {
263+
case "$1" in
264+
Brewfile.dev) echo "Development" ;;
265+
Brewfile.utils) echo "Utilities" ;;
266+
Brewfile.browsers) echo "Browsers" ;;
267+
Brewfile.comm) echo "Communication" ;;
268+
Brewfile.media) echo "Media" ;;
269+
Brewfile.games) echo "Games" ;;
270+
Brewfile.fonts) echo "Fonts" ;;
271+
*) echo "$1" ;;
272+
esac
273+
}
274+
283275
install_all_bundles() {
284276
if ! confirm "Install all bundles? (select packages in each)"; then
285277
return
286278
fi
287279

288280
for brewfile in "$MACRIFT_DIR"/config/Brewfile.*; do
289281
if [[ -f "$brewfile" ]]; then
290-
install_bundle "$(basename "$brewfile")"
282+
local name
283+
name=$(basename "$brewfile")
284+
install_bundle "$name" "$(_bundle_label "$name")"
291285
fi
292286
done
293287

apps/menu.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ apps_menu() {
55
crumb_push "Apps & Packages"
66
while true; do
77
clear
8-
set_title "macrift > apps"
8+
99
local choice
1010
choice=$(show_menu "Apps & Packages" \
1111
"Homebrew Bundles" \

apps/spicetify.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,20 @@ restore_marketplace() {
2121
fi
2222

2323
if [[ ! -d "$HOME/.config/spicetify/CustomApps/marketplace" ]]; then
24-
log_warn "Marketplace custom app not found"
25-
if confirm "Install marketplace?"; then
26-
curl -fsSL https://raw.githubusercontent.com/spicetify/marketplace/main/resources/install.sh | sh
27-
log_ok "Marketplace installed"
24+
log_info "Installing Marketplace..."
25+
curl -fsSL https://raw.githubusercontent.com/spicetify/marketplace/main/resources/install.sh | sh
26+
log_ok "Marketplace installed"
27+
fi
28+
29+
# Spotify must be closed for spicetify apply
30+
log_warn "Spotify must be closed before applying"
31+
if pgrep -x Spotify &>/dev/null; then
32+
if confirm "Quit Spotify now?"; then
33+
killall Spotify 2>/dev/null || true
34+
sleep 1
2835
else
36+
log_info "Close Spotify manually and retry"
37+
wait_enter
2938
return
3039
fi
3140
fi

0 commit comments

Comments
 (0)