2015-01-30 23:04:20 +03:00
_ = require ' underscore-plus '
randomWords = require ' random-words '
2015-01-19 20:48:44 +03:00
TextBuffer = require ' text-buffer '
2015-01-30 23:04:20 +03:00
{ Point , Range } = TextBuffer
2015-01-19 20:48:44 +03:00
TextEditor = require ' ../src/text-editor '
TextEditorPresenter = require ' ../src/text-editor-presenter '
describe " TextEditorPresenter " , ->
2015-01-30 23:04:20 +03:00
# These `describe` and `it` blocks mirror the structure of the ::state object.
# Please maintain this structure when adding specs for new state fields.
describe " ::state " , ->
[ buffer , editor ] = [ ]
2015-01-19 20:48:44 +03:00
2015-01-30 23:04:20 +03:00
beforeEach ->
# These *should* be mocked in the spec helper, but changing that now would break packages :-(
spyOn ( window , " setInterval " ) . andCallFake window . fakeSetInterval
spyOn ( window , " clearInterval " ) . andCallFake window . fakeClearInterval
2015-01-23 19:04:32 +03:00
2015-01-30 23:04:20 +03:00
buffer = new TextBuffer ( filePath: require . resolve ( ' ./fixtures/sample.js ' ) )
editor = new TextEditor ( { buffer } )
waitsForPromise -> buffer . load ( )
2015-01-19 20:48:44 +03:00
2015-01-30 23:04:20 +03:00
afterEach ->
editor . destroy ( )
buffer . destroy ( )
2015-01-19 20:48:44 +03:00
2015-01-30 23:04:20 +03:00
expectValues = (actual, expected) ->
for key , value of expected
expect ( actual [ key ] ) . toEqual value
2015-01-19 20:48:44 +03:00
2015-01-30 23:04:20 +03:00
expectStateUpdate = (presenter, fn) ->
updatedState = false
disposable = presenter . onDidUpdateState ->
updatedState = true
disposable . dispose ( )
fn ( )
expect ( updatedState ) . toBe true
2015-01-23 19:58:42 +03:00
2015-01-29 04:44:10 +03:00
describe " .horizontalScrollbar " , ->
describe " .visible " , ->
it " is true if the scrollWidth exceeds the computed client width " , ->
presenter = new TextEditorPresenter
model: editor
height: editor . getLineCount ( ) * 10
contentFrameWidth: editor . getMaxScreenLineLength ( ) * 10 + 1
baseCharacterWidth: 10
lineHeight: 10
horizontalScrollbarHeight: 10
verticalScrollbarWidth: 10
{ state } = presenter
expect ( state . horizontalScrollbar . visible ) . toBe false
# ::contentFrameWidth itself is smaller than scrollWidth
presenter . setContentFrameWidth ( editor . getMaxScreenLineLength ( ) * 10 )
expect ( state . horizontalScrollbar . visible ) . toBe true
# restore...
presenter . setContentFrameWidth ( editor . getMaxScreenLineLength ( ) * 10 + 1 )
expect ( state . horizontalScrollbar . visible ) . toBe false
# visible vertical scrollbar makes the clientWidth smaller than the scrollWidth
presenter . setHeight ( ( editor . getLineCount ( ) * 10 ) - 1 )
expect ( state . horizontalScrollbar . visible ) . toBe true
describe " .height " , ->
2015-01-29 03:50:42 +03:00
it " tracks the value of ::horizontalScrollbarHeight " , ->
presenter = new TextEditorPresenter ( model: editor , horizontalScrollbarHeight: 10 )
2015-01-29 04:44:10 +03:00
expect ( presenter . state . horizontalScrollbar . height ) . toBe 10
2015-01-29 03:50:42 +03:00
expectStateUpdate presenter , -> presenter . setHorizontalScrollbarHeight ( 20 )
2015-01-29 04:44:10 +03:00
expect ( presenter . state . horizontalScrollbar . height ) . toBe 20
2015-01-29 04:54:50 +03:00
describe " .right " , ->
it " is ::verticalScrollbarWidth if the vertical scrollbar is visible and 0 otherwise " , ->
presenter = new TextEditorPresenter
model: editor
height: editor . getLineCount ( ) * 10 + 50
contentFrameWidth: editor . getMaxScreenLineLength ( ) * 10
baseCharacterWidth: 10
lineHeight: 10
horizontalScrollbarHeight: 10
verticalScrollbarWidth: 10
{ state } = presenter
expect ( state . horizontalScrollbar . right ) . toBe 0
presenter . setHeight ( ( editor . getLineCount ( ) * 10 ) - 1 )
expect ( state . horizontalScrollbar . right ) . toBe 10
2015-01-30 00:27:53 +03:00
describe " .scrollWidth " , ->
it " is initialized as the max of the ::contentFrameWidth and the width of the longest line " , ->
maxLineLength = editor . getMaxScreenLineLength ( )
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 1
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 10 * maxLineLength + 20 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 20
it " updates when the ::contentFrameWidth changes " , ->
maxLineLength = editor . getMaxScreenLineLength ( )
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 1
expectStateUpdate presenter , -> presenter . setContentFrameWidth ( 10 * maxLineLength + 20 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 20
it " updates when the ::baseCharacterWidth changes " , ->
maxLineLength = editor . getMaxScreenLineLength ( )
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 1
expectStateUpdate presenter , -> presenter . setBaseCharacterWidth ( 15 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 15 * maxLineLength + 1
it " updates when the scoped character widths change " , ->
waitsForPromise -> atom . packages . activatePackage ( ' language-javascript ' )
runs ->
maxLineLength = editor . getMaxScreenLineLength ( )
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * maxLineLength + 1
expectStateUpdate presenter , -> presenter . setScopedCharWidth ( [ ' source.js ' , ' support.function.js ' ] , ' p ' , 20 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe ( 10 * ( maxLineLength - 2 ) ) + ( 20 * 2 ) + 1 # 2 of the characters are 20px wide now instead of 10px wide
it " updates when ::softWrapped changes on the editor " , ->
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
expectStateUpdate presenter , -> editor . setSoftWrapped ( true )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( )
expectStateUpdate presenter , -> editor . setSoftWrapped ( false )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
2015-01-30 01:13:10 +03:00
it " updates when the longest line changes " , ->
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
expectStateUpdate presenter , -> editor . setCursorBufferPosition ( [ editor . getLongestScreenRow ( ) , 0 ] )
expectStateUpdate presenter , -> editor . insertText ( ' xyz ' )
expect ( presenter . state . horizontalScrollbar . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
2015-01-30 00:27:53 +03:00
describe " .scrollLeft " , ->
it " tracks the value of ::scrollLeft " , ->
presenter = new TextEditorPresenter ( model: editor , scrollLeft: 10 , lineHeight: 10 , lineOverdrawMargin: 1 )
expect ( presenter . state . horizontalScrollbar . scrollLeft ) . toBe 10
expectStateUpdate presenter , -> presenter . setScrollLeft ( 50 )
expect ( presenter . state . horizontalScrollbar . scrollLeft ) . toBe 50
2015-01-29 04:44:10 +03:00
describe " .verticalScrollbar " , ->
describe " .visible " , ->
it " is true if the scrollHeight exceeds the computed client height " , ->
presenter = new TextEditorPresenter
model: editor
height: editor . getLineCount ( ) * 10
contentFrameWidth: editor . getMaxScreenLineLength ( ) * 10 + 1
baseCharacterWidth: 10
lineHeight: 10
horizontalScrollbarHeight: 10
verticalScrollbarWidth: 10
{ state } = presenter
expect ( state . verticalScrollbar . visible ) . toBe false
# ::height itself is smaller than scrollWidth
presenter . setHeight ( editor . getLineCount ( ) * 10 - 1 )
expect ( state . verticalScrollbar . visible ) . toBe true
# restore...
presenter . setHeight ( editor . getLineCount ( ) * 10 )
expect ( state . verticalScrollbar . visible ) . toBe false
# visible horizontal scrollbar makes the clientHeight smaller than the scrollHeight
presenter . setContentFrameWidth ( editor . getMaxScreenLineLength ( ) * 10 )
expect ( state . verticalScrollbar . visible ) . toBe true
describe " .width " , ->
2015-01-29 03:50:42 +03:00
it " is assigned based on ::verticalScrollbarWidth " , ->
presenter = new TextEditorPresenter ( model: editor , verticalScrollbarWidth: 10 )
2015-01-29 04:44:10 +03:00
expect ( presenter . state . verticalScrollbar . width ) . toBe 10
2015-01-29 03:50:42 +03:00
expectStateUpdate presenter , -> presenter . setVerticalScrollbarWidth ( 20 )
2015-01-29 04:44:10 +03:00
expect ( presenter . state . verticalScrollbar . width ) . toBe 20
2015-01-29 03:50:42 +03:00
2015-01-29 04:54:50 +03:00
describe " .bottom " , ->
it " is ::horizontalScrollbarHeight if the horizontal scrollbar is visible and 0 otherwise " , ->
presenter = new TextEditorPresenter
model: editor
height: editor . getLineCount ( ) * 10 - 1
contentFrameWidth: editor . getMaxScreenLineLength ( ) * 10 + 50
baseCharacterWidth: 10
lineHeight: 10
horizontalScrollbarHeight: 10
verticalScrollbarWidth: 10
{ state } = presenter
expect ( state . verticalScrollbar . bottom ) . toBe 0
presenter . setContentFrameWidth ( editor . getMaxScreenLineLength ( ) * 10 )
expect ( state . verticalScrollbar . bottom ) . toBe 10
2015-01-30 00:27:53 +03:00
describe " .scrollHeight " , ->
it " is initialized based on the lineHeight, the number of lines, and the height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expect ( presenter . state . verticalScrollbar . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , height: 500 )
expect ( presenter . state . verticalScrollbar . scrollHeight ) . toBe 500
it " updates when the ::lineHeight changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setLineHeight ( 20 )
expect ( presenter . state . verticalScrollbar . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 20
it " updates when the line count changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> editor . getBuffer ( ) . append ( " \n \n \n " )
expect ( presenter . state . verticalScrollbar . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
it " updates when ::height changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setHeight ( 500 )
expect ( presenter . state . verticalScrollbar . scrollHeight ) . toBe 500
describe " .scrollTop " , ->
it " tracks the value of ::scrollTop " , ->
2015-02-04 19:38:00 +03:00
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 20 )
2015-01-30 00:27:53 +03:00
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe 10
expectStateUpdate presenter , -> presenter . setScrollTop ( 50 )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe 50
2015-02-04 19:38:00 +03:00
it " never exceeds the computed scroll height minus the computed client height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 50 , horizontalScrollbarHeight: 10 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 100 )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHeight ( 60 )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHorizontalScrollbarHeight ( 15 )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> editor . getBuffer ( ) . delete ( [ [ 8 , 0 ] , [ 12 , 0 ] ] )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
# Scroll top only gets smaller when needed as dimensions change, never bigger
scrollTopBefore = presenter . state . verticalScrollbar . scrollTop
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 9 , Infinity ] , ' \n \n \n ' )
expect ( presenter . state . verticalScrollbar . scrollTop ) . toBe scrollTopBefore
2015-01-22 02:39:00 +03:00
describe " .content " , ->
2015-01-30 00:27:53 +03:00
describe " .scrollingVertically " , ->
it " is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , stoppedScrollingDelay: 200 )
expect ( presenter . state . content . scrollingVertically ) . toBe false
expectStateUpdate presenter , -> presenter . setScrollTop ( 0 )
expect ( presenter . state . content . scrollingVertically ) . toBe true
advanceClock ( 100 )
expect ( presenter . state . content . scrollingVertically ) . toBe true
presenter . setScrollTop ( 10 )
advanceClock ( 100 )
expect ( presenter . state . content . scrollingVertically ) . toBe true
expectStateUpdate presenter , -> advanceClock ( 100 )
expect ( presenter . state . content . scrollingVertically ) . toBe false
describe " .scrollHeight " , ->
it " is initialized based on the lineHeight, the number of lines, and the height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expect ( presenter . state . content . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , height: 500 )
expect ( presenter . state . content . scrollHeight ) . toBe 500
it " updates when the ::lineHeight changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setLineHeight ( 20 )
expect ( presenter . state . content . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 20
it " updates when the line count changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> editor . getBuffer ( ) . append ( " \n \n \n " )
expect ( presenter . state . content . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
it " updates when ::height changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setHeight ( 500 )
expect ( presenter . state . content . scrollHeight ) . toBe 500
2015-01-22 02:39:00 +03:00
describe " .scrollWidth " , ->
2015-01-29 03:59:18 +03:00
it " is initialized as the max of the ::contentFrameWidth and the width of the longest line " , ->
2015-01-22 02:39:00 +03:00
maxLineLength = editor . getMaxScreenLineLength ( )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 1
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 10 * maxLineLength + 20 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 20
2015-01-29 03:59:18 +03:00
it " updates when the ::contentFrameWidth changes " , ->
2015-01-22 02:39:00 +03:00
maxLineLength = editor . getMaxScreenLineLength ( )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 1
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setContentFrameWidth ( 10 * maxLineLength + 20 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 20
it " updates when the ::baseCharacterWidth changes " , ->
maxLineLength = editor . getMaxScreenLineLength ( )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 1
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setBaseCharacterWidth ( 15 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 15 * maxLineLength + 1
it " updates when the scoped character widths change " , ->
waitsForPromise -> atom . packages . activatePackage ( ' language-javascript ' )
runs ->
maxLineLength = editor . getMaxScreenLineLength ( )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * maxLineLength + 1
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScopedCharWidth ( [ ' source.js ' , ' support.function.js ' ] , ' p ' , 20 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe ( 10 * ( maxLineLength - 2 ) ) + ( 20 * 2 ) + 1 # 2 of the characters are 20px wide now instead of 10px wide
it " updates when ::softWrapped changes on the editor " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . setSoftWrapped ( true )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . setSoftWrapped ( false )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
2015-01-30 01:13:10 +03:00
it " updates when the longest line changes " , ->
presenter = new TextEditorPresenter ( model: editor , contentFrameWidth: 50 , baseCharacterWidth: 10 )
expect ( presenter . state . content . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
expectStateUpdate presenter , -> editor . setCursorBufferPosition ( [ editor . getLongestScreenRow ( ) , 0 ] )
expectStateUpdate presenter , -> editor . insertText ( ' xyz ' )
expect ( presenter . state . content . scrollWidth ) . toBe 10 * editor . getMaxScreenLineLength ( ) + 1
2015-01-30 00:27:53 +03:00
describe " .scrollTop " , ->
it " tracks the value of ::scrollTop " , ->
2015-02-04 19:38:00 +03:00
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 20 )
2015-01-30 00:27:53 +03:00
expect ( presenter . state . content . scrollTop ) . toBe 10
expectStateUpdate presenter , -> presenter . setScrollTop ( 50 )
expect ( presenter . state . content . scrollTop ) . toBe 50
2015-02-04 19:38:00 +03:00
it " never exceeds the computed scroll height minus the computed client height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 50 , horizontalScrollbarHeight: 10 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 100 )
expect ( presenter . state . content . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHeight ( 60 )
expect ( presenter . state . content . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHorizontalScrollbarHeight ( 15 )
expect ( presenter . state . content . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> editor . getBuffer ( ) . delete ( [ [ 8 , 0 ] , [ 12 , 0 ] ] )
expect ( presenter . state . content . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
# Scroll top only gets smaller when needed as dimensions change, never bigger
scrollTopBefore = presenter . state . verticalScrollbar . scrollTop
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 9 , Infinity ] , ' \n \n \n ' )
expect ( presenter . state . content . scrollTop ) . toBe scrollTopBefore
2015-01-22 03:01:23 +03:00
describe " .scrollLeft " , ->
it " tracks the value of ::scrollLeft " , ->
presenter = new TextEditorPresenter ( model: editor , scrollLeft: 10 , lineHeight: 10 , lineOverdrawMargin: 1 )
expect ( presenter . state . content . scrollLeft ) . toBe 10
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScrollLeft ( 50 )
2015-01-22 03:01:23 +03:00
expect ( presenter . state . content . scrollLeft ) . toBe 50
2015-01-22 02:39:00 +03:00
describe " .indentGuidesVisible " , ->
it " is initialized based on the editor.showIndentGuide config setting " , ->
presenter = new TextEditorPresenter ( model: editor )
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
atom . config . set ( ' editor.showIndentGuide ' , true )
presenter = new TextEditorPresenter ( model: editor )
2015-01-21 19:38:54 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe true
2015-01-22 02:39:00 +03:00
it " updates when the editor.showIndentGuide config setting changes " , ->
presenter = new TextEditorPresenter ( model: editor )
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> atom . config . set ( ' editor.showIndentGuide ' , true )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe true
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> atom . config . set ( ' editor.showIndentGuide ' , false )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
it " updates when the editor ' s grammar changes " , ->
atom . config . set ( ' editor.showIndentGuide ' , true , scopeSelector: " .source.js " )
presenter = new TextEditorPresenter ( model: editor )
2015-01-21 19:38:54 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
2015-01-23 19:58:42 +03:00
stateUpdated = false
presenter . onDidUpdateState -> stateUpdated = true
2015-01-22 02:39:00 +03:00
waitsForPromise -> atom . packages . activatePackage ( ' language-javascript ' )
runs ->
2015-01-23 19:58:42 +03:00
expect ( stateUpdated ) . toBe true
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe true
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . setGrammar ( atom . grammars . selectGrammar ( ' .txt ' ) )
2015-01-22 02:39:00 +03:00
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
2015-01-28 00:34:53 +03:00
it " is always false when the editor is mini " , ->
atom . config . set ( ' editor.showIndentGuide ' , true )
editor . setMini ( true )
presenter = new TextEditorPresenter ( model: editor )
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
editor . setMini ( false )
expect ( presenter . state . content . indentGuidesVisible ) . toBe true
editor . setMini ( true )
expect ( presenter . state . content . indentGuidesVisible ) . toBe false
2015-01-22 02:39:00 +03:00
2015-01-27 20:27:07 +03:00
describe " .backgroundColor " , ->
it " is assigned to ::backgroundColor unless the editor is mini " , ->
presenter = new TextEditorPresenter ( model: editor , backgroundColor: ' rgba(255, 0, 0, 0) ' )
expect ( presenter . state . content . backgroundColor ) . toBe ' rgba(255, 0, 0, 0) '
editor . setMini ( true )
presenter = new TextEditorPresenter ( model: editor , backgroundColor: ' rgba(255, 0, 0, 0) ' )
expect ( presenter . state . content . backgroundColor ) . toBeNull ( )
it " updates when ::backgroundColor changes " , ->
presenter = new TextEditorPresenter ( model: editor , backgroundColor: ' rgba(255, 0, 0, 0) ' )
expect ( presenter . state . content . backgroundColor ) . toBe ' rgba(255, 0, 0, 0) '
expectStateUpdate presenter , -> presenter . setBackgroundColor ( ' rgba(0, 0, 255, 0) ' )
expect ( presenter . state . content . backgroundColor ) . toBe ' rgba(0, 0, 255, 0) '
it " updates when ::mini changes " , ->
presenter = new TextEditorPresenter ( model: editor , backgroundColor: ' rgba(255, 0, 0, 0) ' )
expect ( presenter . state . content . backgroundColor ) . toBe ' rgba(255, 0, 0, 0) '
expectStateUpdate presenter , -> editor . setMini ( true )
expect ( presenter . state . content . backgroundColor ) . toBeNull ( )
2015-01-28 00:50:02 +03:00
describe " .placeholderText " , ->
it " is present when the editor has no text " , ->
editor . setPlaceholderText ( " the-placeholder-text " )
presenter = new TextEditorPresenter ( model: editor )
expect ( presenter . state . content . placeholderText ) . toBeNull ( )
expectStateUpdate presenter , -> editor . setText ( " " )
expect ( presenter . state . content . placeholderText ) . toBe " the-placeholder-text "
expectStateUpdate presenter , -> editor . setPlaceholderText ( " new-placeholder-text " )
expect ( presenter . state . content . placeholderText ) . toBe " new-placeholder-text "
2015-01-22 02:39:00 +03:00
describe " .lines " , ->
lineStateForScreenRow = (presenter, screenRow) ->
presenter . state . content . lines [ presenter . model . tokenizedLineForScreenRow ( screenRow ) . id ]
it " contains states for lines that are visible on screen, plus and minus the overdraw margin " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 15 , scrollTop: 50 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 3 ) ) . toBeUndefined ( )
line4 = editor . tokenizedLineForScreenRow ( 4 )
expectValues lineStateForScreenRow ( presenter , 4 ) , {
screenRow: 4
text: line4 . text
tokens: line4 . tokens
top: 10 * 4
}
line5 = editor . tokenizedLineForScreenRow ( 5 )
expectValues lineStateForScreenRow ( presenter , 5 ) , {
screenRow: 5
text: line5 . text
tokens: line5 . tokens
top: 10 * 5
}
line6 = editor . tokenizedLineForScreenRow ( 6 )
expectValues lineStateForScreenRow ( presenter , 6 ) , {
screenRow: 6
text: line6 . text
tokens: line6 . tokens
top: 10 * 6
}
line7 = editor . tokenizedLineForScreenRow ( 7 )
expectValues lineStateForScreenRow ( presenter , 7 ) , {
screenRow: 7
text: line7 . text
tokens: line7 . tokens
top: 10 * 7
}
line8 = editor . tokenizedLineForScreenRow ( 8 )
expectValues lineStateForScreenRow ( presenter , 8 ) , {
screenRow: 8
text: line8 . text
tokens: line8 . tokens
top: 10 * 8
}
expect ( lineStateForScreenRow ( presenter , 9 ) ) . toBeUndefined ( )
it " does not overdraw above the first row " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 15 , scrollTop: 10 , lineHeight: 10 , lineOverdrawMargin: 2 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 2 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 3 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 4 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 6 ) ) . toBeUndefined ( )
it " does not overdraw below the last row " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 105 , lineHeight: 10 , lineOverdrawMargin: 2 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 7 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 8 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 9 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 10 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 11 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 12 ) ) . toBeDefined ( )
2015-01-29 03:59:18 +03:00
it " includes state for all lines if no external ::height is assigned " , ->
2015-01-22 02:39:00 +03:00
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 )
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 12 ) ) . toBeDefined ( )
2015-01-28 03:26:54 +03:00
it " is empty until all of the required measurements are assigned " , ->
presenter = new TextEditorPresenter ( model: editor , lineOverdrawMargin: 1 , baseCharacterWidth: 10 )
expect ( presenter . state . content . lines ) . toEqual ( { } )
2015-01-29 03:59:18 +03:00
presenter . setHeight ( 25 )
2015-01-28 03:26:54 +03:00
expect ( presenter . state . content . lines ) . toEqual ( { } )
presenter . setLineHeight ( 10 )
expect ( presenter . state . content . lines ) . toEqual ( { } )
presenter . setScrollTop ( 0 )
expect ( presenter . state . content . lines ) . not . toEqual ( { } )
2015-01-22 02:39:00 +03:00
it " updates when ::scrollTop changes " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 4 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeUndefined ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScrollTop ( 25 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 6 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 7 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
it " updates when ::height changes " , ->
presenter = new TextEditorPresenter ( model: editor , height: 15 , scrollTop: 15 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-22 02:39:00 +03:00
line5 = editor . tokenizedLineForScreenRow ( 5 )
expect ( lineStateForScreenRow ( presenter , 4 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setHeight ( 35 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 6 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 7 ) ) . toBeUndefined ( )
it " updates when ::lineHeight changes " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 15 , scrollTop: 10 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 2 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 4 ) ) . toBeUndefined ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setLineHeight ( 5 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 2 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 6 ) ) . toBeUndefined ( )
it " updates when the editor ' s content changes " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 10 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> buffer . insert ( [ 2 , 0 ] , " hello \n world \n " )
2015-01-22 02:39:00 +03:00
line1 = editor . tokenizedLineForScreenRow ( 1 )
expectValues lineStateForScreenRow ( presenter , 1 ) , {
text: line1 . text
tokens: line1 . tokens
}
line2 = editor . tokenizedLineForScreenRow ( 2 )
expectValues lineStateForScreenRow ( presenter , 2 ) , {
text: line2 . text
tokens: line2 . tokens
}
line3 = editor . tokenizedLineForScreenRow ( 3 )
expectValues lineStateForScreenRow ( presenter , 3 ) , {
text: line3 . text
tokens: line3 . tokens
}
2015-01-29 02:04:43 +03:00
it " does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 , stoppedScrollingDelay: 200 )
2015-01-29 02:04:43 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 4 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 5 ) ) . toBeUndefined ( )
presenter . setMouseWheelScreenRow ( 0 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 35 )
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 7 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> advanceClock ( 200 )
expect ( lineStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expect ( lineStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
2015-01-29 02:30:01 +03:00
expect ( lineStateForScreenRow ( presenter , 2 ) ) . toBeDefined ( )
2015-01-29 02:04:43 +03:00
expect ( lineStateForScreenRow ( presenter , 7 ) ) . toBeDefined ( )
expect ( lineStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
2015-01-29 02:30:01 +03:00
# should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first
presenter . setMouseWheelScreenRow ( 2 )
advanceClock ( 200 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 45 )
expect ( lineStateForScreenRow ( presenter , 2 ) ) . toBeUndefined ( )
2015-01-29 02:04:43 +03:00
it " does not preserve on-screen lines even if they correspond to ::mouseWheelScreenRow " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 , stoppedScrollingDelay: 200 )
2015-01-29 02:04:43 +03:00
oldLine3 = editor . tokenizedLineForScreenRow ( 6 )
presenter . setMouseWheelScreenRow ( 3 )
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 3 , Infinity ] , ' xyz ' )
newLine3 = editor . tokenizedLineForScreenRow ( 3 )
expect ( presenter . state . content . lines [ oldLine3 . id ] ) . toBeUndefined ( )
expect ( presenter . state . content . lines [ newLine3 . id ] ) . toBeDefined ( )
2015-01-22 02:39:00 +03:00
describe " [lineId] " , -> # line state objects
it " includes the .endOfLineInvisibles if the editor.showInvisibles config option is true " , ->
editor . setText ( " hello \n world \r \n " )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) . endOfLineInvisibles ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 1 ) . endOfLineInvisibles ) . toBeNull ( )
atom . config . set ( ' editor.showInvisibles ' , true )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) . endOfLineInvisibles ) . toEqual [ atom . config . get ( ' editor.invisibles.eol ' ) ]
expect ( lineStateForScreenRow ( presenter , 1 ) . endOfLineInvisibles ) . toEqual [ atom . config . get ( ' editor.invisibles.cr ' ) , atom . config . get ( ' editor.invisibles.eol ' ) ]
describe " .decorationClasses " , ->
it " adds decoration classes to the relevant line state objects, both initially and when decorations change " , ->
marker1 = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] , invalidate: ' touch ' )
decoration1 = editor . decorateMarker ( marker1 , type: ' line ' , class : ' a ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
marker2 = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] , invalidate: ' touch ' )
decoration2 = editor . decorateMarker ( marker2 , type: ' line ' , class : ' b ' )
expect ( lineStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 5 , 0 ] , ' x ' )
2015-01-22 02:39:00 +03:00
expect ( marker1 . isValid ( ) ) . toBe false
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . undo ( )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> marker1 . setBufferRange ( [ [ 2 , 0 ] , [ 4 , 2 ] ] )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> decoration1 . destroy ( )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> marker2 . destroy ( )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
it " honors the ' onlyEmpty ' option on line decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 1 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line ' , class : ' a ' , onlyEmpty: true )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> marker . clearTail ( )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
it " honors the ' onlyNonEmpty ' option on line decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line ' , class : ' a ' , onlyNonEmpty: true )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> marker . clearTail ( )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
2015-01-27 17:49:24 +03:00
it " honors the ' onlyHead ' option on line decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 17:49:24 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line ' , class : ' a ' , onlyHead: true )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
2015-01-22 02:39:00 +03:00
it " does not decorate the last line of a non-empty line decoration range if it ends at column 0 " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 0 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line ' , class : ' a ' )
expect ( lineStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
it " does not apply line decorations to mini editors " , ->
editor . setMini ( true )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 10 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-22 02:39:00 +03:00
marker = editor . markBufferRange ( [ [ 0 , 0 ] , [ 0 , 0 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line ' , class : ' a ' )
expect ( lineStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toBeNull ( )
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . setMini ( false )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toEqual [ ' cursor-line ' , ' a ' ]
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . setMini ( true )
2015-01-22 02:39:00 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toBeNull ( )
2015-01-22 20:55:01 +03:00
2015-01-27 17:41:48 +03:00
it " only applies decorations to screen rows that are spanned by their marker when lines are soft-wrapped " , ->
editor . setText ( " a line that wraps, ok " )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 16 )
marker = editor . markBufferRange ( [ [ 0 , 0 ] , [ 0 , 2 ] ] )
editor . decorateMarker ( marker , type: ' line ' , class : ' a ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 10 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 17:41:48 +03:00
expect ( lineStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toContain ' a '
expect ( lineStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toBeNull ( )
marker . setBufferRange ( [ [ 0 , 0 ] , [ 0 , Infinity ] ] )
expect ( lineStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toContain ' a '
expect ( lineStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toContain ' a '
2015-01-22 20:55:01 +03:00
describe " .cursors " , ->
stateForCursor = (presenter, cursorIndex) ->
presenter . state . content . cursors [ presenter . model . getCursors ( ) [ cursorIndex ] . id ]
it " contains pixelRects for empty selections that are visible on screen " , ->
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 2 ] ] ,
[ [ 2 , 4 ] , [ 2 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 5 ] ]
[ [ 5 , 12 ] , [ 5 , 12 ] ] ,
[ [ 8 , 4 ] , [ 8 , 4 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 1 ) ) . toEqual { top: 2 * 10 , left: 4 * 10 , width: 10 , height: 10 }
expect ( stateForCursor ( presenter , 2 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 3 ) ) . toEqual { top: 5 * 10 , left: 12 * 10 , width: 10 , height: 10 }
expect ( stateForCursor ( presenter , 4 ) ) . toBeUndefined ( )
2015-01-28 03:26:54 +03:00
it " is empty until all of the required measurements are assigned " , ->
presenter = new TextEditorPresenter ( model: editor , lineOverdrawMargin: 1 )
expect ( presenter . state . content . cursors ) . toEqual ( { } )
2015-01-29 03:59:18 +03:00
presenter . setHeight ( 25 )
2015-01-28 03:26:54 +03:00
expect ( presenter . state . content . cursors ) . toEqual ( { } )
presenter . setLineHeight ( 10 )
expect ( presenter . state . content . cursors ) . toEqual ( { } )
presenter . setScrollTop ( 0 )
expect ( presenter . state . content . cursors ) . toEqual ( { } )
presenter . setBaseCharacterWidth ( 8 )
expect ( presenter . state . content . cursors ) . not . toEqual ( { } )
2015-01-22 20:55:01 +03:00
it " updates when ::scrollTop changes " , ->
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 2 ] ] ,
[ [ 2 , 4 ] , [ 2 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 5 ] ]
[ [ 5 , 12 ] , [ 5 , 12 ] ] ,
[ [ 8 , 4 ] , [ 8 , 4 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScrollTop ( 5 * 10 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 1 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 2 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 3 ) ) . toEqual { top: 5 * 10 , left: 12 * 10 , width: 10 , height: 10 }
expect ( stateForCursor ( presenter , 4 ) ) . toEqual { top: 8 * 10 , left: 4 * 10 , width: 10 , height: 10 }
2015-01-29 03:59:18 +03:00
it " updates when ::height changes " , ->
2015-01-22 20:55:01 +03:00
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 2 ] ] ,
[ [ 2 , 4 ] , [ 2 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 5 ] ]
[ [ 5 , 12 ] , [ 5 , 12 ] ] ,
[ [ 8 , 4 ] , [ 8 , 4 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setHeight ( 30 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 1 ) ) . toEqual { top: 2 * 10 , left: 4 * 10 , width: 10 , height: 10 }
expect ( stateForCursor ( presenter , 2 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 3 ) ) . toEqual { top: 5 * 10 , left: 12 * 10 , width: 10 , height: 10 }
expect ( stateForCursor ( presenter , 4 ) ) . toBeUndefined ( )
it " updates when ::lineHeight changes " , ->
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 2 ] ] ,
[ [ 2 , 4 ] , [ 2 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 5 ] ]
[ [ 5 , 12 ] , [ 5 , 12 ] ] ,
[ [ 8 , 4 ] , [ 8 , 4 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setLineHeight ( 5 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 1 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 2 ) ) . toBeUndefined ( )
expect ( stateForCursor ( presenter , 3 ) ) . toEqual { top: 5 * 5 , left: 12 * 10 , width: 10 , height: 5 }
expect ( stateForCursor ( presenter , 4 ) ) . toEqual { top: 8 * 5 , left: 4 * 10 , width: 10 , height: 5 }
it " updates when ::baseCharacterWidth changes " , ->
editor . setCursorBufferPosition ( [ 2 , 4 ] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setBaseCharacterWidth ( 20 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toEqual { top: 2 * 10 , left: 4 * 20 , width: 20 , height: 10 }
it " updates when scoped character widths change " , ->
waitsForPromise ->
atom . packages . activatePackage ( ' language-javascript ' )
runs ->
editor . setCursorBufferPosition ( [ 1 , 4 ] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScopedCharWidth ( [ ' source.js ' , ' storage.modifier.js ' ] , ' v ' , 20 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toEqual { top: 1 * 10 , left: ( 3 * 10 ) + 20 , width: 10 , height: 10 }
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> presenter . setScopedCharWidth ( [ ' source.js ' , ' storage.modifier.js ' ] , ' r ' , 20 )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toEqual { top: 1 * 10 , left: ( 3 * 10 ) + 20 , width: 20 , height: 10 }
it " updates when cursors are added, moved, hidden, shown, or destroyed " , ->
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 2 ] ] ,
[ [ 3 , 4 ] , [ 3 , 5 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-22 20:55:01 +03:00
# moving into view
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
editor . getCursors ( ) [ 0 ] . setBufferPosition ( [ 2 , 4 ] )
expect ( stateForCursor ( presenter , 0 ) ) . toEqual { top: 2 * 10 , left: 4 * 10 , width: 10 , height: 10 }
# showing
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . clear ( )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 1 ) ) . toEqual { top: 3 * 10 , left: 5 * 10 , width: 10 , height: 10 }
# hiding
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . setBufferRange ( [ [ 3 , 4 ] , [ 3 , 5 ] ] )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 1 ) ) . toBeUndefined ( )
# moving out of view
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . getCursors ( ) [ 0 ] . setBufferPosition ( [ 10 , 4 ] )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 0 ) ) . toBeUndefined ( )
# adding
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . addCursorAtBufferPosition ( [ 4 , 4 ] )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 2 ) ) . toEqual { top: 4 * 10 , left: 4 * 10 , width: 10 , height: 10 }
# moving added cursor
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> editor . getCursors ( ) [ 2 ] . setBufferPosition ( [ 4 , 6 ] )
2015-01-22 20:55:01 +03:00
expect ( stateForCursor ( presenter , 2 ) ) . toEqual { top: 4 * 10 , left: 6 * 10 , width: 10 , height: 10 }
# destroying
destroyedCursor = editor . getCursors ( ) [ 2 ]
2015-01-23 19:58:42 +03:00
expectStateUpdate presenter , -> destroyedCursor . destroy ( )
2015-01-22 20:55:01 +03:00
expect ( presenter . state . content . cursors [ destroyedCursor . id ] ) . toBeUndefined ( )
2015-01-23 18:19:01 +03:00
it " makes cursors as wide as the ::baseCharacterWidth if they ' re at the end of a line " , ->
editor . setCursorBufferPosition ( [ 1 , Infinity ] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 18:19:01 +03:00
expect ( stateForCursor ( presenter , 0 ) . width ) . toBe 10
2015-01-23 19:04:32 +03:00
2015-01-23 20:33:07 +03:00
describe " .blinkCursorsOff " , ->
it " alternates between true and false twice per ::cursorBlinkPeriod " , ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = new TextEditorPresenter ( { model: editor , cursorBlinkPeriod , cursorBlinkResumeDelay } )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
it " stops alternating for ::cursorBlinkResumeDelay when a cursor moves or a cursor is added " , ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = new TextEditorPresenter ( { model: editor , cursorBlinkPeriod , cursorBlinkResumeDelay } )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
expectStateUpdate presenter , -> editor . moveRight ( )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , ->
advanceClock ( cursorBlinkResumeDelay )
advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , -> advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
expectStateUpdate presenter , -> editor . addCursorAtBufferPosition ( [ 1 , 0 ] )
expect ( presenter . state . content . blinkCursorsOff ) . toBe false
expectStateUpdate presenter , ->
advanceClock ( cursorBlinkResumeDelay )
advanceClock ( cursorBlinkPeriod / 2 )
expect ( presenter . state . content . blinkCursorsOff ) . toBe true
2015-01-23 23:18:27 +03:00
describe " .highlights " , ->
stateForHighlight = (presenter, decoration) ->
presenter . state . content . highlights [ decoration . id ]
stateForSelection = (presenter, selectionIndex) ->
selection = presenter . model . getSelections ( ) [ selectionIndex ]
stateForHighlight ( presenter , selection . decoration )
it " contains states for highlights that are visible on screen " , ->
# off-screen above
marker1 = editor . markBufferRange ( [ [ 0 , 0 ] , [ 1 , 0 ] ] )
highlight1 = editor . decorateMarker ( marker1 , type: ' highlight ' , class : ' a ' )
# partially off-screen above, 1 of 2 regions on screen
marker2 = editor . markBufferRange ( [ [ 1 , 6 ] , [ 2 , 6 ] ] )
highlight2 = editor . decorateMarker ( marker2 , type: ' highlight ' , class : ' b ' )
# partially off-screen above, 2 of 3 regions on screen
marker3 = editor . markBufferRange ( [ [ 0 , 6 ] , [ 3 , 6 ] ] )
highlight3 = editor . decorateMarker ( marker3 , type: ' highlight ' , class : ' c ' )
# on-screen
marker4 = editor . markBufferRange ( [ [ 2 , 6 ] , [ 4 , 6 ] ] )
highlight4 = editor . decorateMarker ( marker4 , type: ' highlight ' , class : ' d ' )
# partially off-screen below, 2 of 3 regions on screen
marker5 = editor . markBufferRange ( [ [ 3 , 6 ] , [ 6 , 6 ] ] )
highlight5 = editor . decorateMarker ( marker5 , type: ' highlight ' , class : ' e ' )
# partially off-screen below, 1 of 3 regions on screen
marker6 = editor . markBufferRange ( [ [ 5 , 6 ] , [ 7 , 6 ] ] )
highlight6 = editor . decorateMarker ( marker6 , type: ' highlight ' , class : ' f ' )
# off-screen below
marker7 = editor . markBufferRange ( [ [ 6 , 6 ] , [ 7 , 6 ] ] )
highlight7 = editor . decorateMarker ( marker7 , type: ' highlight ' , class : ' g ' )
# on-screen, empty
marker8 = editor . markBufferRange ( [ [ 2 , 2 ] , [ 2 , 2 ] ] )
highlight8 = editor . decorateMarker ( marker8 , type: ' highlight ' , class : ' h ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expect ( stateForHighlight ( presenter , highlight1 ) ) . toBeUndefined ( )
expectValues stateForHighlight ( presenter , highlight2 ) , {
class : ' b '
regions: [
{ top: 2 * 10 , left: 0 * 10 , width: 6 * 10 , height: 1 * 10 }
]
}
expectValues stateForHighlight ( presenter , highlight3 ) , {
class : ' c '
regions: [
{ top: 2 * 10 , left: 0 * 10 , right: 0 , height: 1 * 10 }
{ top: 3 * 10 , left: 0 * 10 , width: 6 * 10 , height: 1 * 10 }
]
}
expectValues stateForHighlight ( presenter , highlight4 ) , {
class : ' d '
regions: [
{ top: 2 * 10 , left: 6 * 10 , right: 0 , height: 1 * 10 }
{ top: 3 * 10 , left: 0 , right: 0 , height: 1 * 10 }
{ top: 4 * 10 , left: 0 , width: 6 * 10 , height: 1 * 10 }
]
}
expectValues stateForHighlight ( presenter , highlight5 ) , {
class : ' e '
regions: [
{ top: 3 * 10 , left: 6 * 10 , right: 0 , height: 1 * 10 }
{ top: 4 * 10 , left: 0 * 10 , right: 0 , height: 2 * 10 }
]
}
expectValues stateForHighlight ( presenter , highlight6 ) , {
class : ' f '
regions: [
{ top: 5 * 10 , left: 6 * 10 , right: 0 , height: 1 * 10 }
]
}
expect ( stateForHighlight ( presenter , highlight7 ) ) . toBeUndefined ( )
expect ( stateForHighlight ( presenter , highlight8 ) ) . toBeUndefined ( )
2015-01-28 03:26:54 +03:00
it " is empty until all of the required measurements are assigned " , ->
editor . setSelectedBufferRanges ( [
[ [ 0 , 2 ] , [ 2 , 4 ] ] ,
] )
presenter = new TextEditorPresenter ( model: editor , lineOverdrawMargin: 1 )
expect ( presenter . state . content . highlights ) . toEqual ( { } )
2015-01-29 03:59:18 +03:00
presenter . setHeight ( 25 )
2015-01-28 03:26:54 +03:00
expect ( presenter . state . content . highlights ) . toEqual ( { } )
presenter . setLineHeight ( 10 )
expect ( presenter . state . content . highlights ) . toEqual ( { } )
presenter . setScrollTop ( 0 )
expect ( presenter . state . content . highlights ) . toEqual ( { } )
presenter . setBaseCharacterWidth ( 8 )
expect ( presenter . state . content . highlights ) . not . toEqual ( { } )
2015-01-24 03:48:27 +03:00
it " does not include highlights for invalid markers " , ->
marker = editor . markBufferRange ( [ [ 2 , 2 ] , [ 2 , 4 ] ] , invalidate: ' touch ' )
highlight = editor . decorateMarker ( marker , type: ' highlight ' , class : ' h ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-24 03:48:27 +03:00
expect ( stateForHighlight ( presenter , highlight ) ) . toBeDefined ( )
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 2 , 2 ] , " stuff " )
expect ( stateForHighlight ( presenter , highlight ) ) . toBeUndefined ( )
2015-01-23 23:18:27 +03:00
it " updates when ::scrollTop changes " , ->
editor . setSelectedBufferRanges ( [
[ [ 6 , 2 ] , [ 6 , 4 ] ] ,
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expect ( stateForSelection ( presenter , 0 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> presenter . setScrollTop ( 5 * 10 )
expect ( stateForSelection ( presenter , 0 ) ) . toBeDefined ( )
expectStateUpdate presenter , -> presenter . setScrollTop ( 2 * 10 )
expect ( stateForSelection ( presenter , 0 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
it " updates when ::height changes " , ->
2015-01-23 23:18:27 +03:00
editor . setSelectedBufferRanges ( [
[ [ 6 , 2 ] , [ 6 , 4 ] ] ,
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expect ( stateForSelection ( presenter , 0 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setHeight ( 60 )
2015-01-23 23:18:27 +03:00
expect ( stateForSelection ( presenter , 0 ) ) . toBeDefined ( )
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setHeight ( 20 )
2015-01-23 23:18:27 +03:00
expect ( stateForSelection ( presenter , 0 ) ) . toBeUndefined ( )
it " updates when ::lineHeight changes " , ->
editor . setSelectedBufferRanges ( [
[ [ 2 , 2 ] , [ 2 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 6 ] ] ,
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expectValues stateForSelection ( presenter , 0 ) , {
regions: [
{ top: 2 * 10 , left: 2 * 10 , width: 2 * 10 , height: 10 }
]
}
expect ( stateForSelection ( presenter , 1 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> presenter . setLineHeight ( 5 )
expectValues stateForSelection ( presenter , 0 ) , {
regions: [
{ top: 2 * 5 , left: 2 * 10 , width: 2 * 10 , height: 5 }
]
}
expectValues stateForSelection ( presenter , 1 ) , {
regions: [
{ top: 3 * 5 , left: 4 * 10 , width: 2 * 10 , height: 5 }
]
}
it " updates when ::baseCharacterWidth changes " , ->
editor . setSelectedBufferRanges ( [
[ [ 2 , 2 ] , [ 2 , 4 ] ] ,
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expectValues stateForSelection ( presenter , 0 ) , {
regions: [ { top: 2 * 10 , left: 2 * 10 , width: 2 * 10 , height: 10 } ]
}
expectStateUpdate presenter , -> presenter . setBaseCharacterWidth ( 20 )
expectValues stateForSelection ( presenter , 0 ) , {
regions: [ { top: 2 * 10 , left: 2 * 20 , width: 2 * 20 , height: 10 } ]
}
it " updates when scoped character widths change " , ->
waitsForPromise ->
atom . packages . activatePackage ( ' language-javascript ' )
runs ->
editor . setSelectedBufferRanges ( [
[ [ 2 , 4 ] , [ 2 , 6 ] ] ,
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expectValues stateForSelection ( presenter , 0 ) , {
regions: [ { top: 2 * 10 , left: 4 * 10 , width: 2 * 10 , height: 10 } ]
}
expectStateUpdate presenter , -> presenter . setScopedCharWidth ( [ ' source.js ' , ' keyword.control.js ' ] , ' i ' , 20 )
expectValues stateForSelection ( presenter , 0 ) , {
regions: [ { top: 2 * 10 , left: 4 * 10 , width: 20 + 10 , height: 10 } ]
}
it " updates when highlight decorations are added, moved, hidden, shown, or destroyed " , ->
editor . setSelectedBufferRanges ( [
[ [ 1 , 2 ] , [ 1 , 4 ] ] ,
[ [ 3 , 4 ] , [ 3 , 6 ] ]
] )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 20 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-23 23:18:27 +03:00
expectValues stateForSelection ( presenter , 0 ) , {
regions: [ { top: 1 * 10 , left: 2 * 10 , width: 2 * 10 , height: 10 } ]
}
expect ( stateForSelection ( presenter , 1 ) ) . toBeUndefined ( )
# moving into view
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . setBufferRange ( [ [ 2 , 4 ] , [ 2 , 6 ] ] )
expectValues stateForSelection ( presenter , 1 ) , {
regions: [ { top: 2 * 10 , left: 4 * 10 , width: 2 * 10 , height: 10 } ]
}
# becoming empty
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . clear ( )
expect ( stateForSelection ( presenter , 1 ) ) . toBeUndefined ( )
# becoming non-empty
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . setBufferRange ( [ [ 2 , 4 ] , [ 2 , 6 ] ] )
expectValues stateForSelection ( presenter , 1 ) , {
regions: [ { top: 2 * 10 , left: 4 * 10 , width: 2 * 10 , height: 10 } ]
}
# moving out of view
expectStateUpdate presenter , -> editor . getSelections ( ) [ 1 ] . setBufferRange ( [ [ 3 , 4 ] , [ 3 , 6 ] ] )
expect ( stateForSelection ( presenter , 1 ) ) . toBeUndefined ( )
# adding
expectStateUpdate presenter , -> editor . addSelectionForBufferRange ( [ [ 1 , 4 ] , [ 1 , 6 ] ] )
expectValues stateForSelection ( presenter , 2 ) , {
regions: [ { top: 1 * 10 , left: 4 * 10 , width: 2 * 10 , height: 10 } ]
}
# moving added selection
expectStateUpdate presenter , -> editor . getSelections ( ) [ 2 ] . setBufferRange ( [ [ 1 , 4 ] , [ 1 , 8 ] ] )
expectValues stateForSelection ( presenter , 2 ) , {
regions: [ { top: 1 * 10 , left: 4 * 10 , width: 4 * 10 , height: 10 } ]
}
# destroying
destroyedSelection = editor . getSelections ( ) [ 2 ]
expectStateUpdate presenter , -> destroyedSelection . destroy ( )
expect ( stateForHighlight ( presenter , destroyedSelection . decoration ) ) . toBeUndefined ( )
2015-01-24 03:48:27 +03:00
it " updates when highlight decorations ' properties are updated " , ->
marker = editor . markBufferRange ( [ [ 2 , 2 ] , [ 2 , 4 ] ] )
highlight = editor . decorateMarker ( marker , type: ' highlight ' , class : ' a ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-24 03:48:27 +03:00
expectValues stateForHighlight ( presenter , highlight ) , { class : ' a ' }
expectStateUpdate presenter , -> highlight . setProperties ( class : ' b ' , type: ' highlight ' )
expectValues stateForHighlight ( presenter , highlight ) , { class : ' b ' }
it " increments the .flashCount and sets the .flashClass and .flashDuration when the highlight model flashes " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-24 03:48:27 +03:00
marker = editor . markBufferRange ( [ [ 2 , 2 ] , [ 2 , 4 ] ] )
highlight = editor . decorateMarker ( marker , type: ' highlight ' , class : ' a ' )
expectStateUpdate presenter , -> highlight . flash ( ' b ' , 500 )
expectValues stateForHighlight ( presenter , highlight ) , {
flashClass: ' b '
flashDuration: 500
flashCount: 1
}
expectStateUpdate presenter , -> highlight . flash ( ' c ' , 600 )
expectValues stateForHighlight ( presenter , highlight ) , {
flashClass: ' c '
flashDuration: 600
flashCount: 2
}
2015-01-27 01:13:14 +03:00
2015-01-27 19:03:46 +03:00
describe " .overlays " , ->
stateForOverlay = (presenter, decoration) ->
presenter . state . content . overlays [ decoration . id ]
it " contains state for overlay decorations both initially and when their markers move " , ->
item = { }
marker = editor . markBufferPosition ( [ 2 , 13 ] , invalidate: ' touch ' )
decoration = editor . decorateMarker ( marker , { type: ' overlay ' , item } )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-27 19:03:46 +03:00
# Initial state
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
# Change range
expectStateUpdate presenter , -> marker . setBufferRange ( [ [ 2 , 13 ] , [ 4 , 6 ] ] )
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 4 * 10 , left: 6 * 10 }
}
# Valid -> invalid
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 2 , 14 ] , ' x ' )
expect ( stateForOverlay ( presenter , decoration ) ) . toBeUndefined ( )
# Invalid -> valid
expectStateUpdate presenter , -> editor . undo ( )
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 4 * 10 , left: 6 * 10 }
}
# Reverse direction
expectStateUpdate presenter , -> marker . setBufferRange ( [ [ 2 , 13 ] , [ 4 , 6 ] ] , reversed: true )
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
# Destroy
decoration . destroy ( )
expect ( stateForOverlay ( presenter , decoration ) ) . toBeUndefined ( )
# Add
decoration2 = editor . decorateMarker ( marker , { type: ' overlay ' , item } )
expectValues stateForOverlay ( presenter , decoration2 ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
2015-01-28 03:26:54 +03:00
it " updates when ::baseCharacterWidth changes " , ->
item = { }
marker = editor . markBufferPosition ( [ 2 , 13 ] , invalidate: ' touch ' )
decoration = editor . decorateMarker ( marker , { type: ' overlay ' , item } )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-28 03:26:54 +03:00
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
expectStateUpdate presenter , -> presenter . setBaseCharacterWidth ( 5 )
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 5 }
}
it " updates when ::lineHeight changes " , ->
item = { }
marker = editor . markBufferPosition ( [ 2 , 13 ] , invalidate: ' touch ' )
decoration = editor . decorateMarker ( marker , { type: ' overlay ' , item } )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-28 03:26:54 +03:00
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
expectStateUpdate presenter , -> presenter . setLineHeight ( 5 )
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 5 , left: 13 * 10 }
}
2015-01-27 19:03:46 +03:00
it " honors the ' position ' option on overlay decorations " , ->
item = { }
marker = editor . markBufferRange ( [ [ 2 , 13 ] , [ 4 , 14 ] ] , invalidate: ' touch ' )
decoration = editor . decorateMarker ( marker , { type: ' overlay ' , position: ' tail ' , item } )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 30 , scrollTop: 20 , lineHeight: 10 , lineOverdrawMargin: 0 , baseCharacterWidth: 10 )
2015-01-27 19:03:46 +03:00
expectValues stateForOverlay ( presenter , decoration ) , {
item: item
pixelPosition: { top: 2 * 10 , left: 13 * 10 }
}
2015-01-28 03:26:54 +03:00
it " is empty until all of the required measurements are assigned " , ->
item = { }
marker = editor . markBufferRange ( [ [ 2 , 13 ] , [ 4 , 14 ] ] , invalidate: ' touch ' )
decoration = editor . decorateMarker ( marker , { type: ' overlay ' , position: ' tail ' , item } )
presenter = new TextEditorPresenter ( model: editor , lineOverdrawMargin: 0 , scrollTop: 0 , scrollHeight: 50 )
expect ( presenter . state . content . overlays ) . toEqual ( { } )
presenter . setBaseCharacterWidth ( 10 )
expect ( presenter . state . content . overlays ) . toEqual ( { } )
presenter . setLineHeight ( 10 )
expect ( presenter . state . content . overlays ) . not . toEqual ( { } )
2015-01-27 02:20:31 +03:00
describe " .gutter " , ->
2015-01-30 00:27:53 +03:00
describe " .scrollHeight " , ->
it " is initialized based on the lineHeight, the number of lines, and the height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expect ( presenter . state . gutter . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , height: 500 )
expect ( presenter . state . gutter . scrollHeight ) . toBe 500
it " updates when the ::lineHeight changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setLineHeight ( 20 )
expect ( presenter . state . gutter . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 20
it " updates when the line count changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> editor . getBuffer ( ) . append ( " \n \n \n " )
expect ( presenter . state . gutter . scrollHeight ) . toBe editor . getScreenLineCount ( ) * 10
it " updates when ::height changes " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 )
expectStateUpdate presenter , -> presenter . setHeight ( 500 )
expect ( presenter . state . gutter . scrollHeight ) . toBe 500
describe " .scrollTop " , ->
it " tracks the value of ::scrollTop " , ->
2015-02-04 19:38:00 +03:00
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 20 )
2015-01-30 00:27:53 +03:00
expect ( presenter . state . gutter . scrollTop ) . toBe 10
expectStateUpdate presenter , -> presenter . setScrollTop ( 50 )
expect ( presenter . state . gutter . scrollTop ) . toBe 50
2015-02-04 19:38:00 +03:00
it " never exceeds the computed scroll height minus the computed client height " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 10 , lineHeight: 10 , height: 50 , horizontalScrollbarHeight: 10 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 100 )
expect ( presenter . state . gutter . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHeight ( 60 )
expect ( presenter . state . gutter . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> presenter . setHorizontalScrollbarHeight ( 15 )
expect ( presenter . state . gutter . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
expectStateUpdate presenter , -> editor . getBuffer ( ) . delete ( [ [ 8 , 0 ] , [ 12 , 0 ] ] )
expect ( presenter . state . gutter . scrollTop ) . toBe presenter . computeScrollHeight ( ) - presenter . computeClientHeight ( )
# Scroll top only gets smaller when needed as dimensions change, never bigger
scrollTopBefore = presenter . state . verticalScrollbar . scrollTop
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 9 , Infinity ] , ' \n \n \n ' )
expect ( presenter . state . gutter . scrollTop ) . toBe scrollTopBefore
2015-01-28 01:07:14 +03:00
describe " .backgroundColor " , ->
it " is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise " , ->
presenter = new TextEditorPresenter ( model: editor , backgroundColor: " rgba(255, 0, 0, 0) " , gutterBackgroundColor: " rgba(0, 255, 0, 0) " )
expect ( presenter . state . gutter . backgroundColor ) . toBe " rgba(0, 255, 0, 0) "
expectStateUpdate presenter , -> presenter . setGutterBackgroundColor ( " rgba(0, 0, 255, 0) " )
expect ( presenter . state . gutter . backgroundColor ) . toBe " rgba(0, 0, 255, 0) "
expectStateUpdate presenter , -> presenter . setGutterBackgroundColor ( " rgba(0, 0, 0, 0) " )
expect ( presenter . state . gutter . backgroundColor ) . toBe " rgba(255, 0, 0, 0) "
2015-01-28 01:36:46 +03:00
describe " .maxLineNumberDigits " , ->
it " is set to the number of digits used by the greatest line number " , ->
presenter = new TextEditorPresenter ( model: editor )
expect ( editor . getLastBufferRow ( ) ) . toBe 12
expect ( presenter . state . gutter . maxLineNumberDigits ) . toBe 2
editor . setText ( " 1 \n 2 \n 3 " )
expect ( presenter . state . gutter . maxLineNumberDigits ) . toBe 1
2015-01-27 02:20:31 +03:00
describe " .lineNumbers " , ->
lineNumberStateForScreenRow = (presenter, screenRow) ->
2015-01-27 16:07:21 +03:00
editor = presenter . model
bufferRow = editor . bufferRowForScreenRow ( screenRow )
wrapCount = screenRow - editor . screenRowForBufferRow ( bufferRow )
if wrapCount > 0
key = bufferRow + ' - ' + wrapCount
else
key = bufferRow
presenter . state . gutter . lineNumbers [ key ]
2015-01-27 02:20:31 +03:00
it " contains states for line numbers that are visible on screen, plus and minus the overdraw margin " , ->
editor . foldBufferRow ( 4 )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 50 )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 30 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
2015-01-27 16:07:21 +03:00
expectValues lineNumberStateForScreenRow ( presenter , 2 ) , { screenRow: 2 , bufferRow: 2 , softWrapped: false , top: 2 * 10 }
expectValues lineNumberStateForScreenRow ( presenter , 3 ) , { screenRow: 3 , bufferRow: 3 , softWrapped: false , top: 3 * 10 }
expectValues lineNumberStateForScreenRow ( presenter , 4 ) , { screenRow: 4 , bufferRow: 3 , softWrapped: true , top: 4 * 10 }
expectValues lineNumberStateForScreenRow ( presenter , 5 ) , { screenRow: 5 , bufferRow: 4 , softWrapped: false , top: 5 * 10 }
expectValues lineNumberStateForScreenRow ( presenter , 6 ) , { screenRow: 6 , bufferRow: 7 , softWrapped: false , top: 6 * 10 }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { screenRow: 7 , bufferRow: 8 , softWrapped: false , top: 7 * 10 }
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
it " includes states for all line numbers if no external client height is assigned " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 12 ) ) . toBeDefined ( )
it " updates when ::scrollTop changes " , ->
editor . foldBufferRow ( 4 )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 50 )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 30 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 2 ) , { bufferRow: 2 }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { bufferRow: 8 }
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> presenter . setScrollTop ( 20 )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 1 ) , { bufferRow: 1 }
expectValues lineNumberStateForScreenRow ( presenter , 6 ) , { bufferRow: 7 }
expect ( lineNumberStateForScreenRow ( presenter , 7 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
it " updates when ::height changes " , ->
2015-01-27 02:20:31 +03:00
editor . foldBufferRow ( 4 )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 50 )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 30 , lineHeight: 10 , lineOverdrawMargin: 1 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 2 ) , { bufferRow: 2 }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { bufferRow: 8 }
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
2015-01-29 03:59:18 +03:00
expectStateUpdate presenter , -> presenter . setHeight ( 35 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 2 ) , { bufferRow: 2 }
expectValues lineNumberStateForScreenRow ( presenter , 8 ) , { bufferRow: 8 }
expect ( lineNumberStateForScreenRow ( presenter , 9 ) ) . toBeUndefined ( )
it " updates when ::lineHeight changes " , ->
editor . foldBufferRow ( 4 )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 50 )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
expectValues lineNumberStateForScreenRow ( presenter , 0 ) , { bufferRow: 0 }
expectValues lineNumberStateForScreenRow ( presenter , 3 ) , { bufferRow: 3 }
expect ( lineNumberStateForScreenRow ( presenter , 4 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> presenter . setLineHeight ( 5 )
expectValues lineNumberStateForScreenRow ( presenter , 0 ) , { bufferRow: 0 }
expectValues lineNumberStateForScreenRow ( presenter , 5 ) , { bufferRow: 4 }
expect ( lineNumberStateForScreenRow ( presenter , 6 ) ) . toBeUndefined ( )
it " updates when the editor ' s content changes " , ->
editor . foldBufferRow ( 4 )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 50 )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 35 , scrollTop: 30 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 2 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 3 ) , { bufferRow: 3 }
expectValues lineNumberStateForScreenRow ( presenter , 4 ) , { bufferRow: 3 }
expectValues lineNumberStateForScreenRow ( presenter , 5 ) , { bufferRow: 4 }
expectValues lineNumberStateForScreenRow ( presenter , 6 ) , { bufferRow: 7 }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { bufferRow: 8 }
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
expectStateUpdate presenter , ->
editor . getBuffer ( ) . insert ( [ 3 , Infinity ] , new Array ( 25 ) . join ( " x " ) )
expect ( lineNumberStateForScreenRow ( presenter , 2 ) ) . toBeUndefined ( )
expectValues lineNumberStateForScreenRow ( presenter , 3 ) , { bufferRow: 3 }
expectValues lineNumberStateForScreenRow ( presenter , 4 ) , { bufferRow: 3 }
expectValues lineNumberStateForScreenRow ( presenter , 5 ) , { bufferRow: 3 }
expectValues lineNumberStateForScreenRow ( presenter , 6 ) , { bufferRow: 4 }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { bufferRow: 7 }
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
2015-01-29 02:24:54 +03:00
it " does not remove out-of-view line numbers corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 1 , stoppedScrollingDelay: 200 )
2015-01-29 02:24:54 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) ) . toBeUndefined ( )
presenter . setMouseWheelScreenRow ( 0 )
expectStateUpdate presenter , -> presenter . setScrollTop ( 35 )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 7 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
expectStateUpdate presenter , -> advanceClock ( 200 )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) ) . toBeUndefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 1 ) ) . toBeUndefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 7 ) ) . toBeDefined ( )
expect ( lineNumberStateForScreenRow ( presenter , 8 ) ) . toBeUndefined ( )
2015-01-27 02:20:31 +03:00
2015-02-03 23:30:42 +03:00
it " correctly handles the first screen line being soft-wrapped " , ->
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 30 )
presenter = new TextEditorPresenter ( model: editor , height: 25 , scrollTop: 50 , lineHeight: 10 , lineOverdrawMargin: 0 )
expectValues lineNumberStateForScreenRow ( presenter , 5 ) , { screenRow: 5 , bufferRow: 3 , softWrapped: true }
expectValues lineNumberStateForScreenRow ( presenter , 6 ) , { screenRow: 6 , bufferRow: 3 , softWrapped: true }
expectValues lineNumberStateForScreenRow ( presenter , 7 ) , { screenRow: 7 , bufferRow: 4 , softWrapped: false }
2015-01-27 02:20:31 +03:00
describe " .decorationClasses " , ->
it " adds decoration classes to the relevant line number state objects, both initially and when decorations change " , ->
marker1 = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] , invalidate: ' touch ' )
decoration1 = editor . decorateMarker ( marker1 , type: ' line-number ' , class : ' a ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
marker2 = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] , invalidate: ' touch ' )
decoration2 = editor . decorateMarker ( marker2 , type: ' line-number ' , class : ' b ' )
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> editor . getBuffer ( ) . insert ( [ 5 , 0 ] , ' x ' )
expect ( marker1 . isValid ( ) ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> editor . undo ( )
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> marker1 . setBufferRange ( [ [ 2 , 0 ] , [ 4 , 2 ] ] )
expect ( lineNumberStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' , ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> decoration1 . destroy ( )
expect ( lineNumberStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' b ' ]
expect ( lineNumberStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> marker2 . destroy ( )
expect ( lineNumberStateForScreenRow ( presenter , 2 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 7 ) . decorationClasses ) . toBeNull ( )
2015-01-27 17:46:29 +03:00
it " honors the ' onlyEmpty ' option on line-number decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 1 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' , onlyEmpty: true )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> marker . clearTail ( )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
2015-01-27 17:46:29 +03:00
it " honors the ' onlyNonEmpty ' option on line-number decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' , onlyNonEmpty: true )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
expectStateUpdate presenter , -> marker . clearTail ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
2015-01-27 17:49:24 +03:00
it " honors the ' onlyHead ' option on line-number decorations " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 17:49:24 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 2 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' , onlyHead: true )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toBeNull ( )
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toEqual [ ' a ' ]
2015-01-27 17:46:29 +03:00
it " does not decorate the last line of a non-empty line-number decoration range if it ends at column 0 " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
marker = editor . markBufferRange ( [ [ 4 , 0 ] , [ 6 , 0 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' )
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . decorationClasses ) . toEqual [ ' a ' ]
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . decorationClasses ) . toBeNull ( )
2015-01-27 17:46:29 +03:00
it " does not apply line-number decorations to mini editors " , ->
2015-01-27 02:20:31 +03:00
editor . setMini ( true )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 10 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
marker = editor . markBufferRange ( [ [ 0 , 0 ] , [ 0 , 0 ] ] )
decoration = editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toBeNull ( )
expectStateUpdate presenter , -> editor . setMini ( false )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toEqual [ ' cursor-line ' , ' cursor-line-no-selection ' , ' a ' ]
expectStateUpdate presenter , -> editor . setMini ( true )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toBeNull ( )
2015-01-27 17:46:29 +03:00
it " only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped " , ->
2015-01-27 17:41:48 +03:00
editor . setText ( " a line that wraps, ok " )
editor . setSoftWrapped ( true )
editor . setEditorWidthInChars ( 16 )
marker = editor . markBufferRange ( [ [ 0 , 0 ] , [ 0 , 2 ] ] )
editor . decorateMarker ( marker , type: ' line-number ' , class : ' a ' )
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 10 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 17:41:48 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toContain ' a '
expect ( lineNumberStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toBeNull ( )
marker . setBufferRange ( [ [ 0 , 0 ] , [ 0 , Infinity ] ] )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . decorationClasses ) . toContain ' a '
expect ( lineNumberStateForScreenRow ( presenter , 1 ) . decorationClasses ) . toContain ' a '
2015-01-27 02:20:31 +03:00
describe " .foldable " , ->
it " marks line numbers at the start of a foldable region as foldable " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 1 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 2 ) . foldable ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . foldable ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . foldable ) . toBe false
it " updates the foldable class on the correct line numbers when the foldable positions change " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
editor . getBuffer ( ) . insert ( [ 0 , 0 ] , ' \n ' )
expect ( lineNumberStateForScreenRow ( presenter , 0 ) . foldable ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 1 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 2 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 3 ) . foldable ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 4 ) . foldable ) . toBe false
expect ( lineNumberStateForScreenRow ( presenter , 5 ) . foldable ) . toBe true
expect ( lineNumberStateForScreenRow ( presenter , 6 ) . foldable ) . toBe false
it " updates the foldable class on a line number that becomes foldable " , ->
2015-01-29 03:59:18 +03:00
presenter = new TextEditorPresenter ( model: editor , height: 130 , scrollTop: 0 , lineHeight: 10 , lineOverdrawMargin: 0 )
2015-01-27 02:20:31 +03:00
expect ( lineNumberStateForScreenRow ( presenter , 11 ) . foldable ) . toBe false
editor . getBuffer ( ) . insert ( [ 11 , 44 ] , ' \n fold me ' )
expect ( lineNumberStateForScreenRow ( presenter , 11 ) . foldable ) . toBe true
editor . undo ( )
expect ( lineNumberStateForScreenRow ( presenter , 11 ) . foldable ) . toBe false
2015-01-30 01:05:15 +03:00
describe " .height " , ->
it " tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically " , ->
presenter = new TextEditorPresenter ( model: editor , scrollTop: 0 , lineHeight: 10 , autoHeight: true )
expect ( presenter . state . height ) . toBe editor . getScreenLineCount ( ) * 10
expectStateUpdate presenter , -> presenter . setAutoHeight ( false )
expect ( presenter . state . height ) . toBe null
expectStateUpdate presenter , -> presenter . setAutoHeight ( true )
expect ( presenter . state . height ) . toBe editor . getScreenLineCount ( ) * 10
expectStateUpdate presenter , -> presenter . setLineHeight ( 20 )
expect ( presenter . state . height ) . toBe editor . getScreenLineCount ( ) * 20
expectStateUpdate presenter , -> editor . getBuffer ( ) . append ( " \n \n \n " )
expect ( presenter . state . height ) . toBe editor . getScreenLineCount ( ) * 20
2015-01-30 23:04:20 +03:00
describe " when the model and view measurements are mutated randomly " , ->
[ editor , buffer , presenter , presenterParams ] = [ ]
it " correctly maintains the presenter state " , ->
_ . times 10 , ->
waits ( 0 )
runs ->
buffer = new TextBuffer
editor = new TextEditor ( { buffer } )
editor . setEditorWidthInChars ( 80 )
presenterParams =
model: editor
height: 50
contentFrameWidth: 300
scrollTop: 0
scrollLeft: 0
lineHeight: 10
baseCharacterWidth: 10
lineOverdrawMargin: 1
presenter = new TextEditorPresenter ( presenterParams )
referencePresenter = new TextEditorPresenter ( presenterParams )
expect ( presenter . state ) . toEqual referencePresenter . state
2015-02-03 08:09:25 +03:00
actions = [ ]
2015-01-30 23:04:20 +03:00
_ . times 30 , ->
performRandomAction (action) -> actions . push ( action )
actualState = presenter . state
expectedState = new TextEditorPresenter ( presenterParams ) . state
delete actualState . content . scrollingVertically
delete expectedState . content . scrollingVertically
unless _ . isEqual ( actualState , expectedState )
console . log " Prestenter states differ >>>>>>>>>>>>>>>> "
console . log " Actual: " , actualState
console . log " Expected: " , expectedState
console . log " Uncomment code below this line to see a JSON diff "
# {diff} = require 'json-diff' # !!! Run `npm install json-diff` in your `atom/` repository
# console.log "Difference:", diff(actualState, expectedState)
console . log " "
console . log " Actions: "
console . log action for action in actions
console . log " "
console . log " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< "
throw new Error ( " Unexpected presenter state after random mutation. Check console output for details. " )
buffer . destroy ( )
performRandomAction = (log) ->
getRandomElement ( [
changeScrollLeft
changeScrollTop
toggleSoftWrap
insertText
changeCursors
changeSelections
changeLineDecorations
] ) ( log )
changeScrollTop = (log) ->
scrollHeight = presenterParams . lineHeight * editor . getScreenLineCount ( )
newScrollTop = Math . max ( 0 , _ . random ( 0 , scrollHeight - presenterParams . height ) )
2015-02-04 18:42:06 +03:00
log """
presenterParams.scrollTop = #{newScrollTop}
presenter . setScrollTop ( #{newScrollTop})
"""
2015-01-30 23:04:20 +03:00
presenterParams.scrollTop = newScrollTop
presenter . setScrollTop ( newScrollTop )
changeScrollLeft = (log) ->
scrollWidth = presenter . computeScrollWidth ( )
newScrollLeft = Math . max ( 0 , _ . random ( 0 , scrollWidth - presenterParams . contentFrameWidth ) )
2015-02-04 18:42:06 +03:00
log """
presenterParams.scrollLeft = #{newScrollLeft}
presenter . setScrollLeft ( #{newScrollLeft})
"""
2015-01-30 23:04:20 +03:00
presenterParams.scrollLeft = newScrollLeft
presenter . setScrollLeft ( newScrollLeft )
changeHeight = (log) ->
scrollHeight = presenterParams . lineHeight * editor . getScreenLineCount ( )
newHeight = _ . random ( 30 , scrollHeight * 1.5 )
2015-02-04 18:42:06 +03:00
log """
presenterParams.height = #{newHeight}
presenter . setHeight ( #{newHeight})
"""
2015-01-30 23:04:20 +03:00
presenterParams.height = newHeight
presenter . setHeight ( newHeight )
changeContentFrameWidth = (log) ->
scrollWidth = presenter . computeScrollWidth ( )
newContentFrameWidth = _ . random ( 100 , scrollWidth * 1.5 )
2015-02-04 18:42:06 +03:00
log """
presenterParams.contentFrameWidth = #{newContentFrameWidth}
presenter . setContentFrameWidth ( #{newContentFrameWidth})
"""
2015-01-30 23:04:20 +03:00
presenterParams.contentFrameWidth = newContentFrameWidth
presenter . setContentFrameWidth ( newContentFrameWidth )
toggleSoftWrap = (log) ->
softWrapped = not editor . isSoftWrapped ( )
2015-02-04 18:42:06 +03:00
log " editor.setSoftWrapped( #{ softWrapped } ) "
2015-01-30 23:04:20 +03:00
editor . setSoftWrapped ( softWrapped )
insertText = (log) ->
range = buildRandomRange ( )
text = buildRandomText ( )
2015-02-04 18:42:06 +03:00
log " editor.setTextInBufferRange( #{ JSON . stringify ( range . serialize ( ) ) } , #{ JSON . stringify ( text ) } ) "
2015-01-30 23:04:20 +03:00
editor . setTextInBufferRange ( range , text )
changeCursors = (log) ->
actions = [ addCursor , moveCursor ]
actions . push ( destroyCursor ) if editor . getCursors ( ) . length > 1
getRandomElement ( actions ) ( log )
addCursor = (log) ->
position = buildRandomPoint ( )
2015-02-04 18:42:06 +03:00
log " editor.addCursorAtBufferPosition( #{ JSON . stringify ( position . serialize ( ) ) } ) "
2015-01-30 23:04:20 +03:00
editor . addCursorAtBufferPosition ( position )
moveCursor = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getCursors ( ) . length - 1 )
2015-01-30 23:04:20 +03:00
position = buildRandomPoint ( )
2015-02-04 18:42:06 +03:00
log """
cursor = editor . getCursors ( ) [ #{index}]
cursor . selection . clear ( )
cursor . setBufferPosition ( #{JSON.stringify(position.serialize())})
"""
cursor = editor . getCursors ( ) [ index ]
2015-01-30 23:04:20 +03:00
cursor . selection . clear ( )
cursor . setBufferPosition ( position )
destroyCursor = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getCursors ( ) . length - 1 )
log " editor.getCursors()[ #{ index } ].destroy() "
editor . getCursors ( ) [ index ] . destroy ( )
2015-01-30 23:04:20 +03:00
changeSelections = (log) ->
actions = [ addSelection , changeSelection ]
actions . push ( destroySelection ) if editor . getSelections ( ) . length > 1
getRandomElement ( actions ) ( log )
addSelection = (log) ->
range = buildRandomRange ( )
2015-02-04 18:42:06 +03:00
log " editor.addSelectionForBufferRange( #{ JSON . stringify ( range . serialize ( ) ) } ) "
2015-01-30 23:04:20 +03:00
editor . addSelectionForBufferRange ( range )
changeSelection = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getSelections ( ) . length - 1 )
2015-01-30 23:04:20 +03:00
range = buildRandomRange ( )
2015-02-04 18:42:06 +03:00
log " editor.getSelections()[ #{ index } ].setBufferRange( #{ JSON . stringify ( range . serialize ( ) ) } ) "
editor . getSelections ( ) [ index ] . setBufferRange ( range )
2015-01-30 23:04:20 +03:00
destroySelection = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getSelections ( ) . length - 1 )
log " editor.getSelections()[ #{ index } ].destroy() "
editor . getSelections ( ) [ index ] . destroy ( )
2015-01-30 23:04:20 +03:00
changeLineDecorations = (log) ->
actions = [ addLineDecoration ]
actions . push ( changeLineDecoration , destroyLineDecoration ) if editor . getLineDecorations ( ) . length > 0
getRandomElement ( actions ) ( log )
addLineDecoration = (log) ->
range = buildRandomRange ( )
options = {
type: getRandomElement ( [ ' line ' , ' line-number ' ] )
class : randomWords ( exactly: 1 ) [ 0 ]
}
if Math . random ( ) > . 2
options.onlyEmpty = true
else if Math . random ( ) > . 2
options.onlyNonEmpty = true
else if Math . random ( ) > . 2
options.onlyHead = true
2015-02-04 18:42:06 +03:00
log """
marker = editor . markBufferRange ( #{JSON.stringify(range.serialize())})
editor . decorateMarker ( marker , #{JSON.stringify(options)})
"""
2015-01-30 23:04:20 +03:00
marker = editor . markBufferRange ( range )
editor . decorateMarker ( marker , options )
changeLineDecoration = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getLineDecorations ( ) . length - 1 )
2015-01-30 23:04:20 +03:00
range = buildRandomRange ( )
2015-02-04 18:42:06 +03:00
log " editor.getLineDecorations()[ #{ index } ].getMarker().setBufferRange( #{ JSON . stringify ( range . serialize ( ) ) } ) "
editor . getLineDecorations ( ) [ index ] . getMarker ( ) . setBufferRange ( range )
2015-01-30 23:04:20 +03:00
destroyLineDecoration = (log) ->
2015-02-04 18:42:06 +03:00
index = _ . random ( 0 , editor . getLineDecorations ( ) . length - 1 )
log " editor.getLineDecorations()[ #{ index } ].destroy() "
editor . getLineDecorations ( ) [ index ] . destroy ( )
2015-01-30 23:04:20 +03:00
buildRandomPoint = ->
row = _ . random ( 0 , buffer . getLastRow ( ) )
column = _ . random ( 0 , buffer . lineForRow ( row ) . length )
new Point ( row , column )
buildRandomRange = ->
new Range ( buildRandomPoint ( ) , buildRandomPoint ( ) )
buildRandomText = ->
text = [ ]
_ . times _ . random ( 20 , 60 ) , ->
if Math . random ( ) < . 2
text += ' \n '
else
text += " " if /\w$/ . test ( text )
text += randomWords ( exactly: 1 )
text
getRandomElement = (array) ->
array [ Math . floor ( Math . random ( ) * array . length ) ]