From 08a55dfcacb203973f710b30a1ab4ba5838b612b Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 2 Aug 2012 16:26:40 -0700 Subject: [PATCH] wip: IndentationForRow almost works TextMate preferences --- spec/app/edit-session-spec.coffee | 24 +++++++++++++++++++++++- src/app/edit-session.coffee | 22 ++++++++++------------ src/app/language-mode.coffee | 29 ++++++++++++++++++++++------- src/app/screen-line.coffee | 7 +++++++ src/app/selection.coffee | 5 +++-- src/app/tokenized-buffer.coffee | 5 +++++ 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 8a9b29d01..82bfeb04b 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -2,7 +2,7 @@ Project = require 'project' Buffer = require 'buffer' EditSession = require 'edit-session' -describe "EditSession", -> +fdescribe "EditSession", -> [buffer, editSession, lineLengths] = [] beforeEach -> @@ -1106,6 +1106,28 @@ describe "EditSession", -> expect(buffer.lineForRow(0)).toMatch(tabRegex) describe "when auto-indent is on and there is no text after the cursor", -> + describe "when the preceding line opens a new level of indentation", -> + it "increases the level of indentation by one", -> + buffer.insert([5, 0], " \n") + editSession.tabText = " " + editSession.setCursorBufferPosition [5, 2] + editSession.setAutoIndent(true) + editSession.indent() + expect(buffer.lineForRow(5)).toMatch /^\s+$/ + expect(buffer.lineForRow(5).length).toBe 6 + expect(editSession.getCursorBufferPosition()).toEqual [5, 6] + + describe "when there are empty lines preceding the current line", -> + it "bases indentation on the first non-blank preceding line", -> + buffer.insert([5, 0], "\n\n\n \n") + editSession.tabText = " " + editSession.setCursorBufferPosition [8, 2] + editSession.setAutoIndent(true) + editSession.indent() + expect(buffer.lineForRow(8)).toMatch /^\s+$/ + expect(buffer.lineForRow(8).length).toBe 6 + expect(editSession.getCursorBufferPosition()).toEqual [8, 6] + it "properly indents the line", -> buffer.insert([7, 0], " \n") editSession.tabText = " " diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index a879e38af..f3023f45f 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -137,15 +137,11 @@ class EditSession @insertNewline() indent: -> + currentRow = @getCursorBufferPosition().row if @getSelection().isEmpty() - whitespaceMatch = @lineForBufferRow(@getCursorBufferPosition().row).match /^\s*$/ + whitespaceMatch = @lineForBufferRow(currentRow).match /^\s*$/ if @autoIndent and whitespaceMatch - indentation = @indentationForRow(@getCursorBufferPosition().row) - if indentation.length > whitespaceMatch[0].length - @getSelection().selectLine() - @insertText(indentation) - else - @insertText(@tabText) + @autoIndentRow(currentRow) else if @softTabs @insertText(@tabText) else @@ -251,12 +247,14 @@ class EditSession indentationForRow: (row) -> @languageMode.indentationForRow(row) - autoIndentTextAfterBufferPosition: (text, bufferPosition) -> - return { text } unless @autoIndent - @languageMode.autoIndentTextAfterBufferPosition(text, bufferPosition) + autoIndentRows: (startRow, endRow) -> + @autoIndentRow(row) for row in [startRow..endRow] - autoOutdentBufferRow: (bufferRow) -> - @languageMode.autoOutdentBufferRow(bufferRow) + autoIndentRow: (row) -> + actualIndentation = @lineForBufferRow(row).match(/^\s*/)[0] + desiredIndentation = @indentationForRow(row) + if actualIndentation != desiredIndentation + @buffer.change([[row, 0], [row, actualIndentation.length]], desiredIndentation) toggleLineCommentsInRange: (range) -> @languageMode.toggleLineCommentsInRange(range) diff --git a/src/app/language-mode.coffee b/src/app/language-mode.coffee index ea3efae22..842e86499 100644 --- a/src/app/language-mode.coffee +++ b/src/app/language-mode.coffee @@ -73,21 +73,36 @@ class LanguageMode null indentationForRow: (row) -> - state = @tokenizedBuffer.stackForRow(row) - previousRowText = @buffer.lineForRow(row - 1) - @aceMode.getNextLineIndent(state, previousRowText, @editSession.tabText) + for precedingRow in [row - 1..-1] + return if precedingRow < 0 + precedingLine = @editSession.buffer.lineForRow(precedingRow) + break if /\S/.test(precedingLine) + + scopes = @tokenizedBuffer.scopesForPosition([precedingRow, Infinity]) + indentation = precedingLine.match(/^\s*/)[0] + increaseIndentPattern = TextMateBundle.getPreferenceInScope(scopes[0], 'increaseIndentPattern') + decreaseIndentPattern = TextMateBundle.getPreferenceInScope(scopes[0], 'decreaseIndentPattern') + + if new OnigRegExp(increaseIndentPattern).search(precedingLine) + indentation += @editSession.tabText + + line = @editSession.buffer.lineForRow(row) + if new OnigRegExp(decreaseIndentPattern).search(line) + indentation = indentation.replace(@editSession.tabText, "") + + indentation autoIndentTextAfterBufferPosition: (text, bufferPosition) -> { row, column} = bufferPosition - state = @tokenizedBuffer.stackForRow(row) + stack = @tokenizedBuffer.stackForRow(row) lineBeforeCursor = @buffer.lineForRow(row)[0...column] if text[0] == "\n" - indent = @aceMode.getNextLineIndent(state, lineBeforeCursor, @editSession.tabText) + indent = @aceMode.getNextLineIndent(stack, lineBeforeCursor, @editSession.tabText) text = text[0] + indent + text[1..] - else if @aceMode.checkOutdent(state, lineBeforeCursor, text) + else if @aceMode.checkOutdent(stack, lineBeforeCursor, text) shouldOutdent = true - {text, shouldOutdent} + {text, shouldOutdent: false} autoOutdentBufferRow: (bufferRow) -> state = @tokenizedBuffer.stackForRow(bufferRow) diff --git a/src/app/screen-line.coffee b/src/app/screen-line.coffee index 3b409f8fb..c864015f9 100644 --- a/src/app/screen-line.coffee +++ b/src/app/screen-line.coffee @@ -41,6 +41,13 @@ class ScreenLine rightFragment = new ScreenLine(rightTokens, rightText, rightScreenDelta, rightBufferDelta, {@stack}) [leftFragment, rightFragment] + tokenAtBufferColumn: (bufferColumn) -> + delta = 0 + for token in @tokens + delta += token.bufferDelta + return token if delta >= bufferColumn + token + concat: (other) -> tokens = @tokens.concat(other.tokens) text = @text + other.text diff --git a/src/app/selection.coffee b/src/app/selection.coffee index 522163dd7..ccdeee59b 100644 --- a/src/app/selection.coffee +++ b/src/app/selection.coffee @@ -126,14 +126,15 @@ class Selection @modifySelection => @cursor.moveToEndOfWord() insertText: (text) -> - { text, shouldOutdent } = @autoIndentText(text) oldBufferRange = @getBufferRange() @editSession.destroyFoldsContainingBufferRow(oldBufferRange.end.row) wasReversed = @isReversed() @clear() newBufferRange = @editSession.buffer.change(oldBufferRange, text) @cursor.setBufferPosition(newBufferRange.end, skipAtomicTokens: true) if wasReversed - @autoOutdent() if shouldOutdent + + if @editSession.autoIndent + @editSession.autoIndentRows(newBufferRange.start.row, newBufferRange.end.row) backspace: -> if @isEmpty() and not @editSession.isFoldedAtScreenRow(@cursor.getScreenRow()) diff --git a/src/app/tokenized-buffer.coffee b/src/app/tokenized-buffer.coffee index c4d62fe56..e6db47165 100644 --- a/src/app/tokenized-buffer.coffee +++ b/src/app/tokenized-buffer.coffee @@ -77,6 +77,11 @@ class TokenizedBuffer stackForRow: (row) -> @screenLines[row]?.stack + scopesForPosition: (position) -> + position = Point.fromObject(position) + token = @screenLines[position.row].tokenAtBufferColumn(position.column) + token.scopes + destroy: -> @buffer.off ".tokenized-buffer#{@id}"