occivink / kakoune-snippets

Snippet support for kakoune
The Unlicense
45 stars 6 forks source link

Add configuration example #49

Open ismay opened 1 year ago

ismay commented 1 year ago

The docs mention:

snippets [str-list] is a list of {name, trigger, command} tuples. The name is the identifier of the snippet, the trigger is a short string that identifies the snippet, and the command is what gets eval'd when the snippet is activated. In practice it's just a flat list that looks like snip1-name snip1-trigger snip1-command snip2-name snip2-trigger snip2-command...

While this is descriptive, I'm still having a bit of trouble figuring out how I'd configure this plugin if I have, say, a directory of snippets somewhere. A real world configuration example for the snippets option would be appreciated!

occivink commented 1 year ago

That's a fair point. For the current version, you can have a look at the test.kak file which makes use of the basic functionality of the plugin. For the older version of the plugin, there used to be a repository with extensive configurations at https://github.com/andreyorst/kakoune-snippet-collection. Note that I don't plan to support this anymore.

ismay commented 1 year ago

That's a fair point. For the current version, you can have a look at the test.kak file which makes use of the basic functionality of the plugin.

Thanks. Yeah I went through that. So based on this example:

set -add buffer snippets 'snip1' 'trig1' %{ snippets-insert %{foo bar} }

I suppose iterating over a list of snippets sourced from a directory, add running set -add for each snippet would be the way to go right? I went through your dotfiles and that of others using this plugin, but most of what I could find used the older version, so I'm just thinking what would be the most convenient way to use the new setup.

occivink commented 1 year ago

Here is one example on how you might define some language-specific snippets

hook global BufSetOption filetype=cpp %{ 
    set buffer snippets %opt{snippets} # keep global snippets (if any)
    set -add buffer snippets 'while-loop' 'whib' %{ snippets-insert %{while (${}) {
    ${}
}}}
    set -add buffer snippets 'for-loop' 'forb' \
        %{ phantom-selection-clear ; snippets-insert %{for (${}; ${}; ${}) {
    ${}
}}; phantom-selection-add-selection ; phantom-selection-iterate-next }

}

the for-loop one has integration with https://github.com/occivink/kakoune-phantom-selection, the while-loop one is standalone. The need for line-breaks in the middle of a snippet is a bit annoying, I might add an escape for newlines.

ismay commented 1 year ago

Nice, thanks for the examples 🙏. I'll try it out a bit, see what I come up with.

ismay commented 4 months ago

So something like this works:

#!/bin/bash
# ~/.config/kak/scripts/load-snippets.sh

config="$1"
snippetsdir="$config/snippets"

# Exit if there is no snippets directory
if [ ! -d "$snippetsdir" ]; then
  exit 0
fi

snippets=$(find "$snippetsdir" -type f)

# Exit if there are no snippets
if [ -z "$snippets" ]; then
  exit 0
fi

filetypes=()

for snippet in $snippets; do
  name=$(basename "$snippet" | cut -d. -f1)
  filetype=$(head -1 "$snippet")
  trigger=$(head -2 "$snippet" | tail -1)
  contents=$(tail -n +3 "$snippet" | sed s/\'/\'\'\'\'/g)

  # Check if option was already registered
  registered=0
  for type in "${filetypes[@]}"; do
    if [[ $type = "$filetype" ]]; then
      registered=1
      break
    fi
  done

  # Register option if necessary
  if [[ $registered = 0 ]]; then
    echo "declare-option str-list snippets_$filetype"
    filetypes+=("$filetype")
  fi

  echo "set -add global 'snippets_$filetype' '$name' '$trigger' 'snippets-insert ''$contents'' '"
done

Combined with this in a kakrc:

hook global KakBegin .* %{
  eval %sh{ "$kak_config"/scripts/load-snippets.sh "$kak_config" }
}

hook global BufSetOption filetype=javascript %{
  set buffer snippets %opt{snippets_javascript}
}

Snippets go in ~/.config/kak/snippets and can be nested in subdirectories. Example javascript snippet:

javascript
trigger-here
console.log("Contents go here")

File name is used as the snippet name. First line is the filetype, second line the trigger (can be omitted) and third line and on the snippet.

stacyharper commented 3 weeks ago

Humble rewrite with POSIX script:

#!/bin/sh

config="$1"
snippetsdir="$config/snippets"

# Exit if there is no snippets directory
if [ ! -d "$snippetsdir" ]; then
    exit 0
fi

find "$snippetsdir" -type f -exec head -1 {} \; |
    sort -u |
    xargs -n1 printf "declare-option str-list snippets_%s\n"

find "$snippetsdir" -type f | while read -r snippet; do
    name="$(basename "$snippet" | cut -d. -f1)"
    filetype="$(head -1 "$snippet")"
    trigger="$(head -2 "$snippet" | tail -1)"
    contents="$(tail -n +3 "$snippet" | sed s/\'/\'\'\'\'/g)"

    printf "set -add global 'snippets_%s' '%s' '%s' 'snippets-insert ''%b'' '\n" \
        "$filetype" \
        "$name" \
        "$trigger" \
        "$contents"
done
ismay commented 3 weeks ago

Thanks @stacyharper! I'm currently using cheat. I use this script to insert the snippets in kakoune (sorry, bash again 😅):

#!/bin/bash

session="$1"
client="$2"
filetype="$3"
has_filetype=0

# Check if there are snippets tagged with filetype
if [ -n "$filetype" ] && cheat -p snippets -T | grep -q "^$filetype\$"; then
  has_filetype=1
fi

if [ "$has_filetype" == "1" ]; then
  selection=$(
    cheat -p snippets -t "$filetype" -l | tail -n +2 | awk '{print $1}' |
      fzf --preview "cheat -c -p snippets -t $filetype {}"
  )
else
  selection=$(
    cheat -p snippets -l | tail -n +2 | awk '{print $1}' |
      fzf --preview "cheat -c -p snippets {}"
  )
fi

# Exit if there is no selection
if [ -z "$selection" ]; then
  exit 1
fi

if [ "$has_filetype" == "1" ]; then
  snippet=$(cheat -p snippets -t "$filetype" "$selection")
else
  snippet=$(cheat -p snippets "$selection")
fi

snippet="${snippet//\'/\'\'}"

# Copy snippet to s register
echo "reg s '$snippet'" | kak -p "$session"
# Paste snippet from s register
echo "exec -client $client '\"'sP" | kak -p "$session"

Snippets can then be defined in the format cheat expects, so for js for example:

---
syntax: javascript
tags: [ javascript ]
---
array.forEach(element => {

});