Compare commits

Author SHA1 Message Date
Chris 7198cb031a Update files 2026-07-03 16:05:57 +01:00
Chris fbcdd3af0c Formatting 2026-07-03 13:48:02 +01:00
chris 12b0d3d8b8 Remove blade-nav 2026-06-18 21:50:07 +01:00
Chris 9c6d49cd5d Always render markdown 2026-06-17 07:48:33 +01:00
chris fff9a0e70e Update files 2026-06-16 22:03:42 +01:00
Chris ecbc266165 Cheatsheets and debuggin 2026-06-16 16:26:28 +01:00
Chris 5dd9b59b90 Force saving 2026-05-14 16:30:06 +01:00
Chris 1768a69cf1 Blade 2026-05-06 09:30:50 +01:00
Chris 35e45b9fd5 Update files 2026-05-04 13:43:47 +01:00
chris 086682194b Refactor causing issues 2026-04-28 21:33:20 +01:00
Chris 96ddb7a611 Stuff 2026-04-21 08:00:23 +01:00
Chris bd2349c1ba Merge branch 'main' of labs.scarif.space:chris/nvim 2026-03-31 14:15:49 +01:00
Chris b4fd6c1988 Fixing treesitter 2026-03-31 14:15:12 +01:00
chris 8d1278b84a Fix pywal missing 2026-03-09 23:20:40 +00:00
chris e4a935de25 Use tokyo for fallback 2026-03-08 20:58:50 +00:00
chris d8732c5e2e Update files 2026-03-08 20:50:10 +00:00
chris ba41c9a054 Add pywal theme 2026-03-08 20:48:24 +00:00
chris 894d2fcabf Update files 2026-03-06 17:06:16 +00:00
chris 40adefb70c Update files 2026-03-06 17:05:20 +00:00
chris faea500177 Update files 2026-03-06 17:02:36 +00:00
chris 6f74961fc6 Fix treesitter 2026-03-01 20:52:19 +00:00
chris cc7139c2ff Add keymap to reload file 2026-02-22 20:02:46 +00:00
Chris bac22a5657 Comment out annoying snippets 2026-02-19 09:04:46 +00:00
chris 20d080e223 Stuff 2026-02-15 21:35:09 +00:00
chris 847c71a194 Update projects 2025-12-23 22:52:37 +00:00
Chris 78b8bf177c Merge branch 'main' of labs.scarif.space:chris/nvim 2025-12-18 09:18:41 +00:00
Chris 4f8e722f13 Snippets 2025-12-18 09:18:00 +00:00
chris 1f58b9f136 More snippets 2025-12-17 16:52:51 +00:00
Chris 4d3aada204 Remove textobjects 2025-12-10 14:26:27 +00:00
30 changed files with 1933 additions and 927 deletions
+391
View File
@@ -0,0 +1,391 @@
# Bash Cheat Sheet
## Conditionals
```bash
if [[ -z "$string" ]]; then
echo "String is empty"
elif [[ -n "$string" ]]; then
echo "String is not empty"
fi
```
### String conditions
┌────────────────────────┬──────────────────┐
`[[ -z STRING ]]` │ Empty string │
├────────────────────────┼──────────────────┤
`[[ -n STRING ]]` │ Not empty string │
├────────────────────────┼──────────────────┤
`[[ STRING == STRING ]]` │ Equal │
├────────────────────────┼──────────────────┤
`[[ STRING != STRING ]]` │ Not Equal │
├────────────────────────┼──────────────────┤
`[[ STRING =~ STRING ]]` │ Regex │
└────────────────────────┴──────────────────┘
### Number conditions
┌────────────────────────┬───────────────────────┐
`[[ NUM1 -eq NUM2 ]]` │ Equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -ne NUM2 ]]` │ Not Equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -lt NUM2 ]]` │ Less than │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -le NUM2 ]]` │ Less than or equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -gt NUM2 ]]` │ Greater than │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -ge NUM2 ]]` │ Greater than or equal │
├────────────────────────┼───────────────────────┤
`(( NUM < NUM ))` │ Numeric conditions │
└────────────────────────┴───────────────────────┘
### File conditions
┌───────────────────────┬─────────────────────────┐
`[[ -e FILE ]]` │ Exists │
├───────────────────────┼─────────────────────────┤
`[[ -r FILE ]]` │ Readable │
├───────────────────────┼─────────────────────────┤
`[[ -h FILE ]]` │ Symlink │
├───────────────────────┼─────────────────────────┤
`[[ -d FILE ]]` │ Directory │
├───────────────────────┼─────────────────────────┤
`[[ -w FILE ]]` │ Writable │
├───────────────────────┼─────────────────────────┤
`[[ -s FILE ]]` │ Size is > 0 bytes │
├───────────────────────┼─────────────────────────┤
`[[ -f FILE ]]` │ File │
├───────────────────────┼─────────────────────────┤
`[[ -x FILE ]]` │ Executable │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -nt FILE2 ]]` │ 1 is more recent than 2 │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -ot FILE2 ]]` │ 2 is more recent than 1 │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -ef FILE2 ]]` │ Same files │
└───────────────────────┴─────────────────────────┘
### Other conditions
┌────────────────────┬────────────────────┐
`[[ -o noclobber ]]` │ Option enabled │
├────────────────────┼────────────────────┤
`[[ ! EXPR ]]` │ Not │
├────────────────────┼────────────────────┤
`[[ X && Y ]]` │ And │
├────────────────────┼────────────────────┤
`[[ X || Y ]]` │ Or │
└────────────────────┴────────────────────┘
## Parameter manipulation
┌─────────────────────────────────┬────────────────────────────────────────────────────────────────┐
`${foo}` │ Variable │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo/from/to}` │ Replace first match │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo/#from/to}`/`${foo/%from/to}` │ Replace first match anchored to start (default) or end │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo//from/to}` │ Replace all │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:start:length}` │ Slice from `start` to `length` (both optional and can be negative) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo%suffix}`/`${foo%%suffix}` │ Remove `suffix` (ungreedy/greedy) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo#prefix}`/`${foo##prefix}` │ Remove `prefix` (ungreedy/greedy) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${#foo}` │ Length of `foo`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo,}` │ Lowercase first letter │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo,,}` │ Lowercase all letters │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo^}` │ Uppercase first letter │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo^^}` │ Uppercase all letters │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:-val}` │ Use `val` if `foo` is unset or null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:=val}` │ Set `foo` to `val` if unset or null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:+val}` │ Use `val` if `foo` **is** set and not null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:?message}` │ Print `message` and exit if `foo` is unset or null │
└─────────────────────────────────┴────────────────────────────────────────────────────────────────┘
> Omitting the `:` for default values will only check if the variable is set, not if it is null.
### Examples
```bash
name="John"
echo "${name}"
echo "${name/J/j}" #=> "john" (substitution)
echo "${name:0:2}" #=> "Jo" (slicing)
echo "${name::2}" #=> "Jo" (slicing)
echo "${name::-1}" #=> "Joh" (slicing)
echo "${name:(-1)}" #=> "n" (slicing from right)
echo "${name:(-2):1}" #=> "h" (slicing from right)
echo "${food:-Cake}" #=> $food or "Cake"
length=2
echo "${name:0:length}" #=> "Jo" (slicing with variable)
str="/path/to/foo.cpp"
echo "${str%.cpp}" # /path/to/foo
echo "${str%.cpp}.o" # /path/to/foo.o
echo "${str%/*}" # /path/to
echo "${str##*.}" # cpp (extension)
echo "${str##*/}" # foo.cpp (basepath)
echo "${str#*o}" # o/foo.cpp (first occurrence of 'o')
echo "${str##*o}" # oo.cpp (last occurrence of 'o')
echo "${str#*/}" # path/to/foo.cpp
echo "${str##*/}" # foo.cpp
echo "${str/foo/bar}" # /path/to/bar.cpp
str="HELLO WORLD!"
echo "${str,}" #=> "hELLO WORLD!" (lowercase 1st letter)
echo "${str,,}" #=> "hello world!" (all lowercase)
str="hello world!"
echo "${str^}" #=> "Hello world!" (uppercase 1st letter)
echo "${str^^}" #=> "HELLO WORLD!" (all uppercase)
```
## Comments
```bash
# This is a comment
: '
This is a multi-line comment workaround
'
```
## Loops
### Basic for loop
```bash
for i in /etc/rc.*; do
echo "$i"
done
```
### C-style for loop
```bash
for (( i = 0; i < 10; i++ )); do
echo "$i"
done
```
### Ranges
```bash
for i in {1..10}; do
echo "$i"
done
# With step size
for i in {1..10..2}; do
echo "$i"
done
```
### Reading lines
```bash
while IFS= read -r line; do
echo "$line"
done < file.txt
```
### Infinite loop
```bash
while true; do
echo "Press [CTRL+C] to stop.."
sleep 1
done
```
## History
┌───────────────┬────────────────────────────────────────────────────────────────┐
`!!` │ Expand latest command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$` │ Expand last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!*` │ Expand all parameters of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!-n` │ Expand nth latest command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!n` │ Expand nth command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!string` │ Expand latest command starting with string │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:s/from/to` │ Replace first occurrence of "from" with "to" in latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:gs/from/to` │ Replace all occurrences of "from" with "to" in latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:p` │ Print latest command without executing it │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$:t` │ Expand basename of last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$:h` │ Expand directory of last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n` │ Expand only nth parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!^` │ Expand first parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$` │ Expand last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n-m` │ Expand parameters from nth to mth of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n-$` │ Expand parameters from nth to last of latest command │
└───────────────┴────────────────────────────────────────────────────────────────┘
## Redirection
┌────────────────────────────┬─────────────────────────────────┐
`SCRIPT > FILE` │ stdout to FILE │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT >> FILE` │ Append stdout to FILE │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT 2> FILE` │ stderr to FILE │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT 2>&1`/`SCRIPT &> FILE` │ stderr to stdout │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT 2> /dev/null` │ stderr to /dev/null │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT > FILE 2>&1` │ stdout and stderr to FILE │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT &> /dev/null` │ stdout and stderr to /dev/null │
├────────────────────────────┼─────────────────────────────────┤
`echo "$0: warning" >&2` │ Print to stderr │
├────────────────────────────┼─────────────────────────────────┤
`SCRIPT < FILE` │ stdin from FILE │
└────────────────────────────┴─────────────────────────────────┘
## Switch statement
```bash
case "$1" in
start | up)
vagrant up
;;
*)
echo "Usage: $0 {start|stop|ssh}"
;;
esac
```
### Options switch statement
```bash
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
-V | --version )
echo "$version"
exit
;;
-s | --string )
shift; string=$1
;;
-f | --flag )
flag=1
;;
esac; shift; done
if [[ "$1" == '--' ]]; then shift; fi
```
## Functions
```bash
my_function() {
echo "Hello, World!"
}
```
### Arguments
┌────┬───────────────────────────────────┐
`$#` │ Number of arguments │
├────┼───────────────────────────────────┤
`$*` │ All arguments │
├────┼───────────────────────────────────┤
`$@` │ All arguments as separate strings │
├────┼───────────────────────────────────┤
`$1` │ First argument │
├────┼───────────────────────────────────┤
`$_` │ Last argument │
└────┴───────────────────────────────────┘
## Arrays
```bash
# Create an array in one line
Fruits=('Apple' 'Banana' 'Orange')
# Or assign each value
Fruits[0]="Apple"
Fruits[1]="Banana"
Fruits[2]="Orange"
# Associative array
declare -A sounds
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"
```
### Array element expansion
┌──────────────────────┬────────────────────────────────────────────────────┐
`${array[key]}` │ Element at `key`
├──────────────────────┼────────────────────────────────────────────────────┤
`${array[-1]}` │ Last element (not for associative) │
├──────────────────────┼────────────────────────────────────────────────────┤
`${array[@]}` │ All elements │
├──────────────────────┼────────────────────────────────────────────────────┤
`${#array[@]}` │ Number of elements │
├──────────────────────┼────────────────────────────────────────────────────┤
`${#array}` │ String length of 1st element (not for associative) │
├──────────────────────┼────────────────────────────────────────────────────┤
`${#array[key]}` │ String length of element at `key`
├──────────────────────┼────────────────────────────────────────────────────┤
`${array[@]:n:length}``length` eements from position `n`
├──────────────────────┼────────────────────────────────────────────────────┤
`${!array[@]}` │ Keys of all elements │
└──────────────────────┴────────────────────────────────────────────────────┘
### Operations
```bash
Fruits=("${Fruits[@]}" "Watermelon") # Push
Fruits+=('Watermelon') # Also Push
Fruits=( "${Fruits[@]/Ap*/}" ) # Remove by regex match
unset Fruits[2] # Remove one item
Fruits=("${Fruits[@]}") # Duplicate
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
words=($(< datafile)) # From file (split by IFS)
```
### Looping
```bash
for i in "${Fruits[@]}"; do
echo "$i"
done
for key in "${!sounds[@]}"; do
echo "$key"
done
```
## Misc
### Directory of script
```bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
```
### Special variables
┌──────────────────┬────────────────────────────────────────┐
`$?` │ Exit status of last task │
├──────────────────┼────────────────────────────────────────┤
`$!` │ PID of last background task │
├──────────────────┼────────────────────────────────────────┤
`$$` │ PID of shell │
├──────────────────┼────────────────────────────────────────┤
`$0` │ Filename of the shell script │
├──────────────────┼────────────────────────────────────────┤
`$_` │ Last arugment of altest command │
├──────────────────┼────────────────────────────────────────┤
`${PIPESTATUS[n]}` │ Return value of piped commands (array) │
└──────────────────┴────────────────────────────────────────┘
+205
View File
@@ -0,0 +1,205 @@
# Regex Cheat Sheet
## Anchors
┌────┬─────────────────────────────────────────────────────────┐
│ ^ │ Start of string, or start of line in multi-line pattern │
├────┼─────────────────────────────────────────────────────────┤
│ \A │ Start of string │
├────┼─────────────────────────────────────────────────────────┤
│ $ │ End of string, or end of line in multi-line pattern │
├────┼─────────────────────────────────────────────────────────┤
│ \Z │ End of string │
├────┼─────────────────────────────────────────────────────────┤
│ \b │ Word boundary │
├────┼─────────────────────────────────────────────────────────┤
│ \B │ Not word boundary │
├────┼─────────────────────────────────────────────────────────┤
│ \< │ Start of word │
├────┼─────────────────────────────────────────────────────────┤
│ \> │ End of word │
└────┴─────────────────────────────────────────────────────────┘
## Character Classes
┌────┬────────────────────┐
│ \c │ Control character │
├────┼────────────────────┤
│ \s │ White space │
├────┼────────────────────┤
│ \S │ Not white space │
├────┼────────────────────┤
│ \d │ Digit │
├────┼────────────────────┤
│ \D │ Not digit │
├────┼────────────────────┤
│ \w │ Word │
├────┼────────────────────┤
│ \W │ Not word │
├────┼────────────────────┤
│ \x │ Hexadecimal digit │
├────┼────────────────────┤
│ \O │ Octal digit │
└────┴────────────────────┘
## POSIX
┌───────────┬───────────────────────────────┐
`[:upper:]` │ Upper case letters │
├───────────┼───────────────────────────────┤
`[:lower:]` │ Lower case letters │
├───────────┼───────────────────────────────┤
`[:alpha:]` │ All letters │
├───────────┼───────────────────────────────┤
`[:alnum:]` │ Digits and letters │
├───────────┼───────────────────────────────┤
`[:digit:]` │ Digits │
├───────────┼───────────────────────────────┤
`[:xdigit:]`│ Hexadecimal digits │
├───────────┼───────────────────────────────┤
`[:punct:]` │ Punctuation │
├───────────┼───────────────────────────────┤
`[:blank:]` │ Space and tab │
├───────────┼───────────────────────────────┤
`[:space:]` │ Blank characters │
├───────────┼───────────────────────────────┤
`[:cntrl:]` │ Control characters │
├───────────┼───────────────────────────────┤
`[:graph:]` │ Printed characters │
├───────────┼───────────────────────────────┤
`[:print:]` │ Printed characters and spaces │
├───────────┼───────────────────────────────┤
`[:word:]` │ Digits, letters and underscore│
└───────────┴───────────────────────────────┘
## Assertions
┌──────┬──────────────────────────────┐
│ ?= │ Lookahead assertion │
├──────┼──────────────────────────────┤
│ ?! │ Negative lookahead │
├──────┼──────────────────────────────┤
│ ?<= │ Lookbehind assertion │
├──────┼──────────────────────────────┤
│ ?!= │ Negative lookbehind │
│ ?<! │ │
├──────┼──────────────────────────────┤
│ ?> │ Once-only subexpression │
├──────┼──────────────────────────────┤
│ ?() │ Condition `[if then]`
├──────┼──────────────────────────────┤
│ ?()| │ Condition `[if then else]`
├──────┼──────────────────────────────┤
│ ?# │ Comment │
└──────┴──────────────────────────────┘
## Quantifiers
┌───────┬─────────────┐
│ * │ 0 or more │
├───────┼─────────────┤
│ + │ 1 or more │
├───────┼─────────────┤
│ ? │ 0 or 1 │
├───────┼─────────────┤
│ {3} │ Exactly 3 │
├───────┼─────────────┤
│ {3,} │ 3 or more │
├───────┼─────────────┤
│ {3,5} │ 3, 4 or 5 │
└───────┴─────────────┘
> Add a `?` to a quantifier to make it ungreedy.
## Escape Sequences
┌────┬─────────────────────────────┐
│ \ │ Escape following character │
├────┼─────────────────────────────┤
│ \Q │ Begin literal sequence │
├────┼─────────────────────────────┤
│ \E │ End literal sequence │
└────┴─────────────────────────────┘
> "Escaping" is a way of treating characters which have a special meaning in regular expressions literally, rather than as special characters.
## Common Metacharacters
┌───┬───┬───┬───┐
│ ^ │ [ │ . │ $ │
├───┼───┼───┼───┤
│ { │ * │ ( │ \ │
├───┼───┼───┼───┤
│ + │ ) │ | │ ? │
├───┼───┼───┼───┤
│ < │ > │ │ │
└───┴───┴───┴───┘
> The escape character is usually `\`.
## Special Characters
┌──────┬────────────────────┐
│ \n │ New line │
├──────┼────────────────────┤
│ \r │ Carriage return │
├──────┼────────────────────┤
│ \t │ Tab │
├──────┼────────────────────┤
│ \v │ Vertical tab │
├──────┼────────────────────┤
│ \f │ Form feed │
├──────┼────────────────────┤
│ \xxx │ Octal character xxx│
├──────┼────────────────────┤
│ \xhh │ Hex character hh │
└──────┴────────────────────┘
## Groups and Ranges
┌─────────┬────────────────────────────────────┐
│ . │ Any character except new line (\n) │
├─────────┼────────────────────────────────────┤
│ (a|b) │ a or b │
├─────────┼────────────────────────────────────┤
│ (...) │ Group │
├─────────┼────────────────────────────────────┤
│ (?:...) │ Passive (non-capturing) group │
├─────────┼────────────────────────────────────┤
`[abc]` │ Range (a or b or c) │
├─────────┼────────────────────────────────────┤
`[^abc]` │ Not (a or b or c) │
├─────────┼────────────────────────────────────┤
`[a-q]` │ Lower case letter from a to q │
├─────────┼────────────────────────────────────┤
`[A-Q]` │ Upper case letter from A to Q │
├─────────┼────────────────────────────────────┤
`[0-7]` │ Digit from 0 to 7 │
├─────────┼────────────────────────────────────┤
│ \x │ Group/subpattern number "x" │
└─────────┴────────────────────────────────────┘
> Ranges are inclusive.
## Pattern Modifiers
┌────┬────────────────────────────────────┐
│ g │ Global match │
├────┼────────────────────────────────────┤
│ i │ Case-insensitive │
├────┼────────────────────────────────────┤
│ m │ Multiple lines │
├────┼────────────────────────────────────┤
│ s │ Treat string as single line │
├────┼────────────────────────────────────┤
│ x │ Allow comments and whitespace │
├────┼────────────────────────────────────┤
│ e │ Evaluate replacement │
├────┼────────────────────────────────────┤
│ U │ Ungreedy pattern │
└────┴────────────────────────────────────┘
> * PCRE modifier
## String Replacement
┌────┬──────────────────────────────────┐
`$n` │ nth non-passive group │
├────┼──────────────────────────────────┤
`$2` │ "xyz" in `/^(abc(xyz))$/`
├────┼──────────────────────────────────┤
`$1` │ "xyz" in `/^(?:abc)(xyz)$/`
├────┼──────────────────────────────────┤
`$`` │ Before matched string │
├────┼──────────────────────────────────┤
│ `$'` │ After matched string │
├────┼──────────────────────────────────┤
│ `$+` │ Last matched string │
├────┼──────────────────────────────────┤
│ `$&` │ Entire matched string │
└────┴──────────────────────────────────┘
> Some regex implementations use `\` instead of `$`.
+437
View File
@@ -0,0 +1,437 @@
# ZSH Cheat Sheet
## Conditionals
```zsh
if [[ -z "$string" ]]; then
echo "String is empty"
elif [[ -n "$string" ]]; then
echo "String is not empty"
fi
```
### String conditions
┌────────────────────────┬──────────────────┐
`[[ -z STRING ]]` │ Empty string │
├────────────────────────┼──────────────────┤
`[[ -n STRING ]]` │ Not empty string │
├────────────────────────┼──────────────────┤
`[[ STRING == STRING ]]` │ Equal │
├────────────────────────┼──────────────────┤
`[[ STRING != STRING ]]` │ Not Equal │
├────────────────────────┼──────────────────┤
`[[ STRING =~ STRING ]]` │ Regex │
└────────────────────────┴──────────────────┘
### Number conditions
┌────────────────────────┬───────────────────────┐
`[[ NUM1 -eq NUM2 ]]` │ Equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -ne NUM2 ]]` │ Not Equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -lt NUM2 ]]` │ Less than │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -le NUM2 ]]` │ Less than or equal │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -gt NUM2 ]]` │ Greater than │
├────────────────────────┼───────────────────────┤
`[[ NUM1 -ge NUM2 ]]` │ Greater than or equal │
├────────────────────────┼───────────────────────┤
`(( NUM < NUM ))` │ Numeric conditions │
└────────────────────────┴───────────────────────┘
### File conditions
┌───────────────────────┬─────────────────────────┐
`[[ -e FILE ]]` │ Exists │
├───────────────────────┼─────────────────────────┤
`[[ -r FILE ]]` │ Readable │
├───────────────────────┼─────────────────────────┤
`[[ -h FILE ]]` │ Symlink │
├───────────────────────┼─────────────────────────┤
`[[ -d FILE ]]` │ Directory │
├───────────────────────┼─────────────────────────┤
`[[ -w FILE ]]` │ Writable │
├───────────────────────┼─────────────────────────┤
`[[ -s FILE ]]` │ Size is > 0 bytes │
├───────────────────────┼─────────────────────────┤
`[[ -f FILE ]]` │ File │
├───────────────────────┼─────────────────────────┤
`[[ -x FILE ]]` │ Executable │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -nt FILE2 ]]` │ 1 is more recent than 2 │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -ot FILE2 ]]` │ 2 is more recent than 1 │
├───────────────────────┼─────────────────────────┤
`[[ FILE1 -ef FILE2 ]]` │ Same files │
└───────────────────────┴─────────────────────────┘
### Other conditions
┌────────────────────┬────────────────────┐
`[[ -o noclobber ]]` │ Option enabled │
├────────────────────┼────────────────────┤
`[[ ! EXPR ]]` │ Not │
├────────────────────┼────────────────────┤
`[[ X && Y ]]` │ And │
├────────────────────┼────────────────────┤
`[[ X || Y ]]` │ Or │
└────────────────────┴────────────────────┘
## Parameter manipulation
┌─────────────────────────────────┬────────────────────────────────────────────────────────────────┐
`${foo}` │ Variable │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo/from/to}` │ Replace first match │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo/#from/to}`/`${foo/%from/to}` │ Replace first match anchored to start (default) or end │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo//from/to}` │ Replace all │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo[start,length]}` │ Slice from `start` to `length` (`length` can be negative) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo%suffix}`/`${foo%%suffix}` │ Remove `suffix` (ungreedy/greedy) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo#prefix}`/`${foo##prefix}` │ Remove `prefix` (ungreedy/greedy) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${#foo}` │ Length of `foo`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(L)foo}` │ Lowercase all letters │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(U)foo}` │ Uppercase all letters │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(q)foo}` │ Quote safely │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(qq)foo}` │ Quote more explicitely │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(s.del.)foo}` │ Split on `del`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${(j.del.)foo}` │ Join with `del`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:h}` │ Directory of `file`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:t}` │ Filename of `file`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:e}` │ Extension of `file`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:r}` │ Root of `file` (without extension) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:a}` │ Absolute path of `file`
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${file:A}` │ Absolute path of `file` (resolves symlinks) │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:-val}` │ Use `val` if `foo` is unset or null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:=val}` │ Set `foo` to `val` if unset or null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:+val}` │ Use `val` if `foo` **is** set and not null │
├─────────────────────────────────┼────────────────────────────────────────────────────────────────┤
`${foo:?message}` │ Print `message` and exit if `foo` is unset or null │
└─────────────────────────────────┴────────────────────────────────────────────────────────────────┘
> Omitting the `:` for default values will only check if the variable is set, not if it is null.
### Examples
```zsh
name="John"
echo "${name}"
echo "${name/J/j}" #=> "john" (substitution)
echo "${name[0,2]}" #=> "Jo" (slicing)
echo "${food:-Cake}" #=> $food or "Cake"
length=2
echo "${name[1,length]}" #=> "Jo" (slicing with variable)
str="/path/to/foo.cpp"
echo "${str%.cpp}" # /path/to/foo
echo "${str%.cpp}.o" # /path/to/foo.o
echo "${str%/*}" # /path/to
echo "${str##*.}" # cpp (extension)
echo "${str##*/}" # foo.cpp (basepath)
echo "${str#*o}" # o/foo.cpp (first occurrence of 'o')
echo "${str##*o}" # oo.cpp (last occurrence of 'o')
echo "${str#*/}" # path/to/foo.cpp
echo "${str##*/}" # foo.cpp
echo "${str/foo/bar}" # /path/to/bar.cpp
str="HELLO WORLD!"
echo "${(L)str}" #=> "hello world!" (all lowercase)
str="hello world!"
echo "${(U)str}" #=> "HELLO WORLD!" (all uppercase)
```
## Globs
┌───────────────┬───────────────────────┐
`ls **/*.js` │ Recursive expansion │
├───────────────┼───────────────────────┤
`ls *(.)` │ Plain files │
├───────────────┼───────────────────────┤
`ls *(/)` │ Directories │
├───────────────┼───────────────────────┤
`ls *(@)` │ Symlinks │
├───────────────┼───────────────────────┤
`ls *(*)` │ Executables │
├───────────────┼───────────────────────┤
`ls *(L+1M)` │ Files larger than 1MB │
├───────────────┼───────────────────────┤
`ls *(om[1,5])` │ 5 newest files │
├───────────────┼───────────────────────┤
`ls *(.)~*.bak` │ Files except *.bak │
└───────────────┴───────────────────────┘
## Comments
```zsh
# This is a comment
: '
This is a multi-line comment workaround
'
```
## Loops
### Basic for loop
```zsh
for i in /etc/rc.*; do
echo "$i"
done
```
### C-style for loop
```zsh
for (( i = 0; i < 10; i++ )); do
echo "$i"
done
```
### Ranges
```zsh
for i in {1..10}; do
echo "$i"
done
# With step size
for i in {1..10..2}; do
echo "$i"
done
```
### Reading lines
```zsh
while IFS= read -r line; do
print -r -- "$line"
done < file.txt
```
### Infinite loop
```zsh
while true; do
echo "Press [CTRL+C] to stop.."
sleep 1
done
```
## History
┌───────────────┬────────────────────────────────────────────────────────────────┐
`!!` │ Expand latest command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$` │ Expand last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!*` │ Expand all parameters of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!-n` │ Expand nth latest command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!n` │ Expand nth command in history │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!string` │ Expand latest command starting with string │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:s/from/to` │ Replace first occurrence of "from" with "to" in latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:gs/from/to` │ Replace all occurrences of "from" with "to" in latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:p` │ Print latest command without executing it │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$:t` │ Expand basename of last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$:h` │ Expand directory of last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n` │ Expand only nth parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!^` │ Expand first parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!$` │ Expand last parameter of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n-m` │ Expand parameters from nth to mth of latest command │
├───────────────┼────────────────────────────────────────────────────────────────┤
`!!:n-$` │ Expand parameters from nth to last of latest command │
└───────────────┴────────────────────────────────────────────────────────────────┘
## Redirection
┌────────────────────────┬─────────────────────────────────┐
`SCRIPT > FILE` │ stdout to FILE │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT >> FILE` │ Append stdout to FILE │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT 2> FILE` │ stderr to FILE │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT 2>&1` │ stderr to stdout │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT &> FILE` │ stderr and stdout to FILE │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT 2> /dev/null` │ stderr to /dev/null │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT > FILE 2>&1` │ stdout and stderr to FILE │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT &> /dev/null` │ stdout and stderr to /dev/null │
├────────────────────────┼─────────────────────────────────┤
`echo "$0: warning" >&2` │ Print to stderr │
├────────────────────────┼─────────────────────────────────┤
`SCRIPT < FILE` │ stdin from FILE │
└────────────────────────┴─────────────────────────────────┘
## Switch statement
```zsh
case "$1" in
start | up)
vagrant up
;;
*)
echo "Usage: $0 {start|stop|ssh}"
;;
esac
```
### Options switch statement
```zsh
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
-V | --version )
echo "$version"
exit
;;
-s | --string )
shift; string=$1
;;
-f | --flag )
flag=1
;;
esac; shift; done
if [[ "$1" == '--' ]]; then shift; fi
```
## Functions
```zsh
my_function() {
echo "Hello, World!"
}
```
### Arguments
┌────┬───────────────────────────────────┐
`$#` │ Number of arguments │
├────┼───────────────────────────────────┤
`$*` │ All arguments │
├────┼───────────────────────────────────┤
`$@` │ All arguments as separate strings │
├────┼───────────────────────────────────┤
`$1` │ First argument │
├────┼───────────────────────────────────┤
`$_` │ Last argument │
└────┴───────────────────────────────────┘
## Arrays
```zsh
# Create an array in one line
Fruits=('Apple' 'Banana' 'Orange')
# Or assign each value
Fruits[1]="Apple"
Fruits[2]="Banana"
Fruits[3]="Orange"
# Associative array
typeset -A sounds
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"
```
### Array element expansion
┌──────────────────────────────────────┬────────────────────────────────────┐
`${array[key]}` │ Element at `key`
├──────────────────────────────────────┼────────────────────────────────────┤
`${array[-1]}` │ Last element (not for associative) │
├──────────────────────────────────────┼────────────────────────────────────┤
`${array[@]}` │ All elements │
├──────────────────────────────────────┼────────────────────────────────────┤
`${#array}` │ Number of elements │
├──────────────────────────────────────┼────────────────────────────────────┤
`${#array[key]}` │ String length of element at `key`
├──────────────────────────────────────┼────────────────────────────────────┤
`${array:n:length}`/`${array[n,length]}``length` eements from position `n`
├──────────────────────────────────────┼────────────────────────────────────┤
`${(k)array}` │ Keys of all elements │
└──────────────────────────────────────┴────────────────────────────────────┘
### Operations
```zsh
Fruits=("${Fruits[@]}" "Watermelon") # Push
Fruits+=('Watermelon') # Also Push
Fruits=( "${Fruits[@]/Ap*/}" ) # Remove by regex match
unset Fruits[3] # Remove one item
Fruits=("${Fruits[@]}") # Duplicate
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
words=($(< datafile)) # From file (split by IFS)
```
### Looping
```zsh
for i in "${Fruits[@]}"; do
echo "$i"
done
for val in "${(v)sounds}"; do
echo "$val"
done
for key in "${(k)sounds}"; do
echo "$key"
done
```
## Misc
### Directory of script
```zsh
DIR="$( cd "$( dirname "${ZSH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
```
### Special variables
┌──────────────────┬───────────────────────────────────────────────┐
`$?` │ Exit status of last task │
├──────────────────┼───────────────────────────────────────────────┤
`$!` │ PID of last background task │
├──────────────────┼───────────────────────────────────────────────┤
`$$` │ PID of shell │
├──────────────────┼───────────────────────────────────────────────┤
`$#` │ Number of arguments passed to script │
├──────────────────┼───────────────────────────────────────────────┤
`$0` │ Filename of the shell script │
├──────────────────┼───────────────────────────────────────────────┤
`$_` │ Last arugment of altest command │
├──────────────────┼───────────────────────────────────────────────┤
`$argv` │ Array of all arguments passed to script │
├──────────────────┼───────────────────────────────────────────────┤
`$ARGC` │ Number of arguments passed to script │
├──────────────────┼───────────────────────────────────────────────┤
`${pipestatus[n]}` │ Return value of piped commands (array) │
├──────────────────┼───────────────────────────────────────────────┤
`$RANDOM` │ Random number between 0 and 32767 │
├──────────────────┼───────────────────────────────────────────────┤
`$SECONDS` │ Number of seconds since the shell was started │
├──────────────────┼───────────────────────────────────────────────┤
`$PWD` │ Current working directory │
├──────────────────┼───────────────────────────────────────────────┤
`$OLDPWD` │ Previous working directory │
└──────────────────┴───────────────────────────────────────────────┘
+1
View File
@@ -1,6 +1,7 @@
-- Set <space> as the leader key -- Set <space> as the leader key
-- See `:help mapleader` -- See `:help mapleader`
-- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) -- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used)
vim.lsp.log.set_level 'debug'
vim.g.mapleader = ',' vim.g.mapleader = ','
vim.g.maplocalleader = ',' vim.g.maplocalleader = ','
+105 -3
View File
@@ -18,19 +18,21 @@ vim.api.nvim_create_autocmd('FocusLost', {
group = autosave_group, group = autosave_group,
pattern = '*', pattern = '*',
command = 'silent! wa', -- Save all files when moving away from the window command = 'silent! wa', -- Save all files when moving away from the window
nested = true, -- Allow other autocommands to run after this one
}) })
vim.api.nvim_create_autocmd('InsertLeave', { vim.api.nvim_create_autocmd('BufLeave', {
group = autosave_group, group = autosave_group,
pattern = '*', pattern = '*',
command = 'silent! wa', -- Save all files when leaving insert mode command = 'silent! wa', -- Save all files when switching buffers
nested = true, -- Allow other autocommands to run after this one
}) })
vim.api.nvim_create_autocmd('SwapExists', { vim.api.nvim_create_autocmd('SwapExists', {
desc = 'Always choose to delete the swap file, files are saved automatically', desc = 'Always choose to delete the swap file, files are saved automatically',
group = vim.api.nvim_create_augroup('NoSwaps', { clear = true }), group = vim.api.nvim_create_augroup('NoSwaps', { clear = true }),
callback = function(args) callback = function(args)
vim.cmd("let v:swapchoice = 'd'") vim.cmd "let v:swapchoice = 'd'"
end, end,
}) })
@@ -92,6 +94,13 @@ vim.api.nvim_create_autocmd({ 'User' }, {
-- end, -- end,
-- }) -- })
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
pattern = { '*.lua' },
callback = function(args)
require('helpers').format_buffer('stylua', args.buf)
end,
})
local modes_group = vim.api.nvim_create_augroup('modes', { clear = true }) local modes_group = vim.api.nvim_create_augroup('modes', { clear = true })
vim.api.nvim_create_autocmd('FocusLost', { vim.api.nvim_create_autocmd('FocusLost', {
group = modes_group, group = modes_group,
@@ -116,4 +125,97 @@ vim.api.nvim_create_autocmd('BufWritePost', {
end, end,
}) })
local configs = {
{
path = os.getenv 'HOME' .. '/.config/nixos',
worktree = nil,
git_dir = nil,
track_untracked = false,
force_add = false,
},
{
path = os.getenv 'HOME' .. '/.config/nvim',
worktree = nil,
git_dir = nil,
track_untracked = false,
force_add = false,
},
{
path = os.getenv 'HOME',
worktree = os.getenv 'HOME',
git_dir = os.getenv 'HOME' .. '/.config/dotfiles/.git',
track_untracked = true,
force_add = true, -- Handles ignored files in dotfiles
include_dirs = { '.config', '.local/bin', '.local/share' },
},
}
local function get_git_status(config)
local base = 'git'
if config.git_dir and config.worktree then
base = string.format('git --git-dir=%s --worktree=%s', config.git_dir, config.worktree)
end
-- Check modified and untracked (including ignored if force_add is true)
local cmd = base .. ' status --porcelain'
if config.force_add then
cmd = cmd .. ' --ignored'
end
local handle = io.popen(cmd)
local result = handle:read '*a'
handle:close()
local has_changes = false
for line in result:gmatch '[^\r\n]+' do
local status = line:sub(1, 2)
local file = line:sub(4)
if status:match '[MAR]' then
has_changes = true
elseif (status == '??' or status == '!!') and config.track_untracked then
if config.include_dirs then
for _, dir in ipairs(config.include_dirs) do
if file:sub(1, #dir) == dir then
has_changes = true
break
end
end
else
has_changes = true
end
end
end
return has_changes, base
end
vim.api.nvim_create_autocmd('VimLeavePre', {
callback = function()
local cwd = vim.fn.getcwd()
for _, config in ipairs(configs) do
if cwd:sub(1, #config.path) == config.path then
local has_changes, git_base = get_git_status(config)
if has_changes then
local confirm = vim.fn.confirm('Uncommitted changes in managed path. Commit?', '&Yes\n&No', 2)
if confirm == 1 then
local msg = vim.fn.input('Commit message: ', 'chore: update files')
if msg ~= '' then
msg = 'Update files'
end
local add_cmd = ' add -A'
os.execute(git_base .. add_cmd)
os.execute(git_base .. ' commit -m ' .. vim.fn.shellescape(msg))
os.execute(git_base .. ' push')
print '\nChanges committed.'
end
end
break
end
end
end,
})
require('helpers').edit_cf('a', '/lua/autocmd.lua') require('helpers').edit_cf('a', '/lua/autocmd.lua')
+113 -8
View File
@@ -16,17 +16,24 @@ end
helpers.edit_cf('h', '/lua/helpers.lua') helpers.edit_cf('h', '/lua/helpers.lua')
---@param opts? { cmd?: string } ---@param opts? { cmd?: string, win_opts?: table, buf_opts?: table }
helpers.open_term = function(opts) helpers.open_term = function(opts, buf_opts)
opts = opts or { cmd = '' } opts = opts or {}
local cmd = opts.cmd or ''
local win_opts = opts.win_opts
local buf_options = buf_opts or opts.buf_opts or {
bufhidden = 'wipe',
modifiable = false,
}
local buf = vim.api.nvim_create_buf(false, true) local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('bufhidden', 'wipe', { buf = buf }) for k, v in pairs(buf_options) do
vim.api.nvim_set_option_value('modifiable', false, { buf = buf }) vim.api.nvim_set_option_value(k, v, { buf = buf })
end
local height = math.ceil(vim.o.lines * 0.9) local height = math.ceil(vim.o.lines * 0.9)
local width = math.ceil(vim.o.columns * 0.9) local width = math.ceil(vim.o.columns * 0.9)
local win = vim.api.nvim_open_win(buf, true, { local win = vim.api.nvim_open_win(buf, true, win_opts or {
style = 'minimal', style = 'minimal',
relative = 'editor', relative = 'editor',
width = width, width = width,
@@ -38,7 +45,7 @@ helpers.open_term = function(opts)
vim.api.nvim_set_current_win(win) vim.api.nvim_set_current_win(win)
vim.fn.jobstart(opts.cmd, { vim.fn.jobstart(cmd, {
term = true, term = true,
on_exit = function(_, _, _) on_exit = function(_, _, _)
if vim.api.nvim_win_is_valid(win) then if vim.api.nvim_win_is_valid(win) then
@@ -51,7 +58,105 @@ helpers.open_term = function(opts)
end end
helpers.has_copilot = function() helpers.has_copilot = function()
return vim.fn.getenv('COPILOT_API_KEY') ~= vim.NIL return vim.fn.getenv 'COPILOT_API_KEY' ~= vim.NIL
end
helpers.open_file_modal = function(path, title)
local width = math.floor(vim.o.columns * 0.85)
local height = math.floor(vim.o.lines * 0.85)
local row = math.floor((vim.o.lines - height) / 2)
local col = math.floor((vim.o.columns - width) / 2)
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_open_win(buf, true, {
relative = 'editor',
width = width,
height = height,
row = row,
col = col,
style = 'minimal',
border = 'rounded',
title = ' ' .. title .. ' ',
title_pos = 'center',
})
vim.api.nvim_buf_set_name(buf, path)
local lines = vim.fn.readfile(path)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.bo[buf].filetype = 'markdown'
vim.bo[buf].buftype = 'nofile'
vim.bo[buf].bufhidden = 'wipe'
vim.bo[buf].swapfile = false
vim.bo[buf].modifiable = false
vim.bo[buf].readonly = true
vim.wo.wrap = false
vim.wo.number = false
vim.wo.relativenumber = false
vim.wo.cursorline = true
vim.keymap.set('n', 'q', '<cmd>close<CR>', {
buffer = buf,
silent = true,
desc = 'Close cheatsheet',
})
vim.keymap.set('n', '<Esc>', '<cmd>close<CR>', {
buffer = buf,
silent = true,
desc = 'Close cheatsheet',
})
end
local function get_formatter_bin(formatter)
return vim.fn.stdpath 'data' .. '/mason/bin/' .. formatter
end
local formatter_args = {
pint = function(file)
return {
get_formatter_bin 'pint',
'--stdin-filename',
file,
}
end,
eslint_d = function(file)
return {
get_formatter_bin 'eslint_d',
'--stdin',
'--stdin-filename',
file,
'--fix-to-stdout',
}
end,
stylua = function(file)
return {
get_formatter_bin 'stylua',
'--stdin-filepath',
file,
'-',
}
end,
}
helpers.format_buffer = function(formatter, buf, cwd)
local file = vim.api.nvim_buf_get_name(buf)
local input = table.concat(vim.api.nvim_buf_get_lines(buf, 0, -1, false), '\n')
local result = vim.system(formatter_args[formatter](file), {
text = true,
stdin = input,
cwd = cwd,
}):wait()
if result.code ~= 0 then
vim.notify(result.stderr, vim.log.levels.ERROR)
return
end
vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(result.stdout, '\n', { plain = true }))
end end
return helpers return helpers
+171 -92
View File
@@ -26,7 +26,7 @@ vim.keymap.set('v', 'p', '"zdP', { desc = 'Paste over selection without yanking
-- or just use <C-\><C-n> to exit terminal mode -- or just use <C-\><C-n> to exit terminal mode
vim.keymap.set('t', '<Esc><Esc>', '<C-\\><C-n>', { desc = 'Exit terminal mode' }) vim.keymap.set('t', '<Esc><Esc>', '<C-\\><C-n>', { desc = 'Exit terminal mode' })
vim.keymap.set('n', '<Leader>c', function() vim.keymap.set('n', '<Leader>z', function()
vim.treesitter.inspect_tree() vim.treesitter.inspect_tree()
end, { desc = 'Treesitter' }) end, { desc = 'Treesitter' })
@@ -121,6 +121,11 @@ vim.keymap.set('n', '<C-l>', '<C-w><C-l>', { desc = 'Move focus to the right win
vim.keymap.set('n', '<C-j>', (win_or_treesj)('j', 'Move focus to the lower window or treesj.toggle()')) vim.keymap.set('n', '<C-j>', (win_or_treesj)('j', 'Move focus to the lower window or treesj.toggle()'))
vim.keymap.set('n', '<C-k>', (win_or_treesj)('k', 'Move focus to the upper window or treesj.toggle()')) vim.keymap.set('n', '<C-k>', (win_or_treesj)('k', 'Move focus to the upper window or treesj.toggle()'))
vim.keymap.set('t', '<C-h>', '<C-\\><C-n><C-w>h', { desc = 'Move focus to the left window' })
vim.keymap.set('t', '<C-l>', '<C-\\><C-n><C-w>l', { desc = 'Move focus to the right window' })
vim.keymap.set('t', '<C-j>', '<C-\\><C-n><C-w>j', { desc = 'Move focus to the lower window' })
vim.keymap.set('t', '<C-k>', '<C-\\><C-n><C-w>k', { desc = 'Move focus to the upper window' })
vim.keymap.set({ 'i' }, '<C-J>', function() vim.keymap.set({ 'i' }, '<C-J>', function()
local ls = require 'luasnip' local ls = require 'luasnip'
if ls.choice_active() then if ls.choice_active() then
@@ -177,8 +182,54 @@ vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-f>', function()
end, { desc = 'Search within the whole project' }) end, { desc = 'Search within the whole project' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-Y>', '<CMD>Telescope quickfix<CR>', { desc = 'Show quickfix list' }) vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-Y>', '<CMD>Telescope quickfix<CR>', { desc = 'Show quickfix list' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-Y>', '<CMD>Telescope quickfixhistory<CR>', { desc = 'Show quickfix history' }) vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-Y>', '<CMD>Telescope quickfixhistory<CR>', { desc = 'Show quickfix history' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-A>', '<CMD>CodeCompanionChat Toggle<CR>', { desc = 'Open AI Actions' }) vim.keymap.set({ 'n', 'v', 'c', 'i', 't' }, '<C-A>', function()
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-A>', '<CMD>CodeCompanionActions<CR>', { desc = 'Open AI Actions' }) local ai_tools = { 'codex', 'agy', 'opencode' }
local ai_win_opts = {
width = math.floor(vim.o.columns / 3),
vertical = true,
split = 'right',
}
local term_bufnr = -1
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
if vim.bo[bufnr].buftype == 'terminal' then
local name = vim.api.nvim_buf_get_name(bufnr)
for _, tool in ipairs(ai_tools) do
if name:match(':' .. tool .. '$') or name:match('/' .. tool .. '$') then
term_bufnr = bufnr
end
end
end
end
if term_bufnr ~= -1 then
local term_winid = vim.fn.bufwinid(term_bufnr)
if term_winid ~= -1 then
vim.api.nvim_win_hide(term_winid)
return
end
vim.api.nvim_open_win(term_bufnr, true, ai_win_opts)
vim.cmd.startinsert()
return
end
for _, tool in ipairs(ai_tools) do
if vim.fn.executable(tool) == 1 then
helpers.open_term {
cmd = tool,
win_opts = ai_win_opts,
buf_opts = {
bufhidden = 'hide',
modifiable = false,
},
}
return
end
end
vim.api.nvim_echo({ { 'No AI tool found. Please install one of the following: codex, agy, opencode', 'WarningMsg' } }, false, {})
end, { desc = 'Toggle AI tool' })
-- vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-A>', '<CMD>vsplit term://codex<CR>i', { desc = 'Open AI tool' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S>', function() vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S>', function()
require('snacks').scratch() require('snacks').scratch()
end, { desc = 'Open scratchpad' }) end, { desc = 'Open scratchpad' })
@@ -257,102 +308,119 @@ vim.keymap.set('n', '<Leader>sGS', '<CMD>Telescope git_stash<CR>', { desc = 'Sea
vim.keymap.set('n', '<Leader>]', '<CMD>cnext<CR>', { desc = 'Next item in quickfix list' }) vim.keymap.set('n', '<Leader>]', '<CMD>cnext<CR>', { desc = 'Next item in quickfix list' })
vim.keymap.set('n', '<Leader>[', '<CMD>cprevious<CR>', { desc = 'Previous item in quickfix list' }) vim.keymap.set('n', '<Leader>[', '<CMD>cprevious<CR>', { desc = 'Previous item in quickfix list' })
vim.keymap.set('n', 'gd', '<CMD>Telescope lsp_definitions<CR>', { desc = 'Go to definition' }) vim.keymap.set('n', 'gd', '<CMD>Telescope lsp_definitions<CR>', { desc = 'Go to definition' })
vim.keymap.set('n', '<Leader>r', function()
for _, c in ipairs(vim.lsp.get_clients { bufnr = 0 }) do
if c.name == 'phpantom_lsp' then
c:stop(true)
end
end
vim.cmd 'edit'
end, { desc = 'Reload buffer' })
local function open_test() local function open_test()
require('neotest').summary.open() require('neotest').summary.open()
require('neotest').output_panel.open() require('neotest').output_panel.open()
end end
-- Testing -- Testing
-- local test_maps = { local test_maps = {
-- { {
-- keys = { '<F12>', '<Leader>tn' }, keys = { '<Leader>tc' },
-- action = function() action = function()
-- require('neotest').run.run() require('neotest').summary.close()
-- open_test() require('neotest').output_panel.close()
-- end, end,
-- desc = 'Run nearest test', desc = 'Close [T]est panels',
-- }, },
-- { {
-- keys = { '<F9>', '<Leader>ta' }, keys = { '<Leader>tn' },
-- action = function() action = function()
-- require('neotest').run.run { suite = true } require('neotest').run.run()
-- open_test() open_test()
-- end, end,
-- desc = 'Run all tests in the project', desc = 'Run nearest [T]est',
-- }, },
-- { {
-- keys = { '<F11>', '<Leader>tp' }, keys = { '<Leader>ta' },
-- action = function() action = function()
-- require('neotest').run.run_last() require('neotest').run.run { suite = true }
-- open_test() open_test()
-- end, end,
-- desc = 'Run previous test again', desc = 'Run all [T]ests in the project',
-- }, },
-- { {
-- keys = { '<F10>', '<Leader>td' }, keys = { '<Leader>tp' },
-- action = function() action = function()
-- local dap = require 'dap' require('neotest').run.run_last()
-- if dap.session() == nil then open_test()
-- dap.continue() end,
-- end desc = 'Run previous [T]est again',
-- require('dapui').open() },
-- local neotest = require 'neotest' {
-- local bufnr = vim.api.nvim_get_current_buf() keys = { '<Leader>td' },
-- local row = vim.api.nvim_win_get_cursor(0)[1] - 1 action = function()
-- local dap = require 'dap'
-- local adapters = neotest.state.adapter_ids() if dap.session() == nil then
-- local found = false dap.continue()
-- end
-- for _, adapter_id in ipairs(adapters) do require('dapui').open()
-- local tree = neotest.state.positions(adapter_id, { buffer = bufnr }) local neotest = require 'neotest'
-- if tree then local bufnr = vim.api.nvim_get_current_buf()
-- local nearest = require('neotest.lib.positions').nearest(tree, row) local row = vim.api.nvim_win_get_cursor(0)[1] - 1
-- if nearest and nearest:data().type ~= 'file' then
-- neotest.run.run()
-- found = true
-- break
-- end
-- end
-- end
--
-- if not found then
-- neotest.run.run_last()
-- end
-- end,
-- desc = 'Run last test with debugger',
-- },
-- }
--
-- for _, map_info in ipairs(test_maps) do
-- for _, key in ipairs(map_info.keys) do
-- vim.keymap.set('n', key, map_info.action, { desc = map_info.desc })
-- end
-- end
-- vim.keymap.set('n', '<Leader>tf', function()
-- require('neotest').run.run(vim.fn.expand '%')
-- open_test()
-- end, { desc = 'Run all tests in the current file' })
-- vim.keymap.set('n', '<Leader>tc', function()
-- require('neotest').summary.close()
-- require('neotest').output_panel.close()
-- end, { desc = 'Close test panels' })
-- vim.keymap.set('i', '<Tab>', function() local adapters = neotest.state.adapter_ids()
-- local copilot = require 'copilot.suggestion' local found = false
-- local ls = require 'luasnip'
-- if copilot.is_visible() then vim.g.neotest_debug = true
-- vim.api.nvim_echo({{'Accepting copilot suggestion'}}, false, {}) for _, adapter_id in ipairs(adapters) do
-- copilot.accept() local tree = neotest.state.positions(adapter_id, { buffer = bufnr })
-- copilot.dismiss() if tree then
-- elseif ls.jumpable(1) then local nearest = require('neotest.lib.positions').nearest(tree, row)
-- vim.api.nvim_echo({{'Jumping in snippet'}}, false, {}) if nearest and nearest:data().type ~= 'file' then
-- ls.jump() neotest.run.run()
-- else found = true
-- vim.api.nvim_echo({{'Inserting tab'}}, false, {}) break
-- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Tab>', true, true, true), 'n', true) end
-- end end
-- end, { desc = 'Luasnip accept copilot or jump forward' }) end
if not found then
neotest.run.run_last()
end
vim.g.neotest_debug = nil
end,
desc = 'Run last [T]est with debugger',
},
}
for _, map_info in ipairs(test_maps) do
for _, key in ipairs(map_info.keys) do
vim.keymap.set('n', key, map_info.action, { desc = map_info.desc })
end
end
vim.keymap.set('n', '<Leader>tf', function()
require('neotest').run.run(vim.fn.expand '%')
open_test()
end, { desc = 'Run all tests in the current file' })
vim.keymap.set('n', '<Leader>tc', function()
require('neotest').summary.close()
require('neotest').output_panel.close()
end, { desc = 'Close test panels' })
vim.keymap.set('i', '<Tab>', function()
local copilot = require 'copilot.suggestion'
local ls = require 'luasnip'
if copilot.is_visible() then
vim.api.nvim_echo({ { 'Accepting copilot suggestion' } }, false, {})
copilot.accept()
copilot.dismiss()
elseif ls.jumpable(1) then
vim.api.nvim_echo({ { 'Jumping in snippet' } }, false, {})
ls.jump()
else
vim.api.nvim_echo({ { 'Inserting tab' } }, false, {})
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Tab>', true, true, true), 'n', true)
end
end, { desc = 'Luasnip accept copilot or jump forward' })
-- Leaving this commented out, I will try the format command instead -- Leaving this commented out, I will try the format command instead
-- "A command to properly indent json code -- "A command to properly indent json code
@@ -370,4 +438,15 @@ vim.keymap.set('n', '<Leader>es', function()
vim.cmd('tabedit ' .. snippets_file) vim.cmd('tabedit ' .. snippets_file)
end, { desc = 'Edit snippets file' }) end, { desc = 'Edit snippets file' })
vim.keymap.set('n', '<Leader>cz', function()
require('utils/cheatsheets').open 'zsh'
end, { desc = 'Open zsh cheat sheet' })
vim.keymap.set('n', '<Leader>cb', function()
require('utils/cheatsheets').open 'bash'
end, { desc = 'Open bash cheat sheet' })
vim.keymap.set('n', '<Leader>cr', function()
require('utils/cheatsheets').open 'regex'
end, { desc = 'Open RegExp cheat sheet' })
require('helpers').edit_cf('k', '/lua/keymap.lua') require('helpers').edit_cf('k', '/lua/keymap.lua')
+1
View File
@@ -75,6 +75,7 @@ vim.opt.softtabstop = 4
vim.opt.expandtab = true vim.opt.expandtab = true
-- Automatically indent code -- Automatically indent code
vim.opt.smartindent = true vim.opt.smartindent = true
vim.opt.autoindent = true
-- Save the file when switching buffers -- Save the file when switching buffers
vim.opt.autowriteall = true vim.opt.autowriteall = true
-67
View File
@@ -1,67 +0,0 @@
require('helpers').edit_cf('pa', '/lua/plugins/aider.lua')
local change_model_function = function(model)
return function()
require('nvim_aider').api.send_command('/model', model)
end
end
return {
'GeorgesAlkhouri/nvim-aider',
cmd = 'Aider',
keys = {
{ '<leader>a/', '<cmd>Aider toggle<cr>', desc = 'Toggle Aider' },
{ '<leader>as', '<cmd>Aider send<cr>', desc = 'Send to Aider', mode = { 'n', 'v' } },
{ '<leader>ac', '<cmd>Aider command<cr>', desc = 'Aider Commands' },
{ '<leader>ab', '<cmd>Aider buffer<cr>', desc = 'Send Buffer' },
{ '<leader>a+', '<cmd>Aider add<cr>', desc = 'Add File' },
{ '<leader>a-', '<cmd>Aider drop<cr>', desc = 'Drop File' },
{ '<leader>ar', '<cmd>Aider add readonly<cr>', desc = 'Add Read-Only' },
{ '<leader>aR', '<cmd>Aider reset<cr>', desc = 'Reset Session' },
-- Example nvim-tree.lua integration if needed
{ '<leader>a+', '<cmd>AiderTreeAddFile<cr>', desc = 'Add File from Tree to Aider', ft = 'NvimTree' },
{ '<leader>a-', '<cmd>AiderTreeDropFile<cr>', desc = 'Drop File from Tree from Aider', ft = 'NvimTree' },
{ '<leader>am4', change_model_function 'gpt-4.1', desc = 'Switch aider model to GPT-4.1' },
{ '<leader>amo', change_model_function 'openai/o4-mini', desc = 'Switch aider model to o4-mini' },
{ '<leader>amg', change_model_function 'openai/gemini-2.5-pro', desc = 'Switch aider model to Gemini 2.5 Pro' },
{ '<leader>ams', change_model_function 'openai/claude-sonnet-4', desc = 'Switch aider model to Claude Sonnet 4' },
},
dependencies = {
'folke/snacks.nvim',
--- The below dependencies are optional
'catppuccin/nvim',
'nvim-tree/nvim-tree.lua',
--- Neo-tree integration
{
'nvim-neo-tree/neo-tree.nvim',
opts = function(_, opts)
-- Example mapping configuration (already set by default)
-- opts.window = {
-- mappings = {
-- ["+"] = { "nvim_aider_add", desc = "add to aider" },
-- ["-"] = { "nvim_aider_drop", desc = "drop from aider" }
-- ["="] = { "nvim_aider_add_read_only", desc = "add read-only to aider" }
-- }
-- }
require('nvim_aider.neo_tree').setup(opts)
end,
},
},
config = function()
require('nvim_aider').setup {
aider_cmd = 'aider',
args = {
'--config=$HOME/.config/aider/aider.yaml',
'--env-file=$(pwd)/aider.env',
'--watch',
'--architect',
},
auto_reload = true,
win = {
wo = { winbar = 'Aider' },
style = 'nvim_aider',
position = 'bottom',
},
}
end,
}
+7
View File
@@ -0,0 +1,7 @@
return {
'ricardoramirezr/blade-nav.nvim',
dependencies = { -- totally optional
'saghen/blink.cmp', -- if using blink.cmp
},
ft = { 'blade', 'php' }, -- optional, improves startup time
}
+6
View File
@@ -56,6 +56,12 @@ return {
providers = { providers = {
lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 }, lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 },
-- avante = { module = 'blink-cmp-avante', name = 'Avante', opts = {} }, -- avante = { module = 'blink-cmp-avante', name = 'Avante', opts = {} },
-- ['blade-nav'] = {
-- module = 'blade-nav.blink',
-- opts = {
-- clost_tag_on_complete = false,
-- },
-- },
}, },
per_filetype = { per_filetype = {
codecompanion = { 'codecompanion' }, codecompanion = { 'codecompanion' },
-339
View File
@@ -1,339 +0,0 @@
return {
'olimorris/codecompanion.nvim',
config = function()
require('codecompanion').setup {
adapters = {
http = {
default = function()
if (require('helpers').has_copilot()) then
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = vim.env.DEFAULT_AI_MODEL,
},
max_tokens = {
default = 1000000,
},
}
})
end
return require('codecompanion.adapters').extend('openai_compatible', {
env = {
url = vim.env.DEFAULT_OPENAI_API_BASE,
api_key = vim.env.DEFAULT_OPENAI_API_KEY,
chat_url = '/v1/chat/completions',
models_endpoint = '/v1/models',
},
schema = {
model = {
default = vim.env.DEFAULT_AI_MODEL,
},
max_tokens = {
default = 1000000,
},
},
})
end,
},
},
display = {
chat = {
show_settings = true,
start_in_insert_mode = false,
},
},
strategies = {
chat = {
adapter = 'default',
slash_commands = {
-- codebase = require('vectorcode.integrations').codecompanion.chat.make_slash_command(),
},
tools = {
-- vectorcode = {
-- description = 'Run VectorCode to retrieve the project context.',
-- callback = require('vectorcode.integrations').codecompanion.chat.make_tool(),
-- },
['cmd_runner'] = {
opts = {
requires_approval = false,
},
},
},
roles = {
---@type string|fun(adapter: CodeCompanion.Adapter): string
llm = function(adapter)
return 'CodeCompanion (' .. adapter.formatted_name .. ': ' .. adapter.parameters.model .. ')'
end,
},
keymaps = {
send = {
modes = { n = '<C-s>', i = '<C-s>' },
},
close = {
modes = { n = '<C-c>', i = '<C-c>' },
},
},
},
inline = {
adapter = {
name = 'default',
model = vim.env.FAST_MODEL,
},
},
cmd = {
adapter = {
name = 'default',
model = vim.env.FAST_MODEL,
},
},
},
extensions = {
mcphub = {
callback = 'mcphub.extensions.codecompanion',
opts = {
show_result_in_chat = true,
make_vars = true,
make_slash_commands = true,
},
},
},
system_prompt = function(opts)
local language = opts.language or 'English'
return string.format(
[[You are an AI programming assistant named "CodeCompanion". You are currently plugged into the Neovim text editor on a user's machine.
Your core tasks include:
- Answering general programming questions.
- Explaining how the code in a Neovim buffer works.
- Reviewing the selected code from a Neovim buffer.
- Generating unit tests for the selected code.
- Proposing fixes for problems in the selected code.
- Scaffolding code for a new workspace.
- Finding relevant code to the user's query.
- Proposing fixes for test failures.
- Answering questions about Neovim.
- Running tools.
You must:
- Follow the user's requirements carefully and to the letter.
- Keep your answers short and impersonal, especially if the user's context is outside your core tasks.
- Minimize additional prose unless clarification is needed.
- Use Markdown formatting in your answers.
- Include the programming language name at the start of each Markdown code block.
- Avoid including line numbers in code blocks.
- Avoid wrapping the whole response in triple backticks.
- Only return code that's directly relevant to the task at hand. You may omit code that isnt necessary for the solution.
- Avoid using H1, H2 or H3 headers in your responses as these are reserved for the user.
- Use actual line breaks in your responses; only use "\n" when you want a literal backslash followed by 'n'.
- All non-code text responses must be written in the %s language indicated.
- Multiple, different tools can be called as part of the same response.
- Use full path names when using tools to read and modify files.
When given a task:
1. Think step-by-step and, unless the user requests otherwise or the task is very simple, describe your plan in detailed pseudocode.
2. Output the final code in a single code block, ensuring that only relevant code is included.
3. End your response with a short suggestion for the next user turn that directly supports continuing the conversation.
4. Provide exactly one complete reply per conversation turn.
5. If necessary, execute multiple tools in a single turn.]],
language
)
end,
prompt_library = {
['Code Expert'] = {
strategy = 'chat',
description = 'Get some special advice from an LLM.',
opts = {
mapping = '<Leader>ce',
modes = { 'v' },
short_name = 'expert',
auto_submit = true,
stop_context_insertion = true,
user_prompt = true,
},
prompts = {
{
role = 'system',
content = function(context)
return 'I want you to act as a senior'
.. context.filetype
.. 'developer I will ask you specific questions and I want you to return concise explanations and codeblock examples.'
end,
},
{
role = 'user',
content = function(context)
local text = require('codecompanion.helpers.actions').get_code(context.start_line, context.end_line)
return 'I have the following code:\n\n```' .. context.filetype .. '\n' .. text .. '\n```\n\n'
end,
opts = {
contains_code = true,
},
},
},
},
['Games Master'] = {
strategy = 'chat',
description = 'A personal Games Master Assistant.',
opts = {
user_prompt = false,
},
prompts = {
{
role = 'system',
content = [[
You are a personal Games Master Assistant. You are currently plugged in to the Neovim text editor on a user's machine.
Your core tasks include:
- Crafting engaging role playing sessions
- Building immersive and authentic worlds
- Creating compelling characters for the players to interact with and drive the story
- Reviewing session summaries and building on them
- Providing advice on how to bring sessions to life
- Create exciting encounters to challenge the players
- Encounters can be combat, social, or exploration based
- There should always be a story reason for the encounter
- Combine player character backgrounds and motivations into the world
- Build tension and drama into the game
- Ensure each session provides opportunities for the players to engage with and drive the story
You must:
- Follow the user's requirements carefully and to the letter.
- Keep answers focused on the task at hand.
- Provide original ideas and suggestions.
- Use Markdown formatting in your answers.
- Use actual line breaks instead of '\n' in your response to begin new lines.
- Use '\n' only when you want a literal backslash followed by a character 'n'.
- All responses must be written in English.
- Multiple, different tools can be called as part of the same response.
- Help sessions be fast paced and fun.
- Ensure there are multiple soltuions to each problem.
- Avoid railroading the players.
When given a task:
1. Consider the existing world and characters. Use tools to gather information that may be relevant.
2. Provide exactly one complete reply per conversation turn.
3. If necessary, execute multiple tools in a single turn.
]],
},
{
role = 'user',
content = '',
},
},
},
['PHPStan Fixer'] = {
strategy = 'workflow',
description = 'Use a workflow to fix PHPStan errors until there are none left.',
opts = {
short_name = 'phpstan',
},
prompts = {
{
{
name = 'Run PHPStan',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return [[PHPStan is a static analysis tool for PHP. It is currently reporting errors in the code. Your task is to fix these errors and run PHPStan again until there are no errors left.
First of all use the @cmd_runner tool to run the `composer type-check` command. This will run PHPStan and output type errors in the code.]]
end,
},
},
{
{
name = 'Fetch files',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return 'PHPStan has reported errors. Look at the output and see where the files are reported. Use the @mcp tool to read all the offending files so you can implement the fixes.'
end,
},
},
{
{
name = 'Fix errors and run',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return [[### Instructions
Now you have the errors and the appropriate context you can fix the errors.
### Steps to Follow
You are required to analyse the PHPStan errors and write code to fix them.
Reason through the errors and write out the possible causes and fixes for each.
1. Then use the @mcp tool to update the files with the fixes. When editing files use the full path name including the project name /Users/chris/Code/Sites/hylark/
2. After editing the files use the @cmd_runner tool again to run the `composer type-check` command to see if any errors remain.
We'll repeat this cycle until there are no errors. Ensure no deviations from these steps.
### Tips for fixing PHPStan errors
- Do not ignore the errors
- Use Webmozart Assert library to narrow types
- Most errors are due to missing docblocks or calling methods/parameters on types that PHPStan cannot infer
- Use fully qualified namespaces for classes in doc blocks
- The code is working so fixes should not change the behaviour of the code
- There are some custom types in this project that help define types
- closure<T> creates T|Closure(): T, you can add a second argument to specify the depth so closure<T, 2> creates T|Closure(): T|Closure(): (Closure(): T). This is useful because GraphQL queries can return closures.
- promise<T> creates T|SyncPromise<T>, as with closure, you can add a second argument for depth. You can also add a third argument if T is an array to allow adding promises to each value, so promise<array{a: int}, 1, 1> will create array{a: int}|SyncPromise<array{a: int}>|array{a: SyncPromise<int>}|SyncPromise<array{a: SyncPromise<int>}>. This is useful because GraphQL queries can return promises and arrays of promises.
- GraphQL schema types (these should only be used in the Query classes)
- GArgs<T> will look at the GraphQL schema and create an array type for the arguments of a field on one of the root types (Query or Mutation)
- GArgs<TType, TField> will create a type for the arguments of a field on a type
- GType<T> will create an type for a specific GraphQL type, input, interface, or enum
- GVal<T> will create a type for the return value of a field on one of the root types (Query or Mutation)
- GVal<TType, TField> will create a type for the return value of a field on a type
- pick<T, TKeys> will create an array from T with only the keys in TKeys (e.g. pick<array{a: int, b: int, c: int}, 'a'|'b'> will create array{a: int, b: int})
- except<T, TKeys> works like pick only it excludes the keys in TKeys (e.g. except<array{a: int, b: int, c: int}, 'a'|'b'> will create array{c: int})
- union<T, U> creates a union array of T and U (e.g. union<array{a: int}, array{b: int}> will create array{a: int, b: int})]]
end,
},
},
{
{
name = 'Repeat On Failure',
role = 'user',
opts = { auto_submit = false },
-- Scope this prompt to the cmd_runner tool
condition = function()
return _G.codecompanion_current_tool == 'cmd_runner'
end,
-- Repeat until the tests pass, as indicated by the testing flag
-- which the cmd_runner tool sets on the chat buffer
repeat_until = function(chat)
-- Check if the last message in the chat buffer contains "[ERROR] found"
local messages = chat.messages
local last_message = messages[#messages]
if last_message and last_message.role == 'assistant' then
local content = last_message.content
return not content:find '[ERROR] found'
end
return true
end,
content = 'PHPStan is still reporting errors. Edit the code to fix the errors and run PHPStan again.',
},
},
},
},
},
}
end,
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-treesitter/nvim-treesitter',
-- 'Davidyz/VectorCode',
'ravitemer/mcphub.nvim',
},
}
+13 -8
View File
@@ -4,19 +4,24 @@ return {
-- change the command in the config to whatever the name of that colorscheme is. -- change the command in the config to whatever the name of that colorscheme is.
-- --
-- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`. -- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`.
'AlphaTechnolog/pywal.nvim',
dependencies = {
'folke/tokyonight.nvim', 'folke/tokyonight.nvim',
},
priority = 1000, -- Make sure to load this before all the other start plugins. priority = 1000, -- Make sure to load this before all the other start plugins.
config = function() config = function()
---@diagnostic disable-next-line: missing-fields ---@diagnostic disable-next-line: missing-fields
require('tokyonight').setup { require('tokyonight').setup()
styles = {
comments = { italic = false }, -- Disable italics in comments
},
}
-- Load the colorscheme here.
-- Like many other themes, this one has different styles, and you could load
-- any other, such as 'tokyonight-storm', 'tokyonight-moon', or 'tokyonight-day'.
vim.cmd.colorscheme 'tokyonight-night' vim.cmd.colorscheme 'tokyonight-night'
-- Check if wal directory exists otherwise use tokyo
local handle = io.popen 'ls -d $HOME/.cache/wal 2>/dev/null'
local result = handle:read '*a'
handle:close()
if result ~= '' then
require('pywal').setup()
end
end, end,
} }
-44
View File
@@ -1,44 +0,0 @@
return { -- Autoformat
'stevearc/conform.nvim',
event = { 'BufWritePre' },
cmd = { 'ConformInfo' },
keys = {
{
'<leader>f',
function()
require('conform').format { async = true, lsp_format = 'fallback' }
end,
mode = '',
desc = '[F]ormat buffer',
},
},
config = function()
require('conform').setup({
notify_on_error = false,
format_on_save = function(bufnr)
-- Disable "format_on_save lsp_fallback" for languages that don't
-- have a well standardized coding style. You can add additional
-- languages here or re-enable it for the disabled ones.
local disable_filetypes = { c = true, cpp = true, vue = true, js = true }
if disable_filetypes[vim.bo[bufnr].filetype] then
return nil
else
return {
timeout_ms = 500,
lsp_format = 'fallback',
}
end
end,
formatters_by_ft = {
lua = { 'stylua' },
php = { 'pint' },
-- Conform can also run multiple formatters sequentially
-- python = { "isort", "black" },
--
-- You can use 'stop_after_first' to run the first available formatter from the list
-- javascript = { "prettierd", "prettier", stop_after_first = true },
},
log_level = vim.log.levels.DEBUG
})
end
}
-34
View File
@@ -180,40 +180,6 @@ return {
vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl }) vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl })
end end
local function get_php_ini_dir()
local handle = io.popen 'php --ini 2>/dev/null'
if not handle then
return nil
end
local result = handle:read '*a'
handle:close()
local dir = result:match 'Scan for additional .ini files in:%s+([^\n]+)'
if dir and dir:find '%(none%)' == nil then
return vim.trim(dir)
end
return nil
end
local function enable_xdebug()
local ini_dir = get_php_ini_dir()
if not ini_dir then
return
end
os.execute(string.format('mv "%s/20-xdebug.ini.disabled" "%s/20-xdebug.ini" 2>/dev/null', ini_dir, ini_dir))
end
local function disable_xdebug()
local ini_dir = get_php_ini_dir()
if not ini_dir then
return
end
os.execute(string.format('mv "%s/20-xdebug.ini" "%s/20-xdebug.ini.disabled" 2>/dev/null', ini_dir, ini_dir))
end
dap.listeners.after.event_initialized['xdebug_enable'] = enable_xdebug
dap.listeners.before.event_terminated['xdebug_disable'] = disable_xdebug
dap.listeners.before.event_exited['xdebug_disable'] = disable_xdebug
-- dap.listeners.after.event_output['neotest_display'] = function(_, body) -- dap.listeners.after.event_output['neotest_display'] = function(_, body)
-- require('neotest').output.open { enter = true, last = true } -- require('neotest').output.open { enter = true, last = true }
-- end -- end
+18 -4
View File
@@ -13,9 +13,10 @@ return {
'saghen/blink.cmp', 'saghen/blink.cmp',
'folke/lazydev.nvim', 'folke/lazydev.nvim',
}, },
build = function() -- Might not be necessary for phpantom
vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer' -- build = function()
end, -- vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer'
-- end,
config = function() config = function()
-- This function gets run when an LSP attaches to a particular buffer. -- This function gets run when an LSP attaches to a particular buffer.
-- That is to say, every time a new file is opened that is associated with -- That is to say, every time a new file is opened that is associated with
@@ -115,6 +116,12 @@ return {
}, },
} }
-- vim.lsp.config['phpantom'] = {
-- filetypes = { 'php' },
-- cmd = { 'phpantom_lsp' },
-- root_markers = { 'composer.json', '.git' },
-- }
-- Enable the following language servers -- Enable the following language servers
-- --
-- Add any additional override configuration in the following tables. Available keys are: -- Add any additional override configuration in the following tables. Available keys are:
@@ -139,7 +146,11 @@ return {
}, },
}, },
}, },
phpactor = {}, phpantom_lsp = {
filetypes = { 'php' },
cmd = { 'phpantom_lsp' },
root_markers = { 'composer.json', '.git' },
},
vtsls = { vtsls = {
settings = { settings = {
vtsls = { vtsls = {
@@ -195,6 +206,9 @@ return {
local ensure_installed = vim.tbl_keys(servers or {}) local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, { vim.list_extend(ensure_installed, {
'stylua', -- Used to format Lua code 'stylua', -- Used to format Lua code
'blade-formatter',
'eslint_d',
'pint',
}) })
-- LSP servers and clients are able to communicate to each other what features they support. -- LSP servers and clients are able to communicate to each other what features they support.
+1 -1
View File
@@ -1,7 +1,7 @@
-- Filesystem manager -- Filesystem manager
-- require('helpers').edit_cf('po', '/lua/plugins/oil.lua') -- require('helpers').edit_cf('po', '/lua/plugins/oil.lua')
-- --
-- vim.keymap.set('n', '-', '<CMD>Oil<CR>', { desc = 'Open parent directory' }) vim.keymap.set('n', '-', '<CMD>Oil<CR>', { desc = 'Open parent directory' })
return { return {
'stevearc/oil.nvim', 'stevearc/oil.nvim',
+3
View File
@@ -0,0 +1,3 @@
return {
'AlphaTechnolog/pywal.nvim',
}
+7 -7
View File
@@ -1,9 +1,9 @@
return { return {
"ThePrimeagen/refactoring.nvim", -- "ThePrimeagen/refactoring.nvim",
dependencies = { -- dependencies = {
"nvim-lua/plenary.nvim", -- "nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter", -- "nvim-treesitter/nvim-treesitter",
}, -- },
lazy = false, -- lazy = false,
opts = {}, -- opts = {},
} }
+11 -1
View File
@@ -5,6 +5,16 @@ return {
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons
---@module 'render-markdown' ---@module 'render-markdown'
---@type render.md.UserConfig ---@type render.md.UserConfig
opts = {},
ft = { 'markdown', 'codecompanion' }, ft = { 'markdown', 'codecompanion' },
config = function()
require('render-markdown').setup {
latex = {
enabled = true,
render_modes = true,
},
anti_conceal = {
enabled = false,
},
}
end,
} }
+27
View File
@@ -0,0 +1,27 @@
require('helpers').edit_cf('pt', '/lua/plugins/test.lua')
return {
'nvim-neotest/neotest',
dependencies = {
'V13Axel/neotest-pest',
},
config = function()
require('neotest').setup {
adapters = {
require 'neotest-pest' {
sail_enabled = function()
return false
end,
parallel = 8,
pest_cmd = function()
local cmd = vim.g.neotest_pest_cmd or { 'vendor/bin/pest' }
if vim.g.neotest_debug then
cmd = { 'sh', '-c', 'XDEBUG_MODE=debug exec ' .. table.concat(cmd, ' ') .. ' "$@"' }
end
return cmd
end,
},
},
}
end,
}
-86
View File
@@ -1,86 +0,0 @@
return {
'nvim-treesitter/nvim-treesitter-textobjects',
dependencies = {
'nvim-treesitter/nvim-treesitter',
},
lazy = false,
enabled = true,
config = function()
require('nvim-treesitter.configs').setup {
incremental_selection = {
enable = true,
keymaps = {
-- mappings for incremental selection (visual mappings)
init_selection = 'gnn', -- maps in normal mode to init the node/scope selection
node_incremental = 'grn', -- increment to the upper named parent
scope_incremental = 'grc', -- increment to the upper scope (as defined in locals.scm)
node_decremental = 'grm', -- decrement to the previous node
},
},
textobjects = {
-- syntax-aware textobjects
enable = true,
keymaps = {
['iL'] = {
-- you can define your own textobjects directly here
go = '(function_definition) @function',
},
-- or you use the queries from supported languages with textobjects.scm
['af'] = '@function.outer',
['if'] = '@function.inner',
['aC'] = '@class.outer',
['iC'] = '@class.inner',
['ay'] = '@conditional.outer',
['iy'] = '@conditional.inner',
['aj'] = '@loop.outer',
['ij'] = '@loop.inner',
['is'] = '@statement.inner',
['as'] = '@statement.outer',
['ac'] = '@comment.outer',
['ic'] = '@comment.inner',
['ap'] = '@comment.parameter',
['ip'] = '@comment.parameter',
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
[']m'] = '@function.outer',
[']]'] = '@class.outer',
},
goto_next_end = {
[']M'] = '@function.outer',
[']['] = '@class.outer',
},
goto_previous_start = {
['[m'] = '@function.outer',
['[['] = '@class.outer',
},
goto_previous_end = {
['[M'] = '@function.outer',
['[]'] = '@class.outer',
},
},
select = {
enable = true,
keymaps = {
-- You can use the capture groups defined in textobjects.scm
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
-- Or you can define your own textobjects like this
['iF'] = {
python = '(function_definition) @function',
cpp = '(function_definition) @function',
c = '(function_definition) @function',
java = '(method_declaration) @function',
go = '(method_declaration) @function',
},
},
},
},
}
end,
}
+23 -21
View File
@@ -1,15 +1,17 @@
-- Highlight, edit, and navigate code -- Highlight, edit, and navigate code
return { return {
'nvim-treesitter/nvim-treesitter', 'nvim-treesitter/nvim-treesitter',
branch = 'main',
build = ':TSUpdate', build = ':TSUpdate',
main = 'nvim-treesitter.configs', -- Sets main module to use for opts
-- [[ Configure Treesitter ]] See `:help nvim-treesitter` -- [[ Configure Treesitter ]] See `:help nvim-treesitter`
opts = { config = function()
ensure_installed = { local langs = {
'bash', 'bash',
'zsh',
'c', 'c',
'diff', 'diff',
'html', 'html',
'latex',
'lua', 'lua',
'luadoc', 'luadoc',
'markdown', 'markdown',
@@ -17,22 +19,22 @@ return {
'query', 'query',
'vim', 'vim',
'vimdoc', 'vimdoc',
}, 'php',
-- Autoinstall languages that are not installed 'yaml',
auto_install = true, 'vue',
highlight = { 'javascript',
enable = true, 'typescript',
-- Some languages depend on vim's regex highlighting system (such as Ruby) for indent rules. 'css',
-- If you are experiencing weird indenting issues, add the language to 'blade',
-- the list of additional_vim_regex_highlighting and disabled languages for indent. }
additional_vim_regex_highlighting = { 'ruby' }, require('nvim-treesitter').install(langs)
},
indent = { enable = true, disable = { 'ruby' } }, vim.api.nvim_create_autocmd('FileType', {
}, pattern = langs,
-- There are additional nvim-treesitter modules that you can use to interact callback = function()
-- with nvim-treesitter. You should go explore a few and see what interests you: vim.treesitter.start()
-- vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
-- - Incremental selection: Included, see `:help nvim-treesitter-incremental-selection-mod` end,
-- - Show your current context: https://github.com/nvim-treesitter/nvim-treesitter-context })
-- - Treesitter + textobjects: https://github.com/nvim-treesitter/nvim-treesitter-textobjects end,
} }
-6
View File
@@ -8,12 +8,6 @@ return {
}, },
keys = { keys = {
-- 👇 in this section, choose your own keymappings! -- 👇 in this section, choose your own keymappings!
{
'-',
mode = { 'n', 'v' },
'<cmd>Yazi<cr>',
desc = 'Open yazi at the current file',
},
{ {
-- Open in the current working directory -- Open in the current working directory
'\\', '\\',
+86 -33
View File
@@ -92,39 +92,39 @@ end
local function laravel_bookmarks_with_dir(dir) local function laravel_bookmarks_with_dir(dir)
create_bookmark_maps { create_bookmark_maps {
['e'] = dir .. '/.env', ['e'] = dir .. '.env',
['l'] = dir .. '/storage/logs/laravel.log', ['l'] = dir .. 'storage/logs/laravel.log',
['w'] = dir .. '/routes/web.php', ['w'] = dir .. 'routes/web.php',
['a'] = dir .. '/routes/api.php', ['a'] = dir .. 'routes/api.php',
['m'] = dir .. '/database/migrations', ['m'] = dir .. 'database/migrations',
['dc'] = dir .. '/app/Core/', ['dc'] = dir .. 'app/Core/',
['dd'] = dir .. '/app/Data/', ['dd'] = dir .. 'app/Data/',
['dE'] = dir .. '/app/Enums/', ['dE'] = dir .. 'app/Enums/',
['de'] = dir .. '/app/Events/', ['de'] = dir .. 'app/Events/',
['dh'] = dir .. '/app/Http/', ['dh'] = dir .. 'app/Http/',
['dj'] = dir .. '/app/Jobs/', ['dj'] = dir .. 'app/Jobs/',
['dl'] = dir .. '/app/Listeners/', ['dl'] = dir .. 'app/Listeners/',
['dM'] = dir .. '/app/Mail/', ['dM'] = dir .. 'app/Mail/',
['dm'] = dir .. '/app/Models/', ['dm'] = dir .. 'app/Models/',
['dn'] = dir .. '/app/Notifications/', ['dn'] = dir .. 'app/Notifications/',
['do'] = dir .. '/app/Observers/', ['do'] = dir .. 'app/Observers/',
['dp'] = dir .. '/app/Providers/', ['dp'] = dir .. 'app/Providers/',
['pa'] = dir .. '/app/Providers/AppServiceProvider.php', ['pa'] = dir .. 'app/Providers/AppServiceProvider.php',
['pe'] = dir .. '/app/Providers/EventServiceProvider.php', ['pe'] = dir .. 'app/Providers/EventServiceProvider.php',
['cA'] = dir .. '/config/app.php', ['cA'] = dir .. 'config/app.php',
['ca'] = dir .. '/config/auth.php', ['ca'] = dir .. 'config/auth.php',
['cb'] = dir .. '/config/broadcasting.php', ['cb'] = dir .. 'config/broadcasting.php',
['cd'] = dir .. '/config/database.php', ['cd'] = dir .. 'config/database.php',
['cf'] = dir .. '/config/filesystems.php', ['cf'] = dir .. 'config/filesystems.php',
['ch'] = dir .. '/config/filesystems.php', ['ch'] = dir .. 'config/filesystems.php',
['cl'] = dir .. '/config/logging.php', ['cl'] = dir .. 'config/logging.php',
['cm'] = dir .. '/config/mail.php', ['cm'] = dir .. 'config/mail.php',
['cq'] = dir .. '/config/queue.php', ['cq'] = dir .. 'config/queue.php',
['cS'] = dir .. '/config/services.php', ['cS'] = dir .. 'config/services.php',
['cs'] = dir .. '/config/session.php', ['cs'] = dir .. 'config/session.php',
} }
end end
@@ -216,8 +216,8 @@ local PROJECTS = {
end, { desc = 'Open database manager' }) end, { desc = 'Open database manager' })
map('s ', '!cd server && ', { desc = 'Run command in server directory' }, 'c') map('s ', '!cd server && ', { desc = 'Run command in server directory' }, 'c')
map('c ', '!cd client && ', { desc = 'Run command in client directory' }, 'c') map('c ', '!cd client && ', { desc = 'Run command in client directory' }, 'c')
laravel_keymaps 'server' laravel_keymaps 'server/'
laravel_makes 'server' laravel_makes 'server/'
map('yrn ', '!cd client && yarn ', { desc = 'Run yarn script' }, 'c') map('yrn ', '!cd client && yarn ', { desc = 'Run yarn script' }, 'c')
map('<Leader>pt', ':!cd server && php artisan typescript:transform --format<CR>', { desc = 'Compile typescript' }) map('<Leader>pt', ':!cd server && php artisan typescript:transform --format<CR>', { desc = 'Compile typescript' })
require('conform').formatters.pint = { require('conform').formatters.pint = {
@@ -226,6 +226,13 @@ local PROJECTS = {
}, },
} }
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
pattern = { '*.php' },
callback = function(args)
require('helpers').format_buffer('eslint_d', args.buf)
end,
})
create_bookmark('E', dir .. '/client/src/types/api/endpointMap.d.ts') create_bookmark('E', dir .. '/client/src/types/api/endpointMap.d.ts')
create_bookmark('q', dir .. '/client/quasar.config.ts') create_bookmark('q', dir .. '/client/quasar.config.ts')
create_bookmark('db', dir .. '/client/src/boot') create_bookmark('db', dir .. '/client/src/boot')
@@ -242,6 +249,49 @@ local PROJECTS = {
laravel_makes() laravel_makes()
map('yrn ', '!cd frontend && yarn ', { desc = 'Run yarn script' }, 'c') map('yrn ', '!cd frontend && yarn ', { desc = 'Run yarn script' }, 'c')
map('<Leader>pm', ':vendor/bin/sail composer migrate<CR>') map('<Leader>pm', ':vendor/bin/sail composer migrate<CR>')
vim.api.nvim_create_autocmd({ 'BufWritePost' }, {
pattern = { '*.php', '.env', '.graphql' },
callback = function()
if not vim.fn.expand('%:p'):match(dir .. '/server/') then
vim.fn.jobstart('vendor/bin/sail artisan octane:reload', { stdout_buffered = true })
vim.fn.jobstart('vendor/bin/sail artisan horizon:terminate', { stdout_buffered = true })
end
if vim.fn.search '#\\[TypeScript\\]' ~= 0 then
vim.fn.jobstart('php artisan typescript:transform', { cwd = dir .. '/server', stdout_buffered = true })
end
end,
})
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
pattern = { '*.js', '*.ts', '*.vue' },
callback = function(args)
vim.env.ESLINT_D_PPID = vim.fn.getpid()
local cwd = vim.fn.getcwd()
if vim.fn.expand('%:p'):match(dir .. '/frontend2/') then
cwd = dir .. '/frontend2/'
end
require('helpers').format_buffer('eslint_d', args.buf, cwd)
end,
})
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
pattern = { '*.php' },
callback = function(args)
local cwd = vim.fn.getcwd()
if vim.fn.expand('%:p'):match(dir .. '/server/') then
cwd = dir .. '/server/'
end
require('helpers').format_buffer('pint', args.buf, cwd)
end,
})
vim.api.nvim_create_autocmd({ 'BufWritePost' }, {
pattern = { '.graphql' },
callback = function()
vim.fn.jobstart('vendor/bin/sail artisan lighthouse:clear-cache', { stdout_buffered = true })
end,
})
end, end,
default = function() end, default = function() end,
@@ -257,10 +307,12 @@ function M.apply(cwd)
end end
last_applied = name last_applied = name
local setup = PROJECTS[name] or PROJECTS.default local setup = PROJECTS[name]
if type(setup) == 'function' then if type(setup) == 'function' then
setup(dir) setup(dir)
vim.notify(('Project config loaded: %s'):format(name), vim.log.levels.INFO, { title = 'projects.lua' }) vim.notify(('Project config loaded: %s'):format(name), vim.log.levels.INFO, { title = 'projects.lua' })
else
PROJECTS.default(dir)
end end
end end
@@ -292,3 +344,4 @@ end, {})
-- Keep your helper line -- Keep your helper line
require('helpers').edit_cf('w', '/lua/projects.lua') require('helpers').edit_cf('w', '/lua/projects.lua')
+113 -30
View File
@@ -1,45 +1,128 @@
local ls = require 'luasnip' local ls = require 'luasnip'
local s = ls.snippet local s = ls.snippet
local sn = ls.snippet_node
local fn = ls.function_node
local ms = ls.multi_snippet
local t = ls.text_node local t = ls.text_node
local c = ls.choice_node
local i = ls.insert_node local i = ls.insert_node
local f = ls.function_node local f = ls.function_node
local d = ls.dynamic_node
local fmt = require('luasnip.extras.fmt').fmt
local rep = require('luasnip.extras').rep
local extend_decorator = require 'luasnip.util.extend_decorator'
local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
local utils = require 'snippets.snip_utils'
local tr = utils.tr
local etr = utils.etr
local atr = utils.atr
local ctr = utils.ctr
local bs = utils.bs
return { return {
s('du', { t 'console.log(', i(0), t ');' }), s(etr('du ', 'Dump a variable to the console'), fmta('console.log(#~);', { i(0) })),
s(
etr('vue', 'Vue Single File Component skeleton'),
fmta(
[[
<template>
</template>
<script setup>
#~
</script>
<style scoped>
</style>
]],
{ i(0) }
)
),
s('vue', { -- bs(atr('t ', 'this'), fmta('this.#~', { i(0) })),
t { '<template>', '' },
t { '', '</template>', '', '', '<script setup>', '' }, s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })),
i(0), s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })),
t { '', '</script>', '', '', '<style scoped>', '', '.o-share-page {', '}', '', '</style>' },
s(etr('const ', 'const declaration'), {
c(1, {
sn(nil, fmta('const #~ = #~;', { i(1, 'variableName'), i(2, 'value') })),
sn(
nil,
fmta(
[[
const #~ = (#~) => {
#~
}
]],
{ i(1), i(2), i(3) }
)
),
}),
}), }),
s('fun', { s(
t 'function ', etr('fn ', 'function block'),
i(1), fmta(
t '(', [[
i(2), function #~(#~) {
t ') {', #~
t { '', ' ' }, }
i(0), ]],
t { '', '}' }, { i(1), i(2), i(0) }
)
),
bs(atr('fn ', 'function block'), {
c(1, {
sn(
nil,
fmta(
[[
(#~) => {
#~
}
]],
{ i(1), i(2) }
)
),
sn(
nil,
fmta(
[[
function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}),
}), }),
s('afun', { bs(atr('afn ', 'async function block'), {
t 'async function ', c(1, {
i(1), sn(
t '(', nil,
i(2), fmta(
t ') {', [[
t { '', ' ' }, async (#~) => {
i(0), #~
t { '', '}' }, }
]],
{ i(1), i(2) }
)
),
sn(
nil,
fmta(
[[
async function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}), }),
s('()', {
t '() => {',
t { '', ' ' },
i(0),
t { '', '}' },
}), }),
} }
+157 -140
View File
@@ -16,6 +16,7 @@ local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
local utils = require 'snippets.snip_utils' local utils = require 'snippets.snip_utils'
local tr = utils.tr local tr = utils.tr
local etr = utils.etr local etr = utils.etr
local Etr = utils.Etr
local atr = utils.atr local atr = utils.atr
local ctr = utils.ctr local ctr = utils.ctr
local bs = utils.bs local bs = utils.bs
@@ -69,10 +70,10 @@ return {
--------------- ---------------
-- DEBUGGING -- -- DEBUGGING --
--------------- ---------------
s(etr('du ', 'Dump a variable to the dump server'), fmta('dump(#~);', { i(0) })), s(etr('du ', 'Dump a variable to the dump server', { priority = 1001 }), fmta('dump(#~);', { i(0) })),
bs(atr('du ', 'Dump a variable to the dump server'), fmta('dump(#~)', { i(0) })), bs(etr('du ', 'Dump a variable to the dump server'), fmta('dump(#~)', { i(0) })),
s(etr('r ', 'ray'), fmta('ray(#~);', { i(0) })), s(etr('r ', 'ray', { priority = 1001 }), fmta('ray(#~);', { i(0) })),
bs(atr('r ', 'ray'), fmta('ray(#~)', { i(0) })), bs(etr('r ', 'ray'), fmta('ray(#~)', { i(0) })),
s(etr('dt ', 'Dump PHPStan type definition'), fmta('\\PhpStan\\dumpType(#~);', { i(0) })), s(etr('dt ', 'Dump PHPStan type definition'), fmta('\\PhpStan\\dumpType(#~);', { i(0) })),
s( s(
etr('ql ', 'Log all queries'), etr('ql ', 'Log all queries'),
@@ -107,6 +108,7 @@ return {
}), }),
s(etr('@v', '@var docblock'), fmta('/** @var #~ $#~ */', { i(1), i(0) })), s(etr('@v', '@var docblock'), fmta('/** @var #~ $#~ */', { i(1), i(0) })),
s(ctr('@v', '@var docblock'), fmta('@var #~ $#~', { i(1), i(0) })), s(ctr('@v', '@var docblock'), fmta('@var #~ $#~', { i(1), i(0) })),
s(Etr('@pi', '@phpstan-ignore'), fmta('// @phpstan-ignore #~ (#~)', { i(1), i(0) })),
s(ctr('* @pr', 'Class property docblock'), fmta('* @property #~ $#~', { i(1), i(0) })), s(ctr('* @pr', 'Class property docblock'), fmta('* @property #~ $#~', { i(1), i(0) })),
s(ctr('* @pb', 'Class boolean property docblock'), fmta('* @property bool $#~', { i(0) })), s(ctr('* @pb', 'Class boolean property docblock'), fmta('* @property bool $#~', { i(0) })),
s(ctr('* @pi', 'Class int property docblock'), fmta('* @property int $#~', { i(0) })), s(ctr('* @pi', 'Class int property docblock'), fmta('* @property int $#~', { i(0) })),
@@ -168,9 +170,9 @@ return {
) )
), ),
s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })), s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })),
s(atr(' use ', 'Add use to function'), fmta(' use (#~)', { i(0) })), -- s(atr(' use ', 'Add use to function'), fmta(' use (#~)', { i(0) })),
s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })), s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })),
bs(etr('fn ', 'Shorthand function block'), { bs(atr('fn ', 'Shorthand function block'), {
c(1, { c(1, {
sn(nil, fmta('fn (#~) => #~', { i(1), i(2) })), sn(nil, fmta('fn (#~) => #~', { i(1), i(2) })),
sn( sn(
@@ -186,7 +188,7 @@ return {
), ),
}), }),
}), }),
bs(etr('fun ', 'Shorthand function block'), { bs(atr('fun ', 'Shorthand function block'), {
c(1, { c(1, {
sn( sn(
nil, nil,
@@ -212,36 +214,36 @@ return {
), ),
}), }),
}), }),
s( -- s(
etr('con', 'Constructor function block'), -- etr('con', 'Constructor function block'),
c(1, { -- c(1, {
sn( -- sn(
nil, -- nil,
fmta( -- fmta(
[[ -- [[
public function __construct(#~) -- public function __construct(#~)
{ -- {
#~ -- #~
} -- }
]], -- ]],
{ i(1), i(2) } -- { i(1), i(2) }
) -- )
), -- ),
sn( -- sn(
nil, -- nil,
fmta( -- fmta(
[[ -- [[
public function __construct( -- public function __construct(
#~ -- #~
) { -- ) {
#~ -- #~
} -- }
]], -- ]],
{ i(1), i(2) } -- { i(1), i(2) }
) -- )
), -- ),
}) -- })
), -- ),
bs(atr('function', 'Shorthand function block'), fmta('fun', {})), bs(atr('function', 'Shorthand function block'), fmta('fun', {})),
bs(atr('s%$', 'string type parameter'), fmta('string $#~', { i(0, 'var') })), bs(atr('s%$', 'string type parameter'), fmta('string $#~', { i(0, 'var') })),
bs(atr('i%$', 'int type parameter'), fmta('int $#~', { i(0, 'var') })), bs(atr('i%$', 'int type parameter'), fmta('int $#~', { i(0, 'var') })),
@@ -358,20 +360,35 @@ return {
etr('test', 'Create a test function'), etr('test', 'Create a test function'),
fmta( fmta(
[[ [[
test(#~ function () { test('#~', function () {
#~ #~
}) });
]], ]],
{ i(1), i(0) } { i(1), i(0) }
) )
), ),
s(etr('nn ', 'Assert not null'), fmta('Assert::notNull(#~)', { i(0) })), s(
etr('it ', 'Create a test function'),
fmta(
[[
it('#~', function () {
#~
});
]],
{ i(1), i(0) }
)
),
s(etr('nn ', 'Assert not null'), fmta('Assert::notNull(#~);', { i(0) })),
s(etr('ast ', 'Assert string'), fmta('Assert::string(#~);', { i(0) })),
s(etr('ain ', 'Assert integer'), fmta('Assert::integer(#~);', { i(0) })),
s(etr('aio ', 'Assert instance of'), fmta('Assert::isInstanceOf(#~);', { i(0) })),
s(etr('at ', 'Assert true'), fmta('Assert::true(#~);', { i(0) })),
------------- -------------
-- LARAVEL -- -- LARAVEL --
------------- -------------
s( s(
etr('bt', 'belongsTo Laravel relationship method'), etr('bt', 'belongsTo Laravel relationship method'),
c(0, { c(1, {
sn( sn(
nil, nil,
fmta( fmta(
@@ -384,7 +401,7 @@ return {
return $this->belongsTo(#~::class); return $this->belongsTo(#~::class);
} }
]], ]],
{ rep(1), i(0), i(1) } { rep(1), i(2), i(1) }
) )
), ),
sn( sn(
@@ -399,14 +416,14 @@ return {
return $this->belongsTo(#~::class, #~); return $this->belongsTo(#~::class, #~);
} }
]], ]],
{ rep(1), i(2), i(1), i(0) } { rep(1), i(2), i(1), i(3) }
) )
), ),
}) })
), ),
s( s(
etr('hm', 'hasMany Laravel relationship method'), etr('hm', 'hasMany Laravel relationship method'),
c(0, { c(1, {
sn( sn(
nil, nil,
fmta( fmta(
@@ -419,7 +436,7 @@ return {
return $this->hasOne(#~::class); return $this->hasOne(#~::class);
} }
]], ]],
{ rep(1), i(0), i(1) } { rep(1), i(2), i(1) }
) )
), ),
sn( sn(
@@ -434,14 +451,14 @@ return {
return $this->hasOne(#~::class, #~); return $this->hasOne(#~::class, #~);
} }
]], ]],
{ rep(1), i(2), i(1), i(0) } { rep(1), i(2), i(1), i(3) }
) )
), ),
}) })
), ),
s( s(
etr('ho', 'hasOne Laravel relationship method'), etr('ho', 'hasOne Laravel relationship method'),
c(0, { c(1, {
sn( sn(
nil, nil,
fmta( fmta(
@@ -454,7 +471,7 @@ return {
return $this->hasOne(#~::class); return $this->hasOne(#~::class);
} }
]], ]],
{ rep(1), i(0), i(1) } { rep(1), i(2), i(1) }
) )
), ),
sn( sn(
@@ -469,14 +486,14 @@ return {
return $this->hasOne(#~::class, #~); return $this->hasOne(#~::class, #~);
} }
]], ]],
{ rep(1), i(2), i(1), i(0) } { rep(1), i(2), i(1), i(3) }
) )
), ),
}) })
), ),
s( s(
etr('bm', 'belongsToMany Laravel relationship method'), etr('bm', 'belongsToMany Laravel relationship method'),
c(0, { c(1, {
sn( sn(
nil, nil,
fmta( fmta(
@@ -489,7 +506,7 @@ return {
return $this->belongsToMany(#~::class, #~); return $this->belongsToMany(#~::class, #~);
} }
]], ]],
{ rep(1), i(2), i(1), i(0) } { rep(1), i(2), i(1), i(3) }
) )
), ),
sn( sn(
@@ -504,97 +521,97 @@ return {
return $this->belongsToMany(#~::class, #~, #~); return $this->belongsToMany(#~::class, #~, #~);
} }
]], ]],
{ rep(1), i(2), i(1), i(3), i(0) } { rep(1), i(2), i(1), i(3), i(4) }
)
),
})
),
s(
atr('->wr', 'Eloquent where method'),
c(0, {
sn(nil, fmta("->where('#~', #~)", { i(1), i(0) })),
sn(nil, fmta('->where(fn ($query) => #~)', { i(0) })),
sn(
nil,
fmta(
[[
->where(function ($query) {
#~
})
]],
{ i(0) }
)
),
sn(
nil,
fmta(
[[
->where(function ($query) use (#~) {
#~
})
]],
{ i(1), i(0) }
)
),
})
),
s(atr('->wi', 'Eloquent where in method'), fmta("->whereIn('#~', #~)", { i(1), i(0) })),
s(atr('->wn', 'Eloquent where not in method'), fmta("->whereNotIn('#~', #~)", { i(1), i(0) })),
s(
atr('->wh', 'Eloquent where has method'),
c(0, {
sn(nil, fmta("->whereHas('#~')", { i(1) })),
sn(nil, fmta("->whereHas('#~', fn ($query) => #~)", { i(1), i(0) })),
sn(
nil,
fmta(
[[
->whereHas('#~', function ($query) {
#~
})
]],
{ i(1), i(0) }
)
),
sn(
nil,
fmta(
[[
->whereHas('#~', function ($query) use (#~) {
#~
})
]],
{ i(1), i(2), i(0) }
)
),
})
),
s(
atr('->we', 'Eloquent where exists method'),
c(0, {
sn(nil, fmta('->whereExists(fn ($query) => #~)', { i(0) })),
sn(
nil,
fmta(
[[
->whereExists(function ($query) {
#~
})
]],
{ i(0) }
)
),
sn(
nil,
fmta(
[[
->whereExists(function ($query) use (#~) {
#~
})
]],
{ i(1), i(0) }
) )
), ),
}) })
), ),
-- s(
-- atr('->wr', 'Eloquent where method'),
-- c(0, {
-- sn(nil, fmta("->where('#~', #~)", { i(1), i(0) })),
-- sn(nil, fmta('->where(fn ($query) => #~)', { i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->where(function ($query) {
-- #~
-- })
-- ]],
-- { i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->where(function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- })
-- ),
-- s(atr('->wi', 'Eloquent where in method'), fmta("->whereIn('#~', #~)", { i(1), i(0) })),
-- s(atr('->wn', 'Eloquent where not in method'), fmta("->whereNotIn('#~', #~)", { i(1), i(0) })),
-- s(
-- atr('->wha', 'Eloquent where has method'),
-- c(0, {
-- sn(nil, fmta("->whereHas('#~')", { i(1) })),
-- sn(nil, fmta("->whereHas('#~', fn ($query) => #~)", { i(1), i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereHas('#~', function ($query) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereHas('#~', function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(2), i(0) }
-- )
-- ),
-- })
-- ),
-- s(
-- atr('->we', 'Eloquent where exists method'),
-- c(0, {
-- sn(nil, fmta('->whereExists(fn ($query) => #~)', { i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereExists(function ($query) {
-- #~
-- })
-- ]],
-- { i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereExists(function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- })
-- ),
} }
+16
View File
@@ -11,6 +11,7 @@ local d = ls.dynamic_node
local fmt = require('luasnip.extras.fmt').fmt local fmt = require('luasnip.extras.fmt').fmt
local rep = require('luasnip.extras').rep local rep = require('luasnip.extras').rep
local line_begin = require('luasnip.extras.conditions').line_begin local line_begin = require('luasnip.extras.conditions').line_begin
local line_end = require('luasnip.extras.conditions').line_end
local extend_decorator = require 'luasnip.util.extend_decorator' local extend_decorator = require 'luasnip.util.extend_decorator'
local fmta = extend_decorator.apply(fmt, { delimiters = '#~' }) local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
@@ -109,6 +110,21 @@ utils.atr = function(trigger, description, options)
) )
end end
--- Create a trigger for a snippet to expand at the end of a line
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.Etr = function(trigger, description, options)
return utils.tr(
trigger,
description,
vim.tbl_extend('force', {
condition = line_end
}, options or {})
)
end
--- Create a snippet that will expand anywhere but in the middle of a word --- Create a snippet that will expand anywhere but in the middle of a word
---@param trigger any ---@param trigger any
---@param nodes any ---@param nodes any
+16
View File
@@ -0,0 +1,16 @@
local M = {}
function M.open(name)
local titles = {
zsh = 'ZSH Cheat Sheet',
bash = 'Bash Cheat Sheet',
regex = 'RegExp Cheat Sheet',
}
local path = vim.fn.stdpath 'config' .. '/cheatsheets/' .. name .. '.md'
print('Opening cheat sheet: ' .. path)
require('../helpers').open_file_modal(path, titles[name] or name)
end
return M
+2
View File
@@ -0,0 +1,2 @@
WRN 2026-07-03T16:02:54.215 c/nvim.57084.0 server_start:197: Failed to start server: operation not permitted: /var/folders/j3/6yv08_8s1s740ggr40_kgvrr0000gn/T/nvim.chris/esnddj/nvim.57725.0
WRN 2026-07-03T16:03:18.385 c/nvim.57084.0 server_start:197: Failed to start server: operation not permitted: /var/folders/j3/6yv08_8s1s740ggr40_kgvrr0000gn/T/nvim.chris/O4WnB1/nvim.57764.0