Procházet zdrojové kódy

feat: publish public-safe app settings (ghostty, zed, rectangle)

Add a config/ tree mirroring ~/.config, plus a default-deny .gitignore:
config/** is ignored and only the vetted, secret-free files are opted back
in. setup.sh symlinks ghostty + zed configs into place; Rectangle ships a
cleaned plist export + import.sh (a prefs domain can't be symlinked).

VoiceInk was deliberately excluded (account/token/transcription state).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tom McKenzie před 1 měsícem
rodič
revize
68609d86a0

+ 14 - 0
.gitignore

@@ -4,3 +4,17 @@
 .rc.d/local.sh
 .zshrc.d/local.zsh
 bak
+
+# Application settings: ignore the whole tree by default, then opt-in ONLY the
+# files we've vetted as public-safe. Anything new under config/ stays private
+# until explicitly un-ignored here (guards against leaking app secrets).
+config/**
+!config/ghostty/
+!config/ghostty/config
+!config/zed/
+!config/zed/settings.json
+!config/zed/keymap.json
+!config/zed/tasks.json
+!config/rectangle/
+!config/rectangle/com.knollsoft.Rectangle.plist
+!config/rectangle/import.sh

+ 33 - 0
config/ghostty/config

@@ -0,0 +1,33 @@
+theme = Dark Pastel
+
+background-blur-radius = 20
+background-opacity = 0.85
+
+# font-family = JetBrainsMono
+font-family = Menlo
+font-size = 13
+font-thicken
+cursor-style = block
+cursor-style-blink = true
+
+scrollback-limit = 4294967295
+
+shell-integration = zsh
+shell-integration-features = no-cursor
+copy-on-select = clipboard
+
+window-save-state = always
+
+macos-titlebar-style = tabs
+macos-option-as-alt = true
+macos-icon = custom-style
+# macos-icon-frame = chrome
+macos-icon-ghost-color = #9580FF
+# macos-icon-screen-color = #1E1E2E, #302D41
+
+keybind = global:alt+`=toggle_quick_terminal
+quick-terminal-position = bottom
+quick-terminal-autohide = false
+quick-terminal-animation-duration = 0.1
+# copy-on-select = false
+keybind = shift+enter=text:\x1b\r

+ 192 - 0
config/rectangle/com.knollsoft.Rectangle.plist

@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>allowAnyShortcut</key>
+	<true/>
+	<key>almostMaximize</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>44</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>alternateDefaultShortcuts</key>
+	<true/>
+	<key>bottomHalf</key>
+	<dict/>
+	<key>bottomLeft</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>38</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>bottomRight</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>37</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>center</key>
+	<dict/>
+	<key>centerHalf</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>42</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>centerThird</key>
+	<dict/>
+	<key>firstFourth</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>41</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>firstThird</key>
+	<dict/>
+	<key>firstThreeFourths</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>41</integer>
+		<key>modifierFlags</key>
+		<integer>655360</integer>
+	</dict>
+	<key>firstTwoThirds</key>
+	<dict/>
+	<key>footprintAnimationDurationMultiplier</key>
+	<real>0.75</real>
+	<key>hapticFeedbackOnSnap</key>
+	<integer>1</integer>
+	<key>hideMenubarIcon</key>
+	<true/>
+	<key>internalTilingNotified</key>
+	<true/>
+	<key>landscapeSnapAreas</key>
+	<string>[1,{"action":15},2,{"action":2},8,{"action":14},5,{"action":34},3,{"action":16},6,{"action":13},4,{"compound":-2},7,{"compound":-4}]</string>
+	<key>larger</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>47</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>lastFourth</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>39</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>lastThird</key>
+	<dict/>
+	<key>lastThreeFourths</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>39</integer>
+		<key>modifierFlags</key>
+		<integer>655360</integer>
+	</dict>
+	<key>lastTwoThirds</key>
+	<dict/>
+	<key>lastVersion</key>
+	<string>101</string>
+	<key>launchOnLogin</key>
+	<true/>
+	<key>leftHalf</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>33</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>maximize</key>
+	<dict/>
+	<key>maximizeHeight</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>44</integer>
+		<key>modifierFlags</key>
+		<integer>655360</integer>
+	</dict>
+	<key>nextDisplay</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>30</integer>
+		<key>modifierFlags</key>
+		<integer>655360</integer>
+	</dict>
+	<key>previousDisplay</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>33</integer>
+		<key>modifierFlags</key>
+		<integer>655360</integer>
+	</dict>
+	<key>reflowTodo</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>45</integer>
+		<key>modifierFlags</key>
+		<integer>786432</integer>
+	</dict>
+	<key>restore</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>6</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>rightHalf</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>30</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>smaller</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>43</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>stageSize</key>
+	<real>30.634340286254883</real>
+	<key>subsequentExecutionMode</key>
+	<integer>0</integer>
+	<key>todo</key>
+	<integer>2</integer>
+	<key>toggleTodo</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>11</integer>
+		<key>modifierFlags</key>
+		<integer>786432</integer>
+	</dict>
+	<key>topHalf</key>
+	<dict/>
+	<key>topLeft</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>4</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>topRight</key>
+	<dict>
+		<key>keyCode</key>
+		<integer>40</integer>
+		<key>modifierFlags</key>
+		<integer>524288</integer>
+	</dict>
+	<key>unsnapRestore</key>
+	<integer>2</integer>
+	<key>windowSnapping</key>
+	<integer>2</integer>
+</dict>
+</plist>

+ 28 - 0
config/rectangle/import.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+# Restore Rectangle settings (shortcuts + behavior) on a new machine.
+#
+# Rectangle stores its config as a macOS preferences domain (a cached binary
+# plist), so it can't be symlinked like a text config. We version a *cleaned*
+# export (shortcuts + behavior only — no window-frame or Sparkle-updater noise)
+# and import it here.
+#
+# NOTE: `defaults import` REPLACES the Rectangle domain. Any existing prefs are
+# backed up to bak/ first. Safe on a fresh machine.
+set -euo pipefail
+
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+DOMAIN="com.knollsoft.Rectangle"
+SRC="$DIR/${DOMAIN}.plist"
+BAK="$HOME/dotfiles/bak"
+
+[ -f "$SRC" ] || { echo "missing $SRC" >&2; exit 1; }
+
+mkdir -p "$BAK"
+if defaults export "$DOMAIN" - >/dev/null 2>&1; then
+  defaults export "$DOMAIN" "$BAK/${DOMAIN}.backup.plist" 2>/dev/null \
+    && echo "Backed up existing Rectangle prefs to bak/${DOMAIN}.backup.plist"
+fi
+
+defaults import "$DOMAIN" "$SRC"
+killall Rectangle 2>/dev/null || true
+echo "Rectangle settings imported. Relaunch Rectangle to apply."

+ 87 - 0
config/zed/keymap.json

@@ -0,0 +1,87 @@
+[
+  {
+    "bindings": {
+      "cmd-k cmd-,": "zed::OpenSettings",
+      "cmd-shift-r": "editor::Rename",
+      "cmd-shift-c": "workspace::CopyRelativePath",
+      "cmd-alt-shift-c": "editor::CopyPermalinkToLine",
+      "cmd-o": "file_finder::Toggle",
+      "cmd-shift-o": ["projects::OpenRecent", { "create_new_window": false }],
+      "cmd-t": "outline::Toggle",
+      "cmd-shift-t": "pane::ReopenClosedItem",
+      "cmd-p": "command_palette::Toggle",
+      "cmd-shift-p": "project_symbols::Toggle",
+      "alt-cmd-o": "workspace::Open",
+      "cmd-alt-n": ["task::Spawn", { "task_name": "agent terminal" }]
+    }
+  },
+  {
+    "context": "Editor",
+    "bindings": {
+      "cmd-shift-k": "editor::DeleteLine",
+      // "cmd-shift-e": "pane::RevealInProjectPanel"
+      "alt-shift-i": "editor::SplitSelectionIntoLines",
+      "cmd-,": "editor::Hover",
+      "cmd-;": "editor::FindAllReferences",
+      "cmd-alt-ctrl-[": "editor::FoldSelectedRanges",
+      "cmd-k cmd-l": "vim::ConvertToLowerCase",
+      "cmd-k cmd-u": "editor::ConvertToUpperCase",
+      "cmd-k cmd-i": "editor::ConvertToUpperCamelCase",
+      "cmd-k cmd-o": "editor::ConvertToLowerCamelCase"
+    }
+  },
+  {
+    "context": "ProjectPanel",
+    "bindings": {
+      "cmd-h": "project_panel::CollapseAllEntries"
+    }
+  },
+  {
+    "context": "ProjectPanel && not_editing",
+    "bindings": {
+      "alt-enter": "project_panel::Open"
+    }
+  },
+  {
+    // cmd-N selects tab N (mac-native). This shadows the default
+    // workspace::ActivatePane (jump to split N), so that moves to ctrl-N below
+    // — which was the now-redundant default tab binding (pane::ActivateItem).
+    "context": "Pane",
+    "bindings": {
+      "cmd-1": ["pane::ActivateItem", 0],
+      "cmd-2": ["pane::ActivateItem", 1],
+      "cmd-3": ["pane::ActivateItem", 2],
+      "cmd-4": ["pane::ActivateItem", 3],
+      "cmd-5": ["pane::ActivateItem", 4],
+      "cmd-6": ["pane::ActivateItem", 5],
+      "cmd-7": ["pane::ActivateItem", 6],
+      "cmd-8": ["pane::ActivateItem", 7],
+      "cmd-9": ["pane::ActivateItem", 8],
+      "ctrl-1": ["workspace::ActivatePane", 0],
+      "ctrl-2": ["workspace::ActivatePane", 1],
+      "ctrl-3": ["workspace::ActivatePane", 2],
+      "ctrl-4": ["workspace::ActivatePane", 3],
+      "ctrl-5": ["workspace::ActivatePane", 4],
+      "ctrl-6": ["workspace::ActivatePane", 5],
+      "ctrl-7": ["workspace::ActivatePane", 6],
+      "ctrl-8": ["workspace::ActivatePane", 7],
+      "ctrl-9": ["workspace::ActivatePane", 8]
+    }
+  }
+  // inline suggestions
+  // {
+  //   "context": "Editor && inline_completion && !showing_completions",
+  //   "bindings": {
+  //     // "tab": "editor::Tab",
+  //     // "alt+tab": "editor::AcceptInlineCompletion"
+  //     "tab": "editor::AcceptInlineCompletion"
+  //   }
+  // },
+  // {
+  //   "context": "Editor && showing_completions",
+  //   "bindings": {
+  //     "enter": "editor::Newline",
+  //     "tab": "editor::ConfirmCompletion"
+  //   }
+  // }
+]

+ 205 - 0
config/zed/settings.json

@@ -0,0 +1,205 @@
+//
+// Zed settings — keep this MINIMAL: only overrides vs Zed defaults.
+// Full key reference: command palette -> "zed: open default settings".
+// Docs: https://zed.dev/docs/configuring-zed
+//
+// Rebuilt 2026-05-31: AI/agent config, MCP context servers, and the
+// transparency theme_overrides were stripped for a clean baseline.
+// Backup of the old config: ~/zed-backup-20260531-151032.zip
+//
+{
+  // theme
+  "agent_servers": {
+    "claude-acp": {
+      "default_config_options": {
+        "mode": "acceptEdits",
+      },
+      "type": "registry",
+    },
+  },
+  "minimum_split_diff_width": 220.0,
+  "diff_view_style": "split",
+  "agent": {
+    "use_modifier_to_send": true,
+    "thinking_display": "preview",
+    "play_sound_when_agent_done": "when_hidden",
+    "sidebar_side": "right",
+    "button": true,
+    "favorite_models": [],
+    "model_parameters": [],
+  },
+  "theme": {
+    "mode": "dark",
+    "light": "One Light",
+    "dark": "macOS Classic Dark"
+  },
+  "icon_theme": {
+    "mode": "dark",
+    "light": "Monospace Icon Theme - Dark",
+    "dark": "Monospace Icon Theme - Dark"
+  },
+
+  // fonts
+  "ui_font_family": "Iosevka Aile",
+  "ui_font_size": 14,
+  "buffer_font_family": "Iosevka Slab Extended",
+  "buffer_font_size": 14,
+
+  // editor
+  "show_whitespaces": "selection",
+  "soft_wrap": "editor_width",
+  "always_treat_brackets_as_autoclosed": true,
+  "use_autoclose": true,
+  "confirm_quit": true,
+  "active_pane_modifiers": {
+    "inactive_opacity": 0.8,
+  },
+
+  // one focused window per project
+  "cli_default_open_behavior": "new_window",
+  "use_system_window_tabs": false,
+
+  // ui chrome
+  "title_bar": {
+    "show_menus": false,
+    "show_branch_status_icon": false,
+  },
+  "status_bar": {
+    "show_active_file": false,
+    "line_endings_button": false,
+  },
+  "collaboration_panel": {
+    "button": false,
+  },
+  "bottom_dock_layout": "full",
+
+  // tabs
+  "preview_tabs": {
+    "enable_keep_preview_on_code_navigation": true,
+    "enable_preview_from_file_finder": true,
+  },
+  "tab_bar": {
+    "show_pinned_tabs_in_separate_row": true,
+    "show_nav_history_buttons": true,
+  },
+  "tabs": {
+    "show_diagnostics": "errors",
+    "activate_on_close": "left_neighbour",
+    "file_icons": false,
+    "close_position": "left",
+    "git_status": true,
+  },
+
+  // search
+  "search": {
+    "button": true,
+    "regex": true,
+  },
+
+  // minimap
+  "minimap": {
+    "thumb_border": "none",
+    "show": "auto",
+    "thumb": "hover",
+    // "thumb_border": "left_open",
+    "current_line_highlight": "line",
+  },
+
+  // git
+  "git": {
+    "inline_blame": {
+      "min_column": 80,
+      "show_commit_summary": true,
+    },
+    "git_gutter": null,
+    "worktree_directory": ".worktrees",
+  },
+
+  // terminal
+  "terminal": {
+    "font_family": "Iosevka Term Slab",
+    "toolbar": {
+      "breadcrumbs": true,
+    },
+    "env": {
+      "EDITOR": "zed --wait",
+    },
+  },
+
+  // panels
+  "project_panel": {
+    "entry_spacing": "comfortable",
+    "button": true,
+    "indent_size": 7,
+    "auto_reveal_entries": true,
+    "auto_fold_dirs": true,
+  },
+  "outline_panel": {
+    "dock": "left",
+    "indent_size": 7,
+  },
+
+  // type hints / lsp
+  "inlay_hints": {
+    "enabled": false,
+    "show_type_hints": false,
+    "show_parameter_hints": true,
+    "show_other_hints": true,
+  },
+  "lsp": {
+    "typescript-language-server": {
+      "initialization_options": {
+        "preferences": {
+          "includeInlayParameterNameHints": "all",
+          "includeInlayFunctionParameterTypeHints": true,
+          "includeInlayVariableTypeHints": true,
+          "includeInlayPropertyDeclarationTypeHints": true,
+          "includeInlayFunctionLikeReturnTypeHints": true,
+        },
+      },
+    },
+    "pyright": {
+      "settings": {
+        "python.analysis": {
+          "diagnosticMode": "workspace",
+        },
+        "python": {
+          "pythonPath": ".venv/bin/python",
+        },
+      },
+    },
+    "typos": {
+      "initialization_options": {
+        "diagnosticSeverity": "Hint",
+      },
+    },
+  },
+
+  // languages / formatting
+  "languages": {
+    "JSON": {
+      "prettier": { "allowed": true, "parser": "json" },
+    },
+    "JavaScript": {
+      "format_on_save": "on",
+      "code_actions_on_format": { "source.organizeImports": true },
+    },
+    "TypeScript": {
+      "format_on_save": "on",
+      "code_actions_on_format": { "source.organizeImports": true },
+    },
+    "TSX": {
+      "format_on_save": "on",
+      "code_actions_on_format": {
+        "source.organizeImports": true,
+        "source.fixAll": true,
+      },
+    },
+    "Python": {
+      "format_on_save": "on",
+      "formatter": {
+        "external": { "command": "black", "arguments": ["-"] },
+      },
+    },
+  },
+}

+ 20 - 0
config/zed/tasks.json

@@ -0,0 +1,20 @@
+// Static tasks. Bound to keys in keymap.json.
+[
+  {
+    // Attach (or create) the project's tmux session — same parent_current naming
+    // as the `tt` shell alias. Opens as a CENTER tab, not the bottom dock.
+    // allow_concurrent_runs:false → one canonical, reusable tmux terminal.
+    "label": "agent terminal",
+    "command": "tmux new-session -A -s \"$(basename \"$(dirname \"$ZED_WORKTREE_ROOT\")\")_$(basename \"$ZED_WORKTREE_ROOT\")\" \"$SHELL -ic cc\"",
+    "cwd": "$ZED_WORKTREE_ROOT",
+    "reveal_target": "center",
+    "use_new_terminal": false,
+    "allow_concurrent_runs": false,
+    "reveal": "always",
+    "hide": "on_success",
+    "shell": "system",
+    "env": {
+      "EDITOR": "zed --wait",
+    },
+  },
+]

+ 27 - 2
setup.sh

@@ -10,7 +10,32 @@ mkdir -p $olddir
 
 ## move any existing dotfiles in homedir to dotfiles_old directory, then create symlinks
 for file in $files; do
-    mv -f "$HOME/$file" $olddir
+    [ -e "$HOME/$file" ] && mv -f "$HOME/$file" $olddir
     echo "Creating symlink to $file in ~"
-    ln -s "$dir/$file" "$HOME/$file"
+    ln -sfn "$dir/$file" "$HOME/$file"
 done
+
+# ── App settings ─────────────────────────────────────────────────────────────
+# Symlink vetted, public-safe app configs from config/ into their real homes.
+# (See .gitignore — config/ is ignored by default, these files are opted in.)
+link_config() {   # link_config <repo-path> <abs-dest>
+    local src="$dir/$1" dest="$2"
+    [ -e "$src" ] || return 0
+    mkdir -p "$(dirname "$dest")"
+    if [ -e "$dest" ] && [ ! -L "$dest" ]; then
+        mkdir -p "$olddir/$(dirname "$1")"
+        mv -f "$dest" "$olddir/$1"
+    fi
+    ln -sfn "$src" "$dest"
+    echo "Linked $1 -> $dest"
+}
+
+link_config config/ghostty/config    "$HOME/.config/ghostty/config"
+link_config config/zed/settings.json "$HOME/.config/zed/settings.json"
+link_config config/zed/keymap.json   "$HOME/.config/zed/keymap.json"
+link_config config/zed/tasks.json    "$HOME/.config/zed/tasks.json"
+
+# Rectangle: prefs domain can't be symlinked — import the cleaned export instead.
+if command -v defaults >/dev/null 2>&1 && [ -f "$dir/config/rectangle/import.sh" ]; then
+    bash "$dir/config/rectangle/import.sh" || true
+fi