Sublime Forum

Auto-pair typographical quotes

#1

I am not a programmer and I’m testing Sublime text as a general editor, oriented to tagged text for Desktop publishing. I have been attempting to get auto-pair working for typographical quotes (“”‘’«») without sucess, due to my lack of knowledge. Any suggestion? I attempted to modify the windows sublime keymap but… Thank you very much in advance.

0 Likes

#2

What I mean is to be able to automatically get closing quotes every time I write opening quotes. Anyhow, it’s possible via a macro, I know.

0 Likes

#3

Look at the default keybindings for example on how auto-pair work:

  1. Search “// Auto-pair square brackets”
  2. Copy the corresponding code block to your user keybindings.
  3. Replace ] by what you want.

If done right, it must work.

0 Likes

#4

Excuse my ignorance. No luck, after replacing “” with ““” and “]” with “”” (see lines 2, 6, 9 and 15). This is the piece of code:

// Auto-pair typographical quotes
{ “keys”: ““”], “command”: “insert_snippet”, “args”: {“contents”: ““$0””}, “context”:

  { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
  { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
  { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|”|;|\\}|$)", "match_all": true }
]

},
{ “keys”: ““”], “command”: “insert_snippet”, “args”: {“contents”: ““${0:$SELECTION}””}, “context”:

  { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
  { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }
]

},
{ “keys”: “””], “command”: “move”, “args”: {“by”: “characters”, “forward”: true}, “context”:

  { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
  { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
  { "key": "following_text", "operator": "regex_contains", "operand": "^\\”", "match_all": true }
]

}

0 Likes

#5

Excuse me again: the piece of code works! It didn’t work because I was using a macro to put the typographical quote in my file. If I use Alt+0147 to get the “, it works, but it’s boring. I think it’s better to use a macro to write opening and closing typographical quotes. Of course, any suggestion would be welcome. Maybe it’s possible to redefine the " key to produce a “. Thank you very much.

0 Likes

#6

You presumably want to bind the smart quote snippet to a key you can press, such as the dummy quote ("), i.e., Shift+’

In this case, the first line should read:

{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0”"}, "context":

You had it set up to trigger with , which is not a key. Does this make sense?

I tried out your bindings after switching the other ones and they work okay, although you probably need a couple more to do work:

  • to create when you press " before a word
  • to create when you press " after a word
0 Likes

#7

Thank you very much again.
The idea is to replace ", present in the keyboard, with “ and ', also present, with ‘
I’ll study your previous message if no other suggestion is provided.

0 Likes

#8

Yes. You got it.

I took a quick stab at adding the two bindings I suggested were needed in my previous post. I didn’t really test this very thoroughly. Regular expressions have a tendency to require more thought than I am capable of at the moment :smile: So it’s possible you’ll run into problems.

One problem I encountered is that that replacing smart quotes means you can’t write JSON (i.e., the configuration files that Sublime uses). So I added limited all the bindings to a “text” scope. This means that the keybindings will only work in HTML, Markdown, Plain Text, etc.

// Auto-pair typographical quotes
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|”|;|\\}|$)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“${0:$SELECTION}”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "move", "args": {"by": "characters", "forward": true}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^\\”", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quotes before & after word
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "”$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},

P.S. If these are all the keybindings you’re using, remember to remove the very last comma.

Hope this helps,
Alex

0 Likes

#9

Thank you very much. I’ll test and I’ll report. My first steps with Sublime Text are very promising.

0 Likes

#10

Your code works perfectly out of the box. I’ll attempt to build now the same for the single quotation mark.

0 Likes

#11

Complete success. Thank you very very much. This is the code:

// Auto-pair typographical single quotes
{ “keys”: “’”], “command”: “insert_snippet”, “args”: {“contents”: “‘$0’”}, “context”:

      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|’|;|\\}|$)", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘${0:$SELECTION}’"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "move", "args": {"by": "characters", "forward": true}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^\\’", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
// Smart quotes before & after word
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘$0"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "”$0"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "preceding_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
0 Likes

#12

I think you’ve got the gist of how bindings work.

