Improve brackets auto closing.

When an open bracket is inserted, an anchorRange is created. When a closing bracket is inserted, and its position matches the end of one of the anchorRanges, the closing bracket is not inserted and the cursor moves right.
This commit is contained in:
Corey Johnson
2012-10-24 12:08:37 -07:00
parent 1ad6fcc2d3
commit ebbb39f50e
2 changed files with 104 additions and 34 deletions

View File

@@ -19,11 +19,16 @@ describe "LanguageMode", ->
expect(jsEditSession.languageMode.grammar.name).toBe "JavaScript"
jsEditSession.destroy()
describe "matching character insertion", ->
describe "bracket insertion", ->
beforeEach ->
editSession.buffer.setText("")
describe "when there is non-whitespace after the cursor", ->
describe "when more than one charachter is inserted", ->
it "does not insert a matching bracket", ->
editSession.insertText("woah(")
expect(editSession.buffer.getText()).toBe "woah("
describe "when there is a word charachter after the cursor", ->
it "does not insert a matching bracket", ->
editSession.buffer.setText("ab")
editSession.setCursorBufferPosition([0, 1])
@@ -42,38 +47,94 @@ describe "LanguageMode", ->
expect(editSession.buffer.getText()).toBe "())\na)b\n[)]\n1)2"
describe "when ( is inserted", ->
it "inserts a matching ) following the cursor", ->
editSession.insertText '('
expect(buffer.lineForRow(0)).toMatch /^\(\)/
describe "when [ is inserted", ->
it "inserts a matching ] following the cursor", ->
editSession.insertText '['
expect(buffer.lineForRow(0)).toMatch /^\[\]/
describe "when { is inserted", ->
it "inserts a matching ) following the cursor", ->
describe "when there is a non-word characher after the cursor", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("}")
editSession.setCursorBufferPosition([0, 0])
editSession.insertText '{'
expect(buffer.lineForRow(0)).toMatch /^\{\}/
expect(buffer.lineForRow(0)).toBe "{}}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when \" is inserted", ->
it "inserts a matching \" following the cursor", ->
describe "when the cursor is at the end of the line", ->
it "inserts a closing bracket after an opening bracket is inserted", ->
editSession.buffer.setText("")
editSession.insertText '{'
expect(buffer.lineForRow(0)).toBe "{}"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '['
expect(buffer.lineForRow(0)).toBe "[]"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
editSession.buffer.setText("")
editSession.insertText '"'
expect(buffer.lineForRow(0)).toMatch /^""/
expect(buffer.lineForRow(0)).toBe '""'
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when ' is inserted", ->
it "inserts a matching ' following the cursor", ->
editSession.buffer.setText("")
editSession.insertText "'"
expect(buffer.lineForRow(0)).toMatch /^''/
expect(buffer.lineForRow(0)).toBe "''"
expect(editSession.getCursorBufferPosition()).toEqual([0,1])
describe "when ) is inserted before a )", ->
it "moves the cursor one column to the right instead of inserting a new )", ->
editSession.insertText '() '
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "() "
expect(editSession.getCursorBufferPosition().column).toBe 2
describe "when the cursor is on a closing bracket and a closing bracket is inserted", ->
describe "when the closing bracket was there previously", ->
it "inserts a closing bracket", ->
editSession.insertText '()x'
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())x"
expect(editSession.getCursorBufferPosition().column).toBe 2
describe "when the closing bracket was automatically inserted from inserting an opening bracket", ->
it "only moves cursor over the closing bracket one time", ->
editSession.insertText '('
expect(buffer.lineForRow(0)).toBe "()"
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "()"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
editSession.setCursorBufferPosition([0, 1])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "())"
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
it "moves cursor over the closing bracket after other text is inserted", ->
editSession.insertText '('
editSession.insertText 'ok cool'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
editSession.setCursorBufferPosition([0, 8])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(ok cool)"
expect(editSession.getCursorBufferPosition()).toEqual [0, 9]
it "works with nested brackets", ->
editSession.insertText '('
editSession.insertText '1'
editSession.insertText '('
editSession.insertText '2'
expect(buffer.lineForRow(0)).toBe "(1(2))"
editSession.setCursorBufferPosition([0, 4])
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 5]
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(1(2))"
expect(editSession.getCursorBufferPosition()).toEqual [0, 6]
it "works with mixed brackets", ->
editSession.insertText '('
editSession.insertText '}'
expect(buffer.lineForRow(0)).toBe "(})"
editSession.insertText ')'
expect(buffer.lineForRow(0)).toBe "(})"
expect(editSession.getCursorBufferPosition()).toEqual [0, 3]
describe "javascript", ->
beforeEach ->

View File

@@ -15,20 +15,29 @@ class LanguageMode
constructor: (@editSession) ->
@buffer = @editSession.buffer
@grammar = TextMateBundle.grammarForFileName(@buffer.getBaseName())
@bracketAnchorRanges = []
_.adviseBefore @editSession, 'insertText', (text) =>
return true if @editSession.hasMultipleCursors()
cursorBufferPosition = @editSession.getCursorBufferPosition()
nextCharacter = @editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0, 1])])
nextCharachter = @editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0,1])])
if @isClosingBracket(text) and text == nextCharacter
@editSession.moveCursorRight()
false
else if /^\s*$/.test(nextCharacter) and pairedCharacter = @pairedCharacters[text]
@editSession.insertText text + pairedCharacter
if @isOpeningBracket(text) and /\W|^$/.test(nextCharachter)
@editSession.insertText(text + @pairedCharacters[text])
@editSession.moveCursorLeft()
range = [cursorBufferPosition, cursorBufferPosition.add([0, text.length])]
@bracketAnchorRanges.push @editSession.addAnchorRange(range)
false
else if @isClosingBracket(text)
return true if nextCharachter != text
anchorRange = @bracketAnchorRanges.filter((anchorRange) -> anchorRange.getBufferRange().end.isEqual(cursorBufferPosition))[0]
if anchorRange
anchorRange.destroy()
@bracketAnchorRanges = _.without(@bracketAnchorRanges, anchorRange)
@editSession.moveCursorRight()
false
isOpeningBracket: (string) ->
@pairedCharacters[string]?