├── .alacritty.yml ├── .bin ├── Q ├── Qruby ├── audit-path-writeable ├── backup-application-support ├── backup-bash-history ├── barevim ├── bq-cancel-job ├── brew ├── camelize ├── cfbundle-identifier ├── cgi-escape ├── cgi-unescape ├── dbx ├── die ├── don ├── dtail ├── exa ├── gh-refresh-org ├── gifgen ├── git-aicommit ├── git-prune-history ├── git-refresh ├── google-adc ├── hurl ├── json-to-yaml ├── kubectl-printsecrets ├── lower ├── macos-add-system-user ├── macos-add-user ├── macos-enable-sudo-pam_tid ├── mirror-website ├── openssl-aes-decrypt-file ├── openssl-aes-encrypt-file ├── pipa ├── random-hex ├── random-password ├── random-word ├── restore-application-support ├── safebrowser ├── start-colima ├── titleize ├── wsync └── yaml-to-json ├── .config └── nvim │ ├── coc-settings.json │ ├── commands.vim │ ├── config.vim │ ├── copilot.lua │ ├── filetypes.vim │ ├── gen.lua │ ├── init.vim │ ├── lspconfig.lua │ ├── plug.vim │ ├── plugins.vim │ ├── plugins │ ├── autopairs.vim │ ├── cmp.lua │ ├── coc.vim │ ├── fzf.vim │ ├── ncm2.vim │ ├── supermaven.lua │ ├── tailwindtools.lua │ ├── toggleterm.vim │ ├── ultisnips.vim │ ├── undotree.lua │ └── yowish.vim │ ├── startscreen.vim │ └── treesitter.vim ├── .direnvrc ├── .finicky.js ├── .gemrc ├── .gitattributes ├── .gitconfig ├── .gitignore ├── .gitmodules ├── .hushlogin ├── .inputrc ├── .irbrc ├── .npmrc ├── .phoenix.js ├── .profile ├── .profile.d ├── aliases ├── credentials ├── direnv ├── do_not_track ├── functions ├── fzf ├── golang ├── google-cloud-sdk ├── homebrew ├── nodenv ├── path ├── prompt ├── pyenv ├── rbenv └── tfenv ├── .pryrc ├── .ssh ├── config ├── whatdropsnow-production.pem ├── whatdropsnow-staging.pem └── wooga_heroku_id_rsa.pub ├── .tmux.conf ├── .witchcraft ├── medium.com.js ├── realpython.com.js ├── redirect-to-12ft-io.js ├── theatlantic.com.js └── www.berlinale.de.js ├── Caddyfile ├── LaunchAgents └── com.overbryd.caddy.plist ├── Makefile ├── Pro-gramming.terminal ├── README.md ├── bootstrap.sh └── defaults.sh /.alacritty.yml: -------------------------------------------------------------------------------- 1 | window: 2 | dimensions: 3 | columns: 237 4 | lines: 55 5 | decorations: none 6 | opacity: 0.75 7 | dynamic_padding: true 8 | padding: 9 | x: 5 10 | y: 2 11 | 12 | font: 13 | normal: 14 | family: IBM Plex Mono 15 | style: Text 16 | bold: 17 | family: IBM Plex Mono 18 | style: Medium 19 | italic: 20 | family: IBM Plex Mono 21 | style: Text Italic 22 | bold_italic: 23 | family: IBM Plex Mono 24 | style: Medium Italic 25 | size: 14.0 26 | offset: 27 | x: 0 28 | y: 0 29 | AppleFontSmoothing: true 30 | 31 | key_bindings: 32 | - {key: Left, mods: Alt, chars: "\x1BB" } 33 | - {key: Right, mods: Alt, chars: "\x1BF" } 34 | - {key: H, mods: Alt, chars: "\x1BB" } 35 | - {key: L, mods: Alt, chars: "\x1BF" } 36 | 37 | -------------------------------------------------------------------------------- /.bin/Q: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | OPENAI_BASE_URL="${OPENAI_BASE_URL:=https://api.openai.com}" 4 | OPENAI_ORGANIZATION_KEY="$OPENAI_ORGANIZATION_KEY" 5 | OPENAI_MODEL="${OPENAI_MODEL:=gpt-4o}" 6 | OPENAI_API_KEY="$OPENAI_API_KEY" 7 | OPENAI_SYSTEM="${OPENAI_SYSTEM:=You are a helpful assistant.}" 8 | OPENAI_MAX_TOKENS="${OPENAI_MAX_TOKENS:=2048}" 9 | 10 | if [[ "$1" = "-" ]]; then 11 | content="$(cat)" 12 | elif test "$#" -gt 0; then 13 | content="$@" 14 | else 15 | content="$(gum input --placeholder 'Write a query')" 16 | fi 17 | 18 | # echo "$content" >&2 19 | curl -XPOST "${OPENAI_BASE_URL}/v1/chat/completions" \ 20 | --silent \ 21 | --fail \ 22 | --no-buffer \ 23 | -H"Content-Type: application/json" \ 24 | -H"Authorization: Bearer $OPENAI_API_KEY" \ 25 | -d"$( 26 | jq --null-input \ 27 | --arg model "$OPENAI_MODEL" \ 28 | --arg content "$content" \ 29 | --arg system "$OPENAI_SYSTEM" \ 30 | --arg max_tokens "$OPENAI_MAX_TOKENS" \ 31 | '{ 32 | "model": $model, 33 | "messages": [ 34 | {"role": "system", "content": $system}, 35 | {"role": "user", "content": $content} 36 | ], 37 | "stream": true, 38 | "max_tokens": $max_tokens | tonumber 39 | }' 40 | )" \ 41 | | sed -e 's/^data: //' -e 's/^\[DONE\]/{}/' \ 42 | | jq --join-output --unbuffered '.choices[0].delta.content | select(.)' 43 | 44 | 45 | -------------------------------------------------------------------------------- /.bin/Qruby: -------------------------------------------------------------------------------- 1 | #!/opt/homebrew/rbenv/versions/3.2.2/bin/ruby -rhttpx -rjson -rruby2d 2 | 3 | OPENAI_ORGANIZATION_KEY = ENV.fetch("OPENAI_ORGANIZATION_KEY") 4 | OPENAI_API_KEY = ENV.fetch("OPENAI_API_KEY") 5 | OPENAI_MODEL = ENV.fetch("OPENAI_MODEL", "gpt-4-turbo") 6 | OPENAI_SYSTEM = ENV.fetch("OPENAI_SYSTEM", "You are a helpful assistant.") 7 | OPENAI_MAX_TOKENS = ENV.fetch("OPENAI_MAX_TOKENS", "2048").to_i 8 | 9 | CLICK = Sound.new(File.expand_path("~/Music/click4.wav")) 10 | 11 | HTTP = HTTPX 12 | .plugin(:stream) 13 | .with(headers: {"Authorization" => "Bearer #{OPENAI_API_KEY}"}) 14 | 15 | def query(prompt, system: OPENAI_SYSTEM, history: []) 16 | response = HTTP.post("https://api.openai.com/v1/chat/completions", json: { 17 | "model" => OPENAI_MODEL, 18 | "messages" => [ 19 | { role: "system", content: system }, 20 | *history, 21 | { role: "user", content: prompt }, 22 | ], 23 | stream: true, 24 | max_tokens: OPENAI_MAX_TOKENS, 25 | }, stream: true) 26 | block_given? ? response.each { |chunk| yield chunk } : response 27 | end 28 | 29 | def main 30 | prompt = if ARGV.any? 31 | ARGV.join(" ").to_s 32 | else 33 | io, _ = select([STDIN], [], [], 0) 34 | io[0].read if io 35 | end 36 | exit unless prompt 37 | STDOUT.sync = true 38 | query(prompt, system: OPENAI_SYSTEM) do |chunk| 39 | chunk.split(/data:\s*/).each do |data| 40 | json = JSON.parse(data) rescue next 41 | content = json["choices"][0]["delta"]["content"] rescue next 42 | print(content) 43 | CLICK.play 44 | end 45 | end 46 | end 47 | 48 | main if __FILE__ == $0 49 | 50 | -------------------------------------------------------------------------------- /.bin/audit-path-writeable: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "$PATH" \ 4 | | tr ':' '\n' \ 5 | | xargs -I{} sh -c 'test -w {} && echo "UNSAFE: {}"' 6 | -------------------------------------------------------------------------------- /.bin/backup-application-support: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BACKUP_FOLDER="$HOME/Dropbox/Backups/Application Support" 4 | APPLICATIONS=( 5 | "Farrago" 6 | "Fission" 7 | "Loopback" 8 | "Audio Hijack" 9 | "Flux" 10 | "com.operasoftware.Opera" 11 | "com.tinyapp.TablePlus" 12 | "obs-studio" 13 | ) 14 | 15 | datestamp=$(date +%Y-%m-%d) 16 | directory="${BACKUP_FOLDER}/${datestamp}" 17 | 18 | test -d "$directory" || mkdir -p "$directory" 19 | 20 | cd "$HOME/Library/Application Support" 21 | 22 | for application in "${APPLICATIONS[@]}"; do 23 | echo "Archiving settings of ${application} to ${directory}" 24 | tar cjf "${directory}/${application}.tar.bz2" "$application" 25 | done 26 | 27 | -------------------------------------------------------------------------------- /.bin/backup-bash-history: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | backup_folder="$HOME/Dropbox/Backups/$(hostname)" 4 | 5 | test -d "$backup_folder" || mkdir -p "$backup_folder" 6 | 7 | datestamp=$(date +%Y-%m-%d) 8 | 9 | history > "$backup_folder/bash_history_$datestamp" 10 | 11 | -------------------------------------------------------------------------------- /.bin/barevim: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This is useful for debugging vimrc files or an otherwise broken vim configuration 3 | 4 | vim --clean $@ 5 | 6 | -------------------------------------------------------------------------------- /.bin/bq-cancel-job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | project_id="$1" 4 | job_id="$2" 5 | 6 | if [[ -z "$project_id" || -z "$job_id" ]]; then 7 | die "Usage: bq-cancel-job " 8 | fi 9 | 10 | curl -XPOST -H "Authorization: Bearer $(gcloud auth print-access-token)" \ 11 | https://bigquery.googleapis.com/bigquery/v2/projects/$project_id/jobs/$job_id/cancel 12 | 13 | -------------------------------------------------------------------------------- /.bin/brew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | brew="$HOMEBREW_PREFIX/bin/brew $@" 4 | 5 | sudo -Eubinary /bin/bash -c "cd $HOMEBREW_PREFIX; $brew" 6 | 7 | -------------------------------------------------------------------------------- /.bin/camelize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Found on https://gist.github.com/asv/a286b8aefb972af8f62c 3 | 4 | if [[ -p /dev/stdin ]]; then 5 | string="$(cat - | titleize)" 6 | else 7 | string="$(titleize $@)" 8 | fi 9 | 10 | echo "${string// /}" 11 | 12 | -------------------------------------------------------------------------------- /.bin/cfbundle-identifier: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript 2 | 3 | on run argv 4 | id of app (item 1 of argv) 5 | end run 6 | -------------------------------------------------------------------------------- /.bin/cgi-escape: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -rcgi 2 | 3 | if ARGV.any? 4 | ARGV.each do |arg| 5 | puts CGI.escape(arg) 6 | end 7 | else 8 | STDIN.each_line do |line| 9 | puts CGI.escape(line.sub(/\n$/, '')) 10 | end 11 | end 12 | 13 | -------------------------------------------------------------------------------- /.bin/cgi-unescape: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -rcgi 2 | 3 | if ARGV.any? 4 | ARGV.each do |arg| 5 | puts CGI.unescape(arg) 6 | end 7 | else 8 | STDIN.each_line do |line| 9 | puts CGI.unescape(line.sub(/\n$/, '')) 10 | end 11 | end 12 | 13 | -------------------------------------------------------------------------------- /.bin/dbx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # dbx: iex debug 4 | 5 | exec iex --dbg pry -S $@ 6 | 7 | -------------------------------------------------------------------------------- /.bin/die: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | die() { 4 | echo >&2 "$@" 5 | exit 1 6 | } 7 | 8 | # run if not sourced 9 | if [[ "$_" = "$0" ]]; then 10 | die $@ 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /.bin/don: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exit_status="$?" 4 | echo "done $exit_status" \ 5 | | tee \ 6 | | say 7 | 8 | exit $exit_status 9 | 10 | -------------------------------------------------------------------------------- /.bin/dtail: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | usage() { 5 | echo "Usage: dtail [options] [--] path... 6 | 7 | Options: 8 | -r|--recursive 9 | Watch subdirectories recursively. 10 | --exclude | --excludei 11 | Exclude files if filename matches (POSIX extended regular expression). 12 | It is case insensitive with --excludei. 13 | --fromfile 14 | Read filenames to watch or exclude from a file, one filename per line. 15 | If filenames begin with @ they are excluded as described above. 16 | -p|--poolsize 17 | Maximum number of watching processes. Default 1. 18 | " 19 | exit 1 20 | } 21 | 22 | fail() { 23 | echo $* 24 | exit 2 25 | } 26 | 27 | targets=() 28 | poolsize=1 29 | options=(-q -m -e create,modify,delete) 30 | while [[ $# != 0 ]]; do 31 | case "$1" in 32 | -r|--recursive) 33 | options+=($1) 34 | shift 35 | ;; 36 | --exclude|--excludei) 37 | [[ $# > 1 ]] || fail "Missing pattern for $1" 38 | options+=($1 $2) 39 | shift 2 40 | ;; 41 | --fromfile) 42 | [[ $# > 1 ]] || fail "Missing filename for $1" 43 | [[ -f $2 ]] || fail "No such file $2" 44 | [[ -r $2 ]] || fail "Permission denied reading $2" 45 | options+=($1 $2) 46 | shift 2 47 | ;; 48 | -p|--poolsize) 49 | [[ $# > 1 ]] || fail "Missing poolsize for $1" 50 | poolsize=$2 51 | shift 2 52 | ;; 53 | --) 54 | shift 55 | break 56 | ;; 57 | -*) 58 | fail "Invalid option $1" 59 | ;; 60 | *) 61 | targets+=($1) 62 | shift 63 | ;; 64 | esac 65 | done 66 | 67 | targets+=($*) 68 | [[ ${#targets[@]} > 0 ]] || usage 69 | for t in ${targets[@]}; do 70 | [[ -e $t ]] || fail "Invalid path $t" 71 | [[ -r $t ]] || fail "Permission denied reading $t" 72 | done 73 | 74 | filepool_push() { 75 | if [[ ${#filepool[@]} == $poolsize ]]; then 76 | kill ${filepool[0]%%:*} 77 | if [[ ${#filepool[@]} > 1 ]]; then 78 | unset filepool[0] 79 | filepool=(${filepool[@]}) 80 | else 81 | filepool=() 82 | fi 83 | fi 84 | filepool+=($1:$2) 85 | } 86 | 87 | filepool_find() { 88 | local i 89 | for ((i = 0; i < ${#filepool[@]}; i++)); do 90 | if [[ ${filepool[$i]#*:} == $1 ]]; then 91 | echo ${filepool[$i]} 92 | break 93 | fi 94 | done 95 | } 96 | 97 | filepool_remove() { 98 | local i 99 | case ${#filepool[@]} in 100 | 0) 101 | ;; 102 | 1) 103 | if [[ ${filepool[0]#*:} == $1 ]]; then 104 | filepool=() 105 | fi 106 | ;; 107 | *) 108 | for ((i = 0; i < ${#filepool[@]}; i++)); do 109 | if [[ ${filepool[$i]#*:} == $1 ]]; then 110 | unset filepool[$i] 111 | filepool=(${filepool[@]}) 112 | fi 113 | done 114 | ;; 115 | esac 116 | } 117 | 118 | filepool=() 119 | 120 | for path in $( 121 | find ${targets[@]} -type f -readable -printf '%T@ %p\n' | 122 | sort -n | tail -n $poolsize | cut -f2- -d' ' 123 | ); do 124 | tail -q -F --pid=$$ -n 0 $path & 125 | disown 126 | filepool_push $! $path 127 | done 128 | 129 | while read event path; do 130 | case $event in 131 | CREATE) 132 | [[ -f $path && -r $path ]] || continue 133 | tail -q -F --pid=$$ -n +1 $path & 134 | disown 135 | filepool_push $! $path 136 | ;; 137 | MODIFY) 138 | [[ -f $path && -r $path ]] || continue 139 | f=$(filepool_find $path) 140 | if [[ -n "$f" ]]; then 141 | filepool_remove $path 142 | filepool+=($f) 143 | else 144 | tail -q -F --pid=$$ -n 1 $path & 145 | disown 146 | filepool_push $! $path 147 | fi 148 | ;; 149 | DELETE) 150 | f=$(filepool_find $path) 151 | if [[ -n "$f" ]]; then 152 | filepool_remove $path 153 | kill ${f%%:*} 154 | fi 155 | ;; 156 | esac 157 | done < <(inotifywait ${options[@]} --format '%e %w%f' -- ${targets[@]}) 158 | -------------------------------------------------------------------------------- /.bin/exa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | EXA_BASE_URL="${EXA_BASE_URL:=https://api.exa.ai}" 4 | EXA_API_KEY="$EXA_API_KEY" 5 | # See also: https://docs.exa.ai/reference/search 6 | EXA_CATEGORY="${EXA_CATEGORY:=news}" 7 | 8 | if [[ "$1" = "-" ]]; then 9 | query="$(cat)" 10 | elif [[ "$#" -gt 0 ]]; then 11 | if [[ "$#" -eq 1 ]]; then 12 | query="$1" 13 | elif [[ "$#" -eq 2 ]]; then 14 | EXA_CATEGORY="$1" 15 | query="$2" 16 | else 17 | query="$@" 18 | fi 19 | else 20 | EXA_CATEGORY="$(gum choose 'news' 'company' 'research paper' 'github' 'tweet' 'movie' 'song' 'personal site' 'pdf')" 21 | query="$(gum input --placeholder 'Write a query')" 22 | fi 23 | 24 | curl -XPOST "${EXA_BASE_URL}/search" \ 25 | --silent \ 26 | --fail \ 27 | --no-buffer \ 28 | -H"accept: application/json" \ 29 | -H"content-type: application/json" \ 30 | -H"x-api-key: $EXA_API_KEY" \ 31 | -d"$( 32 | jq --null-input \ 33 | --arg category "$EXA_CATEGORY" \ 34 | --arg query "$query" \ 35 | '{ 36 | "useAutoprompt": true, 37 | "category": $category, 38 | "query": $query 39 | }' 40 | )" \ 41 | | jq '.results[]' 42 | 43 | -------------------------------------------------------------------------------- /.bin/gh-refresh-org: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for org in $(gh org list); do 4 | test -d $org || mkdir $org 5 | 6 | for repo in $(gh repo list $org --json 'nameWithOwner' | jq -r '.[] | .nameWithOwner'); do 7 | if test -d $repo; then 8 | cd $repo 9 | git fetch --all 10 | cd - 11 | else 12 | cd $org 13 | git clone https://$GITHUB_USER:$GITHUB_TOKEN@github.com/$repo.git 14 | cd - 15 | cd $repo 16 | git fetch --all 17 | cd - 18 | fi 19 | done 20 | done 21 | 22 | -------------------------------------------------------------------------------- /.bin/gifgen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | input="$1" 4 | test -z "$input" || die "Usage: gifgen input-file [output] [scale]" 5 | output="$2" 6 | if [[ -z "$output" ]]; then 7 | output="${input%%.*}.gif" 8 | fi 9 | scale="$3" 10 | if [[ -z "$scale" ]]; then 11 | scale="320:-1" 12 | fi 13 | 14 | palette="/tmp/palette.png" 15 | filters="fps=15,scale=$scale:flags=lanczos" 16 | 17 | ffmpeg -i "$1" -vf "$filters,palettegen" -y "$palette" 18 | ffmpeg -i "$1" -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $output 19 | 20 | -------------------------------------------------------------------------------- /.bin/git-aicommit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export OPENAI_MAX_TOKENS=4096 4 | export OPENAI_SYSTEM="You are a helpful assistant, do your best to write a good commit message based on a given git diff. Provide a short first sentence, followed by two newlines with an optional description of the changes as bullet points. Just provide the text of the commit message, nothing else, no explanations." 5 | 6 | export CHANGESET="$(git staged)" 7 | for arg in "$@"; do 8 | case "$arg" in 9 | -a|--all) 10 | export CHANGESET="$(git diff)" 11 | break 12 | ;; 13 | esac 14 | done 15 | test -z "$CHANGESET" && die "No changes to commit" 16 | 17 | Q "Write a commit message for the following changeset:\n\`\`\`$CHANGESET\`\`\`" \ 18 | | git commit --file=- --edit $@ 19 | -------------------------------------------------------------------------------- /.bin/git-prune-history: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | 4 | # Taken and modified from: https://gist.github.com/wdalmut/1610856 5 | 6 | # Author: David Underhill 7 | # Script to permanently delete files/folders from your git repository. To use 8 | # it, cd to your repository's root and then run the script with a list of paths 9 | # you want to delete, e.g., git-delete-history path1 path2 10 | 11 | if [ $# -eq 0 ]; then 12 | exit 0 13 | fi 14 | 15 | # make sure we're at the root of git repo 16 | if [ ! -d .git ]; then 17 | echo "Error: must run this script from the root of a git repository" 18 | exit 1 19 | fi 20 | 21 | # remove all paths passed as arguments from the history of the repo 22 | files=$@ 23 | git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD 24 | 25 | # remove the temporary history git-filter-branch otherwise leaves behind for a long time 26 | rm -rf .git/refs/original/ \ 27 | && git reflog expire --all \ 28 | && git gc --aggressive --prune 29 | 30 | -------------------------------------------------------------------------------- /.bin/git-refresh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find $1 -name .git -type d \ 4 | | sed 's/\/\.git//' \ 5 | | xargs -t -P $(nproc) -I{} git --git-dir="{}/.git" --work-tree="{}" fetch --all 6 | 7 | -------------------------------------------------------------------------------- /.bin/google-adc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if test -z "$GOOGLE_APPLICATION_CREDENTIALS"; then 4 | echo "Missing environment variable GOOGLE_APPLICATION_CREDENTIALS" >&2 5 | exit 1 6 | fi 7 | 8 | gcloud auth login $@ \ 9 | && (yes | gcloud auth application-default login $@) \ 10 | && mv ~/.config/gcloud/application_default_credentials.json $GOOGLE_APPLICATION_CREDENTIALS 11 | 12 | -------------------------------------------------------------------------------- /.bin/hurl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl -vo/dev/null $@ 4 | 5 | -------------------------------------------------------------------------------- /.bin/json-to-yaml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -ryaml -rjson 2 | 3 | puts JSON.parse(STDIN.read).to_yaml 4 | -------------------------------------------------------------------------------- /.bin/kubectl-printsecrets: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Quickly peek at secrets stored in kubernetes yaml files (base64 encoded) 4 | 5 | for file in $@; do 6 | echo "${file}:" 7 | yaml2json < $file \ 8 | | jq '[.select(.type == "Secret") 9 | | .data 10 | | to_entries[] 11 | | .value = (.value | @base64d)] 12 | | from_entries 13 | ' 14 | done 15 | 16 | -------------------------------------------------------------------------------- /.bin/lower: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -p /dev/stdin ]]; then 4 | string="$(cat -)" 5 | else 6 | string="$@" 7 | fi 8 | 9 | echo "$string" | tr '[[:upper:]]' '[[:lower:]]' 10 | 11 | -------------------------------------------------------------------------------- /.bin/macos-add-system-user: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | test "$(id -u)" -eq 0 || die "This script needs to run as root" 5 | 6 | # obtain a username 7 | username="$1" 8 | if [[ "x" = "x$username" ]]; then 9 | read -p "Enter the user name: " username 10 | fi 11 | username="$(lower $username)" 12 | u_username="_$username" 13 | 14 | # check that user does not already exist 15 | if [[ "$username" == $(dscl . -list /Users UniqueID | awk '{print $1}' | grep -w $username) ]]; then 16 | die "User already exists!" 17 | fi 18 | 19 | # generate sensible defaults 20 | realname=$(titleize $username) 21 | lastid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -n | tail -1) 22 | unique_id=$((lastid + 1)) 23 | 24 | # like addgroup but macos 25 | dscl . -create /Groups/$u_username 26 | dscl . -create /Groups/$u_username PrimaryGroupID $unique_id 27 | dscl . -create /Groups/$u_username RecordName $u_username $username 28 | dscl . -create /Groups/$u_username RealName "$realname" 29 | dscl . -create /Groups/$u_username Password \* 30 | 31 | # like adduser but macos 32 | dscl . -create /Users/$u_username 33 | dscl . -create /Users/$u_username UserShell /usr/bin/false 34 | dscl . -create /Users/$u_username RealName "$realname" 35 | dscl . -create /Users/$u_username UniqueID $unique_id 36 | dscl . -create /Users/$u_username PrimaryGroupID $unique_id 37 | dscl . -create /Users/$u_username NFSHomeDirectory /var/empty 38 | dscl . -create /Users/$u_username Password \* 39 | dscl . -create /Users/$u_username RecordName $u_username $username 40 | dscl . -delete /Users/$u_username PasswordPolicyOptions 41 | dscl . -delete /Users/$u_username AuthenticationAuthority 42 | 43 | echo "New system user $username ($u_username) has been created with unique ID $unique_id" 44 | 45 | -------------------------------------------------------------------------------- /.bin/macos-add-user: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | test "$(id -u)" -eq 0 || die "This script needs to run as root" 5 | 6 | # obtain a username 7 | username="$1" 8 | if [[ "x" = "x$username" ]]; then 9 | read -p "Enter the user name: " username 10 | fi 11 | username="$(lower $username)" 12 | 13 | # check that user does not already exist 14 | if [[ "$username" == $(dscl . -list /Users UniqueID | awk '{print $1}' | grep -w $username) ]]; then 15 | die "User already exists!" 16 | fi 17 | 18 | # generate sensible defaults 19 | realname=$(titleize $username) 20 | lastid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -n | tail -1) 21 | unique_id=$((lastid + 1)) 22 | password="$(random-word)-$(random-word)-$(random-word)" 23 | 24 | # like adduser but macos 25 | dscl . -create /Users/$username 26 | dscl . -create /Users/$username UserShell "$SHELL" 27 | dscl . -create /Users/$username RealName "$realname" 28 | dscl . -create /Users/$username UniqueID "$unique_id" 29 | dscl . -create /Users/$username PrimaryGroupID 20 30 | dscl . -create /Users/$username NFSHomeDirectory /Users/$username 31 | dscl . -passwd /Users/$username $password 32 | dscl . -create /Users/$username hint "" 33 | createhomedir -u $username -c 34 | # normal users are member of staff 35 | dseditgroup -o edit -t user -a $username staff 36 | 37 | echo "New user $username has been created with unique ID $unique_id" 38 | echo "New user password: $password" 39 | 40 | -------------------------------------------------------------------------------- /.bin/macos-enable-sudo-pam_tid: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check that we are superuser (i.e. $(id -u) is zero) 4 | [ `id -u` -eq 0 ] || die "This script needs to run as root" 5 | 6 | test -f /usr/lib/pam/pam_tid.so* || (echo "pam_tid not present on this machine" && exit 0) 7 | 8 | grep pam_tid.so /etc/pam.d/sudo \ 9 | || /usr/bin/sed -i'' -e '2i\ 10 | auth sufficient pam_tid.so 11 | ' /etc/pam.d/sudo 12 | 13 | echo "Contents of /etc/pam.d/sudo" 14 | cat /etc/pam.d/sudo 15 | 16 | -------------------------------------------------------------------------------- /.bin/mirror-website: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function mirror-website() { 4 | local url=$@ 5 | local domain=`expr "$url" : '^http[s]*://\([^/?]*\)'` 6 | wget \ 7 | --recursive \ 8 | --no-clobber \ 9 | --page-requisites \ 10 | --html-extension \ 11 | --convert-links \ 12 | --restrict-file-names=windows \ 13 | --domains $domain \ 14 | --no-parent \ 15 | $url 16 | } 17 | 18 | mirror-website $@ 19 | 20 | -------------------------------------------------------------------------------- /.bin/openssl-aes-decrypt-file: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if echo "$1" | grep -E ".enc$"; then 4 | target=${1%%.enc} 5 | echo "Decrypting '$1' to '$target'" 6 | openssl enc -d -aes-256-cbc -in "$1" -out "$target" 7 | else 8 | echo "Cannot decrypt files not ending in .enc" 9 | exit 1 10 | fi 11 | 12 | -------------------------------------------------------------------------------- /.bin/openssl-aes-encrypt-file: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | openssl aes-256-cbc -in "$1" -out "$1.enc" 4 | 5 | -------------------------------------------------------------------------------- /.bin/pipa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This is useful for adding a Python dependency to a project. 3 | 4 | pip install "$1" 5 | grep "$1" requirements.txt 2>/dev/null \ 6 | || pip freeze | grep "$1" >> requirements.txt 7 | 8 | -------------------------------------------------------------------------------- /.bin/random-hex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LC_ALL=C od -A n -t x1 < /dev/urandom \ 4 | | sed 's/ *//g' \ 5 | | head -c ${1:-20} 6 | 7 | -------------------------------------------------------------------------------- /.bin/random-password: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LC_ALL=C tr -dc "[:alnum:]" < /dev/urandom \ 4 | | head -c ${1:-20} 5 | 6 | -------------------------------------------------------------------------------- /.bin/random-word: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | random=$(od -vAn -N4 -tu4 < /dev/urandom | /usr/bin/sed -e 's/[[:space:]]*//') 4 | words=$(wc -w < /usr/share/dict/words) 5 | /usr/bin/sed -n "$(($random % $words))p" < /usr/share/dict/words \ 6 | | tr '[[:upper:]]' '[[:lower:]]' 7 | 8 | -------------------------------------------------------------------------------- /.bin/restore-application-support: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BACKUP_FOLDER="$HOME/Dropbox/Backups/Application Support" 4 | last=$(ls "$BACKUP_FOLDER" | sort | tail -n1) 5 | datestamp="${1:-$last}" 6 | source_directory="${BACKUP_FOLDER}/${datestamp}" 7 | 8 | cd "$HOME/Library/Application Support" 9 | 10 | echo "Restoring '~/Library/Application Support' from $source_directory" 11 | 12 | IFS=$'\n' 13 | for app in $(find "$source_directory" -name "*tar.bz2"); do 14 | target="$(basename -s .tar.bz2 "$app")" 15 | echo "$target" 16 | test -d "$target" \ 17 | && mv "$target" "${target}__old_$(date +%s)" 18 | tar xjf "$app" 19 | done 20 | 21 | -------------------------------------------------------------------------------- /.bin/safebrowser: -------------------------------------------------------------------------------- 1 | #!/usr/bin/osascript 2 | 3 | on run argv 4 | set remoteMachine to first item of (read (POSIX path of (path to home folder as string) & ".config/vm1.local/eppc") using delimiter "\n") 5 | tell application "Finder" of machine remoteMachine to open location (item 1 of argv) 6 | end run 7 | 8 | -------------------------------------------------------------------------------- /.bin/start-colima: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | colima start --vm-type vz --mount-type virtiofs --cpu 4 --memory 8 4 | 5 | -------------------------------------------------------------------------------- /.bin/titleize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Found on https://gist.github.com/asv/a286b8aefb972af8f62c 3 | 4 | if [[ -p /dev/stdin ]]; then 5 | string="$(cat -)" 6 | else 7 | string="$@" 8 | fi 9 | 10 | string_arr=($string) 11 | 12 | echo "${string_arr[*]^}" 13 | 14 | -------------------------------------------------------------------------------- /.bin/wsync: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ "$(hostname)" == "mba1" ]]; then 4 | from="10.10.10.4" 5 | elif [[ "$(hostname)" == "ms1" ]]; then 6 | from="10.10.10.5" 7 | else 8 | die "Unknown host: $(hostname)" 9 | fi 10 | 11 | rsync \ 12 | --archive \ 13 | --verbose \ 14 | --checksum \ 15 | --compress \ 16 | --cache \ 17 | --timeout=120 \ 18 | --partial-dir=/tmp/rsync-$(date +%Y-%m-%d) \ 19 | --progress \ 20 | --exclude='.terraform/' \ 21 | --exclude='.direnv/' \ 22 | --exclude='__pycache__/' \ 23 | $from:$(pwd)/ $(pwd)/ 24 | 25 | -------------------------------------------------------------------------------- /.bin/yaml-to-json: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -ryaml -rjson 2 | 3 | puts YAML.load(STDIN).to_json 4 | -------------------------------------------------------------------------------- /.config/nvim/coc-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "python", 3 | "coc.preferences.jumpCommand": "tabe", 4 | "coc.preferences.messageLevel": "error", 5 | "coc.preferences.formatOnSaveFiletypes": [ 6 | "markdown", 7 | "Markdown", 8 | "terraform" 9 | ], 10 | "suggest.triggerCompletionWait": 15, 11 | "languageserver": { 12 | "terraform": { 13 | "command": "terraform-ls", 14 | "args": ["serve"], 15 | "filetypes": [ 16 | "terraform", 17 | "tf" 18 | ], 19 | "initializationOptions": {}, 20 | "settings": {} 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /.config/nvim/commands.vim: -------------------------------------------------------------------------------- 1 | " :Tabr 2 | " Close tabs (and their splits) to the right with tabr 3 | " https://superuser.com/questions/555011/vim-close-all-tabs-to-the-right 4 | command -nargs=0 Tabr :.+1,$tabdo :tabc 5 | 6 | " :Term 7 | " Open a terminal in insert mode 8 | function! TermOpen(...) 9 | function! NoOp() 10 | endfunction 11 | 12 | let cmd = a:0 >= 1 ? a:1 : '' 13 | let type = a:0 >= 2 ? a:2 : 's' 14 | let Func = a:0 >= 3 ? a:3 : function('NoOp') 15 | 16 | let callback = { 'type': type, 'ext_cb': Func } 17 | function callback.on_exit(job_id, code, event) 18 | if a:code == 0 " close the terminal window when done if no error 19 | silent! bd! 20 | silent! q 21 | endif 22 | call self.ext_cb() 23 | endfunction 24 | 25 | setlocal number relativenumber signcolumn=no listchars= 26 | setlocal nocursorcolumn cursorline 27 | call termopen(len(cmd) ? cmd : &shell, callback) 28 | startinsert 29 | endfunction 30 | " Term opens a terminal 31 | command -nargs=0 Term :call TermOpen('env TERM=st-256color bash -il', 'm') 32 | " start in insert mode 33 | autocmd BufEnter term://* startinsert 34 | " map to exit terminal-mode 35 | tnoremap 36 | 37 | " :w!! 38 | " force the save of write protected files with sudo 39 | cmap w!! w! !sudo tee > /dev/null % 40 | 41 | " command line shortcuts 42 | cnoremap 43 | 44 | " remove search highlight when hitting escape again 45 | nnoremap :nohlsearch 46 | 47 | " disable arrow keys 48 | map 49 | map 50 | map 51 | map 52 | 53 | " search with t 54 | noremap t :Files 55 | " serach files in git with g 56 | noremap g :GFiles 57 | " search buffers with b 58 | noremap b :Buffers 59 | 60 | " replace highlighted text 61 | " first highlight text with a search or * 62 | " then hight s to enter replace mode 63 | noremap s :%s///g 64 | 65 | " prepare command to the current file, confirm with 66 | noremap rm :!rm % 67 | noremap grm :!git rm % 68 | 69 | " Edit ultisnips for current filetype using U 70 | noremap U :UltiSnipsEdit 71 | 72 | 73 | -------------------------------------------------------------------------------- /.config/nvim/config.vim: -------------------------------------------------------------------------------- 1 | " disable old-time vi compatibility 2 | set nocompatible 3 | 4 | " disable ruby provider 5 | let g:loaded_ruby_provider = 0 6 | 7 | " disable perl provider 8 | let g:loaded_perl_provider = 0 9 | 10 | " disable node provider 11 | let g:loaded_node_provider = 0 12 | 13 | " setup python provider 14 | let g:python3_host_prog = $PYENV_ROOT . '/versions/' . $PYENV_GLOBAL . '/bin/python' 15 | 16 | " common settings 17 | filetype plugin indent on 18 | set number 19 | set ruler 20 | set encoding=utf-8 21 | set nowrap 22 | set tabstop=2 23 | set shiftwidth=2 24 | set softtabstop=2 25 | set expandtab 26 | set norelativenumber 27 | set clipboard+=unnamedplus 28 | syntax on 29 | 30 | " colorschema and color customisations 31 | " reduce colors 32 | " let g:yowish = {} 33 | " let g:yowish.colors = { 34 | " \ 'green': ['#ffbe3c', '215'], 35 | " \ 'lightGreen': ['#ffcc66', '222'], 36 | " \ 'lightBlue': ['#ffcc66', '222'], 37 | " \ 'lightViolet': ['#bebebe', '249'], 38 | " \ 'selected': ['#0e0e0e', '232'], 39 | " \ } 40 | " colorscheme yowish 41 | colorscheme paramount 42 | highlight TabLineFill ctermfg=white ctermbg=DarkGrey 43 | highlight TabLine ctermfg=white ctermbg=DarkGrey 44 | highlight TabLineSel ctermfg=Black ctermbg=LightMagenta 45 | 46 | " turn off modeline 47 | set modelines=0 48 | set nomodeline 49 | 50 | " we have a good terminal connection, send more characters for redrawing 51 | set ttyfast 52 | 53 | " turn off that visual and audible bell 54 | set vb t_vb= 55 | 56 | " disable netrw banner 57 | let g:netrw_banner=0 58 | " disable netrw history 59 | let g:netrw_dirhistmax=0 60 | " netrw liststyle as tree 61 | let g:netrw_liststyle=3 62 | " open files on right 63 | let g:netrw_altv=1 64 | " open previews vertically 65 | let g:netrw_preview=1 66 | 67 | " make backspace work as expected 68 | set backspace=indent,eol,start 69 | 70 | " show hard tabs and trailing spaces 71 | set list listchars=tab:»·,trail:· 72 | 73 | " use a vertical line at 100 column width 74 | " set fillchars= 75 | set cc=100 76 | 77 | " allow incremental search and highlight results 78 | set incsearch 79 | set hlsearch 80 | set showmatch 81 | 82 | " No crappy vim regular expression infile searching 83 | " see :help magic for an explanation of flags. 84 | nnoremap / /\M 85 | nnoremap ? ?\M 86 | 87 | " be case insensitive until an uppercase character is typed 88 | set smartcase 89 | 90 | " disable code folding 91 | set nofoldenable 92 | 93 | " directories for backup, tmp and swp files 94 | set backupdir=~/.nvim/tmp/backup// 95 | set directory=~/.nvim/tmp/swap// 96 | 97 | " save an undofile to be able to undo changes after closing files 98 | set undofile 99 | set undodir=~/.nvim/tmp/undo// 100 | 101 | " I got enough memory, no need for swap files 102 | set noswapfile 103 | 104 | " do not show where the cursor is (very slow with ruby syntax *sigh*) 105 | set nocursorline 106 | 107 | " set a scroll offset above and below the cursor 108 | set scrolloff=10 109 | 110 | " Prescribe Vim to switch to an existing tab page if it contains a window displaying 111 | " the target buffer, otherwise open a new tab. 112 | " https://stackoverflow.com/a/6853779 113 | set switchbuf+=usetab,newtab 114 | 115 | " Configure the quickfix buffer (also works in location lists). 116 | " Open file using in a new tab. 117 | " https://vi.stackexchange.com/a/6999 118 | autocmd FileType qf nnoremap T 119 | 120 | " Allow editing crontabs 121 | " http://stackoverflow.com/questions/15395479/why-ive-got-no-crontab-entry-on-os-x-when-using-vim 122 | autocmd FileType crontab setlocal nowritebackup 123 | 124 | " Removes trailing whitespace on save 125 | autocmd BufWritePre .vimrc,Gemfile,Rakefile,*.{js,jsx,rb,ru,html,erl,erb,ex,exs,py,tf} :call Preserve("%s/\\s\\+$//e") 126 | 127 | " Preserves the cursor and search history around executing a command 128 | function! Preserve(command) 129 | let _s=@/ 130 | let line = line(".") 131 | let col = col(".") 132 | execute a:command 133 | let @/=_s 134 | call cursor(line, col) 135 | endfunction 136 | -------------------------------------------------------------------------------- /.config/nvim/copilot.lua: -------------------------------------------------------------------------------- 1 | require("copilot").setup({ 2 | suggestion = { 3 | auto_trigger = true, 4 | filetypes = { 5 | terraform = true, 6 | hcl = true, 7 | javascript = true, 8 | typescript = true, 9 | python = true, 10 | elixir = true, 11 | erlang = true, 12 | ruby = true, 13 | go = true, 14 | rust = true, 15 | java = true, 16 | zig = true, 17 | html = true, 18 | css = true, 19 | markdown = true, 20 | vim = true, 21 | lua = true, 22 | sh = true, 23 | yaml = true, 24 | json = true, 25 | ["*"] = false, 26 | }, 27 | keymap = { 28 | accept = "", 29 | next = "", 30 | prev = "", 31 | dismiss = "", 32 | } 33 | }, 34 | panel = { 35 | auto_refresh = true 36 | }, 37 | copilot_node_command = '/opt/homebrew/nodenv/versions/20.8.1/bin/node' 38 | }) 39 | 40 | -------------------------------------------------------------------------------- /.config/nvim/filetypes.vim: -------------------------------------------------------------------------------- 1 | " *.jsonschema is of type json 2 | au BufRead,BufNewFile *.jsonschema set filetype=json 3 | 4 | " *.tfstate is of type json 5 | au BufRead,BufNewFile *.tfstate set filetype=json 6 | 7 | " set tabwdith for golang 8 | au Filetype go setlocal tabstop=4 shiftwidth=4 softtabstop=4 9 | 10 | -------------------------------------------------------------------------------- /.config/nvim/gen.lua: -------------------------------------------------------------------------------- 1 | local gen = require('gen') 2 | 3 | gen.setup({ 4 | model = 'deepseek-coder:6.7b', 5 | display_mode = 'split', 6 | }) 7 | 8 | vim.keymap.set({ 'n', 'v' }, 'ai', ':Gen') 9 | 10 | -- Note: available replacements 11 | -- $text 12 | -- 13 | 14 | gen.prompts['UltiSnips'] = { 15 | prompt = "Write a UltiSnips snippet, generalizing the necessary parts in the following code:\n$text", 16 | replace = false, 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.config/nvim/init.vim: -------------------------------------------------------------------------------- 1 | source ~/.config/nvim/plug.vim 2 | source ~/.config/nvim/plugins.vim 3 | " source ~/.config/nvim/plugins/coc.vim 4 | source ~/.config/nvim/plugins/fzf.vim 5 | source ~/.config/nvim/plugins/autopairs.vim 6 | source ~/.config/nvim/plugins/ultisnips.vim 7 | source ~/.config/nvim/plugins/toggleterm.vim 8 | source ~/.config/nvim/plugins/undotree.lua 9 | " source ~/.config/nvim/copilot.lua 10 | source ~/.config/nvim/plugins/supermaven.lua 11 | " source ~/.config/nvim/plugins/ncm2.vim 12 | source ~/.config/nvim/plugins/cmp.lua 13 | source ~/.config/nvim/plugins/tailwindtools.lua 14 | source ~/.config/nvim/config.vim 15 | source ~/.config/nvim/filetypes.vim 16 | source ~/.config/nvim/treesitter.vim 17 | source ~/.config/nvim/commands.vim 18 | source ~/.config/nvim/startscreen.vim 19 | source ~/.config/nvim/gen.lua 20 | source ~/.config/nvim/lspconfig.lua 21 | -------------------------------------------------------------------------------- /.config/nvim/lspconfig.lua: -------------------------------------------------------------------------------- 1 | local lsp = require('lspconfig') 2 | local cmp_capabilities = require('cmp_nvim_lsp').default_capabilities() 3 | 4 | -- tame lsp logging when not debugging 5 | vim.lsp.set_log_level("error") 6 | 7 | -- yamlls 8 | lsp.yamlls.setup{ 9 | capabilities=cmp_capabilities, 10 | on_attach=on_attach, 11 | -- capabilities=require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities()), 12 | settings={ 13 | redhat={ 14 | telemetry={ 15 | enabled=false 16 | } 17 | }, 18 | yaml={ 19 | schemas={ 20 | ["https://json.schemastore.org/github-workflow.json"]="/.github/workflows/*" 21 | } 22 | } 23 | } 24 | } 25 | 26 | -- jsonls 27 | lsp.jsonls.setup{ 28 | capabilities=cmp_capabilities, 29 | } 30 | 31 | -- terraform-ls 32 | lsp.terraformls.setup{ 33 | capabilities=cmp_capabilities, 34 | } 35 | 36 | -- elixirls 37 | lsp.elixirls.setup{ 38 | capabilities=cmp_capabilities, 39 | cmd = { "elixir-ls" }, 40 | elixirLS = { 41 | dialyzerEnabled = false, 42 | fetchDeps = false 43 | }, 44 | on_attach = require("lsp-format").on_attach, 45 | } 46 | 47 | -- tailwindcss 48 | lsp.tailwindcss.setup({ 49 | capabilities=cmp_capabilities, 50 | root_dir = lsp.util.root_pattern( 51 | "tailwind.config.js", 52 | "tailwind.config.js", 53 | "package.json", 54 | "mix.exs", 55 | ".git" 56 | ), 57 | filetypes = { 58 | "html", 59 | "elixir", 60 | "eelixir", 61 | "heex", 62 | }, 63 | init_options = { 64 | userLanguages = { 65 | elixir = "html-eex", 66 | eelixir = "html-eex", 67 | heex = "html-eex", 68 | } 69 | }, 70 | settings = { 71 | tailwindCSS = { 72 | experimental = { 73 | classRegex = { 74 | -- add Elixir classRegex 75 | 'class[:]\\s*"([^"]*)"', 76 | } 77 | } 78 | } 79 | } 80 | }) 81 | 82 | -- html 83 | lsp.html.setup({ 84 | capabilities=cmp_capabilities, 85 | filetypes = { "html", "heex" } 86 | }) 87 | 88 | -------------------------------------------------------------------------------- /.config/nvim/plugins.vim: -------------------------------------------------------------------------------- 1 | call plug#begin("~/.nvim/plugged") 2 | 3 | " colorscheme 4 | Plug 'KabbAmine/yowish.vim' 5 | Plug 'owickstrom/vim-colors-paramount' 6 | 7 | " treesitter 8 | Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} 9 | 10 | " nvim-ts-autotag automatically closes html tags 11 | Plug 'windwp/nvim-ts-autotag' 12 | Plug 'windwp/nvim-autopairs' 13 | 14 | " Easy quoting with the surround plugin 15 | Plug 'tpope/vim-surround' 16 | 17 | " repeat hooks for other plugins 18 | Plug 'tpope/vim-repeat' 19 | 20 | " lsp integration 21 | Plug 'neovim/nvim-lspconfig' 22 | " format on save, async via lsp 23 | Plug 'lukas-reineke/lsp-format.nvim' 24 | 25 | " File search 26 | Plug 'junegunn/fzf' 27 | Plug 'junegunn/fzf.vim' 28 | Plug 'duane9/nvim-rg' 29 | 30 | " Snippets 31 | Plug 'SirVer/ultisnips' 32 | Plug 'honza/vim-snippets' 33 | 34 | " Rename current buffer and file on disk 35 | Plug 'danro/rename.vim' 36 | 37 | " Terminal manager, used to toggle ollama sessions 38 | Plug 'akinsho/toggleterm.nvim' 39 | 40 | " Undotree 41 | Plug 'mbbill/undotree' 42 | 43 | " Copilot 44 | " Disabled for now. 45 | " Plug 'zbirenbaum/copilot.lua' 46 | 47 | " Supermaven 48 | Plug 'supermaven-inc/supermaven-nvim' 49 | 50 | "Generative AI 51 | Plug 'David-Kunz/gen.nvim' 52 | 53 | " auto completion 54 | Plug 'hrsh7th/cmp-nvim-lsp' 55 | Plug 'hrsh7th/cmp-buffer' 56 | Plug 'hrsh7th/cmp-path' 57 | Plug 'hrsh7th/cmp-cmdline' 58 | Plug 'hrsh7th/nvim-cmp' 59 | Plug 'quangnguyen30192/cmp-nvim-ultisnips' 60 | Plug 'andersevenrud/cmp-tmux' 61 | " ncm2 auto completion framework, its neatly organized and fast 62 | " Plug 'roxma/nvim-yarp' 63 | " Plug 'ncm2/ncm2' 64 | " " auto complete words from the current buffer 65 | " Plug 'ncm2/ncm2-bufword' 66 | " Plug 'fgrsnau/ncm2-otherbuf' 67 | " " auto complete from ultisnips 68 | " Plug 'ncm2/ncm2-ultisnips' 69 | " " auto complete paths 70 | " Plug 'ncm2/ncm2-path' 71 | " " detect javascript subscope in html documents 72 | " Plug 'ncm2/ncm2-html-subscope' 73 | " Plug 'ncm2/ncm2-markdown-subscope' 74 | " " auto comlete from other tmux buffers 75 | " Plug 'ncm2/ncm2-tmux' 76 | " auto complete lsp stuff 77 | " Plug 'prabirshrestha/vim-lsp' 78 | " Plug 'ncm2/ncm2-vim-lsp' 79 | 80 | " TailwindCSS support 81 | Plug 'luckasRanarison/tailwind-tools.nvim' 82 | 83 | " Golang support 84 | Plug 'fatih/vim-go' 85 | Plug 'sebdah/vim-delve' 86 | 87 | call plug#end() 88 | 89 | -------------------------------------------------------------------------------- /.config/nvim/plugins/autopairs.vim: -------------------------------------------------------------------------------- 1 | " Load autopairs 2 | lua << EOF 3 | require("nvim-autopairs").setup {} 4 | EOF 5 | 6 | -------------------------------------------------------------------------------- /.config/nvim/plugins/cmp.lua: -------------------------------------------------------------------------------- 1 | -- Set up nvim-cmp. 2 | local cmp = require'cmp' 3 | 4 | cmp.setup({ 5 | snippet = { 6 | -- REQUIRED - you must specify a snippet engine 7 | expand = function(args) 8 | vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users. 9 | end, 10 | }, 11 | window = { 12 | -- completion = cmp.config.window.bordered(), 13 | -- documentation = cmp.config.window.bordered(), 14 | }, 15 | mapping = cmp.mapping.preset.insert({ 16 | [''] = cmp.mapping.scroll_docs(-4), 17 | [''] = cmp.mapping.scroll_docs(4), 18 | [''] = cmp.mapping.complete(), 19 | [''] = cmp.mapping.abort(), 20 | [''] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. 21 | }), 22 | sources = cmp.config.sources({ 23 | { name = 'nvim_lsp' }, 24 | { name = 'ultisnips' }, -- For ultisnips users. 25 | { name = 'path' }, 26 | { 27 | name = 'buffer', 28 | option = { 29 | label = '[b]', 30 | -- all buffers which are below 1 megabyte max. 31 | get_bufnrs = function() 32 | local small_buffers = {} 33 | for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do 34 | local byte_size = vim.api.nvim_buf_get_offset(bufnr, vim.api.nvim_buf_line_count(bufnr)) 35 | if byte_size < 1024 * 1024 then -- 1 megabyte in bytes 36 | table.insert(small_buffers, bufnr) 37 | end 38 | end 39 | return small_buffers 40 | end 41 | } 42 | }, 43 | { 44 | name = 'tmux', 45 | option = { 46 | all_panes = true, 47 | label = '[t]' 48 | } 49 | }, 50 | }, { 51 | { name = 'buffer' }, 52 | }) 53 | }) 54 | 55 | -- Set configuration for specific filetype. 56 | cmp.setup.filetype('gitcommit', { 57 | sources = cmp.config.sources({ 58 | { name = 'git' }, -- You can specify the `git` source if [you were installed it](https://github.com/petertriho/cmp-git). 59 | }, { 60 | { name = 'buffer' }, 61 | }) 62 | }) 63 | 64 | -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). 65 | cmp.setup.cmdline({ '/', '?' }, { 66 | mapping = cmp.mapping.preset.cmdline(), 67 | sources = { 68 | { name = 'buffer' } 69 | } 70 | }) 71 | 72 | -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). 73 | cmp.setup.cmdline(':', { 74 | mapping = cmp.mapping.preset.cmdline(), 75 | sources = cmp.config.sources({ 76 | { name = 'path' } 77 | }, { 78 | { name = 'cmdline' } 79 | }) 80 | }) 81 | 82 | -------------------------------------------------------------------------------- /.config/nvim/plugins/coc.vim: -------------------------------------------------------------------------------- 1 | " Always show the signcolumn, otherwise it would shift the text each time 2 | set signcolumn=number 3 | set completeopt+=menuone 4 | 5 | " trigger completion on CTRL-N and CTRL-P 6 | " inoremap coc#refresh() 7 | " inoremap coc#refresh() 8 | 9 | " gd - go to definition of word under cursor 10 | nmap gd (coc-definition) 11 | nmap gy (coc-type-definition) 12 | 13 | " gi - go to implementation 14 | nmap gi (coc-implementation) 15 | 16 | " gr - find references 17 | nmap gr (coc-references) 18 | 19 | " K - get hint on whatever's under the cursor 20 | nnoremap K :call ShowDocumentation() 21 | 22 | function! ShowDocumentation() 23 | if CocAction('hasProvider', 'hover') 24 | call CocActionAsync('doHover') 25 | else 26 | call feedkeys('K', 'in') 27 | endif 28 | endfunction 29 | 30 | 31 | " Highlight symbol under cursor on CursorHold 32 | autocmd CursorHold * silent call CocActionAsync('highlight') 33 | 34 | nnoremap co :CocList outline 35 | nnoremap cs :CocList -I symbols 36 | 37 | " List errors 38 | nnoremap cl :CocList locationlist 39 | 40 | " list commands available in tsserver (and others) 41 | nnoremap cc :CocList commands 42 | 43 | " restart when tsserver gets wonky 44 | nnoremap cR :CocRestart 45 | 46 | " view all errors 47 | nnoremap cl :CocList locationlist 48 | 49 | " manage extensions 50 | nnoremap cx :CocList extensions 51 | 52 | " rename the current word in the cursor 53 | nmap cn (coc-rename) 54 | xmap f (coc-format-selected) 55 | nmap f (coc-format-selected) 56 | 57 | " :Fmt to format the current buffer 58 | command! -nargs=0 Fmt :call CocActionAsync('format') 59 | 60 | " Mappings for CoCList 61 | " Show all diagnostics. 62 | nnoremap a :CocList diagnostics 63 | " Manage extensions. 64 | nnoremap e :CocList extensions 65 | " Show commands. 66 | nnoremap c :CocList commands 67 | " Find symbol of current document. 68 | nnoremap o :CocList outline 69 | " Search workspace symbols. 70 | nnoremap s :CocList -I symbols 71 | " Do default action for next item. 72 | nnoremap j :CocNext 73 | " Do default action for previous item. 74 | nnoremap k :CocPrev 75 | " Resume latest coc list. 76 | nnoremap p :CocListResume 77 | 78 | " Mappings for coc-snippets 79 | " Use for both expand and jump (make expand higher priority.) 80 | imap (coc-snippets-expand-jump) 81 | " Use for select text for visual placeholder of snippet 82 | vmap (coc-snippets-select) 83 | 84 | -------------------------------------------------------------------------------- /.config/nvim/plugins/fzf.vim: -------------------------------------------------------------------------------- 1 | 2 | command! -bang -nargs=? -complete=dir Files 3 | \ call fzf#vim#files(, {'options': ['--layout=reverse', '--info=inline', '--preview', 'head {}']}, 0) 4 | 5 | " fzf window anchored to the buttom 6 | let g:fzf_layout = { 7 | \ 'window': { 8 | \ 'border': 'top', 9 | \ 'xoffset': 0, 10 | \ 'width': 1, 11 | \ 'height': 0.5, 12 | \ 'relative': v:true, 13 | \ 'yoffset': 1.0 14 | \ } } 15 | 16 | " hide statusline when fzf window is open 17 | autocmd! FileType fzf 18 | autocmd FileType fzf set laststatus=0 noshowmode noruler 19 | \| autocmd BufLeave set laststatus=2 showmode ruler 20 | 21 | " close fzf window with 22 | autocmd FileType fzf tnoremap :q 23 | 24 | let g:fzf_action = { 25 | \ 'ctrl-m': 'tabedit', 26 | \ 'ctrl-o': 'e', 27 | \ 'ctrl-t': 'tabedit', 28 | \ 'ctrl-h': 'botright split', 29 | \ 'ctrl-v': 'vertical botright split' } 30 | 31 | function! RipgrepFzf(query, fullscreen) 32 | let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case -- %s || true' 33 | let initial_command = printf(command_fmt, shellescape(a:query)) 34 | let reload_command = printf(command_fmt, '{q}') 35 | let spec = {'options': ['--phony', '--query', a:query, '--bind', 'change:reload:'.reload_command]} 36 | call fzf#vim#grep(initial_command, 1, fzf#vim#with_preview(spec), a:fullscreen) 37 | endfunction 38 | 39 | command! -nargs=* -bang Rg call RipgrepFzf(, 0) 40 | 41 | -------------------------------------------------------------------------------- /.config/nvim/plugins/ncm2.vim: -------------------------------------------------------------------------------- 1 | " enable ncm2 for all buffers 2 | autocmd BufEnter * call ncm2#enable_for_buffer() 3 | 4 | " IMPORTANT: :help Ncm2PopupOpen for more information 5 | set completeopt=noinsert,menuone,noselect 6 | 7 | -------------------------------------------------------------------------------- /.config/nvim/plugins/supermaven.lua: -------------------------------------------------------------------------------- 1 | local supermaven = require'supermaven-nvim' 2 | 3 | supermaven.setup({ 4 | keymaps = { 5 | accept_suggestion = "", 6 | -- clear_suggestion = "", 7 | }, 8 | condition = function() 9 | return string.match(vim.fn.expand("%:t"), ".envrc") 10 | end, 11 | }) 12 | -------------------------------------------------------------------------------- /.config/nvim/plugins/tailwindtools.lua: -------------------------------------------------------------------------------- 1 | require("tailwind-tools").setup({ 2 | server = { 3 | override = false, 4 | } 5 | }) 6 | 7 | -------------------------------------------------------------------------------- /.config/nvim/plugins/toggleterm.vim: -------------------------------------------------------------------------------- 1 | lua << EOF 2 | require('toggleterm').setup({ 3 | start_in_insert = true, 4 | hide_numbers = false, 5 | }) 6 | 7 | function _G.set_toggleterm_keymaps() 8 | local opts = {buffer = 0} 9 | vim.keymap.set('t', '', [[]], opts) 10 | end 11 | -- if you only want these mappings for toggle term use term://*toggleterm#* instead 12 | vim.cmd('autocmd! TermOpen term://*toggleterm#* lua set_toggleterm_keymaps()') 13 | 14 | -- Custom terminals 15 | 16 | -- Create a terminal for ollama 17 | local Terminal = require('toggleterm.terminal').Terminal 18 | local ollama = Terminal:new({ 19 | cmd = "ollama run $(ollama list | tail -n+2 | fzf --cycle | awk '{print $1}')", 20 | hidden = true, 21 | close_on_exit = false, 22 | on_open = function(term) 23 | vim.api.nvim_buf_set_keymap(term.bufnr, "n", "", "close", { noremap = true, silent = true }) 24 | end, 25 | }) 26 | function _ollama_toggle() 27 | ollama:toggle() 28 | end 29 | vim.api.nvim_set_keymap("n", "ai", "lua _ollama_toggle()", { noremap = true, silent = true }) 30 | EOF 31 | 32 | -------------------------------------------------------------------------------- /.config/nvim/plugins/ultisnips.vim: -------------------------------------------------------------------------------- 1 | let g:UltiSnipsExpandTrigger="" 2 | let g:UltiSnipsJumpForwardTrigger="" 3 | let g:UltiSnipsJumpBackwardTrigger="" 4 | 5 | let g:UltiSnipsEditSplit="horizontal" 6 | let g:UltiSnipsSnippetDirectories=[$HOME."/.nvim/my-ultisnips"] 7 | 8 | -------------------------------------------------------------------------------- /.config/nvim/plugins/undotree.lua: -------------------------------------------------------------------------------- 1 | vim.keymap.set("n", "u", vim.cmd.UndotreeToggle) 2 | -------------------------------------------------------------------------------- /.config/nvim/plugins/yowish.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Overbryd/dotfiles/e5ca721a56b59ff6794e380359a11ea8f94bb274/.config/nvim/plugins/yowish.vim -------------------------------------------------------------------------------- /.config/nvim/startscreen.vim: -------------------------------------------------------------------------------- 1 | " Taken from 2 | " https://github.com/arp242/startscreen.vim/blob/master/plugin/startscreen.vim 3 | fun! startscreen#start() 4 | " Don't run if: 5 | " - there are commandline arguments; 6 | " - the buffer isn't empty (e.g. cmd | vi -); 7 | " - we're not invoked as vim or gvim; 8 | " - we're starting in insert mode. 9 | if argc() || line2byte('$') != -1 || v:progname !~? '^[-gmnq]\=vim\=x\=\%[\.exe]$' || &insertmode 10 | return 11 | endif 12 | 13 | " Open the fuzzy file finder 14 | :Files! 15 | 16 | endfun 17 | 18 | augroup startscreen 19 | autocmd! 20 | autocmd VimEnter * call startscreen#start() 21 | augroup end 22 | -------------------------------------------------------------------------------- /.config/nvim/treesitter.vim: -------------------------------------------------------------------------------- 1 | lua < 3 | # 4 | use_ruby() { 5 | local ruby_dir=$HOMEBREW_PREFIX/rubies/$1 6 | load_prefix $ruby_dir 7 | layout ruby 8 | } 9 | 10 | layout_docker-shims() { 11 | export DOCKER_SHIMS_DIR="$(direnv_layout_dir)/.docker-shims" 12 | mkdir -p "$DOCKER_SHIMS_DIR/bin" 13 | mkdir -p "$DOCKER_SHIMS_DIR/home" 14 | test -d "$HOME/.docker-shims/$1" && cp -r "$HOME/.docker-shims/$1/" "$DOCKER_SHIMS_DIR/" 15 | PATH_add "$DOCKER_SHIMS_DIR/bin" 16 | PATH_add "$HOME/.docker-shims/bin" 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.finicky.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | defaultBrowser: { 3 | name: 'SafeBrowser', 4 | appType: 'command', 5 | command: '/Users/partenkirchen/.bin/safebrowser', 6 | }, 7 | handlers: [ 8 | { 9 | match: finicky.matchHostnames([ 10 | // Google 11 | /.*\.?google\.com$/, 12 | /.*\.?google$/, 13 | // Gitlab 14 | /.*\.?gitlab\.com$/, 15 | // Github 16 | /.*\.?github\.com$/, 17 | // draw.io 18 | 'app.diagrams.net', 19 | // Excalidraw 20 | 'excalidraw.com', 21 | // OpenAI 22 | 'chatgpt.com', 23 | /.*\.?openai\.com$/, 24 | // Slite 25 | /.*\.?slite\.com$/, 26 | // Fyrst 27 | /.*\.?fyrst\.de$/, 28 | ]), 29 | browser: 'Safari', 30 | }, 31 | //{ 32 | // match: 'googlemail.com', 33 | // browser: { 34 | // name: 'SafeBrowser', 35 | // appType: 'command', 36 | // command: '/Users/partenkirchen/.bin/safebrowser', 37 | // }, 38 | //}, 39 | ], 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /.gemrc: -------------------------------------------------------------------------------- 1 | --- 2 | :backtrace: false 3 | :bulk_threshold: 1000 4 | :sources: 5 | - https://rubygems.org/ 6 | :update_sources: true 7 | :verbose: true 8 | install: --no-rdoc --no-ri 9 | update: --no-rdoc --no-ri 10 | gem: --no-ri --no-rdoc 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | .ssh/config text=auto 3 | .ssh/*.pem filter=git-crypt diff=git-crypt 4 | .profile.d/credentials filter=git-crypt diff=git-crypt 5 | .envrc filter=git-crypt diff=git-crypt 6 | 7 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [apply] 2 | whitespace = fix 3 | [core] 4 | autocrlf = input 5 | excludesfile = ~/.gitignore 6 | attributesfile = ~/.gitattributes 7 | whitespace = fix,space-before-tab,tab-in-indent,trailing-space 8 | [color] 9 | ui = auto 10 | [color "branch"] 11 | current = yellow reverse 12 | local = yellow 13 | remote = green 14 | [color "diff"] 15 | meta = yellow bold 16 | frag = magenta bold 17 | old = red bold 18 | new = green bold 19 | [color "status"] 20 | added = green 21 | changed = yellow 22 | untracked = cyan 23 | [merge] 24 | log = true 25 | [url "git@github.com:"] 26 | insteadOf = "gh:" 27 | pushInsteadOf = "github:" 28 | pushInsteadOf = "git://github.com/" 29 | [url "git://github.com/"] 30 | insteadOf = "github:" 31 | [url "git@gist.github.com:"] 32 | insteadOf = "gst:" 33 | pushInsteadOf = "gist:" 34 | pushInsteadOf = "git://gist.github.com/" 35 | [url "git://gist.github.com/"] 36 | insteadOf = "gist:" 37 | [user] 38 | name = Lukas Rieder 39 | email = l.rieder@gmail.com 40 | [alias] 41 | s = status 42 | co = checkout 43 | com = commit 44 | coma = "commit -a" 45 | acom = "aicommit" 46 | acoma = "aicommit -a" 47 | history = "log -p" 48 | shallow-clone = "clone --depth=1" 49 | tree = "log --graph --oneline --all --decorate=full" 50 | pick = "cherry-pick" 51 | contributors = "shortlog -n -s --no-merges" 52 | amend = "commit -a --amend" 53 | amenda = "commit -a --amend" 54 | amen = "commit --amend --no-edit" 55 | amena = "commit -a --amend --no-edit" 56 | staged = "diff --staged" 57 | bush = "push --set-upstream $(git remote) HEAD" 58 | [push] 59 | default = upstream 60 | autoSetupRemote = true 61 | [status] 62 | submoduleSummary = true 63 | [pull] 64 | ff = only 65 | [safe] 66 | directory = /usr/local/dotfiles 67 | [init] 68 | defaultBranch = main 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Folder view configuration files 2 | .DS_Store 3 | Desktop.ini 4 | 5 | # Thumbnail cache files 6 | ._* 7 | Thumbs.db 8 | 9 | # Files that might appear on external disks 10 | .Spotlight-V100 11 | .Trashes 12 | 13 | # Ruby byebug debugger history files 14 | .byebug_history 15 | .envrc 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule ".vim/bundle/vundle"] 2 | path = .vim/bundle/vundle 3 | url = https://github.com/gmarik/vundle.git 4 | -------------------------------------------------------------------------------- /.hushlogin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Overbryd/dotfiles/e5ca721a56b59ff6794e380359a11ea8f94bb274/.hushlogin -------------------------------------------------------------------------------- /.inputrc: -------------------------------------------------------------------------------- 1 | # Make Tab autocomplete regardless of filename case 2 | set completion-ignore-case on 3 | 4 | # Treat hyphens and underscores as equivalent 5 | set completion-map-case on 6 | 7 | # List all matches in case multiple possible completions are possible 8 | set show-all-if-ambiguous on 9 | 10 | # Immediately add a trailing slash when autocompleting symlinks to directories 11 | set mark-symlinked-directories on 12 | 13 | # Use the text that has already been typed as the prefix for searching through 14 | # commands (i.e. more intelligent Up/Down behavior) 15 | $if Bash 16 | "\e[B": history-search-forward 17 | "\e[A": history-search-backward 18 | $endif 19 | 20 | # Do not autocomplete hidden files unless the pattern explicitly begins with a dot 21 | set match-hidden-files off 22 | 23 | # Show all autocomplete results at once 24 | set page-completions off 25 | 26 | # Immediately show all possible completions 27 | set show-all-if-ambiguous on 28 | 29 | # If there are more than 200 possible completions for a word, ask to show them all 30 | set completion-query-items 200 31 | 32 | # Show extra file information when completing, like `ls -F` does 33 | set visible-stats on 34 | 35 | # Be more intelligent when autocompleting by also looking at the text after 36 | # the cursor. For example, when the current line is "cd ~/src/mozil", and 37 | # the cursor is on the "z", pressing Tab will not autocomplete it to "cd 38 | # ~/src/mozillail", but to "cd ~/src/mozilla". (This is supported by the 39 | # Readline used by Bash 4.) 40 | set skip-completed-text on 41 | 42 | # Allow UTF-8 input and output, instead of showing stuff like $'\0123\0456' 43 | set input-meta on 44 | set output-meta on 45 | set convert-meta off 46 | 47 | # Use Alt/Meta + Delete to delete the preceding word 48 | "\e[3;3~": kill-word 49 | 50 | # stop at slashes and spaces instead of only spaces 51 | set bind-tty-special-chars off 52 | # delete last word until slashes and spaces 53 | Control-w: unix-filename-rubout 54 | 55 | # Use menu-complete 56 | TAB: menu-complete 57 | 58 | -------------------------------------------------------------------------------- /.irbrc: -------------------------------------------------------------------------------- 1 | require "irb/ext/save-history" 2 | require "irb/completion" 3 | IRB.conf[:SAVE_HISTORY] = 1000 4 | IRB.conf[:HISTORY_FILE] = "#{ENV["HOME"]}/.irb_history" 5 | 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | cache=~/.npmcache 2 | 3 | -------------------------------------------------------------------------------- /.phoenix.js: -------------------------------------------------------------------------------- 1 | Phoenix.set({ 2 | daemon: false, 3 | openAtLogin: true 4 | }); 5 | 6 | const log = Phoenix.log; 7 | const FULLHD = { 8 | width: 1920, 9 | height: 1080, 10 | }; 11 | const IGNORE_APPS = [ 12 | new RegExp('^1Password'), 13 | new RegExp('^System Settings'), 14 | new RegExp('^Activity Monitor'), 15 | new RegExp('^Remote Desktop'), 16 | new RegExp('^Loopback'), 17 | new RegExp('^LaunchBar'), 18 | new RegExp('^Temp Monitor'), 19 | new RegExp('^Pixelmator Pro'), 20 | ]; 21 | const IGNORE_WINDOWS = [ 22 | // ignore windows that have no title 23 | new RegExp('^\s*$'), 24 | // ignore Microsoft Teams notification windows which are invisible, and should not be managed 25 | new RegExp('^Microsoft Teams Notification$'), 26 | // ignore invisible or small short lived auto-update windows that sometimes appear 27 | new RegExp('^Updating.*'), 28 | ]; 29 | 30 | class WindowContainer { 31 | constructor() { 32 | this.stack = []; 33 | this.minimized = []; 34 | this.windowDidCloseHandler = new Event('windowDidClose', (window) => this.removeWindow(window)) 35 | this.windowDidMinimizeHandler = new Event('windowDidMinimize', (window) => this.minimizeWindow(window)) 36 | this.windowDidUnminimizeHandler = new Event('windowDidUnminimize', (window) => this.unminimizeWindow(window)); 37 | } 38 | 39 | debug(indent) { 40 | indent = indent || ''; 41 | log(`${indent}${this.constructor.name}: ${this.stack.length}`); 42 | for (const window of this.stack) { 43 | log(`${indent}${window}: [${window.app().name()}][${window.title()}]`); 44 | } 45 | } 46 | 47 | reload() { 48 | for (const window of this.stack) { 49 | if (SpaceManager.isWindowIgnored(window)) 50 | this.stack = this.stack.filter(instance => instance.hash() !== window.hash()); 51 | } 52 | this.render(); 53 | } 54 | 55 | has(window) { 56 | if (!window) 57 | false; 58 | return !!this.stack.find(instance => instance.hash() === window.hash()); 59 | } 60 | 61 | stackHead() { 62 | return this.stack[0]; 63 | } 64 | 65 | minimizeWindow(window, opts) { 66 | if (!this.has(window)) 67 | return; 68 | this.minimized.push(window); 69 | this.removeWindow(window); 70 | } 71 | 72 | unminimizeWindow(window, opts) { 73 | const found = this.minimized.find(instance => instance.hash() === window.hash()); 74 | this.minimized = this.minimized.filter(instance => instance.hash() !== window.hash()); 75 | if (found) 76 | this.pushWindow(window, opts); 77 | } 78 | 79 | removeWindow(window, opts) { 80 | if (!window) 81 | return; 82 | opts = opts || {} 83 | this.stack = this.stack.filter(instance => instance.hash() !== window.hash()); 84 | if (opts.render !== false) 85 | this.render(); 86 | } 87 | 88 | unshiftWindow(window, opts) { 89 | if (!window) 90 | return; 91 | opts = opts || {} 92 | if (this.has(window)) 93 | return; 94 | this.stack.unshift(window); 95 | if (opts.render !== false) 96 | this.render(); 97 | } 98 | 99 | pushWindow(window, opts) { 100 | if (!window) 101 | return; 102 | opts = opts || {} 103 | if (this.has(window)) 104 | return; 105 | if (window.isMinimized()) 106 | this.minimized.push(window); 107 | else 108 | this.stack.push(window); 109 | if (opts.render !== false) 110 | this.render(); 111 | } 112 | 113 | render() {} 114 | } 115 | 116 | class FramedContainer extends WindowContainer { 117 | constructor(frame) { 118 | super(); 119 | this.frame = frame; 120 | } 121 | 122 | render() { 123 | for (const [i, window] of this.stack.reverse().entries()) { 124 | window.setFrame({ 125 | x: this.frame.x, 126 | y: this.frame.y, 127 | width: this.frame.width, 128 | height: this.frame.height, 129 | }); 130 | } 131 | } 132 | } 133 | 134 | class SingleFramedContainer extends FramedContainer { 135 | pushWindow(window, opts) { 136 | super.pushWindow(window, opts); 137 | opts = opts || {}; 138 | for (const instance of this.stack) { 139 | if (instance.hash() !== window.hash()) 140 | this.removeWindow(instance); 141 | } 142 | } 143 | 144 | unshiftWindow(window, opts) { 145 | super.unshiftWindow(window, opts); 146 | opts = opts || {}; 147 | for (const instance of this.stack) { 148 | if (instance.hash() !== window.hash()) 149 | this.removeWindow(instance); 150 | } 151 | } 152 | } 153 | 154 | class VerticalContainer extends FramedContainer { 155 | render() { 156 | const windowHeight = Math.floor(this.frame.height / this.stack.length); 157 | for (const [i, window] of this.stack.entries()) { 158 | window.setFrame({ 159 | x: this.frame.x, 160 | y: this.frame.y + i * windowHeight, 161 | width: this.frame.width, 162 | height: windowHeight, 163 | }); 164 | } 165 | } 166 | } 167 | 168 | class ContainerManager { 169 | constructor() { 170 | this.containers = new Map(); 171 | } 172 | 173 | debug(indent) { 174 | indent = indent || ''; 175 | log(`${indent}${this.constructor.name}: ${[...this.containers.keys()].join(', ')}`); 176 | for (const [name, container] of this.containers) { 177 | log(`${indent}${name}: [x: ${container.frame.x}, y: ${container.frame.y}, w: ${container.frame.width}, h: ${container.frame.height}`) 178 | container.debug(indent + ' '); 179 | } 180 | } 181 | 182 | reload() { 183 | for (const [name, container] of this.containers) { 184 | container.reload(); 185 | } 186 | } 187 | 188 | setupContainer(screen, name, containerCallback) { 189 | const screenFrame = screen.flippedVisibleFrame(); 190 | const frame = containerCallback(screen, screenFrame); 191 | const container = new frame.handler({name: name, ...frame}); 192 | this.containers.set(name, container); 193 | } 194 | 195 | pushFocused(name) { 196 | const window = Window.focused(); 197 | this.pushWindow(window, name); 198 | } 199 | 200 | unshiftFocused(name) { 201 | const window = Window.focused(); 202 | this.unshiftWindow(window, name); 203 | } 204 | 205 | unshiftWindow(window, name, render) { 206 | render = render === undefined || render; 207 | for (const [name, container] of this.containers) { 208 | container.removeWindow(window, {render: false}); 209 | } 210 | const container = this.containers.get(name); 211 | container.unshiftWindow(window, {render: false}); 212 | if (render) this.render(); 213 | } 214 | 215 | removeWindow(window, render) { 216 | render = render === undefined || render; 217 | for (const [name, container] of this.containers) { 218 | container.removeWindow(window, {render: false}); 219 | } 220 | if (render) this.render(); 221 | } 222 | 223 | pushWindow(window, name, render) { 224 | render = render === undefined || render; 225 | for (const [name, container] of this.containers) { 226 | container.removeWindow(window, {render: false}); 227 | } 228 | const container = this.containers.get(name); 229 | container.pushWindow(window, {render: false}); 230 | if (render) this.render(); 231 | } 232 | 233 | swapFocused(targetContainerName, render) { 234 | render = render === undefined || render; 235 | const window = Window.focused(); 236 | if (SpaceManager.isWindowIgnored(window)) 237 | return; 238 | const targetContainer = this.containers.get(targetContainerName); 239 | if (!targetContainer) 240 | return; 241 | let currentContainerName; 242 | for (const [name, container] of this.containers) { 243 | if (container.has(window)) { 244 | currentContainerName = name; 245 | break; 246 | } 247 | } 248 | if (currentContainerName === targetContainerName) 249 | return; 250 | const swapWindow = targetContainer.stackHead(); 251 | this.unshiftWindow(window, targetContainerName, false); 252 | if (swapWindow !== undefined && currentContainerName) 253 | this.unshiftWindow(swapWindow, currentContainerName, false); 254 | if (render) this.render(); 255 | } 256 | 257 | render() { 258 | for (const [name, container] of this.containers) { 259 | container.render(); 260 | } 261 | } 262 | } 263 | 264 | class SpaceManager { 265 | static spaceManagers = new Map(); 266 | 267 | static active() { 268 | const space = Space.active(); 269 | return SpaceManager.spaceManagers.get(space.hash()); 270 | } 271 | 272 | static add(screen, space, containers) { 273 | const spaceManager = new SpaceManager(screen, space, containers); 274 | spaceManager.setup(); 275 | SpaceManager.spaceManagers.set(space.hash(), spaceManager); 276 | } 277 | 278 | static debug(indent) { 279 | indent = indent || ''; 280 | for (const [key, spaceManager] of SpaceManager.spaceManagers) { 281 | log(`${indent}${this.name}[${key}]:`); 282 | spaceManager.containerManager.debug(indent + ' '); 283 | } 284 | } 285 | 286 | static reload() { 287 | for (const [key, spaceManager] of SpaceManager.spaceManagers) { 288 | spaceManager.containerManager.reload(); 289 | } 290 | } 291 | 292 | static isWindowIgnored(window) { 293 | if (!window || `${window.app().name()}` === '' || `${window.title()}` === '') { 294 | log(`ignoring empty app or window title [${window.app().name()}][${window.title()}]`); 295 | return true; 296 | } 297 | if (window.size().width === 0 && window.size().height === 0) { 298 | log(`ignoring size 0 [${window.app().name()}][${window.title()}]`); 299 | return true; 300 | } 301 | if (IGNORE_APPS.find(regex => { return window.app().name().match(regex)})) { 302 | log(`ignoring [${window.app().name()}][*]`); 303 | return true; 304 | } 305 | if (IGNORE_WINDOWS.find(regex => { return window.title().match(regex)})) { 306 | log(`ignoring [${window.app().name()}][${window.title()}]`); 307 | return true; 308 | } 309 | return false; 310 | } 311 | 312 | static releaseFocusedWindow() { 313 | const window = Window.focused(); 314 | if (!window) 315 | return; 316 | for (const [key, spaceManager] of SpaceManager.spaceManagers) { 317 | spaceManager.containerManager.removeWindow(window); 318 | } 319 | } 320 | 321 | constructor(screen, space, containerSpec) { 322 | this.screen = screen; 323 | this.space = space; 324 | this.containerManager = new ContainerManager(); 325 | this.containerSpec = containerSpec; 326 | } 327 | 328 | setup() { 329 | const affinityRules = [ 330 | (window) => { return window?.hash() == Window.focused().hash() ? 'main' : null} 331 | ]; 332 | 333 | for (const containerSpec of this.containerSpec.values()) { 334 | this.containerManager.setupContainer(this.screen, containerSpec.name, containerSpec.containerCallback); 335 | const affinity = containerSpec.affinity || []; 336 | for (const [appName, windowTitle] of affinity) { 337 | affinityRules.push((window) => { 338 | return ( 339 | window.app().name().match(new RegExp(appName)) && window.title().match(new RegExp(windowTitle)) 340 | ) ? containerSpec.name : null; 341 | }) 342 | } 343 | } 344 | const containerNames = [...this.containerManager.containers.keys()].filter(name => name !== 'main'); 345 | 346 | for (const i in this.space.windows()) { 347 | const window = this.space.windows()[i]; 348 | if (SpaceManager.isWindowIgnored(window)) { 349 | continue; 350 | } 351 | const affinityRule = affinityRules.find(rule => rule(window)); 352 | const containerName = affinityRule && affinityRule(window) || containerNames[i % containerNames.length]; 353 | log(`[${window.app().name()}][${window.title()}] assigned to ${containerName}`); 354 | this.containerManager.pushWindow(window, containerName, false); 355 | } 356 | this.containerManager.render(); 357 | } 358 | } 359 | 360 | function setupOneScreen() { 361 | if (!!SpaceManager.active()) 362 | return; 363 | const screen = Screen.main(); 364 | for (const i in Space.all()) { 365 | const space = Space.all()[i]; 366 | SpaceManager.add(screen, space, [ 367 | { 368 | name: 'main', 369 | containerCallback: (screen, screenFrame) => { 370 | return { 371 | handler: SingleFramedContainer, 372 | x: screenFrame.x + screenFrame.width / 2 - FULLHD.width / 2, 373 | y: screenFrame.y, 374 | width: FULLHD.width, 375 | height: FULLHD.height, 376 | } 377 | } 378 | }, 379 | { 380 | name: 'secondary', 381 | containerCallback: (screen, screenFrame) => { 382 | return { 383 | handler: VerticalContainer, 384 | x: screenFrame.x + screenFrame.width / 2 - FULLHD.width / 2, 385 | y: screenFrame.y + FULLHD.height, 386 | width: FULLHD.width, 387 | height: screenFrame.height - FULLHD.height, 388 | } 389 | } 390 | }, 391 | { 392 | name: 'left', 393 | affinity: [ 394 | ['Slack', '.*'], 395 | ['Spark', '.*'], 396 | ['Vivaldi', 'WhatsApp'], 397 | ['Microsoft Teams', '.*'], 398 | ], 399 | containerCallback: (screen, screenFrame) => { 400 | return { 401 | handler: VerticalContainer, 402 | x: screenFrame.x, 403 | y: screenFrame.y, 404 | width: screenFrame.width / 2 - FULLHD.width / 2, 405 | height: screenFrame.height, 406 | } 407 | } 408 | }, 409 | { 410 | name: 'right', 411 | affinity: [ 412 | ['Notes', '.*'], 413 | ['Preview', '.*'], 414 | ['Google Meet', '.*'], 415 | ], 416 | containerCallback: (screen, screenFrame) => { 417 | return { 418 | handler: VerticalContainer, 419 | x: screenFrame.x + screenFrame.width / 2 + FULLHD.width / 2, 420 | y: screenFrame.y, 421 | width: screenFrame.width / 2 - FULLHD.width / 2, 422 | height: screenFrame.height, 423 | } 424 | } 425 | }, 426 | ]); 427 | } 428 | } 429 | 430 | function setupTwoScreen() { 431 | if (!!SpaceManager.active()) 432 | return; 433 | let recordingScreen = Screen.all()[0]; 434 | let controlScreen = Screen.all()[1]; 435 | if (recordingScreen.frame().width != FULLHD.width && recordingScreen.frame().width != FULLHD.height) { 436 | controlScreen = Screen.all()[0]; 437 | recordingScreen = Screen.all()[1]; 438 | } 439 | for (const i in recordingScreen.spaces()) { 440 | const space = recordingScreen.spaces()[i]; 441 | SpaceManager.add(recordingScreen, space, [ 442 | { 443 | name: 'main', 444 | containerCallback: (screen, screenFrame) => { 445 | return { 446 | handler: SingleFramedContainer, 447 | x: screenFrame.x, 448 | y: screenFrame.y, 449 | width: screenFrame.width, 450 | height: screenFrame.height, 451 | } 452 | } 453 | } 454 | ]); 455 | } 456 | for (const i in controlScreen.spaces()) { 457 | const space = controlScreen.spaces()[i]; 458 | SpaceManager.add(controlScreen, space, [ 459 | { 460 | name: 'left', 461 | containerCallback: (screen, screenFrame) => { 462 | return { 463 | handler: VerticalContainer, 464 | x: screenFrame.x, 465 | y: screenFrame.y, 466 | width: screenFrame.width / 2, 467 | height: screenFrame.height, 468 | } 469 | } 470 | }, 471 | { 472 | name: 'right', 473 | containerCallback: (screen, screenFrame) => { 474 | return { 475 | handler: VerticalContainer, 476 | x: screenFrame.x + screenFrame.width / 2, 477 | y: screenFrame.y, 478 | width: screenFrame.width / 2, 479 | height: screenFrame.height, 480 | } 481 | } 482 | } 483 | ]); 484 | } 485 | } 486 | 487 | function setup() { 488 | const screenCount = Screen.all().length; 489 | // if (screenCount === 1) { 490 | log('setting up one screen layout'); 491 | setupOneScreen(); 492 | // } else if (screenCount === 2) { 493 | // log('setting up two screen layout'); 494 | // setupTwoScreen(); 495 | // } 496 | } 497 | 498 | // Keybindings 499 | const mash = ['ctrl', 'cmd']; 500 | 501 | // Move windows 502 | Key.on('up', mash, () => SpaceManager.active().containerManager.swapFocused('main', true)) 503 | Key.on('down', mash, () => SpaceManager.active().containerManager.swapFocused('secondary', true)) 504 | Key.on('right', mash, () => SpaceManager.active().containerManager.unshiftFocused('right', true)) 505 | Key.on('left', mash, () => SpaceManager.active().containerManager.unshiftFocused('left', true)) 506 | 507 | // Focus windows 508 | Key.on('h', mash, () => Window.focused().focusClosestNeighbour('west')); 509 | Key.on('j', mash, () => Window.focused().focusClosestNeighbour('south')); 510 | Key.on('k', mash, () => Window.focused().focusClosestNeighbour('north')); 511 | Key.on('l', mash, () => Window.focused().focusClosestNeighbour('east')); 512 | 513 | // Debug 514 | Key.on('d', mash, () => SpaceManager.debug()); 515 | // Phoenix keys 516 | // mash + r => reload 517 | Key.on('r', mash, () => SpaceManager.reload()) 518 | // mash + space => release 519 | Key.on('x', mash, () => SpaceManager.releaseFocusedWindow()); 520 | 521 | // Event.on('screensDidChange', () => Phoenix.reload()); 522 | 523 | // Event.on('appDidLaunch', (app) => { 524 | // log(`appDidLaunch: ${app.name()}`) 525 | // }) 526 | 527 | // Event.on('appDidActivate', (app) => { 528 | // log(`appDidActivate: ${app.name()}`) 529 | // }) 530 | 531 | setup(); 532 | log('Configuration loaded.'); 533 | 534 | -------------------------------------------------------------------------------- /.profile: -------------------------------------------------------------------------------- 1 | # vim all the things 2 | export EDITOR="nvim" 3 | export VISUAL="$EDITOR" 4 | 5 | # utf-8 all the things 6 | export LC_ALL=en_US.UTF-8 7 | export LANG=en_US.UTF-8 8 | 9 | # make sure we know the right cpu architecture 10 | # used to set HOMEBRWE_PREFIX, PYENV_ROOT and other environment variables 11 | export ARCH="$(uname -p)" 12 | 13 | # Case-insensitive globbing (used in pathname expansion) 14 | shopt -s nocaseglob 15 | 16 | # Long history without duplicates, flush after every command 17 | export HISTCONTROL=ignoreboth 18 | export HISTSIZE=1000000 19 | 20 | # directly save every command to history 21 | shopt -s histappend 22 | if [ "x$PROMPT_COMMAND" != "x" ]; then 23 | export PROMPT_COMMAND="$PROMPT_COMMAND;" 24 | fi 25 | export PROMPT_COMMAND="$PROMPT_COMMAND history -a; history -n" # preserve other PROMPT_COMMAND stuff! 26 | 27 | source ~/.profile.d/credentials 28 | source ~/.profile.d/aliases 29 | source ~/.profile.d/functions 30 | source ~/.profile.d/prompt 31 | source ~/.profile.d/homebrew 32 | source ~/.profile.d/pyenv 33 | source ~/.profile.d/rbenv 34 | source ~/.profile.d/nodenv 35 | source ~/.profile.d/tfenv 36 | source ~/.profile.d/golang 37 | source ~/.profile.d/path 38 | source ~/.profile.d/direnv 39 | source ~/.profile.d/google-cloud-sdk 40 | source ~/.profile.d/fzf 41 | source ~/.profile.d/do_not_track 42 | 43 | -------------------------------------------------------------------------------- /.profile.d/aliases: -------------------------------------------------------------------------------- 1 | # nice directory listing 2 | alias l="ls -lah" 3 | 4 | # nice directory tree listing, but just 2-3 levels 5 | alias tree2="tree -L 2 --dirsfirst" 6 | alias tree3="tree -L 3 --dirsfirst" 7 | 8 | # I use git so often that aliasing it saves a lot 9 | alias g="git" 10 | # I often mistype gs and then this stupid ghost script shell pops up 11 | alias gs="git status" 12 | 13 | # Prefer neovim over vim 14 | alias vim="nvim" 15 | alias vi="nvim" 16 | 17 | -------------------------------------------------------------------------------- /.profile.d/credentials: -------------------------------------------------------------------------------- 1 | # prevent API throttling when installing/updating homebrew things 2 | export HOMEBREW_GITHUB_API_TOKEN=b6f7d4cc5dc941366f9f4f4f1d41c3dbb63645b6 3 | 4 | -------------------------------------------------------------------------------- /.profile.d/direnv: -------------------------------------------------------------------------------- 1 | # Setup direnv 2 | eval "$(direnv hook bash)" 3 | -------------------------------------------------------------------------------- /.profile.d/do_not_track: -------------------------------------------------------------------------------- 1 | # Various environment variables to disable tracking 2 | export DO_NOT_TRACK=1 3 | export MONGODB_ATLAS_TELEMETRY_ENABLED=false 4 | 5 | -------------------------------------------------------------------------------- /.profile.d/functions: -------------------------------------------------------------------------------- 1 | # tmux, be there and be named well 2 | function tms { 3 | local name=$(basename $PWD | sed -e s/\[^a-zA-Z0-9\\\//\$]/-/g -e s/--*/-/g) 4 | if [ -z "$TMUX" ]; then 5 | tmux new -s $name || tmux attach-session -t $name 6 | else 7 | tmux new-session -d -s $name -c $name && tmux switch-client -t $name 8 | fi 9 | } 10 | 11 | # Open conflicts at once, setting the search pattern to <<<<<<< in order to cycle through them pressing 'n' 12 | function editconflicts() { 13 | vim +/"<<<<<<<" `git diff --name-only --diff-filter=U | xargs` 14 | } 15 | 16 | # quickly cleanup cruft from docker machine 17 | function docker-cleanup() { 18 | docker rm `docker ps -a -q` 19 | docker rmi `docker images | grep "^ /dev/null 8 | 9 | # Key bindings 10 | source "$HOMEBREW_PREFIX/opt/fzf/shell/key-bindings.bash" 11 | 12 | # Configuration 13 | export FZF_DEFAULT_COMMAND="fd --hidden --type file --exclude .git --exclude .direnv --exclude node_modules --exclude .terraform" 14 | export FZF_DEFAULT_OPTS="--layout=reverse" 15 | export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" 16 | 17 | 18 | # bind "$(bind -s | grep '^"\\C-r"' | sed 's/"/"\\C-x/' | sed 's/"$/\\C-m"/')" 19 | 20 | -------------------------------------------------------------------------------- /.profile.d/golang: -------------------------------------------------------------------------------- 1 | export GOPATH="$HOME/Projects/Go" 2 | export GOBIN="$GOPATH/bin" 3 | 4 | -------------------------------------------------------------------------------- /.profile.d/google-cloud-sdk: -------------------------------------------------------------------------------- 1 | # Pin down google cloud sdk python executable 2 | export CLOUDSDK_PYTHON="$HOMEBREW_PREFIX/opt/python@3.8/libexec/bin/python" 3 | source "$HOMEBREW_PREFIX/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc" 4 | source "$HOMEBREW_PREFIX/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc" 5 | -------------------------------------------------------------------------------- /.profile.d/homebrew: -------------------------------------------------------------------------------- 1 | ## 2 | # Homebrew settings 3 | # Note: I am using a isolated user setup, no-one except that 'binary' user can write to the 4 | # Homebrew directories. 5 | if [[ "$(uname -p)" = "arm" ]]; then 6 | export HOMEBREW_PREFIX=/opt/homebrew 7 | else 8 | export HOMEBREW_PREFIX=/usr/local 9 | fi 10 | export HOMEBREW_NO_ANALYTICS=1 11 | export HOMEBREW_NO_INSECURE_REDIRECT=1 12 | export HOMEBREW_CASK_OPTS=--require-sha 13 | export HOMEBREW_CACHE=$HOMEBREW_PREFIX/Caches 14 | export HOMEBREW_LOGS=$HOMEBREW_PREFIX/Logs/Homebrew 15 | export HOMEBREW_NO_AUTO_UPDATE=1 16 | 17 | source "$HOMEBREW_PREFIX/etc/bash_completion" 18 | -------------------------------------------------------------------------------- /.profile.d/nodenv: -------------------------------------------------------------------------------- 1 | # nodenv 2 | export NODENV_ROOT="$HOMEBREW_PREFIX/nodenv" 3 | if test -x "$HOMEBREW_PREFIX/bin/nodenv"; then 4 | eval "$($HOMEBREW_PREFIX/bin/nodenv init -)" 5 | fi 6 | 7 | -------------------------------------------------------------------------------- /.profile.d/path: -------------------------------------------------------------------------------- 1 | # add brew binaries 2 | export PATH="$HOMEBREW_PREFIX/bin:$PATH" 3 | # add brew version of curl 4 | export PATH="$HOMEBREW_PREFIX/opt/curl/bin:$PATH" 5 | # add brew /usr/local/sbin 6 | export PATH="$HOMEBREW_PREFIX/sbin:$PATH" 7 | # add brew version of getop 8 | export PATH="$HOMEBREW_PREFIX/opt/gnu-getopt/bin:$PATH" 9 | # keep this last 10 | # local ~/.bin to overwrite anything on the machine 11 | export PATH="$HOME/.bin:$PATH" 12 | -------------------------------------------------------------------------------- /.profile.d/prompt: -------------------------------------------------------------------------------- 1 | # Setup a simple PROMPT/PS1 2 | export PROMPT_DIRTRIM=1 3 | if id -Gn | grep admin >/dev/null; then 4 | export ADMIN_PROMPT="\[\e[37;41m\]" 5 | else 6 | export ADMIN_PROMPT="" 7 | fi 8 | export PS1="\n${ADMIN_PROMPT}\W$\[\e[m\] " 9 | 10 | -------------------------------------------------------------------------------- /.profile.d/pyenv: -------------------------------------------------------------------------------- 1 | # pyenv 2 | export PYENV_ROOT="$HOMEBREW_PREFIX/pyenv" 3 | if test -x "$HOMEBREW_PREFIX/bin/pyenv"; then 4 | eval "$($HOMEBREW_PREFIX/bin/pyenv init --no-rehash -)" 5 | fi 6 | export PYENV_GLOBAL="$($HOMEBREW_PREFIX/bin/pyenv global)" 7 | 8 | -------------------------------------------------------------------------------- /.profile.d/rbenv: -------------------------------------------------------------------------------- 1 | # rbenv 2 | export RBENV_ROOT="$HOMEBREW_PREFIX/rbenv" 3 | if test -x "$HOMEBREW_PREFIX/rbenv/bin/rbenv"; then 4 | eval "$($HOMEBREW_PREFIX/rbenv/bin/rbenv init - bash)" 5 | # add rbenv path 6 | export PATH="$RBENV_ROOT/bin:$PATH" 7 | fi 8 | 9 | -------------------------------------------------------------------------------- /.profile.d/tfenv: -------------------------------------------------------------------------------- 1 | # tfenv 2 | export TFENV_AUTO_INSTALL=false 3 | export TFENV_INSTALL_DIR=$HOMEBREW_PREFIX/tfenv 4 | export PATH="$PATH:$TFENV_INSTALL_DIR/bin" 5 | -------------------------------------------------------------------------------- /.pryrc: -------------------------------------------------------------------------------- 1 | if defined?(PryByebug) 2 | Pry.commands.alias_command 'c', 'continue' 3 | Pry.commands.alias_command 's', 'step' 4 | Pry.commands.alias_command 'n', 'next' 5 | Pry.commands.alias_command 'f', 'finish' 6 | end 7 | -------------------------------------------------------------------------------- /.ssh/config: -------------------------------------------------------------------------------- 1 | Host * 2 | UseKeychain yes 3 | AddKeysToAgent yes 4 | IdentityFile ~/.ssh/id_ed25519 5 | -------------------------------------------------------------------------------- /.ssh/whatdropsnow-production.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Overbryd/dotfiles/e5ca721a56b59ff6794e380359a11ea8f94bb274/.ssh/whatdropsnow-production.pem -------------------------------------------------------------------------------- /.ssh/whatdropsnow-staging.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Overbryd/dotfiles/e5ca721a56b59ff6794e380359a11ea8f94bb274/.ssh/whatdropsnow-staging.pem -------------------------------------------------------------------------------- /.ssh/wooga_heroku_id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4JFlYk2FnslmAF//iWm/oTSh7eUGR4KXJIJD4urjTOfY+H6r2/nGcz7Ud64dv+z0Vf0UUbPywrF4w4aJPE5E3kjDPAZ3ZlXI5QEchuOowzIYFlqR+VuQPiMgFB5KOYoo/My7a9fycS8CsBb52PmmXcPbUGIhLAeJRZtEM8Ftd1nq2om1vde9VAdvgsoOgYJlSZpf6vXtbZ1ow4YVKUKCz5WTnnvI9Ukf6eafdoLajekv1zasAE7t4mqQWbVSlfvVv3Bjd1d6mzWBowDKDfF7OyWhC2nFNNOOOdQ1yC/5Xa6kPx4sbvWWBxApDsMcHIqjqYdpgj9Hi2kXdyWMn2h2N lukas@minitosh.local 2 | -------------------------------------------------------------------------------- /.tmux.conf: -------------------------------------------------------------------------------- 1 | # lively colors, because I am human 2 | set -g default-terminal 'screen-256color' 3 | set -sa terminal-overrides ',xterm-256color:RGB' 4 | 5 | # vim mode keys 6 | setw -g mode-keys vi 7 | 8 | # Vim style pane selection 9 | bind h select-pane -L 10 | bind j select-pane -D 11 | bind k select-pane -U 12 | bind l select-pane -R 13 | 14 | # mode mouse 15 | setw -g mouse on 16 | 17 | # monitor activity 18 | setw -g monitor-activity on 19 | 20 | # reattach to user namespace to enable mac osx clipboard 21 | # set-option -g default-command "reattach-to-user-namespace -l $SHELL" 22 | 23 | # set faster escape time (ms) 24 | set escape-time 150 25 | 26 | # setup proper select/copy 27 | # 'v' to begin selection as in Vim 28 | bind-key -T copy-mode-vi v send -X begin-selection 29 | bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel "pbcopy" 30 | # update default binding of `Enter` to also use copy-pipe 31 | unbind -T copy-mode-vi Enter 32 | bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel "pbcopy" 33 | 34 | # r to reload tmux conf 35 | bind r source-file ~/.tmux.conf \; display-message "Config reloaded." 36 | 37 | # standard splits 38 | bind - split-window -v 39 | 40 | # start window numbers at 1 to match keyboard order with tmux window order 41 | set -g base-index 1 42 | set-window-option -g pane-base-index 1 43 | 44 | # renumber windows sequentially after closing any of them 45 | set -g renumber-windows on 46 | 47 | # soften status bar color from harsh green to light gray 48 | set -g status-bg colour255 49 | set -g status-fg colour135 50 | 51 | # remove administrative debris (session name, hostname, time) in status bar 52 | set -g status-left '' 53 | set -g status-right '' 54 | 55 | # increase scrollback lines 56 | set -g history-limit 10000 57 | 58 | # enable focus events 59 | set-option -g focus-events on 60 | 61 | # Lets get a bell working (Alacritty does not support a bell) 62 | set -g monitor-bell on 63 | set -g bell-action other 64 | set-hook -g alert-bell 'run-shell "afplay ~/Music/click2.wav"' 65 | 66 | # Clear scrollback buffer using C-b C-k 67 | bind -n C-k clear-history 68 | 69 | -------------------------------------------------------------------------------- /.witchcraft/medium.com.js: -------------------------------------------------------------------------------- 1 | // @include redirect-to-12ft-io.js 2 | 3 | -------------------------------------------------------------------------------- /.witchcraft/realpython.com.js: -------------------------------------------------------------------------------- 1 | // Remove annoying modal from realpython.com 2 | document.addEventListener('DOMContentLoaded', (e) => { 3 | let body = document.querySelector('body'); 4 | setInterval(() => { 5 | document.querySelectorAll('.modal.fade.show, .modal-backdrop').forEach((e) => e.remove()); 6 | body.className = body.className.replace('modal-open', ''); 7 | }, 100); 8 | }); 9 | 10 | -------------------------------------------------------------------------------- /.witchcraft/redirect-to-12ft-io.js: -------------------------------------------------------------------------------- 1 | // redirects the current page to https://12ft.io/{href} 2 | 3 | location.replace(`https://12ft.io/${location.href}`); 4 | -------------------------------------------------------------------------------- /.witchcraft/theatlantic.com.js: -------------------------------------------------------------------------------- 1 | // @include redirect-to-12ft-io.js 2 | 3 | -------------------------------------------------------------------------------- /.witchcraft/www.berlinale.de.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', () => { 2 | 3 | // Hide screenings without tickets 4 | document.querySelectorAll('section.film-entry section.screening').forEach((section) => { 5 | Array.from(section.querySelectorAll('div.row')) 6 | .every(row => row.querySelector('a.ticket--active') === null) && (section.style.display = 'none') 7 | }); 8 | 9 | // Hide films without tickets 10 | document.querySelectorAll('section.film-entry').forEach((filmEntry) => { 11 | Array.from(filmEntry.querySelectorAll('section.screening div.row')) 12 | .every(row => row.querySelector('a.ticket--active') === null) && (filmEntry.style.display = 'none') 13 | }); 14 | 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /Caddyfile: -------------------------------------------------------------------------------- 1 | { 2 | admin off 3 | persist_config off 4 | } 5 | 6 | :5743 { 7 | file_server { 8 | root /Users/partenkirchen/dotfiles/.witchcraft 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /LaunchAgents/com.overbryd.caddy.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | KeepAlive 6 | 7 | Label 8 | com.overbryd.caddy 9 | LimitLoadToSessionType 10 | 11 | Aqua 12 | Background 13 | LoginWindow 14 | StandardIO 15 | System 16 | 17 | ProgramArguments 18 | 19 | /opt/homebrew/opt/caddy/bin/caddy 20 | run 21 | --watch 22 | --config 23 | /Users/partenkirchen/dotfiles/Caddyfile 24 | 25 | RunAtLoad 26 | 27 | StandardErrorPath 28 | /tmp/caddy.log 29 | StandardOutPath 30 | /tmp/caddy.log 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EXCLUDED_DOTFILES := .git .git-crypt .gitattributes .gitignore .gitmodules .ssh 2 | DOTFILES := $(addprefix ~/, $(filter-out $(EXCLUDED_DOTFILES), $(wildcard .*))) 3 | DOT_CONFIG_FILES := $(addprefix ~/, $(wildcard .config/*)) 4 | LAUNCH_AGENTS := $(addprefix ~/Library/, $(wildcard LaunchAgents/*)) 5 | 6 | DOTFILES_ROOT = $(HOME)/dotfiles 7 | BREW = $(DOTFILES_ROOT)/.bin/brew 8 | 9 | # execute all commands per task in one shell, allowing for environment variables to be set for 10 | # all following commands. 11 | .ONESHELL: 12 | 13 | # bootstrap the administrative account 14 | bootstrap-administrator: \ 15 | bootstrap-user \ 16 | bootstrap-binary-user \ 17 | bootstrap-homebrew-folder \ 18 | brew \ 19 | bash \ 20 | defaults-administrator \ 21 | defaults \ 22 | harder 23 | 24 | # bootstrap after reset, this is required because files at root "/" are overwritten by macos updates 25 | # from time to time 26 | bootstrap-administrator-after-reset: \ 27 | bootstrap-binary-user \ 28 | bash 29 | 30 | # bootstrap only, add one-time bootstrap tasks here 31 | # setups the necessary stuff 32 | # restore .gnupg to decrypt the secrets from this repository 33 | # setup ssh config (relies on decrypted repository) 34 | bootstrap: \ 35 | dotfiles \ 36 | ~/.gnupg \ 37 | ~/.ssh/config \ 38 | defaults 39 | 40 | # bootstrap a daily driver user, low privileged that is used to run the computer with. 41 | bootstrap-user: 42 | id partenkirchen || sudo .bin/macos-add-user partenkirchen 43 | 44 | # Bootstrap a system user + group that is used to protect executable paths in $PATH. 45 | # Any directory in $PATH should not be writable by normal user. 46 | # The normal user however can execute binaries from that PATH. 47 | # Test with `$ audit-path-writable` 48 | bootstrap-binary-user: 49 | id binary || sudo .bin/macos-add-system-user binary 50 | sudo grep '_binary ALL = NOPASSWD:SETENV' /etc/sudoers || echo '_binary ALL = NOPASSWD:SETENV: /bin/cp -pR $(HOMEBREW_PREFIX)/Caskroom/* /Applications/*,/bin/cp -pR $(HOMEBREW_PREFIX)/Caskroom/* /Library/Fonts/*,/usr/sbin/installer -pkg $(HOMEBREW_PREFIX)/Caskroom/* -target /,/bin/rm -f -- /Library/Fonts/*' | EDITOR='tee -a' VISUAL=$$EDITOR sudo -E visudo 51 | sudo grep '_binary ALL = (_binary) NOPASSWD:SETENV: ALL' /etc/sudoers || echo '_binary ALL = (_binary) NOPASSWD:SETENV: ALL' | EDITOR='tee -a' VISUAL=$$EDITOR sudo -E visudo 52 | 53 | bootstrap-homebrew-folder: 54 | test -d $(HOMEBREW_PREFIX) || sudo mkdir $(HOMEBREW_PREFIX) 55 | sudo chown -R binary:binary $(HOMEBREW_PREFIX) 56 | sudo chmod -R g+w $(HOMEBREW_PREFIX) 57 | sudo chmod +a "group:_binary allow list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,directory_inherit" $(HOMEBREW_PREFIX) 58 | 59 | brew-itself: $(HOMEBREW_PREFIX)/bin/brew 60 | brew: \ 61 | brew-itself \ 62 | brew-upgrade 63 | 64 | $(HOMEBREW_PREFIX)/bin/brew: 65 | $(BREW) doctor 2>&1 >/dev/null || sudo -Eubinary /bin/bash -c "curl --proto '=https' --tlsv1.2 -fsSL https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C $(HOMEBREW_PREFIX)" 66 | $(BREW) analytics off 67 | 68 | brew-upgrade: brew-itself 69 | # upgrade all installed packages 70 | $(BREW) upgrade 71 | 72 | brew-baseline: brew-itself 73 | @$(BREW) update 74 | # GNU coreutils instead of outdated mac os defaults 75 | -$(BREW) install coreutils moreutils 76 | # newer version of git 77 | $(BREW) install git 78 | # git-crypt for encrypted repository contents 79 | $(BREW) install git-crypt 80 | # install ripgrep, currently the fasted grep alternative 81 | $(BREW) install ripgrep 82 | # tree, a nice directory tree listing 83 | $(BREW) install tree 84 | # install readline, useful in combination with ruby-build because it will link ruby installations to it 85 | $(BREW) install readline 86 | # install direnv for project specific .envrc support 87 | $(BREW) install direnv 88 | # pipeviewer allows to display throughput/eta information on unix pipes 89 | $(BREW) install pv 90 | # pstree is nice to look at 91 | $(BREW) install pstree 92 | # watch is great for building an overview on running stuff 93 | $(BREW) install watch 94 | # sed, stream editor, but replace mac os version 95 | $(BREW) install gnu-sed 96 | # handle json on the command line 97 | $(BREW) install jq --HEAD 98 | # fswatch allows you to stream file changes to a unix pipe, handy for rerunning tests 99 | $(BREW) install fswatch 100 | 101 | brew-work: \ 102 | brew-programming \ 103 | brew-devops \ 104 | brew-nettools 105 | @$(BREW) update 106 | # tableplus is my preferred SQL-client 107 | $(BREW) install --cask tableplus 108 | # Alacritty is a better terminal emulator 109 | $(BREW) install --cask alacritty 110 | 111 | brew-programming: brew-itself 112 | @$(BREW) update 113 | # erlang programming language 114 | $(BREW) install erlang 115 | # elixir programming language 116 | $(BREW) install elixir elixir-ls 117 | # install and manage ruby versions 118 | $(BREW) install ruby-install 119 | # install pyenv to manage python versions 120 | $(BREW) install pyenv 121 | # gum is helpful for scripting https://github.com/charmbracelet/gum 122 | $(BREW) install gum 123 | 124 | brew-devops: casks-itself 125 | @$(BREW) update 126 | # handle amazon web services related stuff 127 | $(BREW) install awscli 128 | $(BREW) install aws-iam-authenticator 129 | # tail cloudwatch logs (e.g. from Fargate containers) 130 | $(BREW) tap TylerBrock/saw 131 | $(BREW) install saw 132 | # handle google cloud related stuff 133 | $(BREW) install python@3.8 134 | HOME=$(HOMEBREW_PREFIX) $(BREW) install --cask google-cloud-sdk 135 | # Google, you are fucking kidding me 136 | # gcloud config set disable_usage_reporting false 137 | # gcloud config set survey/disable_prompts True 138 | # neat way to expose a locally running service 139 | $(BREW) install cloudflared 140 | # smartmontools great for monitoring disks 141 | $(BREW) install smartmontools 142 | # I need to control kubernetes clusters 143 | $(BREW) install kubernetes-cli 144 | kubectl completion bash > $$HOME/.completion.d/kubectl 145 | # Terraform, this is what makes the money 146 | $(BREW) install terraform-ls terraform-docs 147 | # Kops is an alternative to EKS clusters (I no longer prefer) 148 | $(BREW) install kops 149 | # Helm is this crappy tool to template yaml files for Kubernetes (I no longer like) 150 | $(BREW) install helm 151 | 152 | brew-nettools: brew-itself 153 | @$(BREW) update 154 | # nmap is great for test and probing network related stuff 155 | $(BREW) install nmap 156 | # curl is a http development essential 157 | $(BREW) install curl 158 | # websocket client 159 | $(BREW) install websocat 160 | # vegeta is an insanely great http load tester and scalable http-client 161 | $(BREW) install vegeta 162 | # caddy is an outstanding web server 163 | $(BREW) install caddy 164 | # ipcalc helps with network planning 165 | $(BREW) install ipcalc 166 | 167 | brew-fzf: brew-itself 168 | @$(BREW) update 169 | # fd is a alternative find command 170 | $(BREW) install fd 171 | # fzf is a fuzzy file finder 172 | $(BREW) install fzf 173 | $(HOMEBREW_PREFIX)/opt/fzf/install --key-bindings --completion --no-update-rc --no-zsh --no-fish 174 | 175 | mas-itself: brew-itself 176 | $(BREW) install mas 177 | 178 | mas-baseline: mas-itself 179 | # Keynote 180 | mas install 409183694 181 | # Numbers 182 | mas install 409203825 183 | # Pages 184 | mas install 409201541 185 | # Pixelmator Pro 186 | mas install 1289583905 187 | # Wireguard VPN Client 188 | mas install 1451685025 189 | # Spark E-Mail 190 | mas install 1176895641 191 | # 1Password password manager 192 | mas install 1333542190 193 | 194 | mas-work: mas-itself 195 | # Slack 196 | mas install 803453959 197 | # Apple Remote Desktop 198 | mas install 409907375 199 | 200 | casks-itself: brew-itself 201 | # tap homebrew-cask to install other osx related stuff 202 | $(BREW) tap homebrew/cask 203 | 204 | casks: \ 205 | casks-itself \ 206 | casks-baseline 207 | 208 | casks-baseline: casks-itself 209 | @$(BREW) update 210 | # phoenix is a scriptable window management/tiling system 211 | $(BREW) install --cask phoenix 212 | # spectacle for mac osx window management/tiling 213 | $(BREW) install --cask spectacle 214 | # vivaldi for browsing the web 215 | $(BREW) install --cask vivaldi 216 | # 1password is my password manager 217 | $(BREW) install --cask 1password-cli 218 | # gpg-suite provide me with all gpp related things 219 | $(BREW) install --cask gpg-suite 220 | # Flux reduces blue/green colors on the display spectrum and helps me sleep better 221 | $(BREW) install --cask flux 222 | # launchbar is my preferred app launcher/clipboard history, calculator and goto mac utility 223 | $(BREW) install --cask launchbar 224 | # appcleaner removed macOS applications and their cruft 225 | $(BREW) install --cask appcleaner 226 | # Carbon Copy Cloner is my backup tool of choice 227 | $(BREW) install --cask carbon-copy-cloner 228 | # dropbox synchronised files across devices 229 | HOMEBREW_CASK_OPTS=$${HOMEBREW_CASK_OPTS#--require-sha} $(BREW) install --cask dropbox 230 | 231 | casks-work: casks-itself 232 | @$(BREW) update 233 | # tableplus is the best graphical multi-database client 234 | $(BREW) install --cask tableplus 235 | 236 | fonts: \ 237 | casks-itself 238 | # tap homebrew-fonts to install freely available fonts 239 | $(BREW) tap homebrew/cask-fonts 240 | # install IBM Plex, an excellent modern font (https://www.ibm.com/plex/) 241 | $(BREW) install --fontdir /Library/Fonts --cask font-ibm-plex 242 | # install Adobe Source Code Pro, an excellent mono space font for programming 243 | HOMEBREW_CASK_OPTS=$${HOMEBREW_CASK_OPTS#--require-sha} $(BREW) install --fontdir /Library/Fonts --cask font-source-code-pro 244 | 245 | bash: brew-itself 246 | @$(BREW) update 247 | # newer version of bash 248 | $(BREW) install bash 249 | $(BREW) install bash-completion 250 | # change shell to homebrew bash 251 | grep $(HOMEBREW_PREFIX)/bin/bash /etc/shells || (echo "$(HOMEBREW_PREFIX)/bin/bash" | sudo tee -a /etc/shells) 252 | test "$$SHELL" = $(HOMEBREW_PREFIX)/bin/bash || chsh -s $(HOMEBREW_PREFIX)/bin/bash 253 | 254 | ruby: \ 255 | $(HOMEBREW_PREFIX)/rbenv \ 256 | $(HOMEBREW_PREFIX)/rbenv/plugins/ruby-build \ 257 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-update \ 258 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-readline \ 259 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-gemset 260 | $(BREW) install libyaml 261 | TMPDIR=/tmp sudo -Eu binary $(HOMEBREW_PREFIX)/rbenv/bin/rbenv install 3.2.2 262 | TMPDIR=/tmp sudo -Eu binary $(HOMEBREW_PREFIX)/rbenv/bin/rbenv global 3.2.2 263 | 264 | # rbenv is an amazing ruby version manager, simple, straightforward, local 265 | $(HOMEBREW_PREFIX)/rbenv: 266 | test -d $(HOMEBREW_PREFIX)/rbenv || sudo -Eu binary git clone https://github.com/rbenv/rbenv.git $(HOMEBREW_PREFIX)/rbenv 267 | cd $(HOMEBREW_PREFIX)/rbenv && sudo -Eu binary git pull && sudo -Eu binary src/configure && sudo -Eu binary make -C src 268 | 269 | # ruby-build is a repository hosting all kinds of ruby versions to install 270 | $(HOMEBREW_PREFIX)/rbenv/plugins/ruby-build: 271 | sudo -Eu binary git clone https://github.com/rbenv/ruby-build.git $(HOMEBREW_PREFIX)/rbenv/plugins/ruby-build 272 | 273 | # rbenv-update allows updating rbenv plugins easily 274 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-update: 275 | sudo -Eu binary git clone https://github.com/rkh/rbenv-update.git $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-update 276 | 277 | # rbenv-readline does the right thing when it comes to linking a brew installed readline to ruby 278 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-readline: 279 | sudo -Eu binary git clone https://github.com/tpope/rbenv-readline.git $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-readline 280 | 281 | # rbenv-gemset allows managing project specific set of gems 282 | $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-gemset: 283 | sudo -Eu binary git clone https://github.com/jf/rbenv-gemset.git $(HOMEBREW_PREFIX)/rbenv/plugins/rbenv-gemset 284 | 285 | python: 286 | TMPDIR=/tmp sudo -Eubinary pyenv install --skip-existing 3.11.6 287 | TMPDIR=/tmp sudo -Eubinary pyenv global 3.11.6 288 | TMPDIR=/tmp sudo -Eubinary pip install --upgrade pip 289 | TMPDIR=/tmp sudo -Eubinary pip install neovim 290 | 291 | node: \ 292 | $(HOMEBREW_PREFIX)/nodenv 293 | cd $(HOMEBREW_PREFIX) 294 | TMPDIR=/tmp NODENV_ROOT=$(HOMEBREW_PREFIX)/nodenv sudo -Eubinary nodenv install 20.8.1 295 | TMPDIR=/tmp NODENV_ROOT=$(HOMEBREW_PREFIX)/nodenv sudo -Eubinary nodenv global 20.8.1 296 | 297 | $(HOMEBREW_PREFIX)/nodenv: 298 | $(BREW) install nodenv node-build 299 | NODENV_ROOT=$(HOMEBREW_PREFIX)/nodenv sudo -Eubinary nodenv init - > /dev/null 300 | 301 | terraform: \ 302 | $(HOMEBREW_PREFIX)/tfenv 303 | sudo -Eubinary $(HOMEBREW_PREFIX)/bin/tfenv install latest 304 | sudo -Eubinary $(HOMEBREW_PREFIX)/bin/tfenv use latest 305 | 306 | $(HOMEBREW_PREFIX)/tfenv: 307 | $(BREW) install tfenv 308 | sudo -Eubinary mkdir $(HOMEBREW_PREFIX)/tfenv 309 | 310 | nvim: \ 311 | nvim-itself \ 312 | nvim-user 313 | 314 | nvim-user: \ 315 | nvim-directories \ 316 | ~/.config/nvim \ 317 | nvim-plugins 318 | 319 | nvim-directories: 320 | # create nvim directories 321 | mkdir -p ~/.nvim/tmp/{backup,swap,undo} 322 | chmod go= ~/.nvim/tmp{,/*} 323 | 324 | nvim-itself: python 325 | $(BREW) install nvim 326 | TMPDIR=/tmp sudo -Eubinary pip install pynvim 327 | 328 | nvim-coc-install: nvim-plugins 329 | nvim -c 'CocInstall -sync coc-just-complete coc-pairs coc-tsserver coc-json coc-html coc-css coc-pyright coc-docker coc-erlang_ls coc-fzf-preview coc-go coc-html coc-svelte coc-yaml coc-elixir coc-terraform coc-snippets | qa' 330 | 331 | nvim-plugins: 332 | nvim -c 'PlugInstall | qa' 333 | nvim -c 'PlugClean | qa' 334 | 335 | tmux: \ 336 | ~/.tmux.conf 337 | $(BREW) install tmux 338 | $(BREW) install reattach-to-user-namespace 339 | 340 | # See also: https://macos-defaults.com 341 | defaults: \ 342 | defaults-Trackpad \ 343 | defaults-Terminal \ 344 | defaults-Dock \ 345 | defaults-NSGlobalDomain \ 346 | defaults-Calendar \ 347 | defaults-Menubar \ 348 | defaults-LaunchAgents \ 349 | # Show remaining battery time; hide percentage 350 | defaults write com.apple.menuextra.battery ShowPercent -string "NO" 351 | defaults write com.apple.menuextra.battery ShowTime -string "YES" 352 | # Enable AirDrop over Ethernet and on unsupported Macs running Lion 353 | defaults write com.apple.NetworkBrowser BrowseAllInterfaces -bool true 354 | # Automatically open a new Finder window when a volume is mounted 355 | defaults write com.apple.frameworks.diskimages auto-open-ro-root -bool true 356 | defaults write com.apple.frameworks.diskimages auto-open-rw-root -bool true 357 | # Avoid creating .DS_Store files on network volumes 358 | defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true 359 | # Disable the warning when changing a file extension 360 | defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false 361 | # Automatically quit printer app once the print jobs complete 362 | defaults write com.apple.print.PrintingPrefs "Quit When Finished" -bool true 363 | # Check for software updates daily, not just once per week 364 | defaults write com.apple.SoftwareUpdate ScheduleFrequency -int 1 365 | # Automatically illuminate built-in MacBook keyboard in low light 366 | defaults write com.apple.BezelServices kDim -bool true 367 | # Turn off keyboard illumination when computer is not used for 5 minutes 368 | defaults write com.apple.BezelServices kDimTime -int 300 369 | # Save screenshots to the desktop 370 | defaults write com.apple.screencapture location -string "${HOME}/Desktop" 371 | # Disable shadow in screenshots 372 | defaults write com.apple.screencapture disable-shadow -bool true 373 | # Save screenshots in PNG format (other options: BMP, GIF, JPG, PDF, TIFF) 374 | defaults write com.apple.screencapture type -string "png" 375 | # Hide all desktop icons because who needs them, I certainly don't 376 | defaults write com.apple.finder CreateDesktop -bool false 377 | # Finder: disable window animations and Get Info animations 378 | defaults write com.apple.finder DisableAllAnimations -bool true 379 | # Finder: show hidden files by default 380 | defaults write com.apple.Finder AppleShowAllFiles -bool true 381 | # Finder: show path bar 382 | defaults write com.apple.finder ShowPathbar -bool true 383 | # Empty Trash securely by default 384 | defaults write com.apple.finder EmptyTrashSecurely -bool false 385 | # Require password after 5 seconds on sleep or screen saver begins 386 | defaults write com.apple.screensaver askForPassword -int 1 387 | defaults write com.apple.screensaver askForPasswordDelay -int 5 388 | # Disable Game Center 389 | defaults write com.apple.gamed Disabled -bool true 390 | # Show the ~/Library folder 391 | chflags nohidden ~/Library 392 | # Keep this bit last 393 | # Kill affected applications 394 | for app in Safari Finder Mail SystemUIServer; do killall "$$app" >/dev/null 2>&1; done 395 | # Re-enable subpixel aliases that got disabled by default in Mojave 396 | # defaults write -g CGFontRenderingFontSmoothingDisabled -bool false 397 | 398 | defaults-administrator: 399 | # disable apple captive portal (security issue) 400 | # sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.captive.control Active -bool false 401 | # Enable HiDPI display modes (requires restart) 402 | sudo defaults write /Library/Preferences/com.apple.windowserver DisplayResolutionEnabled -bool true 403 | 404 | defaults-Dock: 405 | # Enable the 2D Dock 406 | defaults write com.apple.dock no-glass -bool true 407 | # Automatically hide and show the Dock 408 | defaults write com.apple.dock autohide -bool true 409 | # Make Dock icons of hidden applications translucent 410 | defaults write com.apple.dock showhidden -bool true 411 | # Enable highlight hover effect for the grid view of a stack (Dock) 412 | defaults write com.apple.dock mouse-over-hilte-stack -bool true 413 | # Enable spring loading for all Dock items 414 | defaults write enable-spring-load-actions-on-all-items -bool true 415 | # Show indicator lights for open applications in the Dock 416 | defaults write com.apple.dock show-process-indicators -bool true 417 | # Don’t animate opening applications from the Dock 418 | defaults write com.apple.dock launchanim -bool false 419 | # clean up right side (persistent) 420 | -defaults delete com.apple.dock persistent-others 421 | # and add these folders 422 | defaults write com.apple.dock persistent-others -array-add "$$(echo '{"tile-type": "directory-tile", "tile-data": {"displayas": 0, "file-type":2, "showas":1, "file-label":"Dropbox", "file-data":{"_CFURLString":"file:///Users/$(USER)/Library/CloudStorage/Dropbox","_CFURLStringType":15}}}' | plutil -convert xml1 - -o -)"; 423 | defaults write com.apple.dock persistent-others -array-add "$$(echo '{"tile-type": "directory-tile", "tile-data": {"displayas": 0, "file-type":2, "showas":1, "file-label":"Desktop", "file-data":{"_CFURLString":"file:///Users/$(USER)/Desktop/","_CFURLStringType":15}}}' | plutil -convert xml1 - -o -)"; 424 | defaults write com.apple.dock persistent-others -array-add "$$(echo '{"tile-type": "directory-tile", "tile-data": {"displayas": 0, "file-type":2, "showas":1, "file-label":"Downloads", "file-data":{"_CFURLString":"file:///Users/$(USER)/Downloads/","_CFURLStringType":15}}}' | plutil -convert xml1 - -o -)"; 425 | # restart dock 426 | killall Dock 427 | 428 | defaults-NSGlobalDomain: 429 | # Locale 430 | defaults write NSGlobalDomain AppleLocale -string "en_US" 431 | defaults write NSGlobalDomain AppleMeasurementUnits -string "Centimeters" 432 | defaults write NSGlobalDomain AppleMetricUnits -bool true 433 | # 24-Hour Time 434 | defaults write NSGlobalDomain AppleICUForce12HourTime -bool false 435 | # Enable full keyboard access for all controls (e.g. enable Tab in modal dialogs) 436 | defaults write NSGlobalDomain AppleKeyboardUIMode -int 3 437 | # Enable subpixel font rendering on non-Apple LCDs 438 | defaults write NSGlobalDomain AppleFontSmoothing -int 2 439 | # Disable menu bar transparency 440 | defaults write NSGlobalDomain AppleEnableMenuBarTransparency -bool false 441 | # Enable press-and-hold for keys 442 | defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 443 | # Set a blazingly fast keyboard repeat rate (1 = fastest for macOS high sierra, older versions support 0) 444 | defaults write NSGlobalDomain KeyRepeat -int 2 445 | # Decrase the time to initially trigger key repeat 446 | defaults write NSGlobalDomain InitialKeyRepeat -int 15 447 | # Enable auto-correct 448 | defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool true 449 | # Disable window animations 450 | defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false 451 | # Increase window resize speed for Cocoa applications 452 | defaults write NSGlobalDomain NSWindowResizeTime -float 0.001 453 | # Save to disk (not to iCloud) by default 454 | defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false 455 | # Disable smart quotes as they’re annoying when typing code 456 | defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false 457 | # Disable smart dashes as they’re annoying when typing code 458 | defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false 459 | # Finder: show all filename extensions 460 | defaults write NSGlobalDomain AppleShowAllExtensions -bool true 461 | 462 | defaults-Trackpad: 463 | # Trackpad: enable tap to click for this user and for the login screen 464 | defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 465 | defaults write NSGlobalDomain com.apple.trackpad.tapBehavior -int 1 466 | # Enable three-finger dragging 467 | defaults write NSGlobalDomain com.apple.driver.AppleBluetoothMultitouch.trackpad.TrackpadThreeFingerDrag -int 1 468 | # Make the trackpad fast 469 | defaults write NSGlobalDomain com.apple.mouse.scaling -float 10.0 470 | defaults write NSGlobalDomain com.apple.trackpad.scaling -float 10.0 471 | 472 | defaults-Calendar: 473 | # Show week numbers (10.8 only) 474 | defaults write com.apple.iCal "Show Week Numbers" -bool true 475 | # Show 7 days 476 | defaults write com.apple.iCal "n days of week" -int 7 477 | # Week starts on monday 478 | defaults write com.apple.iCal "first day of week" -int 1 479 | # Show event times 480 | defaults write com.apple.iCal "Show time in Month View" -bool true 481 | 482 | defaults-Terminal: 483 | # Only use UTF-8 in Terminal.app 484 | defaults write com.apple.terminal StringEncodings -array 4 485 | # Set the default shell 486 | defaults write com.apple.terminal Shell -string "$(HOMEBREW_PREFIX)/bin/bash" 487 | # Open new windows with our own Theme 488 | plutil -replace "Window Settings"."Pro-gramming" -xml "$$(cat Pro-gramming.terminal)" ~/Library/Preferences/com.apple.Terminal.plist 489 | defaults write com.apple.Terminal "Default Window Settings" -string "Pro-gramming" 490 | defaults write com.apple.Terminal "Startup Window Settings" -string "Pro-gramming" 491 | 492 | defaults-Menubar: 493 | # I want my menubar to look like this 494 | defaults write com.apple.systemuiserver menuExtras -array \ 495 | "/System/Library/CoreServices/Menu Extras/AirPort.menu" \ 496 | "/System/Library/CoreServices/Menu Extras/Bluetooth.menu" \ 497 | "/System/Library/CoreServices/Menu Extras/Clock.menu" \ 498 | "/System/Library/CoreServices/Menu Extras/Displays.menu" \ 499 | "/System/Library/CoreServices/Menu Extras/Volume.menu" 500 | # I want the datetime display in my menubar to look like this 501 | defaults write com.apple.menuextra.clock DateFormat -string "EEE d MMM HH:mm" 502 | killall SystemUIServer 503 | 504 | defaults-LaunchAgents: \ 505 | $(LAUNCH_AGENTS) 506 | 507 | ~/Library/LaunchAgents/%: 508 | cp -v ~/dotfiles/LaunchAgents/$(notdir $@) $@ 509 | launchctl load -w $@ 510 | 511 | dotfiles: 512 | dotfiles: \ 513 | ~/dotfiles \ 514 | $(DOTFILES) \ 515 | $(DOT_CONFIG_FILES) 516 | 517 | ~/dotfiles: 518 | ln -s /usr/local/dotfiles ~/dotfiles 519 | 520 | ~/.ssh/config: 521 | # Copy a default .ssh/config 522 | grep "Host *" ~/.ssh/config || cp $(DOTFILES_ROOT)/.ssh/config ~/.ssh/config 523 | 524 | ~/.gnupg: 525 | # Ask where to get .gnupg from 526 | @read -p "Where is .gnupg (from backup) located?" gnupg_source; 527 | cp -v $$gnupg_source ~/.gnupg 528 | 529 | ~/.config/%: ~/.config 530 | cd ~ && test -h $(DOTFILES_ROOT)/.config$(notdir $@) || ln -svf $(DOTFILES_ROOT)/.config/$(notdir $@) .config/$(notdir $@) 531 | 532 | ~/.config: 533 | mkdir ~/.config 534 | 535 | ~/.%: 536 | cd ~ && ln -svf $(DOTFILES_ROOT)/$(notdir $@) $@ 537 | 538 | docker: 539 | # Run colima as administrator after install to setup the network. 540 | # Works for low privileged users afterwards. 541 | # $ colima start --cpu 4 --memory 4 --disk 50 --mount-type=virtiofs --network-address 542 | # $ colima stop 543 | $(BREW) install colima 544 | $(BREW) install docker docker-completion 545 | 546 | # Here is a comprehensive guide: https://github.com/drduh/macOS-Security-and-Privacy-Guide 547 | # The following settings implement some basic security measures 548 | harder: \ 549 | harder-common \ 550 | harder-filevault 551 | # harder-firewall \ 552 | 553 | harder-common: 554 | # Enable secure keyboard entry for Terminal 555 | defaults write com.apple.terminal SecureKeyboardEntry -bool true 556 | # Require a firmware password to change boot disk (mode full requires a firmware password on all startups) 557 | # sudo firmwarepasswd -setpasswd -setmode command 558 | # Enable touch id for sudo (if available) 559 | # sudo .bin/macos-enable-sudo-pam_tid 560 | 561 | harder-filevault: 562 | # Enable FileVault (requires restart) 563 | (fdesetup status | grep "FileVault is On") || (sudo fdesetup enable && sudo fdesetup add -usertoadd partenkirchen && read -p "Please note down the FileVault recovery key. Ready to restart?" noop && sudo shutdown -r +1 "Restarting in 1 minute... FileVault setup requires a restart") 564 | 565 | harder-firewall: 566 | # Enable the firewall 567 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on 568 | # Block all incoming connections 569 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setblockall on 570 | # Enable logging on the firewall 571 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on 572 | # Enable stealth mode (computer does not respond to PING or TCP connections on closed ports) 573 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on 574 | # Prevent built-in software as well as code-signed, downloaded software from being whitelisted automatically 575 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsigned off 576 | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsignedapp off 577 | ## 578 | # Restart the firewall (this should remain last) 579 | sudo pkill -HUP socketfilterfw 580 | 581 | -------------------------------------------------------------------------------- /Pro-gramming.terminal: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BackgroundBlur 6 | 1 7 | BackgroundColor 8 | 9 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 10 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxAREldO 11 | U1doaXRlXE5TQ29sb3JTcGFjZVYkY2xhc3NGMCAwLjgAEAOAAtIUFRYXWiRjbGFzc25h 12 | bWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kbHmAh4mL 13 | kJukrK8AAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAAuA== 14 | 15 | CursorColor 16 | 17 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 18 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxAREldO 19 | U1doaXRlXE5TQ29sb3JTcGFjZVYkY2xhc3NLMC4zMDI0MTkzNgAQA4AC0hQVFhdaJGNs 20 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRs 21 | eYCMjpCVoKmxtAAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAAAAAAAAC9 22 | 23 | Font 24 | 25 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 26 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwVFlUkbnVsbNQNDg8QERIT 27 | FFZOU1NpemVYTlNmRmxhZ3NWTlNOYW1lViRjbGFzcyNAKAAAAAAAABAQgAKAA18QEElC 28 | TVBsZXhNb25vLVRleHTSFxgZGlokY2xhc3NuYW1lWCRjbGFzc2VzVk5TRm9udKIZG1hO 29 | U09iamVjdAgRGiQpMjdJTFFTWF5nbnd+hY6QkpSnrLfAx8oAAAAAAAABAQAAAAAAAAAc 30 | AAAAAAAAAAAAAAAAAAAA0w== 31 | 32 | FontAntialias 33 | 34 | FontWidthSpacing 35 | 1 36 | ProfileCurrentVersion 37 | 2.0699999999999998 38 | SelectionColor 39 | 40 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 41 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxAREldO 42 | U1doaXRlXE5TQ29sb3JTcGFjZVYkY2xhc3NLMC4yNTQwMzIyNQAQA4AC0hQVFhdaJGNs 43 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRs 44 | eYCMjpCVoKmxtAAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAAAAAAAAC9 45 | 46 | ShowWindowSettingsNameInTitle 47 | 48 | TextBoldColor 49 | 50 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 51 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxAREldO 52 | U1doaXRlXE5TQ29sb3JTcGFjZVYkY2xhc3NCMQAQA4AC0hQVFhdaJGNsYXNzbmFtZVgk 53 | Y2xhc3Nlc1dOU0NvbG9yohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRseYCDhYeMl6Co 54 | qwAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAAAAAAAAC0 55 | 56 | TextColor 57 | 58 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS 59 | AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxAREldO 60 | U1doaXRlXE5TQ29sb3JTcGFjZVYkY2xhc3NLMC45NDc1ODA2NAAQA4AC0hQVFhdaJGNs 61 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRs 62 | eYCMjpCVoKmxtAAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAAAAAAAAC9 63 | 64 | name 65 | Pro-gramming 66 | shellExitAction 67 | 2 68 | type 69 | Window Settings 70 | 71 | 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overbryd's dotfiles 2 | 3 | ## Bootstrap 4 | 5 | On a new mac, open a Terminal and run: 6 | 7 | curl --proto '=https' --tlsv1.2 -sSf -O https://raw.githubusercontent.com/Overbryd/dotfiles/master/bootstrap.sh 8 | chmod +x bootstrap.sh 9 | ./bootstrap.sh 10 | 11 | ## Maintenance 12 | 13 | Enter the `~/dotfiles` directory, make changes and `make` it: 14 | 15 | cd ~/dotfiles 16 | make 17 | 18 | The Makefile contains sections for installing \*nix command line utilities, macOS applications, macOS settings and maintaing specific configurations. 19 | 20 | So you can also only re-make a section of the project, for example the macOS dock settings: 21 | 22 | cd ~/dotfiles 23 | make defaults-Dock 24 | 25 | Or only rebuild your vim: 26 | 27 | cd ~/dotfiles 28 | make vim 29 | 30 | Or upgrade all installed packages: 31 | 32 | cd ~/dotfiles 33 | make brew 34 | 35 | ## Contents 36 | 37 | . 38 | ├── Makefile # This makefile controls all sections of this project 39 | ├── bootstrap.sh # 0-100 bootstrap script for a new freshly installed Mac 40 | ├── .gitattributes # 41 | ├── .gitconfig # colorful git config, including aliases 42 | ├── .gitignore # general gitignore 43 | ├── .inputrc # great for navigating bash history 44 | ├── .profile # the complete bash setup with comments 45 | ├── .vimrc # a great .vimrc with comments 46 | ├── decrypt.sh # decrypt sensitive files and put them in place 47 | └── encrypt.sh # simple wrapper to encrypt sensitive files for storage 48 | 49 | ## Credits 50 | 51 | This seletion of dotfiles and system settings would not be possible without the great examples provided by: 52 | 53 | * https://github.com/mathiasbynens/dotfiles 54 | * https://github.com/matijs/dotfiles 55 | * https://github.com/paulirish/dotfiles 56 | * https://github.com/why-jay/osx-init 57 | * https://github.com/simonmcc/osx-bootstrap/blob/master/osx-user-defaults.sh 58 | * http://dotfiles.github.io 59 | * https://www.stackoverflow.com/ :) 60 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if !(id -Gn $(id -un) | grep -qw admin); then 4 | echo "This must be executed by an administrative user on the system." 5 | exit 1 6 | fi 7 | 8 | # Set a hostname for the computer 9 | hostname="$(scutil --get ComputerName)" 10 | echo "Current hostname: $(scutil --get LocalHostName) and computer name: $hostname" 11 | read -p "Enter a hostname (default: $hostname): " -r hostname 12 | if [[ "x" = "x$hostname" ]]; then 13 | hostname="$(scutil --get ComputerName)" 14 | fi 15 | sudo scutil --set HostName "$hostname" 16 | sudo scutil --set LocalHostName "$hostname" 17 | sudo scutil --set ComputerName "$hostname" 18 | 19 | # Generate a new ssh key 20 | if ! test -f ~/.ssh/id_ed25519; then 21 | ssh-keygen -t ed25519 22 | 23 | # Wait for the user to add it to github 24 | pbcopy < ~/.ssh/id_ed25519.pub 25 | echo "Now login to https://github.com/settings/keys and add the key that has already been copied to your clipboard." 26 | read -p "Press any key to continue. Ctrl-C to abort." 27 | fi 28 | 29 | # Install Xcode Command Line Tools 30 | if !(softwareupdate --history | grep "Command Line Tools"); then 31 | touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress 32 | COMMAND_LINE_TOOLS=$( 33 | softwareupdate --list \ 34 | | grep "\*.*Command Line" \ 35 | | sort -n \ 36 | | tail -n1 \ 37 | | sed 's/* Label: //' 38 | ) 39 | softwareupdate --install "$COMMAND_LINE_TOOLS" --verbose 40 | rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress 41 | fi 42 | 43 | # Clone the dotfiles 44 | if ! test -d /usr/local/dotfiles; then 45 | sudo mkdir /usr/local/dotfiles 46 | sudo chown $(id -un):admin /usr/local/dotfiles 47 | git clone git@github.com:Overbryd/dotfiles.git /usr/local/dotfiles 48 | cd /usr/local/dotfiles 49 | git checkout main 50 | cd - 51 | fi 52 | 53 | # Bootstrap the administrative stuff 54 | make -C /usr/local/dotfiles dotfiles 55 | export PATH="$PATH:/usr/local/dotfiles/.bin" 56 | source /usr/local/dotfiles/.profile.d/homebrew 57 | make -C /usr/local/dotfiles bootstrap-administrator 58 | 59 | -------------------------------------------------------------------------------- /defaults.sh: -------------------------------------------------------------------------------- 1 | # Enable full keyboard access for all controls (e.g. enable Tab in modal dialogs) 2 | defaults write NSGlobalDomain AppleKeyboardUIMode -int 3 3 | 4 | # Enable subpixel font rendering on non-Apple LCDs 5 | defaults write NSGlobalDomain AppleFontSmoothing -int 2 6 | 7 | # Enable the 2D Dock 8 | defaults write com.apple.dock no-glass -bool true 9 | 10 | # Automatically hide and show the Dock 11 | defaults write com.apple.dock autohide -bool true 12 | 13 | # Make Dock icons of hidden applications translucent 14 | defaults write com.apple.dock showhidden -bool true 15 | 16 | # Disable menu bar transparency 17 | defaults write NSGlobalDomain AppleEnableMenuBarTransparency -bool false 18 | 19 | # Show remaining battery time; hide percentage 20 | defaults write com.apple.menuextra.battery ShowPercent -string "NO" 21 | defaults write com.apple.menuextra.battery ShowTime -string "YES" 22 | 23 | # Disable the “Are you sure you want to open this application?” dialog 24 | defaults write com.apple.LaunchServices LSQuarantine -bool false 25 | 26 | # Disable shadow in screenshots 27 | defaults write com.apple.screencapture disable-shadow -bool true 28 | 29 | # Enable highlight hover effect for the grid view of a stack (Dock) 30 | defaults write com.apple.dock mouse-over-hilte-stack -bool true 31 | 32 | # Enable spring loading for all Dock items 33 | defaults write enable-spring-load-actions-on-all-items -bool true 34 | 35 | # Show indicator lights for open applications in the Dock 36 | defaults write com.apple.dock show-process-indicators -bool true 37 | 38 | # Don’t animate opening applications from the Dock 39 | defaults write com.apple.dock launchanim -bool false 40 | 41 | # Disable press-and-hold for keys in favor of key repeat 42 | defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 43 | 44 | # Set a blazingly fast keyboard repeat rate 45 | defaults write NSGlobalDomain KeyRepeat -int 0 46 | 47 | # Disable auto-correct 48 | defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false 49 | 50 | # Disable window animations 51 | defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false 52 | 53 | # Enable AirDrop over Ethernet and on unsupported Macs running Lion 54 | defaults write com.apple.NetworkBrowser BrowseAllInterfaces -bool true 55 | 56 | # Disable disk image verification 57 | defaults write com.apple.frameworks.diskimages skip-verify -bool true 58 | defaults write com.apple.frameworks.diskimages skip-verify-locked -bool true 59 | defaults write com.apple.frameworks.diskimages skip-verify-remote -bool true 60 | 61 | # Automatically open a new Finder window when a volume is mounted 62 | defaults write com.apple.frameworks.diskimages auto-open-ro-root -bool true 63 | defaults write com.apple.frameworks.diskimages auto-open-rw-root -bool true 64 | 65 | # Increase window resize speed for Cocoa applications 66 | defaults write NSGlobalDomain NSWindowResizeTime -float 0.001 67 | 68 | # Avoid creating .DS_Store files on network volumes 69 | defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true 70 | 71 | # Disable the warning when changing a file extension 72 | defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false 73 | 74 | # Show item info below desktop icons 75 | /usr/libexec/PlistBuddy -c "Set :DesktopViewSettings:IconViewSettings:showItemInfo true" ~/Library/Preferences/com.apple.finder.plist 76 | 77 | # Empty Trash securely by default 78 | defaults write com.apple.finder EmptyTrashSecurely -bool false 79 | 80 | # Require password immediately after 5 seconds on sleep or screen saver begins 81 | defaults write com.apple.screensaver askForPassword -int 1 82 | defaults write com.apple.screensaver askForPasswordDelay -int 5 83 | 84 | # Enable tap to click (Trackpad) 85 | defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true 86 | 87 | # Only use UTF-8 in Terminal.app 88 | defaults write com.apple.terminal StringEncodings -array 4 89 | 90 | # Disable the Ping sidebar in iTunes 91 | defaults write com.apple.iTunes disablePingSidebar -bool true 92 | 93 | # Disable all the other Ping stuff in iTunes 94 | defaults write com.apple.iTunes disablePing -bool true 95 | 96 | # Disable Resume system-wide 97 | defaults write NSGlobalDomain NSQuitAlwaysKeepsWindows -bool false 98 | 99 | # Enable Dashboard dev mode (allows keeping widgets on the desktop) 100 | defaults write com.apple.dashboard devmode -bool true 101 | 102 | # Reset Launchpad 103 | [ -e ~/Library/Application\ Support/Dock/*.db ] && rm ~/Library/Application\ Support/Dock/*.db 104 | 105 | # Show the ~/Library folder 106 | chflags nohidden ~/Library 107 | 108 | # Kill affected applications 109 | for app in Safari Finder Dock Mail SystemUIServer; do killall "$app" >/dev/null 2>&1; done 110 | # TODO: add default for date format weekday, month, day time 111 | 112 | # disable apple captive portal (seucrity issue) 113 | sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.captive.control Active -bool false 114 | 115 | --------------------------------------------------------------------------------