Sublime Forum

Configure Left-Right Paired Characters like [] () {} etc

#1

Is there a way to configure which characters get the left-right auto-insertion behaviour?

For example, right now, if you type ( the ) is inserted for you automatically ahead of the cursor.

There’s a couple other characters I would like similar behaviour for, and am hoping I can configure that.

0 Likes

#2

Auto pairing of characters is handled by your key bindings. For example, if you go into the key bindings and look in the left hand pane where the defaults all, you’ll see this:

	// Auto-pair brackets
	{ "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 }
		]
	},
	{ "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "res://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 }
		]
	},

These are the bindings that make the ( auto-pair a ) character. The first one inserts () when you enter ( and places the cursor in the center, the second one is used when you press the key while text is selected to wrap the selection, the third one moves over a ) without typing one if the next character is a ) character and the last one will remove () if the cursor is between the parenthesis when you press backspace.

All of the bindings rely on the auto_match_enabled setting to be turned on, but that’s the only setting that applies.

You can duplicate these bindings into your user settings and change the characters as appropriate. This also involves changing the regular expressions that help to constrain when the binding is active.

0 Likes

#3

@OdatNurd Thanks! I never would have understood the various blocks without your descriptions.

I added it for ` as I mostly write in JS and it’s a wrapping character despite not having a left-right.

Might as well include for those that also want it:

  // Auto-pair `
  { "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": "wrap_block", "args": {"begin": "`", "end": "`"}, "context":
    [
      { "key": "indented_block", "match_all": true },
      { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
      { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
      { "key": "following_text", "operator": "regex_match", "operand": "^$", "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 }
    ]
  },
  { "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "res://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 }
    ]
  }
1 Like

#4

The core JavaScript package already provides those bindings. Are you using a third-party syntax?

0 Likes