This is just a random post of something I am jealous of… https://github.com/wellle/context.vim – that is great!
oh my dog yes please !
I wonder what would it take to do that in kakoune.
I’m think of use a tmux pane but it doesn’t feel right.
I guess who have to hack with the json RPC to do it properly.
With the relatively new replace-ranges
highlighter it’s possibly to implement this. Currently there a few bugs in the implementation (3644, 3689). The first is a straight up visual bug that needs to be fixed but the second bug just makes it impossible to have a new line in the replaced text so the implementation has to work around that by using the new lines in the buffer (hence <a-:>H
or (?=\n)
before making the range-spec) and by having multiple replace-ranges to handle nesting. Anyway, python is an easy language to show an example in since it’s white space sensitive.
declare-option range-specs context_replace_range
declare-option str context_replace_range_text
add-highlighter window/context_replace_range_function replace-ranges context_replace_range
define-command -override range-replace %{
try %{
exec -draft '<a-:><a-;>K<a-x>s^[^\h]<ret>'
set window context_replace_range %val{timestamp}
} catch %{ try %{
eval -no-hooks -draft %{
exec [ i k <a-x> s ^\h*(def\h|for\h|if\h)[^\n]+:$ <ret>
set window context_replace_range_text "%val{selection} --context"
}
eval -no-hooks -draft %{
exec 'k[iK<a-x><a-:>H'
set window context_replace_range %val{timestamp} "%val{selection_desc}|%opt{context_replace_range_text}"
}
}}
}
remove-hooks window context
hook -group context window NormalKey .* range-replace
hook -group context window InsertKey .* range-replace
def my_python_func():
this()
that()
them()
if 'a' in ['a', 'b', 'c']:
print('hello')
x = 'a' * 4
print(x)
print(x * 4)
print('a')
for character in ['a', 'b', 'c']:
print(character)
print(character * 3)
print(character * 6)
With some shell scripting to make nesting work and some logic to figure out when to fold (probably should only do it for when %val{selection_desc}
is outside %val{window_range}
) it doesn’t seem like too too much work to make an equivalent kakoune plugin. The real PITA will be doing it for each file type.
EDIT:
I prefer this version of the function, much simpler.
define-command -override range-replace %{
try %{
# fails if the line or the line above aren't in a nested block
exec -draft '<a-:><a-;>K<a-x>s^[^\h]<ret>'
set window context_replace_range %val{timestamp}
} catch %{
eval -draft %{
# select the text to replace. Everything between the block start and the current line.
exec 'k[iK<a-x>s^\h*(def\h|for\h|if\h)[^\n]+:\n\K.*(?=\n)<ret>'
set window context_replace_range %val{timestamp} "%val{selection_desc}|------ CONTEXT ------"
}
} catch %{}
}
@prion Kudos for this nice example.
I realized that you can handle nesting using split
, eval -itersel
and set -add
. I haven’t quite figured out how to make sure what’s visible in the current window using pure kakscript but I’m sure it’s do-able. It would probably be a lot easier if %val{window_range}
was formatted the same as a selection_desc
because window based commands do not seem to work in in -draft
contexts.
Anyway if we have some text like
class MyClass():
my_const = 'fdsfdsf'
my_other_const = 'fdsfdsf'
def __init__(self):
self.value = my_const
self.value += my_other_const
for a in [1,2,3,4,5,6]:
print('------------------')
print(self.value + ' ' + a)
print('------------------')
selected then we can do something like
# reset ranges
set window context_replace_range %val{timestamp}
# split into all of our blocks. Currently also includes unrelated blocks but that's probably fixable
exec 'S^\h*(def\h|class\h|if\h|for\h|where\h|else\h|elif\g)[^\n]+:\n<ret>'
# get rid of that annoying selection that's always at the start of every split selection
exec ')<a-space>'
# add each selection to the range spec
eval -itersel %{ set -add window context_replace_range "%val{selection_desc}|" }
to collapse example text down to
class MyClass():
def __init__(self):
for a in [1,2,3,4,5,6]:
You can think of a draft context as a separate, temporary window, with its own input queue and set of selections and all that stuff. As a result, anything window or view-related isn’t much use in a draft context, since it’s describing/affecting the temporary window, not the actual window the user is looking at.
@Screwtapello I think @prion wants to pass values to the draft context.
Something like:
evaluate-commands -draft %{
execute-keys %arg{2} g %arg{4} J <a-x>
...
} -- %val{window_range}
could be nice.
I wrote a very simple proof of concept bash script that scans up through the given lines on stdin and prints all lines where the indentation decreases with respect to the previous printed line.
The output of this program could be shown in a new window.
#!/bin/bash
function get_indent_level {
printf "%s" "$1" | grep -Po '^\s+' | tr -d '\n' | wc -c
}
prev_indent=0
IFS=''
tac /dev/stdin | while read line; do
indent_level=$(get_indent_level "$line")
if [ $prev_indent -eq 0 ] || [ $indent_level -lt $prev_indent ]; then
prev_indent=$indent_level
printf "%s\n" "$line"
fi
if [ $indent_level -eq 0 ]; then
exit
fi
done | tac
From kakoune you could do something like
exec -draft Gk<a-x><a-|>context.sh<ret>
A related config in git to specify different strategies to extract the hunk header (similar to the notion of “context” in this thread) depending of the language: https://tekin.co.uk/2020/10/better-git-diff-output-for-ruby-python-elixir-and-more
I was about to chip in and ask if ul/kak-tree can provide detection for this feature with better semantic accuracy. Looks like @alexherbo2 found a proof of concept for vim, so it should be even easier to reimplement.
Using your code I get the following error:
*** This is the debug buffer, where debug info will be written ***
/home/joe/.config/kak/kakrc:16:1: 'add-highlighter' no window in context
/home/joe/.local/share/kak/kakrc:28:1: 'evaluate-commands' 134:1: 'source' 16:1: 'add-highlighter' no window in context
error while parsing kakrc:
1:1: 'source' 28:1: 'evaluate-commands' 134:1: 'source' 16:1: 'add-highlighter' no window in context
@JJK96 this seems like a very decent and robust idea. I’ve had some problems with the fifo
code — it doesn’t appear to be in a working state (e.g. mktemp
creates a file that mkfifo
can’t override).
Anyway, I’ve picked this up and rewritten it. fast-context.kak, which I will post separately, up to commit context.kak: truncate to window_width (1ec482b4) · Commits · kstr0k / fast-context.kak · GitLab, is derived from your code, and should have a working fifo
-based implementation (after that, I’ve rewritten it to use an infobox and implement other features).
As for the context script posted above, a non-bash, less-external command-hungry version is
#!/bin/sh
set -u
get_indent_level() {
local trimmed; trimmed=$(echo "$1" | { read -r trimmed; echo "$trimmed"; })
set -- "${1%"$trimmed"*}"
echo ${#1}
}
prev_indent=99999
tac |
while IFS= read -r line; do
case "$line" in *[^[:space:]]*) ;; *) continue ;; esac
indent_level=$(get_indent_level "$line")
if [ $indent_level -lt $prev_indent ]; then
prev_indent=$indent_level
printf '%s\n' "$line"
fi
[ $indent_level -ne 0 ] || exit
done | tac
Nice work, and thx for the credits!