Compare commits

...

31 Commits

Author SHA1 Message Date
88efedf26b feat: updates, docs, license fixes, new helpers 2025-02-12 01:05:37 +02:00
renovate[bot]
cdd68748e0 chore(deps): update node.js to v22.14.0 (#77)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-12 00:35:00 +02:00
github-actions[bot]
f8ff2699e6 chore: update pre-commit hooks (#76) 2025-02-10 14:19:32 +02:00
c5e06888b8 chore(config): update Brewfile, zed settings 2025-02-07 12:41:55 +02:00
renovate[bot]
4f138eee73 fix(container): update image python (3.13.1 → 3.13.2) (#75)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-07 10:02:48 +02:00
github-actions[bot]
90258e5105 chore: update pre-commit hooks (#74) 2025-02-06 13:44:34 +02:00
efc53fc9bf feat(ci): sync-labels from ivuorinen/actions 2025-02-05 09:09:31 +02:00
github-actions[bot]
f62c17d940 chore: update pre-commit hooks (#73)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-02-03 14:36:14 +02:00
github-actions[bot]
fb15b93887 chore: update pre-commit hooks (#72)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-01-30 09:44:16 +02:00
renovate[bot]
222276486a feat(github-action): update actions/setup-python (v5.3.0 → v5.4.0)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-28 22:37:48 +00:00
github-actions[bot]
4446d59e73 chore: update pre-commit hooks (#71) 2025-01-28 17:08:31 +02:00
a22709a0f0 chore(repo): add-submodules submodule ignore dirty 2025-01-28 14:54:58 +02:00
76598ad33b chore(config): tmux config tweaks, .ignore 2025-01-28 14:51:38 +02:00
56ccb7c136 chore(nvim): plugin tweaks, config tweaks 2025-01-24 01:33:58 +02:00
github-actions[bot]
b6d933d018 chore: update pre-commit hooks (#70) 2025-01-23 08:20:21 +02:00
f9856a27b9 chore(nvim): drop mini.jump, mini.move, update docs 2025-01-22 16:26:45 +02:00
b36b52ad57 chore(config): brew bundle update 2025-01-22 15:13:47 +02:00
1e60ccf49b chore(ssh): ignore submodule changes, tweak config 2025-01-22 15:12:59 +02:00
renovate[bot]
9ca9439b9a chore(deps): update node.js to v22.13.1 (#69)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-22 09:34:00 +02:00
6d30ae7e84 chore(config): aerospace - add phpstorm 2025-01-21 14:08:06 +02:00
031e124663 chore(ssh): ft=sshconfig to turingpi config 2025-01-20 14:51:37 +02:00
bb50c9fe18 chore(scripts): macos default tweaks 2025-01-20 14:50:05 +02:00
8e608de501 chore(config): aerospace tweaks 2025-01-20 14:47:22 +02:00
github-actions[bot]
8917b7736b chore: update pre-commit hooks (#68)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-01-20 11:49:36 +02:00
18ff879f1d chore(config): tms colors, depth from 10 to 3 2025-01-17 13:25:32 +02:00
c5a258d7be feat(docs): alias docs and update script 2025-01-17 13:07:15 +02:00
7525f1f71d feat(dfm): dfm apt helper commands 2025-01-16 16:19:45 +02:00
3b665bdba0 chore(nvim): tweaks to lsp, autocommands, sessions 2025-01-16 16:18:50 +02:00
99477364bd chore(bin): t - filters, sorting, tweak checks 2025-01-16 16:17:42 +02:00
github-actions[bot]
629fdf6d4c chore: update pre-commit hooks (#67) 2025-01-16 07:10:21 +02:00
1288599b1f feat(docs): aerospace keybindings and update code 2025-01-15 15:33:01 +02:00
52 changed files with 2183 additions and 579 deletions

View File

@@ -13,7 +13,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5.3.0 - uses: actions/setup-python@v5.4.0
- run: pip install pre-commit && pre-commit autoupdate - run: pip install pre-commit && pre-commit autoupdate
- uses: peter-evans/create-pull-request@v7 - uses: peter-evans/create-pull-request@v7
with: with:

23
.github/workflows/sync-labels.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
---
name: Sync labels
# yamllint disable-line rule:truthy
on:
push:
branches:
- main
paths:
- .github/workflows/sync-labels.yml
- .github/labels.yml
schedule:
- cron: "34 5 * * *"
workflow_call:
workflow_dispatch:
jobs:
SyncLabels:
permissions:
issues: write
runs-on: ubuntu-latest
steps:
- uses: ivuorinen/actions/sync-labels@main

24
.gitmodules vendored
View File

@@ -1,4 +1,4 @@
# vim: set expandtab: # vim: noexpandtab filetype=gitconfig
[submodule "dotbot"] [submodule "dotbot"]
path = tools/dotbot path = tools/dotbot
url = https://github.com/anishathalye/dotbot.git url = https://github.com/anishathalye/dotbot.git
@@ -23,47 +23,69 @@
path = config/tmux/plugins/tmux-continuum path = config/tmux/plugins/tmux-continuum
url = https://github.com/tmux-plugins/tmux-continuum url = https://github.com/tmux-plugins/tmux-continuum
ignore = dirty ignore = dirty
[submodule "tmux/tmux-sensible"] [submodule "tmux/tmux-sensible"]
path = config/tmux/plugins/tmux-sensible path = config/tmux/plugins/tmux-sensible
url = https://github.com/tmux-plugins/tmux-sensible.git url = https://github.com/tmux-plugins/tmux-sensible.git
ignore = dirty ignore = dirty
[submodule "tmux/tmux-sessionist"] [submodule "tmux/tmux-sessionist"]
path = config/tmux/plugins/tmux-sessionist path = config/tmux/plugins/tmux-sessionist
url = https://github.com/tmux-plugins/tmux-sessionist.git url = https://github.com/tmux-plugins/tmux-sessionist.git
ignore = dirty ignore = dirty
[submodule "tmux/tmux-yank"] [submodule "tmux/tmux-yank"]
path = config/tmux/plugins/tmux-yank path = config/tmux/plugins/tmux-yank
url = https://github.com/tmux-plugins/tmux-yank.git url = https://github.com/tmux-plugins/tmux-yank.git
ignore = dirty ignore = dirty
[submodule "tmux/tmux-window-name"] [submodule "tmux/tmux-window-name"]
path = config/tmux/plugins/tmux-window-name path = config/tmux/plugins/tmux-window-name
url = https://github.com/ivuorinen/tmux-window-name.git url = https://github.com/ivuorinen/tmux-window-name.git
ignore = dirty ignore = dirty
[submodule "dotbot-pip"] [submodule "dotbot-pip"]
path = tools/dotbot-pip path = tools/dotbot-pip
url = https://github.com/sobolevn/dotbot-pip.git url = https://github.com/sobolevn/dotbot-pip.git
ignore = dirty
[submodule "tmux/tmux-suspend"] [submodule "tmux/tmux-suspend"]
path = config/tmux/plugins/tmux-suspend path = config/tmux/plugins/tmux-suspend
url = https://github.com/MunifTanjim/tmux-suspend.git url = https://github.com/MunifTanjim/tmux-suspend.git
ignore = dirty
[submodule "tmux/tmux-mode-indicator"] [submodule "tmux/tmux-mode-indicator"]
path = config/tmux/plugins/tmux-mode-indicator path = config/tmux/plugins/tmux-mode-indicator
url = https://github.com/MunifTanjim/tmux-mode-indicator.git url = https://github.com/MunifTanjim/tmux-mode-indicator.git
ignore = dirty
[submodule "tmux/tmux-current-pane-hostname"] [submodule "tmux/tmux-current-pane-hostname"]
path = config/tmux/plugins/tmux-current-pane-hostname path = config/tmux/plugins/tmux-current-pane-hostname
url = https://github.com/soyuka/tmux-current-pane-hostname.git url = https://github.com/soyuka/tmux-current-pane-hostname.git
ignore = dirty
[submodule "cheat-tldr"] [submodule "cheat-tldr"]
path = config/cheat/cheatsheets/tldr path = config/cheat/cheatsheets/tldr
url = https://github.com/ivuorinen/cheatsheet-tldr.git url = https://github.com/ivuorinen/cheatsheet-tldr.git
ignore = dirty
[submodule "tmux/tmux-dark-notify"] [submodule "tmux/tmux-dark-notify"]
path = config/tmux/plugins/tmux-dark-notify path = config/tmux/plugins/tmux-dark-notify
url = https://github.com/erikw/tmux-dark-notify.git url = https://github.com/erikw/tmux-dark-notify.git
ignore = dirty
[submodule "asdf"] [submodule "asdf"]
path = local/bin/asdf path = local/bin/asdf
url = https://github.com/asdf-vm/asdf.git url = https://github.com/asdf-vm/asdf.git
ignore = dirty
[submodule "antidote"] [submodule "antidote"]
path = tools/antidote path = tools/antidote
url = https://github.com/mattmc3/antidote.git url = https://github.com/mattmc3/antidote.git
shallow = true shallow = true
ignore = dirty
[submodule "dotbot-asdf"] [submodule "dotbot-asdf"]
path = tools/dotbot-asdf path = tools/dotbot-asdf
url = https://github.com/sobolevn/dotbot-asdf url = https://github.com/sobolevn/dotbot-asdf
ignore = dirty

2
.nvmrc
View File

@@ -1 +1 @@
22.13.0 22.14.0

View File

@@ -23,7 +23,7 @@ repos:
args: [--autofix, --no-sort-keys] args: [--autofix, --no-sort-keys]
- repo: https://github.com/igorshubovych/markdownlint-cli - repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.43.0 rev: v0.44.0
hooks: hooks:
- id: markdownlint - id: markdownlint
args: [-c, .markdownlint.json, --fix] args: [-c, .markdownlint.json, --fix]
@@ -44,12 +44,12 @@ repos:
- id: shfmt - id: shfmt
- repo: https://github.com/rhysd/actionlint - repo: https://github.com/rhysd/actionlint
rev: v1.7.6 rev: v1.7.7
hooks: hooks:
- id: actionlint - id: actionlint
- repo: https://github.com/renovatebot/pre-commit-hooks - repo: https://github.com/renovatebot/pre-commit-hooks
rev: 39.100.1 rev: 39.164.1
hooks: hooks:
- id: renovate-config-validator - id: renovate-config-validator

View File

@@ -1 +1 @@
3.13.1 3.13.2

View File

@@ -46,7 +46,7 @@ git submodule add --name tmux/tmux-dark-notify \
# Takes submodules and sets them to ignore all changes # Takes submodules and sets them to ignore all changes
for MODULE in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'); do for MODULE in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'); do
echo "Ignoring submodule changes for submodule.${MODULE}..." echo "Ignoring submodule changes for submodule.${MODULE}..."
git config "submodule.${MODULE}.ignore" all git config "submodule.${MODULE}.ignore" "dirty"
done done
# Mark certain repositories shallow # Mark certain repositories shallow

View File

@@ -43,16 +43,28 @@ automatically-unhide-macos-hidden-apps = true
if.app-name-regex-substring = 'settings' # All settings if.app-name-regex-substring = 'settings' # All settings
run = ['layout floating'] run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.apple.systempreferences' # macOS System Preferences
run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.1password.1password' # 1Password
run = ['layout floating']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'org.ferdium.ferdium-app' # Ferdium, has WhatsApp etc. if.app-id = 'org.ferdium.ferdium-app' # Ferdium, has WhatsApp etc.
run = ['layout floating'] run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.jetbrains.PhpStorm' # PhpStorm
run = ['layout floating']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.apple.finder' # Finder if.app-id = 'com.apple.finder' # Finder
run = ['layout floating'] run = ['layout floating']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.apple.Preview' if.app-id = 'com.apple.Preview' # Preview
run = ['layout floating'] run = ['layout floating']
[[on-window-detected]] [[on-window-detected]]
@@ -91,6 +103,19 @@ run = ['layout floating']
if.app-id = 'com.tinyspeck.slackmacgap' # Slack if.app-id = 'com.tinyspeck.slackmacgap' # Slack
run = ['layout floating'] run = ['layout floating']
[[on-window-detected]]
if.app-id = 'md.obsidia' # Obsidian
run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.todoist.mac.Todoist' # Todoist
run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.apple.backup.launcher' # TimeMachine
run = ['layout floating']
# Possible values: (qwerty|dvorak) # Possible values: (qwerty|dvorak)
# See https://nikitabobko.github.io/AeroSpace/guide#key-mapping # See https://nikitabobko.github.io/AeroSpace/guide#key-mapping
[key-mapping] [key-mapping]
@@ -117,6 +142,9 @@ outer.left = 0
# Fallback value (if you omit the key): mode.main.binding = {} # Fallback value (if you omit the key): mode.main.binding = {}
[mode.main.binding] [mode.main.binding]
cmd-h = [] # Disable "hide application"
cmd-alt-h = [] # Disable "hide others"
# All possible keys: # All possible keys:
# - Letters. a, b, c, ..., z # - Letters. a, b, c, ..., z
# - Numbers. 0, 1, 2, ..., 9 # - Numbers. 0, 1, 2, ..., 9
@@ -154,10 +182,10 @@ alt-l = 'focus right'
# See: https://nikitabobko.github.io/AeroSpace/commands#workspace # See: https://nikitabobko.github.io/AeroSpace/commands#workspace
alt-shift-1 = 'workspace 1' # Main alt-shift-1 = 'workspace 1' # Main
alt-shift-2 = 'workspace 2' # Media alt-shift-2 = 'workspace 2' # Media
ctrl-shift-1 = 'move-node-to-workspace 1' ctrl-shift-1 = 'move-node-to-workspace 1' # Move node to Main
ctrl-shift-2 = 'move-node-to-workspace 2' ctrl-shift-2 = 'move-node-to-workspace 2' # Move node to Media
alt-shift-tab = 'workspace-back-and-forth' alt-shift-tab = 'workspace-back-and-forth' # Switch between workspaces
ctrl-shift-tab = 'move-workspace-to-monitor --wrap-around prev' ctrl-shift-tab = 'move-workspace-to-monitor --wrap-around prev'
# See: https://nikitabobko.github.io/AeroSpace/commands#mode # See: https://nikitabobko.github.io/AeroSpace/commands#mode

View File

@@ -61,30 +61,28 @@ brew "apr"
brew "apr-util" brew "apr-util"
# Password hashing library and CLI utility # Password hashing library and CLI utility
brew "argon2" brew "argon2"
# Automatic configure script builder
brew "autoconf"
# Tool for generating GNU Standards-compliant Makefiles
brew "automake"
# GNU multiple precision arithmetic library
brew "gmp"
# GNU File, Shell, and Text utilities
brew "coreutils"
# Extendable version manager with support for Ruby, Node.js, Erlang & more
brew "asdf"
# Spell checker with better logic than ispell # Spell checker with better logic than ispell
brew "aspell" brew "aspell"
# Automatic configure script builder
brew "autoconf"
# Collection of over 500 reusable autoconf macros # Collection of over 500 reusable autoconf macros
brew "autoconf-archive" brew "autoconf-archive"
# GNU multiple precision arithmetic library
brew "gmp"
# Package compiler and linker metadata toolkit # Package compiler and linker metadata toolkit
brew "pkgconf" brew "pkgconf"
# Automated text file generator # Automated text file generator
brew "autogen" brew "autogen"
# Tool for generating GNU Standards-compliant Makefiles
brew "automake"
# Official Amazon AWS command-line interface # Official Amazon AWS command-line interface
brew "awscli" brew "awscli"
# Bourne-Again SHell, a UNIX command interpreter # Bourne-Again SHell, a UNIX command interpreter
brew "bash" brew "bash"
# Clone of cat(1) with syntax highlighting and Git integration # Clone of cat(1) with syntax highlighting and Git integration
brew "bat" brew "bat"
# GNU File, Shell, and Text utilities
brew "coreutils"
# Bash Automated Testing System # Bash Automated Testing System
brew "bats-core" brew "bats-core"
# Parser generator # Parser generator
@@ -97,6 +95,8 @@ brew "fontconfig"
brew "gettext" brew "gettext"
# Core application library for C # Core application library for C
brew "glib" brew "glib"
# Prevent cloud misconfigurations during build-time for IaC tools
brew "checkov"
# Human-friendly and fast alternative to cut and (sometimes) awk # Human-friendly and fast alternative to cut and (sometimes) awk
brew "choose-rust" brew "choose-rust"
# Cross-platform make # Cross-platform make
@@ -149,8 +149,6 @@ brew "unbound"
brew "gnutls" brew "gnutls"
# GNU Pretty Good Privacy (PGP) package # GNU Pretty Good Privacy (PGP) package
brew "gnupg" brew "gnupg"
# Open source programming language to build simple/reliable/efficient software
brew "go"
# Library access to GnuPG # Library access to GnuPG
brew "gpgme" brew "gpgme"
# Manage your GnuPG keys with ease! # Manage your GnuPG keys with ease!
@@ -303,8 +301,6 @@ brew "shivammathur/php/php@7.4"
brew "shivammathur/php/php@8.0", link: true brew "shivammathur/php/php@8.0", link: true
# Find & fix known vulnerabilities in open-source dependencies # Find & fix known vulnerabilities in open-source dependencies
brew "snyk/tap/snyk" brew "snyk/tap/snyk"
# Command-line interface for 1Password
cask "1password-cli"
# AeroSpace is an i3-like tiling window manager for macOS # AeroSpace is an i3-like tiling window manager for macOS
cask "aerospace" cask "aerospace"
# Text editor # Text editor

View File

@@ -93,19 +93,16 @@ autocmd({ 'FileType' }, {
-- Set filetype for SSH config directory -- Set filetype for SSH config directory
-- Pattern handles directories with files like: -- Pattern handles directories with files like:
-- .dotfiles/ssh/config.d/*, .ssh/config.local, .ssh/config.work -- .dotfiles/ssh/config.d/*, .ssh/config.local, .ssh/config.work,
-- .ssh/shared.d/*, .ssh/local.d/*
autocmd({ 'BufRead', 'BufNewFile' }, { autocmd({ 'BufRead', 'BufNewFile' }, {
desc = 'Set filetype for SSH config directory', desc = 'Set filetype for SSH config directory',
pattern = { pattern = {
'*/?.ssh/{config|shared}.d/*', '*/?.ssh/{config|shared|local}.d/*',
'*/?.ssh/config.local', '*/?.ssh/config.local',
'*/?.ssh/config.work', '*/?.ssh/config.work',
}, },
command = 'set filetype=sshconfig', command = 'set filetype=sshconfig',
}) })
autocmd('QuickFixCmdPost', {
callback = function() vim.cmd [[Trouble qflist open]] end,
})
-- vim: ts=2 sts=2 sw=2 et -- vim: ts=2 sts=2 sw=2 et

View File

@@ -18,11 +18,14 @@ return {
}, },
}, },
{ 'L3MON4D3/LuaSnip', version = 'v2.*' }, { 'L3MON4D3/LuaSnip', version = 'v2.*', build = 'make install_jsregexp' },
-- Set of preconfigured snippets for different languages. -- Set of preconfigured snippets for different languages.
-- https://github.com/rafamadriz/friendly-snippets -- https://github.com/rafamadriz/friendly-snippets
{ 'rafamadriz/friendly-snippets' }, {
'rafamadriz/friendly-snippets',
config = function() require('luasnip.loaders.from_vscode').lazy_load() end,
},
-- Lua plugin to turn github copilot into a cmp source -- Lua plugin to turn github copilot into a cmp source
-- https://github.com/giuxtaposition/blink-cmp-copilot -- https://github.com/giuxtaposition/blink-cmp-copilot

View File

@@ -42,12 +42,6 @@ local lsp_servers = {
diagnostics = { diagnostics = {
globals = { globals = {
'vim', 'vim',
-- busted
'describe',
'it',
'before_each',
'after_each',
'assert',
}, },
disable = { disable = {
-- Ignore lua_ls noisy `missing-fields` warnings -- Ignore lua_ls noisy `missing-fields` warnings
@@ -55,7 +49,7 @@ local lsp_servers = {
}, },
}, },
hint = { hint = {
enable = false, enable = true,
arrayIndex = 'Auto', arrayIndex = 'Auto',
await = true, await = true,
paramName = 'All', paramName = 'All',
@@ -154,70 +148,61 @@ return {
-- https://github.com/Bilal2453/luvit-meta -- https://github.com/Bilal2453/luvit-meta
{ 'Bilal2453/luvit-meta', lazy = true }, { 'Bilal2453/luvit-meta', lazy = true },
-- Quickstart configs for Nvim LSP
-- https://github.com/neovim/nvim-lspconfig
{ 'neovim/nvim-lspconfig' },
-- Portable package manager for Neovim that runs everywhere Neovim runs.
-- Easily install and manage LSP servers, DAP servers, linters, and formatters.
-- https://github.com/williamboman/mason.nvim
{
'williamboman/mason.nvim',
version = '*',
cmd = 'Mason',
run = ':MasonUpdate',
opts = {},
},
-- Extensible UI for Neovim notifications and LSP progress messages.
-- https://github.com/j-hui/fidget.nvim
{
'j-hui/fidget.nvim',
version = '*',
opts = {},
},
-- Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.
-- https://github.com/williamboman/mason-lspconfig.nvim
{ 'williamboman/mason-lspconfig.nvim' },
-- Install and upgrade third party tools automatically
-- https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim
{
'WhoIsSethDaniel/mason-tool-installer.nvim',
version = '*',
opts = {
auto_install = true,
auto_update = true,
ensure_installed = mason_tools,
},
},
-- JSON schemas for Neovim
-- https://github.com/b0o/SchemaStore.nvim
{ 'b0o/schemastore.nvim' },
-- Performant, batteries-included completion plugin for Neovim
-- https://github.com/saghen/blink.cmp
-- See lua/plugins/blink.lua for configs
{ 'saghen/blink.cmp' },
-- A simple wrapper for nvim-lspconfig and mason-lspconfig -- A simple wrapper for nvim-lspconfig and mason-lspconfig
-- to easily setup LSP servers. -- to easily setup LSP servers.
-- https://github.com/junnplus/lsp-setup.nvim -- https://github.com/junnplus/lsp-setup.nvim
{ {
'junnplus/lsp-setup.nvim', 'junnplus/lsp-setup.nvim',
dependencies = {
-- Quickstart configs for Nvim LSP
-- https://github.com/neovim/nvim-lspconfig
{ 'neovim/nvim-lspconfig' },
-- Portable package manager for Neovim that runs everywhere Neovim runs.
-- Easily install and manage LSP servers, DAP servers, linters, and formatters.
-- https://github.com/williamboman/mason.nvim
{
'williamboman/mason.nvim',
version = '*',
cmd = 'Mason',
run = ':MasonUpdate',
opts = {},
},
-- Extensible UI for Neovim notifications and LSP progress messages.
-- https://github.com/j-hui/fidget.nvim
{
'j-hui/fidget.nvim',
version = '*',
opts = {},
},
-- Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.
-- https://github.com/williamboman/mason-lspconfig.nvim
{ 'williamboman/mason-lspconfig.nvim' },
-- Install and upgrade third party tools automatically
-- https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim
{
'WhoIsSethDaniel/mason-tool-installer.nvim',
version = '*',
opts = {
auto_install = true,
auto_update = true,
ensure_installed = mason_tools,
},
},
-- JSON schemas for Neovim
-- https://github.com/b0o/SchemaStore.nvim
{ 'b0o/schemastore.nvim' },
-- Performant, batteries-included completion plugin for Neovim
-- https://github.com/saghen/blink.cmp
-- See lua/plugins/blink.lua for configs
{ 'saghen/blink.cmp' },
},
opts = { opts = {
default_mappings = false, default_mappings = false,
mappings = {
gd = 'lua require"telescope.builtin".lsp_definitions()',
gi = 'lua require"telescope.builtin".lsp_implementations()',
gr = 'lua require"telescope.builtin".lsp_references()',
},
inlay_hints = {
enabled = true,
},
servers = lsp_servers, servers = lsp_servers,
}, },
config = function(_, opts) config = function(_, opts)
@@ -321,16 +306,6 @@ return {
'stevearc/conform.nvim', 'stevearc/conform.nvim',
event = { 'BufWritePre' }, event = { 'BufWritePre' },
cmd = { 'ConformInfo' }, cmd = { 'ConformInfo' },
keys = {
{
'<leader>cf',
function()
require('conform').format { async = true, lsp_format = 'fallback' }
end,
mode = '',
desc = 'Format buffer',
},
},
opts = { opts = {
notify_on_error = false, notify_on_error = false,
---@type nil|conform.FormatOpts|fun(bufnr: integer): nil|conform.FormatOpts ---@type nil|conform.FormatOpts|fun(bufnr: integer): nil|conform.FormatOpts
@@ -346,9 +321,9 @@ return {
lsp_format_opt = 'fallback' lsp_format_opt = 'fallback'
end end
-- Disable autoformat for files in a certain path -- Disable autoformat for files in a certain paths
local bufname = vim.api.nvim_buf_get_name(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr)
if bufname:match '/node_modules/' then return end if bufname:match '/node_modules|vendor/' then return end
return { return {
timeout_ms = 500, timeout_ms = 500,

View File

@@ -165,20 +165,6 @@ return {
-- Replaced lukas-reineke/indent-blankline.nvim -- Replaced lukas-reineke/indent-blankline.nvim
require('mini.indentscope').setup() require('mini.indentscope').setup()
-- Jump to next/previous single character
require('mini.jump').setup {
mappings = {
forward = 'f',
backward = 'F',
forward_till = 't',
backward_till = 'T',
repeat_jump = ';',
},
}
-- Move lines and blocks of text
require('mini.move').setup()
-- Text edit operators -- Text edit operators
-- g= - Evaluate text and replace with output -- g= - Evaluate text and replace with output
-- gx - Exchange text regions -- gx - Exchange text regions
@@ -223,11 +209,11 @@ return {
content = { content = {
active = function() active = function()
local mode, mode_hl = sl.section_mode { trunc_width = 120 } local mode, mode_hl = sl.section_mode { trunc_width = 120 }
local git = sl.section_git { trunc_width = 75 } local git = sl.section_git { trunc_width = 9999 }
local diagnostics = sl.section_diagnostics { trunc_width = 75 } local diagnostics = sl.section_diagnostics { trunc_width = 9999 }
local filename = sl.section_filename { trunc_width = 9999 } local filename = sl.section_filename { trunc_width = 9999 }
local fileinfo = sl.section_fileinfo { trunc_width = 120 } local fileinfo = sl.section_fileinfo { trunc_width = 9999 }
local location = sl.section_location { trunc_width = 75 } local location = sl.section_location { trunc_width = 9999 }
return sl.combine_groups { return sl.combine_groups {
{ hl = mode_hl, strings = { mode } }, { hl = mode_hl, strings = { mode } },
{ hl = 'statuslineDevinfo', strings = { git, diagnostics } }, { hl = 'statuslineDevinfo', strings = { git, diagnostics } },

View File

@@ -10,6 +10,28 @@ return {
'~/Downloads', '~/Downloads',
'~/Library', '~/Library',
}, },
bypass_save_filetypes = {
'PlenaryTestPopup',
'alpha',
'checkhealth',
'dashboard',
'dbout',
'gitsigns.blame',
'grug-far',
'help',
'lspinfo',
'man',
'neo-tree',
'neotest-output',
'neotest-output-panel',
'neotest-summary',
'notify',
'qf',
'spectre_panel',
'startuptime',
'trouble',
'tsplayground',
},
-- log_level = 'debug', -- log_level = 'debug',
}, },
}, },

View File

@@ -2,4 +2,9 @@ default_session = "main"
[[search_dirs]] [[search_dirs]]
path = "~/Code" path = "~/Code"
depth = 10 depth = 3
[picker_colors]
highlight_color = "#21202e"
highlight_text_color = "#86e1fc"
border_color = "#524f67"

1
config/tmux/.ignore Normal file
View File

@@ -0,0 +1 @@
plugins/*

View File

@@ -40,6 +40,8 @@ run-shell "$TMUX_PLUGINS/tmux-sensible/sensible.tmux"
run-shell "$TMUX_PLUGINS/tmux-window-name/tmux_window_name.tmux" run-shell "$TMUX_PLUGINS/tmux-window-name/tmux_window_name.tmux"
run-shell "$TMUX_PLUGINS/tmux-mode-indicator/mode_indicator.tmux" run-shell "$TMUX_PLUGINS/tmux-mode-indicator/mode_indicator.tmux"
run-shell "$TMUX_PLUGINS/tmux-suspend/suspend.tmux" run-shell "$TMUX_PLUGINS/tmux-suspend/suspend.tmux"
run-shell "$TMUX_PLUGINS/tmux-continuum/continuum.tmux"
run-shell "$TMUX_PLUGINS/tmux-sessionist/sessionist.tmux"
run-shell "$TMUX_PLUGINS/tmux-yank/yank.tmux" run-shell "$TMUX_PLUGINS/tmux-yank/yank.tmux"
run-shell "$TMUX_PLUGINS/tmux-current-pane-hostname/current_pane_hostname.tmux" run-shell "$TMUX_PLUGINS/tmux-current-pane-hostname/current_pane_hostname.tmux"
run-shell "$TMUX_PLUGINS/tmux-dark-notify/main.tmux" run-shell "$TMUX_PLUGINS/tmux-dark-notify/main.tmux"

View File

@@ -1,8 +1,11 @@
{ {
"telemetry": {
"metrics": false
},
"assistant": { "assistant": {
"default_model": { "default_model": {
"provider": "copilot_chat", "provider": "copilot_chat",
"model": "gpt-4o" "model": "claude-3-5-sonnet"
}, },
"version": "2" "version": "2"
}, },

View File

@@ -0,0 +1,66 @@
# aerospace keybindings
## main
| Key | Command(s) and actions |
|-----------------|-----------------------------------------------|
| alt-a | mode apps |
| alt-h | focus left |
| alt-j | focus down |
| alt-k | focus up |
| alt-l | focus right |
| alt-m | mode move |
| alt-s | mode service |
| alt-shift-1 | workspace 1 |
| alt-shift-2 | workspace 2 |
| alt-shift-tab | workspace-back-and-forth |
| ctrl-shift-1 | move-node-to-workspace 1 |
| ctrl-shift-2 | move-node-to-workspace 2 |
| ctrl-shift-tab | move-workspace-to-monitor --wrap-around prev |
## apps
| Key | Command(s) and actions |
|------|----------------------------------------------------------------------|
| b | exec-and-forget open -a /Applications/Brave Browser.app; mode main |
| c | exec-and-forget open -a /Applications/Ferdium.app; mode main |
| esc | reload-config; mode main |
| g | exec-and-forget open -a /Applications/Ghostty.app; mode main |
| o | exec-and-forget open -a /Applications/Obsidian.app; mode main |
| s | exec-and-forget open -a /Applications/Slack.app; mode main |
| t | exec-and-forget open -a /Applications/TIDAL.app; mode main |
| w | exec-and-forget open -a /Applications/WezTerm.app; mode main |
## move
| Key | Command(s) and actions |
|--------------|--------------------------------------------------|
| 1 | move-node-to-workspace 1 --focus-follows-window |
| 2 | move-node-to-workspace 2 --focus-follows-window |
| ctrl-h | resize smart -70 |
| ctrl-l | resize smart +70 |
| esc | reload-config; mode main |
| h | move left |
| j | move down |
| k | move up |
| l | move right |
| r | flatten-workspace-tree; mode main |
| shift-h | join-with left |
| shift-j | join-with down |
| shift-k | join-with up |
| shift-l | join-with right |
| shift-left | resize smart +70 |
| shift-right | resize smart -70 |
## service
| Key | Command(s) and actions |
|------------|-------------------------------------------|
| backspace | close-all-windows-but-current; mode main |
| esc | reload-config; mode main |
| f | layout floating tiling; mode main |
| r | flatten-workspace-tree; mode main |
File generated: 2025-01-15 13:32:41
Config file: [config/aerospace/aerospace.toml](./../config/aerospace/aerospace.toml)

52
docs/alias.md Normal file
View File

@@ -0,0 +1,52 @@
# Alias Commands
This file lists all aliases defined in `config/alias`.
| Alias | Command |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `....` | `cd ../../..` |
| `...` | `cd ../..` |
| `..` | `cd ..` |
| `.` | `cd $HOME` |
| `.b` | `cd $XDG_BIN_HOME` |
| `.c` | `cd $HOME/Code` |
| `.d` | `cd $DOTFILES` |
| `.l` | `cd $HOME/.local` |
| `.o` | `cd $HOME/Code/ivuorinen/obsidian/` |
| `art` | `[ -f artisan ] && php artisan \|\| php vendor/bin/artisan` |
| `cd..` | `cd ..` |
| `cdgr` | `cd "$(get_git_root)"` |
| `dn` | `du -chd1` |
| `flush` | `dscacheutil -flushcache` |
| `grep` | `grep --color` |
| `hide` | `defaults write com.apple.finder AppleShowAllFiles -bool false; killall Finder` |
| `ips` | `ifconfig -a \| grep -o 'inet6\? \(\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\)\\|[a-fA-F0-9:]\+\)' \| sed -e 's/inet6* //' \| sort` |
| `irssi` | `irssi --config=$XDG_CONFIG_HOME/irssi/config --home=$XDG_CONFIG_HOME/irssi` |
| `isodate` | `date +'%Y-%m-%d'` |
| `l` | `ls -a` |
| `ll` | `ls -la` |
| `localip` | `ipconfig getifaddr en1` |
| `mirror_site` | `wget -m -k -K -E -e robots=off` |
| `peek` | `tee >(cat 1>&2)` |
| `pubkey` | `more ~/.ssh/id_rsa.pub \| pbcopy \| echo '=> Public key copied to pasteboard.'` |
| `sail` | `[ -f sail ] && bash sail \|\| bash vendor/bin/sail` |
| `show` | `defaults write com.apple.finder AppleShowAllFiles -bool true; killall Finder` |
| `sl` | `ls` |
| `svn` | `svn --config-dir $XDG_CONFIG_HOME/subversion` |
| `trivy_scan` | `docker run -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ aquasec/trivy` |
| `updatedb` | `sudo /usr/libexec/locate.updatedb` |
| `vi` | `nvim` |
| `vim` | `nvim` |
| `watchx` | `watch -dpbc` |
| `wget` | `wget --hsts-file=$XDG_DATA_HOME/wget-hsts` |
| `x-datetime` | `date +'%Y-%m-%d %H:%M:%S'` |
| `x-ip` | `dig +short myip.opendns.com @resolver1.opendns.com` |
| `x-timestamp` | `date +'%s'` |
| `xdg` | `xdg-ninja --skip-ok --skip-unsupported` |
| `zapall` | `zapds && zappyc` |
| `zapds` | `find . -name ".DS_Store" -print -delete` |
| `zappyc` | `find . -type f -name '*.pyc' -ls -delete` |
| `zedit` | `$EDITOR ~/.dotfiles` |
Total aliases: 43
Last updated: Fri 17 Jan 2025 13:06:59 EET

View File

@@ -54,7 +54,7 @@ n <Space>xq * :Trouble quickfix<CR>
Quickfix Quickfix
n <Space>xl * :Trouble loclist<CR> n <Space>xl * :Trouble loclist<CR>
Location List Location List
n <Space>xd * :Trouble document_diagnostics<CR> n <Space>xd * :Trouble diagnostics<CR>
Document Diagnostics Document Diagnostics
n <Space>sx * :Telescope import<CR> n <Space>sx * :Telescope import<CR>
Telescope: Import Telescope: Import
@@ -64,7 +64,7 @@ n <Space>ss * :Telescope treesitter<CR>
Treesitter Treesitter
n <Space>sq * :Telescope quickfix<CR> n <Space>sq * :Telescope quickfix<CR>
Quickfix Quickfix
n <Space>sp * :lua require("telescope").extensions.lazy_plugins.lazy_plugins()<CR> n <Space>sp * ~/.config/nvim/lua/keymaps.lua
Lazy Plugins Lazy Plugins
n <Space>so * :Telescope oldfiles<CR> n <Space>so * :Telescope oldfiles<CR>
Old Files Old Files
@@ -80,14 +80,6 @@ n <Space>sd * :Telescope diagnostics<CR>
Search Diagnostics Search Diagnostics
n <Space>sc * :Telescope commands<CR> n <Space>sc * :Telescope commands<CR>
Commands Commands
n <Space>pt * :PhpactorTransform<CR>
PHPactor: Transform
n <Space>ps * :PhpactorClassSearch<CR>
PHPactor: Class Search
n <Space>pn * :PhpactorClassNew<CR>
PHPactor: Class New
n <Space>pm * :PhpactorContextMenu<CR>
PHPactor: Context Menu
n <Space>/ * ~/.config/nvim/lua/keymaps.lua n <Space>/ * ~/.config/nvim/lua/keymaps.lua
Fuzzily search in current buffer Fuzzily search in current buffer
n <Space>, * :Telescope buffers<CR> n <Space>, * :Telescope buffers<CR>
@@ -104,37 +96,33 @@ n <Space>cbd * <Cmd>CBd<CR>
CB: Remove a box CB: Remove a box
n <Space>cbb * <Cmd>CBccbox<CR> n <Space>cbb * <Cmd>CBccbox<CR>
CB: Box Title CB: Box Title
n <Space>cw * :Lspsaga diagnostic_jump_next<CR> n <Space>cwd * ~/.config/nvim/lua/keymaps.lua
Diagnostic Jump Next Dynamic Workspace Symbols
n <Space>cv * :Lspsaga diagnostic_jump_prev<CR> n <Space>cws * ~/.config/nvim/lua/keymaps.lua
Diagnostic Jump Prev Workspace Symbols
n <Space>cu * :Lspsaga preview_definition<CR> n <Space>ct * ~/.config/nvim/lua/keymaps.lua
Preview Definition treesitter
n <Space>cT * :Telescope lsp_type_definitions<CR>
LSP Type Definitions
n <Space>ct * :Lspsaga peek_type_definition<CR>
Peek Type Definition
n <Space>cs * :Telescope lsp_document_symbols<CR> n <Space>cs * :Telescope lsp_document_symbols<CR>
LSP Document Symbols LSP Document Symbols
n <Space>cR * :Lspsaga rename ++project<CR> n <Space>cr * ~/.local/share/bob/v0.10.2/nvim-macos-arm64/share/nvim/runtime/lua/vim/lsp/buf.lua
Rename Project wide
n <Space>cr * :Lspsaga rename<CR>
Rename Rename
n <Space>cp * :Lspsaga peek_definition<CR> n <Space>cp * ~/.config/nvim/lua/keymaps.lua
Peek Definition Type Definition
n <Space>cl * :Lspsaga show_cursor_diagnostics<CR> n <Space>ci * ~/.config/nvim/lua/keymaps.lua
Cursor Diagnostics
n <Space>ci * :Lspsaga implement<CR>
Implementations Implementations
n <Space>cg * :lua require("neogen").generate()<CR> n <Space>cg * :lua require("neogen").generate()<CR>
Generate annotations Generate annotations
n <Space>cd * :Lspsaga show_line_diagnostics<CR> x <Space>cf * :lua vim.lsp.buf.format()<CR>
Line Diagnostics Format
n <Space>cco * :Lspsaga outgoing_calls<CR> n <Space>cf * :lua vim.lsp.buf.format()<CR>
Outgoing Calls Format
n <Space>cci * :Lspsaga incoming_calls<CR> n <Space>cd * ~/.config/nvim/lua/keymaps.lua
Incoming Calls Definitions
n <Space>ca * :Lspsaga code_action<CR> n <Space>cco * ~/.config/nvim/lua/keymaps.lua
Outgoing calls
n <Space>cci * ~/.config/nvim/lua/keymaps.lua
Incoming calls
n <Space>ca * :lua vim.lsp.buf.code_action()<CR>
Code Action Code Action
n <Space>bw * :lua MiniBufremove.wipeout()<CR> n <Space>bw * :lua MiniBufremove.wipeout()<CR>
Wipeout Wipeout
@@ -150,6 +138,14 @@ n <Space>bd * :lua MiniBufremove.delete()<CR>
Delete Delete
n <Space>ba * :%bd|e#|bd#<CR> n <Space>ba * :%bd|e#|bd#<CR>
Close all except current Close all except current
n <Space>apt * :PhpactorTransform<CR>
PHPactor: Transform
n <Space>aps * :PhpactorClassSearch<CR>
PHPactor: Class Search
n <Space>apn * :PhpactorClassNew<CR>
PHPactor: Class New
n <Space>apm * :PhpactorContextMenu<CR>
PHPactor: Context Menu
n <Space>av * :silent TestVisit<CR> n <Space>av * :silent TestVisit<CR>
Test Visit Test Visit
n <Space>al * :silent TestLast<CR> n <Space>al * :silent TestLast<CR>
@@ -184,8 +180,6 @@ n <Space>tmc * <Cmd>setlocal cursorline! cursorline?<CR>
Toggle 'cursorline' Toggle 'cursorline'
n <Space>tmb * <Cmd>lua vim.o.bg = vim.o.bg == "dark" and "light" or "dark"; print(vim.o.bg)<CR> n <Space>tmb * <Cmd>lua vim.o.bg = vim.o.bg == "dark" and "light" or "dark"; print(vim.o.bg)<CR>
Toggle 'background' Toggle 'background'
<Space>cf * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua
Format buffer
x # * vim/_defaults.lua x # * vim/_defaults.lua
:help v_#-default :help v_#-default
o % <Plug>(MatchitOperationForward) o % <Plug>(MatchitOperationForward)
@@ -194,17 +188,11 @@ n % <Plug>(MatchitNormalForward)
n & * :&&<CR> n & * :&&<CR>
:help &-default :help &-default
n '? & :<C-U>echo ":Start" dispatch#start_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR> n '? & :<C-U>echo ":Start" dispatch#start_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR>
n '! & <SNR>30_:.Start! n '! & <SNR>28_:.Start!
n '<Space> & <SNR>30_:.Start<Space> n '<Space> & <SNR>28_:.Start<Space>
n '<CR> & <SNR>30_:.Start<CR> n '<CR> & <SNR>28_:.Start<CR>
x * * vim/_defaults.lua x * * vim/_defaults.lua
:help v_star-default :help v_star-default
o ; * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/jump.lua
Repeat jump
x ; * <Cmd>lua MiniJump.jump()<CR>
Repeat jump
n ; * <Cmd>lua MiniJump.jump()<CR>
Repeat jump
v < * <gv v < * <gv
Indent Left Indent Left
n < * <gv n < * <gv
@@ -217,31 +205,19 @@ n @ * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/clue.lua
Execute macro without 'mini.clue' triggers Execute macro without 'mini.clue' triggers
x @ * mode() ==# 'V' ? ':normal! @'.getcharstr().'<CR>' : '@' x @ * mode() ==# 'V' ? ':normal! @'.getcharstr().'<CR>' : '@'
:help v_@-default :help v_@-default
o F * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/jump.lua n K * :lua vim.lsp.buf.hover()<CR>
Jump backward
x F * <Cmd>lua MiniJump.smart_jump(true, false)<CR>
Jump backward
n F * <Cmd>lua MiniJump.smart_jump(true, false)<CR>
Jump backward
n K * :Lspsaga hover_doc<CR>
Hover Documentation Hover Documentation
n Q * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/clue.lua n Q * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/clue.lua
Execute macro without 'mini.clue' triggers Execute macro without 'mini.clue' triggers
x Q * mode() ==# 'V' ? ':normal! @<C-R>=reg_recorded()<CR><CR>' : 'Q' x Q * mode() ==# 'V' ? ':normal! @<C-R>=reg_recorded()<CR><CR>' : 'Q'
:help v_Q-default :help v_Q-default
o T * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/jump.lua
Jump backward till
x T * <Cmd>lua MiniJump.smart_jump(true, true)<CR>
Jump backward till
n T * <Cmd>lua MiniJump.smart_jump(true, true)<CR>
Jump backward till
n Y * y$ n Y * y$
:help Y-default :help Y-default
n Zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua o Zk * ~/.config/nvim/lua/keymaps.lua
Flash Treesitter Flash Treesitter
o Zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua x Zk * ~/.config/nvim/lua/keymaps.lua
Flash Treesitter Flash Treesitter
x Zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua n Zk * ~/.config/nvim/lua/keymaps.lua
Flash Treesitter Flash Treesitter
o [% <Plug>(MatchitOperationMultiBackward) o [% <Plug>(MatchitOperationMultiBackward)
x [% <Plug>(MatchitVisualMultiBackward) x [% <Plug>(MatchitVisualMultiBackward)
@@ -289,10 +265,10 @@ n ]h * <Cmd>lua MiniDiff.goto_hunk('next')<CR>
Next hunk Next hunk
n ]d * vim/_defaults.lua n ]d * vim/_defaults.lua
Jump to the next diagnostic Jump to the next diagnostic
n `? & <SNR>30_:.FocusDispatch<CR> n `? & <SNR>28_:.FocusDispatch<CR>
n `! & <SNR>30_:.Dispatch! n `! & <SNR>28_:.Dispatch!
n `<Space> & <SNR>30_:.Dispatch<Space> n `<Space> & <SNR>28_:.Dispatch<Space>
n `<CR> & <SNR>30_:.Dispatch<CR> n `<CR> & <SNR>28_:.Dispatch<CR>
x a% <Plug>(MatchitVisualTextObject) x a% <Plug>(MatchitVisualTextObject)
o ax <Plug>(textobj-xmlattr-attr-a) o ax <Plug>(textobj-xmlattr-attr-a)
x ax <Plug>(textobj-xmlattr-attr-a) x ax <Plug>(textobj-xmlattr-attr-a)
@@ -300,25 +276,19 @@ o ai * <Cmd>lua MiniIndentscope.textobject(true)<CR>
Object scope with border Object scope with border
x ai * <Cmd>lua MiniIndentscope.textobject(true)<CR> x ai * <Cmd>lua MiniIndentscope.textobject(true)<CR>
Object scope with border Object scope with border
o f * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/jump.lua
Jump forward
x f * <Cmd>lua MiniJump.smart_jump(false, false)<CR>
Jump forward
n f * <Cmd>lua MiniJump.smart_jump(false, false)<CR>
Jump forward
n gR * :RegexplainerToggle<CR> n gR * :RegexplainerToggle<CR>
Toggle Regexplainer Toggle Regexplainer
o g% <Plug>(MatchitOperationBackward) o g% <Plug>(MatchitOperationBackward)
x g% <Plug>(MatchitVisualBackward) x g% <Plug>(MatchitVisualBackward)
n g% <Plug>(MatchitNormalBackward) n g% <Plug>(MatchitNormalBackward)
n g`? & :<C-U>echo ":Spawn" dispatch#spawn_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR> n g`? & :<C-U>echo ":Spawn" dispatch#spawn_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR>
n g`! & <SNR>30_:.Spawn! n g`! & <SNR>28_:.Spawn!
n g`<Space> & <SNR>30_:.Spawn<Space> n g`<Space> & <SNR>28_:.Spawn<Space>
n g`<CR> & <SNR>30_:.Spawn<CR> n g`<CR> & <SNR>28_:.Spawn<CR>
n g'? & :<C-U>echo ":Spawn" dispatch#spawn_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR> n g'? & :<C-U>echo ":Spawn" dispatch#spawn_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR>
n g'! & <SNR>30_:.Spawn! n g'! & <SNR>28_:.Spawn!
n g'<Space> & <SNR>30_:.Spawn<Space> n g'<Space> & <SNR>28_:.Spawn<Space>
n g'<CR> & <SNR>30_:.Spawn<CR> n g'<CR> & <SNR>28_:.Spawn<CR>
x gS * :<C-U>lua MiniSplitjoin.toggle({ region = MiniSplitjoin.get_visual_region() })<CR> x gS * :<C-U>lua MiniSplitjoin.toggle({ region = MiniSplitjoin.get_visual_region() })<CR>
Toggle arguments Toggle arguments
n gS * v:lua.MiniSplitjoin.operator("toggle") . " " n gS * v:lua.MiniSplitjoin.operator("toggle") . " "
@@ -400,9 +370,9 @@ x k * v:count == 0 ? 'gk' : 'k'
n k * v:count == 0 ? 'gk' : 'k' n k * v:count == 0 ? 'gk' : 'k'
Move up Move up
n m? & :<C-U>echo ":Dispatch" dispatch#make_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR> n m? & :<C-U>echo ":Dispatch" dispatch#make_focus(v:count > 1 ? 0 : v:count ? line(".") : -1)<CR>
n m! & <SNR>30_:.Make! n m! & <SNR>28_:.Make!
n m<Space> & <SNR>30_:.Make<Space> n m<Space> & <SNR>28_:.Make<Space>
n m<CR> & <SNR>30_:.Make<CR> n m<CR> & <SNR>28_:.Make<CR>
n shn * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua n shn * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua
Highlight next surrounding Highlight next surrounding
n sFn * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua n sFn * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua
@@ -439,17 +409,11 @@ n sd * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua
Delete surrounding Delete surrounding
n sa * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua n sa * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/surround.lua
Add surrounding Add surrounding
o t * ~/.local/share/nvim/lazy/mini.nvim/lua/mini/jump.lua o zk * ~/.config/nvim/lua/keymaps.lua
Jump forward till
x t * <Cmd>lua MiniJump.smart_jump(false, true)<CR>
Jump forward till
n t * <Cmd>lua MiniJump.smart_jump(false, true)<CR>
Jump forward till
o zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua
Flash Flash
x zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua x zk * ~/.config/nvim/lua/keymaps.lua
Flash Flash
n zk * ~/.local/share/nvim/lazy/lazy.nvim/lua/lazy/core/handler/keys.lua n zk * ~/.config/nvim/lua/keymaps.lua
Flash Flash
n <F1> * :FloatermToggle<CR> n <F1> * :FloatermToggle<CR>
Toggle Floaterm Toggle Floaterm
@@ -492,30 +456,30 @@ x <Plug>(MatchitVisualBackward) * :<C-U>call matchit#Match_wrapper('',0,'v')<CR
x <Plug>(MatchitVisualForward) * :<C-U>call matchit#Match_wrapper('',1,'v')<CR>:if col("''") != col("$") | exe ":normal! m'" | endif<CR>gv`` x <Plug>(MatchitVisualForward) * :<C-U>call matchit#Match_wrapper('',1,'v')<CR>:if col("''") != col("$") | exe ":normal! m'" | endif<CR>gv``
n <Plug>(MatchitNormalBackward) * :<C-U>call matchit#Match_wrapper('',0,'n')<CR> n <Plug>(MatchitNormalBackward) * :<C-U>call matchit#Match_wrapper('',0,'n')<CR>
n <Plug>(MatchitNormalForward) * :<C-U>call matchit#Match_wrapper('',1,'n')<CR> n <Plug>(MatchitNormalForward) * :<C-U>call matchit#Match_wrapper('',1,'n')<CR>
n <SNR>30_:. & :<C-R>=getcmdline() =~ ',' ? "\0250" : ""<CR> o <Plug>(textobj-xmlattr-attr-i) & <SNR>34_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-i","o")<CR>
o <Plug>(textobj-xmlattr-attr-i) & <SNR>26_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-i","o")<CR> v <Plug>(textobj-xmlattr-attr-i) & <SNR>34_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-i","v")<CR>
v <Plug>(textobj-xmlattr-attr-i) & <SNR>26_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-i","v")<CR> o <Plug>(textobj-xmlattr-attr-a) & <SNR>34_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-a","o")<CR>
o <Plug>(textobj-xmlattr-attr-a) & <SNR>26_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-a","o")<CR> v <Plug>(textobj-xmlattr-attr-a) & <SNR>34_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-a","v")<CR>
v <Plug>(textobj-xmlattr-attr-a) & <SNR>26_(save-cursor-pos):<C-U>call g:__textobj_xmlattr.do_by_pattern("select","attr-a","v")<CR> n <SNR>34_ * <SNR>34_
n <SNR>26_ * <SNR>26_ <SNR>34_(save-cursor-pos) * <SNR>34_save_cursor_pos()
<SNR>26_(save-cursor-pos) * <SNR>26_save_cursor_pos() n <SNR>28_:. & :<C-R>=getcmdline() =~ ',' ? "\0250" : ""<CR>
n <Plug>PlenaryTestFile * :lua require('plenary.test_harness').test_file(vim.fn.expand("%:p"))<CR> n <Plug>PlenaryTestFile * :lua require('plenary.test_harness').test_file(vim.fn.expand("%:p"))<CR>
n <M-k> * <Cmd>lua MiniMove.move_line('up')<CR> s <Plug>luasnip-jump-prev * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move line up LuaSnip: Jump to the previous node
n <M-j> * <Cmd>lua MiniMove.move_line('down')<CR> s <Plug>luasnip-jump-next * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move line down LuaSnip: Jump to the next node
n <M-l> * <Cmd>lua MiniMove.move_line('right')<CR> s <Plug>luasnip-prev-choice * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move line right LuaSnip: Change to the previous choice from the choiceNode
n <M-h> * <Cmd>lua MiniMove.move_line('left')<CR> s <Plug>luasnip-next-choice * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move line left LuaSnip: Change to the next choice from the choiceNode
x <M-k> * <Cmd>lua MiniMove.move_selection('up')<CR> s <Plug>luasnip-expand-snippet * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move up LuaSnip: Expand the current snippet
x <M-j> * <Cmd>lua MiniMove.move_selection('down')<CR> s <Plug>luasnip-expand-or-jump * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move down LuaSnip: Expand or jump in the current snippet
x <M-l> * <Cmd>lua MiniMove.move_selection('right')<CR> <Plug>luasnip-expand-repeat * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move right LuaSnip: Repeat last node expansion
x <M-h> * <Cmd>lua MiniMove.move_selection('left')<CR> n <Plug>luasnip-delete-check * ~/.local/share/nvim/lazy/LuaSnip/plugin/luasnip.lua
Move left LuaSnip: Removes current snippet from jumplist
x <C-S> * <Esc><Cmd>silent! update | redraw<CR> x <C-S> * <Esc><Cmd>silent! update | redraw<CR>
Save and go to Normal mode Save and go to Normal mode
n <C-S> * :w!<CR> n <C-S> * :w!<CR>
@@ -528,4 +492,4 @@ n <C-L> * :lua vim.lsp.buf.signature_help()<CR>
Signature Signature
``` ```
- Generated on Tue 7 Jan 2025 21:37:18 EET - Generated on Tue 21 Jan 2025 15:24:13 EET

View File

@@ -13,7 +13,7 @@ Some problematic code has been fixed per `shellcheck` suggestions.
## Sourced ## Sourced
| Script | Source | | Script | Source |
| ----------------------- | ----------------- | |-------------------------|-------------------|
| `x-dupes` | skx/sysadmin-util | | `x-dupes` | skx/sysadmin-util |
| `x-foreach` | mvdan/dotfiles | | `x-foreach` | mvdan/dotfiles |
| `x-multi-ping` | skx/sysadmin-util | | `x-multi-ping` | skx/sysadmin-util |

View File

@@ -436,6 +436,7 @@ section_helpers()
"colors:Show colors" "colors:Show colors"
"env:Show environment variables" "env:Show environment variables"
"functions:Show functions" "functions:Show functions"
"aerospace:Show aerospace keybindings"
"nvim:Show nvim keybindings" "nvim:Show nvim keybindings"
'path:Show $PATH dir by dir' 'path:Show $PATH dir by dir'
"tmux:Show tmux keybindings" "tmux:Show tmux keybindings"
@@ -494,6 +495,7 @@ section_helpers()
"env") env | sort ;; "env") env | sort ;;
"functions") declare -F ;; "functions") declare -F ;;
"aerospace") cat "$DOTFILES/docs/aerospace-keybindings.md" ;;
"nvim") cat "$DOTFILES/docs/nvim-keybindings.md" ;; "nvim") cat "$DOTFILES/docs/nvim-keybindings.md" ;;
"tmux") cat "$DOTFILES/docs/tmux-keybindings.md" ;; "tmux") cat "$DOTFILES/docs/tmux-keybindings.md" ;;
"wezterm") cat "$DOTFILES/docs/wezterm-keybindings.md" ;; "wezterm") cat "$DOTFILES/docs/wezterm-keybindings.md" ;;
@@ -501,12 +503,76 @@ section_helpers()
esac esac
} }
section_apt()
{
USAGE_PREFIX="$SCRIPT apt <command>"
MENU=(
"upkeep:Run update, upgrade, autoremove and clean"
'install:Install packages from $DOTFILES/tools/apt.txt'
"update:Update apt packages"
"upgrade:Upgrade apt packages"
"autoremove:Remove unused apt packages"
"clean:Clean apt cache"
)
x-have apt && {
case "$1" in
upkeep)
sudo apt update \
&& sudo apt upgrade -y \
&& sudo apt autoremove -y \
&& sudo apt clean
;;
install)
# if apt.txt is not found, exit
[ ! -f "$DOTFILES/tools/apt.txt" ] && msgr err "apt.txt not found" && exit 0
# Load apt.txt, remove comments (even if trailing comment) and empty lines.
#
# Ignoring "Quote this to prevent word splitting."
# shellcheck disable=SC2046
sudo apt install \
-y $(
grep -vE '^\s*#' "$DOTFILES/tools/apt.txt" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
# If there's a apt.txt file under hosts/$hostname/apt.txt,
# run install on those lines too.
HOSTNAME=$(hostname -s)
HOST_APT="$DOTFILES/hosts/$HOSTNAME/apt.txt"
[[ -f $HOST_APT ]] && {
# shellcheck disable=SC2046
sudo apt install -y $(
grep -vE '^\s*#' "$HOST_APT" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
}
# Try this for an alternative way to install packages
# xargs -a <(awk '! /^ *(#|$)/' "$packagelist") -r -- sudo apt-get install -y
;;
update) sudo apt update ;;
upgrade) sudo apt upgrade -y ;;
autoremove) sudo apt autoremove -y ;;
clean) sudo apt clean ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac
}
! x-have apt && menu_builder "$USAGE_PREFIX" "apt not available on this system"
}
section_docs() section_docs()
{ {
USAGE_PREFIX="$SCRIPT docs <command>" USAGE_PREFIX="$SCRIPT docs <command>"
MENU=( MENU=(
"all:Update all keybindings documentations" "all:Update all keybindings documentations"
"aerospace:Update aerospace keybindings documentation"
"tmux:Update tmux keybindings documentation" "tmux:Update tmux keybindings documentation"
"nvim:Update nvim keybindings documentation" "nvim:Update nvim keybindings documentation"
"wezterm:Update wezterm keybindings documentation" "wezterm:Update wezterm keybindings documentation"
@@ -514,10 +580,12 @@ section_docs()
case "$1" in case "$1" in
all) all)
$0 docs aerospace
$0 docs tmux $0 docs tmux
$0 docs nvim $0 docs nvim
$0 docs wezterm $0 docs wezterm
;; ;;
aerospace) bash "$DOTFILES/scripts/create-aerospace-keymaps.php" ;;
tmux) bash "$DOTFILES/local/bin/x-dfm-docs-xterm-keybindings" ;; tmux) bash "$DOTFILES/local/bin/x-dfm-docs-xterm-keybindings" ;;
nvim) bash "$DOTFILES/scripts/create-nvim-keymaps.sh" ;; nvim) bash "$DOTFILES/scripts/create-nvim-keymaps.sh" ;;
wezterm) bash "$DOTFILES/scripts/create-wezterm-keymaps.sh" ;; wezterm) bash "$DOTFILES/scripts/create-wezterm-keymaps.sh" ;;
@@ -708,6 +776,8 @@ usage()
echo "" echo ""
section_install section_install
echo "" echo ""
section_apt
echo ""
section_asdf section_asdf
echo "" echo ""
section_brew section_brew
@@ -730,6 +800,7 @@ main()
# The main loop. The first keyword after $0 triggers section, or help. # The main loop. The first keyword after $0 triggers section, or help.
case "$SECTION" in case "$SECTION" in
install) section_install "$@" ;; install) section_install "$@" ;;
apt) section_apt "$@" ;;
asdf) section_asdf "$@" ;; asdf) section_asdf "$@" ;;
brew) section_brew "$@" ;; brew) section_brew "$@" ;;
check) section_check "$@" ;; check) section_check "$@" ;;

View File

@@ -23,8 +23,8 @@
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# UTF-8 ftw # UTF-8 ftw
GITDIRTY="❌ " GIT_DIRTY="❌ "
GITCLEAN="✅ " GIT_CLEAN="✅ "
# Function to print messages if VERBOSE is enabled # Function to print messages if VERBOSE is enabled
# $1 - message (string) # $1 - message (string)
@@ -41,7 +41,7 @@ catch()
# Function to check the git status of a directory # Function to check the git status of a directory
# $1 - directory (string) # $1 - directory (string)
gitdirty() git_dirty()
{ {
local d="$1" local d="$1"
trap 'catch $? $LINENO' ERR trap 'catch $? $LINENO' ERR
@@ -58,15 +58,15 @@ gitdirty()
# If we have `.git` folder, check it. # If we have `.git` folder, check it.
if [[ -d ".git" ]]; then if [[ -d ".git" ]]; then
ISDIRTY=$(git diff --shortstat 2> /dev/null | tail -n1) GIT_IS_DIRTY=$(git diff --shortstat 2> /dev/null | tail -n1)
ICON="$GITCLEAN" ICON="$GIT_CLEAN"
[[ $ISDIRTY != "" ]] && ICON="$GITDIRTY" [[ $GIT_IS_DIRTY != "" ]] && ICON="$GIT_DIRTY"
printf " %s %s\n" "$ICON" "$(pwd)" printf " %s %s\n" "$ICON" "$(pwd)"
else else
# If it wasn't git repository, check subdirectories. # If it wasn't git repository, check subdirectories.
gitdirtyrepos ./* git_dirty_repos ./*
fi fi
cd - > /dev/null || exit cd - > /dev/null || exit
fi fi
@@ -76,10 +76,10 @@ gitdirty()
# Function to check git status for multiple directories # Function to check git status for multiple directories
# $@ - directories # $@ - directories
gitdirtyrepos() git_dirty_repos()
{ {
for x in "$@"; do for x in "$@"; do
gitdirty "$x" git_dirty "$x"
done done
} }
@@ -96,7 +96,7 @@ main()
11) echo "segfault occurred";; 11) echo "segfault occurred";;
esac' EXIT esac' EXIT
gitdirtyrepos "$GIT_DIRTY_DIR" git_dirty_repos "$GIT_DIRTY_DIR"
} }
main "$@" main "$@"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Credit to ThePrimeagen, jessarcher # Credit to ThePrimeagen, Jess Archer
# https://github.com/jessarcher/dotfiles/blob/master/scripts/t # See https://github.com/jessarcher/dotfiles/blob/master/scripts/t
# #
# Tweaks by Ismo Vuorinen <https://github.com/ivuorinen> 2025 # Tweaks by Ismo Vuorinen <https://github.com/ivuorinen> 2025
# vim: ft=bash ts=2 sw=2 et # vim: ft=bash ts=2 sw=2 et
@@ -9,81 +9,135 @@
# Set environment variables for configuration with defaults # Set environment variables for configuration with defaults
T_ROOT="${T_ROOT:-$HOME/Code}" T_ROOT="${T_ROOT:-$HOME/Code}"
DOTFILES="${DOTFILES:-$HOME/.dotfiles}" DOTFILES="${DOTFILES:-$HOME/.dotfiles}"
T_MAX_DEPTH="${T_MAX_DEPTH:-3}"
# Function to print an error message and exit # Function to print an error message and exit
error_exit() error_exit() {
{
echo "Error: $1" >&2 echo "Error: $1" >&2
exit 1 exit 1
} }
get_directories() # Validate that T_ROOT exists
{ if [[ ! -d "$T_ROOT" ]]; then
local dirs='' error_exit "T_ROOT directory '$T_ROOT' does not exist."
dirs+='# Directories\n' fi
dirs+=$(find "$T_ROOT" -maxdepth 2 -mindepth 1 -type d ! -name '.git' ! -name '.svn')
dirs+="$(printf "\n%s" "$DOTFILES")"
echo "$dirs"
# Check for required dependencies
check_dependencies() {
local T_DEPS=(tmux fzf find)
for cmd in "${T_DEPS[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
error_exit "$cmd is not installed."
fi
done
} }
check_tmux() check_dependencies
{
# Generate an array of '-not -path' rules for each exclusion pattern
# without using namerefs.
generate_exclude_rules() {
local result_var="$1"
shift
local arr=()
for pattern in "$@"; do
# Exclude both the directory and any subdirectories under it.
arr+=( -not -path "*/${pattern}" -not -path "*/${pattern}/*" )
done
# Use eval to assign the array to the variable whose name was passed.
eval "$result_var=(\"\${arr[@]}\")"
}
get_directories() {
local exclude_patterns=(
".bzr" ".git" ".hg" ".idea" ".obsidian" ".run" ".svn" ".vscode"
"build" "dist" "node_modules" "out" "target" "vendor"
)
local exclude_rules=()
generate_exclude_rules exclude_rules "${exclude_patterns[@]}"
local dirs
# Use $'string' to correctly process escape sequences.
dirs=$'# Directories\n'
dirs+=$(find "$T_ROOT" \
-maxdepth "$T_MAX_DEPTH" \
-mindepth 1 \
-type d \
"${exclude_rules[@]}"
)
echo -e "$dirs"
}
check_tmux() {
if ! command -v tmux &> /dev/null; then if ! command -v tmux &> /dev/null; then
error_exit "tmux is not installed." error_exit "tmux is not installed."
fi fi
# check to see that tmux server is running # Ensure tmux server is running
if ! tmux info &> /dev/null; then if ! tmux info &> /dev/null; then
tmux start-server tmux start-server
fi fi
} }
get_sessions() get_sessions() {
{
check_tmux check_tmux
local sessions='' T_TMUX_SESSIONS=$(tmux list-sessions -F "#{session_name}" 2> /dev/null)
sessions+='# Sessions\n'
sessions+=$(tmux list-sessions -F "#{session_name}" 2> /dev/null)
echo "$sessions" if [[ -z "$T_TMUX_SESSIONS" ]]; then
echo ""
return
fi
echo -e "# Sessions\n$T_TMUX_SESSIONS"
} }
items='' # Determine selection from command-line argument or interactive fzf menu
# Select the directory
if [[ $# -eq 1 ]]; then if [[ $# -eq 1 ]]; then
selected="$1" selected="$1"
else else
items+=$(get_sessions) # Combine sessions and directories for selection
items+='\n' T_ITEMS="$(get_sessions | sort)
items+=$(get_directories) $(get_directories | sort)"
selected=$(echo -e "$items" | fzf) || exit 0 # Exit if no selection is made # Use sort to order the entries and fzf for interactive selection
selected=$(echo "$T_ITEMS" | fzf) || exit 0
fi fi
# If user selected a header, exit # Reject selection if it is a header line
[[ ${selected:0:1} == "#" ]] && error_exit "You selected a header, why?" [[ ${selected:0:1} == "#" ]] && error_exit "Header selected. Please choose a valid session or directory."
# Exit if no directory was selected [[ -z "$selected" ]] && error_exit "No directory or session selected."
[[ -z $selected ]] && error_exit "No directory selected."
# Sanitize the session name # Sanitize the session name
session_name=$(basename "$selected") session_name=$(basename "$selected")
# If we get nothing, we are dealing with a session if [[ -z "$session_name" ]]; then
[[ $session_name == "" ]] && session_name="$selected" session_name="$selected"
# Remove dots from the session name as tmux doesn't like them fi
# Remove dots since tmux dislikes them
session_name="${session_name//./}" session_name="${session_name//./}"
# Try to switch to the tmux session # Attempt to switch to an existing session
if tmux switch-client -t "=$session_name" 2> /dev/null; then tmux switch-client -t "=$session_name" 2>/dev/null
active_session=$(tmux display-message -p -F '#{session_name}' 2>/dev/null)
if [[ "$active_session" == "$session_name" ]]; then
exit 0 exit 0
fi fi
# Create a new tmux session or attach to an existing one # Create a new session (or attach to an existing one) based on the selection
if tmux new-session -c "$selected" -d -s "$session_name" 2> /dev/null; then if [ -z "$TMUX" ]; then
tmux switch-client -t "$session_name" # Not inside tmux: create (or attach to) the session and attach.
tmux new-session -A -s "$session_name" -c "$selected"
else else
tmux new -c "$selected" -A -s "$session_name" # Inside tmux: check if the target session exists.
if tmux has-session -t "$session_name" 2>/dev/null; then
# Session exists; switch to it.
tmux switch-client -t "$session_name"
else
# Session does not exist; create it in detached mode and then switch.
tmux new-session -d -s "$session_name" -c "$selected"
tmux switch-client -t "$session_name"
fi
fi fi

54
local/bin/x-clean-vendordirs Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# vim: ft=bash sw=2 ts=2 et
#
# Removes vendor and node_modules directories from the
# current directory and all subdirectories.
#
# Author: Ismo Vuorinen 2025
# License: MIT
# Check if the user has provided a directory as an argument
if [ "$1" ]; then
# Check if the directory exists
if [ -d "$1" ]; then
CLEANDIR="$1"
else
msgr err "Directory $1 does not exist."
exit 1
fi
else
CLEANDIR="."
fi
# Function to remove node_modules and vendor folders
remove_node_modules_vendor() {
local dir=$1
# If the directory is a symlink, skip it
if [ -L "$dir" ]; then
msgr msg "Skipping symlink $dir"
return
fi
# Check if the directory exists
if [ -d "$dir" ]; then
# If node_modules or vendor folder exists, remove it and all its contents
if [ -d "$dir/node_modules" ]; then
msgr run "Removing $dir/node_modules"
rm -rf "$dir/node_modules"
fi
if [ -d "$dir/vendor" ]; then
msgr run "Removing $dir/vendor"
rm -rf "$dir/vendor"
fi
# Recursively check subdirectories
for item in "$dir"/*; do
remove_node_modules_vendor "$item"
done
fi
}
# Start removing node_modules and vendor folders from the current working directory
remove_node_modules_vendor "$CLEANDIR"

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# foreach <folder> <commands that should be run to each file> # foreach <folder> <commands that should be run to each file>
# foreach "ls -d */" "git status" # run git status in each folder
# #
# Source: https://github.com/mvdan/dotfiles/blob/master/.bin/foreach # Source: https://github.com/mvdan/dotfiles/blob/master/.bin/foreach
@@ -11,6 +12,7 @@ for dir in $($cmd); do
( (
echo "$dir" echo "$dir"
cd "$dir" || exit 1 cd "$dir" || exit 1
# shellcheck disable=SC2294,SC2034
eval "$@" # allow multiple commands like "foo && bar" eval "$@" # allow multiple commands like "foo && bar"
) )
done done

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Fetch the latest release version of a GitHub repository in tar.gz format (e.g. v1.0.0.tar.gz) # Fetch the latest release version of a GitHub repository in tar.gz format (e.g. v1.0.0.tar.gz)
# Usage: x-gh-get-latest-release-targ <repo> [--get] # Usage: x-gh-get-latest-release-targz <repo> [--get]
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024 # Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
set -euo pipefail set -euo pipefail

View File

@@ -1,66 +1,190 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Get latest release version from GitHub # Get latest release version, branch tag, or latest commit from GitHub
# Usage: x-gh-get-latest-version <repo> # Usage: x-gh-get-latest-version <repo>
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024 # Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
set -euo pipefail set -euo pipefail
# Enable verbosity with VERBOSE=1 # Environment variables, more under get_release_version() and get_latest_branch_tag()
# functions. These can be overridden by the user.
GITHUB_API_URL="${GITHUB_API_URL:-https://api.github.com/repos}"
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Function to print usage information # Prints a message if VERBOSE=1
usage() msg() {
{ [[ "$VERBOSE" -eq 1 ]] && echo "$1"
echo "Usage: $0 <repo> (e.g. ivuorinen/dotfiles)" }
# Show usage information
usage() {
cat <<EOF
Usage: $0 <repo> (e.g. ivuorinen/dotfiles)
Fetches the latest release version, latest branch tag, or latest commit SHA from GitHub.
Options:
- INCLUDE_PRERELEASES=1 Include prerelease versions (default: only stable releases).
- OLDEST_RELEASE=1 Fetch the oldest release instead of the latest.
- BRANCH=<branch> Fetch the latest tag from a specific branch (default: main).
- LATEST_COMMIT=1 Fetch the latest commit SHA from the specified branch.
- OUTPUT=json Return output as JSON (default: plain text).
- GITHUB_API_URL=<url> Override GitHub API URL (useful for GitHub Enterprise).
- GITHUB_TOKEN=<token> Use GitHub API token to increase rate limits (default: unauthenticated).
Requirements:
- curl
- jq (for JSON processing)
Examples:
# Fetch the latest stable release
$0 ivuorinen/dotfiles
# Fetch the latest release including prereleases
INCLUDE_PRERELEASES=1 $0 ivuorinen/dotfiles
# Fetch the oldest release
OLDEST_RELEASE=1 $0 ivuorinen/dotfiles
# Fetch the latest tag from the 'develop' branch
BRANCH=develop $0 ivuorinen/dotfiles
# Fetch the latest commit SHA from 'main' branch
LATEST_COMMIT=1 $0 ivuorinen/dotfiles
# Output result in JSON format
OUTPUT=json $0 ivuorinen/dotfiles
# Use GitHub API token for higher rate limits
GITHUB_TOKEN="your_personal_access_token" $0 ivuorinen/dotfiles
# Use GitHub Enterprise API
GITHUB_API_URL="https://github.example.com/api/v3/repos" $0 ivuorinen/dotfiles
EOF
exit 1 exit 1
} }
# Function to print messages if VERBOSE is enabled # Check that required dependencies are installed
# $1 - message (string) check_dependencies() {
msg() for cmd in curl jq; do
{ if ! command -v "$cmd" &>/dev/null; then
[[ "$VERBOSE" -eq 1 ]] && echo "$1" echo "Error: '$cmd' is required but not installed." >&2
return 0 exit 1
fi
done
} }
# Function to fetch the latest release version from GitHub # Fetches the latest release or the oldest if OLDEST_RELEASE=1
# $1 - GitHub repository (string) # $1 - GitHub repository (string)
get_latest_release() get_release_version() {
{ local repo="$1"
local repo=$1 local include_prereleases="${INCLUDE_PRERELEASES:-0}"
local oldest_release="${OLDEST_RELEASE:-0}"
local api_url="${GITHUB_API_URL}/${repo}/releases"
local auth_header=()
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
msg "Fetching release data from: $api_url (Include prereleases: $include_prereleases, Oldest: $oldest_release)"
local json_response
json_response=$(curl -sSL "${auth_header[@]}" "$api_url")
# Check for API errors
if echo "$json_response" | jq -e 'has("message")' >/dev/null; then
msg "GitHub API error: $(echo "$json_response" | jq -r '.message')"
exit 1
fi
local filter='.[] | select(.tag_name)'
[[ "$include_prereleases" -eq 0 ]] && filter+='.prerelease == false'
local version local version
version=$(curl -s "https://api.github.com/repos/${repo}/releases/latest" \ if [[ "$oldest_release" -eq 1 ]]; then
| grep "tag_name" \ version=$(echo "$json_response" | jq -r "[${filter}] | last.tag_name // empty")
| awk -F '"' '{print $4}') else
version=$(echo "$json_response" | jq -r "[${filter}] | first.tag_name // empty")
fi
if [ -z "$version" ]; then if [[ -z "$version" ]]; then
msg "Failed to fetch the latest release version for repository: $repo" msg "Failed to fetch release version for repository: $repo"
echo ""
exit 1 exit 1
fi fi
echo "$version" echo "$version"
return 0 }
# Fetches the latest tag from the specified branch
get_latest_branch_tag() {
local repo="$1"
local branch="${BRANCH:-main}"
local api_url="${GITHUB_API_URL}/${repo}/git/refs/tags"
msg "Fetching latest tag for branch '$branch' from: $api_url"
local json_response
json_response=$(curl -sSL "$api_url")
local version
version=$(echo "$json_response" | jq -r "[.[] | select(.ref | contains(\"refs/tags/$branch\"))] | last.ref | sub(\"refs/tags/\"; \"\") // empty")
if [[ -z "$version" ]]; then
msg "Failed to fetch latest tag for branch: $branch"
exit 1
fi
echo "$version"
}
# Fetches the latest commit SHA from the specified branch
get_latest_commit() {
local repo="$1"
local branch="${BRANCH:-main}"
local api_url="${GITHUB_API_URL}/${repo}/commits/$branch"
msg "Fetching latest commit SHA from: $api_url"
local json_response
json_response=$(curl -sSL "$api_url")
local sha
sha=$(echo "$json_response" | jq -r '.sha // empty')
if [[ -z "$sha" ]]; then
msg "Failed to fetch latest commit SHA for branch: $branch"
exit 1
fi
echo "$sha"
} }
# Main function # Main function
main() # $1 - GitHub repository (string)
{ main() {
if [ "$#" -ne 1 ]; then if [[ $# -ne 1 ]]; then
usage usage
fi fi
local repo=$1 check_dependencies
msg "Fetching the latest release version for repository: $repo" local repo="$1"
local result
local version if [[ "${LATEST_COMMIT:-0}" -eq 1 ]]; then
version=$(get_latest_release "$repo") result=$(get_latest_commit "$repo")
elif [[ -n "${BRANCH:-}" ]]; then
result=$(get_latest_branch_tag "$repo")
else
result=$(get_release_version "$repo")
fi
echo "$version" if [[ "${OUTPUT:-text}" == "json" ]]; then
return 0 echo "{\"repository\": \"$repo\", \"result\": \"$result\"}"
else
echo "$result"
fi
} }
main "$@" main "$@"

View File

@@ -6,11 +6,12 @@
# License: MIT # License: MIT
VERSION="1.0.0" VERSION="1.0.0"
SCRIPT_NAME="$(basename "$0")"
# Function to display usage # Function to display usage
usage() usage()
{ {
echo "Usage: x-localip [options] [interface]" echo "Usage: $SCRIPT_NAME [options] [interface]"
echo "Options:" echo "Options:"
echo " --help Show this help message" echo " --help Show this help message"
echo " --version Show version information" echo " --version Show version information"
@@ -31,7 +32,7 @@ while [[ $# -gt 0 ]]; do
exit 0 exit 0
;; ;;
--version) --version)
echo "x-localip version $VERSION" echo "$SCRIPT_NAME version $VERSION"
exit 0 exit 0
;; ;;
--ipv4) --ipv4)

183
local/bin/x-multi-ping Executable file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env bash
# x-multi-ping: Multi-protocol ping wrapper in Bash
#
# Description:
# This script pings a list of hostnames using both IPv4 and IPv6 protocols.
# It uses the 'dig' command to resolve the hostnames and then pings each IP
# address found. The script can run once or loop indefinitely with a sleep
# interval between iterations.
#
# This script is based on the original work by Steve Kemp.
# Original work Copyright (c) 2014 by Steve Kemp.
#
# The code in the original repository may be modified and distributed under your choice of:
# * The Perl Artistic License (http://dev.perl.org/licenses/artistic.html) or
# * The GNU General Public License, version 2 or later (http://www.gnu.org/licenses/gpl2.txt).
#
# Modifications and enhancements by Ismo Vuorinen on 2025.
#
# Usage:
# x-multi-ping [--loop|--forever] [--sleep=N] hostname1 hostname2 ...
#
# Options:
# --help Display this help message.
# --verbose Enable verbose output.
# --loop, --forever Loop indefinitely.
# --sleep=N Sleep N seconds between iterations (default: 1).
#
# Examples:
# x-multi-ping example.com
# x-multi-ping --loop --sleep=5 example.com
# x-multi-ping --forever example.com example.org
#
# Dependencies:
# - dig (DNS lookup utility)
# - ping (ICMP ping utility)
# - ping6 (IPv6 ping utility) or ping -6 (alternative)
#
# Defaults
LOOP=0
SLEEP=1
VERBOSE=0
TIMEOUT=5
usage()
{
echo "Usage: $0 [--loop|--forever] [--sleep=N] hostname1 hostname2 ..."
echo "Options:"
echo " --help Display this help message."
echo " --verbose Enable verbose output."
echo " --loop, --forever Loop indefinitely."
echo " --sleep=N Sleep N seconds between iterations (default: 1)."
}
# Parse command-line options
while [[ $# -gt 0 ]]; do
case "$1" in
--help)
usage
exit 0
;;
--verbose)
# shellcheck disable=SC2034
VERBOSE=1
shift
;;
--loop | --forever)
LOOP=1
shift
;;
--sleep=*)
SLEEP="${1#*=}"
shift
;;
--sleep)
if [[ -n "$2" ]]; then
SLEEP="$2"
shift 2
else
echo "Error: --sleep requires a numeric value."
exit 1
fi
;;
--*)
echo "Unknown option: $1"
usage
exit 1
;;
*)
break
;;
esac
done
# Check for required hostnames
if [[ $# -lt 1 ]]; then
usage
exit 1
fi
# Dependency check for dig and ping
if ! command -v dig > /dev/null 2>&1; then
echo "The required 'dig' command is missing. Aborting."
exit 1
fi
if ! command -v ping > /dev/null 2>&1; then
echo "The required 'ping' command is missing. Aborting."
exit 1
fi
# Determine how to invoke IPv6 ping
if command -v ping6 > /dev/null 2>&1; then
PING6="ping6"
elif ping -6 -c1 ::1 > /dev/null 2>&1; then
PING6="ping -6"
else
echo "The required IPv6 ping command (ping6 or ping -6) is missing. Aborting."
exit 1
fi
# Function to remove any URI scheme and port from the hostname.
strip_hostname()
{
local host="$1"
# Remove leading scheme (e.g., http://) if present.
if [[ "$host" =~ ^[a-z]+://([^/]+)/? ]]; then
host="${BASH_REMATCH[1]}"
fi
# Remove a port if specified (e.g., example.com:80).
if [[ "$host" =~ ^([^:]+):[0-9]+$ ]]; then
host="${BASH_REMATCH[1]}"
fi
echo "$host"
}
# Function to ping a given host based on DNS lookups.
pingHost()
{
local original_host="$1"
local host
host=$(strip_hostname "$original_host")
for type in A AAAA; do
# Look up the DNS records for the host.
ips=$(dig +short "$host" "$type")
if [[ -z "$ips" ]]; then
echo "WARNING: Failed to resolve $host [$type]"
else
# For each IP address found, perform the appropriate ping.
while IFS= read -r ip; do
if [[ "$type" == "A" ]]; then
ping_binary="ping"
else
ping_binary="$PING6"
fi
# Execute ping with one packet and a timeout.
$ping_binary -c1 -w"$TIMEOUT" -W"$TIMEOUT" "$host" > /dev/null 2>&1
# shellcheck disable=SC2181
if [[ $? -eq 0 ]]; then
echo "Host $host - $ip - alive"
else
echo "Host $host - $ip - FAILED"
fi
done <<< "$ips"
fi
done
}
# Main loop: run once or forever based on the options.
if [[ $LOOP -eq 1 ]]; then
while true; do
for host in "$@"; do
pingHost "$host"
done
sleep "$SLEEP"
done
else
for host in "$@"; do
pingHost "$host"
done
fi

View File

@@ -1,37 +1,141 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# List open (listened) ports, without the crud that # List open (listened) ports in Markdown or JSON format.
# usually comes with `lsof -i`
# #
# Modified by: Ismo Vuorinen <https://github.com/ivuorinen> 2020 # Modified by: Ismo Vuorinen <https://github.com/ivuorinen> 2020, 2025
# Originally from: https://www.commandlinefu.com/commands/view/8951 # Originally from: https://www.commandlinefu.com/commands/view/8951
# Original author: https://www.commandlinefu.com/commands/by/wickedcpj # Original author: https://www.commandlinefu.com/commands/by/wickedcpj
set -euo pipefail set -euo pipefail
# Function to print the header FORMAT="markdown"
print_header()
# Function to print help message
print_help()
{ {
echo 'User: Command: PID: Port:' cat << EOF
echo '=========================================================' Usage: $(basename "$0") [OPTIONS]
List open (listened) ports in a formatted table (Markdown) or JSON.
Options:
--json Output results in JSON format instead of Markdown
--help Show this help message
Examples:
$(basename "$0") # List open ports as a Markdown table
$(basename "$0") --json # List open ports in JSON format
EOF
exit 0
} }
# Function to list open ports # Function to print the Markdown table header
print_header()
{
echo "| User | Command | PID | Port |"
echo "|------------------|----------------------------|----------|---------|"
}
# Function to list open ports using lsof
list_open_ports_lsof()
{
lsof -i -P -n -sTCP:LISTEN +c 0 2> /dev/null | awk '
NR > 1 {
port = $9
sub(/.*:/, "", port) # Extract port number
printf "| %-16s | %-26s | %-8s | %-7s |\n", substr($3, 1, 16), substr($1, 1, 26), substr($2, 1, 8), port
}
' | sort -k3,3n | uniq
}
# Function to list open ports using ss (alternative)
list_open_ports_ss()
{
ss -ltpn 2> /dev/null | awk '
NR > 1 {
split($5, addr, ":")
port = addr[length(addr)]
user = $1
cmd = $7
sub(/users:\(\(/, "", cmd) # Cleanup command
sub(/\)\)/, "", cmd)
pid = "-"
match(cmd, /pid=([0-9]+)/, m)
if (m[1] != "") pid = m[1]
printf "| %-16s | %-26s | %-8s | %-7s |\n", substr(user, 1, 16), substr(cmd, 1, 26), substr(pid, 1, 8), port
}
' | sort -k3,3n | uniq
}
# Function to print JSON output
list_open_ports_json()
{
if command -v lsof &> /dev/null; then
lsof -i -P -n -sTCP:LISTEN +c 0 2> /dev/null | awk '
NR > 1 {
port = $9
sub(/.*:/, "", port) # Extract port number
printf "{\"user\": \"%s\", \"command\": \"%s\", \"pid\": \"%s\", \"port\": \"%s\"},\n", $3, $1, $2, port
}
' | sort -k3,3n | uniq | sed '$ s/,$//'
elif command -v ss &> /dev/null; then
ss -ltpn 2> /dev/null | awk '
NR > 1 {
split($5, addr, ":")
port = addr[length(addr)]
user = $1
cmd = $7
sub(/users:\(\(/, "", cmd)
sub(/\)\)/, "", cmd)
pid = "-"
match(cmd, /pid=([0-9]+)/, m)
if (m[1] != "") pid = m[1]
printf "{\"user\": \"%s\", \"command\": \"%s\", \"pid\": \"%s\", \"port\": \"%s\"},\n", user, cmd, pid, port
}
' | sort -k3,3n | uniq | sed '$ s/,$//'
else
echo "[]"
fi
}
# Function to determine available command
list_open_ports() list_open_ports()
{ {
lsof -i 4 -P -n +c 0 \ if [[ "$FORMAT" == "json" ]]; then
| grep -i 'listen' \ echo "["
| awk '{print $3, $1, $2, $9}' \ list_open_ports_json
| sed 's/ [a-z0-9\.\*]*:/ /' \ echo "]"
| sort -k 3 -n \ else
| xargs printf '%-15s %-25s %-8s %-5s\n' \ print_header
| uniq if command -v lsof &> /dev/null; then
list_open_ports_lsof
elif command -v ss &> /dev/null; then
list_open_ports_ss
else
echo "**Error:** Neither 'lsof' nor 'ss' is available."
exit 1
fi
fi
} }
# Main function # Main function
main() main()
{ {
print_header case "${1:-}" in
--json)
FORMAT="json"
;;
--help)
print_help
;;
"") ;;
*)
echo "Unknown option: $1"
print_help
;;
esac
list_open_ports list_open_ports
echo "" echo ""
} }

281
local/bin/x-path Executable file
View File

@@ -0,0 +1,281 @@
#!/usr/bin/env bash
#
# x-path: A unified script to manipulate the PATH variable.
#
# This script supports four subcommands:
# - append (or a): Remove duplicates and append one or more directories.
# - prepend (or p): Remove duplicates and prepend one or more directories.
# - remove: Remove one or more directories from PATH.
# - check: Check if the directories (or all directories in PATH if none provided) are valid.
#
# All directory arguments are normalized (trailing slashes removed, except for "/"),
# and the current PATH is normalized before any operations.
#
# Usage:
# x-path <command> <directory1> [<directory2> ...]
#
# Examples:
# x-path append /usr/local/bin /opt/bin
# x-path p /home/user/bin
# x-path remove /usr/local/bin
# x-path check # Check all directories in PATH
# x-path check /usr/local/bin /bin
#
# Enable verbose output by setting:
# export VERBOSE=1
VERBOSE="${VERBOSE:-0}"
#######################################
# Normalize a directory by removing a trailing slash (unless the directory is "/").
# Globals:
# None
# Arguments:
# $1 - Directory path to normalize
# Returns:
# Echoes the normalized directory.
#######################################
normalize_dir()
{
local d="$1"
if [ "$d" != "/" ]; then
d="${d%/}"
fi
echo "$d"
}
#######################################
# Normalize the PATH variable by normalizing each of its components.
# Globals:
# PATH
# Arguments:
# None
# Returns:
# Updates and exports PATH.
#######################################
normalize_path_var()
{
local new_path=""
local d
IFS=':' read -r -a arr <<< "$PATH"
for d in "${arr[@]}"; do
d=$(normalize_dir "$d")
if [ -z "$new_path" ]; then
new_path="$d"
else
new_path="$new_path:$d"
fi
done
PATH="$new_path"
export PATH
}
#######################################
# Remove all occurrences of a normalized directory from PATH.
# Globals:
# PATH
# Arguments:
# $1 - Normalized directory to remove from PATH.
# Returns:
# Updates PATH.
#######################################
remove_from_path()
{
local d="$1"
PATH=":${PATH}:"
PATH="${PATH//:$d:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
}
#######################################
# Append one or more directories to PATH.
# Globals:
# PATH, VERBOSE
# Arguments:
# One or more directory paths.
# Returns:
# Updates PATH.
#######################################
do_append()
{
local processed=""
local d
for arg in "$@"; do
d=$(normalize_dir "$arg")
if [[ " $processed " == *" $d "* ]]; then
continue
else
processed="$processed $d"
fi
if [ ! -d "$d" ]; then
[ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$d' does not exist. Skipping."
continue
fi
remove_from_path "$d"
PATH="${PATH:+"$PATH:"}$d"
[ "$VERBOSE" -eq 1 ] && echo "Appended '$d' to PATH."
done
export PATH
}
#######################################
# Prepend one or more directories to PATH.
# Directories are processed in reverse order so that the first argument ends up leftmost.
# Globals:
# PATH, VERBOSE
# Arguments:
# One or more directory paths.
# Returns:
# Updates PATH.
#######################################
do_prepend()
{
local processed=""
local d
local -a arr=("$@")
local i
for ((i = ${#arr[@]} - 1; i >= 0; i--)); do
d=$(normalize_dir "${arr[i]}")
if [[ " $processed " == *" $d "* ]]; then
continue
else
processed="$processed $d"
fi
if [ ! -d "$d" ]; then
[ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$d' does not exist. Skipping."
continue
fi
remove_from_path "$d"
PATH="$d${PATH:+":$PATH"}"
[ "$VERBOSE" -eq 1 ] && echo "Prepended '$d' to PATH."
done
export PATH
}
#######################################
# Remove one or more directories from PATH.
# Globals:
# PATH, VERBOSE
# Arguments:
# One or more directory paths.
# Returns:
# Updates PATH.
#######################################
do_remove()
{
local processed=""
local d
for arg in "$@"; do
d=$(normalize_dir "$arg")
if [[ " $processed " == *" $d "* ]]; then
continue
else
processed="$processed $d"
fi
case ":$PATH:" in
*":$d:"*)
remove_from_path "$d"
[ "$VERBOSE" -eq 1 ] && echo "Removed '$d' from PATH."
;;
*)
[ "$VERBOSE" -eq 1 ] && echo "(?) '$d' is not in PATH."
;;
esac
done
export PATH
}
#######################################
# Check the validity of directories.
# If arguments are provided, check those directories; otherwise, check all directories in PATH.
# Globals:
# PATH
# Arguments:
# Zero or more directory paths.
# Returns:
# Outputs the validity status of each directory.
#######################################
do_check()
{
local d
if [ "$#" -eq 0 ]; then
echo "Checking all directories in PATH:"
IFS=':' read -r -a arr <<< "$PATH"
for d in "${arr[@]}"; do
d=$(normalize_dir "$d")
if [ -d "$d" ]; then
echo "Valid: $d"
else
echo "Invalid: $d"
fi
done
else
for arg in "$@"; do
d=$(normalize_dir "$arg")
if [ -d "$d" ]; then
echo "Valid: $d"
else
echo "Invalid: $d"
fi
done
fi
}
#######################################
# Main routine: Parse subcommand and arguments, normalize PATH,
# and dispatch to the appropriate functionality.
#######################################
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <command> <directory1> [<directory2> ...]"
echo "Commands:"
echo " append (or a) - Append directories to PATH"
echo " prepend (or p) - Prepend directories to PATH"
echo " remove - Remove directories from PATH"
echo " check - Check validity of directories (or all in PATH if none given)"
exit 1
fi
cmd="$1"
shift
# Normalize the current PATH variable.
normalize_path_var
case "$cmd" in
append | a)
[ "$#" -ge 1 ] || {
echo "Usage: $0 append <directory1> [<directory2> ...]"
exit 1
}
do_append "$@"
;;
prepend | p)
[ "$#" -ge 1 ] || {
echo "Usage: $0 prepend <directory1> [<directory2> ...]"
exit 1
}
do_prepend "$@"
;;
remove)
[ "$#" -ge 1 ] || {
echo "Usage: $0 remove <directory1> [<directory2> ...]"
exit 1
}
do_remove "$@"
;;
check)
# If no directories are provided, check all directories in PATH.
do_check "$@"
;;
*)
echo "Unknown command: $cmd"
echo "Usage: $0 <command> <directory1> [<directory2> ...]"
exit 1
;;
esac

View File

@@ -1,40 +1,44 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Add a directory to the beginning of the PATH if it's not already there. # Optimized script to append directories to PATH.
# Usage: x-path-append <dir> # For each given directory, it removes all duplicate occurrences from PATH
# and then appends it if the directory exists.
#
# Usage: x-path-append <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
# Set verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Function to print messages if VERBOSE is enabled # Ensure that at least one directory is provided.
# $1 - message (string) [ "$#" -lt 1 ] && {
msg() echo "Usage: $0 <directory> [<directory> ...]"
{ exit 1
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
} }
if [ "$#" -ne 1 ]; then for dir in "$@"; do
echo "Usage: $0 <dir>" # Check if the specified directory exists.
exit 1 if [ ! -d "$dir" ]; then
fi [ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$dir' does not exist. Skipping."
continue
fi
dir="$1" # Remove all duplicate occurrences of the directory from PATH.
case ":$PATH:" in
*":$dir:"*)
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed previous occurrences of '$dir' from PATH."
;;
*) ;;
esac
if echo "$PATH" | grep -qE "(^|:)$dir($|:)"; then # Append the directory to PATH.
export PATH=$(echo -n "$PATH" | awk -v RS=: -v ORS=: "\$0 != \"$dir\"" | sed 's/:$//')
msg "Directory $dir has been removed from PATH"
else
msg "Directory $dir is not in PATH"
fi
if [ ! -d "$dir" ]; then
msg "(?) Directory $dir does not exist"
exit 0
fi
if echo "$PATH" | grep -qE "(^|:)$dir($|:)"; then
msg "(!) Directory $dir is already in PATH"
else
export PATH="${PATH:+"$PATH:"}$dir" export PATH="${PATH:+"$PATH:"}$dir"
msg "(!) Directory $dir has been added to the end of PATH" [ "$VERBOSE" -eq 1 ] && echo "Appended '$dir' to PATH."
fi done

View File

@@ -1,33 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Add a directory to the front of the PATH if it exists and is not already there # Optimized script to batch prepend directories to PATH.
# Usage: x-path-prepend <dir> # For each given directory, it removes all duplicate occurrences from PATH
# and then prepends it. Directories that do not exist are skipped.
#
# Usage: x-path-prepend <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
# Set verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Function to print messages if VERBOSE is enabled # Ensure that at least one argument is provided.
# $1 - message (string) [ "$#" -lt 1 ] && {
msg() echo "Usage: $0 <directory> [<directory> ...]"
{ exit 1
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
} }
if [ "$#" -ne 1 ]; then # Save the arguments in an array.
echo "Usage: $0 <dir>" dirs=("$@")
exit 1
fi
dir="$1" # Process the directories in reverse order so that the first argument ends up leftmost in PATH.
for ((idx = ${#dirs[@]} - 1; idx >= 0; idx--)); do
dir="${dirs[idx]}"
if [ ! -d "$dir" ]; then # Check if the specified directory exists.
msg "(?) Directory $dir does not exist" if [ ! -d "$dir" ]; then
exit 0 [ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$dir' does not exist. Skipping."
fi continue
fi
if echo "$PATH" | grep -qE "(^|:)$dir($|:)"; then # Remove all duplicate occurrences of the directory from PATH using built-in string operations.
msg "(!) Directory $dir is already in PATH" case ":$PATH:" in
else *":$dir:"*)
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed duplicate occurrences of '$dir' from PATH."
;;
*) ;;
esac
# Prepend the directory to PATH.
export PATH="$dir${PATH:+":$PATH"}" export PATH="$dir${PATH:+":$PATH"}"
msg "(!) Directory $dir has been added to the front of PATH" [ "$VERBOSE" -eq 1 ] && echo "Prepended '$dir' to PATH."
fi done

View File

@@ -1,29 +1,41 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Remove a directory from the PATH # Optimized script to remove directories from PATH.
# Usage: x-path-remove <dir> # For each specified directory, all occurrences are removed from PATH.
#
# Usage: x-path-remove <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
# Set verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Function to print messages if VERBOSE is enabled # Ensure that at least one directory is provided.
# $1 - message (string) [ "$#" -lt 1 ] && {
msg() echo "Usage: $0 <directory> [<directory> ...]"
{ exit 1
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
} }
if [ "$#" -ne 1 ]; then for dir in "$@"; do
echo "Usage: $0 <dir>" # Remove trailing slash if present, unless the directory is "/"
exit 1 [ "$dir" != "/" ] && dir="${dir%/}"
fi
dir="$1" # Check if the directory is present in PATH.
case ":$PATH:" in
*":$dir:"*)
# Remove all occurrences of the directory from PATH using parameter expansion.
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed '$dir' from PATH."
;;
*)
[ "$VERBOSE" -eq 1 ] && echo "(?) '$dir' is not in PATH."
;;
esac
done
if ! echo "$PATH" | grep -qE "(^|:)$dir($|:)"; then export PATH
msg "(?) Directory $dir is not in PATH"
exit 0
fi
export PATH=$(echo -n "$PATH" | awk -v RS=: -v ORS=: "\$0 != \"$dir\"" | sed 's/:$//')
msg "(!) Directory $dir has been removed from PATH"

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/** /**
* Quota usage * Quota usage
* Show quota usage * Show quota usage
@@ -10,6 +11,7 @@
* @license MIT * @license MIT
* @author Ismo Vuorinen <https://github.com/ivuorinen> * @author Ismo Vuorinen <https://github.com/ivuorinen>
*/ */
error_reporting(E_ALL); error_reporting(E_ALL);
$debug = false; $debug = false;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env bash
# #
# DESCRIPTION: # DESCRIPTION:
# Simple recording tool and wrapper around giph (ffmpeg). # Simple recording tool and wrapper around giph (ffmpeg).

View File

@@ -1,71 +1,137 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Check which PHP versions are installed with brew, and create aliases for each installation. # -----------------------------------------------------------------------------
# Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved. # This script caches the list of PHP installations via Homebrew and generates
# shell aliases for each installation. Both the brew list and the generated
# alias definitions are stored in the XDG cache directory.
#
# If the brew list cache is invalid (older than CACHE_TTL), then both caches are
# regenerated. Otherwise, if only the alias cache is stale, it is regenerated
# from the brew list cache.
#
# Usage:
# source x-set-php-aliases.sh
#
# (C) 2023, 2025 Ismo Vuorinen. All Rights Reserved.
# -----------------------------------------------------------------------------
set -euo pipefail set -euo pipefail
# Set verbosity with VERBOSE=1 x-set-php-aliases # Set verbosity level (0 by default; set to 1 or 2 for more detail)
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Enable debugging if verbosity is set to 2
[ "$VERBOSE" = "2" ] && set -x [ "$VERBOSE" = "2" ] && set -x
# Check if brew is installed, if not exit. # Exit early if Homebrew is not installed.
if ! command -v brew &> /dev/null; then if ! command -v brew &> /dev/null; then
echo "Homebrew is not installed. Exiting."
exit 0 exit 0
fi fi
# Function to read installed PHP versions using brew # Determine Homebrew's prefix.
get_php_versions() HOMEBREW_PREFIX="${HOMEBREW_PREFIX:-$(brew --prefix)}"
# Determine the XDG cache directory (default to ~/.cache).
XDG_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}"
CACHE_DIR="${XDG_CACHE}/x-set-php-aliases"
mkdir -p "$CACHE_DIR"
# Define cache file paths.
BREW_LIST_CACHE="${CACHE_DIR}/brew_list.cache"
ALIASES_CACHE="${CACHE_DIR}/aliases.cache"
# Cache time-to-live in seconds (here 300 seconds = 5 minutes).
CACHE_TTL=300
# -----------------------------------------------------------------------------
# Function: cache_is_valid
# Returns 0 if the file exists and its modification time is within TTL.
# -----------------------------------------------------------------------------
cache_is_valid()
{ {
local versions=() local file="$1"
while IFS="" read -r line; do local ttl="$2"
versions+=("$line") if [[ -f "$file" ]]; then
done < <(bkt -- brew list | grep '^php') local mod_time
echo "${versions[@]}" if stat --version &> /dev/null; then
mod_time=$(stat -c %Y "$file")
else
mod_time=$(stat -f %m "$file")
fi
local current_time
current_time=$(date +%s)
if ((current_time - mod_time < ttl)); then
return 0
fi
fi
return 1
} }
# Function to create aliases for each PHP version # -----------------------------------------------------------------------------
create_aliases() # Function: generate_aliases
# Reads PHP formulas (one per line) from the specified file and prints out
# alias definitions for each valid PHP installation.
#
# The following aliases are created (assuming the formula is "php@80"):
#
# p80r : Raw PHP (executable only)
# p80 : PHP with an error reporting flag enabled
# p80s : Launches a PHP local server at localhost:9000
# p80c : Runs composer (if found) using this PHP and error reporting flag
# -----------------------------------------------------------------------------
generate_aliases()
{ {
local php_versions=("$@") local brew_file="$1"
local php_error_reporting='-d error_reporting=22527' local php_error_reporting='-d error_reporting=22527'
local composer_path
composer_path=$(command -v composer 2> /dev/null || true)
for version in "${php_versions[@]}"; do while IFS= read -r version || [[ -n "$version" ]]; do
[ "$VERBOSE" = "1" ] && echo "Setting aliases for $version" # Remove any leading/trailing whitespace.
version=$(echo "$version" | xargs)
[[ -z "$version" ]] && continue
# Drop the dot from version (e.g., 8.0 -> 80) # Compute an alias name: remove dots and replace "php@" with "p"
local php_abbr="${version//\./}" local php_abbr="${version//\./}"
# Replace "php@" with "p" so "php@80" becomes "p80"
local php_alias="${php_abbr//php@/p}" local php_alias="${php_abbr//php@/p}"
# Fetch the exec path once local php_exec="${HOMEBREW_PREFIX}/opt/${version}/bin/php"
local php_exec="$HOMEBREW_PREFIX/opt/$version/bin/php" if [[ -x "$php_exec" ]]; then
echo "alias ${php_alias}r='$php_exec'"
if [ -f "$php_exec" ]; then echo "alias $php_alias='$php_exec $php_error_reporting'"
[ "$VERBOSE" = "1" ] && echo "-> php_exec $php_exec" echo "alias ${php_alias}s='$php_exec -S localhost:9000'"
if [[ -n "$composer_path" ]]; then
# Raw PHP without error_reporting flag. echo "alias ${php_alias}c='$php_exec $php_error_reporting $composer_path'"
alias "${php_alias}r"="$php_exec" fi
else
# PHP with error_reporting flag. [[ "$VERBOSE" -ge 1 ]] && echo "Executable not found: $php_exec (skipping alias for $version)"
alias "$php_alias"="$php_exec $php_error_reporting"
# Local PHP Server.
alias "${php_alias}s"="$php_exec -S localhost:9000"
# Use composer with specific PHP and error_reporting flag on.
alias "${php_alias}c"="$php_exec $php_error_reporting $(which composer)"
fi fi
done done < "$brew_file"
} }
# Main function # -----------------------------------------------------------------------------
main() # Main Cache Update Logic
{ #
local php_versions # If the brew list cache is stale (or missing), regenerate it and the aliases.
php_versions=($(get_php_versions)) # If only the alias cache is stale, regenerate just the alias cache.
create_aliases "${php_versions[@]}" # -----------------------------------------------------------------------------
} if ! cache_is_valid "$BREW_LIST_CACHE" "$CACHE_TTL"; then
[[ "$VERBOSE" -ge 1 ]] && echo "Brew list cache is stale or missing. Regenerating brew list and aliases."
# Regenerate the brew list cache (filtering only PHP formulas).
brew list | grep '^php' > "$BREW_LIST_CACHE"
# Generate the aliases cache from the new brew list.
generate_aliases "$BREW_LIST_CACHE" > "$ALIASES_CACHE"
else
[[ "$VERBOSE" -ge 1 ]] && echo "Using cached brew list from $BREW_LIST_CACHE."
if ! cache_is_valid "$ALIASES_CACHE" "$CACHE_TTL"; then
[[ "$VERBOSE" -ge 1 ]] && echo "Alias cache is stale or missing. Regenerating aliases."
generate_aliases "$BREW_LIST_CACHE" > "$ALIASES_CACHE"
fi
fi
main "$@" # Source the cached alias definitions.
if [[ -f "$ALIASES_CACHE" ]]; then
# shellcheck source=/dev/null
source "$ALIASES_CACHE"
[[ "$VERBOSE" -ge 1 ]] && echo "Aliases loaded from cache."
else
[[ "$VERBOSE" -ge 1 ]] && echo "No alias cache found; no aliases were loaded."
fi

View File

@@ -1,78 +1,112 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# x-sha256sum-matcher # x-sha256sum-matcher
# #
# Check if two files are the same # Compare two files by computing their SHA256 hashes.
# #
# Ismo Vuorinen <https://github.com/ivuorinen> 2023 # Ismo Vuorinen <https://github.com/ivuorinen> 2023
# MIT License # MIT License
set -euo pipefail set -euo pipefail
# ENV Variables # Default settings
: "${VERBOSE:=0}" # VERBOSE=1 x-sha256sum-matcher file1 file2 VERBOSE=0
# Return sha256sum for file # Print usage/help message
# $1 - filename (string) usage()
get_sha256sum()
{ {
sha256sum "$1" | head -c 64 cat << EOF
Usage: $0 [options] file1 file2
Compare two files by computing their SHA256 hashes.
Options:
-v Enable verbose output.
-h, --help Display this help message and exit.
EOF
} }
# Print message if VERBOSE is enabled # Check if a command exists
# $1 - message (string) command_exists()
msg()
{ {
[[ "$VERBOSE" -eq 1 ]] && echo "$1" command -v "$1" > /dev/null 2>&1
} }
# Print error message and exit # Ensure sha256sum is available
# $1 - error message (string) if ! command_exists sha256sum; then
error() echo "Error: sha256sum command not found. Please install it." >&2
{
msg "(!) ERROR: $1"
exit 1 exit 1
} fi
# Validate input arguments # Process command-line options
validate_inputs() while [[ $# -gt 0 ]]; do
{ case "$1" in
if [ "$#" -ne 2 ]; then -h | --help)
echo "Usage: $0 file1 file2" usage
exit 0
;;
-v)
VERBOSE=1
shift
;;
-*)
echo "Error: Unknown option: $1" >&2
usage
exit 1
;;
*)
break
;;
esac
done
# Validate input arguments: expect exactly 2 files
if [[ $# -ne 2 ]]; then
echo "Error: Two file arguments required." >&2
usage
exit 1
fi
file1="$1"
file2="$2"
# Check if files exist and are readable
for file in "$file1" "$file2"; do
if [[ ! -f "$file" ]]; then
echo "Error: File does not exist: $file" >&2
exit 1
elif [[ ! -r "$file" ]]; then
echo "Error: File is not readable: $file" >&2
exit 1 exit 1
fi fi
} done
# Check if file exists # Print verbose messages if enabled
# $1 - filename (string) msg()
check_file_exists()
{ {
local filename=$1 if [[ "$VERBOSE" -eq 1 ]]; then
if [ ! -f "$filename" ]; then echo "$1"
error "File does not exist: $filename"
fi fi
} }
# Main function # Compute SHA256 hash for a file using awk to extract the first field
main() get_sha256sum()
{ {
local file_1=$1 sha256sum "$1" | awk '{print $1}'
local file_2=$2
validate_inputs "$file_1" "$file_2"
check_file_exists "$file_1"
check_file_exists "$file_2"
local file_1_hash
local file_2_hash
file_1_hash=$(get_sha256sum "$file_1")
file_2_hash=$(get_sha256sum "$file_2")
if [ "$file_1_hash" != "$file_2_hash" ]; then
error "Files do not match"
else
msg "(*) Success: Files do match"
fi
} }
main "$@" msg "Computing SHA256 for '$file1'..."
hash1=$(get_sha256sum "$file1")
msg "SHA256 for '$file1': $hash1"
msg "Computing SHA256 for '$file2'..."
hash2=$(get_sha256sum "$file2")
msg "SHA256 for '$file2': $hash2"
if [[ "$hash1" != "$hash2" ]]; then
echo "Files do not match." >&2
exit 1
else
msg "Success: Files match."
exit 0
fi

View File

@@ -1,69 +1,192 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Generate thumbnails using ImageMagick (magick) #
# Generate thumbnails using ImageMagick (magick) with MIME type filtering.
# https://imagemagick.org/script/download.php # https://imagemagick.org/script/download.php
# #
# Defaults to current directory creating thumbnails with 1000x1000 # This script recursively processes images in a given directory (and its subdirectories)
# dimensions and 200px white borders around the original image. # by using the `mimetype` command to detect file types. Files with MIME types that are not
# supported by ImageMagick (as defined in the ALLOWED_MIMETYPES array) are skipped.
# #
# Defaults can be overridden with ENV variables like this: # Defaults (can be overridden by environment variables or command-line options):
# $ THMB_BACKGROUND=black x-thumbgen ~/images/ # THUMB_SOURCE: Directory with images (provided as a positional argument)
# THUMB_OUTPUT: Directory to store thumbnails (default: same as THUMB_SOURCE)
# THUMB_BACKGROUND: Background color (default: white)
# THUMB_RESIZE: Resize dimensions (default: 800x800)
# THUMB_EXTENT: Canvas dimensions (default: 1000x1000)
# THUMB_SUFFIX: Suffix appended to filename (default: _thumb)
# #
# Created by: Ismo Vuorinen <https://github.com/ivuorinen> 2015 # Options:
# -o output_directory Specify the output directory for thumbnails (default: same as source).
# -s suffix Specify a custom suffix for thumbnail filenames (default: _thumb).
# -h, --help Display this help message and exit.
#
# Example:
# THUMB_BACKGROUND=black x-thumbgen.sh -o ~/thumbnails ~/images/
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2015
# Improved in 2025
set -euo pipefail set -euo pipefail
# Default values
: "${THMB_SOURCE:=${1:-}}"
: "${THMB_BACKGROUND:=white}"
: "${THMB_RESIZE:=800x800}"
: "${THMB_EXTENT:=1000x1000}"
# Print usage information
usage() usage()
{ {
echo "Usage: $0 /full/path/to/image/folder" cat << EOF
Usage: $0 [options] source_directory
Options:
-o output_directory Specify the output directory for thumbnails (default: same as source).
-s suffix Specify a custom suffix for thumbnail filenames (default: _thumb).
-h, --help Display this help message and exit.
EOF
exit 1 exit 1
} }
# Check if ImageMagick is installed # Default values (can be overridden by ENV variables)
THUMB_SOURCE=""
THUMB_OUTPUT=""
THUMB_BACKGROUND="${THUMB_BACKGROUND:-white}"
THUMB_RESIZE="${THUMB_RESIZE:-800x800}"
THUMB_EXTENT="${THUMB_EXTENT:-1000x1000}"
THUMB_SUFFIX="${THUMB_SUFFIX:-_thumb}"
# List of MIME types supported by ImageMagick (adjust as needed)
ALLOWED_MIMETYPES=("image/jpeg" "image/png" "image/gif" "image/bmp" "image/tiff" "image/webp")
check_magick_installed() check_magick_installed()
{ {
if ! command -v magick &> /dev/null; then if ! command -v magick &> /dev/null; then
echo "magick not found in PATH, https://imagemagick.org/script/download.php" echo "Error: 'magick' command not found. Please install ImageMagick from https://imagemagick.org/script/download.php" >&2
exit 1 exit 1
fi fi
} }
# Generate thumbnails check_mimetype_installed()
generate_thumbnails()
{ {
local source=$1 if ! command -v mimetype &> /dev/null; then
echo "Error: 'mimetype' command not found. Please install it (e.g. via 'sudo apt install libfile-mimeinfo-perl' on Debian/Ubuntu)." >&2
magick \ exit 1
"${source}/*" \ fi
-resize "$THMB_RESIZE" \
-background "$THMB_BACKGROUND" \
-gravity center \
-extent "$THMB_EXTENT" \
-set filename:fname '%t_thumb.%e' +adjoin '%[filename:fname]'
} }
# Main function # Helper function to check if a given MIME type is allowed
main() is_supported_mimetype()
{ {
# Validate input local mt=$1
if [ -z "$THMB_SOURCE" ]; then for allowed in "${ALLOWED_MIMETYPES[@]}"; do
if [[ "$mt" == "$allowed" ]]; then
return 0
fi
done
return 1
}
# Parse command-line options using getopts
parse_options()
{
while getopts ":o:s:h-:" opt; do
case $opt in
o)
THUMB_OUTPUT="$OPTARG"
;;
s)
THUMB_SUFFIX="$OPTARG"
;;
h)
usage
;;
-)
if [[ "$OPTARG" == "help" ]]; then
usage
else
echo "Error: Unknown option --$OPTARG" >&2
usage
fi
;;
\?)
echo "Error: Invalid option -$OPTARG" >&2
usage
;;
:)
echo "Error: Option -$OPTARG requires an argument." >&2
usage
;;
esac
done
shift $((OPTIND - 1))
# The remaining argument should be the source directory.
if [ $# -lt 1 ]; then
echo "Error: Source directory is required." >&2
usage usage
fi fi
# Check if the source directory is valid THUMB_SOURCE="$1"
if [ ! -d "$THMB_SOURCE" ]; then }
echo "Invalid directory: $THMB_SOURCE"
# Generate thumbnails recursively using find and filtering by MIME type
generate_thumbnails()
{
local source_dir=$1
local output_dir=$2
# Ensure the output directory exists (create if necessary)
if [ ! -d "$output_dir" ]; then
mkdir -p "$output_dir"
fi
# Recursively find all files.
while IFS= read -r -d '' file; do
# Use mimetype to determine the file's MIME type.
file_mimetype=$(mimetype -b "$file")
if ! is_supported_mimetype "$file_mimetype"; then
echo "Skipping unsupported MIME type '$file_mimetype' for file: $file" >&2
continue
fi
# Determine the relative path with respect to the source directory.
rel_path="${file#$source_dir/}"
dir="$(dirname "$rel_path")"
base="$(basename "$rel_path")"
filename="${base%.*}"
ext="${base##*.}"
# Create corresponding output subdirectory
out_dir="${output_dir}/${dir}"
mkdir -p "$out_dir"
outfile="${out_dir}/${filename}${THUMB_SUFFIX}.${ext}"
echo "Processing '$file' -> '$outfile'..."
magick "$file" \
-resize "$THUMB_RESIZE" \
-background "$THUMB_BACKGROUND" \
-gravity center \
-extent "$THUMB_EXTENT" \
"$outfile"
done < <(find "$source_dir" -type f -print0)
}
main()
{
parse_options "$@"
if [ -z "$THUMB_SOURCE" ]; then
echo "Error: Source directory not specified." >&2
usage
fi
if [ ! -d "$THUMB_SOURCE" ]; then
echo "Error: Source directory '$THUMB_SOURCE' does not exist or is not accessible." >&2
exit 1 exit 1
fi fi
# If output directory is not specified, default to the source directory.
if [ -z "$THUMB_OUTPUT" ]; then
THUMB_OUTPUT="$THUMB_SOURCE"
fi
check_magick_installed check_magick_installed
generate_thumbnails "$THMB_SOURCE" check_mimetype_installed
generate_thumbnails "$THUMB_SOURCE" "$THUMB_OUTPUT"
} }
main "$@" main "$@"

View File

@@ -1,12 +1,92 @@
#!/bin/sh #!/bin/sh
# #
# About # x-until-error: Repeatedly execute a command until it fails (non-zero exit status)
# ----- #
# Repeat the command until it fails - always run at least once. # Description:
# This script executes the given command repeatedly until it returns a non-zero
# exit status. It always runs the command at least once.
#
# This script is based on the original work by Steve Kemp.
# Original work Copyright (c) 2013 by Steve Kemp.
#
# The code in the original repository may be modified and distributed under your choice of:
# * The Perl Artistic License (http://dev.perl.org/licenses/artistic.html) or
# * The GNU General Public License, version 2 or later (http://www.gnu.org/licenses/gpl2.txt).
#
# Modifications and enhancements by Ismo Vuorinen on 2025.
#
# Usage:
# x-until-error [--sleep SECONDS] command [arguments...]
#
# Options:
# --sleep SECONDS Wait SECONDS (default: 1) between command executions.
# -h, --help Display this help message.
#
# Example:
# x-until-error --sleep 2 ls -l
"$@" # Default sleep interval between executions.
SLEEP_INTERVAL=1
# If the status code was zero then repeat. # Function to display usage information.
while [ $? -eq 0 ]; do usage()
"$@" {
cat << EOF
Usage: $0 [--sleep SECONDS] command [arguments...]
Repeats the given command until it fails (returns a non-zero exit status).
Options:
--sleep SECONDS Wait SECONDS (default: 1) between command executions.
-h, --help Display this help message.
Example:
$0 --sleep 2 ls -l
EOF
exit 1
}
# Parse command-line options.
while [ $# -gt 0 ]; do
case "$1" in
--sleep)
shift
if [ $# -eq 0 ]; then
echo "Error: --sleep requires a numeric argument." >&2
exit 1
fi
SLEEP_INTERVAL="$1"
shift
;;
-h | --help)
usage
;;
--) # End of options marker.
shift
break
;;
-*)
echo "Error: Unknown option: $1" >&2
usage
;;
*)
break
;;
esac
done
# Ensure a command is provided.
if [ $# -eq 0 ]; then
echo "Error: No command specified." >&2
usage
fi
# Execute the command repeatedly until it fails.
while true; do
"$@"
status=$?
if [ $status -ne 0 ]; then
exit $status
fi
sleep "$SLEEP_INTERVAL"
done done

View File

@@ -1,24 +1,92 @@
#!/bin/sh #!/bin/sh
# #
# About # x-until-success: Repeat the command until it succeeds - always run at least once.
# -----
# Repeat the command until it succeeds - always run at least once.
# #
# This script is based on the original work by Steve Kemp.
# Original work Copyright (c) 2013 by Steve Kemp.
# #
# License # The code in the original repository may be modified and distributed under your choice of:
# ------- # * The Perl Artistic License (http://dev.perl.org/licenses/artistic.html) or
# * The GNU General Public License, version 2 or later (http://www.gnu.org/licenses/gpl2.txt).
# #
# Copyright (c) 2013 by Steve Kemp. All rights reserved. # Modifications and enhancements by Ismo Vuorinen on 2025.
# #
# This script is free software; you can redistribute it and/or modify it under # Usage:
# the same terms as Perl itself. # x-until-success [--sleep SECONDS] command [arguments...]
# #
# The LICENSE file contains the full text of the license. # Options:
# --sleep SECONDS Wait SECONDS (default: 1) between command executions.
# -h, --help Display this help message.
#
# Example:
# x-until-success --sleep 2 ls -l
# Run the first time. # Default sleep interval between command executions.
"$@" SLEEP_INTERVAL=1
# If the status code was not zero then repeat. # Display usage information.
while [ $? -ne 0 ]; do usage()
"$@" {
cat << EOF
Usage: $0 [--sleep SECONDS] command [arguments...]
Repeats the given command until it succeeds (returns a zero exit status).
The command is always executed at least once.
Options:
--sleep SECONDS Wait SECONDS (default: 1) between command executions.
-h, --help Display this help message.
Example:
$0 --sleep 2 ping -c 1 google.com
EOF
exit 1
}
# Parse command-line options.
while [ $# -gt 0 ]; do
case "$1" in
--sleep)
shift
if [ $# -eq 0 ]; then
echo "Error: --sleep requires a numeric argument." >&2
usage
fi
SLEEP_INTERVAL="$1"
shift
;;
-h | --help)
usage
;;
--)
shift
break
;;
-*)
echo "Error: Unknown option: $1" >&2
usage
;;
*)
break
;;
esac
done done
# Ensure that a command is provided.
if [ $# -eq 0 ]; then
echo "Error: No command specified." >&2
usage
fi
# Execute the command at least once.
"$@"
status=$?
# If the command did not succeed, repeat until it does.
while [ $status -ne 0 ]; do
sleep "$SLEEP_INTERVAL"
"$@"
status=$?
done
exit $status

View File

@@ -15,7 +15,7 @@ COLOR_P='\033[1;36m'
COLOR_S='\033[0;36m' COLOR_S='\033[0;36m'
RESET='\033[0m' RESET='\033[0m'
# Print time-based personalized message, using figlet & lolcat if availible # Print time-based personalized message, using figlet & lolcat if available
function welcome_greeting() function welcome_greeting()
{ {
h=$(date +%H) h=$(date +%H)
@@ -51,7 +51,7 @@ function welcome_sysinfo()
fi fi
} }
# Print todays info: Date, IP, weather, etc # Print today's info: Date, IP, weather, etc
function welcome_today() function welcome_today()
{ {
timeout=1 timeout=1

View File

@@ -1,8 +1,17 @@
#!/bin/sh #!/usr/bin/env bash
# #
# Wait until a given host is down (determined by ping) then execute the # Wait until a given host is down (determined by ping) then execute the
# given command # given command
# #
# This script is based on the original work by Steve Kemp.
# Original work Copyright (c) 2013 by Steve Kemp.
#
# The code in the original repository may be modified and distributed under your choice of:
# * The Perl Artistic License (http://dev.perl.org/licenses/artistic.html) or
# * The GNU General Public License, version 2 or later (http://www.gnu.org/licenses/gpl2.txt).
#
# Modifications and enhancements by Ismo Vuorinen on 2025.
#
# Usage: # Usage:
# ./when-down HOST COMMAND... # ./when-down HOST COMMAND...
# #

View File

@@ -1,8 +1,17 @@
#!/bin/sh #!/usr/bin/env bash
# #
# Wait until a given host is online (determined by ping) then execute the # Wait until a given host is online (determined by ping) then execute the
# given command # given command
# #
# This script is based on the original work by Steve Kemp.
# Original work Copyright (c) 2013 by Steve Kemp.
#
# The code in the original repository may be modified and distributed under your choice of:
# * The Perl Artistic License (http://dev.perl.org/licenses/artistic.html) or
# * The GNU General Public License, version 2 or later (http://www.gnu.org/licenses/gpl2.txt).
#
# Modifications and enhancements by Ismo Vuorinen on 2025.
#
# Usage: # Usage:
# ./when-up HOST COMMAND... # ./when-up HOST COMMAND...
# #

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env php
<?php
// @description Create file containing key mappings for aerospace
// Usage: ./create-aerospace-keymaps.sh
// vim: ft=php ts=4 sw=4 sts=4 sr et
$dotfiles_env = getenv("DOTFILES") ?? '~/.dotfiles';
$dest = "$dotfiles_env/docs/aerospace-keybindings.md";
exec("aerospace config --get mode --json", $output);
$output = implode(' ', $output);
$config = json_decode($output, true);
$main = $config['main'];
unset($config['main']);
function process_section(string $title, array $array): string
{
$bindings = $array['binding'] ?? [];
ksort($bindings);
$output = [];
$output[] = sprintf("\n## %s\n", $title);
$k_len = max(array_map('strlen', array_keys($bindings)));
$v_len = max(array_map('strlen', array_values($bindings)));
$output[] = sprintf(
"| %s | %s |",
str_pad('Key', $k_len + 1),
str_pad('Command(s) and actions', $v_len + 1)
);
$output[] = sprintf(
"|%s|%s|",
str_repeat('-', $k_len + 3),
str_repeat('-', $v_len + 3)
);
foreach ($bindings as $key => $value) {
$k = str_pad($key, $k_len + 1);
$v = str_pad($value, $v_len + 1);
$output[] = sprintf("| %s | %s |", $k, $v);
}
return implode("\n", $output);
}
$contents = [];
$contents[] = "# aerospace keybindings";
$contents[] = process_section("main", $main);
ksort($config);
foreach ($config as $mode => $bindings) {
$contents[] = process_section($mode, $bindings);
}
$contents[] = "\nFile generated: " . date("Y-m-d H:i:s") . "\n";
$config_file_name = 'config/aerospace/aerospace.toml';
$config_file_source = './../config/aerospace/aerospace.toml';
$contents[] = "Config file: [$config_file_name]($config_file_source)\n";
$file = implode("\n", $contents);
file_put_contents($dest, $file);

View File

@@ -26,7 +26,7 @@ msgr nested "Change user shell to zsh if it is available and not the current"
# Change user shell to zsh if not that already. # Change user shell to zsh if not that already.
if hash zsh 2> /dev/null; then if hash zsh 2> /dev/null; then
[[ "$SHELL" != $(which zsh) ]] && chsh -s "$(which zsh)" [[ $SHELL != $(which zsh) ]] && chsh -s "$(which zsh)"
fi fi
############################################################################### ###############################################################################
@@ -150,7 +150,7 @@ msgr nested "Settings for Finder"
# Set Desktop as the default location for new Finder windows # Set Desktop as the default location for new Finder windows
# For other paths, use `PfLo` and `file:///full/path/here/` # For other paths, use `PfLo` and `file:///full/path/here/`
defaults write com.apple.finder NewWindowTarget -string "PfDe" defaults write com.apple.finder NewWindowTarget -string "PfDe"
defaults write com.apple.finder NewWindowTargetPath -string "file://${HOME}/Desktop/" defaults write com.apple.finder NewWindowTargetPath -string "file://${HOME}/"
# Show icons for external hard drives, servers, and removable media on the desktop # Show icons for external hard drives, servers, and removable media on the desktop
defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true
@@ -201,6 +201,10 @@ defaults write com.apple.finder FXInfoPanesExpanded -dict \
OpenWith -bool true \ OpenWith -bool true \
Privileges -bool true Privileges -bool true
# Move windows by dragging any part of the window
# From https://nikitabobko.github.io/AeroSpace/goodies
defaults write -g NSWindowShouldDragOnGesture -bool true
############################################################################### ###############################################################################
# Screenshots # # Screenshots #
############################################################################### ###############################################################################

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# update-readme-aliases.sh
# @description Update alias documentation in $DOTFILES/docs/alias.md
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2025
# License: MIT
set -euo pipefail
# Paths
ALIAS_FILE="$DOTFILES/config/alias"
OUTPUT_FILE="$DOTFILES/docs/alias.md"
# Check if alias file exists
if [[ ! -f $ALIAS_FILE ]]; then
echo "Alias file not found: $ALIAS_FILE"
exit 1
fi
# Declare associative array
declare -a alias_table
echo "Parsing aliases..."
while IFS= read -r line; do
# Skip all lines that do not start with 'alias'
if [[ ! $line =~ ^alias\ ]]; then
continue
fi
# Split alias and command and handle both ' and "
if [[ $line =~ ^alias\ ([^=]+)=[\'\"](.*)[\'\"]$ ]]; then
alias_name="${BASH_REMATCH[1]}"
alias_command="${BASH_REMATCH[2]//|/\\|}" # fix markdown table separator
# Save alias to table
alias_table+=("\`$alias_name\`␟\`$alias_command\`")
else
echo "Warning: Could not parse line: $line"
fi
done < "$ALIAS_FILE"
# Sort array by alias name
# shellcheck disable=SC2207
IFS=$'\n' sorted_aliases=($(sort <<< "${alias_table[*]}"))
unset IFS
# Calculate cell max lengths
max_alias_length=5 # "Alias" min length
max_command_length=7 # "Command" min length
for entry in "${sorted_aliases[@]}"; do
IFS=$'␟' read -r alias_name alias_command <<< "$entry"
max_alias_length=$((${#alias_name} > max_alias_length ? ${#alias_name} : max_alias_length))
max_command_length=$((${#alias_command} > max_command_length ? ${#alias_command} : max_command_length))
done
# Empty the markdown file and add header
printf "# Alias Commands\n\nThis file lists all aliases defined in \`config/alias\`.\n\n" > "$OUTPUT_FILE"
# Add table header
printf "| %-*s | %-*s |\n" \
"$max_alias_length" "Alias" \
"$max_command_length" "Command" >> "$OUTPUT_FILE"
# Add table header separator
printf "| %-*s | %-*s |\n" \
"$max_alias_length" "$(printf '%0.s-' $(seq 1 $max_alias_length))" \
"$max_command_length" "$(printf '%0.s-' $(seq 1 $max_command_length))" >> "$OUTPUT_FILE"
# Create table with max cell lengths
for entry in "${sorted_aliases[@]}"; do
IFS=$'␟' read -r alias_name alias_command <<< "$entry"
printf "| %-*s | %-*s |\n" \
"$max_alias_length" "$alias_name" \
"$max_command_length" "$alias_command" >> "$OUTPUT_FILE"
done
{
printf "\n"
printf "Total aliases: %d\n" "${#sorted_aliases[@]}"
printf "Last updated: %s\n" "$(date)"
} >> "$OUTPUT_FILE"
# Announce process completion
echo "Alias documentation updated: $OUTPUT_FILE"

View File

@@ -1,7 +1,9 @@
# vim: ft=sshconfig
Include shared.d/* Include shared.d/*
Include local.d/* Include local.d/*
Host * Host *
ServerAliveInterval 300 # send null packets every 5min to keep connection alive ServerAliveInterval 300 # send null packets every 5min to keep connection alive
ServerAliveCountMax 2 # if the server doesn't respond 2 times, it's gone so give up ServerAliveCountMax 2 # if the server doesn't respond 2 times, it's gone so give up
# IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" ForwardAgent yes
# IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

View File

@@ -1,3 +1,5 @@
# vim: ft=sshconfig
Host t1 Host t1
User ubuntu User ubuntu
HostName t1.home.antiprocess.net HostName t1.home.antiprocess.net
@@ -14,4 +16,3 @@ Host t4
User ubuntu User ubuntu
HostName t4.home.antiprocess.net HostName t4.home.antiprocess.net
IdentityFile ~/.ssh/id_rsa IdentityFile ~/.ssh/id_rsa

1
tools/apt.txt Normal file
View File

@@ -0,0 +1 @@
# apt install list