cohama/lexima.vim

Prevent auto-close of quote when standing at a word boundary?

Opened this issue · 4 comments

erikw commented

Hey, first thanks for this nice plugin!

I've been using this for a while and it works mostly good, except for one type of editing that I do actually a multitude times per day. That is the case of adding single or double quotes around an existing word. Let's say that I have the following text line

apple orange pear

and my goal is to quote the word orange so that the line becomes

apple "orange" pear

If I put my cursor at the the first character of orange and enter insert mode with i

apple orange pear
      ^

and type ", lexima.vim will insert a closing quote like

apple ""orange pear

In this case it is not desirable. Now I have to press backspace, or go to normal mode and press x to remove one of the quotes.

The same is true for when I will add the closing quote after the word. If I stand at the last character for orange and go to insert mode after the cursor with a

apple "orange pear
            ^

and I type ", lexima.vim will also auto-close this to

apple "orange"" pear

And once again I have to remove the quote too much.

As this is something that I do many times per day, I would be very keen on finding a way to make lexima.vim not auto-close when being at a word boundary (or maybe there's a better formulated condition here?)!

Is there already a way to configure this, or to re-define the rule for double and single quotes?

Thanks in advance :)

Please try the following settings.

call lexima#add_rule({'char': '"', 'at': '\%#\s*\w'})

If the cursor (\%#) is preceding any spaces (\s*) and a word character (\w) then only one " will be input.

This rule overrides a built-in rule on " because 'at' is longer.

erikw commented

Thanks! It works for orange but not at the end of pear

Trial 1

apple "orange" "pear
                   ^

becomes

apple "orange" "pear""

Trial 2

I tried to develop something that would consider the end-of-line case and came up with

call lexima#add_rule({'char': '"', 'at': '\%#\s*\w\|\w\%#$'})

This works for all 3 test words. However it does not work to insert an auto-closed quote between words that have >2 spaces between them

If the goal is to insert "banana" between orange pear using auto-closed double quote i.e. transforming (note that there are 2 spaces between orange and pear)

apple orange  pear
            ^

to

apple orange "banana" pear

then typing " insert mode at the middle space as indicated will not auto-close the double quote, which is desired here.

Trial 3

Going back to the original formulation of word boundary, I then tried using use that regex feature

call lexima#add_rule({'char': '"', 'at': '\%#\(\<\|\>\)'})

This seems to work in both the original case + the insert-between-words case above. To test this out further I opened up a source code file (Ruby) and picked a line having some special characters and decided I wanted to transform

private_constant :TOP_LEVEL_TYPES, :CUSTOM_CLASS_KEY {}
                 ^              ^

by quoting :TOP_LEVEL_TYPES to

private_constant ":TOP_LEVEL_TYPES", :CUSTOM_CLASS_KEY {}

This did of course not work becuase special characters are not word boundaries.

Trial 4

Then I though then about the problem from the other way around: maybe we want to auto-complete double quotes only when there are some spaces or nothing before and after the cursor. This condition negated is when we want to insert only one double quote:

call lexima#add_rule({'char': '"', 'at': '\%#\S\|\S\%#'})

So far, this rule seems to actually work for all cases above! :O

I have been using rules that @erikw suggested, but noticed they don't always work for me. For example, |] + " = "|] where I would expect "|"]. Therefore I have created rules that so far work for me:

call lexima#add_rule({'char': '"', 'at': '"\S\{-1,}\%#\|\%#\S\{-1,}"'})
call lexima#add_rule({'char': "'", 'at': "'\S\{-1,}\%#\|\%#\S\{-1,}'"})
call lexima#add_rule({'char': '`', 'at': '`\S\{-1,}\%#\|\%#\S\{-1,}`'})

Every rule is analogous and has two parts. One part handles "words" starting and the other "words" ending with given character. This way it looks like a quoting is being closed.

Additionally, I have a set of rules for opening brackets, so they won't insert a closing bracket if there is one at the end of the word:

call lexima#add_rule({'char': '(', 'at': '\%#\S\{-1,})'})
call lexima#add_rule({'char': '[', 'at': '\%#\S\{-1,}]'})
call lexima#add_rule({'char': '{', 'at': '\%#\S\{-1,}}'})

Examples

Before    Input    After
----------------------------
|foo"     "        "|foo"
----------------------------
"foo|     "        "foo"|
----------------------------
foo|      "        foo"|"
----------------------------
|foo)     (        (|foo)
----------------------------
foo|      (        foo(|)
----------------------------

I found that with this pattern:

call lexima#add_rule({'char': '"', 'at': '"\S\{-1,}\%#\|\%#\S\{-1,}"'})

I won't be able to leave the quote with ":

Before    Input    After
----------------------------
|         "foo"    "foo"|"
----------------------------