mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Merge branch 'master' into ns-fix-editor-auto-height
# Conflicts: # src/text-editor.coffee
This commit is contained in:
@@ -111,7 +111,7 @@
|
||||
"package-generator": "1.0.0",
|
||||
"settings-view": "0.241.2",
|
||||
"snippets": "1.0.2",
|
||||
"spell-check": "0.67.1",
|
||||
"spell-check": "0.68.0",
|
||||
"status-bar": "1.4.1",
|
||||
"styleguide": "0.47.0",
|
||||
"symbols-view": "0.113.1",
|
||||
|
||||
@@ -1119,6 +1119,20 @@ describe "Pane", ->
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "restores the active item when it doesn't implement getURI()", ->
|
||||
pane.items[1].getURI = null
|
||||
pane.activateItemAtIndex(1)
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "restores the correct item when it doesn't implement getURI() and some items weren't deserialized", ->
|
||||
unserializable = {}
|
||||
pane.addItem(unserializable, {index: 0})
|
||||
pane.items[2].getURI = null
|
||||
pane.activateItemAtIndex(2)
|
||||
newPane = Pane.deserialize(pane.serialize(), atom)
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "does not include items that cannot be deserialized", ->
|
||||
spyOn(console, 'warn')
|
||||
unserializable = {}
|
||||
|
||||
@@ -3,6 +3,7 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
clipboard = require '../src/safe-clipboard'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextBuffer = require 'text-buffer'
|
||||
|
||||
describe "TextEditor", ->
|
||||
[buffer, editor, lineLengths] = []
|
||||
@@ -41,7 +42,7 @@ describe "TextEditor", ->
|
||||
it "restores the editor's layout configuration", ->
|
||||
editor.update({
|
||||
softTabs: true
|
||||
atomicSoftTabs: true
|
||||
atomicSoftTabs: false
|
||||
tabLength: 12
|
||||
softWrapped: true
|
||||
softWrapAtPreferredLineLength: true
|
||||
@@ -51,7 +52,16 @@ describe "TextEditor", ->
|
||||
editorWidthInChars: 120
|
||||
})
|
||||
|
||||
editor2 = TextEditor.deserialize(editor.serialize(), atom)
|
||||
# Force buffer and display layer to be deserialized as well, rather than
|
||||
# reusing the same buffer instance
|
||||
editor2 = TextEditor.deserialize(editor.serialize(), {
|
||||
assert: atom.assert,
|
||||
clipboard: atom.clipboard,
|
||||
textEditors: atom.textEditors,
|
||||
project: {
|
||||
bufferForIdSync: (id) -> TextBuffer.deserialize(editor.buffer.serialize())
|
||||
}
|
||||
})
|
||||
|
||||
expect(editor2.getSoftTabs()).toBe(editor.getSoftTabs())
|
||||
expect(editor2.hasAtomicSoftTabs()).toBe(editor.hasAtomicSoftTabs())
|
||||
@@ -60,6 +70,7 @@ describe "TextEditor", ->
|
||||
expect(editor2.getSoftWrapHangingIndentLength()).toBe(editor.getSoftWrapHangingIndentLength())
|
||||
expect(editor2.getInvisibles()).toEqual(editor.getInvisibles())
|
||||
expect(editor2.getEditorWidthInChars()).toBe(editor.getEditorWidthInChars())
|
||||
expect(editor2.displayLayer.tabLength).toBe(editor2.getTabLength())
|
||||
|
||||
describe "when the editor is constructed with the largeFileMode option set to true", ->
|
||||
it "loads the editor but doesn't tokenize", ->
|
||||
|
||||
@@ -432,9 +432,9 @@ describe "Workspace", ->
|
||||
runs ->
|
||||
expect(editor.largeFileMode).toBe true
|
||||
|
||||
describe "when the file is over 20MB", ->
|
||||
it "prompts the user to make sure they want to open a file this big", ->
|
||||
spyOn(fs, 'getSizeSync').andReturn 20 * 1048577 # 20MB
|
||||
describe "when the file is over user-defined limit", ->
|
||||
shouldPromptForFileOfSize = (size, shouldPrompt) ->
|
||||
spyOn(fs, 'getSizeSync').andReturn size * 1048577
|
||||
atom.applicationDelegate.confirm.andCallFake -> selectedButtonIndex
|
||||
atom.applicationDelegate.confirm()
|
||||
selectedButtonIndex = 1 # cancel
|
||||
@@ -442,20 +442,35 @@ describe "Workspace", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('sample.js').then (e) -> editor = e
|
||||
if shouldPrompt
|
||||
runs ->
|
||||
expect(editor).toBeUndefined()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
|
||||
runs ->
|
||||
expect(editor).toBeUndefined()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
atom.applicationDelegate.confirm.reset()
|
||||
selectedButtonIndex = 0 # open the file
|
||||
|
||||
atom.applicationDelegate.confirm.reset()
|
||||
selectedButtonIndex = 0 # open the file
|
||||
waitsForPromise ->
|
||||
workspace.open('sample.js').then (e) -> editor = e
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('sample.js').then (e) -> editor = e
|
||||
runs ->
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(editor.largeFileMode).toBe true
|
||||
else
|
||||
runs ->
|
||||
expect(editor).not.toBeUndefined()
|
||||
|
||||
runs ->
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(editor.largeFileMode).toBe true
|
||||
it "prompts the user to make sure they want to open a file this big", ->
|
||||
atom.config.set "core.warnOnLargeFileLimit", 20
|
||||
shouldPromptForFileOfSize 20, true
|
||||
|
||||
it "doesn't prompt on files below the limit", ->
|
||||
atom.config.set "core.warnOnLargeFileLimit", 30
|
||||
shouldPromptForFileOfSize 20, false
|
||||
|
||||
it "prompts for smaller files with a lower limit", ->
|
||||
atom.config.set "core.warnOnLargeFileLimit", 5
|
||||
shouldPromptForFileOfSize 10, true
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
it "returns the resource returned by the custom opener", ->
|
||||
|
||||
@@ -122,6 +122,10 @@ module.exports =
|
||||
{value: 'no', description: 'Do not send any telemetry data'}
|
||||
{value: 'undecided', description: 'Undecided (Atom will ask again next time it is launched)'}
|
||||
]
|
||||
warnOnLargeFileLimit:
|
||||
description: 'Warn before opening files larger than this number of megabytes.'
|
||||
type: 'number'
|
||||
default: 20
|
||||
editor:
|
||||
type: 'object'
|
||||
properties:
|
||||
|
||||
@@ -21,13 +21,16 @@ class Pane extends Model
|
||||
focused: false
|
||||
|
||||
@deserialize: (state, {deserializers, applicationDelegate, config, notifications}) ->
|
||||
{items, itemStackIndices, activeItemURI, activeItemUri} = state
|
||||
{items, itemStackIndices, activeItemIndex, activeItemURI, activeItemUri} = state
|
||||
activeItemURI ?= activeItemUri
|
||||
state.items = compact(items.map (itemState) -> deserializers.deserialize(itemState))
|
||||
state.activeItem = find state.items, (item) ->
|
||||
if typeof item.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
itemURI is activeItemURI
|
||||
items = items.map (itemState) -> deserializers.deserialize(itemState)
|
||||
state.activeItem = items[activeItemIndex]
|
||||
state.items = compact(items)
|
||||
if activeItemURI?
|
||||
state.activeItem ?= find state.items, (item) ->
|
||||
if typeof item.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
itemURI is activeItemURI
|
||||
new Pane(extend(state, {
|
||||
deserializerManager: deserializers,
|
||||
notificationManager: notifications,
|
||||
@@ -53,16 +56,15 @@ class Pane extends Model
|
||||
@setFlexScale(params?.flexScale ? 1)
|
||||
|
||||
serialize: ->
|
||||
if typeof @activeItem?.getURI is 'function'
|
||||
activeItemURI = @activeItem.getURI()
|
||||
itemsToBeSerialized = compact(@items.map((item) -> item if typeof item.serialize is 'function'))
|
||||
itemStackIndices = (itemsToBeSerialized.indexOf(item) for item in @itemStack when typeof item.serialize is 'function')
|
||||
activeItemIndex = itemsToBeSerialized.indexOf(@activeItem)
|
||||
|
||||
deserializer: 'Pane'
|
||||
id: @id
|
||||
items: itemsToBeSerialized.map((item) -> item.serialize())
|
||||
itemStackIndices: itemStackIndices
|
||||
activeItemURI: activeItemURI
|
||||
activeItemIndex: activeItemIndex
|
||||
focused: @focused
|
||||
flexScale: @flexScale
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ class TextEditor extends Model
|
||||
|
||||
try
|
||||
state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer, atomEnvironment)
|
||||
state.tabLength = state.tokenizedBuffer.getTabLength()
|
||||
catch error
|
||||
if error.syscall is 'read'
|
||||
return # Error reading the file, don't deserialize an editor for it
|
||||
@@ -128,7 +129,7 @@ class TextEditor extends Model
|
||||
@softWrapped, @decorationManager, @selectionsMarkerLayer, @buffer, suppressCursorCreation,
|
||||
@mini, @placeholderText, lineNumberGutterVisible, @largeFileMode, @clipboard,
|
||||
@assert, grammar, @showInvisibles, @autoHeight, @autoWidth, @scrollPastEnd, @editorWidthInChars,
|
||||
@tokenizedBuffer, @displayLayer, @invisibles, @showIndentGuide, @softWrapHangingIndentLength,
|
||||
@tokenizedBuffer, @displayLayer, @invisibles, @showIndentGuide,
|
||||
@softWrapped, @softWrapAtPreferredLineLength, @preferredLineLength
|
||||
} = params
|
||||
|
||||
@@ -154,7 +155,6 @@ class TextEditor extends Model
|
||||
@undoGroupingInterval ?= 300
|
||||
@nonWordCharacters ?= "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-…"
|
||||
@softWrapped ?= false
|
||||
@softWrapHangingIndentLength ?= 0
|
||||
@softWrapAtPreferredLineLength ?= false
|
||||
@preferredLineLength ?= 80
|
||||
|
||||
@@ -162,17 +162,24 @@ class TextEditor extends Model
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({
|
||||
grammar, tabLength, @buffer, @largeFileMode, @assert
|
||||
})
|
||||
@displayLayer ?= @buffer.addDisplayLayer({
|
||||
|
||||
displayLayerParams = {
|
||||
invisibles: @getInvisibles(),
|
||||
softWrapColumn: @getSoftWrapColumn(),
|
||||
showIndentGuides: not @isMini() and @doesShowIndentGuide(),
|
||||
atomicSoftTabs: @hasAtomicSoftTabs(),
|
||||
tabLength: @getTabLength(),
|
||||
atomicSoftTabs: params.atomicSoftTabs ? true,
|
||||
tabLength: tabLength,
|
||||
ratioForCharacter: @ratioForCharacter.bind(this),
|
||||
isWrapBoundary: isWrapBoundary,
|
||||
foldCharacter: ZERO_WIDTH_NBSP,
|
||||
softWrapHangingIndent: @getSoftWrapHangingIndentLength()
|
||||
})
|
||||
softWrapHangingIndent: params.softWrapHangingIndentLength ? 0
|
||||
}
|
||||
|
||||
if @displayLayer?
|
||||
@displayLayer.reset(displayLayerParams)
|
||||
else
|
||||
@displayLayer = @buffer.addDisplayLayer(displayLayerParams)
|
||||
|
||||
@displayLayer.setTextDecorationLayer(@tokenizedBuffer)
|
||||
@defaultMarkerLayer = @displayLayer.addMarkerLayer()
|
||||
@selectionsMarkerLayer ?= @addMarkerLayer(maintainHistory: true, persistent: true)
|
||||
@@ -229,8 +236,7 @@ class TextEditor extends Model
|
||||
@softTabs = value
|
||||
|
||||
when 'atomicSoftTabs'
|
||||
if value isnt @atomicSoftTabs
|
||||
@atomicSoftTabs = value
|
||||
if value isnt @displayLayer.atomicSoftTabs
|
||||
displayLayerParams.atomicSoftTabs = value
|
||||
|
||||
when 'tabLength'
|
||||
@@ -245,8 +251,7 @@ class TextEditor extends Model
|
||||
@emitter.emit 'did-change-soft-wrapped', @isSoftWrapped()
|
||||
|
||||
when 'softWrapHangingIndentLength'
|
||||
if value isnt @softWrapHangingIndentLength
|
||||
@softWrapHangingIndentLength = value
|
||||
if value isnt @displayLayer.softWrapHangingIndent
|
||||
displayLayerParams.softWrapHangingIndent = value
|
||||
|
||||
when 'softWrapAtPreferredLineLength'
|
||||
@@ -351,11 +356,12 @@ class TextEditor extends Model
|
||||
firstVisibleScreenRow: @getFirstVisibleScreenRow()
|
||||
firstVisibleScreenColumn: @getFirstVisibleScreenColumn()
|
||||
|
||||
@id, @softTabs, @atomicSoftTabs, @tabLength, @softWrapped,
|
||||
@softWrapHangingIndentLength, @softWrapAtPreferredLineLength,
|
||||
@preferredLineLength, @mini, @editorWidthInChars, @width, @largeFileMode,
|
||||
@registered, @invisibles, @showInvisibles, @showIndentGuide, @autoHeight,
|
||||
@autoWidth
|
||||
atomicSoftTabs: @displayLayer.atomicSoftTabs
|
||||
softWrapHangingIndentLength: @displayLayer.softWrapHangingIndent
|
||||
|
||||
@id, @softTabs, @softWrapped, @softWrapAtPreferredLineLength,
|
||||
@preferredLineLength, @mini, @editorWidthInChars, @width, @largeFileMode,
|
||||
@registered, @invisibles, @showInvisibles, @showIndentGuide, @autoHeight, @autoWidth
|
||||
}
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@@ -694,8 +700,9 @@ class TextEditor extends Model
|
||||
selectionsMarkerLayer = displayLayer.getMarkerLayer(@buffer.getMarkerLayer(@selectionsMarkerLayer.id).copy().id)
|
||||
softTabs = @getSoftTabs()
|
||||
new TextEditor({
|
||||
@buffer, selectionsMarkerLayer, @tabLength, softTabs,
|
||||
@buffer, selectionsMarkerLayer, softTabs,
|
||||
suppressCursorCreation: true,
|
||||
tabLength: @tokenizedBuffer.getTabLength(),
|
||||
@firstVisibleScreenRow, @firstVisibleScreenColumn,
|
||||
@clipboard, @assert, displayLayer, grammar: @getGrammar()
|
||||
})
|
||||
@@ -2817,7 +2824,7 @@ class TextEditor extends Model
|
||||
setSoftTabs: (@softTabs) -> @update({softTabs})
|
||||
|
||||
# Returns a {Boolean} indicating whether atomic soft tabs are enabled for this editor.
|
||||
hasAtomicSoftTabs: -> @atomicSoftTabs
|
||||
hasAtomicSoftTabs: -> @displayLayer.atomicSoftTabs
|
||||
|
||||
# Essential: Toggle soft tabs for this editor
|
||||
toggleSoftTabs: -> @setSoftTabs(not @getSoftTabs())
|
||||
@@ -2844,7 +2851,7 @@ class TextEditor extends Model
|
||||
|
||||
doesShowIndentGuide: -> @showIndentGuide and not @mini
|
||||
|
||||
getSoftWrapHangingIndentLength: -> @softWrapHangingIndentLength
|
||||
getSoftWrapHangingIndentLength: -> @displayLayer.softWrapHangingIndent
|
||||
|
||||
# Extended: Determine if the buffer uses hard or soft tabs.
|
||||
#
|
||||
|
||||
@@ -550,7 +550,7 @@ class Workspace extends Model
|
||||
fileSize = fs.getSizeSync(filePath)
|
||||
|
||||
largeFileMode = fileSize >= 2 * 1048576 # 2MB
|
||||
if fileSize >= 20 * 1048576 # 20MB
|
||||
if fileSize >= @config.get('core.warnOnLargeFileLimit') * 1048576 # 20MB by default
|
||||
choice = @applicationDelegate.confirm
|
||||
message: 'Atom will be unresponsive during the loading of very large files.'
|
||||
detailedMessage: "Do you still want to load this file?"
|
||||
|
||||
Reference in New Issue
Block a user