diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 0000000..06161d7 --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,19 @@ +name: shellcheck + +on: + pull_request: + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: install tools + run: bin/setup /usr/local/bin + + - name: run shellcheck + run: | + find bin dotfiles -type f -print0 \ + | xargs -0 grep -lZE '^#! ?/usr/bin/env bash|^#!/usr/bin/env bash|^#! ?/bin/bash' \ + | xargs -0 shellcheck -x diff --git a/.github/workflows/shfmt.yml b/.github/workflows/shfmt.yml new file mode 100644 index 0000000..5e12c49 --- /dev/null +++ b/.github/workflows/shfmt.yml @@ -0,0 +1,19 @@ +name: shfmt + +on: + pull_request: + +jobs: + shfmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: install tools + run: bin/setup /usr/local/bin + + - name: run shfmt + run: | + find bin dotfiles -type f -print0 \ + | xargs -0 grep -lZE '^#! ?/usr/bin/env bash|^#!/usr/bin/env bash|^#! ?/bin/bash' \ + | xargs -0 shfmt -i 2 -ln bash -d diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0435e0d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,35 @@ +# Agent guidelines for interface -- a personal dotfiles and script repo + +## AI Role, behavior, system prompt + +We are senior software engineers hacking some shell script together. +I'm reviewing your code and explaining how the codebase is designed. +I'll also give you tasks, directions, we'll be working together so let's have a good time :) +What matters is good design, clean code and reducing maintenance, performance comes second. +See files under doc/ for project structure and documentation (faster than reading the source code) + +## Build and Test Commands + +Most of the scripts have no tests, we gotta run them to test. + +## Code Style + +Keep comments short and sweet, don't document obvious code. +**Formatting:** We use `shfmt`. +When moving an alias foo to a function add: +```sh +# todo: remove +unalias foo 2>/dev/null +foo() { +``` +this fixes weird bash errors when an alias and a function conflict. +separate functions neatly using #----------------# + +## Misc + +be more minimalistic: being helpful is good but we need to right answer, avoid guessing or crazy workarounds. +avoid single letter vars if their scope is not small. +when we refactor, minimize renames unless asked for. +run formatter as last step after making code changes. +this is a jujutsu repo and do not make commits. +lib-git-prompt.sh has been vendored and we can modify it. \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0bc569a..6cdcfce 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2018-present, Raphael Thomazella +Copyright (c) 2018-present, R. Thomazella All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/bin/app-inhibit-sleep b/bin/app-inhibit-sleep index 4485343..d41712b 100755 --- a/bin/app-inhibit-sleep +++ b/bin/app-inhibit-sleep @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2025 Raphael Thomazella. All rights reserved. +# Copyright 2025-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/btrfs-scrub b/bin/btrfs-scrub index 42f6e5e..10cd5b7 100755 --- a/bin/btrfs-scrub +++ b/bin/btrfs-scrub @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/bulk-curl-from-file b/bin/bulk-curl-from-file index c58cc41..67d010e 100755 --- a/bin/bulk-curl-from-file +++ b/bin/bulk-curl-from-file @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/compile-bin b/bin/compile-bin index df5957c..3204a22 100755 --- a/bin/compile-bin +++ b/bin/compile-bin @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2025 Raphael Thomazella. All rights reserved. +# Copyright 2025-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/dictation-keyboard-hook b/bin/dictation-keyboard-hook index 57f0898..bc85a03 100755 --- a/bin/dictation-keyboard-hook +++ b/bin/dictation-keyboard-hook @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -import sys, evdev, subprocess, time +"""Push-to-talk dictation: record while F2 held, transcribe via whisper-server on release.""" +import sys, subprocess, tempfile, os, json, signal from evdev import InputDevice, categorize, ecodes if len(sys.argv) != 3: @@ -11,13 +12,39 @@ if len(sys.argv) != 3: key = sys.argv[1] device = InputDevice(sys.argv[2]) -subprocess.Popen(['/usr/bin/nerd-dictation', 'begin', '--numbers-as-digits', "--suspend-on-start", "--simulate-input-tool=YDOTOOL", "--idle-time=0", "--verbose=1"]) +SERVER = "http://127.0.0.1:8765/inference" +recording = None for event in device.read_loop(): - if event.type == ecodes.EV_KEY: - k = categorize(event) - if k.keycode == key: - if k.keystate == k.key_down: - subprocess.Popen(['/usr/bin/nerd-dictation', 'resume']) - elif k.keystate == k.key_up: - subprocess.Popen(['/usr/bin/nerd-dictation', 'suspend']) + if event.type != ecodes.EV_KEY: + continue + k = categorize(event) + if k.keycode != key: + continue + + if k.keystate == k.key_down and recording is None: + wav = tempfile.mktemp(suffix=".wav") + recording = subprocess.Popen(["pw-record", "--rate=16000", "--channels=1", wav]) + + elif k.keystate == k.key_up and recording is not None: + recording.send_signal(signal.SIGINT) + recording.wait() + recording = None + + result = subprocess.run( + ["curl", "-sf", "-F", f"file=@{wav}", SERVER], + capture_output=True, text=True + ) + print(result.stderr, end="", flush=True) + print(result.stdout, end="", flush=True) + try: + text = json.loads(result.stdout).get("text", "").strip() + except json.JSONDecodeError: + print(f"whisper-server parse error: {result.stdout}", flush=True) + text = "" + if text: + subprocess.run(["wl-copy", text + " "]) + # ctrl+v keycodes, 1 is keydown + subprocess.run(["ydotool", "key", "29:1", "47:1", "47:0", "29:0"]) + os.unlink(wav) + wav = None diff --git a/bin/download-youtube-id b/bin/download-youtube-id index 3fab911..185d92f 100755 --- a/bin/download-youtube-id +++ b/bin/download-youtube-id @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. @@ -83,7 +83,7 @@ prepare_temp() { } download() { - local format_id=$1 + local format_id=$1 prefix=${2:-} if [ ! "$format_id" ]; then return @@ -91,38 +91,25 @@ download() { # downloading big videos can max out /tmp # ejs:github related to automated captcha challenges using deno - if ! yt-dlp -f "$format_id" "$vid_id" --output "%(title)s-%(release_date)s.%(ext)s" --remote-components ejs:github --paths "temp:/plex/tmp"; then + if ! yt-dlp -f "$format_id" "$vid_id" --output "${prefix}%(title)s-%(release_date)s.%(ext)s" --remote-components ejs:github --paths "temp:/plex/tmp"; then fatal "$LINENO" "yt-dlp error" fi } prompt_audio_format() { msgln note: high quality video has no audio, choose audio now - msgln choose an audio format: + msgln "type an audio format extension (ID EXT columns) e.g. 251 webm:" - read -r - audio_fmt="$REPLY" - msgln audio extension: \(see column EXT\) - - read -r - audio_ext="$REPLY" + read -r audio_fmt audio_ext } prompt_video_format() { - msgln Choose a video format: - msgln 4k: look for mp4 3840x2160 - msgln 2k: look for mp4 2560x1440 - msgln Leave blank to download only audio - - read -r - video_fmt="$REPLY" + msgln "type a video format extension (ID EXT columns) e.g. 137 mp4:" + msgln "4k: look for mp4 3840x2160" + msgln "2k: look for mp4 2560x1440" + msgln "Leave blank to download only audio" - if [ "$video_fmt" ]; then - msgln Video extension: \(see column EXT\) - - read -r - video_ext="$REPLY" - fi + read -r video_fmt video_ext } validate_formats() { @@ -159,7 +146,7 @@ mux() { # ffmpeg -i ./*."$audio_ext" -i ./*."$video_ext" -crf "$crf" -ac 2 "$name.mp4" # gpu using va - ffmpeg -vaapi_device /dev/dri/renderD128 -i ./*."$audio_ext" -i ./*."$video_ext" \ + ffmpeg -vaapi_device /dev/dri/renderD128 -i ./audio-*."$audio_ext" -i ./video-*."$video_ext" \ -c:v hevc_vaapi -vf format=nv12,hwupload \ -qp "$crf" -ac 2 "$name.mp4" mv "$name.mp4" "$out_dir" @@ -174,7 +161,7 @@ convert_MP3() { fi local audio_file - audio_file=$(find . -maxdepth 1 -type f | head -1) + audio_file=$(find . -maxdepth 1 -name "audio-*" -type f | head -1) if [ ! "$audio_file" ]; then fatal "$LINENO" "no audio file found" @@ -207,8 +194,8 @@ prompt_video_format validate_formats -download "$audio_fmt" -download "$video_fmt" +download "$audio_fmt" "audio-" +download "$video_fmt" "video-" mux "$title-$vid_id" convert_MP3 "$title-$vid_id" @@ -218,4 +205,4 @@ cleanup_tmp cd "$initial_working_dir" -info $LINENO ok "$out_dir/$title-$vid_id.mp4" +log $LINENO ok "$out_dir/$title-$vid_id.mp4" diff --git a/bin/extract b/bin/extract index f7dc1ad..a451322 100755 --- a/bin/extract +++ b/bin/extract @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/game-audio-fix b/bin/game-audio-fix index b144e14..a65ed9b 100755 --- a/bin/game-audio-fix +++ b/bin/game-audio-fix @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2025 Raphael Thomazella. All rights reserved. +# Copyright 2025-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/hue b/bin/hue index a6f2005..074b537 100755 --- a/bin/hue +++ b/bin/hue @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2018-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. @@ -8,7 +8,7 @@ # 🚀 2018 by Thomazella 🌙 # http://tazel.website # https://github.com/Thomazella -# reviewed by Thomazella on 2024 +# reviewed by R. Thomazella on 2024 # main changes were linter fixes and some # bad var names renamed for clarity # diff --git a/bin/lazy-git b/bin/lazy-git index 5cc700e..e90bc0f 100755 --- a/bin/lazy-git +++ b/bin/lazy-git @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/lazy-jujutsu b/bin/lazy-jujutsu index 4771396..f8663a9 100755 --- a/bin/lazy-jujutsu +++ b/bin/lazy-jujutsu @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. @@ -97,7 +97,7 @@ push() { debug $LINENO "$base_pwd matches \$PUSH_REPOS" - command jj git push --quiet + command jj git push --quiet } ### script ### diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..9fec3a0 --- /dev/null +++ b/bin/setup @@ -0,0 +1,126 @@ +#! /usr/bin/env bash +# Copyright 2025-present R. Thomazella. All rights reserved. +# Use of this source code is governed by the BSD-3-Clause +# license that can be found in the LICENSE file and online +# at https://opensource.org/license/BSD-3-clause. +# +# Installs development tools required by this repo. +# Self-contained: does not require $BASH_ENV. +# Interactive shell: prints install instructions and exits. +# Non-interactive: downloads and installs binaries from GitHub releases. + +set -euo pipefail +shopt -s globstar + +### vars and functions ### + +msgln() { echo -e "$*"; } +log() { echo -e "INFO ($0:${1}) ${*:2}" >&2; } +err() { echo -e "ERROR ($0:${1})" >&2; } +fatal() { + err "$1" "${*:2}" + exit 1 +} + +trap 'err $LINENO' ERR + +readonly install_dir="${1:-/root/bin}" + +run_privileged() { + if [ "$(id -u)" = "0" ]; then + "$@" + else + sudo "$@" + fi +} + +print_manual_instructions() { + msgln "Some tools are missing. Please install them manually:" + msgln + msgln " shfmt: https://github.com/mvdan/sh/releases/latest" + msgln " shellcheck: https://github.com/koalaman/shellcheck/releases/latest" + msgln + msgln "On Arch: sudo pacman -S shfmt shellcheck" + msgln "On macOS: brew install shfmt shellcheck" +} + +latest_version() { + local repo=$1 + + curl -sf "https://api.github.com/repos/$repo/releases/latest" | + grep '"tag_name"' | + sed -E 's/.*"tag_name": "(.*)".*/\1/' +} + +install_shfmt() { + local version os arch url tmp + + log $LINENO "fetching latest shfmt version" + version=$(latest_version mvdan/sh) + + os=$(uname -s | tr '[:upper:]' '[:lower:]') + arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + url="https://github.com/mvdan/sh/releases/download/${version}/shfmt_${version}_${os}_${arch}" + tmp=$(mktemp) + + log $LINENO "downloading shfmt $version" + curl -sfL "$url" -o "$tmp" + chmod +x "$tmp" + run_privileged mv "$tmp" "$install_dir/shfmt" + log $LINENO "shfmt installed to $install_dir/shfmt" +} + +install_shellcheck() { + local version os arch tarball url tmp_dir + + log $LINENO "fetching latest shellcheck version" + version=$(latest_version koalaman/shellcheck) + + os=$(uname -s | tr '[:upper:]' '[:lower:]') + arch=$(uname -m) + tarball="shellcheck-${version}.${os}.${arch}.tar.xz" + url="https://github.com/koalaman/shellcheck/releases/download/${version}/${tarball}" + tmp_dir=$(mktemp -d) + + log $LINENO "downloading shellcheck $version" + curl -sfL "$url" | tar -xJ -C "$tmp_dir" + run_privileged mv "$tmp_dir/shellcheck-${version}/shellcheck" "$install_dir/shellcheck" + rm -rf "$tmp_dir" + log $LINENO "shellcheck installed to $install_dir/shellcheck" +} + +install_tool() { + local tool=$1 install_fn=$2 + + if command -v "$tool" >/dev/null 2>&1; then + log $LINENO "$tool already installed" + return + fi + + "$install_fn" +} + +### script ### + +missing=false + +command -v shfmt >/dev/null 2>&1 || missing=true +command -v shellcheck >/dev/null 2>&1 || missing=true + +if ! $missing; then + log $LINENO "all tools already installed" + exit 0 +fi + +# todo: runing script as user doesn't trigger this +# interactive shell: just tell the user +if [[ $- == *i* ]]; then + print_manual_instructions + exit 0 +fi + +# non-interactive: download and install +install_tool shfmt install_shfmt +install_tool shellcheck install_shellcheck + +msgln "setup complete" diff --git a/bin/snapshot b/bin/snapshot index 87fdc90..016e3e5 100755 --- a/bin/snapshot +++ b/bin/snapshot @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/system-snapshot b/bin/system-snapshot index fd03c31..190e180 100755 --- a/bin/system-snapshot +++ b/bin/system-snapshot @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/bin/system-up b/bin/system-up index 5ece32b..bcc7f09 100755 --- a/bin/system-up +++ b/bin/system-up @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. @@ -215,20 +215,10 @@ mise_install_globals() { mise use --global npm@latest # reinstall missing npm globals - local packages=(cspell cspell@latest prettier prettier@latest commitlint @commitlint/cli@latest commitlint/config-conventional @commitlint/config-conventional@latest) + local packages=(cspell@latest prettier@latest @commitlint/cli@latest @commitlint/config-conventional@latest) for ((i = 0; i < ${#packages[@]}; i++)); do - if ((i % 2 != 0)); then - continue - fi - - name="${packages[i]}" - version="${packages[i + 1]}" - - # command -v reports false positives on aliases - if ! which "$name" >/dev/null 2>&1; then - npm install --global "$version" - fi + npm install --global "${packages[i]}" done # export PATH="$PATH:$HOME/.local/share/mise/installs/node/$(node -v | tr -d v)/bin" diff --git a/bin/template b/bin/template index 25273dc..0ad9b5f 100755 --- a/bin/template +++ b/bin/template @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2025 Raphael Thomazella. All rights reserved. +# Copyright 2025-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/doc/bin.md b/doc/bin.md new file mode 100644 index 0000000..7430c76 --- /dev/null +++ b/doc/bin.md @@ -0,0 +1,47 @@ +# bin/ — Executables + +All scripts require `$BASH_ENV` to be set (sources `lib.sh` for `msgln`, `log`, `err`, `fatal`, etc.). +Scripts use the standard header: `set -euo pipefail`, `trap 'err $LINENO' ERR`. + +## Shell Scripts + +| Script | Purpose | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `snapshot` | Interactive btrfs subvolume snapshot tool. Prompts for source subvolume under `/toplevel`, name, and read-only flag. Supports `--dry-run`. | +| `system-snapshot` | Non-interactive btrfs snapshot for automated use. Takes target subvolume names as args, keeps max 50 snapshots, trims old ones. | +| `system-up` | Full Arch Linux system update: snapshot → stop postgres → update pacman/AUR/mise globals → migrate postgres if major version changed → btrfs scrub optional → kexec into new kernel. | +| `btrfs-scrub` | Runs `btrfs scrub` on specified disks. | +| `app-inhibit-sleep` | Watches if Firefox (or given apps) is playing audio via `playerctl`; calls `systemd-inhibit` to prevent idle sleep while playing. | +| `lazy-git` | Interactive git helper: stages, composits commitlint-compliant commit messages, and pushes repos listed in `$PUSH_REPOS`. Reads `$GIT_BRANCH`. | +| `lazy-jujutsu` | Same as `lazy-git` but for jujutsu (`jj`). | +| `extract` | Universal archive extractor. Detects format and calls the right tool (tar, unzip, 7z, etc.). | +| `hue` | Philips Hue light controller (~425 lines). Talks to the Hue bridge REST API. | +| `compile-bin` | Builds all Go tools under `src/` into `bin/`. Iterates `src/**/main.go`, runs `go build -race`. | +| `bulk-curl-from-file` | Runs curl for each URL in a file. | +| `cpfgen` | CPF number generator (Brazilian tax ID). | +| `dictation-keyboard-hook` | Push-to-talk dictation via whisper-server. Records with `pw-record` while `KEY_F2` held, POSTs WAV to `whisper-server` on release, types result via `ydotool`. Multilingual (auto-detect). | +| `dir-rename` | Compiled Go binary — bulk directory rename tool. | +| `download-youtube-id` | Downloads a YouTube video by ID using `yt-dlp`. | +| `forex` | Compiled Go binary — currency exchange rate fetcher. | +| `game-audio-fix` | Fixes audio for games (likely resets PulseAudio/PipeWire). | +| `mac-defaults` | Applies `defaults write` settings for macOS. | +| `presentvalue` | Compiled Go binary — present value financial calculator. | +| `rename` | Perl script for powerful batch file renaming (regex-based). | +| `system-up` | (see above) | +| `template` | Scaffold script — creates new scripts from a template. | +| `typo` | Compiled binary — likely a typo/spell checker helper. | + +## Go Sources (`src/`) + +Built by `compile-bin`. Each subdirectory has a `main.go`. + +| Tool | Description | +| -------------- | ----------------------------------------- | +| `forex` | Fetches live exchange rates | +| `presentvalue` | Present value / financial math calculator | + +`dir-rename` and `typo` binaries are present in `bin/` but their source is not in this repo (compiled elsewhere or vendored as binaries). + +## git/ hooks + +`bin/git/interface-hook-pre-commit` — pre-commit hook for this repo (cspell spellcheck, shfmt formatting, etc.). diff --git a/doc/dotfiles.md b/doc/dotfiles.md new file mode 100644 index 0000000..ea5657b --- /dev/null +++ b/doc/dotfiles.md @@ -0,0 +1,59 @@ +# dotfiles/ + +Files here are symlinked into `$HOME`. The install mechanism is not in this repo +(managed manually or by a separate tool). + +## Shell + +| File | Purpose | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `.bashrc` | Main interactive shell config. Sets exports, sources libs and aliases. | +| `.bash_profile` | Login shell — sources `.bashrc`. | +| `.bash_env` | Non-interactive env loaded via `$BASH_ENV`. Sets `$GOPRIVATE`, `$T0_COLOR`, sources `lib.sh`, extends `$PATH`. | +| `.bash_logout` | Cleanup on logout. | +| `.bashrc.linux.sh` | Linux-specific bash config. | +| `.bashrc.mac.sh` | macOS-specific bash config. | +| `.aliases.sh` | Cross-platform aliases: navigation, work shortcuts (psql, gcloud), typo corrections, git aliases. | +| `.aliases.linux.sh` | Linux aliases: ls, mv, wl-copy/paste, pacman/yay wrappers, chromium VPN. | +| `.aliases.mac.sh` | macOS aliases. | +| `lib.sh` | **Core library.** Logging functions: `log`, `debug`, `err`, `warn`, `fatal`, `msg`, `msgln`. Helpers: `macos`, `requested_help`, `is_me`, `term_emulator`. Color via `$T0_COLOR`. Kept in sync with `github.com/tcodes0/sh`. | +| `lib-git-prompt.sh` | Git prompt helpers, exports `$GIT_BRANCH`. | +| `lib-prompt.sh` | PS1 prompt builder. | + +## Key exports (from `.bashrc`) + +| Variable | Value | +| ------------- | ----------------------------------------------------------- | +| `DOTFILES` | `$HOME/Desktop/interface/dotfiles` | +| `BASH_ENV` | `$HOME/.bash_env` | +| `GOPRIVATE` | `github.com/eleanorhealth/* github.com/tcodes0/*` | +| `T0_COLOR` | `true` (enables ANSI color in lib.sh logging) | +| `EDITOR` | `code -w` | +| `PUSH_REPOS` | Space-separated list of repo names for `lazy-git` auto-push | +| `KNOWN_HOSTS` | Array of known machine hostnames | + +## .config/ + +| Path | Purpose | +| ----------------------------------- | ------------------------------------------------------------------------- | +| `Claude/claude_desktop_config.json` | Claude Desktop config. Registers `jailMPC` MCP server via Docker Compose. | +| `jj/config.toml` | Jujutsu global config. | +| `jj/repos` | Known jj repos list. | +| `code*/User/` | VSCode / VSCodium settings and keybindings. | +| `systemd/user/` | User systemd service units. | +| `autostart/guake.desktop` | Autostart Guake terminal on login. | +| `keymap.xkb` | Custom XKB keyboard layout. | +| `htop/htoprc` | htop config. | +| `ollama/` | Ollama model config files (`aux-chat`, `aux-code`). | +| `fontconfig/` | Font rendering config. | + +## Other dotfiles + +| File | Purpose | +| -------------------------- | ------------------------------------------- | +| `.emacs` | Emacs config. | +| `.fonts/` | Custom fonts (DejaVu, 16bit, etc.). | +| `.commitlintrc.yml` | Commitlint rules for conventional commits. | +| `.cspell.config.yml` | cspell dictionary/config for spellchecking. | +| `.chatgpt-cli-config.yaml` | chatgpt-cli config. | +| `.fonts.conf` | Fontconfig (legacy location). | diff --git a/doc/etc.md b/doc/etc.md new file mode 100644 index 0000000..007ad7b --- /dev/null +++ b/doc/etc.md @@ -0,0 +1,90 @@ +# etc/ — System Configuration + +Files here are symlinked (or hardlinked for `fstab`) into `/etc`. Requires root for install. +Note: `/etc/fstab` must be a **hardlink**, not a symlink — the kernel reads it before symlinks resolve. + +## Filesystem & Boot + +### `fstab` + +Full btrfs-based layout using labels. All major mounts use `noatime,compress=lzo`. + +| Label | Mount | Notes | +| ----------- | --------------------------- | ------------------------------------ | +| `EFI-BLUE` | `/boot` | vfat EFI partition | +| `Archlinux` | `/toplevel` | btrfs root, all subvolumes live here | +| `Archlinux` | `/home/vacation` | `@vacation` subvolume | +| `Archlinux` | `~/.local/share/lutris` | `@lutris` — games isolated | +| `Archlinux` | `~/.local/share/Steam` | `@steam` — Steam isolated | +| `Archlinux` | `/var/lib/postgres` | `@postgres` | +| `Archlinux` | `~/.cache` | `@.cache` | +| `Archlinux` | `/var/lib/docker` | `@docker` | +| `Archlinux` | `/swap` | `@swap` subvolume | +| `Data2TB` | `/media/data` | secondary data disk | +| `Data2TB` | `~/.ollama` | Ollama model storage | +| `Data4TB` | `/media/data4tb` | tertiary data disk | +| `Data4TB` | `/plex` and `~/Videos/plex` | Plex media (double-mounted) | +| `External` | `/media/external` | exfat external drive, noauto | + +Swap is a swapfile at `/swap/swapfile`. + +### `mkinitcpio.conf` + +- **MODULES**: `fs_btrfs amdgpu` — preloaded for btrfs root and AMD GPU early KMS. +- **HOOKS**: `base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume` + — notably includes `resume` for hibernation support. +- `MODULES_DECOMPRESS=yes` — decompress kernel modules in initramfs for faster boot. + +### `boot/EFI/CLOVER/` + +CLOVER EFI bootloader config. The pre-commit hook syncs `config.plist` to `/boot/EFI/CLOVER/config.plist` on commit. + +## Display + +### `X11/xorg.conf.d/settings.conf` + +`DontVTSwitch=False` — allows VT switching from X11. + +### `sddm.conf.d/settings.conf` + +SDDM display manager config. Key settings: + +- Theme: `breeze` +- `EnableHiDPI=true` (X11 and Wayland) +- `Numlock=on` +- Autologin disabled + +## System Services + +### `systemd/sleep.conf.d/hibernate.conf` + +- Hibernate mode: `shutdown` (writes RAM to swap, powers off) +- `HibernateDelaySec=22h` — suspend-then-hibernate after 22h +- All sleep modes allowed: suspend, hibernate, hybrid, suspend-then-hibernate. + +### `systemd/system.conf.d/watchdog.conf` + +- `RuntimeWatchdogSec=3min` — kernel watchdog resets if systemd stalls +- `RebootWatchdogSec=15` — reboot watchdog on system reboot + +### `systemd/system/` — Root system units + +| Unit | Purpose | +| ------------------------- | -------------------------------------------------------------------------------------------------------- | +| `system-snapshot.service` | Runs `~/bin/system-snapshot` as root | +| `system-snapshot.timer` | Triggers hourly, persistent | +| `btrfs-scrub@.service` | Template unit; `%i` = volume name (Archlinux/Data2TB/Data4TB). Nice=19, IO idle priority. 30min timeout. | +| `btrfs-scrub@.timer` | Monthly, randomized by up to 1 week | +| `memreserver.service` | Runs before sleep (`Before=sleep.target`). Frees RAM so GPU VRAM can be evacuated on suspend. | + +## Network + +### `resolvconf.conf` + +- DNS: `1.1.1.1 8.8.8.8` (Cloudflare + Google) +- Blacklists Brazilian ISP DNS servers (`2804:14d:*`, `192.168.*`) and `wlp4s0` interface DNS + +### `geoclue/geoclue.conf` + +Geolocation daemon config. Uses Mozilla Location Service (`location.services.mozilla.com`). +Firefox and GNOME shell are whitelisted for location access. diff --git a/doc/ideas.md b/doc/ideas.md new file mode 100644 index 0000000..f22311d --- /dev/null +++ b/doc/ideas.md @@ -0,0 +1,14 @@ +# open questions + +Things that jump out: +The `BASHENV‘patterniscleverbutfragile—everyscripthasthat‘checkdependencies‘boilerplateatthetop.Itworks,butitmeansifyouevermoveorrename‘lib.sh‘,everyscriptbreakssilentlyatruntimeratherthanatsourcetime.Thecheckalsoonlytestsif‘BASH_ENV` pattern is clever but fragile — every script has that `check_dependencies` boilerplate at the top. It works, but it means if you ever move or rename `lib.sh`, every script breaks silently at runtime rather than at source time. The check also only tests if ` +BASHE​NV‘patterniscleverbutfragile—everyscripthasthat‘checkd​ependencies‘boilerplateatthetop.Itworks,butitmeansifyouevermoveorrename‘lib.sh‘,everyscriptbreakssilentlyatruntimeratherthanatsourcetime.Thecheckalsoonlytestsif‘BASH_ENV` is _set_, not if `lib.sh` actually _loaded_ — so a wrong path in `.bash_env` would still pass the check. + +The binaries committed directly to bin/ (typo, dir-rename) are interesting — they're ELF x86-64 blobs with no source in the repo. That's a trust and portability issue, and if you ever need to rebuild them or debug them, there's no path forward from within the repo. +fstab as a hardlink is a smart workaround but it means the repo and /etc/fstab are silently diverging any time you edit one without the other. There's no enforcement. +The system-up script has a postgres_up function that calls extract_version and then does [ "$major_sub" -ge 1 ] — but extract_version returns strings like "15." (with a trailing dot from the regex). The bc subtraction would work, but the comparison on the result of bc gives a float like "1.0", and [ "1.0" -ge 1 ] is actually a bash integer comparison that would fail on the .0 suffix. Worth checking if that code path has actually been exercised recently. + +Genuine questions: +The PUSH_REPOS list in .bashrc has interface in it — but the repo uses jujutsu, not git. lazy-git checks $PUSH_REPOS and calls git push. Does lazy-git ever actually run against this repo, or is lazy-jujutsu always the one used here? +The ollama service listens on 0.0.0.0 so Docker containers can reach it — what are you running in Docker that talks to Ollama? Local LLM tooling for work, or something else? +And the dictation-keyboard-hook on KEY_F2 of the Keychron Q10 — what does it actually do? Does it pipe audio to a Whisper model, or is it hooking into some other dictation stack? diff --git a/doc/structure.md b/doc/structure.md new file mode 100644 index 0000000..6d1de08 --- /dev/null +++ b/doc/structure.md @@ -0,0 +1,38 @@ +# Project Structure + +`interface` is a personal dotfiles and scripts repo for Arch Linux (primary) and macOS (secondary). +The repo is managed with **jujutsu** (`jj`). Do not make commits manually. + +## Directory Layout + +``` +interface/ +├── bin/ # Executables added to $PATH ($HOME/bin symlinks here) +│ └── git/ # Git hooks +├── boot/ # EFI/bootloader configs (CLOVER) +├── doc/ # Project documentation (this folder) +├── dotfiles/ # Config files symlinked into $HOME +│ ├── .config/ # XDG config (jj, Claude, VSCode, etc.) +│ └── lib*.sh # Shell libraries sourced at startup +├── etc/ # System configs symlinked into /etc +├── priv/ # Private/sensitive configs (not detailed here) +└── src/ # Go source for compiled tools + ├── forex/ + └── presentvalue/ +``` + +## Absolute-path symlinks + +Some symlinks reference `/home/vacation/` or `/Users/thom.ribeiro/`. They only work in the +original environment. When cloning elsewhere, update the prefix to your home directory. + +## How dotfiles are loaded + +1. `.bashrc` sets `$DOTFILES=$HOME/Desktop/interface/dotfiles` and sources: + - `lib.sh` — shell function library (logging, OS detection, etc.) + - `lib-git-prompt.sh` — git PS1 helpers, exports `$GIT_BRANCH` + - `lib-prompt.sh` — prompt construction + - `.aliases.sh` — cross-platform aliases + - `.aliases.linux.sh` or `.aliases.mac.sh` — OS-specific aliases +2. `.bash_env` sets `$BASH_ENV` so non-interactive scripts pick up `lib.sh` functions. + Scripts check `$BASH_ENV` is set and fail early if not. diff --git a/doc/workflows.md b/doc/workflows.md new file mode 100644 index 0000000..b1f5a23 --- /dev/null +++ b/doc/workflows.md @@ -0,0 +1,131 @@ +# Workflows & Tooling + +## Commit workflow — `lazy-git` / `lazy-jujutsu` + +Both scripts enforce [Conventional Commits](https://www.conventionalcommits.org/) via `commitlint` +and spell-check the commit message with `cspell`. Invoked as: + +``` +lg # aliased to lazy-git / lazy-jujutsu +``` + +Colons in `type` and `scope` are stripped automatically. +If `scope` is a single character, the format collapses to `type: subject` (no parens). + +**`lazy-git` flow:** + +1. If files are already staged, commits those. Otherwise runs `git add --all`. +2. Builds `type(scope): subject` message, validates with `commitlint` + `cspell`. +3. Commits with `--no-verify` (hook already ran via pre-commit, or skipped intentionally). +4. If `$PWD`'s basename matches `$PUSH_REPOS`, pushes to origin. Sets upstream automatically if missing. +5. Prints `git status --short`. + +**`lazy-jujutsu` flow:** + +1. Same message construction and validation. +2. Finds the nearest ancestor bookmark via `jj log`. Updates the bookmark to `@` (unless it's `main`/`master`). +3. Runs `jj commit`. +4. If repo matches `$PUSH_REPOS`, runs `jj git push`. + +Config fallback: looks for `.commitlintrc.yml` and `.cspell.config.yml` in `$PWD`, falls back to `~/` defaults. + +**Globals consumed:** + +- `$PUSH_REPOS` — space-separated list of repo basenames to auto-push (set in `.bashrc`) +- `$GIT_BRANCH` — exported by `lib-git-prompt.sh` via `PROMPT_COMMAND` / `__git_ps1` +- `$BASH_ENV` — must be set; sources `lib.sh` functions + +## Pre-commit hook (`bin/git/interface-hook-pre-commit`) + +Installed on the `interface` and `priv` repos. Runs on every `git commit`: + +1. `cspell --unique .` — spellchecks the entire repo. +2. `install_config_plist` — if `boot/EFI/CLOVER/config.plist` changed, copies it to `/boot/EFI/CLOVER/config.plist` (Linux only, skipped on macOS). + +## System update — `system-up` + +Full Arch Linux update orchestrator. Run manually, interactive. + +``` +system-up +``` + +1. Prompts to snapshot `@root` (10s timeout, default skip). +2. Stops `postgresql` service. +3. Optionally runs `btrfs check` on Data2TB and Data4TB (prompts to unmount first). +4. Checks if PostgreSQL has a major version bump in AUR; if so, runs `pg_upgrade` automatically. +5. Runs `mise use --global` to update Node, Go, yarn, npm and reinstalls missing npm globals. +6. Updates Arch packages in order: `archlinux-keyring` → `linux*` → repo packages (non-linux) → AUR packages. +7. Starts `postgresql`, refreshes collations on all known databases. +8. Cleans up old postgres data dirs if a major migration happened. +9. Prompts to `kexec` into the new kernel (fast reboot, no POST). +10. Kills background `sudo -v` refresh loop. + +## Snapshot workflow + +### Interactive (`snapshot`) + +``` +snapshot [-n|--dry-run] +``` + +Prompts for: source subvolume under `/toplevel` → snapshot name (default `name-YYYY-MM-DD[-ro]`) → read-only flag. + +### Automated (`system-snapshot`) + +Called by `system-snapshot.service` (root, hourly timer). Takes target subvolume names as arguments, +creates read-only snapshots named `target-YYYY-MM-DD-HH-ro`, trims to keep max 50 per target. + +## Btrfs scrub + +### Manual (`btrfs-scrub`) + +``` +btrfs-scrub [cancel] +``` + +Maps volume labels to mount points and runs `btrfs scrub start` (or `cancel`). + +### Automated + +`btrfs-scrub@.service` / `btrfs-scrub@.timer` — monthly, randomized ±1 week, IO idle priority. + +## User systemd services (dotfiles/.config/systemd/user/) + +| Service | Timer | Purpose | +| ---------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `app-inhibit-sleep` | always-on | Watches `pacman`, `yay`, and Firefox audio via `playerctl`; calls `systemd-inhibit` to block idle sleep | +| `forex@.service` | hourly | Fetches exchange rate for currency `%i`; reads env from `~/.config/t0/forex.env` | +| `game-audio-fix` | every minute | Corrects 5.1→2.0 audio routing for games | +| `docker-prune` | Saturdays 15–23h | `docker system prune` | +| `system-update-notification` | Sundays 11:00 | `notify-send` reminder to run system update | +| `ollama` | always-on | `ollama serve` with ROCm (AMD GPU), listens on `0.0.0.0:11434` for Docker bridge access | +| `xkbcomp` | on graphical session | Loads custom XKB keymap from `dotfiles/.config/keymap.xkb` | +| `xset-rate` | on default target | Sets key repeat: 140ms delay, 70ms interval | +| `whisper-server` | always-on | `whisper-server` with model loaded on GPU (ROCm); listens on `127.0.0.1:8765` for dictation inference | +| `dictation-shortcut` | always-on | Push-to-talk dictation on `KEY_F2` (Keychron Q10); records via `pw-record`, transcribes via `whisper-server`, types via `ydotool`. Requires `whisper-server`. | +| `docker` override | — | Sets `DOCKERD_ROOTLESS_ROOTLESSKIT_DISABLE_HOST_LOOPBACK=false` so containers can reach host | + +## Prompt + +`lib-prompt.sh` builds PS1 via `make_ps1`: + +- Random 256-color ANSI color per session. +- Decorations: `~>` for known user, `#>` for root, `*>` in secondary color for unknown hostnames. +- Appends hostname if not in `$KNOWN_HOSTS`. +- Integrates with `lib-git-prompt.sh` (`__git_ps1`) for git/jj branch and dirty-state indicators. + +## Go tools — building + +```bash +compile-bin # run from repo root +``` + +Iterates `src/**/main.go`, builds each with `go build -race -mod=readonly` into `bin/`. + +## Code style + +- Shell: `shfmt` (run as last step after edits) +- Commits: Conventional Commits via `commitlint` +- Spellcheck: `cspell` +- VCS: **jujutsu** (`jj`) — do not make manual commits diff --git a/dotfiles/.aliases.sh b/dotfiles/.aliases.sh index 67a52f8..a0df753 100644 --- a/dotfiles/.aliases.sh +++ b/dotfiles/.aliases.sh @@ -86,7 +86,6 @@ alias gcpa='git cherry-pick --abort' alias gcpc='git cherry-pick --continue' alias gcs='git commit -S' alias gcsm='git commit -s -m' -alias gd='jj diff' alias gdca='git diff --cached' alias gdct='git describe --tags `git rev-list --tags --max-count=1`' alias gdcw='git diff --cached --word-diff' @@ -240,9 +239,13 @@ alias misc-="lg misc -" alias chore-="lg chore -" # jujutsu +alias j="jj" alias jgp="jj git push" +alias jgf="jj git fetch" alias jn="jj new" -alias gss="jss" +alias jsq="jj squash -m" +alias jre="jj resolve" +alias jbf="jj bookmark forget" # general alias la='ls -A' @@ -259,7 +262,6 @@ alias part='partutil' alias srit='source $HOME/.bashrc && clear' alias dirs='dirs -v' alias stat='stat -L' -alias j='jobs' alias f='fg' alias g='grep -Eie' alias ping='ping -c 1' @@ -270,8 +272,6 @@ alias visudo="EDITOR='code -w' && command sudo visudo" alias shfmt="shfmt -i 2 -ln bash" alias shellcheck="shellcheck --color=auto -s bash" alias cat='bat --theme Monokai\ Extended\ Origin' -alias gppr='gpsup && git pull-request -b main --browse --assign thomazella' -alias gpprd='gpsup && git pull-request -b develop --browse --assign thomazella' alias t="cat" alias l="less" alias wget='wget -c' diff --git a/dotfiles/.bash_env b/dotfiles/.bash_env index 86ee844..2f23389 100644 --- a/dotfiles/.bash_env +++ b/dotfiles/.bash_env @@ -1,4 +1,5 @@ #! /usr/bin/env bash +# shellcheck disable=SC1091 # uninteractive bash env # BASH_ENV must be set to this script in bash config files diff --git a/dotfiles/.bash_profile b/dotfiles/.bash_profile index 4195884..3c92fde 100644 --- a/dotfiles/.bash_profile +++ b/dotfiles/.bash_profile @@ -1,4 +1,5 @@ #! /usr/bin/env bash +# shellcheck disable=SC1091 if [ -f "$HOME/.bashrc" ]; then # shellcheck source=.bashrc diff --git a/dotfiles/.bashrc b/dotfiles/.bashrc index d1eb05e..17e0225 100644 --- a/dotfiles/.bashrc +++ b/dotfiles/.bashrc @@ -41,7 +41,7 @@ export GPG_TTY=$(tty) export XDG_RUNTIME_DIR export WAYLAND_DISPLAY # see lazy-git -export PUSH_REPOS="member-client interface priv hub-client server server-1 server-2 server-3 server-4 member-server shared go-athenahealth scheduling jail-mcp comms programming-problems" +export PUSH_REPOS="member-client go-common interface priv hub-client server server-1 server-2 server-3 server-4 member-server shared go-athenahealth scheduling jail-mcp comms programming-problems" # libs src_dotfile "lib.sh" "$LINENO" diff --git a/dotfiles/.config/Claude/claude_desktop_config.json b/dotfiles/.config/Claude/claude_desktop_config.json index 433cc09..b55b353 100644 --- a/dotfiles/.config/Claude/claude_desktop_config.json +++ b/dotfiles/.config/Claude/claude_desktop_config.json @@ -1,6 +1,6 @@ { "mcpServers": { - "jailMPC": { + "3_jailMCP": { "command": "docker", "args": [ "compose", diff --git a/dotfiles/.config/code-oss/User/settings.json b/dotfiles/.config/code-oss/User/settings.json index b8b20e0..6457137 100644 --- a/dotfiles/.config/code-oss/User/settings.json +++ b/dotfiles/.config/code-oss/User/settings.json @@ -18,7 +18,7 @@ "tab.activeBackground": "#000", "titleBar.activeBackground": "#000", "editorGutter.background": "#000", - "breadcrumb.background": "#000" + "breadcrumb.background": "#000", }, "activityBarBadge.background": "#FF4081", "list.activeSelectionForeground": "#FF4081", @@ -38,7 +38,7 @@ "panelTitle.activeBorder": "#FF4081", "breadcrumb.activeSelectionForeground": "#FF4081", "menu.selectionForeground": "#FF4081", - "menubar.selectionForeground": "#FF4081" + "menubar.selectionForeground": "#FF4081", }, "editor.tokenColorCustomizations": { "[GitHub Dark High Contrast]": { @@ -46,8 +46,8 @@ "functions": "#7e7fdd", "strings": "#8b907f", "keywords": "#c5ad97", - "types": "#6abe7f" - } + "types": "#6abe7f", + }, }, // // - - - - - - - - FONT - - - - - - - - - @@ -68,31 +68,31 @@ // "eslint.run": "onType", "eslint.options": { - "resolvePluginsRelativeTo": "." + "resolvePluginsRelativeTo": ".", }, "[shellscript]": { - "editor.defaultFormatter": "lumirelle.shell-format-rev" + "editor.defaultFormatter": "lumirelle.shell-format-rev", }, "[typescriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[javascriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[sql]": { - "editor.formatOnPaste": false + "editor.formatOnPaste": false, }, "[yaml]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "sql-formatter.uppercase": true, // @@ -120,10 +120,10 @@ "typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.importModuleSpecifierEnding": "minimal", "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "[jsonc]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", }, "typescript.implementationsCodeLens.enabled": true, "typescript.updateImportsOnFileMove.enabled": "always", @@ -134,21 +134,68 @@ "[go]": { "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports": "explicit" - } + "source.organizeImports": "explicit", + }, }, "go.testOnSave": false, "go.delveConfig": { - "debugAdapter": "dlv-dap" + "debugAdapter": "dlv-dap", }, "go.testEnvFile": "${workspaceFolder}/.env", "go.testFlags": ["-race"], "go.lintTool": "golangci-lint", "go.lintFlags": ["--print-issued-lines=false"], "go.vetOnSave": "off", - "go.formatTool": "gofumpt", + "go.formatTool": "default", "gopls": { - "ui.semanticTokens": true + "ui.semanticTokens": true, + "build.buildFlags": ["-buildvcs=false"], + + // Show inlay hints for parameter names, type params, etc. + "ui.inlayhints.parameterNames": true, + "ui.inlayhints.assignVariableTypes": true, + "ui.inlayhints.compositeLiteralFields": true, + "ui.inlayhints.compositeLiteralTypes": true, + "ui.inlayhints.constantValues": true, + "ui.inlayhints.functionTypeParameters": true, + "ui.inlayhints.rangeVariableTypes": true, + + // Staticcheck: enables many extra linters beyond go vet + "ui.diagnostic.staticcheck": true, + + // Analyses: fine-grained control over individual analyzers + "ui.diagnostic.analyses": { + "shadow": true, // warn on shadowed variables + "nilness": true, // detect nil dereferences + "unusedparams": true, // warn on unused function params + "unusedwrite": true, // warn on writes to vars never read + "useany": true, // suggest `any` instead of `interface{}` + }, + + // Completion options + "ui.completion.usePlaceholders": true, // fill in param placeholders on completion + "ui.completion.matcher": "Fuzzy", // fuzzy matching (vs "CaseInsensitive" or "CaseSensitive") + + // Codelens: inline actionable buttons + "ui.codelenses": { + "gc_details": true, // toggle compiler optimization details + "run_govulncheck": true, + "tidy": true, + "vendor": true, + "generate": true, + }, + + // Format with gofumpt (stricter than gofmt) — requires gofumpt installed + "formatting.gofumpt": true, + + // Automatically add missing imports and remove unused ones on save + // (usually controlled by editor settings, but can be forced here) + "ui.diagnostic.annotations": { + "bounds": true, // annotate slice bounds checks + "escape": true, // annotate heap escapes + "inline": true, // annotate inlining decisions + "nil": true, + }, }, "go.toolsManagement.autoUpdate": true, // @@ -192,28 +239,28 @@ "githubPullRequests.queries": [ { "label": "Local Pull Request Branches", - "query": "default" + "query": "default", }, { "label": "Waiting", - "query": "repo:${owner}/${repository} is:open review-requested:${user}" + "query": "repo:${owner}/${repository} is:open review-requested:${user}", }, { "label": "Open", - "query": "repo:${owner}/${repository} is:open" + "query": "repo:${owner}/${repository} is:open", }, { "label": "Assigned", - "query": "repo:${owner}/${repository} is:open assignee:${user}" + "query": "repo:${owner}/${repository} is:open assignee:${user}", }, { "label": "Created", - "query": "repo:${owner}/${repository} is:open author:${user}" + "query": "repo:${owner}/${repository} is:open author:${user}", }, { "label": "All Open", - "query": "default" - } + "query": "default", + }, ], "githubPullRequests.fileListLayout": "flat", "githubPullRequests.pullBranch": "never", @@ -221,7 +268,7 @@ "*": true, "plaintext": false, "markdown": false, - "scminput": false + "scminput": false, }, "cSpell.userWords": [ "AIAPI", @@ -292,7 +339,7 @@ "Unnotified", "vamac", "Wrapf", - "zerolog" + "zerolog", ], "cSpell.maxDuplicateProblems": 2, "cSpell.spellCheckDelayMs": 2000, @@ -307,10 +354,10 @@ "css", "javascript", "typescript", - "shellscript" + "shellscript", ], "cSpell.enabledNotifications": { - "Lines too Long": false + "Lines too Long": false, }, "window.commandCenter": false, "window.menuBarVisibility": "hidden", @@ -327,15 +374,15 @@ "editor.insertSpaces": true, "editor.tabSize": 2, "editor.autoIndent": "advanced", - "editor.defaultFormatter": "redhat.vscode-yaml" + "editor.defaultFormatter": "redhat.vscode-yaml", }, "[github-actions-workflow]": { - "editor.defaultFormatter": "redhat.vscode-yaml" + "editor.defaultFormatter": "redhat.vscode-yaml", }, "github.copilot.nextEditSuggestions.enabled": true, "[css]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - } + "editor.defaultFormatter": "esbenp.prettier-vscode", + }, // // - - - - - - - - NEW - - - - - - - - - // diff --git a/dotfiles/.config/jj/config.toml b/dotfiles/.config/jj/config.toml index 3dc70e6..1376044 100644 --- a/dotfiles/.config/jj/config.toml +++ b/dotfiles/.config/jj/config.toml @@ -1,7 +1,7 @@ "$schema" = "https://jj-vcs.github.io/jj/latest/config-schema.json" [user] -name = "Raphael \"Thom\" Thomazella" +name = "R. Thomazella" email = "thomazella9@gmail.com" [signing] diff --git a/dotfiles/.config/systemd/user/default.target.wants/whisper-server.service b/dotfiles/.config/systemd/user/default.target.wants/whisper-server.service new file mode 120000 index 0000000..4bcb4ad --- /dev/null +++ b/dotfiles/.config/systemd/user/default.target.wants/whisper-server.service @@ -0,0 +1 @@ +/home/vacation/.config/systemd/user/whisper-server.service \ No newline at end of file diff --git a/dotfiles/.config/systemd/user/dictation-shortcut.service b/dotfiles/.config/systemd/user/dictation-shortcut.service index c23774f..4bf66ed 100644 --- a/dotfiles/.config/systemd/user/dictation-shortcut.service +++ b/dotfiles/.config/systemd/user/dictation-shortcut.service @@ -1,8 +1,10 @@ [Unit] Description=Dictation shortcut on key down and key up +After=whisper-server.service +Wants=whisper-server.service [Service] -ExecStart=/usr/bin/python3 %h/bin/dictation-keyboard-hook KEY_F2 /dev/input/by-id/usb-Keychron_Keychron_Q10-if02-event-kbd +ExecStart=%h/bin/dictation-keyboard-hook KEY_F2 /dev/input/by-id/usb-Keychron_Keychron_Q10-if02-event-kbd Restart=on-failure RestartSec=5 StartLimitBurst=3 diff --git a/dotfiles/.config/systemd/user/whisper-server.service b/dotfiles/.config/systemd/user/whisper-server.service new file mode 100644 index 0000000..a60fa3a --- /dev/null +++ b/dotfiles/.config/systemd/user/whisper-server.service @@ -0,0 +1,14 @@ +[Unit] +Description=Whisper.cpp inference server +# note: ffmpeg is a dependency + +[Service] +ExecStart=/usr/bin/whisper-server \ + -m /usr/share/whisper.cpp-model-large-v3-turbo-q5_0/ggml-large-v3-turbo-q5_0.bin \ + --host 127.0.0.1 --port 8765 \ + --language auto --suppress-nst --no-timestamps --convert +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target diff --git a/dotfiles/.cspell.config.yml b/dotfiles/.cspell.config.yml index a5241f4..252dcf1 100644 --- a/dotfiles/.cspell.config.yml +++ b/dotfiles/.cspell.config.yml @@ -113,7 +113,7 @@ words: - IOUSB - IPIC - iterm - - jjrb + - jrb - kaue - kazuo - kdesu diff --git a/dotfiles/.functions.linux.sh b/dotfiles/.functions.linux.sh index ac5d53f..e47f71d 100644 --- a/dotfiles/.functions.linux.sh +++ b/dotfiles/.functions.linux.sh @@ -209,7 +209,7 @@ compress() { msg "creating tar.7z archive: $out" # tar stream → 7za via stdin (your exact pattern) - if ! tar -cf - "$src" | 7za a -si -mx=7 "$out" > /dev/null; then + if ! tar -cf - "$src" | 7za a -si -mx=7 "$out" >/dev/null; then err $LINENO "tar.7z compression failed" return 1 fi @@ -221,4 +221,3 @@ compress() { msg "done: $out" } - diff --git a/dotfiles/.functions.sh b/dotfiles/.functions.sh index 2316f7c..bc38c9c 100644 --- a/dotfiles/.functions.sh +++ b/dotfiles/.functions.sh @@ -131,10 +131,26 @@ yad() { #- - - - - - - - - - - +# todo: remove +unalias gd 2>/dev/null + +gd() { + if ! command jj root &>/dev/null; then + command git diff "$@" + return $? + fi + + command jj diff "$@" +} + +#- - - - - - - - - - - + # when there's no repo, call ls instead -jss() { +# todo: remove +unalias gss 2>/dev/null +gss() { if ! command jj root &>/dev/null; then - _git_gss "$@" + _git_gss return $? fi @@ -396,10 +412,10 @@ __jj_bookmark_set() { #---------------- # jj bookmark set on @ -jjb() { +jb() { if [[ $# == 0 ]]; then - echo "jjb bookmark set on @" - echo "'jjb foobar' jj bookmark set foobar --revision @" + echo "jb bookmark set on @" + echo "'jb foobar' jj bookmark set foobar --revision @" return fi @@ -409,10 +425,10 @@ jjb() { #---------------- # jj bookmark set on @- -jjb-() { +jb-() { if [[ $# == 0 ]]; then - echo "jjb- bookmark set on @-" - echo "'jjb- foobar' jj bookmark set foobar --revision @- --allow-backwards" + echo "jb- bookmark set on @-" + echo "'jb- foobar' jj bookmark set foobar --revision @- --allow-backwards" return fi @@ -421,8 +437,20 @@ jjb-() { #---------------- +# jj bookmark track --remote=origin +jbt() { + if [[ $# == 0 ]]; then + echo "jbt — jj bookmark track --remote=origin" + return + fi + + jj bookmark track "$1" --remote=origin +} + +#---------------- + # jj rebase --source $1 --destination $2 -jjrb() { +jrb() { if [[ $# != 2 ]]; then echo "jj rebase --source \$1 --destination \$2" return @@ -474,9 +502,9 @@ __npc() { local branch=$1 backwards_flag="$2" today_date=$(date +"%b-%d" | tr '[:upper:]' '[:lower:]') prefix=px if [ "$backwards_flag" == "-" ]; then - jjb- "$prefix-$1-$today_date" + jb- "$prefix-$1-$today_date" else - jjb "$prefix-$1-$today_date" + jb "$prefix-$1-$today_date" fi } diff --git a/dotfiles/.gitconfig b/dotfiles/.gitconfig index 7f9185a..fc036ff 100644 --- a/dotfiles/.gitconfig +++ b/dotfiles/.gitconfig @@ -1,5 +1,5 @@ [user] - name = Raphael \"Thom\" Thomazella + name = R. Thomazella email = thomazella9@gmail.com signingkey = D600E88A0C5FE062 [core] diff --git a/dotfiles/lib-git-prompt.sh b/dotfiles/lib-git-prompt.sh index cf032d5..a2e79c7 100644 --- a/dotfiles/lib-git-prompt.sh +++ b/dotfiles/lib-git-prompt.sh @@ -3,8 +3,11 @@ # bash/zsh git prompt support # # Copyright (C) 2006,2007 Shawn O. Pearce +# Copyright (C) 2025 R. Thomazella # Distributed under the GNU General Public License, version 2.0. # +# This file is a modified fork of the original git-prompt.sh. +# # This script allows you to see repository status in your prompt. # # To enable: @@ -121,7 +124,7 @@ __git_ps1_show_upstream() { fi ;; svn-remote.*.url) - svn_remote[${#svn_remote[@]} + 1]="$value" + svn_remote[${#svn_remote[@]}+1]="$value" svn_url_pattern="$svn_url_pattern\\|$value" upstream=svn+git # default upstream is SVN if available, else git ;; @@ -145,21 +148,21 @@ __git_ps1_show_upstream() { # get the upstream from the "git-svn-id: ..." in a commit message # (git-svn uses essentially the same procedure internally) local -a svn_upstream - svn_upstream=($(git log --first-parent -1 \ - --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null)) + mapfile -t svn_upstream < <(git log --first-parent -1 \ + --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null) if [[ 0 -ne ${#svn_upstream[@]} ]]; then - svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]} - svn_upstream=${svn_upstream%@*} + local svn_upstream_str=${svn_upstream[${#svn_upstream[@]}-2]} + svn_upstream_str=${svn_upstream_str%@*} local n_stop="${#svn_remote[@]}" for ((n = 1; n <= n_stop; n++)); do - svn_upstream=${svn_upstream#${svn_remote[$n]}} + svn_upstream_str=${svn_upstream_str#"${svn_remote[$n]}"} done - if [[ -z "${svn_upstream[0]}" ]]; then + if [[ -z "$svn_upstream_str" ]]; then # default branch name for checkouts with no layout: upstream=${GIT_SVN_ID:-git-svn} else - upstream=${svn_upstream#/} + upstream=${svn_upstream_str#/} fi elif [[ "svn+git" == "$upstream" ]]; then upstream="@{upstream}" @@ -331,7 +334,7 @@ __git_ps1() { local printf_format=' (%s)' if git describe --contains --all HEAD >/dev/null 2>&1; then GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) - GIT_UPSTREAM="$(git rev-parse --abbrev-ref "$GIT_BRANCH"@{upstream} 2>/dev/null)" + GIT_UPSTREAM="$(git rev-parse --abbrev-ref "${GIT_BRANCH}@{upstream}" 2>/dev/null)" export GIT_BRANCH export GIT_UPSTREAM fi diff --git a/dotfiles/lib.sh b/dotfiles/lib.sh index 3dc4bfe..b643761 100644 --- a/dotfiles/lib.sh +++ b/dotfiles/lib.sh @@ -1,5 +1,5 @@ #! /usr/bin/env bash -# Copyright 2024 Raphael Thomazella. All rights reserved. +# Copyright 2024-present R. Thomazella. All rights reserved. # Use of this source code is governed by the BSD-3-Clause # license that can be found in the LICENSE file and online # at https://opensource.org/license/BSD-3-clause. diff --git a/run b/run new file mode 100755 index 0000000..3a7b258 --- /dev/null +++ b/run @@ -0,0 +1,32 @@ +#! /usr/bin/env bash + +set -euo pipefail +shopt -s globstar +trap 'echo fatal: $0:$LINENO >&2' ERR + +cmd="${1:-help}" + +case "$cmd" in +# -- run shfmt on all bash scripts +format) + find bin dotfiles -type f -print0 \ + | xargs -0 grep -lZE '^#! ?/usr/bin/env bash|^#!/usr/bin/env bash|^#! ?/bin/bash' \ + | xargs -0 shfmt -i 2 -ln bash -w + ;; +# -- run shellcheck on all bash scripts +lint) + find bin dotfiles -type f -print0 \ + | xargs -0 grep -lZE '^#! ?/usr/bin/env bash|^#!/usr/bin/env bash|^#! ?/bin/bash' \ + | xargs -0 shellcheck -x + ;; +# -- install required dev tools +setup) + bin/setup + ;; +help | *) + echo "Usage: ./run " + echo "" + echo "Commands:" + awk '/^# -- /{desc=substr($0, index($0,"-- ")+3)} /\)$/ && desc{cmd=$0; gsub(/[[:space:]()|*]/, "", cmd); printf " %-20s %s\n", cmd, desc; desc=""}' "$0" + ;; +esac diff --git a/src/forex/main.go b/src/forex/main.go index f4d2749..5c146e2 100644 --- a/src/forex/main.go +++ b/src/forex/main.go @@ -1,4 +1,4 @@ -// Copyright 2025 Raphael Thomazella. All rights reserved. +// Copyright 2025-present R. Thomazella. All rights reserved. // Use of this source code is governed by the BSD-3-Clause // license that can be found in the LICENSE file and online // at https://opensource.org/license/BSD-3-clause.