kakoune-snippets
kakoune-snippets copied to clipboard
Implement auto-discard of snippets default text
Should fix #8
For lack of a better idea, it's now implemented directly in the script. The auto-discard is removed as soon as insert mode is exited, or the selections were moved.
Doesn't work for ${0:text}
placeholders.
Other than that works great!
Good catch, fixed
Seems that first input is duplicated when selection is single char:
Here I've pressed v once when first placeholder was selected. Snippet definition:
for (int ${1:i} = 0; $1 ${2:< 100}; $1${3:++}) {
$0
}
It's more interesting than I've initially thought. Look at the following snippet:
${1:1} ${2:2} ${3:3} ${4:4} ${5:5} ${6:6} ${7:7} ${8:8} ${9:9}
If I jumpt towards the 9th placeholder without changing anything, and press a
key it will insert:
1 2 3 4 5 6 7 8 aaaaaaaaaa
but if I change each time I jump, it will always insert two letters:
aa aa aa aa aa aa aa aa aa
It also eats text forward, so if I jump without changing to the 8th placeholder and insert a
, ninth placeholder will be gone:
1 2 3 4 5 6 7 aaaaaaaaa
Right, that's a bit annoying. It happens because in one case the inserted letter is selected (for example if you're in append mode) and so exec <a-;>d
will remove it, but if it's in regular insert mode then the inserted letter is not selected and we don't need to remove it. I think it's possible to detect in which mode we are when jumping to the placeholders but that's not super trivial.
Thanks for testing
Thanks for testing
it's like top priority feature for my workflow, so really big thanks to you for working on this.
I think it's possible to detect in which mode we are when jumping to the placeholders but that's not super trivial.
I've thought that introduction of has_default
will mean that hook should be equal for single and multi-char selections and declared on successful jump by checking this parameter. Since you select whole text anyway, and your cursor stays inside word I don't see the difference between:
[i]
and
[insert]
by means of insert
or append
mode. Because in append mode both selections would looks like so:
[a ]
[ppend ]
Which requires different hooks indeed. So I mean selections always in insert
mode state, despite the fact that cursor is placed on the word's end. Isn't it?
I've managed to make it work with this hook:
hook window -group snippets-auto-discard InsertChar .* %sh{
cursor=${kak_cursor_column}
selection=${kak_selection_desc}
# let's get cursor positions from selection description
selection1=${selection##*,}; selection1=${selection1##*.}
selection2=${selection%%,*}; selection2=${selection2##*.}
# let's find which actually is a cursor
selection1=${selection1##$cursor*}
selection2=${selection2##$cursor*}
if [ -z "${selection2}" ] && [ -z "${selection1}" ]; then
anchor=$cursor
elif [ -z "${selection2}" ]; then
anchor=${selection1}
else
anchor=${selection2}
fi
if [ "$anchor" != "$cursor" ]; then
printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c%val{hook_param}"'
else
printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c"'
fi
}
I think it's overengineered, but it works.
probably we could slim it down to
hook window -group snippets-auto-discard InsertChar .* %sh{
if [ $(printf "%s\n" ${kak_selection} | wc -m) -eq 2 ]; then
printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c"'
else
printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c%val{hook_param}"'
fi
}
Since selection will be always with cursor >= anchor, and mirrored selections are always same size we only need to check if single selection is more then 1 char or not. Probably.
I've tested it with this snippet: ${1:a} ${2:bb} ${3:я} ेे${4:न} ${5:ने} ${6:नमस्ते}
. No issues so far.
From 1fefa41c4947ed745547081f315bb8ef05a02d85 Mon Sep 17 00:00:00 2001
From: Andrey Orst <[email protected]>
Date: Tue, 7 May 2019 18:39:27 +0300
Subject: [PATCH] fix autodiscard
---
snippets.kak | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/snippets.kak b/snippets.kak
index 09657e7..877a316 100644
--- a/snippets.kak
+++ b/snippets.kak
@@ -331,7 +331,14 @@ print("\n");
def -hidden snippets-setup-auto-discard %{
remove-hooks window snippets-auto-discard
- hook window -group snippets-auto-discard InsertChar .* %{ remove-hooks window snippets-auto-discard; exec "<a-;>d%val{hook_param}" }
+
+ hook window -group snippets-auto-discard InsertChar .* %sh{
+ if [ $(printf "%s\n" ${kak_selection} | wc -m) -eq 2 ]; then
+ printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c"'
+ else
+ printf "%s\n" 'remove-hooks window snippets-auto-discard; exec -draft "c%val{hook_param}"'
+ fi
+ }
hook window -group snippets-auto-discard InsertEnd .* %{ remove-hooks window snippets-auto-discard }
hook window -group snippets-auto-discard InsertMove .* %{ remove-hooks window snippets-auto-discard }
}
--
2.21.0
@occivink
I've thought about one aspect of allowing user to visually distinguish if default text is going to be discarded or not. But this will require modifications on how you select things in different modes. Here's a thing.
I'm using Emacs's plugin called yasnippet which is a best template system for Emacs, and it is a great snippet engine whatsoever. The thing is, that when I expand the snippet in it, it highlights current placeholder. It isn't selection really, but a highlighting, and text is going to be inserted once i move or replaced if I actually press any key other than movement. Here, I've expanded for
snippet for Rust language:
You can see that the cursor (represented by |
) is placed at the beginning of iterable
placeholder. That clearly means that we're going to replace it. This is exactly how it would look in Kakoune if we select something and go to insert mode. The cursor is placed at the beginning of selection, and on pressing a key we replacing text.
This way, I believe, we don't need two different hooks for different default text sizes.
If the automatic discard is turned off, I think that your plugin should select default text, but place cursor on the 1 character beyond the placeholder default text, as if we entered append mode. And if user decides to go to normal mode, cursor should go 1 character back to allow user modify the selection, as if user used real selections and append mode. It's difficult, because your script would need to act differently if snippet was expanded in normal mode, since it doesn't change mode to normal one. So if user expand snippet in insert mode it shoul look like this
And if user expands it in normal mode, it shoul look like this:
Which is how plugin currently works.
So what I'm trying to say can be summarized to:
If discard default is turned on:
- place cursor on the beginning of the selection
- use single hook for both single and multiple character selections
If discard default is turned off:
- place cursor on 1 character beyond the selection
- use hook or real append mode to go back on character when user escapes the append mode.
Why this is important? In current state with discard default is turned off, the cursor is placed on the last character of the selection. This means if we start typing directly, text will be inserted before the last character of current selection which isn't really useful.
By using appropriate append or insert modes we showing the user what's plugin is going to do.
seems like 78852bf91b23005c57cfe6febff9c04f3acf2bc1 doesn't affect zero placeholders
Is this feature now working? Can it be merged to master?
Well you can use the branch if you want to, but the issues reported by @andreyorst have not been addressed so you might run into them. As you can see I haven't done much on this plugin in a while. It's a combination of me not being satisfied with the complexity and not being able to integrate well the plugin into my workflow, such that I'm not using at the moment. So I don't have much motivation to work on this and sort out all this complexity.