In the meantime, I noticed several issues with the previous bindings, particularly in liminal cases. I’ve put enough stopgaps in the following code to solve all the issues I found – but there are probably bugs I didn’t notice, and I may even have added a couple. So, while these bindings should be an improvement to my previous attempt, they’re not quite finished. One issue that I haven’t even looked at is nested double- and single-quotes, such as: “The ‘thing’”.

Anyway, new & improved* bindings:

// Auto-pair typographical quotes
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|”|;|\\}|$)", "match_all": true },
		// { "key": "preceding_text", "operator": "not_regex_contains", "operand": "”$", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“${0:$SELECTION}”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "move", "args": {"by": "characters", "forward": true}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quotes before & after word
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "”$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\S$", "match_all": true },
		{ "key": "preceding_text", "operator": "not_regex_contains", "operand": "”$", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
  • hopefully
0 Likes

#13

Don’t worry. Your bindings are very useful, even if recursive quoting is not covered. By the way: recursive capabilities in Sublime Text lets me solve problems with InDesign and Ventura tagged text that no other editor, as far as I know, can solve (and I have tested a pretty amount of editors with syntax highlighting capabilities, believe me). I got it with very poor knowledge in this matter and no knowledge at all in programming, adapting examples taken from the unofficial documentation.
Thank you very much again.

Updated version of the single typographic quotes binding:

// // Auto-pair typographical single quotes
{ “keys”: “’”], “command”: “insert_snippet”, “args”: {“contents”: “‘$0’”}, “context”:

      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|’|;|\\}|$)", "match_all": true },
      // { "key": "preceding_text", "operator": "not_regex_contains", "operand": "’$", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘${0:$SELECTION}’"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "move", "args": {"by": "characters", "forward": true}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^(‘|’)", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
// Smart quotes before & after word
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘$0"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
      { "key": "following_text", "operator": "not_regex_contains", "operand": "^(‘|’)", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
},
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "’$0"}, "context":
   
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "preceding_text", "operator": "regex_contains", "operand": "\\S$", "match_all": true },
      { "key": "preceding_text", "operator": "not_regex_contains", "operand": "’$", "match_all": true },
      { "key": "following_text", "operator": "not_regex_contains", "operand": "^(‘|’)", "match_all": true },
      { "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
   ]
}
0 Likes

#14

I’m actually not sure what I was thinking of last night, when I thought nested quotes might pose a problem :smiley:

The keybindings we’ve been looking at are actually fairly simple. The only complicated bits are the ones that use regular expressions. They’re very useful to know, because a lot of stuff in Sublime leverages regular expressions, including color schemes, language syntaxes, keybindings, the find/replace functionality and maybe other things I have forgotten :wink:

After many years of skillful evasion, I started learning regular expressions a few months ago because they’re so useful when tinkering with Sublime. I am very glad I did, because they’re indispensable if you work with text a lot (and it sounds like do).

Obligatory XKCD reference --> xkcd.com/208/

Let me know how the bindings hold up and we can tinker some more if you run into trouble. (I won’t be using them myself – because I generally write in Markdown and convert to other formats with Pandoc, which takes cares of typographical niceties – and will therefore not come across any problems.)

Alex

0 Likes

#15

Your “obligatory” XKCD reference is really funny.
My knowledge about regular expressions is very limited but you’re right: it’s mandatory to properly use Sublime Text. Give me time. And yes: texts are my life.
I’ll continue to test and I’ll report.
Best regards.

0 Likes

#16

So far, everything works according to my needs. Only a problem: after opening parenthesis (), when I attempt to write quotes, the quotes I get are the closing quotes: ” (only).

0 Likes

#17

I am assuming the caret is between the parentheses like so:

(|)

And that what you want as an outcome is:

(“|”)

Fixing this issue requires some thinking, which I am not currently able to do. (I am next to the sea and the sea beckons.)

Here’s a highly inelegant hack to get you by, written for double-quotes. You will need to change the “smart quotes” section:

