-
Notifications
You must be signed in to change notification settings - Fork 715
Annotated examples of "Kakoune script"
Taupiqueur edited this page Oct 21, 2020
·
1 revision
From https://github.com/occivink/kakoune-find
# Apply changes only to open buffers, it takes 4 parameters
def -hidden find-apply-impl -params 4 %{
# Evaluate the following block of Kakoune commands in the buffer indicated by %arg{1}
# (which holds the filename that was selected in the find buffer)
eval -buffer %arg{1} %{
try %{ # If something fails in this block, it will not stop the execution outside of this try block
# go to the target line and select it (except for \n)
# arg 2 holds the line number
# %arg{2}g : Jump to the line indicated by %arg{2}
# <a-x> : Select the current line
# H : Move the end of the selection 1 to the left, this deselects the newline character
exec "%arg{2}g<a-x>H"
# check for noop, and abort if it's one
reg / %arg{3} # Set the search register "/" to the contents of %arg{3}, which is a regex that matches if the current selection is exactly the changed content
# <a-K> : Keep all lines that DONT match the regex in the "/" register.
# This regex is the changed content, so if it matches, we don't need to do anything.
# <a-K> throws an error if no selections are left, which happens if the current selection contains the changed content
exec <a-K><ret>
# replace
reg '"' %arg{4} # Set the paste register (") to the contents of %arg{4} which contains the changed content
exec R # Replace the current selection with the contents of the (") register
reg s "%reg{s}o" # Append an "o" to the "s" register since we successfully applied a change
} catch %{
# If the try block failed execute this
# This happens if the <a-K> threw an error because the content was already the new content, so we could ignore
reg i "%reg{i}o" # Append an "o" to the "i" register since a change was ignored
}
}
}
def -hidden find-apply-force-impl -params 4 %{
try %{
# First try to run the normal apply, this will fail if it cannot open a buffer with the given filename.
find-apply-impl %arg{@}
} catch %{
# the buffer wasn't open: try editing it
# if this fails there is nothing we can do
# -no-hooks : don't execute any hooks triggreed by these commands
# -draft : execute while preserving the selections of the user
# -existing : Fail if the file does not exist, instead of creating the file
eval -no-hooks -draft "edit -existing %arg{1}" # Open the file with the given filename (%arg{1})
find-apply-impl %arg{@} # Run the normal apply, this should succeed because we just opened a buffer for this file
# -buffer : Execute the given commands in the context of the given buffer (%arg{1})
eval -no-hooks -buffer %arg{1} "write; delete-buffer" # Write the buffer to disk and delete it
}
}
# This function takes 0 or 1 parameters
def find-apply-changes -params ..1 -docstring "
find-apply-changes [-force]: apply changes specified in the current buffer to their respective file
If -force is specified, changes will also be applied to files that do not currently have a buffer
" %{
# Execute the block of code without running any Kakoune hooks
# Save the registers c,s,i and f because they will be changed in this code
eval -no-hooks -save-regs 'csif' %{
# Set the values of s, i and f
reg s "" # keep track of the amount of changes applied
reg i "" # keep track of the amount of changes ignored
reg f "" # keep track of the amount of changes failed
# The following block is run in a %sh{} block, so it is shell code
reg c %sh{ # store the implementation to execute in the register "c"
[ "$1" = "-force" ] && # If the first argument of find-apply-changes is the string "-force"
printf find-apply-force-impl || # Use the force implementation
printf find-apply-impl # Else use the normal implementation
}
# Execute the block of code and save the / (find) and " (yank) registers because they will be changed
eval -save-regs '/"' -draft %{
# select all lines that match the *find* pattern
#
# This regex is quite hairy, I'll split it out
# % : select whole file
# 3s : create a selection for each match of the given regex and select the 3rd capture, this opens a prompt to enter the regex
# ^ : Beginning of line
# The following is capture group 1 which holds the filename
# ( : Enter first capture group
# [^\n]+? : Match any character except newline for 1 or more times, make the match as short as possible (?)
# ) : Close first capture group
# : : Match a ":"
# The following is capture group 2 which holds the line number
# ( : Enter second capture group
# \d+ : Match 1 or more numbers
# ) : Close second capture group
# The following is a non-capturing group "(?: )" it does not capture its content. It matches an optional column number
# (?: : Open non-capturing group
# : : Match a ":"
# \d+ : Match 1 or more numbers
# ) : Close non-capturing group
# ? : Make matching this group optional
# : : Match a ":", this is the ":" before the line content
# The following is capture group 3 which holds the (changed) line content
# ( : Enter third capture group
# [^\n]* : Match 0 or more characters that are not a newline
# ) : Close third capture group
# $ : Match end of line
# The <ret> key stands for pressing "Enter" or "Return", since `exec` executes keys, we need to hit enter to close the prompt that was opened by the `s` key.
exec '%3s^([^\n]+?):(\d+)(?::\d+)?:([^\n]*)$<ret>'
# Now the three capture groups are saved into the registres 1, 2 and 3.
# 1 holds the filename
# 2 holds the line numbers
# 3 holds the (changed) line content
# Evaluate the folowing for every selection (-itersel)
eval -itersel %{
try %{ # If something fails in this block, it will not stop the execution outside of this try block
# Set the search pattern ("/" register) to the selected content (which is the third capture group containing the line content)
exec -save-regs '' <a-*>
# Execute the command stored in register c with the following arguments:
# filename (reg 1)
# line number (reg 2)
# A regex that matches the line content (reg "/"). The \A and \z match the beginning and end of a selection respectively.
# The (changed) line content (reg 3)
%reg{c} %reg{1} %reg{2} "\A%reg{/}\z" %reg{3}
} catch %{
# If the executed function failed for the given selection, add an "o" to the f register
reg f "%reg{f}o"
}
}
}
# print something in the prompt line while interpreting markup
echo -markup %sh{ # Open a shell
printf "{Information}" # Apply the {Information} face, see :doc faces
s=${#kak_main_reg_s} # Set a local variable "s" to the length of the Kakoune "s" register which holds an "o" for every successful application
[ $s -ne 1 ] && p=s # If there are 0 or more than 1 changes applied, we need to say "changes" instead of "change", so set $p to "s"
printf "%i change%s applied" "$s" "$p" # Print the number of changes applied
i=${#kak_main_reg_i} # Set a local variable "i" to the length of the Kakoune "i" register which holds an "o" for every successful application
[ $i -gt 0 ] && printf ", %i ignored" "$i" # If there are ignored selections, print how many it were
f=${#kak_main_reg_f} # Set a local variable "f" to the length of the Kakoune "f" register which holds an "o" for every successful application
[ $f -gt 0 ] && printf ", %i failed" "$f" # If there are failed selections, print how many it were
}
}
}
- Normal mode commands
- Avoid the escape key
- Implementing user mode (Leader key)
- Kakoune explain
- Kakoune TV