diff --git a/cheatsheets/bash.md b/cheatsheets/bash.md new file mode 100644 index 0000000..8fb042a --- /dev/null +++ b/cheatsheets/bash.md @@ -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) │ +└──────────────────┴────────────────────────────────────────┘ diff --git a/cheatsheets/regex.md b/cheatsheets/regex.md new file mode 100644 index 0000000..0b9f661 --- /dev/null +++ b/cheatsheets/regex.md @@ -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 `$`. diff --git a/cheatsheets/zsh.md b/cheatsheets/zsh.md new file mode 100644 index 0000000..825b423 --- /dev/null +++ b/cheatsheets/zsh.md @@ -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 │ +└──────────────────┴───────────────────────────────────────────────┘ diff --git a/lua/helpers.lua b/lua/helpers.lua index edcafe8..3299aa4 100644 --- a/lua/helpers.lua +++ b/lua/helpers.lua @@ -51,7 +51,57 @@ helpers.open_term = function(opts) end 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', 'close', { + buffer = buf, + silent = true, + desc = 'Close cheatsheet', + }) + vim.keymap.set('n', '', 'close', { + buffer = buf, + silent = true, + desc = 'Close cheatsheet', + }) end return helpers diff --git a/lua/keymap.lua b/lua/keymap.lua index 5e51489..56c5e1b 100644 --- a/lua/keymap.lua +++ b/lua/keymap.lua @@ -26,7 +26,7 @@ vim.keymap.set('v', 'p', '"zdP', { desc = 'Paste over selection without yanking -- or just use to exit terminal mode vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) -vim.keymap.set('n', 'c', function() +vim.keymap.set('n', 'z', function() vim.treesitter.inspect_tree() end, { desc = 'Treesitter' }) @@ -259,101 +259,110 @@ vim.keymap.set('n', '[', 'cprevious', { desc = 'Previous item i vim.keymap.set('n', 'gd', 'Telescope lsp_definitions', { desc = 'Go to definition' }) vim.keymap.set('n', 'r', 'e!', { desc = 'Reload buffer' }) - local function open_test() require('neotest').summary.open() require('neotest').output_panel.open() end -- Testing --- local test_maps = { --- { --- keys = { '', 'tn' }, --- action = function() --- require('neotest').run.run() --- open_test() --- end, --- desc = 'Run nearest test', --- }, --- { --- keys = { '', 'ta' }, --- action = function() --- require('neotest').run.run { suite = true } --- open_test() --- end, --- desc = 'Run all tests in the project', --- }, --- { --- keys = { '', 'tp' }, --- action = function() --- require('neotest').run.run_last() --- open_test() --- end, --- desc = 'Run previous test again', --- }, --- { --- keys = { '', 'td' }, --- action = function() --- local dap = require 'dap' --- if dap.session() == nil then --- dap.continue() --- end --- require('dapui').open() --- local neotest = require 'neotest' --- local bufnr = vim.api.nvim_get_current_buf() --- local row = vim.api.nvim_win_get_cursor(0)[1] - 1 --- --- local adapters = neotest.state.adapter_ids() --- local found = false --- --- for _, adapter_id in ipairs(adapters) do --- local tree = neotest.state.positions(adapter_id, { buffer = bufnr }) --- if tree then --- local nearest = require('neotest.lib.positions').nearest(tree, row) --- 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', 'tf', function() --- require('neotest').run.run(vim.fn.expand '%') --- open_test() --- end, { desc = 'Run all tests in the current file' }) --- vim.keymap.set('n', 'tc', function() --- require('neotest').summary.close() --- require('neotest').output_panel.close() --- end, { desc = 'Close test panels' }) +local test_maps = { + { + keys = { 'tc' }, + action = function() + require('neotest').summary.close() + require('neotest').output_panel.close() + end, + desc = 'Close [T]est panels', + }, + { + keys = { 'tn' }, + action = function() + require('neotest').run.run() + open_test() + end, + desc = 'Run nearest [T]est', + }, + { + keys = { 'ta' }, + action = function() + require('neotest').run.run { suite = true } + open_test() + end, + desc = 'Run all [T]ests in the project', + }, + { + keys = { 'tp' }, + action = function() + require('neotest').run.run_last() + open_test() + end, + desc = 'Run previous [T]est again', + }, + { + keys = { 'td' }, + action = function() + local dap = require 'dap' + if dap.session() == nil then + dap.continue() + end + require('dapui').open() + local neotest = require 'neotest' + local bufnr = vim.api.nvim_get_current_buf() + local row = vim.api.nvim_win_get_cursor(0)[1] - 1 --- vim.keymap.set('i', '', 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('', true, true, true), 'n', true) --- end --- end, { desc = 'Luasnip accept copilot or jump forward' }) + local adapters = neotest.state.adapter_ids() + local found = false + + vim.g.neotest_debug = true + for _, adapter_id in ipairs(adapters) do + local tree = neotest.state.positions(adapter_id, { buffer = bufnr }) + if tree then + local nearest = require('neotest.lib.positions').nearest(tree, row) + 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 + 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', 'tf', function() + require('neotest').run.run(vim.fn.expand '%') + open_test() +end, { desc = 'Run all tests in the current file' }) +vim.keymap.set('n', 'tc', function() + require('neotest').summary.close() + require('neotest').output_panel.close() +end, { desc = 'Close test panels' }) + +vim.keymap.set('i', '', 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('', 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 -- "A command to properly indent json code @@ -371,4 +380,14 @@ vim.keymap.set('n', 'es', function() vim.cmd('tabedit ' .. snippets_file) end, { desc = 'Edit snippets file' }) +vim.keymap.set('n', 'cz', function() + require('utils/cheatsheets').open 'zsh' +end, { desc = 'Open zsh cheat sheet' }) +vim.keymap.set('n', 'cb', function() + require('utils/cheatsheets').open 'bash' +end, { desc = 'Open bash cheat sheet' }) +vim.keymap.set('n', 'cr', function() + require('utils/cheatsheets').open 'regex' +end, { desc = 'Open RegExp cheat sheet' }) + require('helpers').edit_cf('k', '/lua/keymap.lua') diff --git a/lua/plugins/blink.lua b/lua/plugins/blink.lua index cef5907..b2f47df 100644 --- a/lua/plugins/blink.lua +++ b/lua/plugins/blink.lua @@ -52,16 +52,16 @@ return { }, sources = { - default = { 'lsp', 'path', 'snippets', 'lazydev', 'blade-nav' }, + default = { 'lsp', 'path', 'snippets', 'lazydev' }, providers = { lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 }, -- avante = { module = 'blink-cmp-avante', name = 'Avante', opts = {} }, - ['blade-nav'] = { - module = 'blade-nav.blink', - opts = { - clost_tag_on_complete = false, - }, - }, + -- ['blade-nav'] = { + -- module = 'blade-nav.blink', + -- opts = { + -- clost_tag_on_complete = false, + -- }, + -- }, }, per_filetype = { codecompanion = { 'codecompanion' }, diff --git a/lua/plugins/debug.lua b/lua/plugins/debug.lua index 43ff6ea..2404899 100644 --- a/lua/plugins/debug.lua +++ b/lua/plugins/debug.lua @@ -180,40 +180,6 @@ return { vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl }) 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) -- require('neotest').output.open { enter = true, last = true } -- end diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index f892d7c..8a4f398 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -13,9 +13,10 @@ return { 'saghen/blink.cmp', 'folke/lazydev.nvim', }, - build = function() - vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer' - end, + -- Might not be necessary for phpantom + -- build = function() + -- vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer' + -- end, config = function() -- 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 @@ -115,10 +116,11 @@ return { }, } - vim.lsp.phpactor = { - cmd = { 'phpactor', 'language-server' }, - filetypes = { 'php' }, - } + -- vim.lsp.config['phpantom'] = { + -- filetypes = { 'php' }, + -- cmd = { 'phpantom_lsp' }, + -- root_markers = { 'composer.json', '.git' }, + -- } -- Enable the following language servers -- @@ -144,7 +146,11 @@ return { }, }, }, - -- phpactor = {}, + phpantom_lsp = { + filetypes = { 'php' }, + cmd = { 'phpantom_lsp' }, + root_markers = { 'composer.json', '.git' }, + }, vtsls = { settings = { vtsls = { diff --git a/lua/plugins/render_markdown.lua b/lua/plugins/render_markdown.lua index 6b7e546..fc62a0f 100644 --- a/lua/plugins/render_markdown.lua +++ b/lua/plugins/render_markdown.lua @@ -5,6 +5,13 @@ return { -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons ---@module 'render-markdown' ---@type render.md.UserConfig - opts = {}, ft = { 'markdown', 'codecompanion' }, + config = function() + require('render-markdown').setup { + latex = { + enabled = true, + render_modes = true, + }, + } + end, } diff --git a/lua/plugins/test.lua b/lua/plugins/test.lua new file mode 100644 index 0000000..abf563e --- /dev/null +++ b/lua/plugins/test.lua @@ -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, +} diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua index 04fc9cc..0cdcb99 100644 --- a/lua/plugins/treesitter.lua +++ b/lua/plugins/treesitter.lua @@ -7,9 +7,11 @@ return { config = function() local langs = { 'bash', + 'zsh', 'c', 'diff', 'html', + 'latex', 'lua', 'luadoc', 'markdown', diff --git a/lua/projects.lua b/lua/projects.lua index c42bcb3..053bffb 100644 --- a/lua/projects.lua +++ b/lua/projects.lua @@ -258,6 +258,31 @@ local PROJECTS = { end, }) end, + ['server'] = function(dir) + map('pl', ':cexpr system("vendor/bin/phpstan analyse --no-progress --error-format=raw --memory-limit=2G -vv") ', { desc = 'Run lint' }) + map('pd', function() + helpers.open_term { cmd = 'lazysql pgsql://homestead:password@localhost:5432/homestead' } + end, { desc = 'Open database manager' }) + laravel_keymaps() + laravel_makes() + map('yrn ', '!cd frontend && yarn ', { desc = 'Run yarn script' }, 'c') + map('pm', ':vendor/bin/sail composer migrate') + + vim.api.nvim_create_autocmd({ 'BufWritePost' }, { + pattern = { '*.php', '.env', '.graphql' }, + callback = function() + 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, + }) + + 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, default = function() end, } diff --git a/lua/snippets/php.lua b/lua/snippets/php.lua index 48ea3db..074f6ea 100644 --- a/lua/snippets/php.lua +++ b/lua/snippets/php.lua @@ -378,7 +378,11 @@ return { { i(1), i(0) } ) ), - s(etr('nn ', 'Assert not null'), fmta('Assert::notNull(#~)', { 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 -- ------------- diff --git a/lua/utils/cheatsheets.lua b/lua/utils/cheatsheets.lua new file mode 100644 index 0000000..c141836 --- /dev/null +++ b/lua/utils/cheatsheets.lua @@ -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