// Smart quotes before & after word
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "preceding_text", "operator": "not_regex_contains", "operand": "($", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "”$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\S$", "match_all": true },
		{ "key": "preceding_text", "operator": "not_regex_contains", "operand": "”(]$", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},

I haven’t tested it much, so it might introduce other issues.

The issue, I think, boils down on what to do when the caret is between two characters, e.g.:

x|y

For x and y are there values other than parentheses that you would like to the auto-pair quotes to be triggered?

Alex

0 Likes

#18

You are perfectly understanding my goal (“”). I am in a also hurry but I’ll test as soon as possible and I’ll report. Anyhow, don’t worry: I can wait. It’s not urgent at all. Thank you very much again.

0 Likes

#19

You were right. The new version has undesirable side-effects. For example: if I attempt to add quotes to an existent text, the previous version, very cleverly, avoided auto-pair and put only opening or closing quotes. Now, I get non-typographical quotes ("). Anyhow, I’ll continue to test for a while, even if the old version is much preferable for me.
Other values for x and y other than parentheses? Brackets ] and, if possible, recursive quoting, already mentioned in a previous message: “‘lorem’ etc. / lorem’” etc.
Anyhow, take it easy. The old code works very well.
Best regards.

0 Likes

#20

Hi,

I was looking over the existing bindings and I couldn’t figure out what purpose was served by certain things, so I quickly re-wrote it. I’ve taken a lot of stuff out, but I think the functionality is the same (?). I’ve left some comments in there, as well as some stuff I’m not sure about, but if you get back to me soon enough I will hopefully remember why I’ve left them in :smile:

It would be very helpful if I could find an example document to type, which would highlight potential issues.

Anyway, let me know if this is better or worse. (Oh, by the way, this includes both double and singe quotes; I think it makes sense to look at these together. Guillemets, etc. are another story and I don’t know enough about them.)

/*** Smart Double Quotes (“”) ***/
// Surround selection with smart quotes // OK, I think
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“${0:$SELECTION}”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Auto-pair smart quotes // OK -- but what about following/preceding regexs?
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0”"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		// { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|”|;|\\}|$)", "match_all": true }, // does commenting it out alter anything?
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quote before word
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "“$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "reg ex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”|‘|’|\\)|])", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quote after word
{ "keys": "\""], "command": "insert_snippet", "args": {"contents": "”$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\S$", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”|‘|’|\\)|])", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Do not overwrite smart quotes with dumb quotes // OK, I think
{ "keys": "\""], "command": "move", "args": {"by": "characters", "forward": true}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^(“|”)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "backspace"], "command": "run_macro_file", "args": {"file": "Packages/Default/Delete Left Right.sublime-macro"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "“$", "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^”", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
/*** Smart Single Quotes (‘’) ***/
// Surround selection with smart quotes // OK, I think
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘${0:$SELECTION}’"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Auto-pair smart quotes // OK -- but what about following/preceding regexs?
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘$0’"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		// { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|’|;|\\}|$)", "match_all": true }, // does commenting it out alter anything?
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quote before word
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "‘$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^\\S", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”|‘|’|\\)|])", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Smart quote after word
{ "keys": "'"], "command": "insert_snippet", "args": {"contents": "’$0"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\S$", "match_all": true },
		{ "key": "preceding_text", "operator": "not_regex_contains", "operand": "(“|‘)$", "match_all": true },
		// { "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|”|‘|’|\\)|])", "match_all": true },
		{ "key": "following_text", "operator": "not_regex_contains", "operand": "^(“|‘|’|\\)|])", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
// Do not overwrite smart quotes with dumb quotes // OK, I think
{ "keys": "'"], "command": "move", "args": {"by": "characters", "forward": true}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^(‘|’)", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},
{ "keys": "backspace"], "command": "run_macro_file", "args": {"file": "Packages/Default/Delete Left Right.sublime-macro"}, "context":
	
		{ "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
		{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "‘$", "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "^’", "match_all": true },
		{ "key": "selector", "operator": "equal", "operand": "text", "match_all": true }
	]
},

Alex

1 Like

Insert smart quotes into Sublime