Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request: non-recursive mapping #437

Closed
aeosynth opened this issue Dec 17, 2016 · 6 comments
Closed

request: non-recursive mapping #437

aeosynth opened this issue Dec 17, 2016 · 6 comments

Comments

@aeosynth
Copy link
Contributor

stop infinite recursion

@martanne
Copy link
Owner

Why? What do you want to achieve, it can almost certainly be done in some other way.

@aeosynth
Copy link
Contributor Author

aeosynth commented Dec 18, 2016

i'm implementing html tag auto completion: map! insert >< ></TAG>. i could use the trick of writing <C-v>u003c to insert an opening bracket, or simply use different keys, or reorder my sequence to not input ><. it would just be easier for me if i didn't have to think about that.

edit: bonus: the key binding action pseudo-keys could be dropped

@martanne
Copy link
Owner

I agree that recursive bindings might require a bit more thought, but I don't really see a better alternative.

edit: bonus: the key binding action pseudo-keys could be dropped

I don't want them to be dropped though. The reason why vim has non-recursive bindings is because certain stuff is hard coded/built-in into the editor core. For example you can't really unmap those ( :nunmap j doesn't work). In vis there are no such priviledged commands. We start with no built-in mappings and then add a default set during startup. In vis after an :unmap normal j it is gone. That is why you should generally use the pseudo-keys in your mappings. And yes they are a bit inconvenient for interactive use (i.e. setting up a new mapping).

Now suppose we want to write a nano frontend on top of the text editing code, j doesn't have any special meaning in that context but <cursor-line-down> is still perfectly understandable.

As for your concrete use case/problem, how would you get the tag to insert? One mapping per tag?

Probably a better approach would be to use a Lua function, something like the following:

local autoclose_htmltags = function()
	local win = vis.win
	local file = win.file
	for cursor in win:cursors_iterator() do
		local pos = cursor.pos
		file:insert(pos, ">")
		local tag_range = file:text_object_angle_bracket(pos)
		if tag_range then
			local tag_name = file:content(tag_range)
			if not tag_name:find("\n") and tag_name:sub(-1) ~= "/" then
				local space = tag_name:find(" ")
				if space then
					tag_name = tag_name:sub(1, space-1)
				end
				file:insert(pos+1, string.format("</%s>", tag_name))
			end
		end
		cursor.pos = pos + 1
	end
end

vis.events.subscribe(vis.events.WIN_OPEN, function(win)
	if win.syntax == 'html' then
		win:map(vis.modes.INSERT, ">", autoclose_htmltags, "Autoclose HTML tags")
	end
end)

This depends on the following patch to expose the text_object_angle_bracket function:

diff --git a/vis-lua.c b/vis-lua.c
index 301d719..ac31e16 100644
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -1964,6 +1964,7 @@ void vis_lua_init(Vis *vis) {
 		const char *name;
 	} textobjects[] = {
 		{ VIS_TEXTOBJECT_INNER_WORD, "text_object_word" },
+		{ VIS_TEXTOBJECT_INNER_ANGLE_BRACKET, "text_object_angle_bracket" },
 	};
 
 	for (size_t i = 0; i < LENGTH(textobjects); i++) {

I'm not yet sure how to best expose the text object functionality to Lua. Duplicating the C API would be one approach, but maybe we can do better. To be discussed in #292.

@aeosynth
Copy link
Contributor Author

I agree that recursive bindings might require a bit more thought, but I don't really see a better alternative.

the alternative is non-recursive bindings. we can have both, just like vim.

As for your concrete use case/problem, how would you get the tag to insert?

  if win.syntax == 'html' then
    vis:command('map! insert >>       <Escape>ybea></<C-r>0><Escape>h%i')
    vis:command('map! insert ><Enter> <Escape>ybea></<C-r>0><Escape>h%i<Enter><Escape>O')
  end

@martanne
Copy link
Owner

martanne commented Dec 18, 2016

the alternative is non-recursive bindings. we can have both, just like vim.

You failed to address the better part.

As explained in my last post vis does not have special internal commands. Hence, consider the following imaginary mapping :map-nonrecursive normal j 2j and how it would be handled:

  1. We find a j in the input queue
  2. It is a non-recursive mapping, replace it with 2j
  3. Execute mapping for 2
  4. Process j, because we are in non-recursive mode, do not expand it. j has no special meaning, ignore it (yes in insert mode we could insert it literally, but still).

The current model is simple to reason about. I don't want the additional complexity.

Also personally I do not like these hackish mappings (e.g. you just clobbered the default register, you exited insert mode which messes with undo history etc). In my opinion they should only be used to set up preferred key bindings.

@aeosynth
Copy link
Contributor Author

ok, i didn't grasp what no builtin mappings meant. i can live with recursion.

text_object_word is what i was confusingly asking for in the api issue; i'm now using it to implement abbreviations: https://github.com/aeosynth/dot/blob/master/vis/abbr.lua. exposing more text objects would probably be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants