Compare commits

..

1 Commits

Author SHA1 Message Date
8460c2d408 feat: switch to chezmoi
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-11-13 00:26:19 +02:00
111 changed files with 10982 additions and 927 deletions

53
.chezmoi.yaml.tmpl Normal file
View File

@@ -0,0 +1,53 @@
{{- $hostname := .chezmoi.hostname -}}
{{- $username := .chezmoi.username -}}
{{- $osid := .chezmoi.os -}}
sourceDir: {{ .chezmoi.sourceDir | quote }}
data:
hostname: {{ $hostname | quote }}
username: {{ $username | quote }}
osid: {{ $osid | quote }}
# Detect if we're on macOS
is_macos: {{ eq $osid "darwin" }}
# Detect if we're on Linux
is_linux: {{ eq $osid "linux" }}
# Host-specific flags
is_air: {{ eq $hostname "air" }}
is_lakka: {{ eq $hostname "lakka" }}
is_tunkki: {{ eq $hostname "tunkki" }}
is_s: {{ eq $hostname "s" }}
# Merge strategy for dealing with conflicts
merge:
command: "nvim"
args:
- "-d"
- "{{ "{{" }} .Destination {{ "}}" }}"
- "{{ "{{" }} .Source {{ "}}" }}"
- "{{ "{{" }} .Target {{ "}}" }}"
# Template options
template:
options:
- "missingkey=error"
# Diff options
diff:
exclude:
- "scripts"
pager: "delta"
# Git options
git:
autoCommit: false
autoPush: false
# Hooks
hooks:
read-source-state:
pre:
command: ".local/share/chezmoi/.chezmoihooks/pre-read-source-state.sh"

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Pre-read-source-state hook for chezmoi
# This runs before chezmoi reads the source state
set -e
DOTFILES="${CHEZMOI_SOURCE_DIR:-$HOME/.local/share/chezmoi}"
# Update git submodules if they exist
if [ -d "$DOTFILES/.git" ]; then
cd "$DOTFILES"
git submodule update --init --recursive --quiet || true
fi

90
.chezmoiignore Normal file
View File

@@ -0,0 +1,90 @@
# Chezmoi ignore file
# Files and directories that should not be managed by chezmoi
# Git and version control
.git/
.gitignore
.gitattributes
.gitmodules
# GitHub
.github/
# Documentation
README.md
*.md
docs/
AGENTS.md
# Development tools
.vscode/
.serena/
.claude/
node_modules/
# Testing
tests/
test-all.sh
# Configuration files for the repo itself
.editorconfig
.editorconfig-checker.json
.eslintrc.json
.prettierrc.js
.prettierignore
.markdownlint.json
.markdownlintignore
.mega-linter.yml
.commitlintrc.json
.releaserc.json
.shellcheckrc
.yamlignore
.yamllint.yml
.browserslistrc
.actrc
.luarc.json
.ignore
stylua.toml
phpcs.xml
# Package management
package.json
yarn.lock
# Python and Node version files
.python-version
.nvmrc
.go-version
# Dotbot (old system)
install.conf.yaml
tools/dotbot/
tools/dotbot-*/
tools/dotbot-defaults.yaml
# Installation and build scripts in root
install
add-submodules.sh
# Chezmoi-specific directories (not to be managed)
.chezmoihooks/
# Host-specific directories (will be handled via templates)
{{- if not .is_air }}
hosts/air/
{{- end }}
{{- if not .is_lakka }}
hosts/lakka/
{{- end }}
{{- if not .is_tunkki }}
hosts/tunkki/
{{- end }}
{{- if not .is_s }}
hosts/s/
{{- end }}
# Secrets (should use separate secrets management)
secrets/
# macOS specific files
.DS_Store

View File

@@ -9,7 +9,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
[*.fish]
max_line_length = 120
max_line_length = 80
[*.md]
max_line_length = 120
@@ -49,6 +49,3 @@ ignore = true
[plan]
trim_trailing_whitespace = false
max_line_length = off
[base/hammerspoon/hammerspoon.types.lua]
max_line_length = off

3
.eslintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": ["@ivuorinen"]
}

8
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
---
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'

View File

@@ -16,10 +16,10 @@ module.exports = {
excludeTypes: [],
renderTypeSection: (label, commits) => {
renderTypeSection: function (label, commits) {
let text = `\n## ${label}\n\n`
commits.forEach((commit) => {
commits.forEach(commit => {
const scope = commit.scope ? `**${commit.scope}:** ` : ''
text += `- ${scope}${commit.subject}\n`
})
@@ -27,10 +27,10 @@ module.exports = {
return text
},
renderChangelog: (release, changes) => {
renderChangelog: function (release, changes) {
const now = new Date()
const d = now.toISOString().substring(0, 10)
const header = `# ${release} - ${d}\n`
return `${header}${changes}\n\n`
return header + changes + '\n\n'
},
}

View File

@@ -18,7 +18,7 @@ jobs:
permissions: write-all
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Create changelog text
id: changelog

View File

@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Yarn Lock Changes
uses: Simek/yarn-lock-changes@61d1a0595070b79c1abdc8e1e5a5f5d98b18918c # v0.12.2
@@ -35,4 +35,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run PR Lint
uses: ivuorinen/actions/pr-lint@fb25736f7e7a438979c11764e9fe6a100278b4c5 # v2026.01.01
uses: ivuorinen/actions/pr-lint@ff0ca4bc920c518b2ce2dc20c5e5a6e95f76dee0 # v2025.11.02

View File

@@ -24,7 +24,7 @@ jobs:
version: ${{ steps.daily-version.outputs.version }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Create tag if necessary
uses: fregante/daily-version-action@fb1a60b7c4daf1410cd755e360ebec3901e58588 # v2.1.3
@@ -40,7 +40,7 @@ jobs:
- name: Create release
if: steps.daily-version.outputs.created
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ steps.daily-version.outputs.version }}

View File

@@ -23,13 +23,13 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
- run: pip install pre-commit && pre-commit autoupdate
- uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
- uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update/pre-commit-hooks

View File

@@ -29,4 +29,4 @@ jobs:
issues: write
steps:
- uses: ivuorinen/actions/sync-labels@fb25736f7e7a438979c11764e9fe6a100278b4c5 # v2026.01.01
- uses: ivuorinen/actions/sync-labels@ff0ca4bc920c518b2ce2dc20c5e5a6e95f76dee0 # v2025.11.02

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
submodules: true
fetch-depth: 2

1
.gitignore vendored
View File

@@ -11,7 +11,6 @@
.nfs*
.scannerwork
.vscode
.yarn/
!config/git/local.d/.gitkeep
!config/nvim/spell/.gitkeep
!config/zed/settings.json

View File

@@ -1 +1 @@
1.25.5
1.25.3

19
.markdownlint.json Normal file
View File

@@ -0,0 +1,19 @@
{
"extends": "@ivuorinen/markdownlint-config",
"code-block-style": {
"style": "fenced"
},
"code-fence-style": {
"style": "backtick"
},
"heading-style": {
"style": "atx"
},
"no-duplicate-heading": {
"siblings_only": true
},
"required-headings": false,
"ul-style": {
"style": "dash"
}
}

View File

@@ -16,9 +16,12 @@ SHOW_SKIPPED_LINTERS: false # Show skipped linters in MegaLinter log
TYPESCRIPT_DEFAULT_STYLE: prettier # Default style for TypeScript
DISABLE_LINTERS:
- REPOSITORY_DEVSKIM
- JAVASCRIPT_ES # using biome
- JAVASCRIPT_PRETTIER # using biome
- JAVASCRIPT_ES
YAML_YAMLLINT_CONFIG_FILE: .yamllint.yml
MARKDOWN_MARKDOWNLINT_CONFIG_FILE: .markdownlint.json
JAVASCRIPT_ES_CONFIG_FILE: .eslintrc.json
TYPESCRIPT_ES_CONFIG_FILE: .eslintrc.json
REPOSITORY_GIT_DIFF_DISABLE_ERRORS: true
FILTER_REGEX_EXCLUDE: >
(node_modules|tools|config/cheat/cheatsheets/community|config/cheat/cheatsheets/tldr|config/fzf|config/zsh|config/tmux/plugins)

2
.nvmrc
View File

@@ -1 +1 @@
24.12.0
24.11.0

View File

@@ -20,22 +20,22 @@ repos:
- id: end-of-file-fixer
- id: mixed-line-ending
args: [--fix=auto]
- id: pretty-format-json
args: [--autofix, --no-sort-keys]
- repo: local
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.45.0
hooks:
- id: biome-check
name: Biome Check
entry: yarn biome check --write --files-ignore-unknown=true --no-errors-on-unmatched
language: system
files: \.(js|ts|jsx|tsx|json|md)$
- id: markdownlint
args: [-c, .markdownlint.json, --fix]
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
hooks:
- id: yamllint
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.11.0
hooks:
- id: shellcheck
@@ -45,15 +45,19 @@ repos:
- id: shfmt
- repo: https://github.com/rhysd/actionlint
rev: v1.7.10
rev: v1.7.8
hooks:
- id: actionlint
- repo: https://github.com/renovatebot/pre-commit-hooks
rev: 42.2.0
hooks:
- id: renovate-config-validator
- repo: https://github.com/JohnnyMorganz/StyLua
rev: v2.3.1
hooks:
- id: stylua # or stylua-system / stylua-github
exclude: hammerspoon\.types\.lua$
- repo: https://github.com/hugoh/pre-commit-fish.git
rev: v1.2

16
.prettierignore Normal file
View File

@@ -0,0 +1,16 @@
# vim: ft=gitignore
.mypy_cache/*
Brewfile.lock.json
base/plan
config/cheat/cheatsheets/community
config/cheat/cheatsheets/tldr
config/fzf/*
config/nvim/*
config/op/plugins/used_plugins/*
config/tmux/plugins/*
config/zsh/*
lazy-lock.json
local/bin/antigen.zsh
local/bin/asdf
tools/antidote/*
tools/dotbot*

15
.prettierrc.js Normal file
View File

@@ -0,0 +1,15 @@
module.exports = {
...require('@ivuorinen/prettier-config'),
trailingComma: 'all',
// Add custom options below:
overrides: [
{
files: '*.md',
options: {
printWidth: 120,
proseWrap: 'preserve',
tabWidth: 2,
},
},
],
}

View File

@@ -1 +1 @@
3.14.2
3.14.0

View File

@@ -1,5 +0,0 @@
{
"sonarCloudOrganization": "ivuorinen",
"projectKey": "ivuorinen_dotfiles",
"region": "EU"
}

View File

@@ -1 +0,0 @@
nodeLinker: node-modules

View File

@@ -2673,7 +2673,7 @@ function canvas:delete(fadeOutTime) end
--- optionally return false to indicate that you do not wish to accept the item being dragged.
--- "exit" - the user has moved the item out of the canvas; if the previous "enter" callback returned false, this
--- message will also occur when the user finally releases the items being dragged.
--- "receive" - indicates that the user has released the dragged object while it is still within the canvas frame.
--- "receive" - indicates that the user has released the dragged object while it is still within the canvas frame.
--- When your callback receives this message, you can optionally return false to indicate to the sending application
--- that you do not want to accept the dragged item -- this may affect the animations provided by the sending
--- application.
@@ -2810,7 +2810,7 @@ function canvas:minimumTextSize(index, text) end
--- element. The message will be "mouseDown".
--- trackMouseUp - indicates that a callback should be invoked when a mouse button has been released over the canvas
--- element. The message will be "mouseUp".
--- trackMouseEnterExit - indicates that a callback should be invoked when the mouse pointer enters or exits the
--- trackMouseEnterExit - indicates that a callback should be invoked when the mouse pointer enters or exits the
--- canvas element. The message will be "mouseEnter" or "mouseExit".
--- trackMouseMove - indicates that a callback should be invoked when the mouse pointer moves within the canvas
--- element. The message will be "mouseMove".
@@ -4197,7 +4197,7 @@ hs.drawing.windowLevels = nil
--- hs.drawing
--- for text drawing objects.
---
--- Note: This method returns the default font, size, color, and paragraphStyle used by hs.drawing for text objects.
--- Note: This method returns the default font, size, color, and paragraphStyle used by hs.drawing for text objects.
--- If you modify a drawing object's defaults with hs.drawing:setColor , hs.drawing:setTextFont , or
--- hs.drawing:setTextSize , the changes will not be reflected by this function.
---@return table
@@ -4662,7 +4662,7 @@ hs.drawing.color.ansiTerminalColors = nil
---@type table
hs.drawing.color.hammerspoon = nil
--- A collection of colors representing the X11 color names as defined at
--- A collection of colors representing the X11 color names as defined at
--- https://en.wikipedia.org/wiki/Web_colors#X11_color_names (names in lowercase)
---@type any
hs.drawing.color.x11 = nil
@@ -7022,7 +7022,7 @@ function hs.http.doAsyncRequest(url, method, data, headers, callback, cachePolic
--- use the asynchronous functions.
--- If you attempt to connect to a local Hammerspoon server created with hs.httpserver , then Hammerspoon will block
--- until the connection times out (60 seconds), return a failed result due to the timeout, and then the hs.httpserver
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- Use hs.http.doAsyncRequest to avoid this.
--- If the Content-Type response header begins text/ then the response body return value is a UTF8 string. Any other
--- content type passes the response body, unaltered, as a stream of bytes.
@@ -7054,7 +7054,7 @@ function hs.http.encodeForQuery(string) end
--- are encouraged to use the asynchronous functions
--- If you attempt to connect to a local Hammerspoon server created with hs.httpserver , then Hammerspoon will block
--- until the connection times out (60 seconds), return a failed result due to the timeout, and then the hs.httpserver
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- Use hs.http.asyncGet to avoid this.
---@param url string
---@param headers table|nil
@@ -7072,7 +7072,7 @@ function hs.http.get(url, headers) end
--- are encouraged to use the asynchronous functions
--- If you attempt to connect to a local Hammerspoon server created with hs.httpserver , then Hammerspoon will block
--- until the connection times out (60 seconds), return a failed result due to the timeout, and then the hs.httpserver
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- Use hs.http.asyncPost to avoid this.
---@param url string
---@param data string|nil
@@ -7091,7 +7091,7 @@ function hs.http.post(url, data, headers) end
--- are encouraged to use the asynchronous functions
--- If you attempt to connect to a local Hammerspoon server created with hs.httpserver , then Hammerspoon will block
--- until the connection times out (60 seconds), return a failed result due to the timeout, and then the hs.httpserver
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- callback function will be invoked (so any side effects of the function will occur, but it's results will be lost).
--- Use hs.http.asyncPost to avoid this.
---@param url string
---@param data string|nil
@@ -7374,7 +7374,7 @@ function hs.httpserver.hsminweb.new(documentRoot) end
--- Get or set the access-list table for the hsminweb web server
---
--- Note: The access-list feature works by comparing the request headers against a list of tests which either accept or
--- reject the request. If no access list is set (i.e. it is assigned a value of nil ), then all requests are served.
--- reject the request. If no access list is set (i.e. it is assigned a value of nil ), then all requests are served.
--- If a table is passed into this method, then any request which is not explicitly accepted by one of the tests
--- provided is rejected (i.e. there is an implicit "reject" at the end of the list).
--- The access-list table is a list of tests which are evaluated in order. The first test which matches a given
@@ -7919,7 +7919,7 @@ function hs.httpserver.hsminweb.cgilua.urlcode.insertfield(table, key, value) en
--- Parse the query string and store the key-value pairs in the provided table.
---
--- Note: The specification allows for the same key to be assigned multiple values in an encoded string, but does not
--- specify the behavior; by convention, web servers assign these multiple values to the same key in an array (table).
--- specify the behavior; by convention, web servers assign these multiple values to the same key in an array (table).
--- This function follows that convention. This is most commonly used by forms which allow selecting multiple options
--- via check boxes or in a selection list.
--- This function uses cgilua.urlcode.insertfield to build the key-value table.
@@ -10225,7 +10225,7 @@ function echorequest:seeAllUnexpectedPackets(state) end
--- Sends a single ICMP Echo Request packet.
---
--- Note: By convention, unless you are trying to test for specific network fragmentation or congestion problems, ICMP
--- Echo Requests are generally 64 bytes in length (this includes the 8 byte header, giving 56 bytes of payload data).
--- Echo Requests are generally 64 bytes in length (this includes the 8 byte header, giving 56 bytes of payload data).
--- If you do not specify a payload, a default payload which will result in a packet size of 64 bytes is constructed.
---@param payload string|nil
---@return echoRequestObject|boolean|nil
@@ -15169,7 +15169,7 @@ function watcher:stop() end
---@class hs.utf8
hs.utf8 = {}
--- A collection of UTF-8 characters already converted from codepoint and available as convenient key-value pairs.
--- A collection of UTF-8 characters already converted from codepoint and available as convenient key-value pairs.
--- UTF-8 printable versions of common Apple and OS X special keys are predefined and others can be added with
--- hs.utf8.registerCodepoint(label, codepoint)
--- for your own use.
@@ -15238,7 +15238,7 @@ function hs.utf8.hexDump(inputString, count) end
--- hs.utf8.registeredKeys[label]
--- for convenience and readability.
---
--- Note: If a codepoint label was previously registered, this will overwrite the previous value with a new one.
--- Note: If a codepoint label was previously registered, this will overwrite the previous value with a new one.
--- Because many of the special keys you may want to register have different variants, this allows you to easily modify
--- the existing predefined defaults to suite your preferences.
--- The return value is merely syntactic sugar and you do not need to save it locally; it can be safely ignored --
@@ -15585,13 +15585,13 @@ function hs.webview.newBrowser(rect, preferencesTable, userContentController) en
---@return webviewObject
function webview:allowGestures(value) end
--- Get or set whether or not the webview will respond to magnification gestures from a trackpad or magic mouse.
--- Get or set whether or not the webview will respond to magnification gestures from a trackpad or magic mouse.
--- Default is false.
---@param value any
---@return webviewObject
function webview:allowMagnificationGestures(value) end
--- Get or set whether or not the webview will respond to the navigation gestures from a trackpad or magic mouse.
--- Get or set whether or not the webview will respond to the navigation gestures from a trackpad or magic mouse.
--- Default is false.
---@param value any
---@return webviewObject
@@ -16455,7 +16455,7 @@ function usercontent:removeAllScripts() end
--- } catch(err) {
--- console.log('The controller does not exist yet');
--- }
--- Where name matches the name specified in the constructor and message-object is the object to post to the function.
--- Where name matches the name specified in the constructor and message-object is the object to post to the function.
--- This object can be a number, string, date, array, dictionary(table), or nil.
---@param fn function
---@return usercontentControllerObject
@@ -17860,4 +17860,4 @@ hs.window.tiling = {}
---@param preserveRelativeArea? any
---@param animationDuration? hs.window.animationDuration|nil
---@return any
function hs.window.tiling.tileWindows(windows, rect, desiredAspect, processInOrder, preserveRelativeArea, animationDuration) end
function hs.window.tiling.tileWindows(windows, rect, desiredAspect, processInOrder, preserveRelativeArea, animationDuration) end

View File

@@ -193,12 +193,11 @@ end)
-- Paste 1Password secret with Meh + P
f18:bind({}, 'p', function()
local output, status =
hs.execute('op read "op://Svea/3hzhctmvovbwlgulv7mgy25rf4/login-input"', true)
local output, status = hs.execute('op read "op://Svea/3hzhctmvovbwlgulv7mgy25rf4/login-input"', true)
if status then
hs.eventtap.keyStrokes(output:gsub('%s+$', '')) -- trim trailing whitespace
else
hs.alert.show '1Password CLI error'
hs.alert.show('1Password CLI error')
end
end)

View File

@@ -1,103 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.1/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"files": {
"ignoreUnknown": true,
"includes": [
"**",
"!!**/.mypy_cache",
"!!**/Brewfile.lock.json",
"!!**/base/plan",
"!!**/config/cheat/cheatsheets/community",
"!!**/config/cheat/cheatsheets/tldr",
"!!**/config/fzf",
"!!**/config/nvim",
"!!**/config/op/plugins/used_plugins",
"!!**/config/tmux/plugins",
"!!**/config/zsh",
"!!**/config/vim",
"!!**/lazy-lock.json",
"!!**/local/bin/antigen.zsh",
"!!**/local/bin/asdf",
"!!**/tools/antidote",
"!!**/tools/dotbot",
"!!**/node_modules"
]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "warn",
"noUnusedImports": "warn"
},
"style": {
"useConst": "warn",
"useTemplate": "warn"
},
"suspicious": {
"noExplicitAny": "warn",
"noConsole": "off"
}
}
},
"javascript": {
"formatter": {
"enabled": true,
"quoteStyle": "single",
"jsxQuoteStyle": "double",
"trailingCommas": "all",
"semicolons": "asNeeded",
"arrowParentheses": "always",
"bracketSpacing": true,
"bracketSameLine": false,
"quoteProperties": "asNeeded",
"indentStyle": "space",
"indentWidth": 2
}
},
"json": {
"parser": {
"allowComments": true,
"allowTrailingCommas": false
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 80
}
},
"overrides": [
{
"includes": ["*.md", "*.mdx"],
"formatter": {
"enabled": true,
"lineWidth": 120
}
},
{
"includes": ["package.json"],
"json": {
"formatter": {
"enabled": true,
"indentWidth": 2
}
}
}
]
}

