mirror of
https://github.com/atom/atom.git
synced 2026-01-24 22:38:20 -05:00
Merge branch 'master' into mb-tree-sitter-parsers
This commit is contained in:
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "1.18.10"
|
||||
"atom-package-manager": "1.18.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
"background-tips": "0.27.1",
|
||||
"bookmarks": "0.45.0",
|
||||
"bracket-matcher": "0.88.0",
|
||||
"command-palette": "0.42.1",
|
||||
"command-palette": "0.43.0",
|
||||
"dalek": "0.2.1",
|
||||
"deprecation-cop": "0.56.9",
|
||||
"dev-live-reload": "0.48.1",
|
||||
@@ -121,7 +121,7 @@
|
||||
"link": "0.31.4",
|
||||
"markdown-preview": "0.159.18",
|
||||
"metrics": "1.2.6",
|
||||
"notifications": "0.69.2",
|
||||
"notifications": "0.70.2",
|
||||
"open-on-github": "1.3.1",
|
||||
"package-generator": "1.3.0",
|
||||
"settings-view": "0.253.0",
|
||||
|
||||
@@ -9,34 +9,41 @@ ipcHelpers = require '../src/ipc-helpers'
|
||||
formatStackTrace = (spec, message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
# at ... (.../jasmine.js:1:2)
|
||||
jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at [/\\].*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
# at jasmine.Something... (.../jasmine.js:1:2)
|
||||
firstJasmineLinePattern = /^\s*at\s+jasmine\.[A-Z][^\s]*\s+\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
lines = []
|
||||
for line in stackTrace.split('\n')
|
||||
lines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
lines.push(line) unless jasminePattern.test(line)
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
for line, index in lines
|
||||
# Remove prefix of lines matching: at jasmine.Spec.<anonymous> (path:1:2)
|
||||
prefixMatch = line.match(/at jasmine\.Spec\.<anonymous> \(([^)]+)\)/)
|
||||
line = "at #{prefixMatch[1]}" if prefixMatch
|
||||
lines = lines.map (line) ->
|
||||
# Only format actual stacktrace lines
|
||||
if /^\s*at\s/.test(line)
|
||||
# Needs to occur before path relativization
|
||||
if process.platform is 'win32' and /file:\/\/\//.test(line)
|
||||
# file:///C:/some/file -> C:\some\file
|
||||
line = line.replace('file:///', '').replace(///#{path.posix.sep}///g, path.win32.sep)
|
||||
|
||||
# Relativize locations to spec directory
|
||||
if process.platform is 'win32'
|
||||
line = line.replace('file:///', '').replace(///#{path.posix.sep}///g, path.win32.sep)
|
||||
line = line.replace("at #{spec.specDirectory}#{path.sep}", 'at ')
|
||||
lines[index] = line.replace("(#{spec.specDirectory}#{path.sep}", '(') # at step (path:1:2)
|
||||
line = line.trim()
|
||||
# at jasmine.Spec.<anonymous> (path:1:2) -> at path:1:2
|
||||
.replace(/^at jasmine\.Spec\.<anonymous> \(([^)]+)\)/, 'at $1')
|
||||
# at it (path:1:2) -> at path:1:2
|
||||
.replace(/^at f*it \(([^)]+)\)/, 'at $1')
|
||||
# at spec/file-test.js -> at file-test.js
|
||||
.replace(spec.specDirectory + path.sep, '')
|
||||
|
||||
return line
|
||||
|
||||
lines = lines.map (line) -> line.trim()
|
||||
lines.join('\n').trim()
|
||||
|
||||
module.exports =
|
||||
class AtomReporter
|
||||
|
||||
constructor: ->
|
||||
@element = document.createElement('div')
|
||||
@element.classList.add('spec-reporter-container')
|
||||
|
||||
@@ -70,6 +70,19 @@ describe('TextEditorElement', () => {
|
||||
expect(element.getModel().isLineNumberGutterVisible()).toBe(false)
|
||||
})
|
||||
|
||||
it("honors the 'readonly' attribute", async function() {
|
||||
jasmineContent.innerHTML = "<atom-text-editor readonly>"
|
||||
const element = jasmineContent.firstChild
|
||||
|
||||
expect(element.getComponent().isInputEnabled()).toBe(false)
|
||||
|
||||
element.removeAttribute('readonly')
|
||||
expect(element.getComponent().isInputEnabled()).toBe(true)
|
||||
|
||||
element.setAttribute('readonly', true)
|
||||
expect(element.getComponent().isInputEnabled()).toBe(false)
|
||||
})
|
||||
|
||||
it('honors the text content', () => {
|
||||
jasmineContent.innerHTML = '<atom-text-editor>testing</atom-text-editor>'
|
||||
const element = jasmineContent.firstChild
|
||||
|
||||
@@ -86,6 +86,23 @@ describe('TextEditor', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the editor is readonly', () => {
|
||||
it('overrides TextBuffer.isModified to return false', async () => {
|
||||
const editor = await atom.workspace.open(null, {readOnly: true})
|
||||
editor.setText('I am altering the buffer, pray I do not alter it any further')
|
||||
expect(editor.isModified()).toBe(false)
|
||||
editor.setReadOnly(false)
|
||||
expect(editor.isModified()).toBe(true)
|
||||
})
|
||||
it('clears the readonly status when saved', async () => {
|
||||
const editor = await atom.workspace.open(null, {readOnly: true})
|
||||
editor.setText('I am altering the buffer, pray I do not alter it any further')
|
||||
expect(editor.isReadOnly()).toBe(true)
|
||||
await editor.saveAs(temp.openSync('was-readonly').path)
|
||||
expect(editor.isReadOnly()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.copy()', () => {
|
||||
it('returns a different editor with the same initial state', () => {
|
||||
expect(editor.getAutoHeight()).toBeFalsy()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const path = require('path')
|
||||
const temp = require('temp').track()
|
||||
const dedent = require('dedent')
|
||||
const TextBuffer = require('text-buffer')
|
||||
const TextEditor = require('../src/text-editor')
|
||||
const Workspace = require('../src/workspace')
|
||||
const Project = require('../src/project')
|
||||
@@ -932,6 +934,18 @@ describe('Workspace', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when opening an editor with a buffer that isn\'t part of the project', () => {
|
||||
it('adds the buffer to the project', async () => {
|
||||
const buffer = new TextBuffer()
|
||||
const editor = new TextEditor({buffer})
|
||||
|
||||
await atom.workspace.open(editor)
|
||||
|
||||
expect(atom.project.getBuffers().map(buffer => buffer.id)).toContain(buffer.id)
|
||||
expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('finding items in the workspace', () => {
|
||||
@@ -1206,8 +1220,8 @@ describe('Workspace', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('::onDidStopChangingActivePaneItem()', function () {
|
||||
it('invokes observers when the active item of the active pane stops changing', function () {
|
||||
describe('::onDidStopChangingActivePaneItem()', () => {
|
||||
it('invokes observers when the active item of the active pane stops changing', () => {
|
||||
const pane1 = atom.workspace.getCenter().getActivePane()
|
||||
const pane2 = pane1.splitRight({items: [document.createElement('div'), document.createElement('div')]});
|
||||
atom.workspace.getLeftDock().getActivePane().addItem(document.createElement('div'))
|
||||
@@ -1364,7 +1378,7 @@ describe('Workspace', () => {
|
||||
|
||||
describe('::getActiveTextEditor()', () => {
|
||||
describe("when the workspace center's active pane item is a text editor", () => {
|
||||
describe('when the workspace center has focus', function () {
|
||||
describe('when the workspace center has focus', () => {
|
||||
it('returns the text editor', () => {
|
||||
const workspaceCenter = workspace.getCenter()
|
||||
const editor = new TextEditor()
|
||||
@@ -1375,7 +1389,7 @@ describe('Workspace', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a dock has focus', function () {
|
||||
describe('when a dock has focus', () => {
|
||||
it('returns the text editor', () => {
|
||||
const workspaceCenter = workspace.getCenter()
|
||||
const editor = new TextEditor()
|
||||
@@ -1536,11 +1550,10 @@ describe('Workspace', () => {
|
||||
|
||||
waitsForPromise(() => atom.workspace.open('sample.coffee'))
|
||||
|
||||
runs(function () {
|
||||
atom.workspace.getActiveTextEditor().setText(`\
|
||||
i = /test/; #FIXME\
|
||||
`
|
||||
)
|
||||
runs(() => {
|
||||
atom.workspace.getActiveTextEditor().setText(dedent `
|
||||
i = /test/; #FIXME\
|
||||
`)
|
||||
|
||||
const atom2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate})
|
||||
atom2.initialize({
|
||||
@@ -2867,4 +2880,6 @@ i = /test/; #FIXME\
|
||||
})
|
||||
})
|
||||
|
||||
const escapeStringRegex = str => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
|
||||
function escapeStringRegex (string) {
|
||||
return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class TextEditorComponent {
|
||||
this.props = props
|
||||
|
||||
if (!props.model) {
|
||||
props.model = new TextEditor({mini: props.mini})
|
||||
props.model = new TextEditor({mini: props.mini, readOnly: props.readOnly})
|
||||
}
|
||||
this.props.model.component = this
|
||||
|
||||
@@ -460,9 +460,13 @@ class TextEditorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
let attributes = null
|
||||
let attributes = {}
|
||||
if (model.isMini()) {
|
||||
attributes = {mini: ''}
|
||||
attributes.mini = ''
|
||||
}
|
||||
|
||||
if (!this.isInputEnabled()) {
|
||||
attributes.readonly = ''
|
||||
}
|
||||
|
||||
const dataset = {encoding: model.getEncoding()}
|
||||
@@ -819,7 +823,7 @@ class TextEditorComponent {
|
||||
|
||||
const oldClassList = this.classList
|
||||
const newClassList = ['editor']
|
||||
if (this.focused) newClassList.push('is-focused')
|
||||
if (this.focused && this.isInputEnabled()) newClassList.push('is-focused')
|
||||
if (model.isMini()) newClassList.push('mini')
|
||||
for (var i = 0; i < model.selections.length; i++) {
|
||||
if (!model.selections[i].isEmpty()) {
|
||||
@@ -2962,11 +2966,11 @@ class TextEditorComponent {
|
||||
}
|
||||
|
||||
setInputEnabled (inputEnabled) {
|
||||
this.props.inputEnabled = inputEnabled
|
||||
this.props.model.update({readOnly: !inputEnabled})
|
||||
}
|
||||
|
||||
isInputEnabled (inputEnabled) {
|
||||
return this.props.inputEnabled != null ? this.props.inputEnabled : true
|
||||
return !this.props.model.isReadOnly()
|
||||
}
|
||||
|
||||
getHiddenInput () {
|
||||
|
||||
@@ -59,6 +59,9 @@ class TextEditorElement extends HTMLElement {
|
||||
case 'gutter-hidden':
|
||||
this.getModel().update({lineNumberGutterVisible: newValue == null})
|
||||
break
|
||||
case 'readonly':
|
||||
this.getModel().update({readOnly: newValue != null})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,7 +278,8 @@ class TextEditorElement extends HTMLElement {
|
||||
this.component = new TextEditorComponent({
|
||||
element: this,
|
||||
mini: this.hasAttribute('mini'),
|
||||
updatedSynchronously: this.updatedSynchronously
|
||||
updatedSynchronously: this.updatedSynchronously,
|
||||
readOnly: this.hasAttribute('readonly')
|
||||
})
|
||||
this.updateModelFromAttributes()
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ class TextEditor {
|
||||
this.decorationManager = params.decorationManager
|
||||
this.selectionsMarkerLayer = params.selectionsMarkerLayer
|
||||
this.mini = (params.mini != null) ? params.mini : false
|
||||
this.readOnly = (params.readOnly != null) ? params.readOnly : false
|
||||
this.placeholderText = params.placeholderText
|
||||
this.showLineNumbers = params.showLineNumbers
|
||||
this.assert = params.assert || (condition => condition)
|
||||
@@ -400,6 +401,16 @@ class TextEditor {
|
||||
}
|
||||
break
|
||||
|
||||
case 'readOnly':
|
||||
if (value !== this.readOnly) {
|
||||
this.readOnly = value
|
||||
if (this.component != null) {
|
||||
this.component.scheduleUpdate()
|
||||
}
|
||||
this.buffer.emitModifiedStatusChanged(this.isModified())
|
||||
}
|
||||
break
|
||||
|
||||
case 'placeholderText':
|
||||
if (value !== this.placeholderText) {
|
||||
this.placeholderText = value
|
||||
@@ -530,6 +541,7 @@ class TextEditor {
|
||||
softWrapAtPreferredLineLength: this.softWrapAtPreferredLineLength,
|
||||
preferredLineLength: this.preferredLineLength,
|
||||
mini: this.mini,
|
||||
readOnly: this.readOnly,
|
||||
editorWidthInChars: this.editorWidthInChars,
|
||||
width: this.width,
|
||||
maxScreenLineLength: this.maxScreenLineLength,
|
||||
@@ -556,6 +568,11 @@ class TextEditor {
|
||||
this.disposables.add(this.buffer.onDidChangeModified(() => {
|
||||
if (!this.hasTerminatedPendingState && this.buffer.isModified()) this.terminatePendingState()
|
||||
}))
|
||||
this.disposables.add(this.buffer.onDidSave(() => {
|
||||
if (this.isReadOnly()) {
|
||||
this.setReadOnly(false)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
terminatePendingState () {
|
||||
@@ -965,6 +982,12 @@ class TextEditor {
|
||||
|
||||
isMini () { return this.mini }
|
||||
|
||||
setReadOnly (readOnly) {
|
||||
this.update({readOnly})
|
||||
}
|
||||
|
||||
isReadOnly () { return this.readOnly }
|
||||
|
||||
onDidChangeMini (callback) {
|
||||
return this.emitter.on('did-change-mini', callback)
|
||||
}
|
||||
@@ -1106,7 +1129,7 @@ class TextEditor {
|
||||
setEncoding (encoding) { this.buffer.setEncoding(encoding) }
|
||||
|
||||
// Essential: Returns {Boolean} `true` if this editor has been modified.
|
||||
isModified () { return this.buffer.isModified() }
|
||||
isModified () { return this.isReadOnly() ? false : this.buffer.isModified() }
|
||||
|
||||
// Essential: Returns {Boolean} `true` if this editor has no content.
|
||||
isEmpty () { return this.buffer.isEmpty() }
|
||||
@@ -4552,8 +4575,7 @@ class TextEditor {
|
||||
? minBlankIndentLevel
|
||||
: 0
|
||||
|
||||
const tabLength = this.getTabLength()
|
||||
const indentString = ' '.repeat(tabLength * minIndentLevel)
|
||||
const indentString = this.buildIndentString(minIndentLevel)
|
||||
for (let row = start; row <= end; row++) {
|
||||
const line = this.buffer.lineForRow(row)
|
||||
if (NON_WHITESPACE_REGEXP.test(line)) {
|
||||
|
||||
@@ -497,6 +497,9 @@ module.exports = class Workspace extends Model {
|
||||
this.textEditorRegistry.maintainConfig(item),
|
||||
item.observeGrammar(this.handleGrammarUsed.bind(this))
|
||||
)
|
||||
if (!this.project.findBufferForId(item.buffer.id)) {
|
||||
this.project.addBuffer(item.buffer)
|
||||
}
|
||||
item.onDidDestroy(() => { subscriptions.dispose() })
|
||||
this.emitter.emit('did-add-text-editor', {textEditor: item, pane, index})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user