mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2025-01-09 00:30:14 +03:00
Merge branch 'invisibles'
This commit is contained in:
commit
33b1b66ee4
@ -91,7 +91,7 @@ describe "TokenizedBuffer.", ->
|
|||||||
{ languageMode, buffer } = editSession
|
{ languageMode, buffer } = editSession
|
||||||
|
|
||||||
benchmark "construction", 20, ->
|
benchmark "construction", 20, ->
|
||||||
new TokenizedBuffer(buffer, { languageMode, tabText: ' '})
|
new TokenizedBuffer(buffer, { languageMode, tabLength: 2})
|
||||||
|
|
||||||
describe "OnigRegExp.", ->
|
describe "OnigRegExp.", ->
|
||||||
[regexes, line] = []
|
[regexes, line] = []
|
||||||
|
@ -2,10 +2,10 @@ DisplayBuffer = require 'display-buffer'
|
|||||||
Buffer = require 'buffer'
|
Buffer = require 'buffer'
|
||||||
|
|
||||||
describe "DisplayBuffer", ->
|
describe "DisplayBuffer", ->
|
||||||
[editSession, displayBuffer, buffer, changeHandler, tabText] = []
|
[editSession, displayBuffer, buffer, changeHandler, tabLength] = []
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
tabText = ' '
|
tabLength = 2
|
||||||
editSession = fixturesProject.buildEditSessionForPath('sample.js', { tabText })
|
editSession = fixturesProject.buildEditSessionForPath('sample.js', { tabLength })
|
||||||
{ buffer, displayBuffer } = editSession
|
{ buffer, displayBuffer } = editSession
|
||||||
changeHandler = jasmine.createSpy 'changeHandler'
|
changeHandler = jasmine.createSpy 'changeHandler'
|
||||||
displayBuffer.on 'change', changeHandler
|
displayBuffer.on 'change', changeHandler
|
||||||
@ -636,14 +636,14 @@ describe "DisplayBuffer", ->
|
|||||||
buffer.insert([0, 0], '\t')
|
buffer.insert([0, 0], '\t')
|
||||||
expect(displayBuffer.clipScreenPosition([0, 0])).toEqual [0, 0]
|
expect(displayBuffer.clipScreenPosition([0, 0])).toEqual [0, 0]
|
||||||
expect(displayBuffer.clipScreenPosition([0, 1])).toEqual [0, 0]
|
expect(displayBuffer.clipScreenPosition([0, 1])).toEqual [0, 0]
|
||||||
expect(displayBuffer.clipScreenPosition([0, tabText.length])).toEqual [0, tabText.length]
|
expect(displayBuffer.clipScreenPosition([0, tabLength])).toEqual [0, tabLength]
|
||||||
|
|
||||||
describe "when skipAtomicTokens is true", ->
|
describe "when skipAtomicTokens is true", ->
|
||||||
it "clips screen positions in the middle of atomic tab characters to the end of the character", ->
|
it "clips screen positions in the middle of atomic tab characters to the end of the character", ->
|
||||||
buffer.insert([0, 0], '\t')
|
buffer.insert([0, 0], '\t')
|
||||||
expect(displayBuffer.clipScreenPosition([0, 0], skipAtomicTokens: true)).toEqual [0, 0]
|
expect(displayBuffer.clipScreenPosition([0, 0], skipAtomicTokens: true)).toEqual [0, 0]
|
||||||
expect(displayBuffer.clipScreenPosition([0, 1], skipAtomicTokens: true)).toEqual [0, tabText.length]
|
expect(displayBuffer.clipScreenPosition([0, 1], skipAtomicTokens: true)).toEqual [0, tabLength]
|
||||||
expect(displayBuffer.clipScreenPosition([0, tabText.length], skipAtomicTokens: true)).toEqual [0, tabText.length]
|
expect(displayBuffer.clipScreenPosition([0, tabLength], skipAtomicTokens: true)).toEqual [0, tabLength]
|
||||||
|
|
||||||
describe ".maxLineLength()", ->
|
describe ".maxLineLength()", ->
|
||||||
it "returns the length of the longest screen line", ->
|
it "returns the length of the longest screen line", ->
|
||||||
|
@ -1141,8 +1141,8 @@ describe "EditSession", ->
|
|||||||
describe ".indent()", ->
|
describe ".indent()", ->
|
||||||
describe "when nothing is selected", ->
|
describe "when nothing is selected", ->
|
||||||
describe "if 'softTabs' is true (the default)", ->
|
describe "if 'softTabs' is true (the default)", ->
|
||||||
it "inserts the value of 'tabText' into the buffer", ->
|
it "inserts 'tabLength' spaces into the buffer", ->
|
||||||
tabRegex = new RegExp("^#{editSession.tabText}")
|
tabRegex = new RegExp("^[ ]{#{editSession.tabLength}}")
|
||||||
expect(buffer.lineForRow(0)).not.toMatch(tabRegex)
|
expect(buffer.lineForRow(0)).not.toMatch(tabRegex)
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
expect(buffer.lineForRow(0)).toMatch(tabRegex)
|
expect(buffer.lineForRow(0)).toMatch(tabRegex)
|
||||||
@ -1151,7 +1151,7 @@ describe "EditSession", ->
|
|||||||
describe "when the preceding line opens a new level of indentation", ->
|
describe "when the preceding line opens a new level of indentation", ->
|
||||||
it "increases the level of indentation by one", ->
|
it "increases the level of indentation by one", ->
|
||||||
buffer.insert([5, 0], " \n")
|
buffer.insert([5, 0], " \n")
|
||||||
editSession.tabText = " "
|
editSession.tabLength = 2
|
||||||
editSession.setCursorBufferPosition [5, 2]
|
editSession.setCursorBufferPosition [5, 2]
|
||||||
editSession.setAutoIndent(true)
|
editSession.setAutoIndent(true)
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
@ -1162,7 +1162,7 @@ describe "EditSession", ->
|
|||||||
describe "when there are empty lines preceding the current line", ->
|
describe "when there are empty lines preceding the current line", ->
|
||||||
it "bases indentation on the first non-blank preceding line", ->
|
it "bases indentation on the first non-blank preceding line", ->
|
||||||
buffer.insert([5, 0], "\n\n\n \n")
|
buffer.insert([5, 0], "\n\n\n \n")
|
||||||
editSession.tabText = " "
|
editSession.tabLength = 2
|
||||||
editSession.setCursorBufferPosition [8, 2]
|
editSession.setCursorBufferPosition [8, 2]
|
||||||
editSession.setAutoIndent(true)
|
editSession.setAutoIndent(true)
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
@ -1172,7 +1172,7 @@ describe "EditSession", ->
|
|||||||
|
|
||||||
it "properly indents the line", ->
|
it "properly indents the line", ->
|
||||||
buffer.insert([7, 0], " \n")
|
buffer.insert([7, 0], " \n")
|
||||||
editSession.tabText = " "
|
editSession.tabLength = 2
|
||||||
editSession.setCursorBufferPosition [7, 2]
|
editSession.setCursorBufferPosition [7, 2]
|
||||||
editSession.setAutoIndent(true)
|
editSession.setAutoIndent(true)
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
@ -1182,7 +1182,7 @@ describe "EditSession", ->
|
|||||||
|
|
||||||
it "allows for additional indentation if the cursor is beyond the proper indentation point", ->
|
it "allows for additional indentation if the cursor is beyond the proper indentation point", ->
|
||||||
buffer.insert([7, 0], " \n")
|
buffer.insert([7, 0], " \n")
|
||||||
editSession.tabText = " "
|
editSession.tabLength = 2
|
||||||
editSession.setCursorBufferPosition [7, 6]
|
editSession.setCursorBufferPosition [7, 6]
|
||||||
editSession.setAutoIndent(true)
|
editSession.setAutoIndent(true)
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
@ -1197,12 +1197,12 @@ describe "EditSession", ->
|
|||||||
editSession.indent()
|
editSession.indent()
|
||||||
expect(buffer.lineForRow(0)).toMatch(/^\t/)
|
expect(buffer.lineForRow(0)).toMatch(/^\t/)
|
||||||
expect(editSession.getCursorBufferPosition()).toEqual [0, 1]
|
expect(editSession.getCursorBufferPosition()).toEqual [0, 1]
|
||||||
expect(editSession.getCursorScreenPosition()).toEqual [0, editSession.tabText.length]
|
expect(editSession.getCursorScreenPosition()).toEqual [0, editSession.tabLength]
|
||||||
|
|
||||||
editSession.indent()
|
editSession.indent()
|
||||||
expect(buffer.lineForRow(0)).toMatch(/^\t\t/)
|
expect(buffer.lineForRow(0)).toMatch(/^\t\t/)
|
||||||
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
|
expect(editSession.getCursorBufferPosition()).toEqual [0, 2]
|
||||||
expect(editSession.getCursorScreenPosition()).toEqual [0, editSession.tabText.length * 2]
|
expect(editSession.getCursorScreenPosition()).toEqual [0, editSession.tabLength * 2]
|
||||||
|
|
||||||
describe "pasteboard operations", ->
|
describe "pasteboard operations", ->
|
||||||
pasteboard = null
|
pasteboard = null
|
||||||
@ -1254,24 +1254,22 @@ describe "EditSession", ->
|
|||||||
expect(buffer.lineForRow(1)).toBe " var first = function(items) {"
|
expect(buffer.lineForRow(1)).toBe " var first = function(items) {"
|
||||||
|
|
||||||
describe ".indentSelectedRows()", ->
|
describe ".indentSelectedRows()", ->
|
||||||
tabLength = null
|
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
tabLength = editSession.tabText.length
|
editSession.tabLength = 2
|
||||||
|
|
||||||
describe "when nothing is selected", ->
|
describe "when nothing is selected", ->
|
||||||
it "indents line and retains selection", ->
|
it "indents line and retains selection", ->
|
||||||
editSession.setSelectedBufferRange([[0,3], [0,3]])
|
editSession.setSelectedBufferRange([[0,3], [0,3]])
|
||||||
editSession.indentSelectedRows()
|
editSession.indentSelectedRows()
|
||||||
expect(buffer.lineForRow(0)).toBe "#{editSession.tabText}var quicksort = function () {"
|
expect(buffer.lineForRow(0)).toBe "#{editSession.getTabText()}var quicksort = function () {"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[0, 3 + tabLength], [0, 3 + tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[0, 3 + editSession.tabLength], [0, 3 + editSession.tabLength]]
|
||||||
|
|
||||||
describe "when one line is selected", ->
|
describe "when one line is selected", ->
|
||||||
it "indents line and retains selection", ->
|
it "indents line and retains selection", ->
|
||||||
editSession.setSelectedBufferRange([[0,4], [0,14]])
|
editSession.setSelectedBufferRange([[0,4], [0,14]])
|
||||||
editSession.indentSelectedRows()
|
editSession.indentSelectedRows()
|
||||||
expect(buffer.lineForRow(0)).toBe "#{editSession.tabText}var quicksort = function () {"
|
expect(buffer.lineForRow(0)).toBe "#{editSession.getTabText()}var quicksort = function () {"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[0, 4 + tabLength], [0, 14 + tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[0, 4 + editSession.tabLength], [0, 14 + editSession.tabLength]]
|
||||||
|
|
||||||
describe "when multiple lines are selected", ->
|
describe "when multiple lines are selected", ->
|
||||||
it "indents selected lines (that are not empty) and retains selection", ->
|
it "indents selected lines (that are not empty) and retains selection", ->
|
||||||
@ -1280,28 +1278,25 @@ describe "EditSession", ->
|
|||||||
expect(buffer.lineForRow(9)).toBe " };"
|
expect(buffer.lineForRow(9)).toBe " };"
|
||||||
expect(buffer.lineForRow(10)).toBe ""
|
expect(buffer.lineForRow(10)).toBe ""
|
||||||
expect(buffer.lineForRow(11)).toBe " return sort(Array.apply(this, arguments));"
|
expect(buffer.lineForRow(11)).toBe " return sort(Array.apply(this, arguments));"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[9, 1 + tabLength], [11, 15 + tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[9, 1 + editSession.tabLength], [11, 15 + editSession.tabLength]]
|
||||||
|
|
||||||
describe ".outdentSelectedRows()", ->
|
describe ".outdentSelectedRows()", ->
|
||||||
tabLength = null
|
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
editSession.tabText = " "
|
editSession.tabLength = 2
|
||||||
tabLength = editSession.tabText.length
|
|
||||||
|
|
||||||
describe "when nothing is selected", ->
|
describe "when nothing is selected", ->
|
||||||
it "outdents line and retains selection", ->
|
it "outdents line and retains selection", ->
|
||||||
editSession.setSelectedBufferRange([[1,3], [1,3]])
|
editSession.setSelectedBufferRange([[1,3], [1,3]])
|
||||||
editSession.outdentSelectedRows()
|
editSession.outdentSelectedRows()
|
||||||
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[1, 3 - tabLength], [1, 3 - tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[1, 3 - editSession.tabLength], [1, 3 - editSession.tabLength]]
|
||||||
|
|
||||||
describe "when one line is selected", ->
|
describe "when one line is selected", ->
|
||||||
it "outdents line and retains editSession", ->
|
it "outdents line and retains editSession", ->
|
||||||
editSession.setSelectedBufferRange([[1,4], [1,14]])
|
editSession.setSelectedBufferRange([[1,4], [1,14]])
|
||||||
editSession.outdentSelectedRows()
|
editSession.outdentSelectedRows()
|
||||||
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[1, 4 - tabLength], [1, 14 - tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[1, 4 - editSession.tabLength], [1, 14 - editSession.tabLength]]
|
||||||
|
|
||||||
describe "when multiple lines are selected", ->
|
describe "when multiple lines are selected", ->
|
||||||
it "outdents selected lines and retains editSession", ->
|
it "outdents selected lines and retains editSession", ->
|
||||||
@ -1310,7 +1305,7 @@ describe "EditSession", ->
|
|||||||
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
|
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
|
||||||
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
expect(buffer.lineForRow(1)).toBe "var sort = function(items) {"
|
||||||
expect(buffer.lineForRow(2)).toBe " if (items.length <= 1) return items;"
|
expect(buffer.lineForRow(2)).toBe " if (items.length <= 1) return items;"
|
||||||
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [3, 15 - tabLength]]
|
expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [3, 15 - editSession.tabLength]]
|
||||||
|
|
||||||
describe ".toggleLineCommentsInSelection()", ->
|
describe ".toggleLineCommentsInSelection()", ->
|
||||||
it "toggles comments on the selected lines", ->
|
it "toggles comments on the selected lines", ->
|
||||||
|
@ -1472,6 +1472,17 @@ describe "Editor", ->
|
|||||||
expect(editor.renderedLines.find('.line:eq(14)').text()).toBe 'B'
|
expect(editor.renderedLines.find('.line:eq(14)').text()).toBe 'B'
|
||||||
expect(editor.renderedLines.find('.line:eq(15)')).not.toExist()
|
expect(editor.renderedLines.find('.line:eq(15)')).not.toExist()
|
||||||
|
|
||||||
|
describe "when editor.setShowInvisibles is called", ->
|
||||||
|
it "displays spaces as •, tabs as ▸ and newlines as ¬ when true", ->
|
||||||
|
editor.attachToDom()
|
||||||
|
editor.setText " a line with tabs\tand spaces "
|
||||||
|
expect(editor.showInvisibles).toBeFalsy()
|
||||||
|
expect(editor.find('.line').text()).toBe " a line with tabs and spaces "
|
||||||
|
editor.setShowInvisibles(true)
|
||||||
|
expect(editor.find('.line').text()).toBe "•a line with tabs▸ and spaces•¬"
|
||||||
|
editor.setShowInvisibles(false)
|
||||||
|
expect(editor.find('.line').text()).toBe " a line with tabs and spaces "
|
||||||
|
|
||||||
describe "gutter rendering", ->
|
describe "gutter rendering", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
editor.attachToDom(heightInLines: 5.5)
|
editor.attachToDom(heightInLines: 5.5)
|
||||||
@ -1595,7 +1606,6 @@ describe "Editor", ->
|
|||||||
expect(miniEditor.getCursorBufferPosition().row).toBe 0
|
expect(miniEditor.getCursorBufferPosition().row).toBe 0
|
||||||
expect(miniEditor.find('.line.cursor-line').length).toBe 0
|
expect(miniEditor.find('.line.cursor-line').length).toBe 0
|
||||||
|
|
||||||
|
|
||||||
describe "gutter line highlighting", ->
|
describe "gutter line highlighting", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
editor.attachToDom(heightInLines: 5.5)
|
editor.attachToDom(heightInLines: 5.5)
|
||||||
|
@ -690,3 +690,27 @@ describe "RootView", ->
|
|||||||
expect(fs.read(buffer1.getPath())).toBe("edited1")
|
expect(fs.read(buffer1.getPath())).toBe("edited1")
|
||||||
expect(buffer2.isModified()).toBe(false)
|
expect(buffer2.isModified()).toBe(false)
|
||||||
expect(fs.read(buffer2.getPath())).toBe("edited2")
|
expect(fs.read(buffer2.getPath())).toBe("edited2")
|
||||||
|
|
||||||
|
describe "window:toggle-invisibles event", ->
|
||||||
|
it "shows/hides invisibles in all open and future editors", ->
|
||||||
|
rootView.height(200)
|
||||||
|
rootView.attachToDom()
|
||||||
|
rightEditor = rootView.getActiveEditor()
|
||||||
|
rightEditor.setText(" \t ")
|
||||||
|
leftEditor = rightEditor.splitLeft()
|
||||||
|
expect(rightEditor.find(".line:first").text()).toBe " "
|
||||||
|
expect(leftEditor.find(".line:first").text()).toBe " "
|
||||||
|
|
||||||
|
rootView.trigger "root-view:toggle-invisibles"
|
||||||
|
expect(rightEditor.find(".line:first").text()).toBe "•▸ •¬"
|
||||||
|
expect(leftEditor.find(".line:first").text()).toBe "•▸ •¬"
|
||||||
|
|
||||||
|
lowerLeftEditor = leftEditor.splitDown()
|
||||||
|
expect(lowerLeftEditor.find(".line:first").text()).toBe "•▸ •¬"
|
||||||
|
|
||||||
|
rootView.trigger "root-view:toggle-invisibles"
|
||||||
|
expect(rightEditor.find(".line:first").text()).toBe " "
|
||||||
|
expect(leftEditor.find(".line:first").text()).toBe " "
|
||||||
|
|
||||||
|
lowerRightEditor = rightEditor.splitDown()
|
||||||
|
expect(lowerRightEditor.find(".line:first").text()).toBe " "
|
||||||
|
@ -3,11 +3,10 @@ Buffer = require 'buffer'
|
|||||||
TokenizedBuffer = require 'tokenized-buffer'
|
TokenizedBuffer = require 'tokenized-buffer'
|
||||||
|
|
||||||
describe "ScreenLine", ->
|
describe "ScreenLine", ->
|
||||||
[editSession, buffer, tabText, screenLine, tokenizedBuffer] = []
|
[editSession, buffer, screenLine, tokenizedBuffer] = []
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
tabText = '••'
|
editSession = fixturesProject.buildEditSessionForPath('sample.js', { tabLength: 2 } )
|
||||||
editSession = fixturesProject.buildEditSessionForPath('sample.js', { tabText } )
|
|
||||||
{ buffer, tokenizedBuffer } = editSession
|
{ buffer, tokenizedBuffer } = editSession
|
||||||
screenLine = tokenizedBuffer.lineForScreenRow(3)
|
screenLine = tokenizedBuffer.lineForScreenRow(3)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ describe "Selection", ->
|
|||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
buffer = new Buffer(require.resolve('fixtures/sample.js'))
|
buffer = new Buffer(require.resolve('fixtures/sample.js'))
|
||||||
editSession = new EditSession(buffer: buffer, tabText: ' ')
|
editSession = new EditSession(buffer: buffer, tabLength: 2)
|
||||||
selection = editSession.getSelection()
|
selection = editSession.getSelection()
|
||||||
|
|
||||||
afterEach ->
|
afterEach ->
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
_ = require 'underscore'
|
|
||||||
Buffer = require 'buffer'
|
|
||||||
TokenizedBuffer = require 'tokenized-buffer'
|
|
||||||
|
|
||||||
describe "Token", ->
|
|
||||||
[editSession, token] = []
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
tabText = ' '
|
|
||||||
editSession = fixturesProject.buildEditSessionForPath('sample.js')
|
|
||||||
{ tokenizedBuffer } = editSession
|
|
||||||
screenLine = tokenizedBuffer.lineForScreenRow(3)
|
|
||||||
token = _.last(screenLine.tokens)
|
|
||||||
|
|
||||||
afterEach ->
|
|
||||||
editSession.destroy()
|
|
@ -151,25 +151,25 @@ describe "TokenizedBuffer", ->
|
|||||||
expect(event.newRange).toEqual new Range([2, 0], [7, buffer.lineForRow(7).length])
|
expect(event.newRange).toEqual new Range([2, 0], [7, buffer.lineForRow(7).length])
|
||||||
|
|
||||||
describe "when the buffer contains tab characters", ->
|
describe "when the buffer contains tab characters", ->
|
||||||
tabText = ' '
|
|
||||||
editSession2 = null
|
editSession2 = null
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
editSession2 = fixturesProject.buildEditSessionForPath('sample-with-tabs.coffee', { tabText })
|
tabLength = 2
|
||||||
|
editSession2 = fixturesProject.buildEditSessionForPath('sample-with-tabs.coffee', { tabLength })
|
||||||
{ buffer, tokenizedBuffer } = editSession2
|
{ buffer, tokenizedBuffer } = editSession2
|
||||||
|
|
||||||
afterEach ->
|
afterEach ->
|
||||||
editSession2.destroy()
|
editSession2.destroy()
|
||||||
|
|
||||||
it "always renders each tab as its own atomic token containing tabText", ->
|
it "always renders each tab as its own atomic token with a value of size tabLength", ->
|
||||||
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
|
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
|
||||||
expect(screenLine0.text).toBe "# Econ 101#{tabText}"
|
expect(screenLine0.text).toBe "# Econ 101#{editSession2.getTabText()}"
|
||||||
{ tokens } = screenLine0
|
{ tokens } = screenLine0
|
||||||
expect(tokens.length).toBe 3
|
expect(tokens.length).toBe 3
|
||||||
expect(tokens[0].value).toBe "#"
|
expect(tokens[0].value).toBe "#"
|
||||||
expect(tokens[1].value).toBe " Econ 101"
|
expect(tokens[1].value).toBe " Econ 101"
|
||||||
expect(tokens[2].value).toBe tabText
|
expect(tokens[2].value).toBe editSession2.getTabText()
|
||||||
expect(tokens[2].scopes).toEqual tokens[1].scopes
|
expect(tokens[2].scopes).toEqual tokens[1].scopes
|
||||||
expect(tokens[2].isAtomic).toBeTruthy()
|
expect(tokens[2].isAtomic).toBeTruthy()
|
||||||
|
|
||||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabText} buy()#{tabText}while supply > demand"
|
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{editSession2.getTabText()} buy()#{editSession2.getTabText()}while supply > demand"
|
||||||
|
@ -20,7 +20,6 @@ class DisplayBuffer
|
|||||||
|
|
||||||
constructor: (@buffer, options={}) ->
|
constructor: (@buffer, options={}) ->
|
||||||
@id = @constructor.idCounter++
|
@id = @constructor.idCounter++
|
||||||
options.tabText ?= ' '
|
|
||||||
@languageMode = options.languageMode
|
@languageMode = options.languageMode
|
||||||
@tokenizedBuffer = new TokenizedBuffer(@buffer, options)
|
@tokenizedBuffer = new TokenizedBuffer(@buffer, options)
|
||||||
@softWrapColumn = options.softWrapColumn ? Infinity
|
@softWrapColumn = options.softWrapColumn ? Infinity
|
||||||
|
@ -35,14 +35,15 @@ class EditSession
|
|||||||
cursors: null
|
cursors: null
|
||||||
selections: null
|
selections: null
|
||||||
autoIndent: false # TODO: re-enabled auto-indent after fixing the rest of tokenization
|
autoIndent: false # TODO: re-enabled auto-indent after fixing the rest of tokenization
|
||||||
|
tabLength: null
|
||||||
softTabs: true
|
softTabs: true
|
||||||
softWrap: false
|
softWrap: false
|
||||||
|
|
||||||
constructor: ({@project, @buffer, @tabText, @autoIndent, @softTabs, @softWrap}) ->
|
constructor: ({@project, @buffer, @tabLength, @autoIndent, @softTabs, @softWrap }) ->
|
||||||
@id = @constructor.idCounter++
|
@id = @constructor.idCounter++
|
||||||
@softTabs ?= true
|
@softTabs ?= true
|
||||||
@languageMode = new LanguageMode(this, @buffer.getExtension())
|
@languageMode = new LanguageMode(this, @buffer.getExtension())
|
||||||
@displayBuffer = new DisplayBuffer(@buffer, { @languageMode, @tabText })
|
@displayBuffer = new DisplayBuffer(@buffer, { @languageMode, @tabLength })
|
||||||
@tokenizedBuffer = @displayBuffer.tokenizedBuffer
|
@tokenizedBuffer = @displayBuffer.tokenizedBuffer
|
||||||
@anchors = []
|
@anchors = []
|
||||||
@anchorRanges = []
|
@anchorRanges = []
|
||||||
@ -106,6 +107,8 @@ class EditSession
|
|||||||
getSoftWrap: -> @softWrap
|
getSoftWrap: -> @softWrap
|
||||||
setSoftWrap: (@softWrap) ->
|
setSoftWrap: (@softWrap) ->
|
||||||
|
|
||||||
|
getTabText: -> new Array(@tabLength + 1).join(" ")
|
||||||
|
|
||||||
clipBufferPosition: (bufferPosition) ->
|
clipBufferPosition: (bufferPosition) ->
|
||||||
@buffer.clipPosition(bufferPosition)
|
@buffer.clipPosition(bufferPosition)
|
||||||
|
|
||||||
@ -149,7 +152,7 @@ class EditSession
|
|||||||
currentRow = @getCursorBufferPosition().row
|
currentRow = @getCursorBufferPosition().row
|
||||||
if @getSelection().isEmpty()
|
if @getSelection().isEmpty()
|
||||||
if @softTabs
|
if @softTabs
|
||||||
@insertText(@tabText)
|
@insertText(@getTabText())
|
||||||
else
|
else
|
||||||
@insertText('\t')
|
@insertText('\t')
|
||||||
else
|
else
|
||||||
|
@ -46,12 +46,12 @@ class Editor extends View
|
|||||||
|
|
||||||
@deserialize: (state, rootView) ->
|
@deserialize: (state, rootView) ->
|
||||||
editSessions = state.editSessions.map (state) -> EditSession.deserialize(state, rootView.project)
|
editSessions = state.editSessions.map (state) -> EditSession.deserialize(state, rootView.project)
|
||||||
editor = new Editor(editSession: editSessions[state.activeEditSessionIndex], mini: state.mini)
|
editor = new Editor(editSession: editSessions[state.activeEditSessionIndex], mini: state.mini, showInvisibles: rootView.showInvisibles)
|
||||||
editor.editSessions = editSessions
|
editor.editSessions = editSessions
|
||||||
editor.isFocused = state.isFocused
|
editor.isFocused = state.isFocused
|
||||||
editor
|
editor
|
||||||
|
|
||||||
initialize: ({editSession, @mini} = {}) ->
|
initialize: ({editSession, @mini, @showInvisibles} = {}) ->
|
||||||
requireStylesheet 'editor.css'
|
requireStylesheet 'editor.css'
|
||||||
|
|
||||||
@id = Editor.idCounter++
|
@id = Editor.idCounter++
|
||||||
@ -69,7 +69,7 @@ class Editor extends View
|
|||||||
editSession = new EditSession
|
editSession = new EditSession
|
||||||
buffer: new Buffer()
|
buffer: new Buffer()
|
||||||
softWrap: false
|
softWrap: false
|
||||||
tabText: " "
|
tabLength: 2
|
||||||
autoIndent: false
|
autoIndent: false
|
||||||
softTabs: true
|
softTabs: true
|
||||||
|
|
||||||
@ -265,6 +265,11 @@ class Editor extends View
|
|||||||
getPageRows: ->
|
getPageRows: ->
|
||||||
Math.max(1, Math.ceil(@scrollView[0].clientHeight / @lineHeight))
|
Math.max(1, Math.ceil(@scrollView[0].clientHeight / @lineHeight))
|
||||||
|
|
||||||
|
setShowInvisibles: (showInvisibles) ->
|
||||||
|
return if showInvisibles == @showInvisibles
|
||||||
|
@showInvisibles = showInvisibles
|
||||||
|
@renderLines()
|
||||||
|
|
||||||
setText: (text) -> @getBuffer().setText(text)
|
setText: (text) -> @getBuffer().setText(text)
|
||||||
getText: -> @getBuffer().getText()
|
getText: -> @getBuffer().getText()
|
||||||
getPath: -> @getBuffer().getPath()
|
getPath: -> @getBuffer().getPath()
|
||||||
@ -569,7 +574,7 @@ class Editor extends View
|
|||||||
@updateRenderedLines()
|
@updateRenderedLines()
|
||||||
|
|
||||||
newSplitEditor: ->
|
newSplitEditor: ->
|
||||||
new Editor { editSession: @activeEditSession.copy() }
|
new Editor { editSession: @activeEditSession.copy(), @showInvisibles }
|
||||||
|
|
||||||
splitLeft: ->
|
splitLeft: ->
|
||||||
@pane()?.splitLeft(@newSplitEditor()).wrappedView
|
@pane()?.splitLeft(@newSplitEditor()).wrappedView
|
||||||
@ -874,20 +879,23 @@ class Editor extends View
|
|||||||
line.push("<pre #{attributePairs.join(' ')}>")
|
line.push("<pre #{attributePairs.join(' ')}>")
|
||||||
|
|
||||||
if screenLine.text == ''
|
if screenLine.text == ''
|
||||||
line.push(' ')
|
line.push(" ") unless @showInvisibles
|
||||||
else
|
else
|
||||||
|
firstNonWhitespacePosition = screenLine.text.search(/\S/)
|
||||||
|
firstTrailingWhitespacePosition = screenLine.text.search(/\s*$/)
|
||||||
|
position = 0
|
||||||
for token in screenLine.tokens
|
for token in screenLine.tokens
|
||||||
updateScopeStack(token.scopes)
|
updateScopeStack(token.scopes)
|
||||||
line.push(
|
line.push(token.getValueAsHtml(
|
||||||
token.value
|
showInvisibles: @showInvisibles
|
||||||
.replace(/&/g, '&')
|
hasLeadingWhitespace: position < firstNonWhitespacePosition
|
||||||
.replace(/"/g, '"')
|
hasTrailingWhitespace: position + token.value.length > firstTrailingWhitespacePosition
|
||||||
.replace(/'/g, ''')
|
))
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
)
|
|
||||||
|
|
||||||
line.push("</pre>")
|
position += token.value.length
|
||||||
|
|
||||||
|
line.push("<span class='invisible'>¬</span>") if @showInvisibles
|
||||||
|
line.push('</pre>')
|
||||||
line.join('')
|
line.join('')
|
||||||
|
|
||||||
insertLineElements: (row, lineElements) ->
|
insertLineElements: (row, lineElements) ->
|
||||||
|
@ -104,7 +104,7 @@ class LanguageMode
|
|||||||
|
|
||||||
currentIndentation = @buffer.indentationForRow(bufferRow)
|
currentIndentation = @buffer.indentationForRow(bufferRow)
|
||||||
desiredIndentation = @buffer.indentationForRow(precedingRow)
|
desiredIndentation = @buffer.indentationForRow(precedingRow)
|
||||||
desiredIndentation += @editSession.tabText.length if increaseIndentPattern.test(precedingLine)
|
desiredIndentation += @editSession.tabLength if increaseIndentPattern.test(precedingLine)
|
||||||
if desiredIndentation > currentIndentation
|
if desiredIndentation > currentIndentation
|
||||||
@buffer.setIndentationForRow(bufferRow, desiredIndentation)
|
@buffer.setIndentationForRow(bufferRow, desiredIndentation)
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ class LanguageMode
|
|||||||
precedingLine = @buffer.lineForRow(precedingRow)
|
precedingLine = @buffer.lineForRow(precedingRow)
|
||||||
|
|
||||||
desiredIndentation = @buffer.indentationForRow(precedingRow)
|
desiredIndentation = @buffer.indentationForRow(precedingRow)
|
||||||
desiredIndentation -= @editSession.tabText.length unless increaseIndentPattern.test(precedingLine)
|
desiredIndentation -= @editSession.tabLength unless increaseIndentPattern.test(precedingLine)
|
||||||
if desiredIndentation < currentIndentation
|
if desiredIndentation < currentIndentation
|
||||||
@buffer.setIndentationForRow(bufferRow, desiredIndentation)
|
@buffer.setIndentationForRow(bufferRow, desiredIndentation)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ ChildProcess = require 'child-process'
|
|||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
class Project
|
class Project
|
||||||
tabText: ' '
|
tabLength: 2
|
||||||
autoIndent: true
|
autoIndent: true
|
||||||
softTabs: true
|
softTabs: true
|
||||||
softWrap: false
|
softWrap: false
|
||||||
@ -101,9 +101,6 @@ class Project
|
|||||||
relativize: (fullPath) ->
|
relativize: (fullPath) ->
|
||||||
fullPath.replace(@getPath(), "").replace(/^\//, '')
|
fullPath.replace(@getPath(), "").replace(/^\//, '')
|
||||||
|
|
||||||
getTabText: -> @tabText
|
|
||||||
setTabText: (@tabText) ->
|
|
||||||
|
|
||||||
getAutoIndent: -> @autoIndent
|
getAutoIndent: -> @autoIndent
|
||||||
setAutoIndent: (@autoIndent) ->
|
setAutoIndent: (@autoIndent) ->
|
||||||
|
|
||||||
@ -126,7 +123,7 @@ class Project
|
|||||||
editSession
|
editSession
|
||||||
|
|
||||||
defaultEditSessionOptions: ->
|
defaultEditSessionOptions: ->
|
||||||
tabText: @getTabText()
|
tabLength: @tabLength
|
||||||
autoIndent: @getAutoIndent()
|
autoIndent: @getAutoIndent()
|
||||||
softTabs: @getSoftTabs()
|
softTabs: @getSoftTabs()
|
||||||
softWrap: @getSoftWrap()
|
softWrap: @getSoftWrap()
|
||||||
|
@ -31,6 +31,7 @@ class RootView extends View
|
|||||||
extensions: null
|
extensions: null
|
||||||
extensionStates: null
|
extensionStates: null
|
||||||
fontSize: 20
|
fontSize: 20
|
||||||
|
showInvisibles: false
|
||||||
|
|
||||||
initialize: (pathToOpen, { @extensionStates, suppressOpen } = {}) ->
|
initialize: (pathToOpen, { @extensionStates, suppressOpen } = {}) ->
|
||||||
window.rootView = this
|
window.rootView = this
|
||||||
@ -77,6 +78,7 @@ class RootView extends View
|
|||||||
@on 'root-view:decrease-font-size', => @setFontSize(@getFontSize() - 1)
|
@on 'root-view:decrease-font-size', => @setFontSize(@getFontSize() - 1)
|
||||||
@on 'root-view:focus-next-pane', => @focusNextPane()
|
@on 'root-view:focus-next-pane', => @focusNextPane()
|
||||||
@on 'root-view:save-all', => @saveAll()
|
@on 'root-view:save-all', => @saveAll()
|
||||||
|
@on 'root-view:toggle-invisibles', => @setShowInvisibles(not @showInvisibles)
|
||||||
|
|
||||||
afterAttach: (onDom) ->
|
afterAttach: (onDom) ->
|
||||||
@focus() if onDom
|
@focus() if onDom
|
||||||
@ -117,7 +119,7 @@ class RootView extends View
|
|||||||
|
|
||||||
unless editSession = @openInExistingEditor(path, allowActiveEditorChange, changeFocus)
|
unless editSession = @openInExistingEditor(path, allowActiveEditorChange, changeFocus)
|
||||||
editSession = @project.buildEditSessionForPath(path)
|
editSession = @project.buildEditSessionForPath(path)
|
||||||
editor = new Editor({editSession})
|
editor = new Editor({editSession, @showInvisibles})
|
||||||
pane = new Pane(editor)
|
pane = new Pane(editor)
|
||||||
@panes.append(pane)
|
@panes.append(pane)
|
||||||
if changeFocus
|
if changeFocus
|
||||||
@ -170,6 +172,11 @@ class RootView extends View
|
|||||||
setTitle: (title='untitled') ->
|
setTitle: (title='untitled') ->
|
||||||
document.title = title
|
document.title = title
|
||||||
|
|
||||||
|
setShowInvisibles: (showInvisibles) ->
|
||||||
|
return if @showInvisibles == showInvisibles
|
||||||
|
@showInvisibles = showInvisibles
|
||||||
|
editor.setShowInvisibles(@showInvisibles) for editor in @getEditors()
|
||||||
|
|
||||||
getEditors: ->
|
getEditors: ->
|
||||||
@panes.find('.pane > .editor').map(-> $(this).view()).toArray()
|
@panes.find('.pane > .editor').map(-> $(this).view()).toArray()
|
||||||
|
|
||||||
|
@ -208,15 +208,15 @@ class Selection
|
|||||||
indentSelectedRows: ->
|
indentSelectedRows: ->
|
||||||
range = @getBufferRange()
|
range = @getBufferRange()
|
||||||
for row in [range.start.row..range.end.row]
|
for row in [range.start.row..range.end.row]
|
||||||
@editSession.buffer.insert([row, 0], @editSession.tabText) unless @editSession.buffer.lineLengthForRow(row) == 0
|
@editSession.buffer.insert([row, 0], @editSession.getTabText()) unless @editSession.buffer.lineLengthForRow(row) == 0
|
||||||
|
|
||||||
outdentSelectedRows: ->
|
outdentSelectedRows: ->
|
||||||
range = @getBufferRange()
|
range = @getBufferRange()
|
||||||
buffer = @editSession.buffer
|
buffer = @editSession.buffer
|
||||||
leadingTabRegex = new RegExp("^#{@editSession.tabText}")
|
leadingTabRegex = new RegExp("^#{@editSession.getTabText()}")
|
||||||
for row in [range.start.row..range.end.row]
|
for row in [range.start.row..range.end.row]
|
||||||
if leadingTabRegex.test buffer.lineForRow(row)
|
if leadingTabRegex.test buffer.lineForRow(row)
|
||||||
buffer.delete [[row, 0], [row, @editSession.tabText.length]]
|
buffer.delete [[row, 0], [row, @editSession.tabLength]]
|
||||||
|
|
||||||
toggleLineComments: ->
|
toggleLineComments: ->
|
||||||
@modifySelection =>
|
@modifySelection =>
|
||||||
|
@ -5,8 +5,9 @@ class Token
|
|||||||
value: null
|
value: null
|
||||||
scopes: null
|
scopes: null
|
||||||
isAtomic: null
|
isAtomic: null
|
||||||
|
isTab: null
|
||||||
|
|
||||||
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @fold}) ->
|
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @fold, @isTab}) ->
|
||||||
@screenDelta = @value.length
|
@screenDelta = @value.length
|
||||||
@bufferDelta ?= @screenDelta
|
@bufferDelta ?= @screenDelta
|
||||||
|
|
||||||
@ -21,14 +22,41 @@ class Token
|
|||||||
value2 = @value.substring(splitIndex)
|
value2 = @value.substring(splitIndex)
|
||||||
[new Token(value: value1, scopes: @scopes), new Token(value: value2, scopes: @scopes)]
|
[new Token(value: value1, scopes: @scopes), new Token(value: value2, scopes: @scopes)]
|
||||||
|
|
||||||
breakOutTabCharacters: (tabText) ->
|
breakOutTabCharacters: (tabLength, showInvisibles) ->
|
||||||
return [this] unless /\t/.test(@value)
|
return [this] unless /\t/.test(@value)
|
||||||
|
|
||||||
for substring in @value.match(/([^\t]+|\t)/g)
|
for substring in @value.match(/[^\t]+|\t/g)
|
||||||
if substring == '\t'
|
if substring == "\t"
|
||||||
@buildTabToken(tabText)
|
@buildTabToken(tabLength)
|
||||||
else
|
else
|
||||||
new Token(value: substring, scopes: @scopes)
|
new Token(value: substring, scopes: @scopes)
|
||||||
|
|
||||||
buildTabToken: (tabText) ->
|
buildTabToken: (tabLength) ->
|
||||||
new Token(value: tabText, scopes: @scopes, bufferDelta: 1, isAtomic: true)
|
new Token(
|
||||||
|
value: new Array(tabLength + 1).join(" ")
|
||||||
|
scopes: @scopes
|
||||||
|
bufferDelta: 1
|
||||||
|
isAtomic: true
|
||||||
|
isTab: true
|
||||||
|
)
|
||||||
|
|
||||||
|
getValueAsHtml: ({showInvisibles, hasLeadingWhitespace, hasTrailingWhitespace})->
|
||||||
|
html = @value
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
|
||||||
|
if showInvisibles
|
||||||
|
if @isTab
|
||||||
|
html = html.replace(/^./, "<span class='invisible'>▸</span>")
|
||||||
|
else
|
||||||
|
if hasLeadingWhitespace
|
||||||
|
html = html.replace /^[ ]+/, (match) ->
|
||||||
|
"<span class='invisible'>#{match.replace(/./g, '•')}</span>"
|
||||||
|
if hasTrailingWhitespace
|
||||||
|
html = html.replace /[ ]+$/, (match) ->
|
||||||
|
"<span class='invisible'>#{match.replace(/./g, '•')}</span>"
|
||||||
|
|
||||||
|
html
|
||||||
|
@ -10,11 +10,13 @@ class TokenizedBuffer
|
|||||||
@idCounter: 1
|
@idCounter: 1
|
||||||
|
|
||||||
languageMode: null
|
languageMode: null
|
||||||
|
tabLength: null
|
||||||
buffer: null
|
buffer: null
|
||||||
aceAdaptor: null
|
aceAdaptor: null
|
||||||
screenLines: null
|
screenLines: null
|
||||||
|
|
||||||
constructor: (@buffer, { @languageMode, @tabText }) ->
|
constructor: (@buffer, { @languageMode, @tabLength }) ->
|
||||||
|
@tabLength ?= 2
|
||||||
@languageMode.tokenizedBuffer = this
|
@languageMode.tokenizedBuffer = this
|
||||||
@id = @constructor.idCounter++
|
@id = @constructor.idCounter++
|
||||||
@screenLines = @buildScreenLinesForRows(0, @buffer.getLastRow())
|
@screenLines = @buildScreenLinesForRows(0, @buffer.getLastRow())
|
||||||
@ -64,7 +66,7 @@ class TokenizedBuffer
|
|||||||
tokenObjects = []
|
tokenObjects = []
|
||||||
for tokenProperties in tokens
|
for tokenProperties in tokens
|
||||||
token = new Token(tokenProperties)
|
token = new Token(tokenProperties)
|
||||||
tokenObjects.push(token.breakOutTabCharacters(@tabText)...)
|
tokenObjects.push(token.breakOutTabCharacters(@tabLength)...)
|
||||||
text = _.pluck(tokenObjects, 'value').join('')
|
text = _.pluck(tokenObjects, 'value').join('')
|
||||||
new ScreenLine(tokenObjects, text, [1, 0], [1, 0], { stack })
|
new ScreenLine(tokenObjects, text, [1, 0], [1, 0], { stack })
|
||||||
|
|
||||||
|
@ -123,3 +123,7 @@
|
|||||||
.editor .fold.selected {
|
.editor .fold.selected {
|
||||||
background-color: #244;
|
background-color: #244;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor .invisible {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user