View File

@@ -6,19 +6,21 @@
*
* @param {Object} windows - All windows in the current space.
* @param {Object} screenFrame - The frame of the current screen.
* @param {Object} state - The state of the current space.
* @param {Object} extendedFrames - The frames of the windows in the current space.
* @return {Object} - The frames for the windows in the current space.
*/
function layout() {
return {
name: 'Almost Maximize',
getFrameAssignments: (windows, screenFrame) => {
getFrameAssignments: (windows, screenFrame, state, extendedFrames) => {
const width = screenFrame.width * 0.95
const height = screenFrame.height * 0.95
const x = (screenFrame.width - width) / 2
const y = (screenFrame.height - height) / 2
const windowFrames = {}
windows.forEach((window) => {
windows.forEach(window => {
windowFrames[window.id] = {
Y: screenFrame.y + y,
x: screenFrame.x + x,
@@ -31,5 +33,3 @@ function layout() {
},
}
}
module.exports = layout()

View File

@@ -23,7 +23,5 @@ github.com/junegunn/fzf@latest
golang.org/x/tools/gopls@latest
// A language for writing HTML user interfaces in Go.
github.com/a-h/templ/cmd/templ@latest
// A tool for glamorous shell scripts 🎀
github.com/charmbracelet/gum@latest
// A terminal session manager
github.com/joshmedeski/sesh/v2@latest

View File

@@ -1,3 +1,5 @@
#!/usr/bin/env bash
#
# This file is secret and wont be added to the git repo.
export GITLAB_API_TOKEN=""

0
config/fish/completions/docker.fish Normal file → Executable file
View File

View File

@@ -26,7 +26,7 @@ if status is-interactive
# type -q fnm; and fnm env --use-on-cd --shell fish | source
type -q load_nvm; and load_nvm >/dev/stderr
# Initialize other tools if available
# Intialize other tools if available
type -q zoxide; and zoxide init fish | source
# Start tmux if not already running and not in SSH
@@ -40,7 +40,7 @@ set -gx PATH $PATH $HOME/.lmstudio/bin
# vim: ft=fish ts=4 sw=4 et:
# opencode
fish_add_path $HOME/.opencode/bin
fish_add_path /Users/ivuorinen/.opencode/bin
# Added by OrbStack: command-line tools and integration
# This won't be added again if you remove it.

View File

@@ -1,3 +1,5 @@
#!/usr/bin/env fish
# XDG Base Directory Specification
set -q XDG_CONFIG_HOME; or set -x XDG_CONFIG_HOME "$HOME/.config"
set -q XDG_DATA_HOME; or set -x XDG_DATA_HOME "$HOME/.local/share"

View File

@@ -26,6 +26,7 @@ Options:
return 1
end
if set --query _flag_exact
set --function apps (__macos_app_find --exact $argv)
or return 1

View File

@@ -139,6 +139,7 @@ Options:
return 0
end
__macos_mac_touchid_sudo::check_supported
or return

View File

@@ -1,25 +1,23 @@
function __ssh_agent_is_started -d "check if ssh agent is already started"
if test -n "$SSH_CONNECTION"
# This is an SSH session
ssh-add -l >/dev/null 2>&1
if test $status -eq 0 -o $status -eq 1
# An SSH agent was forwarded
return 0
end
end
if test -n "$SSH_CONNECTION"
# This is an SSH session
ssh-add -l > /dev/null 2>&1
if test $status -eq 0 -o $status -eq 1
# An SSH agent was forwarded
return 0
end
end
if begin
test -f "$SSH_ENV"; and test -z "$SSH_AGENT_PID"
end
source $SSH_ENV >/dev/null
end
if begin; test -f "$SSH_ENV"; and test -z "$SSH_AGENT_PID"; end
source $SSH_ENV > /dev/null
end
if test -z "$SSH_AGENT_PID"
return 1
end
if test -z "$SSH_AGENT_PID"
return 1
end
ssh-add -l >/dev/null 2>&1
if test $status -eq 2
return 1
end
ssh-add -l > /dev/null 2>&1
if test $status -eq 2
return 1
end
end

View File

@@ -1,5 +1,5 @@
function __ssh_agent_start -d "start a new ssh agent"
ssh-agent -c | sed 's/^echo/#echo/' >$SSH_ENV
chmod 600 $SSH_ENV
source $SSH_ENV >/dev/null
ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV
chmod 600 $SSH_ENV
source $SSH_ENV > /dev/null
end

View File

@@ -3,8 +3,10 @@ function _fzf_extract_var_info --argument-names variable_name set_show_output --
# Extract only the lines about the variable, all of which begin with either
# $variable_name: ...or... $variable_name[
string match --regex "^\\\$$variable_name(?::|\[).*" <$set_show_output |
# Strip the variable name prefix, including ": " for scope info lines
string replace --regex "^\\\$$variable_name(?:: )?" '' |
# Distill the lines of values, replacing...
# [1]: |value|
# ...with...

View File

@@ -24,6 +24,7 @@ function _fzf_search_directory --description "Search the current directory. Repl
set -f file_paths_selected ($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
end
if test $status -eq 0
commandline --current-token --replace -- (string escape -- $file_paths_selected | string join ' ')
end

View File

@@ -1,8 +1,8 @@
function _puffer_fish_expand_bang
switch (commandline -t)
case '!'
commandline -t $history[1]
case '*'
commandline -i '!'
case '!'
commandline -t $history[1]
case '*'
commandline -i '!'
end
end

View File

@@ -1,9 +1,9 @@
function _puffer_fish_expand_lastarg
switch (commandline -t)
case '!'
commandline -t ""
commandline -f history-token-search-backward
case '*'
commandline -i '$'
case '!'
commandline -t ""
commandline -f history-token-search-backward
case '*'
commandline -i '$'
end
end

View File

@@ -1,5 +1,5 @@
function _sponge_clear_state
set --erase --global _sponge_current_command
set --erase --global _sponge_current_command_exit_code
set --erase --global _sponge_current_command_previously_in_history
set --erase --global _sponge_current_command
set --erase --global _sponge_current_command_exit_code
set --erase --global _sponge_current_command_previously_in_history
end

View File

@@ -1,3 +1,3 @@
function _sponge_on_exit --on-event fish_exit
sponge_delay=0 _sponge_remove_from_history
sponge_delay=0 _sponge_remove_from_history
end

View File

@@ -1,24 +1,24 @@
function _sponge_on_postexec --on-event fish_postexec
set --global _sponge_current_command_exit_code $status
set --global _sponge_current_command_exit_code $status
# Remove command from the queue if it's been added previously
if set --local index (contains --index -- $_sponge_current_command $_sponge_queue)
set --erase _sponge_queue[$index]
end
# Remove command from the queue if it's been added previously
if set --local index (contains --index -- $_sponge_current_command $_sponge_queue)
set --erase _sponge_queue[$index]
end
# Ignore empty commands
if test -n $_sponge_current_command
set --local command ''
# Run filters
for filter in $sponge_filters
if $filter \
$_sponge_current_command \
$_sponge_current_command_exit_code \
$_sponge_current_command_previously_in_history
set command $_sponge_current_command
break
end
end
set --prepend --global _sponge_queue $command
# Ignore empty commands
if test -n $_sponge_current_command
set --local command ''
# Run filters
for filter in $sponge_filters
if $filter \
$_sponge_current_command \
$_sponge_current_command_exit_code \
$_sponge_current_command_previously_in_history
set command $_sponge_current_command
break
end
end
set --prepend --global _sponge_queue $command
end
end

View File

@@ -1,16 +1,16 @@
function _sponge_on_preexec --on-event fish_preexec \
--argument-names command
_sponge_clear_state
--argument-names command
_sponge_clear_state
set --global _sponge_current_command $command
set --global _sponge_current_command $command
builtin history search --case-sensitive --exact --max=1 --null $command \
| read --local --null found_entries
builtin history search --case-sensitive --exact --max=1 --null $command \
| read --local --null found_entries
# If a command is in the history and in the queue, ignore it, like if it wasnt in the history
if test (count $found_entries) -ne 0; and not contains $command $_sponge_queue
set --global _sponge_current_command_previously_in_history true
else
set --global _sponge_current_command_previously_in_history false
end
# If a command is in the history and in the queue, ignore it, like if it wasnt in the history
if test (count $found_entries) -ne 0; and not contains $command $_sponge_queue
set --global _sponge_current_command_previously_in_history true
else
set --global _sponge_current_command_previously_in_history false
end
end

View File

@@ -1,5 +1,5 @@
function _sponge_on_prompt --on-event fish_prompt
if test $sponge_purge_only_on_exit = false
_sponge_remove_from_history
end
if test $sponge_purge_only_on_exit = false
_sponge_remove_from_history
end
end

View File

@@ -1,9 +1,9 @@
function _sponge_remove_from_history
while test (count $_sponge_queue) -gt $sponge_delay
builtin history delete --case-sensitive --exact -- $_sponge_queue[-1]
set --erase _sponge_queue[-1]
end
while test (count $_sponge_queue) -gt $sponge_delay
builtin history delete --case-sensitive --exact -- $_sponge_queue[-1]
set --erase _sponge_queue[-1]
end
builtin history save
builtin history save
end

View File

@@ -1,29 +1,29 @@
function bass
set -l bash_args $argv
set -l bass_debug
if test "$bash_args[1]_" = -d_
set bass_debug true
set -e bash_args[1]
end
set -l bash_args $argv
set -l bass_debug
if test "$bash_args[1]_" = '-d_'
set bass_debug true
set -e bash_args[1]
end
set -l script_file (mktemp)
if command -v python3 >/dev/null 2>&1
command python3 -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
else
command python -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
end
set -l bass_status $status
if test $bass_status -ne 0
return $bass_status
end
set -l script_file (mktemp)
if command -v python3 >/dev/null 2>&1
command python3 -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
else
command python -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
end
set -l bass_status $status
if test $bass_status -ne 0
return $bass_status
end
if test -n "$bass_debug"
cat $script_file
end
source $script_file
command rm $script_file
if test -n "$bass_debug"
cat $script_file
end
source $script_file
command rm $script_file
end
function __bass_usage
echo "Usage: bass [-d] <bash-command>"
echo "Usage: bass [-d] <bash-command>"
end

View File

@@ -1,16 +1,16 @@
function load_nvm --on-variable="PWD"
set -l default_node_version (nvm version default)
set -l node_version (nvm version)
set -l nvmrc_path (nvm_find_nvmrc)
if test -n "$nvmrc_path"
set -l nvmrc_node_version (nvm version (cat $nvmrc_path))
if test "$nvmrc_node_version" = N/A
nvm install (cat $nvmrc_path)
else if test "$nvmrc_node_version" != "$node_version"
nvm use $nvmrc_node_version
end
else if test "$node_version" != "$default_node_version"
echo "Reverting to default Node version"
nvm use default
set -l default_node_version (nvm version default)
set -l node_version (nvm version)
set -l nvmrc_path (nvm_find_nvmrc)
if test -n "$nvmrc_path"
set -l nvmrc_node_version (nvm version (cat $nvmrc_path))
if test "$nvmrc_node_version" = "N/A"
nvm install (cat $nvmrc_path)
else if test "$nvmrc_node_version" != "$node_version"
nvm use $nvmrc_node_version
end
else if test "$node_version" != "$default_node_version"
echo "Reverting to default Node version"
nvm use default
end
end

View File

@@ -1,3 +1,3 @@
function nvm_find_nvmrc
bass source $NVM_DIR/nvm.sh --no-use ';' nvm_find_nvmrc
bass source $NVM_DIR/nvm.sh --no-use ';' nvm_find_nvmrc
end

View File

@@ -158,7 +158,7 @@ function paths --description "Reveal the executable matches in shell paths or fi
# check
set -l built (type --type $input 12&>/dev/null)
if test -n "$built"
and test "$built" = builtin
and test "$built" = 'builtin'
set $foundStatus 0
if not set -q _flag_c
echo -e -n "builtin\n"

View File

@@ -1,11 +1,11 @@
function sponge_filter_failed \
--argument-names command exit_code previously_in_history
--argument-names command exit_code previously_in_history
if test $previously_in_history = true -a $sponge_allow_previously_successful = true
return 1
end
if test $previously_in_history = true -a $sponge_allow_previously_successful = true
return 1
end
if contains $exit_code $sponge_successful_exit_codes
return 1
end
if contains $exit_code $sponge_successful_exit_codes
return 1
end
end

View File

@@ -1,11 +1,11 @@
function sponge_filter_matched \
--argument-names command
--argument-names command
for pattern in $sponge_regex_patterns
if string match --regex --quiet $pattern -- $command
return
end
for pattern in $sponge_regex_patterns
if string match --regex --quiet $pattern -- $command
return
end
end
return 1
return 1
end

1
config/fzf/completion.bash Normal file → Executable file
View File

@@ -1,4 +1,3 @@
# shellcheck disable=all
# ____ ____
# / __/___ / __/
# / /_/_ / / /_

1
config/fzf/completion.zsh Normal file → Executable file
View File

@@ -1,4 +1,3 @@
# shellcheck disable=all
# ____ ____
# / __/___ / __/
# / /_/_ / / /_

View File

@@ -1,4 +1,3 @@
# shellcheck shell=bash
# Everforest theme for fzf
# Generated from template - do not edit manually

0
config/fzf/fzf.bash Normal file → Executable file
View File

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env zsh
# shellcheck disable=SC1071
# Setup fzf
# ---------

9
config/fzf/key-bindings.bash Normal file → Executable file
View File

@@ -20,8 +20,8 @@ __fzf_select__() {
-o -type d -print \
-o -type l -print 2> /dev/null | cut -b3-"}"
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-} -m"
# shellcheck disable=SC2091 # Intentionally execute output of __fzfcmd
eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
eval "$cmd" |
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
while read -r item; do
printf '%q ' "$item" # escape special chars
done
@@ -35,8 +35,7 @@ if [[ $- =~ i ]]; then
}
fzf-file-widget() {
local selected
selected="$(__fzf_select__ "$@")"
local selected="$(__fzf_select__ "$@")"
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$((READLINE_POINT + ${#selected}))
}
@@ -46,7 +45,6 @@ if [[ $- =~ i ]]; then
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
-o -type d -print 2> /dev/null | cut -b3-"}"
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-} +m"
# shellcheck disable=SC2091 # Intentionally execute output of __fzfcmd
dir=$(
set +o pipefail
eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)
@@ -57,7 +55,6 @@ if [[ $- =~ i ]]; then
local output opts script
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort ${FZF_CTRL_R_OPTS-} +m --read0"
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
# shellcheck disable=SC2091 # Intentionally execute output of __fzfcmd
output=$(
set +o pipefail
builtin fc -lnr -2147483648 |

263
config/fzf/key-bindings.fish Normal file → Executable file
View File

@@ -15,161 +15,158 @@
# ------------
function fzf_key_bindings
# Store current token in $dir as root for the 'find' command
function fzf-file-widget -d "List files and folders"
set -l commandline (__fzf_parse_commandline)
set -l dir $commandline[1]
set -l fzf_query $commandline[2]
set -l prefix $commandline[3]
# Store current token in $dir as root for the 'find' command
function fzf-file-widget -d "List files and folders"
set -l commandline (__fzf_parse_commandline)
set -l dir $commandline[1]
set -l fzf_query $commandline[2]
set -l prefix $commandline[3]
# "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not
# $dir itself, even if hidden.
test -n "$FZF_CTRL_T_COMMAND"; or set -l FZF_CTRL_T_COMMAND "
# "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not
# $dir itself, even if hidden.
test -n "$FZF_CTRL_T_COMMAND"; or set -l FZF_CTRL_T_COMMAND "
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
-o -type f -print \
-o -type d -print \
-o -type l -print 2> /dev/null | sed 's@^\./@@'"
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS"
eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)' -m --query "'$fzf_query'"' | while read -l r
set result $result $r
end
end
if [ -z "$result" ]
commandline -f repaint
return
else
# Remove last token from commandline.
commandline -t ""
end
for i in $result
commandline -it -- $prefix
commandline -it -- (string escape $i)
commandline -it -- ' '
end
commandline -f repaint
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS"
eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)' -m --query "'$fzf_query'"' | while read -l r; set result $result $r; end
end
function fzf-history-widget -d "Show command history"
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m"
set -l FISH_MAJOR (echo $version | cut -f1 -d.)
set -l FISH_MINOR (echo $version | cut -f2 -d.)
# history's -z flag is needed for multi-line support.
# history's -z flag was added in fish 2.4.0, so don't use it for versions
# before 2.4.0.
if [ "$FISH_MAJOR" -gt 2 -o \( "$FISH_MAJOR" -eq 2 -a "$FISH_MINOR" -ge 4 \) ]
history -z | eval (__fzfcmd) --read0 --print0 -q '(commandline)' | read -lz result
and commandline -- $result
else
history | eval (__fzfcmd) -q '(commandline)' | read -l result
and commandline -- $result
end
end
commandline -f repaint
if [ -z "$result" ]
commandline -f repaint
return
else
# Remove last token from commandline.
commandline -t ""
end
for i in $result
commandline -it -- $prefix
commandline -it -- (string escape $i)
commandline -it -- ' '
end
commandline -f repaint
end
function fzf-cd-widget -d "Change directory"
set -l commandline (__fzf_parse_commandline)
set -l dir $commandline[1]
set -l fzf_query $commandline[2]
set -l prefix $commandline[3]
function fzf-history-widget -d "Show command history"
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m"
test -n "$FZF_ALT_C_COMMAND"; or set -l FZF_ALT_C_COMMAND "
set -l FISH_MAJOR (echo $version | cut -f1 -d.)
set -l FISH_MINOR (echo $version | cut -f2 -d.)
# history's -z flag is needed for multi-line support.
# history's -z flag was added in fish 2.4.0, so don't use it for versions
# before 2.4.0.
if [ "$FISH_MAJOR" -gt 2 -o \( "$FISH_MAJOR" -eq 2 -a "$FISH_MINOR" -ge 4 \) ];
history -z | eval (__fzfcmd) --read0 --print0 -q '(commandline)' | read -lz result
and commandline -- $result
else
history | eval (__fzfcmd) -q '(commandline)' | read -l result
and commandline -- $result
end
end
commandline -f repaint
end
function fzf-cd-widget -d "Change directory"
set -l commandline (__fzf_parse_commandline)
set -l dir $commandline[1]
set -l fzf_query $commandline[2]
set -l prefix $commandline[3]
test -n "$FZF_ALT_C_COMMAND"; or set -l FZF_ALT_C_COMMAND "
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
-o -type d -print 2> /dev/null | sed 's@^\./@@'"
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS"
eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS"
eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result
if [ -n "$result" ]
cd -- $result
if [ -n "$result" ]
cd -- $result
# Remove last token from commandline.
commandline -t ""
commandline -it -- $prefix
end
end
commandline -f repaint
# Remove last token from commandline.
commandline -t ""
commandline -it -- $prefix
end
end
function __fzfcmd
test -n "$FZF_TMUX"; or set FZF_TMUX 0
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
if [ -n "$FZF_TMUX_OPTS" ]
echo "fzf-tmux $FZF_TMUX_OPTS -- "
else if [ $FZF_TMUX -eq 1 ]
echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- "
else
echo fzf
end
commandline -f repaint
end
function __fzfcmd
test -n "$FZF_TMUX"; or set FZF_TMUX 0
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
if [ -n "$FZF_TMUX_OPTS" ]
echo "fzf-tmux $FZF_TMUX_OPTS -- "
else if [ $FZF_TMUX -eq 1 ]
echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- "
else
echo "fzf"
end
end
bind \ct fzf-file-widget
bind \cr fzf-history-widget
bind \ec fzf-cd-widget
if bind -M insert > /dev/null 2>&1
bind -M insert \ct fzf-file-widget
bind -M insert \cr fzf-history-widget
bind -M insert \ec fzf-cd-widget
end
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
set -l commandline (commandline -t)
# strip -option= from token if present
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
set commandline (string replace -- "$prefix" '' $commandline)
# eval is used to do shell expansion on paths
eval set commandline $commandline
if [ -z $commandline ]
# Default to current directory with no --query
set dir '.'
set fzf_query ''
else
set dir (__fzf_get_dir $commandline)
if [ "$dir" = "." -a (string sub -l 1 -- $commandline) != '.' ]
# if $dir is "." but commandline is not a relative path, this means no file path found
set fzf_query $commandline
else
# Also remove trailing slash after dir, to "split" input properly
set fzf_query (string replace -r "^$dir/?" -- '' "$commandline")
end
end
bind \ct fzf-file-widget
bind \cr fzf-history-widget
bind \ec fzf-cd-widget
echo $dir
echo $fzf_query
echo $prefix
end
if bind -M insert >/dev/null 2>&1
bind -M insert \ct fzf-file-widget
bind -M insert \cr fzf-history-widget
bind -M insert \ec fzf-cd-widget
function __fzf_get_dir -d 'Find the longest existing filepath from input string'
set dir $argv
# Strip all trailing slashes. Ignore if $dir is root dir (/)
if [ (string length -- $dir) -gt 1 ]
set dir (string replace -r '/*$' -- '' $dir)
end
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
set -l commandline (commandline -t)
# strip -option= from token if present
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
set commandline (string replace -- "$prefix" '' $commandline)
# eval is used to do shell expansion on paths
eval set commandline $commandline
if [ -z $commandline ]
# Default to current directory with no --query
set dir '.'
set fzf_query ''
else
set dir (__fzf_get_dir $commandline)
if [ "$dir" = "." -a (string sub -l 1 -- $commandline) != '.' ]
# if $dir is "." but commandline is not a relative path, this means no file path found
set fzf_query $commandline
else
# Also remove trailing slash after dir, to "split" input properly
set fzf_query (string replace -r "^$dir/?" -- '' "$commandline")
end
end
echo $dir
echo $fzf_query
echo $prefix
# Iteratively check if dir exists and strip tail end of path
while [ ! -d "$dir" ]
# If path is absolute, this can keep going until ends up at /
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
set dir (dirname -- "$dir")
end
function __fzf_get_dir -d 'Find the longest existing filepath from input string'
set dir $argv
# Strip all trailing slashes. Ignore if $dir is root dir (/)
if [ (string length -- $dir) -gt 1 ]
set dir (string replace -r '/*$' -- '' $dir)
end
# Iteratively check if dir exists and strip tail end of path
while [ ! -d "$dir" ]
# If path is absolute, this can keep going until ends up at /
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
set dir (dirname -- "$dir")
end
echo $dir
end
echo $dir
end
end

1
config/fzf/key-bindings.zsh Normal file → Executable file
View File

@@ -1,4 +1,3 @@
# shellcheck disable=all
# ____ ____
# / __/___ / __/
# / /_/_ / / /_

View File

@@ -1,68 +1,68 @@
{
"profiles": [
{
"complex_modifications": {
"rules": [
{
"description": "Change right_command+hjkl to arrow keys",
"manipulators": [
{
"from": {
"key_code": "h",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "left_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "j",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "down_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "k",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "up_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "l",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "right_arrow" }],
"type": "basic"
}
]
}
]
},
"name": "Default profile",
"selected": true,
"simple_modifications": [
"profiles": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "f18" }]
"complex_modifications": {
"rules": [
{
"description": "Change right_command+hjkl to arrow keys",
"manipulators": [
{
"from": {
"key_code": "h",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "left_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "j",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "down_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "k",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "up_arrow" }],
"type": "basic"
},
{
"from": {
"key_code": "l",
"modifiers": {
"mandatory": ["right_command"],
"optional": ["any"]
}
},
"to": [{ "key_code": "right_arrow" }],
"type": "basic"
}
]
}
]
},
"name": "Default profile",
"selected": true,
"simple_modifications": [
{
"from": { "key_code": "caps_lock" },
"to": [{ "key_code": "f18" }]
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "iso" }
}
],
"virtual_hid_keyboard": { "keyboard_type_v2": "iso" }
}
]
}
]
}

View File

@@ -0,0 +1,114 @@
-- Everforest theme for Neovim
-- Generated from template - do not edit manually
local M = {}
M.colors = {
bg = '#2f383e',
bg1 = '#374247',
bg2 = '#404c51',
fg = '#d3c6aa',
red = '#e67e80',
orange = '#e69875',
yellow = '#dbbc7f',
green = '#a7c080',
aqua = '#83c092',
blue = '#7fbbb3',
purple = '#d699b6',
gray1 = '#7a8478',
gray2 = '#859289',
gray3 = '#9da9a0',
}
M.highlights = {
-- Editor highlights
Normal = { fg = M.colors.fg, bg = M.colors.bg },
NormalFloat = { fg = M.colors.fg, bg = M.colors.bg1 },
ColorColumn = { bg = M.colors.bg1 },
Conceal = { fg = M.colors.gray2 },
Cursor = { fg = M.colors.bg, bg = M.colors.fg },
lCursor = { fg = M.colors.bg, bg = M.colors.fg },
CursorIM = { fg = M.colors.bg, bg = M.colors.fg },
CursorColumn = { bg = M.colors.bg1 },
CursorLine = { bg = M.colors.bg1 },
Directory = { fg = M.colors.blue, bold = true },
DiffAdd = { fg = M.colors.green, bg = M.colors.bg },
DiffChange = { fg = M.colors.blue, bg = M.colors.bg },
DiffDelete = { fg = M.colors.red, bg = M.colors.bg },
DiffText = { fg = M.colors.yellow, bg = M.colors.bg },
EndOfBuffer = { fg = M.colors.gray2 },
ErrorMsg = { fg = M.colors.red, bold = true },
VertSplit = { fg = M.colors.gray2 },
Folded = { fg = M.colors.gray2, bg = M.colors.bg1 },
FoldColumn = { fg = M.colors.gray2, bg = M.colors.bg },
SignColumn = { fg = M.colors.fg, bg = M.colors.bg },
IncSearch = { fg = M.colors.bg, bg = M.colors.orange },
LineNr = { fg = M.colors.gray2 },
CursorLineNr = { fg = M.colors.yellow, bold = true },
MatchParen = { fg = M.colors.orange, bold = true },
ModeMsg = { fg = M.colors.fg, bold = true },
MoreMsg = { fg = M.colors.blue, bold = true },
NonText = { fg = M.colors.gray2 },
Pmenu = { fg = M.colors.fg, bg = M.colors.bg1 },
PmenuSel = { fg = M.colors.bg, bg = M.colors.blue },
PmenuSbar = { bg = M.colors.bg2 },
PmenuThumb = { bg = M.colors.gray2 },
Question = { fg = M.colors.yellow, bold = true },
QuickFixLine = { fg = M.colors.bg, bg = M.colors.yellow },
Search = { fg = M.colors.bg, bg = M.colors.yellow },
SpecialKey = { fg = M.colors.gray2 },
SpellBad = { fg = M.colors.red, undercurl = true },
SpellCap = { fg = M.colors.blue, undercurl = true },
SpellLocal = { fg = M.colors.aqua, undercurl = true },
SpellRare = { fg = M.colors.purple, undercurl = true },
StatusLine = { fg = M.colors.fg, bg = M.colors.bg1 },
StatusLineNC = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLine = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLineFill = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLineSel = { fg = M.colors.fg, bg = M.colors.bg },
Title = { fg = M.colors.orange, bold = true },
Visual = { bg = M.colors.bg2 },
VisualNOS = { fg = M.colors.gray2 },
WarningMsg = { fg = M.colors.yellow, bold = true },
Whitespace = { fg = M.colors.gray2 },
WildMenu = { fg = M.colors.bg, bg = M.colors.blue },
-- Syntax highlighting
Comment = { fg = M.colors.gray2 },
Constant = { fg = M.colors.purple },
String = { fg = M.colors.green },
Character = { fg = M.colors.green },
Number = { fg = M.colors.purple },
Boolean = { fg = M.colors.purple },
Float = { fg = M.colors.purple },
Identifier = { fg = M.colors.blue },
Function = { fg = M.colors.green },
Statement = { fg = M.colors.red },
Conditional = { fg = M.colors.red },
Repeat = { fg = M.colors.red },
Label = { fg = M.colors.orange },
Operator = { fg = M.colors.orange },
Keyword = { fg = M.colors.red },
Exception = { fg = M.colors.red },
PreProc = { fg = M.colors.aqua },
Include = { fg = M.colors.blue },
Define = { fg = M.colors.purple },
Macro = { fg = M.colors.purple },
PreCondit = { fg = M.colors.aqua },
Type = { fg = M.colors.yellow },
StorageClass = { fg = M.colors.orange },
Structure = { fg = M.colors.aqua },
Typedef = { fg = M.colors.yellow },
Special = { fg = M.colors.orange },
SpecialChar = { fg = M.colors.red },
Tag = { fg = M.colors.orange },
Delimiter = { fg = M.colors.gray2 },
SpecialComment = { fg = M.colors.aqua },
Debug = { fg = M.colors.red },
Underlined = { fg = M.colors.blue, underline = true },
Ignore = { fg = M.colors.gray2 },
Error = { fg = M.colors.red, bold = true },
Todo = { fg = M.colors.yellow, bold = true },
}
return M

View File

@@ -0,0 +1,114 @@
-- Everforest theme for Neovim
-- Generated from template - do not edit manually
local M = {}
M.colors = {
bg = '#f3ead3',
bg1 = '#ede6cf',
bg2 = '#e8e3cc',
fg = '#5c6a72',
red = '#e67e80',
orange = '#e69875',
yellow = '#dbbc7f',
green = '#a7c080',
aqua = '#83c092',
blue = '#7fbbb3',
purple = '#d699b6',
gray1 = '#a6b0a0',
gray2 = '#b3c0b0',
gray3 = '#c0cdb8',
}
M.highlights = {
-- Editor highlights
Normal = { fg = M.colors.fg, bg = M.colors.bg },
NormalFloat = { fg = M.colors.fg, bg = M.colors.bg1 },
ColorColumn = { bg = M.colors.bg1 },
Conceal = { fg = M.colors.gray2 },
Cursor = { fg = M.colors.bg, bg = M.colors.fg },
lCursor = { fg = M.colors.bg, bg = M.colors.fg },
CursorIM = { fg = M.colors.bg, bg = M.colors.fg },
CursorColumn = { bg = M.colors.bg1 },
CursorLine = { bg = M.colors.bg1 },
Directory = { fg = M.colors.blue, bold = true },
DiffAdd = { fg = M.colors.green, bg = M.colors.bg },
DiffChange = { fg = M.colors.blue, bg = M.colors.bg },
DiffDelete = { fg = M.colors.red, bg = M.colors.bg },
DiffText = { fg = M.colors.yellow, bg = M.colors.bg },
EndOfBuffer = { fg = M.colors.gray2 },
ErrorMsg = { fg = M.colors.red, bold = true },
VertSplit = { fg = M.colors.gray2 },
Folded = { fg = M.colors.gray2, bg = M.colors.bg1 },
FoldColumn = { fg = M.colors.gray2, bg = M.colors.bg },
SignColumn = { fg = M.colors.fg, bg = M.colors.bg },
IncSearch = { fg = M.colors.bg, bg = M.colors.orange },
LineNr = { fg = M.colors.gray2 },
CursorLineNr = { fg = M.colors.yellow, bold = true },
MatchParen = { fg = M.colors.orange, bold = true },
ModeMsg = { fg = M.colors.fg, bold = true },
MoreMsg = { fg = M.colors.blue, bold = true },
NonText = { fg = M.colors.gray2 },
Pmenu = { fg = M.colors.fg, bg = M.colors.bg1 },
PmenuSel = { fg = M.colors.bg, bg = M.colors.blue },
PmenuSbar = { bg = M.colors.bg2 },
PmenuThumb = { bg = M.colors.gray2 },
Question = { fg = M.colors.yellow, bold = true },
QuickFixLine = { fg = M.colors.bg, bg = M.colors.yellow },
Search = { fg = M.colors.bg, bg = M.colors.yellow },
SpecialKey = { fg = M.colors.gray2 },
SpellBad = { fg = M.colors.red, undercurl = true },
SpellCap = { fg = M.colors.blue, undercurl = true },
SpellLocal = { fg = M.colors.aqua, undercurl = true },
SpellRare = { fg = M.colors.purple, undercurl = true },
StatusLine = { fg = M.colors.fg, bg = M.colors.bg1 },
StatusLineNC = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLine = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLineFill = { fg = M.colors.gray2, bg = M.colors.bg1 },
TabLineSel = { fg = M.colors.fg, bg = M.colors.bg },
Title = { fg = M.colors.orange, bold = true },
Visual = { bg = M.colors.bg2 },
VisualNOS = { fg = M.colors.gray2 },
WarningMsg = { fg = M.colors.yellow, bold = true },
Whitespace = { fg = M.colors.gray2 },
WildMenu = { fg = M.colors.bg, bg = M.colors.blue },
-- Syntax highlighting
Comment = { fg = M.colors.gray2 },
Constant = { fg = M.colors.purple },
String = { fg = M.colors.green },
Character = { fg = M.colors.green },
Number = { fg = M.colors.purple },
Boolean = { fg = M.colors.purple },
Float = { fg = M.colors.purple },
Identifier = { fg = M.colors.blue },
Function = { fg = M.colors.green },
Statement = { fg = M.colors.red },
Conditional = { fg = M.colors.red },
Repeat = { fg = M.colors.red },
Label = { fg = M.colors.orange },
Operator = { fg = M.colors.orange },
Keyword = { fg = M.colors.red },
Exception = { fg = M.colors.red },
PreProc = { fg = M.colors.aqua },
Include = { fg = M.colors.blue },
Define = { fg = M.colors.purple },
Macro = { fg = M.colors.purple },
PreCondit = { fg = M.colors.aqua },
Type = { fg = M.colors.yellow },
StorageClass = { fg = M.colors.orange },
Structure = { fg = M.colors.aqua },
Typedef = { fg = M.colors.yellow },
Special = { fg = M.colors.orange },
SpecialChar = { fg = M.colors.red },
Tag = { fg = M.colors.orange },
Delimiter = { fg = M.colors.gray2 },
SpecialComment = { fg = M.colors.aqua },
Debug = { fg = M.colors.red },
Underlined = { fg = M.colors.blue, underline = true },
Ignore = { fg = M.colors.gray2 },
Error = { fg = M.colors.red, bold = true },
Todo = { fg = M.colors.yellow, bold = true },
}
return M

View File

@@ -32,6 +32,24 @@ K.nl('o', function() require('snacks').gitbrowse() end, 'Open repo in browser')
K.n('<C-s>', ':w!<cr>', { desc = 'Save', noremap = true })
K.n('<esc><esc>', ':nohlsearch<cr>', { desc = 'Clear Search Highlighting' })
-- ── ToggleTerm ──────────────────────────────────────────────────────
K.d('<F1>', 'n', ':FloatermToggle<CR>', 'Toggle Floaterm')
K.d('<F1>', 'i', '<Esc>:FloatermToggle<CR>', 'Toggle Floaterm')
K.d('<F1>', 't', '<C-\\><C-n>:FloatermToggle<CR>', 'Toggle Floaterm')
-- ── Test operations ─────────────────────────────────────────────────
K.nl('an', ':silent TestNearest<CR>', 'Test Nearest')
K.nl('af', ':silent TestFile<CR>', 'Test File')
K.nl('as', ':silent TestSuite<CR>', 'Test Suite')
K.nl('al', ':silent TestLast<CR>', 'Test Last')
K.nl('av', ':silent TestVisit<CR>', 'Test Visit')
-- ── PHPActor Operations ─────────────────────────────────────────────
K.nl('apm', ':PhpactorContextMenu<cr>', 'PHPactor: Context Menu')
K.nl('apn', ':PhpactorClassNew<cr>', 'PHPactor: Class New')
K.nl('aps', ':PhpactorClassSearch<cr>', 'PHPactor: Class Search')
K.nl('apt', ':PhpactorTransform<cr>', 'PHPactor: Transform')
-- ── Buffer operations ───────────────────────────────────────────────
-- Mappings for buffer management operations like switching, deleting, etc.
-- Convention: All mappings start with 'b' followed by the operation
@@ -82,21 +100,32 @@ K.nl('cbt', '<Cmd>CBllline<CR>', 'CB: Titled Line')
-- Convention: All mappings start with 's' followed by the operation
-- unless it's a generic operation like searching or finding buffers
local fuzzy_search = function()
require('telescope.builtin').find_files(require('telescope.themes').get_dropdown {
winblend = 20,
previewer = true,
})
end
local lazy_plugins = function()
return require('telescope').extensions.lazy_plugins.lazy_plugins()
end
K.nl('f', function() require('fff').find_files() end, 'Find Files')
K.nl('f', ':Telescope find_files<cr>', 'Find Files')
K.nl(',', ':Telescope buffers<cr>', 'Find existing buffers')
K.nl('/', function() fuzzy_search() end, 'Fuzzily search in current buffer')
K.nl('sc', ':Telescope commands<cr>', 'Commands')
K.nl('sd', ':Telescope diagnostics<cr>', 'Search Diagnostics')
K.nl('sf', ':Telescope grep_string<cr>', 'Grep String')
K.nl('sg', ':Telescope live_grep<cr>', 'Search by Grep')
K.nl('sh', ':Telescope help_tags<cr>', 'Help tags')
K.nl('sk', ':Telescope keymaps<cr>', 'Search Keymaps')
K.nl('sl', ':Telescope luasnip<CR>', 'Search LuaSnip')
K.nl('so', ':Telescope oldfiles<CR>', 'Old Files')
K.nl('sp', function() lazy_plugins() end, 'Lazy Plugins')
K.nl('sq', ':Telescope quickfix<cr>', 'Quickfix')
K.nl('ss', ':Telescope treesitter<cr>', 'Treesitter')
K.nl('sw', ':Telescope grep_string<cr>', 'Grep String')
K.nl('sx', ':Telescope import<cr>', 'Telescope: Import')
-- ── Trouble operations ──────────────────────────────────────────────
@@ -127,4 +156,13 @@ K.nl('qQ', function()
end
end, 'Force quit without saving')
-- ── Flash.nvim keymaps ──────────────────────────────────────────────
local nxo = { 'n', 'x', 'o' }
local fj = function() return require('flash').jump() end
local ft = function() return require('flash').treesitter() end
local fx = function() return require('flash').toggle() end
K.d('zk', nxo, fj, { desc = 'Flash' })
K.d('Zk', nxo, ft, { desc = 'Flash Treesitter' })
K.d('<m-s>', 'c', fx, { desc = 'Toggle Flash Search' })
-- That concludes the keymaps section of the config.

View File

@@ -3,7 +3,7 @@ return {
-- https:/github.com/saghen/blink.cmp
{
'saghen/blink.cmp',
version = '*',
version = '1.*',
lazy = false, -- lazy loading handled internally
dependencies = {
-- Compatibility layer for using nvim-cmp sources on blink.cmp
@@ -18,6 +18,15 @@ return {
},
},
{ 'L3MON4D3/LuaSnip', version = 'v2.*', build = 'make install_jsregexp' },
-- Set of preconfigured snippets for different languages.
-- https://github.com/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
-- https://github.com/giuxtaposition/blink-cmp-copilot
{
@@ -45,6 +54,7 @@ return {
},
---@module 'blink.cmp'
opts = {
snippets = { preset = 'luasnip' },
-- 'default' for mappings similar to built-in completion
-- 'super-tab' for mappings similar to vscode (tab to accept,
-- arrow keys to navigate)

View File

@@ -1,4 +1,16 @@
return {
-- Terminal manager for (neo)vim
-- https://github.com/voldikss/vim-floaterm
{
'voldikss/vim-floaterm',
lazy = true,
cmd = { 'FloatermToggle' },
init = function()
vim.g.floaterm_width = 0.8
vim.g.floaterm_height = 0.8
end,
},
{
'ivuorinen/nvim-shellspec',
ft = 'shellspec',
@@ -27,6 +39,112 @@ return {
config = function() end,
},
-- Run your tests at the speed of thought
-- https://github.com/vim-test/vim-test
{
'vim-test/vim-test',
dependencies = { 'voldikss/vim-floaterm' },
config = function()
vim.cmd [[
function! PhpUnitTransform(cmd) abort
return join(map(split(a:cmd), 'v:val == "--colors" ? "--colors=always" : v:val'))
endfunction
let g:test#custom_transformations = {'phpunit': function('PhpUnitTransform')}
let g:test#transformation = 'phpunit'
" let test#php#phpunit#options = '--colors=always'
let test#php#pest#options = '-v'
let test#javascript#jest#options = '--color'
function! FloatermStrategy(cmd)
execute 'silent FloatermSend q'
execute 'silent FloatermKill'
execute 'FloatermNew! '.a:cmd.' | less -X'
endfunction
let g:test#custom_strategies = {'floaterm': function('FloatermStrategy')}
let g:test#strategy = 'floaterm'
]]
end,
},
-- projectionist.vim: Granular project configuration
-- https://github.com/tpope/vim-projectionist
{
'tpope/vim-projectionist',
dependencies = 'tpope/vim-dispatch',
config = function()
vim.g.projectionist_heuristics = {
artisan = {
['*'] = {
start = 'php artisan serve',
console = 'php artisan tinker',
},
['app/*.php'] = {
type = 'source',
alternate = {
'tests/Unit/{}Test.php',
'tests/Feature/{}Test.php',
},
},
['tests/Feature/*Test.php'] = {
type = 'test',
alternate = 'app/{}.php',
},
['tests/Unit/*Test.php'] = {
type = 'test',
alternate = 'app/{}.php',
},
['app/Models/*.php'] = {
type = 'model',
},
['app/Http/Controllers/*.php'] = {
type = 'controller',
},
['routes/*.php'] = {
type = 'route',
},
['database/migrations/*.php'] = {
type = 'migration',
},
},
['src/&composer.json'] = {
['src/*.php'] = {
type = 'source',
alternate = {
'tests/{}Test.php',
},
},
['tests/*Test.php'] = {
type = 'test',
alternate = 'src/{}.php',
},
},
['app/&composer.json'] = {
['app/*.php'] = {
type = 'source',
alternate = {
'tests/{}Test.php',
},
},
['tests/*Test.php'] = {
type = 'test',
alternate = 'app/{}.php',
},
},
}
end,
},
-- A vim text object for XML/HTML attributes.
-- https://github.com/whatyouhide/vim-textobj-xmlattr
{
'whatyouhide/vim-textobj-xmlattr',
dependencies = { 'kana/vim-textobj-user' },
ft = { 'html', 'xml', 'javascriptreact', 'typescriptreact', 'vue' },
},
-- Clarify and beautify your comments using boxes and lines.
-- https://github.com/LudoPinelli/comment-box.nvim
{

View File

@@ -55,8 +55,7 @@ return {
{
event = 'file_opened',
handler = function(_)
local c = require 'neo-tree.command'
c.execute { action = 'close' }
require('neo-tree.command').execute { action = 'close' }
end,
},
},

View File

@@ -7,19 +7,41 @@ return {
cmd = 'Telescope',
dependencies = {
{ 'nvim-lua/plenary.nvim' },
{ 'nvim-telescope/telescope-symbols.nvim' },
-- Telescope plugin for file browsing
{ 'nvim-telescope/telescope-file-browser.nvim' },
-- A Telescope picker to quickly access configurations
-- of plugins managed by lazy.nvim.
-- https://github.com/polirritmico/telescope-lazy-plugins.nvim
{ 'polirritmico/telescope-lazy-plugins.nvim' },
-- Fuzzy Finder Algorithm which requires local dependencies to be built.
-- Only load if `make` is available
{
'nvim-telescope/telescope-fzf-native.nvim',
build = 'make',
cond = vim.fn.executable 'make' == 1,
},
},
config = function()
local t = require 'telescope'
local a = require 'telescope.actions'
local c = require 'telescope.config'
local open_with_trouble = require('trouble.sources.telescope').open
local add_to_trouble = require('trouble.sources.telescope').add
-- Clone the default Telescope configuration
local vimgrep_arguments = { unpack(c.values.vimgrep_arguments) }
-- I want to search in hidden/dot files.
table.insert(vimgrep_arguments, '--hidden=true')
table.insert(vimgrep_arguments, '--glob')
-- I don't want to search in the `.git` directory.
table.insert(vimgrep_arguments, '!**/.git/*')
-- [[ Configure Telescope ]]
-- See `:help telescope` and `:help telescope.setup()`
t.setup {
@@ -27,8 +49,17 @@ return {
preview = {
filesize_limit = 0.1, -- MB
},
-- `hidden = true` is not supported in text grep commands.
vimgrep_arguments = vimgrep_arguments,
layout_strategy = 'horizontal',
pickers = {
find_files = {
-- `hidden = true` will still show the inside of `.git/` as
-- it's not `.gitignore`d.
find_command = { 'rg', '--files', '--hidden', '--glob', '!**/.git/*' },
theme = 'dropdown',
},
mappings = {
i = {
['<C-s>'] = a.cycle_previewers_next,
@@ -55,6 +86,19 @@ return {
enable = true,
additional_vim_regex_highlighting = false,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<CR>',
node_incremental = '<CR>',
scope_incremental = '<TAB>',
node_decremental = '<S-TAB>',
},
},
context_commentstring = {
enable = true,
enable_autocmd = false,
},
extensions = {
lazy_plugins = {
-- Must be a valid path to the file containing the lazy spec and setup() call.
@@ -64,7 +108,16 @@ return {
}
-- Load extensions
pcall(t.load_extension, 'git_worktree')
pcall(t.load_extension, 'lazy_plugins')
pcall(t.load_extension, 'luasnip')
pcall(t.load_extension, 'import')
-- Enable telescope fzf native, if installed
pcall(t.load_extension, 'fzf')
-- [[ Telescope Keymaps ]]
-- See `:help telescope.builtin`
-- See `:help telescope.keymap`
end,
}

View File

@@ -18,11 +18,17 @@ return {
-- Add languages to be installed here that you want installed for treesitter
ensure_installed = {
'bash',
'json',
'jsonc',
'lua',
'luadoc',
'markdown',
'markdown_inline',
'query',
'regex',
'vim',
'vimdoc',
'yaml',
},
@@ -48,6 +54,9 @@ return {
if require('nvim-treesitter.parsers').has_parser() then
vim.opt.foldmethod = 'expr'
vim.opt.foldexpr = 'nvim_treesitter#foldexpr()'
else
-- Otherwise, set foldmethod to syntax
vim.opt.foldmethod = 'syntax'
end
vim.opt.foldlevel = 9 -- Open all folds by default

View File

@@ -80,6 +80,33 @@ return {
vim.cmd.colorscheme 'catppuccin'
end,
},
-- {
-- 'neanias/everforest-nvim',
-- version = false,
-- lazy = false,
-- priority = 1000, -- make sure to load this before all the other start plugins
-- config = function()
-- require('everforest').setup {
-- background = 'medium', -- hard, medium, soft
-- transparent_background_level = 2, -- 0, 1, 2
-- sign_column_background = 'grey', -- none, grey
-- disable_italic_comments = false,
-- diagnostic_virtual_text = 'coloured', -- coloured, gray, underline, none
-- diagnostic_line_highlight = true,
-- diagnostic_line_highlight_background = 'dimmed', -- dimmed, normal
-- diagnostic_text_highlight = true,
-- ui_contrast = 'low', -- high, low
-- italics = true,
-- spell_foreground = true,
-- show_eob = true,
-- colours_override = function() end,
-- float_style = 'dim',
-- on_highlights = function(_, _) end,
-- dim_inactive_windows = true,
-- inlay_hints_background = 'dimmed',
-- }
-- end,
-- },
-- Automatic dark mode
-- https://github.com/f-person/auto-dark-mode.nvim
@@ -112,32 +139,39 @@ return {
},
},
{
'dmtrKovalenko/fff.nvim',
build = function()
-- this will download prebuild binary or try to use existing rustup toolchain to build from source
-- (if you are using lazy you can use gb for rebuilding a plugin if needed)
require('fff.download').download_or_build_binary()
end,
-- if you are using nixos
-- build = "nix run .#release",
opts = { -- (optional)
debug = {
enabled = true, -- we expect your collaboration at least during the beta
show_scores = true, -- to help us optimize the scoring system, feel free to share your scores!
},
},
-- No need to lazy-load with lazy.nvim.
-- This plugin initializes itself lazily.
lazy = false,
keys = {
{
'ff', -- try it if you didn't it is a banger keybinding for a picker
function() require('fff').find_files() end,
desc = 'FFFind files',
},
},
},
-- Remove all background colors to make nvim transparent
-- https://github.com/xiyaowong/nvim-transparent
-- {
-- 'xiyaowong/nvim-transparent',
-- lazy = false,
-- enabled = true,
-- config = function()
-- local t = require 'transparent'
-- t.setup {
-- extra_groups = {
-- 'NormalNC',
-- 'NormalFloat',
-- 'EndOfBuffer',
-- 'FloatTitle',
-- 'FloatBorder',
-- 'NotifyDEBUGBorder',
-- 'NotifyERRORBorder',
-- 'NotifyINFOBorder',
-- 'NotifyINFOBorder73',
-- 'NotifyINFOBorder75',
-- 'NotifyINFOBorder101',
-- 'NotifyTRACEBorder',
-- 'NotifyWARNBorder',
-- 'NotifyBackground',
-- 'TelescopeBorder',
-- 'TelescopePromptBorder',
-- 'TelescopeResultsBorder',
-- 'TelescopePreviewBorder',
-- },
-- }
-- t.clear_prefix 'NeoTree'
-- end,
-- },
-- Display a character as the colorcolumn
-- https://github.com/lukas-reineke/virt-column.nvim

View File

@@ -0,0 +1,462 @@
{
"While ..": {
"body": [
"while (${1:condition}) {",
"\t$0",
"}"
],
"prefix": "while .."
},
"argv (node)": {
"body": "const argv = process.argv.slice(2);",
"description": "Arguments from the command line. [0] is the node executable path, [1] the path of the file being executed, making [2] the first positional argument.",
"prefix": "argv (node)"
},
"cast (JSDoc)": {
"body": "/** @type {${1:string}} */ (${2:bracketedVar})",
"prefix": "cast (JSDoc)"
},
"class (JSDoc) + typedef (JSDoc)": {
"body": [
"/** @typedef {Object} ${1:name}",
" * @property {${2:string}} ${3:prop1}",
" */"
],
"description": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#typedef-callback-and-param",
"prefix": [
"class (JSDoc)",
"typedef (JSDoc)"
]
},
"do .. while ..": {
"body": [
"do {",
"\t$0",
"} while (${1:condition});"
],
"prefix": [
"do .. while",
"repeat until"
]
},
"ec (export const)": {
"body": "export const ${1:CONSTANT}",
"prefix": "ec (export const)"
},
"ef (export function)": {
"body": [
"export function ${1:name}($2) {",
"\t$0",
"}"
],
"prefix": "ef (export function)"
},
"filter ( => )": {
"body": "filter(${1:item} => ${1:item}$0)",
"prefix": "filter ( => )"
},
"for (i++)": {
"body": [
"for (let i = 0; i < ${1:array}.length; i++) {",
"\tconst ${2:element} = ${1:array}[i];",
"\t$0",
"}"
],
"prefix": "for (i++)"
},
"for (i--)": {
"body": [
"for (let i = ${1:array}.length - 1; i >= 0; i--) {",
"\tconst ${2:element} = ${1:array}[i];",
"\t$0",
"}"
],
"prefix": "for (i--)"
},
"for (key, value)": {
"body": [
"for (const [key, value] of Object.entries(${1:dict})) {",
"\t$0",
"}"
],
"prefix": "for (key, value)"
},
"for .. in (key)": {
"body": [
"for (const ${1:key} in ${2:object}) {",
"\t$0",
"}"
],
"prefix": "for .. in (key)"
},
"for .. of (array)": {
"body": [
"for (const ${1:iterator} of ${2:array}) {",
"\t$0",
"}"
],
"prefix": "for .. of (array)"
},
"forEach": {
"body": [
"forEach(${1:item} => {",
"\t$0",
"});"
],
"prefix": "forEach =>"
},
"function_trad": {
"body": [
"function ${1:name}() {",
"\t$0",
"}"
],
"prefix": "function"
},
"if ..": {
"body": [
"if (${1:condition}) {",
"\t$0",
"}"
],
"prefix": "if"
},
"if .. else": {
"body": [
"if (${1:condition}) {",
"\t$0",
"} else {",
"\t",
"}"
],
"prefix": "if .. else"
},
"ignore (biome formatter)": {
"body": "// biome-ignore format: ${1:explanation}",
"description": "Ignores the next block of code.",
"prefix": "ignore (biome formatter)"
},
"ignore file (TypeScript) + nocheck (TypeScript)": {
"body": "// @ts-nocheck",
"prefix": [
"ignore file (TypeScript)",
"nocheck (TypeScript)"
]
},
"map ( () => {} )": {
"body": [
"map(${1:item} => {",
"\t$0",
"\treturn;",
"})"
],
"prefix": "map ( () => {} )"
},
"map ( => )": {
"body": "map(${1:item} => ${1:item}$0)",
"prefix": "map ( => )"
},
"reduce()": {
"body": [
".reduce((acc, ${1:item}) => {",
"\t$0",
"\treturn acc;",
"}, ${2:initialValue})"
],
"prefix": "reduce()"
},
"relative date": {
"body": [
"/**",
" * @param {string} absoluteDate string to be converted to a date",
" * @return {string} relative date",
" */",
"function relativeDate(absoluteDate) {",
"\tconst deltaSecs = (+new Date() - +new Date(absoluteDate)) / 1000;",
"\t/** @type {\"year\"|\"month\"|\"week\"|\"day\"|\"hour\"|\"minute\"|\"second\"} */",
"\tlet unit;",
"\tlet delta;",
"\tif (deltaSecs < 60) {",
"\t\tunit = \"second\";",
"\t\tdelta = deltaSecs;",
"\t} else if (deltaSecs < 60 * 60) {",
"\t\tunit = \"minute\";",
"\t\tdelta = Math.ceil(deltaSecs / 60);",
"\t} else if (deltaSecs < 60 * 60 * 24) {",
"\t\tunit = \"hour\";",
"\t\tdelta = Math.ceil(deltaSecs / 60 / 60);",
"\t} else if (deltaSecs < 60 * 60 * 24 * 7) {",
"\t\tunit = \"day\";",
"\t\tdelta = Math.ceil(deltaSecs / 60 / 60 / 24);",
"\t} else if (deltaSecs < 60 * 60 * 24 * 7 * 4) {",
"\t\tunit = \"week\";",
"\t\tdelta = Math.ceil(deltaSecs / 60 / 60 / 24 / 7);",
"\t} else if (deltaSecs < 60 * 60 * 24 * 7 * 4 * 12) {",
"\t\tunit = \"month\";",
"\t\tdelta = Math.ceil(deltaSecs / 60 / 60 / 24 / 7 / 4);",
"\t} else {",
"\t\tunit = \"year\";",
"\t\tdelta = Math.ceil(deltaSecs / 60 / 60 / 24 / 7 / 4 / 12);",
"\t}",
"\tconst formatter = new Intl.RelativeTimeFormat(\"en\", { style: \"long\", numeric: \"auto\" });",
"\treturn formatter.format(-delta, unit);",
"}"
],
"prefix": "relative date"
},
"replace": {
"body": "replace(/${1:regexp}/, \"$2\")",
"prefix": "replace"
},
"sort ( () => {} )": {
"body": [
"sort((a, b) => {",
"\treturn ${1:b - a};",
"})"
],
"description": "Sort Array with basic a-b-comparator function",
"prefix": "sort ( () => {} )"
},
"split by \\n": {
"body": ".split(\"\\n\")",
"prefix": ".split by \\n"
},
"split by \\r": {
"body": ".split(\"\\r\")",
"description": "required for output from app.doShellScript()",
"prefix": ".split by \\r"
},
"switch .. case": {
"body": [
"switch (${1:key}) {",
"\tcase ${2:value}:",
"\t\t$0",
"\t\tbreak;",
"\tdefault:",
"}"
],
"prefix": "switch .. case"
},
"ternary": {
"body": "${1:condition} ? ${2:value1} : ${3:value2}",
"prefix": "ternary"
},
"thousand separator": {
"body": ".toLocaleString(\"de-DE\")",
"description": "insert thousand separator into a digit string",
"prefix": "thousand separator"
},
"timeout + delay": {
"body": [
"setTimeout(() => {",
"\t$0",
"}, ${1:timeoutMs});"
],
"prefix": [
"timeout",
"delay"
]
},
"today as ISO 8601 string": {
"body": "new Date().toISOString().slice(0, 10);",
"prefix": "ISO date"
},
"today's date": {
"body": "const today = new Date();",
"prefix": [
"today",
"date"
]
},
"tomorrow's date": {
"body": [
"const tomorrow = new Date();",
"tomorrow.setDate(tomorrow.getDate() + 1);"
],
"prefix": [
"tomorrow",
"date"
]
},
"try .. catch": {
"body": [
"try {",
"\t$0",
"} catch (_error) {",
"\t",
"}"
],
"description": "leading underscore so the variable is ignored by biome when not used.",
"prefix": "try .. catch"
},
"type (JSDoc)": {
"body": "/** @type {${1:string}} */",
"prefix": "type (JSDoc)"
},
"type: Record (JSDoc)": {
"body": "/** @type {Record<string, string>} */",
"prefix": "type: Record (JSDoc)"
},
"unique items": {
"body": "${1:arr} = [...new Set(${2:arr})];",
"prefix": "unique items"
},
"Class": {
"prefix": [
"clax"
],
"body": [
"export class $1 ${2:extends ${3:Parent} }{",
"\tconstructor(${4:props}) {",
"\t\tthis.$4 = $4;",
"\t}",
"",
"\t$0",
"}"
],
"description": "Class definition template."
},
"test": {
"prefix": [
"it"
],
"body": [
"it('${1:should ${2}}', async () => {",
"\t$0",
"});"
],
"description": "Test template"
},
"method": {
"prefix": [
"mtd"
],
"body": [
"${1:async ${2:method}}(${3:params}) {",
"\t$0",
"}"
],
"description": "method"
},
"function": {
"prefix": [
"fun"
],
"body": [
"${1:async }${2:(${3:params})} => {$0}"
],
"description": "function"
},
"const": {
"prefix": [
"const"
],
"body": [
"const $1 = $0;"
],
"description": "const"
},
"let": {
"prefix": [
"let"
],
"body": [
"let $1 = $0;"
],
"description": "let"
},
"Console log": {
"prefix": [
"cl"
],
"body": [
"console.log($0);"
],
"description": "Console log"
},
"Console debug": {
"prefix": [
"cd"
],
"body": [
"console.debug($0);"
],
"description": "Console debug"
},
"Console log all": {
"prefix": [
"clj"
],
"body": [
"console.log(JSON.stringify($0, null, 2));"
],
"description": "Console log whole object"
},
"Console debug all": {
"prefix": [
"cdj"
],
"body": [
"console.debug(JSON.stringify($0, null, 2));"
],
"description": "Console debug whole object"
},
"If": {
"prefix": [
"if"
],
"body": [
"if (${1:condition}) {",
"\t$0",
"}"
],
"description": "Console debug whole object"
},
"If-else": {
"prefix": [
"ifelse"
],
"body": [
"if (${1:condition}) {",
"\t$2",
"} else {",
"\t$0",
"}"
],
"description": "Console debug whole object"
},
"docblock": {
"prefix": [
"/**"
],
"body": [
"/**",
" * $0",
" */"
]
},
"trycatch": {
"prefix": [
"tc"
],
"body": [
"try {",
"\t$0",
"} catch (e) {",
"\tthrow e;",
"}"
],
"description": "Try catch block"
},
"Describe test": {
"prefix": [
"desc"
],
"body": [
"describe('${1}', () => {",
"\t$0",
"})"
],
"description": "Describe test"
}
}

View File

@@ -0,0 +1,262 @@
{
"@class (LuaDoc)": {
"body": [
"---@class (exact) ${1:class_name}",
"---@field ${2:field_name} string"
],
"description": "https://github.com/LuaLS/lua-language-server/wiki/Annotations#class",
"prefix": "@class (LuaDoc)"
},
"@type (LuaDoc)": {
"body": "---@type ${1:string}",
"prefix": "@type (LuaDoc)"
},
"Record (type)": {
"body": "---@type table<string, string>",
"prefix": "Record (type)"
},
"count occurrences in string": {
"body": "local _, count = ${1:str}:gsub(\"${2:find}\", \"\")",
"prefix": "count occurrences in string"
},
"export module": {
"body": [
"local M = {}",
"--------------------------------------------------------------------------------",
"",
"$0--------------------------------------------------------------------------------",
"return M"
],
"prefix": "export module"
},
"find all in string": {
"body": [
"local ${1:matches} = {}",
"for match in ${2:str}:gmatch(${3:pattern}) do",
"\ttable.insert(${1:matches}, match)",
"end"
],
"prefix": "find all in string"
},
"for each (list)": {
"body": [
"for _, ${1:v} in pairs(${2:table}) do",
"\t$0",
"end"
],
"prefix": "for each (list)"
},
"for each line (of file)": {
"body": [
"for line in io.lines(${1:filepath}) do",
"\t$0",
"end"
],
"prefix": [
"for each line (file)",
"read file (as lines)"
]
},
"home": {
"body": "os.getenv(\"HOME\")",
"prefix": "home"
},
"if .. then .. else": {
"body": [
"if ${1:true} then",
"\t$2",
"else",
"\t$0",
"end"
],
"filetype": "lua",
"prefix": "if .. then .. else"
},
"nodiscard": {
"body": "---@nodiscard",
"description": "Luadoc Annotation that a function's return value should not be discarded. https://github.com/LuaLS/lua-language-server/wiki/Annotations#nodiscard",
"prefix": "nodiscard"
},
"path of this file": {
"body": "local pathOfThisFile = debug.getinfo(1).source:sub(2)",
"prefix": "path of this file"
},
"path separator (os-independent)": {
"body": "local osPathSep = package.config:sub(1, 1)",
"prefix": "path separator (os-independent)"
},
"pcall": {
"body": [
"local success = pcall(${1:func})",
"if not success then",
"\t$0",
"\treturn",
"end"
],
"prefix": [
"try",
"pcall"
]
},
"read file": {
"body": [
"---@param filePath string",
"---@return string? -- content or error message",
"---@return boolean success",
"local function readFile(filePath)",
"\tlocal file, err = io.open(filePath, \"r\")",
"\tif not file then return err, false end",
"\tlocal content = file:read(\"*a\")",
"\tfile:close()",
"\treturn content, true",
"end"
],
"prefix": "read file"
},
"redirect (metatable __index)": {
"body": [
"setmetatable(M, {",
"\t__index = function(_, key)",
"\t\treturn function(...)",
"\t\t\trequire(${1:moduleToRedirectTo})[key](...)",
"\t\tend",
"\tend,",
"})"
],
"prefix": "redirect (metatable __index)"
},
"round number": {
"body": "local roundedNum = tonumber(string.format(\"%.${1:decimals}f\", exactNum))",
"prefix": "round number"
},
"safe require": {
"body": [
"local ok, ${1:module} = require(\"${1:module}\")",
"if not (ok and ${1:module}) then return end",
"${1:module}.$0"
],
"prefix": "safe require"
},
"sort (table)": {
"body": "table.sort(${1:table}, function(a, b) return ${2:a} > ${3:b} end)",
"prefix": "sort (table)"
},
"split (gmatch)": {
"body": [
"local acc = {}",
"for part in ${1:str}:gmatch(\"(.-)\" .. ${2:delimiter}) do",
"\ttable.insert(acc, part)",
"end"
],
"filetype": "lua",
"prefix": "split (gmatch)"
},
"ternary": {
"body": "${1:condition} and ${2:value1} or ${3:value2}",
"prefix": "ternary"
},
"trim trailing line break": {
"body": ":gsub(\"\\n$\", \"\")",
"prefix": "trim"
},
"write file": {
"body": [
"---@param str string",
"---@param filePath string",
"---@return string|nil -- error message",
"local function overwriteFile(filePath, str)",
"\tlocal file, _ = io.open(filePath, \"w\")",
"\tif not file then return end",
"\tfile:write(str)",
"\tfile:close()",
"end"
],
"description": "Overwriting file, for appending use `a` instead of `w`.",
"prefix": "write file"
},
"Create Auto Command": {
"prefix": "autocmd",
"body": [
"vim.api.nvim_create_autocmd(\"${1:event}\", {",
" group = vim.api.nvim_create_augroup(\"${2:group}\", { clear = true }),",
" callback = function(ev)",
" ${0}",
" end",
"})"
]
},
"Create Auto Command Group": {
"prefix": "augroup",
"body": [
"vim.api.nvim_create_augroup(\"${1:group}\", { clear = true })$0"
]
},
"Current Win": {
"prefix": "win",
"body": "local win = vim.api.nvim_get_current_win()\n$0"
},
"Current Buf": {
"prefix": "buf",
"body": "local buf = vim.api.nvim_get_current_buf()\n$0"
},
"Buf Valid": {
"prefix": "bufvalid",
"body": "vim.api.nvim_buf_is_valid(${1:buf})"
},
"Win Valid": {
"prefix": "winvalid",
"body": "vim.api.nvim_win_is_valid(${1:win})"
},
"Win Call": {
"prefix": "wincall",
"body": [
"vim.api.nvim_win_call(${1:win}, function(win)",
" ${0}",
"end)"
]
},
"Buf Call": {
"prefix": "bufcall",
"body": [
"vim.api.nvim_buf_call(${1:buf}, function(buf)",
" ${0}",
"end)"
]
},
"Schedule": {
"prefix": "schedule",
"body": [
"vim.schedule(function()",
" ${0}",
"end)"
]
},
"Table Deep Extend": {
"prefix": "deepextend",
"body": "vim.tbl_deep_extend(\"force\", ${1:table}, ${2:table})$0"
},
"Table Filter": {
"prefix": "filter",
"body": [
"vim.tbl_filter(function()",
" $0",
"end, ${1:table})"
]
},
"Table Map": {
"prefix": "map",
"body": [
"vim.tbl_map(function()",
" $0",
"end, ${1:table})"
]
},
"Table Values": {
"prefix": "values",
"body": "vim.tbl_values(${1:table})"
},
"Table Keys": {
"prefix": "keys",
"body": "vim.tbl_keys(${1:table})"
}
}

View File

@@ -0,0 +1,133 @@
{
"Misc": {
"body": "Miscellaneous",
"prefix": "Misc"
},
"bash (Codeblock)": {
"body": [
"```bash",
"$CLIPBOARD$0",
"```"
],
"prefix": "bash (Codeblock)"
},
"caution (callout)": {
"body": [
"> [!CAUTION]",
"> $0"
],
"description": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts",
"prefix": "caution (callout)"
},
"details & summary": {
"body": [
"<details>",
"<summary>${1:Text}</summary>",
"$0",
"</details>"
],
"description": "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details",
"prefix": [
"toggle / fold",
"details & summary"
]
},
"ignore file (ltex)": {
"body": "<!-- LTeX: enabled=false -->",
"prefix": "ignore file (ltex)"
},
"image": {
"body": "<img src=\"${1:image_path}\" alt=\"${2:alt text}\" width=\"${3:50%}\">",
"description": "HTML syntax for images used to display images with reduced size",
"prefix": "image"
},
"important (callout)": {
"body": [
"> [!IMPORTANT]",
"> $0"
],
"description": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts",
"prefix": "important (callout)"
},
"insert table 2x2": {
"body": [
"| ${1:Column1} | ${2:Column2} |",
"|--------------- | -------------- |",
"| ${3:Item1.1} | ${4:Item2.1} |"
],
"prefix": "table (2x2)"
},
"insert toc": {
"body": [
"## Table of Content",
"",
"<!-- toc -->"
],
"description": "https://github.com/jonschlinkert/markdown-toc#tocinsert",
"prefix": "insert toc"
},
"js (Codeblock)": {
"body": [
"```js",
"$CLIPBOARD$0",
"```"
],
"prefix": "js (Codeblock)"
},
"kbd": {
"body": "<kbd>$0</kbd>",
"description": "HTML tag for keys",
"prefix": "kbd"
},
"lua (Codeblock)": {
"body": [
"```lua",
"$CLIPBOARD$0",
"```"
],
"prefix": "lua (Codeblock)"
},
"note (GitHub callout)": {
"body": [
"> [!NOTE]",
"> $0"
],
"description": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts",
"prefix": [
"info (callout)",
"note (callout)"
]
},
"py (Codeblock)": {
"body": [
"```py",
"$CLIPBOARD$0",
"```"
],
"prefix": "py (Codeblock)"
},
"tip (callout)": {
"body": [
"> [!TIP]",
"> $0"
],
"description": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts",
"prefix": "tip (callout)"
},
"ts (Codeblock)": {
"body": [
"```ts",
"$CLIPBOARD$0",
"```"
],
"prefix": "ts (Codeblock)"
},
"warning (callout)": {
"body": [
"> [!WARNING]",
"> $0"
],
"description": "https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts",
"prefix": "warning (callout)"
}
}

View File

@@ -0,0 +1,334 @@
{
"PATH (export)": {
"body": "export PATH=/usr/local/lib:/usr/local/bin:/opt/homebrew/bin/:\\$PATH",
"description": "Extends PATH in a way that homebrew installed CLIs are recognized in ARM and Intel Macs.",
"prefix": "PATH (export)"
},
"awk (get field)": {
"body": "awk '{ print $${1:1} }'",
"description": "Retrieve a field from the piped in string, with whitespace as the default field delimiter. `$n` means that the nth field will be used.",
"prefix": "awk (field)"
},
"check device name": {
"body": "scutil --get ComputerName | grep -q \"$0\"",
"prefix": "device name"
},
"check if dark mode (macOS)": {
"body": "defaults read -g AppleInterfaceStyle &>/dev/null; && echo 'isDark'",
"prefix": "check if dark mode (macOS)"
},
"check if in git repo": {
"body": "if ! git rev-parse --is-inside-work-tree &>/dev/null ; then print \"\\e[0;33mfile is not ins a git repository.\\e[0m\" && return 1 ; fi",
"prefix": "check if in git repo"
},
"check if installed": {
"body": [
"if [[ ! -x \"\\$(command -v ${1:cli})\" ]]; then print \"\\e[0;33m${1:cli} not installed.\\e[0m\" && return 1; fi",
"$0"
],
"description": "https://stackoverflow.com/a/26759734/22114136",
"prefix": "check if installed"
},
"check if on macOS": {
"body": "[[ \"\\$OSTYPE\" =~ \"darwin\" ]]",
"prefix": "check if on macOS"
},
"check if process is running": {
"body": "pgrep -xq \"${1:process}\" && $0",
"prefix": "check if process is running"
},
"check if sudo user": {
"body": "sudo -nv && ${1:some_sudo_action}",
"prefix": "check if sudo user"
},
"confirmation prompt": {
"body": [
"# confirmation prompt",
"print \"\\e[1;34m$0Proceed? (y/n)\\e[0m\"",
"read -rk pressed",
"echo",
"if [[ \"\\$pressed\" != \"y\" ]]; then",
"\techo \"Aborted.\"",
"\treturn 1",
"fi",
"echo"
],
"prefix": "confirmation prompt"
},
"default value": {
"body": "\\${${1:var}:-${2:default_value}}",
"prefix": "default value"
},
"directory of script": {
"body": "\"$(dirname \"$(readlink -f \"\\$0\")\")\"",
"prefix": "directory of this script"
},
"elseif": {
"body": "elif [[ ${1:condition} ]]; then\n\t${0}",
"description": "Add an elseif to an if statement.",
"prefix": "elseif"
},
"extension": {
"body": "ext=${${1:file_name}##*.}",
"prefix": "get extension"
},
"filename": {
"body": "file_name=$(basename \"$${1:file_path}\")",
"prefix": "filename"
},
"filename w/o ext": {
"body": "${1:file_name}=${${1:file_name}%.*}",
"prefix": "filename w/o ext"
},
"find & xargs": {
"body": "find . -print0 | xargs -0 -I '{}'",
"prefix": "find & xargs"
},
"find -exec": {
"body": "find . $0 -exec open '{}' \\;",
"prefix": "find -exec"
},
"for each file": {
"body": [
"for filename in *.txt; do",
"\techo \"\\$filename\"",
"done"
],
"prefix": "for each file"
},
"for each line (read)": {
"body": [
"while read -r line; do",
"\techo \"\\$line\"$0",
"done < \"\\$${1:input_file}\""
],
"prefix": "for each line (read)"
},
"for each line (variable)": {
"body": [
"echo \"\\$lines\" | while read -r line; do",
"\techo \"\\$line\"",
"done"
],
"prefix": "for each line (variable)"
},
"for i ..": {
"body": [
"for ((i = 0; i <= ${1:length}; i++)); do",
" echo \\$i$0",
"done"
],
"prefix": "for i .."
},
"function": {
"body": "function ${1:name} {\n\t${0}\n}",
"prefix": "function"
},
"get nth line from string": {
"body": "line=$(echo \"\\$${1:str}\" | sed -n \"${2:n}p\")",
"prefix": "get nth line from string"
},
"i++": {
"body": "((${1:i}++))",
"prefix": "i++"
},
"i--": {
"body": "((${1:i}--))",
"prefix": "i--"
},
"if (short)": {
"body": "[[ \"\\$${1:var}\" ]] && $0",
"prefix": "if (short)"
},
"if .. then": {
"body": [
"if [[ \"\\$${1:var}\" ]]; then",
"\t$0",
"fi"
],
"prefix": "if .. then"
},
"if .. then .. else": {
"body": [
"if [[ \"$${1:cond}\" ]]; then",
"\t$0",
"else",
"\t",
"fi"
],
"prefix": "if .. then .. else"
},
"input (stdin or $1)": {
"body": [
"if [[ $# -eq 0 ]]; then",
"\tinput=$(< /dev/stdin)",
"else",
"\tinput=\"$1\"",
"fi"
],
"description": "reads either from STDIN or $1. stdin may have unescaped newlines, which have to be removed, e.g. via `tr -d '\n'`.",
"prefix": "input (stdin or $1)"
},
"notify (msg)": {
"body": "osascript -e 'display notification \"\" with title \"${1:msg}\"'",
"prefix": "notify (msg)"
},
"notify (var)": {
"body": "osascript -e \"display notification \\\"\\\" with title \\\"$${1:var}\\\"\"",
"prefix": "notify (var)"
},
"null (pipe)": {
"body": "&> /dev/null",
"prefix": "null (pipe)"
},
"osascript jxa (run script)": {
"body": "osascript -l JavaScript \"${1:file}\"",
"prefix": [
"jxa (run script)",
"osascript -l JavaScript"
]
},
"plist: extract key": {
"body": "plutil -extract name.childkey xml1 -o - example.plist | sed -n 4p | cut -d'>' -f2 | cut -d'<' -f1",
"prefix": "plist: extract key"
},
"print in blue": {
"body": "print \"\\e[1;34m$0\\e[0m\"",
"prefix": "print in blue"
},
"progress bar": {
"body": [
"for _ in {1..100}; do",
"\tprintf \"\ud83e\udf0b\"",
"\tsleep 0.5",
"done"
],
"prefix": "progress bar"
},
"quicklook": {
"body": "qlmanage -p \"${1:filepath}\"",
"description": "QuickLook the file. MacOS only.",
"prefix": "quicklook"
},
"redirect to stderr": {
"body": ">&2",
"prefix": "redirect to stderr"
},
"resolve home": {
"body": "${1:path}=\"\\${${1:path}/#\\~/\\$HOME}\"",
"prefix": "resolve home"
},
"restart app": {
"body": [
"killall \"${1:app_name}\"",
"while pgrep -xq \"${1:app_name}\"; do sleep 0.1; done",
"open -a \"${1:app_name}\""
],
"description": "safely restart app, avoiding race condition",
"prefix": "restart app"
},
"sed substitution": {
"body": "sed 's/$0//'",
"prefix": "sed substitution"
},
"shebang": {
"body": "#!/usr/bin/env zsh",
"prefix": "shebang"
},
"slice": {
"body": "${1:var}=\"${${1:var}:${2:from}:${3:to}}\"",
"prefix": "slice"
},
"spinner": {
"body": [
"# spinner with 20s timeout",
"spinner=\"\u280b\u2819\u2839\u2838\u283c\u2834\u2826\u2827\u2807\u280f\"",
"for i in {1..100}; do",
"\tpos=\\$((i % \\${#spinner}))",
"\tprintf \"\\r%s\" \"\\${spinner:\\$pos:1}\"",
"\tsleep 0.2",
"done",
"printf \"\\r\" # remove spinner"
],
"prefix": "spinner"
},
"stderr (merge with stdout)": {
"body": "2>&1",
"prefix": "stderr (merge with stdout)"
},
"stdin": {
"body": "stdin=\\$(< /dev/stdin)",
"description": "$(cat) also works. See https://stackoverflow.com/questions/32363887/in-a-bash-function-how-do-i-get-stdin-into-a-variable",
"prefix": "stdin"
},
"stdout is to a terminal": {
"body": "[[ -t true ]]",
"prefix": "stdout is to a terminal"
},
"substitute": {
"body": "\\${${1:var}//${2:search}/${3:replace}}",
"description": "one slash for single substitution, two for global",
"prefix": "substitute (expansion)"
},
"suppress stderr": {
"body": "2>/dev/null",
"prefix": "suppress stderr"
},
"switch case": {
"body": [
"case $${1:var} in",
"\"one\" | \"two\")",
"\techo \"foo\"",
"\t;;",
"\"three\")",
"\techo \"bar\"",
"\t;;",
"*)",
"\techo \"default\"",
"\t;;",
"esac"
],
"description": "A case command first expands word, and tries to match it against each pattern in turn.",
"prefix": "switch case"
},
"ternary": {
"body": "\\$([[ \"${1:cond}\" ]] && echo \"${2:value1}\" || echo \"${3:value2}\")",
"prefix": "ternary"
},
"then": {
"body": "then\n\t$0\nfi",
"prefix": "then .. fi"
},
"today (ISO date) + now": {
"body": "${1:now}=\\$(date +\"%Y-%m-%d %H:%M:%S\")",
"prefix": [
"today (ISO date)",
"now"
]
},
"trim whitespace": {
"body": "${1:text}=$(echo -n \"$${1:text}\" | sed -e 's/^ *//' -e 's/ *$//')",
"prefix": "trim whitespace"
},
"urlEncode": {
"body": "osascript -l JavaScript -e \"encodeURIComponent('${1:text}')\"",
"prefix": "urlEncode"
},
"wait until app running": {
"body": "while ! pgrep -xq \"${1:app_name}\"; do sleep 0.1; done",
"prefix": "wait until app running"
},
"wait until app terminated": {
"body": "while pgrep -xq \"${1:app_name}\"; do sleep 0.1; done",
"prefix": "wait until app terminated"
},
"while": {
"body": "while [[ ${1:condition} ]]; do\n\t${0}\ndone\n",
"description": "A while loop by condition.",
"prefix": "while"
},
"xargs (for each line)": {
"body": "xargs -I {} ${1:some_cmd} '{}'",
"prefix": "xargs (for each line)"
}
}

View File

@@ -0,0 +1,7 @@
{
"schema (modeline)": {
"body": "# yaml-language-server: $$schema=${1:url}",
"description": "https://github.com/redhat-developer/yaml-language-server#using-inlined-schema",
"prefix": "schema (modeline)"
}
}

View File

@@ -56,3 +56,4 @@ disable_startup_command = true
name = "Downloads"
path = "~/Downloads"
startup_command = "lsa"

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
# Get session list and pipe it to gum for selection
SESH_LIST=$(
sesh list -i \
| gum filter \
--limit 1 \
--no-sort \
--fuzzy \
--placeholder 'Pick a sesh' \
--height 50 \
--prompt='⚡'
)
# If a session was selected, connect to it
if [ "$SESH_LIST" != "" ]; then
sesh connect "$SESH_LIST"
fi

View File

@@ -1 +1,3 @@
set -g @catppuccin_flavor "mocha"
set -g @catppuccin_window_status_style "basic"

View File

@@ -1 +1,2 @@
set -g @catppuccin_flavor "latte"
set -g @catppuccin_window_status_style "basic"

View File

@@ -16,6 +16,7 @@
# -u : Unset the specified option.
set -ag terminal-overrides ",xterm-256color:RGB"
set -ag terminal-features 'xterm-256color:RGB'
# Enable proper color support
set -as terminal-features ",*:RGB"
@@ -28,6 +29,15 @@ set -g mouse on # Mouse support
set -g set-titles on # Allow tmux to set the terminal title
set -g status on # Setting status on
set -g status-keys vi # vi keys to move between panes
set -g history-limit 3000 # Scrollback history limit
# Activity Monitoring (for when something happens in another pain)
set -g monitor-activity on
set -g visual-activity off
set -g visual-bell off
# A bell in another window should cause a bell in the current window
set -g bell-action any
# Keep Tmux alive when the initial command is finished
set -g remain-on-exit off
@@ -37,23 +47,24 @@ set -g base-index 1
set -g pane-base-index 1
set -g renumber-windows on
# Activate with `DEBUG=1 tmux -vv`
if-shell '[ "$DEBUG" = "1" ]' 'set -g debug-file ~/.cache/tmux-debug.log'
# ╭──────────────────────────────────────────────────────────╮
# │ Theme │
# ╰──────────────────────────────────────────────────────────╯
set -g status-bg default
set -g status-justify left
set -g status-justify "left"
set -g status-left ''
set -g status-left-length "0"
set -g status-position "bottom"
#set -g status-right "#S@#h #{tmux_mode_indicator}"
set -g status-right "#S@#h #{tmux_mode_indicator}"
set -g status-right-length "50"
#set -g window-status-current-format ' #I:#W#{?window_zoomed_flag, ◈ ,} '
#set -g window-status-format ' #I:#W '
set -g window-status-current-format ' #I:#W#{?window_zoomed_flag, ◈ ,} '
set -g window-status-format ' #I:#W '
set -g @catppuccin_status_background 'none'
set -g @catppuccin_window_flags 'icon'
set -g @catppuccin_window_text "#T"
set -g @catppuccin_window_current_text "#T"
set -g @catppuccin_status_connect_separator 'no'
# ╭──────────────────────────────────────────────────────────╮
# │ Bindings │
@@ -75,6 +86,11 @@ bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
# Easier switching between window
bind C-n next-window
bind C-p previous-window
bind C-a last-window
# Reload tmux config with <prefix> + r
unbind r
bind r "source-file ~/.dotfiles/config/tmux/tmux.conf; display 'tmux cfg reloaded!'"
@@ -87,8 +103,15 @@ bind Escape copy-mode
unbind p
bind p paste-buffer
# tms bindings
bind -N "tms" T display-popup -E "tms"
bind -N "tms windows" C-w display-popup -E "tms windows"
bind -N "tms switch" C-s display-popup -E "tms switch"
bind -N "tms refresh" C-r display-popup -E "tms refresh"
# global sessions
bind -N "sesh selection" t display-popup -E "$HOME/.dotfiles/config/tmux/sesh-gum.sh"
# bind-key "K" display-popup -h 90% -w 50% -E "sesh ui"
bind -N "sesh selection" t run-shell "$HOME/.dotfiles/config/tmux/sesh-tmux.fish"
bind -N "last-session (via sesh) " L run-shell "sesh last"
bind -N "sesh ui" N display-popup -E "sesh ui"

View File

@@ -1,4 +1,4 @@
# shellcheck disable=SC1071,SC1103,SC2148
# shellcheck shell=zsh
# Source: https://github.com/nvm-sh/nvm#zsh
# place this after nvm initialization!
autoload -U add-zsh-hook

View File

@@ -1,52 +0,0 @@
version: "0.2"
ignorePaths: []
dictionaryDefinitions: []
dictionaries: []
words:
- aquasec
- cdgr
- cheatsheets
- CODEQUALITY
- DEVSKIM
- dscacheutil
- emptytrash
- flushcache
- getifaddr
- goenv
- irssi
- Ismo
- isodate
- KEYSFILE
- KEYSSOURCE
- killall
- lakka
- libexec
- Licence
- lmstudio
- localip
- locatedb
- LOGFILE
- luarocks
- mvdan
- myip
- onnimonni
- opencode
- optstring
- orbstack
- osascript
- phpenv
- psub
- pyenv
- SARIF
- shellcheck
- shfmt
- shivammathur
- spelllang
- updatedb
- vendordirs
- vimrc
- virtualenv
- Vuorinen
- zedit
ignoreWords: []
import: []

View File

@@ -0,0 +1,425 @@
# Chezmoi Migration Summary
## What Was Done
Your dotfiles repository has been prepared for migration from dotbot to chezmoi. Here's what was created:
### 1. Updated Install Script
- **File**: `install`
- **Change**: Now uses chezmoi's one-line installer
- **Command**: `sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen`
### 2. Chezmoi Configuration Files
#### `.chezmoi.yaml.tmpl`
Main configuration file that includes:
- Source directory configuration
- Host detection (air, lakka, tunkki, s)
- OS detection (macOS, Linux)
- Custom data variables for templates
- Merge and diff settings
- Git configuration
- Pre-read hook for submodule updates
#### `.chezmoiignore`
Specifies what files should NOT be managed by chezmoi:
- Git and GitHub files
- Documentation (*.md files)
- Development tools (.vscode, node_modules, etc.)
- Old dotbot configuration
- Host-specific files (via templates)
- Repository management files
### 3. Run Scripts (Automated Setup)
#### `run_once_before_install-prerequisites.sh.tmpl`
Runs **once before** applying dotfiles:
- Installs Homebrew (macOS)
- Installs Xcode CLI tools (macOS)
- Updates package manager (Linux)
#### `run_once_after_install-packages.sh.tmpl`
Runs **once after** applying dotfiles:
- Installs Homebrew packages (Brewfile)
- Sets macOS defaults
- Installs apt packages (Linux)
- Installs pipx packages
#### `run_once_after_setup-languages.sh.tmpl`
Runs **once after** applying dotfiles:
- Installs fonts
- Installs Cargo packages (Rust)
- Installs Go packages
- Installs Composer (PHP)
- Installs NVM and latest Node LTS
- Installs NPM packages
- Installs GitHub CLI extensions
- Installs z (directory jumper)
- Installs cheat databases
#### `run_once_after_create-directories.sh.tmpl`
Runs **once after** applying dotfiles:
- Creates required directories in `$HOME`
- Sets proper permissions (e.g., `.ssh` → 0700)
### 4. Hooks
#### `.chezmoihooks/pre-read-source-state.sh`
Runs before chezmoi reads the source state:
- Updates git submodules automatically
### 5. Documentation
#### `MIGRATION-DOTBOT-TO-CHEZMOI.md` (66KB)
Comprehensive migration guide including:
- Why migrate to chezmoi
- Key differences between dotbot and chezmoi
- Complete dotbot → chezmoi mapping
- File structure comparison
- Step-by-step migration instructions
- Usage guide with examples
- Troubleshooting section
- Migration checklist
#### `CHEZMOI-QUICK-REFERENCE.md` (11KB)
Quick reference guide for daily use:
- Common commands
- File naming conventions
- Template syntax examples
- Host-specific configuration patterns
- Troubleshooting tips
- Useful aliases
#### `HOST-SPECIFIC-MIGRATION.md` (9KB)
Detailed guide for migrating host-specific configurations:
- Three migration approaches explained
- Examples from your current hosts
- Step-by-step host config migration
- Testing strategies
- Best practices
### 6. Migration Helper Script
#### `migrate-to-chezmoi.sh`
Automated script to restructure your files:
- Creates backup branch automatically
- Creates migration branch
- Renames files to chezmoi conventions
- `base/*``dot_*`
- `config/*``dot_config/*`
- `local/bin/*``executable_dot_local/bin/*`
- `ssh/*``private_dot_ssh/*`
- Cleans up empty directories
- Generates migration notes
## What Needs To Be Done
### Immediate Next Steps
1. **Review Changes**
```bash
cd ~/.dotfiles
git status
git diff
```
2. **Read Documentation**
- Start with: `MIGRATION-DOTBOT-TO-CHEZMOI.md`
- Quick reference: `CHEZMOI-QUICK-REFERENCE.md`
- Host configs: `HOST-SPECIFIC-MIGRATION.md`
3. **Commit Current State**
```bash
git add install .chezmoi.yaml.tmpl .chezmoiignore
git add run_once_*.sh.tmpl .chezmoihooks/
git add migrate-to-chezmoi.sh
git add *.md
git commit -m "Add chezmoi configuration and migration tools"
```
### File Restructuring
You have two options:
#### Option A: Automated (Recommended for First Pass)
```bash
# Run the migration script
./migrate-to-chezmoi.sh
# This will:
# - Create backup branch
# - Create migration branch
# - Rename all files to chezmoi conventions
# - Show you what was done
```
#### Option B: Manual (More Control)
Manually rename files following chezmoi conventions:
```bash
# Base files become dot_ files
git mv base/bashrc dot_bashrc
git mv base/zshrc dot_zshrc
git mv base/tmux.conf dot_tmux.conf
# Config files
mkdir -p dot_config
git mv config/fish dot_config/fish
git mv config/nvim dot_config/nvim
# ... etc
# Local bin (make executable)
mkdir -p executable_dot_local/bin
for file in local/bin/*; do
git mv "$file" "executable_dot_local/bin/$(basename $file)"
done
# SSH files (private)
mkdir -p private_dot_ssh
git mv ssh/* private_dot_ssh/
# See full examples in MIGRATION-DOTBOT-TO-CHEZMOI.md
```
### Host-Specific Configurations
Your hosts need special attention:
```bash
hosts/
├── air/
├── lakka/
├── tunkki/
└── s/
```
**Read**: `HOST-SPECIFIC-MIGRATION.md` for detailed strategies.
**Quick decision guide**:
- **Few differences per file** → Use templates with `{{ if .is_air }}`
- **Complete replacement** → Use `filename__hostname` suffix
- **Host-specific directories** → Use `.chezmoiignore` with templates
### Testing Before Commit
```bash
# After restructuring files, test with chezmoi
cd ~/.dotfiles
# Initialize chezmoi with current directory as source
chezmoi init --source $(pwd)
# See what would happen (dry run)
chezmoi apply --dry-run --verbose
# See what a specific file would look like
chezmoi cat ~/.bashrc
# Check for errors
chezmoi verify
```
### Final Steps
1. **Commit Migration**
```bash
git add -A
git commit -m "Migrate from dotbot to chezmoi"
git push
```
2. **Test on Current Machine**
```bash
# Apply dotfiles
chezmoi apply -v
# Verify everything works
# Open new terminal
# Check configs
```
3. **Test on Another Machine** (if available)
```bash
# On another machine
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
# Verify host-specific configs applied correctly
```
4. **Clean Up** (after confirming everything works)
```bash
cd $(chezmoi source-path)
# Remove old dotbot files
rm -rf tools/dotbot tools/dotbot-*
rm install.conf.yaml
rm tools/dotbot-defaults.yaml
# Optionally remove hosts/ if fully migrated to templates
# rm -rf hosts/
git add -A
git commit -m "Clean up old dotbot files"
git push
```
## Key Differences to Remember
### Installation
**Before**: `./install` (ran dotbot)
**After**: `sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen`
### Making Changes
**Before**:
```bash
cd ~/.dotfiles
vim base/bashrc
./install # Re-run to create symlinks
```
**After**:
```bash
chezmoi edit ~/.bashrc
# Or: vim ~/.bashrc && chezmoi add ~/.bashrc
chezmoi apply
```
### Syncing Across Machines
**Before**:
```bash
cd ~/.dotfiles
git pull
./install
```
**After**:
```bash
chezmoi update
# Equivalent to: cd $(chezmoi source-path) && git pull && chezmoi apply
```
### Host-Specific Configs
**Before**: Separate files in `hosts/hostname/`
**After**: Templates with `{{ if eq .chezmoi.hostname "air" }}` or `filename__hostname`
## File Mapping Reference
| Old Location | New Location | Notes |
|--------------|--------------|-------|
| `base/bashrc` | `dot_bashrc` | Becomes `~/.bashrc` |
| `config/fish/` | `dot_config/fish/` | Becomes `~/.config/fish/` |
| `local/bin/script` | `executable_dot_local/bin/script` | Executable `~/.local/bin/script` |
| `ssh/config` | `private_dot_ssh/config` | Private (0600) `~/.ssh/config` |
| `install.conf.yaml` | `run_once_*.sh.tmpl` | Setup tasks |
| `hosts/air/config/` | `dot_config/*.tmpl` or `*__air` | Host-specific |
## Troubleshooting Quick Tips
### "Entry not in source state"
```bash
# File not added to chezmoi
chezmoi add <file>
```
### "File modified since chezmoi last wrote it"
```bash
# See changes
chezmoi diff
# Re-add
chezmoi add <file>
```
### "Template undefined variable"
```bash
# Check available data
chezmoi data
# Test template
chezmoi execute-template "{{ .chezmoi.hostname }}"
```
### Scripts not running
```bash
# Check permissions
chmod +x run_once_*.sh.tmpl
# Force re-run
chezmoi apply --force
```
## Additional Resources
### Created Documentation
- `MIGRATION-DOTBOT-TO-CHEZMOI.md` - Complete migration guide
- `CHEZMOI-QUICK-REFERENCE.md` - Daily usage reference
- `HOST-SPECIFIC-MIGRATION.md` - Host configuration guide
- `MIGRATION-NOTES.md` - Generated after running migration script
### External Resources
- [Chezmoi Official Docs](https://www.chezmoi.io/)
- [Chezmoi Quick Start](https://www.chezmoi.io/quick-start/)
- [Chezmoi User Guide](https://www.chezmoi.io/user-guide/)
- [Chezmoi Templates](https://www.chezmoi.io/reference/templates/)
## Summary Checklist
- [x] Install script updated
- [x] Chezmoi configuration created (`.chezmoi.yaml.tmpl`)
- [x] Ignore file created (`.chezmoiignore`)
- [x] Run scripts created (4 scripts)
- [x] Hooks created (pre-read-source-state)
- [x] Migration script created (`migrate-to-chezmoi.sh`)
- [x] Documentation created (3 guides)
- [ ] **Review and commit configuration files**
- [ ] **Run migration script** or manually restructure
- [ ] **Migrate host-specific configs**
- [ ] **Test with chezmoi**
- [ ] **Commit migration**
- [ ] **Test on current machine**
- [ ] **Test on other machines**
- [ ] **Clean up old dotbot files**
- [ ] **Update README.md** (document chezmoi usage)
## Questions?
If you have questions during migration:
1. Check the relevant guide:
- General questions → `MIGRATION-DOTBOT-TO-CHEZMOI.md`
- Usage questions → `CHEZMOI-QUICK-REFERENCE.md`
- Host configs → `HOST-SPECIFIC-MIGRATION.md`
2. Use chezmoi's help:
```bash
chezmoi help
chezmoi help <command>
chezmoi doctor
```
3. Check official docs:
- https://www.chezmoi.io/
## What Makes This Migration Special
Your dotfiles have:
- ✅ Custom `dfm` script → Wrapped in run_once scripts
- ✅ Multiple dotbot plugins → Equivalent run_once scripts
- ✅ Host-specific configs → Template support added
- ✅ Complex installation → Automated in run scripts
- ✅ Git submodules → Pre-read hook handles this
- ✅ Multiple hosts (air, lakka, tunkki, s) → Detected and flagged
Everything from your dotbot setup has been accounted for in the chezmoi migration!
## Final Notes
- **Take your time**: This is a significant migration
- **Test thoroughly**: Use `--dry-run` extensively
- **Backup everything**: The migration script creates backups
- **Iterate**: You can always refine the migration later
- **Have fun**: Chezmoi offers powerful features to explore!
Good luck with your migration! 🚀

View File

@@ -0,0 +1,432 @@
# Chezmoi Quick Reference
Quick reference guide for common chezmoi operations with your dotfiles.
## Installation
```bash
# Fresh install on a new machine
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
# Or if chezmoi is already installed
chezmoi init --apply ivuorinen
```
## Daily Workflow
### Making Changes
```bash
# Edit a dotfile (opens in $EDITOR)
chezmoi edit ~/.bashrc
# Or edit directly and add to chezmoi
vim ~/.bashrc
chezmoi add ~/.bashrc
# See what would change
chezmoi diff
# Apply changes
chezmoi apply
```
### Syncing Across Machines
```bash
# On machine A: commit and push changes
cd $(chezmoi source-path)
git add -A
git commit -m "Update configuration"
git push
# On machine B: pull and apply changes
chezmoi update
# This is equivalent to:
# cd $(chezmoi source-path) && git pull && chezmoi apply
```
## Common Commands
### Viewing and Inspecting
```bash
# See what chezmoi would do
chezmoi diff
# List all managed files
chezmoi managed
# List unmanaged files
chezmoi unmanaged
# Show the source path
chezmoi source-path
# Show what a file would look like after templating
chezmoi cat ~/.bashrc
# Show available template data
chezmoi data
```
### Adding and Removing Files
```bash
# Add a file
chezmoi add ~/.newfile
# Add a file as a template
chezmoi add --template ~/.newfile
# Add a directory recursively
chezmoi add --recursive ~/.config/newapp
# Add with autodetection (templates, scripts, etc.)
chezmoi add --autotemplate ~/.newfile
# Stop managing a file (removes from chezmoi)
chezmoi forget ~/.oldfile
# Remove a file from both chezmoi and home directory
chezmoi remove ~/.oldfile
```
### Working with Templates
```bash
# Execute a template expression
chezmoi execute-template "{{ .chezmoi.hostname }}"
# Edit template data
chezmoi edit-config
# Verify templates
chezmoi verify
```
### Applying Changes
```bash
# Apply all changes
chezmoi apply
# Apply with verbose output
chezmoi apply -v
# Dry run (show what would happen)
chezmoi apply --dry-run -v
# Force apply (re-runs scripts)
chezmoi apply --force
# Apply only specific files
chezmoi apply ~/.bashrc ~/.zshrc
```
### Updating from Repository
```bash
# Update dotfiles from repository
chezmoi update
# Update but don't apply
cd $(chezmoi source-path) && git pull
# Update with interactive merge
chezmoi update --interactive
```
## File Naming Conventions
### Basic Prefixes
| Source File | Destination | Description |
|------------|-------------|-------------|
| `dot_bashrc` | `~/.bashrc` | Dot file |
| `dot_config/` | `~/.config/` | Dot directory |
| `private_dot_ssh/` | `~/.ssh/` | Private directory (0700) |
| `executable_dot_local/bin/script` | `~/.local/bin/script` | Executable |
| `symlink_dot_vim` | `~/.vim` | Symlink |
| `readonly_dot_file` | `~/.file` | Read-only |
### Template Files
| Source File | Description |
|------------|-------------|
| `dot_bashrc.tmpl` | Template file |
| `dot_config/fish/config.fish.tmpl` | Nested template |
### Scripts
| Script Name | When It Runs |
|------------|--------------|
| `run_once_before_*.sh` | Once before applying |
| `run_once_after_*.sh` | Once after applying |
| `run_before_*.sh` | Every time before applying |
| `run_after_*.sh` | Every time after applying |
| `run_onchange_*.sh` | When script content changes |
## Template Syntax
### Basic Variables
```go
// Hostname
{{ .chezmoi.hostname }}
// Username
{{ .chezmoi.username }}
// Operating system
{{ .chezmoi.os }}
// Home directory
{{ .chezmoi.homeDir }}
// Source directory
{{ .chezmoi.sourceDir }}
// Custom data from .chezmoi.yaml
{{ .is_macos }}
{{ .is_linux }}
```
### Conditionals
```go
{{ if eq .chezmoi.hostname "air" }}
# Configuration for air
{{ else if eq .chezmoi.hostname "lakka" }}
# Configuration for lakka
{{ else }}
# Default configuration
{{ end }}
{{ if .is_macos }}
# macOS-specific
{{ end }}
{{ if and .is_macos (eq .chezmoi.hostname "air") }}
# macOS on air
{{ end }}
```
### Loops
```go
{{ range $key, $value := .data }}
{{ $key }}: {{ $value }}
{{ end }}
```
### Including Files
```go
{{ include "template-file.txt" }}
{{ includeTemplate "template-file.tmpl" }}
```
## Host-Specific Configuration
### Method 1: Template Conditionals
In `dot_bashrc.tmpl`:
```bash
# Common configuration
export PATH="$HOME/.local/bin:$PATH"
{{ if eq .chezmoi.hostname "air" }}
# air-specific configuration
export WORK_DIR="$HOME/Work"
{{ end }}
{{ if eq .chezmoi.hostname "lakka" }}
# lakka-specific configuration
export WORK_DIR="$HOME/Projects"
{{ end }}
```
### Method 2: Separate Files with Symlinks
Use `.chezmoiignore` to exclude files for specific hosts:
```
{{ if ne .chezmoi.hostname "air" }}
dot_config/air-specific-app/
{{ end }}
{{ if ne .chezmoi.hostname "lakka" }}
dot_config/lakka-specific-app/
{{ end }}
```
## Working with Secrets
### Environment Variables
```go
{{ .Env.MY_SECRET }}
```
### 1Password
```go
{{ (onepasswordDocument "my-secret").content }}
{{ (onepasswordItemFields "my-item").password.value }}
```
### External Commands
```go
{{ output "op" "read" "op://vault/item/field" }}
```
## Troubleshooting
### Check Configuration
```bash
# Verify chezmoi is working correctly
chezmoi doctor
# Check state
chezmoi verify
# See detailed info
chezmoi data
```
### Debug Templates
```bash
# See what a template would produce
chezmoi cat ~/.bashrc
# Execute a template
chezmoi execute-template "{{ .chezmoi.hostname }}"
# Verbose output
chezmoi apply -v
```
### Fix Issues
```bash
# Re-apply everything
chezmoi apply --force
# Reset state (dangerous!)
chezmoi state reset
# Clear cache
rm -rf $(chezmoi source-path)/.git/chezmoi-*
```
### Common Errors
**Error: template: ... undefined variable**
- Check template syntax
- Verify data with `chezmoi data`
**Error: entry ... is not in source state**
- File not added to chezmoi: `chezmoi add <file>`
**Error: ... has been modified since chezmoi last wrote it**
- See changes: `chezmoi diff`
- Re-add: `chezmoi add <file>`
- Or force apply: `chezmoi apply --force`
## Useful Aliases
Add these to your shell configuration:
```bash
# Chezmoi shortcuts
alias cm='chezmoi'
alias cma='chezmoi apply'
alias cmd='chezmoi diff'
alias cme='chezmoi edit'
alias cmu='chezmoi update'
alias cmcd='cd $(chezmoi source-path)'
# Common workflows
alias cmup='chezmoi git pull && chezmoi apply'
alias cmpush='cd $(chezmoi source-path) && git add -A && git commit && git push'
```
## Environment Variables
```bash
# Change source directory (default: ~/.local/share/chezmoi)
export CHEZMOI_SOURCE_DIR="$HOME/.dotfiles"
# Change config file location
export CHEZMOI_CONFIG_FILE="$HOME/.config/chezmoi/chezmoi.yaml"
# Use different editor
export EDITOR="vim"
```
## Advanced Usage
### Using chezmoi as a dotfiles manager
```bash
# Initialize with local directory
chezmoi init --source ~/.dotfiles
# Use current directory as source
chezmoi init --source $(pwd)
```
### Managing Multiple Machines
Use data in `.chezmoi.yaml.tmpl`:
```yaml
data:
is_work_machine: {{ or (eq .chezmoi.hostname "work-laptop") (eq .chezmoi.hostname "work-desktop") }}
is_personal: {{ eq .chezmoi.hostname "personal-laptop" }}
```
Then in templates:
```go
{{ if .is_work_machine }}
# Work configuration
{{ end }}
```
### External Files
```yaml
# .chezmoiexternal.yaml
".config/nvim/lua/plugins":
type: "archive"
url: "https://github.com/user/nvim-config/archive/main.tar.gz"
stripComponents: 1
refreshPeriod: "168h"
```
## Resources
- [Official Documentation](https://www.chezmoi.io/)
- [User Guide](https://www.chezmoi.io/user-guide/)
- [Template Reference](https://www.chezmoi.io/reference/templates/)
- [Command Reference](https://www.chezmoi.io/reference/commands/)
- [FAQ](https://www.chezmoi.io/faq/)
## Help
```bash
# General help
chezmoi help
# Command-specific help
chezmoi help apply
chezmoi help add
# Show version
chezmoi --version
```

View File

@@ -0,0 +1,462 @@
# Host-Specific Configuration Migration
Guide for migrating host-specific configurations from dotbot to chezmoi.
## Current Dotbot Structure
You currently have host-specific configurations in:
```
hosts/
├── air/
│ ├── base/
│ ├── config/
│ └── install.conf.yaml
├── lakka/
│ ├── base/
│ ├── config/
│ └── install.conf.yaml
├── tunkki/
│ └── install.conf.yaml
└── s/
└── install.conf.yaml
```
## Chezmoi Approaches
There are three main approaches to handle host-specific configurations in chezmoi:
### 1. Template Conditionals (Recommended)
Use if/else conditions in template files.
**Pros:**
- Single source file for all hosts
- Easy to see all variations
- Less file duplication
**Cons:**
- Files can get complex with many hosts
- Need `.tmpl` extension
**Example:**
Create `dot_bashrc.tmpl`:
```bash
# Common configuration for all hosts
export PATH="$HOME/.local/bin:$PATH"
{{ if eq .chezmoi.hostname "air" }}
# air-specific
export WORK_DIR="$HOME/Work"
alias air-specific="echo air"
{{ end }}
{{ if eq .chezmoi.hostname "lakka" }}
# lakka-specific
export WORK_DIR="$HOME/Projects"
alias lakka-specific="echo lakka"
{{ end }}
# More common configuration
```
### 2. Separate Files with .chezmoiignore (Simple)
Keep separate files per host and ignore the ones that don't apply.
**Pros:**
- Clean separation
- No template syntax needed
- Easy to maintain
**Cons:**
- More files to manage
- Some duplication
**Example:**
Create multiple version files:
```
dot_bashrc__air
dot_bashrc__lakka
dot_bashrc__tunkki
```
These automatically apply based on hostname. No `.chezmoiignore` needed!
Or use directories:
```
dot_config/
├── app/
│ ├── config.yaml__air
│ ├── config.yaml__lakka
│ └── config.yaml__default
```
### 3. Hybrid Approach (Most Flexible)
Combine both methods:
- Use templates for files with minor differences
- Use separate files for completely different configs
## Migration Steps for Your Hosts
### Step 1: Analyze Each Host
Review what's different per host:
```bash
# See what's in each host directory
ls -la hosts/air/
ls -la hosts/lakka/
ls -la hosts/tunkki/
ls -la hosts/s/
# Compare configs
diff hosts/air/config/some-app/config hosts/lakka/config/some-app/config
```
### Step 2: Choose Strategy Per File
For each file that differs:
**Small differences** (few lines):
→ Use templates with conditionals
**Complete replacement**:
→ Use `filename__hostname` suffix
**Shared base + host additions**:
→ Use templates with includes or blocks
### Step 3: Migrate Host Configurations
#### Example: Fish Configuration
Your `hosts/air/config/fish/config.fish` differences:
**Current dotbot way:**
```yaml
# hosts/air/install.conf.yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**New chezmoi way - Option A (Templates):**
Create `dot_config/fish/config.fish.tmpl`:
```fish
# Common fish configuration
set -gx EDITOR nvim
{{ if eq .chezmoi.hostname "air" }}
# air-specific config
set -gx WORK_DIR ~/Work
{{ else if eq .chezmoi.hostname "lakka" }}
# lakka-specific config
set -gx WORK_DIR ~/Projects
{{ end }}
# More common configuration
```
**New chezmoi way - Option B (Separate files):**
Create multiple files:
```
dot_config/fish/config.fish__air
dot_config/fish/config.fish__lakka
```
Chezmoi will automatically use the correct file based on hostname.
### Step 4: Update .chezmoi.yaml.tmpl
Add host flags for easier conditionals:
```yaml
{{- $hostname := .chezmoi.hostname -}}
data:
hostname: {{ $hostname | quote }}
# Host-specific flags
is_air: {{ eq $hostname "air" }}
is_lakka: {{ eq $hostname "lakka" }}
is_tunkki: {{ eq $hostname "tunkki" }}
is_s: {{ eq $hostname "s" }}
# Group flags
is_work: {{ or (eq $hostname "air") (eq $hostname "tunkki") }}
is_personal: {{ or (eq $hostname "lakka") (eq $hostname "s") }}
```
Then use simpler conditionals:
```go
{{ if .is_air }}
# air config
{{ end }}
{{ if .is_work }}
# All work machines
{{ end }}
```
## Specific Migration Examples
### Example 1: Simple Host-Specific Line
**Before (dotbot):**
```yaml
# hosts/air/config/app/config
setting=value_for_air
# hosts/lakka/config/app/config
setting=value_for_lakka
```
**After (chezmoi) - Option A:**
```
# dot_config/app/config.tmpl
{{ if .is_air -}}
setting=value_for_air
{{- else if .is_lakka -}}
setting=value_for_lakka
{{- end }}
```
**After (chezmoi) - Option B:**
```
# dot_config/app/config__air
setting=value_for_air
# dot_config/app/config__lakka
setting=value_for_lakka
```
### Example 2: Mostly Shared with Few Differences
**Before:**
100 lines shared, 5 lines different per host
**After (recommended - templates):**
```bash
# dot_config/app/config.tmpl
# ... 50 lines of shared config ...
{{ if .is_air }}
air_specific_setting=true
{{ else if .is_lakka }}
lakka_specific_setting=true
{{ end }}
# ... 50 more lines of shared config ...
```
### Example 3: Completely Different Configs
**Before:**
Two totally different config files
**After (recommended - separate files):**
```
dot_config/app/config__air
dot_config/app/config__lakka
```
### Example 4: Host-Specific Directories
**Before:**
```
hosts/air/config/air-only-app/
hosts/lakka/config/lakka-only-app/
```
**After - Use .chezmoiignore:**
```
# .chezmoiignore
{{ if ne .chezmoi.hostname "air" }}
dot_config/air-only-app/
{{ end }}
{{ if ne .chezmoi.hostname "lakka" }}
dot_config/lakka-only-app/
{{ end }}
```
Then create:
```
dot_config/air-only-app/ # Only applied on air
dot_config/lakka-only-app/ # Only applied on lakka
```
## Testing Host-Specific Configs
### Before Applying
```bash
# See what would be applied on this host
chezmoi diff
# See what a specific file would look like
chezmoi cat ~/.config/fish/config.fish
# Check template data
chezmoi data | grep hostname
```
### Simulating Other Hosts
```bash
# Test what would be applied on another host
chezmoi execute-template --init --promptString hostname=air "{{ .chezmoi.hostname }}"
# See what a file would look like on another host
# (This requires manual variable setting in templates)
```
### On Another Machine
```bash
# Initialize and test without applying
chezmoi init --dry-run --verbose ivuorinen
# Apply with dry-run
chezmoi apply --dry-run -v
```
## Migration Script Adjustments
Add to `migrate-to-chezmoi.sh`:
```bash
# Migrate host-specific configs
log_info "Processing host-specific configurations..."
CURRENT_HOST=$(hostname -s)
log_info "Current hostname: $CURRENT_HOST"
# Prompt for migration strategy
echo ""
log_warning "How do you want to handle host-specific configs?"
echo " 1) Merge into templates (recommended for small differences)"
echo " 2) Keep separate files per host (recommended for large differences)"
echo " 3) Manual (skip automatic migration)"
read -p "Choose (1/2/3): " -r STRATEGY
if [ "$STRATEGY" = "1" ]; then
log_info "Will merge into templates (requires manual editing after)"
# Create template files
# ... migration logic ...
elif [ "$STRATEGY" = "2" ]; then
log_info "Creating separate host-specific files..."
for host in air lakka tunkki s; do
if [ -d "hosts/$host" ]; then
log_info "Processing host: $host"
# Process host-specific base files
if [ -d "hosts/$host/base" ]; then
for file in hosts/$host/base/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
move_dotfiles "$file" "dot_${filename}__${host}" ""
fi
done
fi
# Process host-specific config files
if [ -d "hosts/$host/config" ]; then
for file in hosts/$host/config/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
dest="dot_config/$(dirname $file)__${host}"
move_dotfiles "$file" "$dest/$(basename $file)" ""
fi
done
fi
fi
done
else
log_info "Skipping automatic host-specific migration"
log_info "You'll need to manually migrate hosts/ directory"
fi
```
## Best Practices
1. **Start Simple**: Use separate files first, move to templates as you see patterns
2. **Don't Over-Template**: If a file is completely different per host, use separate files
3. **Document Hosts**: Add comments in `.chezmoi.yaml.tmpl` explaining each host
4. **Test Thoroughly**: Test on each host before committing
5. **Use Host Groups**: Group hosts (work/personal, laptop/desktop) for easier conditionals
## Checklist
- [ ] Identify all host-specific files
- [ ] Choose strategy per file (templates vs separate)
- [ ] Update `.chezmoi.yaml.tmpl` with host flags
- [ ] Migrate host-specific base files
- [ ] Migrate host-specific config files
- [ ] Update `.chezmoiignore` for host-specific directories
- [ ] Test on current host
- [ ] Test on other hosts
- [ ] Document which approach was used where
- [ ] Clean up old hosts/ directory
## Examples from Your Hosts
Based on your current structure:
### hosts/air/install.conf.yaml
```yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**Migration approach:**
- Check what's in `hosts/air/config/`
- If it's app configs, use separate files: `dot_config/app/config__air`
- If it's just a few lines different, merge into templates
### Common Pattern
For configurations that need host-specific values but share structure:
```yaml
# dot_config/app/config.tmpl
# Common settings
port=8080
# Host-specific
{{ if .is_air -}}
workspace=/Users/yourname/Work
{{- else if .is_lakka -}}
workspace=/Users/yourname/Projects
{{- end }}
# More common settings
debug=false
```
## Need Help?
If you're unsure about a specific file:
1. Check the diff: `diff hosts/air/file hosts/lakka/file`
2. Count different lines
3. If < 20% different use templates
4. If > 20% different → use separate files
Remember: You can always refactor later!

View File

@@ -0,0 +1,523 @@
# Migration Guide: Dotbot to Chezmoi
This guide documents the migration from dotbot to chezmoi for managing dotfiles.
## Table of Contents
1. [Why Migrate to Chezmoi?](#why-migrate-to-chezmoi)
2. [Key Differences](#key-differences)
3. [Dotbot to Chezmoi Mapping](#dotbot-to-chezmoi-mapping)
4. [New File Structure](#new-file-structure)
5. [Migration Steps](#migration-steps)
6. [Usage Guide](#usage-guide)
7. [Troubleshooting](#troubleshooting)
## Why Migrate to Chezmoi?
Chezmoi offers several advantages over dotbot:
- **Built-in templating**: Use Go templates for dynamic configuration
- **Secret management**: Native support for password managers (1Password, LastPass, etc.)
- **Cross-platform**: Better support for managing dotfiles across different OS and machines
- **State tracking**: Chezmoi tracks what it manages more precisely
- **Active development**: Regular updates and large community
- **No dependencies**: Single binary, no Python required
## Key Differences
### Philosophy
**Dotbot**:
- Configuration-driven (YAML files)
- Manages symlinks from a source directory
- Plugins extend functionality
**Chezmoi**:
- Source-state driven
- Copies files to home directory (can also use symlinks)
- Built-in templating for dynamic content
- Manages the entire lifecycle of dotfiles
### Directory Structure
**Dotbot**:
```
~/.dotfiles/
├── base/ # Files symlinked to ~/.*
├── config/ # Files symlinked to ~/.config/
├── local/ # Scripts and local files
├── install # Installation script
└── install.conf.yaml # Configuration
```
**Chezmoi**:
```
~/.local/share/chezmoi/ # Source directory
├── .chezmoi.yaml.tmpl # Configuration template
├── .chezmoiignore # Files to ignore
├── run_once_*.sh.tmpl # One-time setup scripts
├── run_*.sh.tmpl # Scripts that run on every apply
├── dot_bashrc # Becomes ~/.bashrc
├── dot_config/ # Becomes ~/.config/
└── private_dot_ssh/ # Becomes ~/.ssh/ with 0700
```
## Dotbot to Chezmoi Mapping
### 1. Link Directives
**Dotbot** (install.conf.yaml):
```yaml
- link:
~/.bashrc: base/bashrc
~/.config/fish: config/fish
```
**Chezmoi**:
- Files are automatically managed based on their names in the source directory
- `dot_bashrc``~/.bashrc`
- `dot_config/fish/``~/.config/fish/`
- Use `symlink_` prefix for symlinks: `symlink_dot_vim` → symlinked `~/.vim`
### 2. Create Directives
**Dotbot**:
```yaml
- create:
~/.ssh:
mode: 0700
~/.local/bin:
```
**Chezmoi**:
- Create a `run_once_after_create-directories.sh.tmpl` script
- Or use `.chezmoitemplates` for reusable directory creation
- Chezmoi automatically creates parent directories
### 3. Shell Commands
**Dotbot**:
```yaml
- shell:
- git submodule update --init --recursive
- bash local/bin/dfm install all
```
**Chezmoi**:
- Use `run_once_*.sh.tmpl` for one-time setup scripts
- Use `run_*.sh.tmpl` for scripts that run every time
- Use `run_before_*.sh` for scripts that run before applying
- Use `run_after_*.sh` for scripts that run after applying
### 4. Clean Directives
**Dotbot**:
```yaml
- clean:
~/:
~/.config:
recursive: true
```
**Chezmoi**:
- Chezmoi doesn't automatically remove files
- Use `chezmoi unmanaged` to see unmanaged files
- Manually remove or add to `.chezmoiignore`
### 5. Host-Specific Configuration
**Dotbot**:
```yaml
# hosts/air/install.conf.yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**Chezmoi**:
- Use templates with conditionals:
```
{{ if eq .chezmoi.hostname "air" }}
# air-specific content
{{ end }}
```
- Or use separate files: `dot_config/file.tmpl` with hostname checks
### 6. Dotbot Plugins
**dotbot-brew**:
- Replace with `run_once_after_install-packages.sh.tmpl`
- Use `brew bundle install`
**dotbot-asdf**:
- Chezmoi doesn't have built-in asdf support
- Use `run_once_after_*.sh` scripts to install asdf plugins
**dotbot-pip/pipx**:
- Use `run_once_after_*.sh` scripts
- Or use chezmoi's external management
## New File Structure
### Configuration Files
#### `.chezmoi.yaml.tmpl`
Main configuration file with template support. Defines:
- Source directory
- Data variables (hostname, OS, custom flags)
- Merge strategy
- Template options
- Git options
#### `.chezmoiignore`
Files and patterns to ignore when applying dotfiles. Includes:
- Repository management files (.git, .github, etc.)
- Documentation
- Development tools
- Old dotbot configuration
### Run Scripts
Scripts follow a naming convention:
- `run_once_before_*.sh.tmpl`: Runs once before applying (prerequisites)
- `run_once_after_*.sh.tmpl`: Runs once after applying (installation)
- `run_before_*.sh.tmpl`: Runs every time before applying
- `run_after_*.sh.tmpl`: Runs every time after applying
- `run_onchange_*.sh.tmpl`: Runs when file content changes
### File Naming
Chezmoi uses special prefixes:
- `dot_`: Becomes a dot file (`.`)
- `private_`: Sets permissions to 0600
- `executable_`: Makes file executable
- `symlink_`: Creates a symlink
- `readonly_`: Makes file read-only
Examples:
- `dot_bashrc``~/.bashrc`
- `private_dot_ssh/``~/.ssh/` (mode 0700)
- `executable_dot_local/bin/script``~/.local/bin/script` (executable)
## Migration Steps
### 1. Backup Current Setup
```bash
# Backup your current dotfiles
cd ~/.dotfiles
git add -A
git commit -m "Backup before chezmoi migration"
git push
```
### 2. Install Chezmoi
```bash
# The new install script will do this automatically
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
```
### 3. Initialize Chezmoi with Existing Dotfiles
```bash
# If you want to test before full migration
chezmoi init --apply ivuorinen
# Or initialize without applying
chezmoi init ivuorinen
```
### 4. Restructure Files (Manual Step)
You'll need to rename files to follow chezmoi conventions:
```bash
cd ~/.local/share/chezmoi
# Rename base files
mv base/bashrc dot_bashrc
mv base/zshrc dot_zshrc
mv base/tmux.conf dot_tmux.conf
# Move config files
mkdir -p dot_config
mv config/* dot_config/
# Move local/bin files
mkdir -p dot_local/bin
for file in local/bin/*; do
mv "$file" "executable_dot_local/bin/$(basename "$file")"
done
# Move SSH files with proper permissions
mkdir -p private_dot_ssh
mv ssh/* private_dot_ssh/
```
### 5. Convert Host-Specific Configurations
For files that differ between hosts, use templates:
```bash
# Instead of hosts/air/config/fish/config.fish
# Create: dot_config/fish/config.fish.tmpl
{{ if eq .chezmoi.hostname "air" }}
# air-specific configuration
{{ else if eq .chezmoi.hostname "lakka" }}
# lakka-specific configuration
{{ end }}
```
### 6. Test the Migration
```bash
# See what changes chezmoi would make
chezmoi diff
# Apply changes
chezmoi apply
# Verify everything works
chezmoi verify
```
### 7. Clean Up Old Files
```bash
# Remove dotbot directories (after confirming everything works)
cd ~/.local/share/chezmoi
rm -rf tools/dotbot tools/dotbot-*
rm install.conf.yaml
rm -rf hosts/ # If fully migrated to templates
```
## Usage Guide
### Basic Commands
```bash
# Initialize chezmoi with your dotfiles
chezmoi init ivuorinen
# See what changes would be made
chezmoi diff
# Apply dotfiles
chezmoi apply
# Apply with verbose output
chezmoi apply -v
# Edit a file managed by chezmoi
chezmoi edit ~/.bashrc
# Add a new file to chezmoi
chezmoi add ~/.newfile
# Update dotfiles from source
chezmoi update
# See what files are managed
chezmoi managed
# See what files are unmanaged
chezmoi unmanaged
# Re-run scripts
chezmoi apply --force
# Check for issues
chezmoi doctor
```
### Working with Templates
```bash
# Execute a template
chezmoi execute-template "{{ .chezmoi.hostname }}"
# See the data available in templates
chezmoi data
# Edit template data
chezmoi edit-config
```
### Managing Secrets
```bash
# Use with 1Password
chezmoi secret keychain
# Template with 1Password
{{ (index (onepasswordDocument "my-secret") 0).content }}
# Use with environment variables
{{ .Env.MY_SECRET }}
```
### Updating Dotfiles
```bash
# Edit source file
chezmoi edit ~/.bashrc
# Or edit directly and add
vi ~/.bashrc
chezmoi add ~/.bashrc
# Commit changes
cd $(chezmoi source-path)
git add -A
git commit -m "Update bashrc"
git push
# On another machine
chezmoi update
```
## Troubleshooting
### Common Issues
#### 1. File Permissions
**Problem**: Files have wrong permissions after applying.
**Solution**: Use prefixes:
```bash
# For 0600 permissions
chezmoi add --template private_dot_ssh/config
# For 0700 directories
mkdir -p private_dot_ssh
```
#### 2. Symlinks Not Working
**Problem**: Chezmoi copies files instead of symlinking.
**Solution**: Use `symlink_` prefix:
```bash
chezmoi add --symlink ~/.vim
# This creates symlink_dot_vim in the source directory
```
#### 3. Templates Not Rendering
**Problem**: Template syntax is showing literally in files.
**Solution**:
- Ensure file has `.tmpl` extension
- Check template syntax
- Verify data with `chezmoi data`
#### 4. Scripts Not Running
**Problem**: `run_once_` scripts not executing.
**Solution**:
- Check script permissions: `chmod +x run_once_*.sh.tmpl`
- Run with force: `chezmoi apply --force`
- Check script order (before/after)
#### 5. Host-Specific Files Not Applying
**Problem**: Wrong host configuration applied.
**Solution**:
- Check hostname: `chezmoi data | grep hostname`
- Verify template conditionals
- Use `.chezmoiignore` for host-specific exclusions
### Debugging
```bash
# Verbose output
chezmoi apply -v
# Very verbose output
chezmoi apply -vv
# Dry run to see what would happen
chezmoi apply --dry-run -v
# Check configuration
chezmoi doctor
# Verify state
chezmoi verify
# See source directory
chezmoi source-path
# See what would be applied to a specific file
chezmoi cat ~/.bashrc
```
### Migration Checklist
- [ ] Backup current dotfiles
- [ ] Install chezmoi
- [ ] Create `.chezmoi.yaml.tmpl`
- [ ] Create `.chezmoiignore`
- [ ] Rename files with proper prefixes
- [ ] Convert host-specific configs to templates
- [ ] Create `run_once_before` scripts
- [ ] Create `run_once_after` scripts
- [ ] Test with `chezmoi diff`
- [ ] Apply with `chezmoi apply`
- [ ] Verify everything works
- [ ] Update documentation
- [ ] Clean up old dotbot files
- [ ] Update README.md
- [ ] Test on another machine
## Additional Resources
- [Chezmoi Documentation](https://www.chezmoi.io/)
- [Chezmoi Quick Start](https://www.chezmoi.io/quick-start/)
- [Chezmoi User Guide](https://www.chezmoi.io/user-guide/)
- [Chezmoi Template Reference](https://www.chezmoi.io/reference/templates/)
- [Example Dotfiles Using Chezmoi](https://github.com/topics/chezmoi)
## Notes
### What Stays the Same
- Your actual dotfile contents
- Directory structure in home directory
- Git workflow for managing dotfiles
- The `dfm` script functionality (wrapped in run_once scripts)
### What Changes
- Installation method (new `install` script)
- Source directory location (`~/.local/share/chezmoi` by default)
- Configuration method (templates instead of YAML)
- File naming (special prefixes)
- No more symlinks by default (unless specified)
### Benefits of Migration
1. **Simplicity**: Single binary, no dependencies
2. **Templating**: Dynamic content based on hostname, OS, etc.
3. **Secrets**: Built-in support for password managers
4. **State Management**: Better tracking of what's managed
5. **Cross-platform**: Excellent support for different OSes
6. **Documentation**: Extensive docs and examples
7. **Community**: Active development and support
## Post-Migration
After successful migration:
1. Update your README to reflect chezmoi usage
2. Archive dotbot configuration for reference
3. Document any custom scripts or workflows
4. Test on all your machines
5. Share your experience!

View File

@@ -33,7 +33,7 @@ Leader: `<ctrl><space>`
? List key bindings
D Choose and detach a client from a list
E Spread panes out evenly
L last-session (via sesh)
L last-session (via sesh)
M Clear the marked pane
N sesh ui
T tms
@@ -87,3 +87,4 @@ Leader: `<ctrl><space>`
S-Left Move the visible part of the window left
S-Right Move the visible part of the window right
```

37
install
View File

@@ -1,38 +1,5 @@
#!/usr/bin/env bash
set -e
CONFIG="install.conf.yaml"
DOTBOT_DIR="tools/dotbot"
DOTBOT_BIN="bin/dotbot"
BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOTBOT_BIN_PATH="${BASEDIR}/${DOTBOT_DIR}/${DOTBOT_BIN}"
DOTBOT_HOST="$(hostname -s)"
cd "${BASEDIR}"
git -C "${DOTBOT_DIR}" submodule sync --quiet --recursive
git submodule update --init --recursive "${DOTBOT_DIR}"
"${DOTBOT_BIN_PATH}" \
-d "${BASEDIR}" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "${CONFIG}" \
"${@}"
if [ "${DOTBOT_HOST}" != "" ]; then
DOTBOT_HOST_CONFIG="${BASEDIR}/hosts/${DOTBOT_HOST}/${CONFIG}"
echo "-> Trying if host config can be found: ${DOTBOT_HOST_CONFIG}"
[ -r "$DOTBOT_HOST_CONFIG" ] && [ -f "$DOTBOT_HOST_CONFIG" ] &&
echo "(!) Found $DOTBOT_HOST_CONFIG" &&
"$DOTBOT_BIN_PATH" \
-d "$BASEDIR" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "$DOTBOT_HOST_CONFIG" \
"${@}"
fi
# Install and apply chezmoi
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen

View File

@@ -103,9 +103,9 @@ fetch_keys_if_missing()
if [[ ! -f "$KEYS_FILE" ]]; then
log_message "Keys file '$KEYS_FILE' not found. Attempting to fetch from $KEYS_SOURCE..."
mkdir -p "$(dirname "$KEYS_FILE")"
curl -s "$KEYS_SOURCE" -o "$KEYS_FILE"
if ! curl -s "$KEYS_SOURCE" -o "$KEYS_FILE" || [[ ! -s "$KEYS_FILE" ]]; then
rm -f "$KEYS_FILE" 2> /dev/null || true
if [[ $? -ne 0 || ! -s "$KEYS_FILE" ]]; then
log_message "Error: Failed to fetch keys from $KEYS_SOURCE"
exit 1
fi
@@ -126,12 +126,10 @@ encrypt_file_or_directory()
elif [[ -f "$file" ]]; then
fetch_keys_if_missing
local output_file="${file}.age"
local temp_file
temp_file="$(mktemp -p "$(dirname "$file")")"
if age -R "$KEYS_FILE" "$file" > "$temp_file" && mv "$temp_file" "$output_file"; then
age -R "$KEYS_FILE" "$file" > "$output_file"
if [[ $? -eq 0 ]]; then
log_message "File encrypted successfully: $output_file"
else
rm -f "$temp_file"
log_message "Error: Failed to encrypt file '$file'."
exit 1
fi
@@ -149,12 +147,10 @@ decrypt_file_or_directory()
elif [[ -f "$file" ]]; then
fetch_keys_if_missing
local output_file="${file%.age}"
local temp_file
temp_file="$(mktemp -p "$(dirname "$file")")"
if age -d -i "$KEYS_FILE" "$file" > "$temp_file" && mv "$temp_file" "$output_file"; then
age -d -i "$KEYS_FILE" "$file" > "$output_file"
if [[ $? -eq 0 ]]; then
log_message "File decrypted successfully: $output_file"
else
rm -f "$temp_file"
log_message "Error: Failed to decrypt file '$file'."
exit 1
fi

View File

@@ -36,8 +36,9 @@ if [[ ! -f "$KEYS_FILE" ]]; then
mkdir -p "$(dirname "$KEYS_FILE")"
# Fetch the keys and save to the file
if ! curl -s "$KEYS_SOURCE" -o "$KEYS_FILE" || [[ ! -s "$KEYS_FILE" ]]; then
rm -f "$KEYS_FILE" 2> /dev/null || true
curl -s "$KEYS_SOURCE" -o "$KEYS_FILE"
if [[ $? -ne 0 || ! -s "$KEYS_FILE" ]]; then
echo "Error: Failed to fetch keys from $KEYS_SOURCE"
exit 1
fi
@@ -49,11 +50,11 @@ fi
# Decrypt the file
OUTPUT_FILE="${FILE%.age}"
TEMP_FILE="$(mktemp -p "$(dirname "$OUTPUT_FILE")")"
if age -d -i "$KEYS_FILE" "$FILE" > "$TEMP_FILE" && mv "$TEMP_FILE" "$OUTPUT_FILE"; then
age -d -i "$KEYS_FILE" "$FILE" > "$OUTPUT_FILE"
if [[ $? -eq 0 ]]; then
echo "File decrypted successfully: $OUTPUT_FILE"
else
rm -f "$TEMP_FILE"
echo "Error: Failed to decrypt file."
exit 1
fi

View File

@@ -37,7 +37,9 @@ if [[ ! -f "$KEYS_FILE" ]]; then
mkdir -p "$(dirname "$KEYS_FILE")"
# Fetch the keys and save to the file
if ! curl -s "$KEYS_SOURCE" -o "$KEYS_FILE" || [[ ! -s "$KEYS_FILE" ]]; then
curl -s "$KEYS_SOURCE" -o "$KEYS_FILE"
if [[ $? -ne 0 || ! -s "$KEYS_FILE" ]]; then
echo "Error: Failed to fetch keys from $KEYS_SOURCE"
exit 1
fi
@@ -49,7 +51,9 @@ fi
# Encrypt the file
OUTPUT_FILE="${FILE}.age"
if age -R "$KEYS_FILE" "$FILE" > "$OUTPUT_FILE"; then
age -R "$KEYS_FILE" "$FILE" > "$OUTPUT_FILE"
if [[ $? -eq 0 ]]; then
echo "File encrypted successfully: $OUTPUT_FILE"
else
echo "Error: Failed to encrypt file."

View File

@@ -25,7 +25,6 @@ source_file()
case "$CURRENT_SHELL" in
fish)
if [[ -f "$file.fish" ]]; then
# shellcheck disable=SC1090
source "$file.fish"
else
echo "Fish shell file not found: $file.fish"
@@ -33,7 +32,6 @@ source_file()
fi
;;
sh | bash | zsh)
# shellcheck disable=SC1090
source "$file"
;;
*)

View File

@@ -142,7 +142,7 @@ if [[ ! "$opt" =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
zoomed_without_popup=1
original_window=$(tmux display-message -p "#{window_id}")
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
tmux swap-pane -t "$tmp_window" \; select-window -t "$tmp_window"
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
fi
set -e
@@ -154,16 +154,15 @@ fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
if tmux_win_opts=$(tmux show-options -p remain-on-exit \; show-options -p synchronize-panes 2> /dev/null); then
mapfile -t tmux_win_opts < <(sed '/ off/d; s/synchronize-panes/set-option -p synchronize-panes/; s/remain-on-exit/set-option -p remain-on-exit/; s/$/ \\;/' <<< "$tmux_win_opts")
tmux_win_opts=($(sed '/ off/d; s/synchronize-panes/set-option -p synchronize-panes/; s/remain-on-exit/set-option -p remain-on-exit/; s/$/ \\;/' <<< "$tmux_win_opts"))
tmux_off_opts='; set-option -p synchronize-panes off ; set-option -p remain-on-exit off'
else
mapfile -t tmux_win_opts < <(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/')
tmux_win_opts=($(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/'))
tmux_off_opts='; set-window-option synchronize-panes off ; set-window-option remain-on-exit off'
fi
# shellcheck disable=SC2329
cleanup()
{
\rm -f "$argsf" "$fifo1" "$fifo2" "$fifo3"
\rm -f $argsf $fifo1 $fifo2 $fifo3
# Restore tmux window options
if [[ "${#tmux_win_opts[@]}" -gt 0 ]]; then
@@ -173,9 +172,9 @@ cleanup()
# Remove temp window if we were zoomed without popup options
if [[ -n "$zoomed_without_popup" ]]; then
tmux display-message -p "#{window_id}" > /dev/null
tmux swap-pane -t "$original_window" \; \
select-window -t "$original_window" \; \
kill-window -t "$tmp_window" \; \
tmux swap-pane -t $original_window \; \
select-window -t $original_window \; \
kill-window -t $tmp_window \; \
resize-pane -Z
fi
@@ -210,40 +209,39 @@ echo "$envs;" > "$argsf"
opts=$(printf "%q " "${args[@]}")
pppid=$$
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" >> "$argsf"
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" >> $argsf
close="; trap - EXIT SIGINT SIGTERM $close"
export TMUX
TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
mkfifo -m o+w "$fifo2"
export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
mkfifo -m o+w $fifo2
if [[ "$opt" =~ "-E" ]]; then
cat "$fifo2" &
cat $fifo2 &
if [[ -n "$term" ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> "$argsf"
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
else
mkfifo "$fifo1"
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; out=\$? $close; exit \$out" >> "$argsf"
cat <&0 > "$fifo1" &
mkfifo $fifo1
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; out=\$? $close; exit \$out" >> $argsf
cat <&0 > $fifo1 &
fi
tmux popup -d "$PWD" "$opt" "bash $argsf" > /dev/null 2>&1
tmux popup -d "$PWD" $opt "bash $argsf" > /dev/null 2>&1
exit $?
fi
mkfifo -m o+w "$fifo3"
mkfifo -m o+w $fifo3
if [[ -n "$term" ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> "$argsf"
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
else
mkfifo "$fifo1"
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> "$argsf"
cat <&0 > "$fifo1" &
mkfifo $fifo1
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> $argsf
cat <&0 > $fifo1 &
fi
tmux \
split-window -c "$PWD" "$opt" "bash -c 'exec -a fzf bash $argsf'" "$swap" \
"$tmux_off_opts" \
split-window -c "$PWD" $opt "bash -c 'exec -a fzf bash $argsf'" $swap \
$tmux_off_opts \
> /dev/null 2>&1 || {
"$fzf" "${args[@]}"
exit $?
}
cat "$fifo2"
exit "$(cat "$fifo3")"
cat $fifo2
exit "$(cat $fifo3)"

View File

@@ -25,27 +25,27 @@ fi
# Output functions
msg_err()
{
echo -e "\e[31m$*\e[0m" >&2
echo -e "\e[31m$@\e[0m" >&2
}
msg_success()
{
echo -e "\e[32m$*\e[0m"
echo -e "\e[32m$@\e[0m"
}
msg_warn()
{
echo -e "\e[33m$*\e[0m" >&2
echo -e "\e[33m$@\e[0m" >&2
}
msg_info()
{
echo -e "\e[36m$*\e[0m"
echo -e "\e[36m$@\e[0m"
}
msg_debug()
{
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$*\e[0m"
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$@\e[0m"
}
show_help()
@@ -180,8 +180,7 @@ format_rule()
get_file_extension()
{
local file="$1"
local basename
basename=$(basename "$file")
local basename=$(basename "$file")
local extension=""
# Check if file has no extension or is a dotfile
@@ -232,8 +231,8 @@ suggest_rule()
# If file path contains .d/ pattern, we need special handling
if [[ "$file" =~ \.d/ ]]; then
# Extract the pattern part that includes the .d/ directory
local dir_part
dir_part=$(dirname "$file")
local dir_part=$(dirname "$file")
local base_name=$(basename "$file")
# Check if it's a config directory pattern worth capturing
if [[ "$dir_part" =~ /(\.d|[^/]+\.d)$ ]]; then
@@ -431,8 +430,7 @@ detect_shell_scripts()
fi
# Skip if file extension already covered
local extension
extension=$(get_file_extension "$rel_path")
local extension=$(get_file_extension "$rel_path")
if [[ "$extension" != "$rel_path" ]] && grep -q "^\*\.$extension " <<< "$existing_rules"; then
msg_debug "Script covered by extension rule: $rel_path (*.$extension)"
continue
@@ -460,8 +458,7 @@ detect_shell_scripts()
fi
# Group by directory
local dir
dir=$(dirname "$rel_path")
local dir=$(dirname "$rel_path")
if [[ "$dir" == "." ]]; then
dir="root"
fi
@@ -483,8 +480,7 @@ detect_shell_scripts()
# Check if we can use directory-based rules instead of individual files
for dir in "${!scripts_by_dir[@]}"; do
local files_in_dir
files_in_dir=$(echo -e "${scripts_by_dir[$dir]}" | wc -l)
local files_in_dir=$(echo -e "${scripts_by_dir[$dir]}" | wc -l)
local dir_path="$dir"
if [[ "$dir" == "root" ]]; then
@@ -579,8 +575,7 @@ suggest_gitattributes()
declare -A seen_patterns=()
while IFS= read -r file; do
local suggestion
suggestion=$(suggest_rule "$file")
local suggestion=$(suggest_rule "$file")
if [[ -n "$suggestion" ]]; then
IFS=':' read -r pattern attributes <<< "$suggestion"
@@ -644,8 +639,7 @@ suggest_gitattributes()
formatted_suggestions+="$pattern\n"
echo "$pattern"
else
local formatted_rule
formatted_rule=$(printf "%-${format_width}s %s\n" "$pattern" "$attributes")
local formatted_rule=$(printf "%-${format_width}s %s\n" "$pattern" "$attributes")
formatted_suggestions+="$formatted_rule\n"
echo "$formatted_rule"
fi

1
local/bin/iterm2_shell_integration.zsh Normal file → Executable file
View File

@@ -1,4 +1,3 @@
# shellcheck disable=all
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2

View File

@@ -142,7 +142,7 @@ if [ ! -x "${CURL}" ]; then
exit 1
fi
devices="$(printf "%s" "${devices}" | xargs -n1 | sort -u)"
devices="$(printf "${devices}" | xargs -n1 | sort -u | uniq)\n"
if [ -z "${devices}" ]; then
__pushover_send_message

View File

@@ -126,11 +126,11 @@ if [[ -f "$CONFIG_FILE" ]]; then
PROTECTED_KEYS+=("$key")
done <<< "$CUSTOM_KEYS"
mapfile -t SKIPPED < <(yq '.skipped_keys[]' "$CONFIG_FILE")
for key in "${SKIPPED[@]}"; do
SKIPPED+=("$(yq '.skipped_keys[]' "$CONFIG_FILE")")
while IFS= read -r key; do
# Add to default_skipped_keys
SKIPPED_KEYS+=("$key")
done
done <<< "$SKIPPED"
CUSTOM_GROUPS=$(yq '.custom_grouping[]' "$CONFIG_FILE")
while IFS= read -r group; do
@@ -159,7 +159,6 @@ is_protected()
return 0
fi
# Wildcard match (protected_key contains '*')
# shellcheck disable=SC2053 # Intentional glob matching - protected_key contains wildcard patterns
if [[ "$protected_key" == *"*"* ]] && [[ "$key" == $protected_key ]]; then
return 0
fi
@@ -199,7 +198,6 @@ is_skipped()
return 0
fi
# Wildcard match (skipped_key contains '*')
# shellcheck disable=SC2053 # Intentional glob matching - skipped_key contains wildcard patterns
if [[ "$skipped_key" == *"*"* ]] && [[ "$key" == $skipped_key ]]; then
return 0
fi
@@ -246,15 +244,8 @@ while IFS='=' read -r key value; do
value="[protected value]"
fi
# Update group data - check if group already exists
group_exists=false
for existing_group in "${all_groups[@]}"; do
if [[ "$existing_group" == "$group" ]]; then
group_exists=true
break
fi
done
if [[ "$group_exists" == false ]]; then
# Update group data
if [[ ! " ${all_groups[*]} " =~ " $group " ]]; then
all_groups+=("$group")
fi

View File

@@ -30,9 +30,10 @@ config_msg()
{
# if $1 is empty, return
[ -z "$1" ] && return
[ -z "$2" ] && $2=""
local msg_type="$1"
local msg_content="${2:-}"
local msg_content="$2"
[[ "$VERBOSE" -eq 1 ]] && printf 'x-load-configs: %s %s\n' "$msg_type" "$msg_content"
return 0
}
@@ -49,8 +50,7 @@ source_config()
{
local config_file=$1
if [ -f "$config_file" ]; then
# shellcheck disable=SC1090
source "$config_file"
eval "$config_file"
config_msg "Sourced" "$config_file"
else
msg "Config file $config_file not found"

View File

@@ -60,7 +60,7 @@ log_debug()
filter_coderabbit_addressed_comments()
{
local input_data="$1"
local is_wrapped="$2" # true for {comments: [...]}, false for [...]
local is_wrapped="$2" # true for {comments: [...]}, false for [...]
local jq_filter='select(
(.user.login | contains("coderabbit") | not) or
@@ -68,9 +68,9 @@ filter_coderabbit_addressed_comments()
)'
if [[ "$is_wrapped" == "true" ]]; then
echo "$input_data" | jq "{comments: [.comments[] | $jq_filter]}" 2> /dev/null || echo "$input_data"
echo "$input_data" | jq "{comments: [.comments[] | $jq_filter]}" 2>/dev/null || echo "$input_data"
else
echo "$input_data" | jq "[.[] | $jq_filter]" 2> /dev/null || echo "$input_data"
echo "$input_data" | jq "[.[] | $jq_filter]" 2>/dev/null || echo "$input_data"
fi
}
@@ -79,13 +79,13 @@ fetch_and_filter_data()
{
local endpoint="$1"
local data_name="$2"
local is_wrapped="$3" # true/false
local is_wrapped="$3" # true/false
local data
data=$(gh api "$endpoint" 2> /dev/null || echo "[]")
data=$(gh api "$endpoint" 2>/dev/null || echo "[]")
if [[ "$is_wrapped" == "true" ]]; then
data=$(echo "$data" | jq '{comments: .}' 2> /dev/null || echo '{"comments":[]}')
data=$(echo "$data" | jq '{comments: .}' 2>/dev/null || echo '{"comments":[]}')
fi
data=$(filter_coderabbit_addressed_comments "$data" "$is_wrapped")
@@ -94,12 +94,14 @@ fetch_and_filter_data()
[[ "$is_wrapped" == "true" ]] && count_field=".comments | length"
local count
count=$(echo "$data" | jq -r "$count_field" 2> /dev/null || echo "0")
count=$(echo "$data" | jq -r "$count_field" 2>/dev/null || echo "0")
log_debug "$data_name count: $count"
echo "$data"
}
# Format file-specific comments grouped by review
format_grouped_review_comments()
{
@@ -108,7 +110,7 @@ format_grouped_review_comments()
local repo="$3"
local count
count=$(echo "$review_comments" | jq -r 'length' 2> /dev/null || echo "0")
count=$(echo "$review_comments" | jq -r 'length' 2>/dev/null || echo "0")
if [[ "$count" -eq 0 ]]; then
echo "No file-specific comments found."
@@ -141,7 +143,7 @@ Review ID: \($review.id) - API: gh api /repos/'"$repo"'/pulls/1/reviews/\($revie
"] | join("")) + "
---
"
' 2> /dev/null || {
' 2>/dev/null || {
log_debug "Error grouping review comments by review ID"
echo "Error parsing grouped review comments."
}
@@ -242,7 +244,7 @@ EOF
**URL:** \(.url)
**Number:** '"$pr_number"'
**Repository:** '"$repo"'
"' 2> /dev/null || {
"' 2>/dev/null || {
echo "**Error:** Could not parse PR information"
return 1
}

Some files were not shown because too many files have changed in this diff Show More