howl.editing.auto_pair.handle(event, editor)

local buffer, editor, cursor

event = (character, key_name = character) -> :character, :key_name, key_code: 65

before_each ->
  buffer = Buffer!
  editor = Editor buffer
  cursor = editor.cursor
  buffer.text = ''

returns non-true when the character does not match a known pair

assert.is_not_true auto_pair.handle event('x'), editor

always returns non-true if the auto_pair config variable is false

buffer.mode.auto_pairs = { ['(']: ')' }
buffer.config.auto_pair = false
assert.is_not_true auto_pair.handle event('('), editor

(when the character matches a known pair from buffer.mode.auto_pairs)

before_each ->
  buffer.mode.auto_pairs = {
    '(': ')'
    '[': ']'
    '"': '"'
  }

(.. when there is an active selection)

before_each ->
  buffer.text = ' foo '
  editor.selection\set 2, 5

surrounds the selection with the pair as one undo operation

auto_pair.handle event('('), editor
assert.equal ' (foo) ', buffer.text
buffer\undo!
assert.equal ' foo ', buffer.text

returns true

assert.is_true auto_pair.handle event('('), editor

(.. with no selection active)

returns true

assert.is_true auto_pair.handle event('('), editor

inserts the pair in the buffer, as one undo operation

for start_c, end_c in pairs buffer.mode.auto_pairs
  auto_pair.handle event(start_c), editor
  assert.equal "#{start_c}#{end_c}", buffer.text
  buffer\undo!
  assert.equal '', buffer.text

positions the cursor within the pair

auto_pair.handle event('['), editor
assert.equal 2, cursor.pos

does not trigger for a same character pair if the current balance is uneven

buffer.text = '"foo'
cursor.pos = 5
assert.is_not_true auto_pair.handle event('"'), editor

does not trigger when the next character is a word character

buffer.text = 'foo'
cursor.pos = 1
assert.is_not_true auto_pair.handle event('('), editor

(overtyping companion characters)

before_each ->
  buffer.mode.auto_pairs = {
    '(': ')'
    '"': '"'
  }

overtypes any companion characters if the current pair-balance is even

buffer.text = '()'
cursor.pos = 2
assert.is_true auto_pair.handle event(')'), editor
assert.equal '()', buffer.text
assert.equal 3, cursor.pos

overtypes any companion characters for even pair-balance when the start characters and end character is the same

buffer.text = '""'
cursor.pos = 2
assert.is_true auto_pair.handle event('"'), editor
assert.equal '""', buffer.text
assert.equal 3, cursor.pos

does not overtype if the current pair-balance is non-even

buffer.text = '(foo'
cursor.pos = 5
assert.is_not_true auto_pair.handle event(')'), editor

does not overtype if the current character is different

buffer.text = '(foo)'
cursor.pos = 6
assert.is_not_true auto_pair.handle event(')'), editor

(deleting back inside a pair)

before_each -> buffer.mode.auto_pairs = ['(']: ')'

returns true

buffer.text = '()'
cursor.pos = 2
assert.is_true auto_pair.handle event('\8', 'backspace'), editor

deletes both characters as one undo

buffer.text = '()'
cursor.pos = 2
auto_pair.handle event('\8', 'backspace'), editor
assert.equal '', buffer.text
buffer\undo!
assert.equal '()', buffer.text