From 9f3b49d10aec509e48a3ae131b0e8d44113323b2 Mon Sep 17 00:00:00 2001 From: Philipp Emanuel Weidmann Date: Sun, 23 Jul 2017 12:55:25 +0000 Subject: [PATCH 01/90] Replace font stack with "system-ui" generic font family --- static/variables/ui-variables.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/variables/ui-variables.less b/static/variables/ui-variables.less index 8ef4d48e7..7bea17e72 100644 --- a/static/variables/ui-variables.less +++ b/static/variables/ui-variables.less @@ -81,5 +81,5 @@ // Other -@font-family: 'BlinkMacSystemFont', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif; +@font-family: system-ui; @use-custom-controls: true; // false uses native controls From 5a1459cf0a1abe02f20fab1a2d6864f5a13320b7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 5 Oct 2017 15:01:46 -0600 Subject: [PATCH 02/90] Clear the dimensions cache after updating the soft wrap column Updating the soft wrap column could cause us to compute different values for derived dimensions, so any dimensions that were cached *in the process* of updating the soft wrap column need to be cleared. --- src/text-editor-component.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 5667a733e..8dda2297d 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -2118,6 +2118,7 @@ class TextEditorComponent { // rendered start row accurately. 😥 this.populateVisibleRowRange(renderedStartRow) this.props.model.setEditorWidthInChars(this.getScrollContainerClientWidthInBaseCharacters()) + this.derivedDimensionsCache = {} this.suppressUpdates = false } From 43fcdf84a10fcc9544e4aefe10345057ec7c6660 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Fri, 6 Oct 2017 00:58:46 +0200 Subject: [PATCH 03/90] WIP --- spec/text-editor-component-spec.js | 42 ++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 029cfee19..475a68f7d 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -6,7 +6,7 @@ const TextEditorComponent = require('../src/text-editor-component') const TextEditorElement = require('../src/text-editor-element') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') -const {Point} = TextBuffer +const {Point, Range} = TextBuffer const fs = require('fs') const path = require('path') const Grim = require('grim') @@ -908,11 +908,42 @@ describe('TextEditorComponent', () => { jasmine.getEnv().defaultTimeoutInterval = originalTimeout }) - it('renders the visible rows correctly after randomly mutating the editor', async () => { + it('failing test', async () => { + const rowsPerTile = 1 + const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) + + await setEditorHeightInLines(component, 1) + await setEditorWidthInCharacters(component, 7) + + element.focus() + component.setScrollTop(component.measurements.lineHeight) + + component.scheduleUpdate() + await component.getNextUpdatePromise() + + editor.setSelectedBufferRange(new Range(Point(0,1),Point(12,2))) + editor.backspace() + + component.scheduleUpdate() + await component.getNextUpdatePromise() + + const renderedLines = queryOnScreenLineElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedLineNumbers = queryOnScreenLineNumberElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedStartRow = component.getRenderedStartRow() + const expectedLines = editor.displayLayer.getScreenLines(renderedStartRow, component.getRenderedEndRow()) + + expect(renderedLines.length).toBe(expectedLines.length) + expect(renderedLineNumbers.length).toBe(expectedLines.length) + + element.remove() + editor.destroy() + }) + + xit('renders the visible rows correctly after randomly mutating the editor', async () => { const initialSeed = Date.now() - for (var i = 0; i < 20; i++) { + for (var i = 0; i < 1; i++) { let seed = initialSeed + i - // seed = 1507224195357 + seed = 1507231571985 const failureMessage = 'Randomized test failed with seed: ' + seed const random = Random(seed) @@ -921,9 +952,10 @@ describe('TextEditorComponent', () => { editor.setSoftWrapped(Boolean(random(2))) await setEditorWidthInCharacters(component, random(20)) await setEditorHeightInLines(component, random(10)) + element.focus() - for (var j = 0; j < 5; j++) { + for (var j = 0; j < 10; j++) { const k = random(100) const range = getRandomBufferRange(random, editor.buffer) From c1c9d3f75f184313100fd9434fd8dbd2449c0034 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Thu, 19 Oct 2017 21:39:59 +0200 Subject: [PATCH 04/90] Handle edits that scroll up due to hiding the horizontal scrollbar --- spec/text-editor-component-spec.js | 66 +++++++++++++++--------------- src/text-editor-component.js | 19 ++++++--- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 475a68f7d..a4dc7412d 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -896,6 +896,39 @@ describe('TextEditorComponent', () => { expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) }) + it('gracefully handles edits that change the maxScrollTop by causing the horizontal scrollbar to disappear', async () => { + const rowsPerTile = 1 + const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) + + await setEditorHeightInLines(component, 1) + await setEditorWidthInCharacters(component, 7) + + element.focus() + component.setScrollTop(component.measurements.lineHeight) + + component.scheduleUpdate() + await component.getNextUpdatePromise() + + editor.setSelectedBufferRange(new Range(Point(0,1),Point(12,2))) + editor.backspace() + + // component.scheduleUpdate() + await component.getNextUpdatePromise() + + expect(component.getScrollTop()).toBe(0) + + const renderedLines = queryOnScreenLineElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedLineNumbers = queryOnScreenLineNumberElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedStartRow = component.getRenderedStartRow() + const expectedLines = editor.displayLayer.getScreenLines(renderedStartRow, component.getRenderedEndRow()) + + expect(renderedLines.length).toBe(expectedLines.length) + expect(renderedLineNumbers.length).toBe(expectedLines.length) + + element.remove() + editor.destroy() + }) + describe('randomized tests', () => { let originalTimeout @@ -908,38 +941,7 @@ describe('TextEditorComponent', () => { jasmine.getEnv().defaultTimeoutInterval = originalTimeout }) - it('failing test', async () => { - const rowsPerTile = 1 - const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) - - await setEditorHeightInLines(component, 1) - await setEditorWidthInCharacters(component, 7) - - element.focus() - component.setScrollTop(component.measurements.lineHeight) - - component.scheduleUpdate() - await component.getNextUpdatePromise() - - editor.setSelectedBufferRange(new Range(Point(0,1),Point(12,2))) - editor.backspace() - - component.scheduleUpdate() - await component.getNextUpdatePromise() - - const renderedLines = queryOnScreenLineElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) - const renderedLineNumbers = queryOnScreenLineNumberElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) - const renderedStartRow = component.getRenderedStartRow() - const expectedLines = editor.displayLayer.getScreenLines(renderedStartRow, component.getRenderedEndRow()) - - expect(renderedLines.length).toBe(expectedLines.length) - expect(renderedLineNumbers.length).toBe(expectedLines.length) - - element.remove() - editor.destroy() - }) - - xit('renders the visible rows correctly after randomly mutating the editor', async () => { + it('renders the visible rows correctly after randomly mutating the editor', async () => { const initialSeed = Date.now() for (var i = 0; i < 1; i++) { let seed = initialSeed + i diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 8dda2297d..a6505d760 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -266,9 +266,13 @@ class TextEditorComponent { if (useScheduler === true) { const scheduler = etch.getScheduler() scheduler.readDocument(() => { - this.measureContentDuringUpdateSync() + const restartFrame = this.measureContentDuringUpdateSync() scheduler.updateDocument(() => { - this.updateSyncAfterMeasuringContent() + if (restartFrame) { + this.updateSync(true) + } else { + this.updateSyncAfterMeasuringContent() + } }) }) } else { @@ -391,15 +395,16 @@ class TextEditorComponent { this.measureHorizontalPositions() this.updateAbsolutePositionedDecorations() + const isHorizontalScrollbarVisible = ( + this.canScrollHorizontally() && + this.getHorizontalScrollbarHeight() > 0 + ) + if (this.pendingAutoscroll) { this.derivedDimensionsCache = {} const {screenRange, options} = this.pendingAutoscroll this.autoscrollHorizontally(screenRange, options) - const isHorizontalScrollbarVisible = ( - this.canScrollHorizontally() && - this.getHorizontalScrollbarHeight() > 0 - ) if (!wasHorizontalScrollbarVisible && isHorizontalScrollbarVisible) { this.autoscrollVertically(screenRange, options) } @@ -408,6 +413,8 @@ class TextEditorComponent { this.linesToMeasure.clear() this.measuredContent = true + + return wasHorizontalScrollbarVisible !== isHorizontalScrollbarVisible } updateSyncAfterMeasuringContent () { From 612feb7cea2697501fa8b8769dd05dd29f5fcde6 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Thu, 19 Oct 2017 21:46:09 +0200 Subject: [PATCH 05/90] Fix the randomized test --- spec/text-editor-component-spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index a4dc7412d..0bf1c849a 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -943,9 +943,9 @@ describe('TextEditorComponent', () => { it('renders the visible rows correctly after randomly mutating the editor', async () => { const initialSeed = Date.now() - for (var i = 0; i < 1; i++) { + for (var i = 0; i < 20; i++) { let seed = initialSeed + i - seed = 1507231571985 + // seed = 1507231571985 const failureMessage = 'Randomized test failed with seed: ' + seed const random = Random(seed) @@ -957,7 +957,7 @@ describe('TextEditorComponent', () => { element.focus() - for (var j = 0; j < 10; j++) { + for (var j = 0; j < 5; j++) { const k = random(100) const range = getRandomBufferRange(random, editor.buffer) From 04507e9ee2a4e4aa5573dcae39e454b1b2179e35 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Fri, 19 Jan 2018 19:09:54 +0100 Subject: [PATCH 06/90] Use nested arrays instead of Range --- spec/text-editor-component-spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index d7489348a..62d00056e 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -6,7 +6,7 @@ const TextEditorComponent = require('../src/text-editor-component') const TextEditorElement = require('../src/text-editor-element') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') -const {Point, Range} = TextBuffer +const {Point} = TextBuffer const fs = require('fs') const path = require('path') const Grim = require('grim') @@ -918,7 +918,7 @@ describe('TextEditorComponent', () => { component.scheduleUpdate() await component.getNextUpdatePromise() - editor.setSelectedBufferRange(new Range(Point(0,1),Point(12,2))) + editor.setSelectedBufferRange([[0, 1], [12, 2]]) editor.backspace() // component.scheduleUpdate() From b7138a041079fc85fa13b4c1218f0a7c197957dc Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Fri, 19 Jan 2018 19:11:16 +0100 Subject: [PATCH 07/90] Add these changes to the non scheduled code path --- src/text-editor-component.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 67323e66f..d1a9d9a50 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -276,8 +276,12 @@ class TextEditorComponent { }) }) } else { - this.measureContentDuringUpdateSync() - this.updateSyncAfterMeasuringContent() + const restartFrame = this.measureContentDuringUpdateSync() + if (restartFrame) { + this.updateSync(false) + } else { + this.updateSyncAfterMeasuringContent() + } } this.updateScheduled = false From 49e704291d2b299d1809e82c2a342f3237faf5ca Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 31 Jan 2018 09:24:15 -0700 Subject: [PATCH 08/90] Register for `core.titleBar` changes after the initial load of config This prevents the change handler for `core.titleBar` from being triggered every time a new instance of the main process is created. This fixes a regression that was causing users to be prompted for a restart every time they opened Atom. Co-authored-by: Max Brunsfeld Co-authored-by: Nathan Sobo --- src/main-process/atom-application.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index c57b43305..c2d40e92b 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -146,8 +146,6 @@ class AtomApplication extends EventEmitter { this.config.set('core.titleBar', 'custom') } - this.config.onDidChange('core.titleBar', this.promptForRestart.bind(this)) - process.nextTick(() => this.autoUpdateManager.initialize()) this.applicationMenu = new ApplicationMenu(this.version, this.autoUpdateManager) this.atomProtocolHandler = new AtomProtocolHandler(this.resourcePath, this.safeMode) @@ -171,6 +169,7 @@ class AtomApplication extends EventEmitter { if (!this.configFilePromise) { this.configFilePromise = this.configFile.watch() this.disposable.add(await this.configFilePromise) + this.config.onDidChange('core.titleBar', this.promptForRestart.bind(this)) } const optionsForWindowsToOpen = [] From 7a60c9920c2364b225788979a6e730898848af6b Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Fri, 26 Jan 2018 11:44:01 -0800 Subject: [PATCH 09/90] Allow packages to control the order of context menu items --- spec/context-menu-manager-spec.coffee | 43 +++++ spec/menu-sort-helpers-spec.js | 227 ++++++++++++++++++++++++++ src/context-menu-manager.coffee | 10 +- src/menu-helpers.js | 6 +- src/menu-sort-helpers.js | 192 ++++++++++++++++++++++ 5 files changed, 476 insertions(+), 2 deletions(-) create mode 100644 spec/menu-sort-helpers-spec.js create mode 100644 src/menu-sort-helpers.js diff --git a/spec/context-menu-manager-spec.coffee b/spec/context-menu-manager-spec.coffee index 035d56a61..70ab4b3e7 100644 --- a/spec/context-menu-manager-spec.coffee +++ b/spec/context-menu-manager-spec.coffee @@ -333,3 +333,46 @@ describe "ContextMenuManager", -> } ] ]) + + describe "::templateForEvent(target) (sorting)", -> + it "applies simple sorting rules", -> + contextMenu.add('.parent': [{ + label: 'My Command', + command: "test:my-command", + after: ["test:my-other-command"] + }, { + label: 'My Other Command', + command: "test:my-other-command", + }]) + dispatchedEvent = {target: parent} + expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([{ + label: 'My Other Command', + command: 'test:my-other-command', + }, { + label: 'My Command', + command: 'test:my-command', + after: ["test:my-other-command"] + }]) + + it "applies sorting rules recursively to submenus", -> + contextMenu.add('.parent': [{ + submenu: [{ + label: 'My Command', + command: "test:my-command", + after: ["test:my-other-command"] + }, { + label: 'My Other Command', + command: "test:my-other-command", + }] + }]) + dispatchedEvent = {target: parent} + expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual([{ + submenu: [{ + label: 'My Other Command', + command: 'test:my-other-command', + }, { + label: 'My Command', + command: 'test:my-command', + after: ["test:my-other-command"] + }] + }]) diff --git a/spec/menu-sort-helpers-spec.js b/spec/menu-sort-helpers-spec.js new file mode 100644 index 000000000..e3daf1d4a --- /dev/null +++ b/spec/menu-sort-helpers-spec.js @@ -0,0 +1,227 @@ +const {sortMenuItems} = require('../src/menu-sort-helpers') + +describe('contextMenu', () => { + describe('dedupes separators', () => { + it('preserves existing submenus', () => { + const items = [{ submenu: [] }] + expect(sortMenuItems(items)).toEqual(items) + }) + }) + describe('dedupes separators', () => { + it('trims leading separators', () => { + const items = [{ type: 'separator' }, { command: 'core:one' }] + const expected = [{ command: 'core:one' }] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('preserves separators at the begining of set two', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, { command: 'core:two' } + ] + const expected = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('trims trailing separators', () => { + const items = [{ command: 'core:one' }, { type: 'separator' }] + const expected = [{ command: 'core:one' }] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('removes duplicate separators across sets', () => { + const items = [ + { command: 'core:one' }, { type: 'separator' }, + { type: 'separator' }, { command: 'core:two' } + ] + const expected = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + }) + describe('can move an item to a different group by merging groups', () => { + it('can move a group of one item', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' }, + { type: 'separator' }, + { command: 'core:three', after: ['core:one'] }, + { type: 'separator' } + ] + const expected = [ + { command: 'core:one' }, + { command: 'core:three', after: ['core:one'] }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it("moves all items in the moving item's group", () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' }, + { type: 'separator' }, + { command: 'core:three', after: ['core:one'] }, + { command: 'core:four' }, + { type: 'separator' } + ] + const expected = [ + { command: 'core:one' }, + { command: 'core:three', after: ['core:one'] }, + { command: 'core:four' }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it("ignores positions relative to commands that don't exist", () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' }, + { type: 'separator' }, + { command: 'core:three', after: ['core:does-not-exist'] }, + { command: 'core:four', after: ['core:one'] }, + { type: 'separator' } + ] + const expected = [ + { command: 'core:one' }, + { command: 'core:three', after: ['core:does-not-exist'] }, + { command: 'core:four', after: ['core:one'] }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('can handle recursive group merging', () => { + const items = [ + { command: 'core:one', after: ['core:three'] }, + { command: 'core:two', before: ['core:one'] }, + { command: 'core:three' } + ] + const expected = [ + { command: 'core:three' }, + { command: 'core:two', before: ['core:one'] }, + { command: 'core:one', after: ['core:three'] } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('can merge multiple groups when given a list of before/after commands', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' }, + { type: 'separator' }, + { command: 'core:three', after: ['core:one', 'core:two'] } + ] + const expected = [ + { command: 'core:two' }, + { command: 'core:one' }, + { command: 'core:three', after: ['core:one', 'core:two'] } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + it('can merge multiple groups based on both before/after commands', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' }, + { type: 'separator' }, + { command: 'core:three', after: ['core:one'], before: ['core:two'] } + ] + const expected = [ + { command: 'core:one' }, + { command: 'core:three', after: ['core:one'], before: ['core:two'] }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual(expected) + }) + }) + describe('sorts items within their ultimate group', () => { + it('does a simple sort', () => { + const items = [ + { command: 'core:two', after: ['core:one'] }, + { command: 'core:one' } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:one' }, + { command: 'core:two', after: ['core:one'] } + ]) + }) + it('resolves cycles by ignoring things that conflict', () => { + const items = [ + { command: 'core:two', after: ['core:one'] }, + { command: 'core:one', after: ['core:two'] } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:one', after: ['core:two'] }, + { command: 'core:two', after: ['core:one'] } + ]) + }) + }) + describe('sorts groups', () => { + it('does a simple sort', () => { + const items = [ + { command: 'core:two', afterGroupContaining: ['core:one'] }, + { type: 'separator' }, + { command: 'core:one' } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two', afterGroupContaining: ['core:one'] } + ]) + }) + it('resolves cycles by ignoring things that conflict', () => { + const items = [ + { command: 'core:two', afterGroupContaining: ['core:one'] }, + { type: 'separator' }, + { command: 'core:one', afterGroupContaining: ['core:two'] } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:one', afterGroupContaining: ['core:two'] }, + { type: 'separator' }, + { command: 'core:two', afterGroupContaining: ['core:one'] } + ]) + }) + it('ignores references to commands that do not exist', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { + command: 'core:two', + afterGroupContaining: ['core:does-not-exist'] + } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two', afterGroupContaining: ['core:does-not-exist'] } + ]) + }) + it('only respects the first matching [before|after]GroupContaining rule in a given group', () => { + const items = [ + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:three', beforeGroupContaining: ['core:one'] }, + { command: 'core:four', afterGroupContaining: ['core:two'] }, + { type: 'separator' }, + { command: 'core:two' } + ] + expect(sortMenuItems(items)).toEqual([ + { command: 'core:three', beforeGroupContaining: ['core:one'] }, + { command: 'core:four', afterGroupContaining: ['core:two'] }, + { type: 'separator' }, + { command: 'core:one' }, + { type: 'separator' }, + { command: 'core:two' } + ]) + }) + }) +}) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 10a7a3bdb..9cff5497b 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -5,6 +5,7 @@ fs = require 'fs-plus' {Disposable} = require 'event-kit' {remote} = require 'electron' MenuHelpers = require './menu-helpers' +{sortMenuItems} = require './menu-sort-helpers' platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] @@ -149,7 +150,7 @@ class ContextMenuManager @pruneRedundantSeparators(template) @addAccelerators(template) - template + return @sortTemplate(template) # Adds an `accelerator` property to items that have key bindings. Electron # uses this property to surface the relevant keymaps in the context menu. @@ -175,6 +176,13 @@ class ContextMenuManager keepNextItemIfSeparator = true index++ + sortTemplate: (template) -> + template = sortMenuItems(template) + for id, item of template + if Array.isArray(item.submenu) + item.submenu = @sortTemplate(item.submenu) + return template + # Returns an object compatible with `::add()` or `null`. cloneItemForEvent: (item, event) -> return null if item.devMode and not @devMode diff --git a/src/menu-helpers.js b/src/menu-helpers.js index 398feb40e..12598764e 100644 --- a/src/menu-helpers.js +++ b/src/menu-helpers.js @@ -83,7 +83,11 @@ function cloneMenuItem (item) { 'submenu', 'commandDetail', 'role', - 'accelerator' + 'accelerator', + 'before', + 'after', + 'beforeGroupContaining', + 'afterGroupContaining' ) if (item.submenu != null) { item.submenu = item.submenu.map(submenuItem => cloneMenuItem(submenuItem)) diff --git a/src/menu-sort-helpers.js b/src/menu-sort-helpers.js new file mode 100644 index 000000000..b05bf4faf --- /dev/null +++ b/src/menu-sort-helpers.js @@ -0,0 +1,192 @@ +// UTILS + +function splitArray (arr, predicate) { + let lastArr = [] + const multiArr = [lastArr] + arr.forEach(item => { + if (predicate(item)) { + if (lastArr.length > 0) { + lastArr = [] + multiArr.push(lastArr) + } + } else { + lastArr.push(item) + } + }) + return multiArr +} + +function joinArrays (arrays, joiner) { + const joinedArr = [] + arrays.forEach((arr, i) => { + if (i > 0 && arr.length > 0) { + joinedArr.push(joiner) + } + joinedArr.push(...arr) + }) + return joinedArr +} + +const pushOntoMultiMap = (map, key, value) => { + if (!map.has(key)) { + map.set(key, []) + } + map.get(key).push(value) +} + +function indexOfGroupContainingCommand (groups, command, ignoreGroup) { + return groups.findIndex( + candiateGroup => + candiateGroup !== ignoreGroup && + candiateGroup.some( + candidateItem => candidateItem.command === command + ) + ) +} + +// Sort nodes topologically using a depth-first approach. Encountered cycles +// and broken. +function sortTopologically (originalOrder, edgesById) { + const sorted = [] + const marked = new Set() + + function visit (id) { + if (marked.has(id)) { + // Either this node has already been placed, or we have encountered a + // cycle and need to exit. + return + } + marked.add(id) + const edges = edgesById.get(id) + if (edges != null) { + edges.forEach(visit) + } + sorted.push(id) + } + + while (true) { + const unmarkedId = originalOrder.find(id => !marked.has(id)) + if (unmarkedId == null) { + break + } + visit(unmarkedId) + } + return sorted +} + +function attemptToMergeAGroup (groups) { + for (let i = 0; i < groups.length; i++) { + const group = groups[i] + for (const item of group) { + const toCommands = [...(item.before || []), ...(item.after || [])] + for (const command of toCommands) { + const index = indexOfGroupContainingCommand(groups, command, group) + if (index === -1) { + // No valid edge for this command + continue + } + const mergeTarget = groups[index] + // Merge with group containing `command` + mergeTarget.push(...group) + groups.splice(i, 1) + return true + } + } + } + return false +} + +// Merge groups based on before/after positions +// Mutates both the array of groups, and the individual group arrays. +function mergeGroups (groups) { + let mergedAGroup = true + while (mergedAGroup) { + mergedAGroup = attemptToMergeAGroup(groups) + } + return groups +} + +function sortItemsInGroup (group) { + const originalOrder = group.map((node, i) => i) + const edges = new Map() + const commandToIndex = new Map(group.map((item, i) => [item.command, i])) + + group.forEach((item, i) => { + if (item.before) { + item.before.forEach(toCommand => { + const to = commandToIndex.get(toCommand) + if (to != null) { + pushOntoMultiMap(edges, to, i) + } + }) + } + if (item.after) { + item.after.forEach(toCommand => { + const to = commandToIndex.get(toCommand) + if (to != null) { + pushOntoMultiMap(edges, i, to) + } + }) + } + }) + + const sortedNodes = sortTopologically(originalOrder, edges) + + return sortedNodes.map(i => group[i]) +} + +function findEdgesInGroup (groups, i, edges) { + const group = groups[i] + for (const item of group) { + if (item.beforeGroupContaining) { + for (const command of item.beforeGroupContaining) { + const to = indexOfGroupContainingCommand(groups, command, group) + if (to !== -1) { + pushOntoMultiMap(edges, to, i) + return + } + } + } + if (item.afterGroupContaining) { + for (const command of item.afterGroupContaining) { + const to = indexOfGroupContainingCommand(groups, command, group) + if (to !== -1) { + pushOntoMultiMap(edges, i, to) + return + } + } + } + } +} + +function sortGroups (groups) { + const originalOrder = groups.map((item, i) => i) + const edges = new Map() + + for (let i = 0; i < groups.length; i++) { + findEdgesInGroup(groups, i, edges) + } + + const sortedGroupIndexes = sortTopologically(originalOrder, edges) + return sortedGroupIndexes.map(i => groups[i]) +} + +function isSeparator (item) { + return item.type === 'separator' +} + +function sortMenuItems (menuItems) { + // Split the items into their implicit groups based upon separators. + const groups = splitArray(menuItems, isSeparator) + // Merge groups that contain before/after references to eachother. + const mergedGroups = mergeGroups(groups) + // Sort each individual group internally. + const mergedGroupsWithSortedItems = mergedGroups.map(sortItemsInGroup) + // Sort the groups based upon their beforeGroupContaining/afterGroupContaining + // references. + const sortedGroups = sortGroups(mergedGroupsWithSortedItems) + // Join the groups back + return joinArrays(sortedGroups, { type: 'separator' }) +} + +module.exports = {sortMenuItems} From a3108623de406e6f162c37b2dffd0872ab39e276 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Thu, 1 Feb 2018 11:38:22 -0800 Subject: [PATCH 10/90] :arrow_up: language-csharp --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 990d20f7d..d6a192ba7 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "language-c": "0.59.1", "language-clojure": "0.22.7", "language-coffee-script": "0.49.3", - "language-csharp": "0.14.4", + "language-csharp": "1.0.1", "language-css": "0.42.10", "language-gfm": "0.90.3", "language-git": "0.19.1", From fe16e5131cd1c6046c4ea055412ae4e8947cc931 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 4 Feb 2018 23:20:28 -0500 Subject: [PATCH 11/90] :arrow_up: language-php@0.43.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6a192ba7..b416a568f 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-mustache": "0.14.4", "language-objective-c": "0.15.1", "language-perl": "0.38.1", - "language-php": "0.43.0", + "language-php": "0.43.1", "language-property-list": "0.9.1", "language-python": "0.48.0", "language-ruby": "0.71.4", From 8f78b8f4b4ad5566c4b92b90ec4d7c1f21502b6c Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 4 Feb 2018 23:21:28 -0500 Subject: [PATCH 12/90] :arrow_up: language-python@0.49.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b416a568f..b3d3062a8 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "language-perl": "0.38.1", "language-php": "0.43.1", "language-property-list": "0.9.1", - "language-python": "0.48.0", + "language-python": "0.49.0", "language-ruby": "0.71.4", "language-ruby-on-rails": "0.25.3", "language-sass": "0.61.4", From 9114cd3dca3a52af300694aef5a1a1d0871455e6 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 4 Feb 2018 23:22:05 -0500 Subject: [PATCH 13/90] :arrow_up: language-yaml@0.31.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b3d3062a8..7697dd35d 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "language-toml": "0.18.2", "language-typescript": "0.3.0", "language-xml": "0.35.2", - "language-yaml": "0.31.1" + "language-yaml": "0.31.2" }, "private": true, "scripts": { From ee73183dc953fe736a59b981d66c2babc08f3d69 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 5 Feb 2018 11:04:34 -0800 Subject: [PATCH 14/90] Fix comment typo --- src/menu-sort-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu-sort-helpers.js b/src/menu-sort-helpers.js index b05bf4faf..a56e2edf0 100644 --- a/src/menu-sort-helpers.js +++ b/src/menu-sort-helpers.js @@ -45,7 +45,7 @@ function indexOfGroupContainingCommand (groups, command, ignoreGroup) { } // Sort nodes topologically using a depth-first approach. Encountered cycles -// and broken. +// are broken. function sortTopologically (originalOrder, edgesById) { const sorted = [] const marked = new Set() From a1d96714401aaeae2bf4a5244cad2ef57fed7d29 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 5 Feb 2018 11:34:49 -0800 Subject: [PATCH 15/90] Fix accidental quadratic --- src/menu-sort-helpers.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/menu-sort-helpers.js b/src/menu-sort-helpers.js index a56e2edf0..259f8321e 100644 --- a/src/menu-sort-helpers.js +++ b/src/menu-sort-helpers.js @@ -64,13 +64,7 @@ function sortTopologically (originalOrder, edgesById) { sorted.push(id) } - while (true) { - const unmarkedId = originalOrder.find(id => !marked.has(id)) - if (unmarkedId == null) { - break - } - visit(unmarkedId) - } + originalOrder.forEach(visit) return sorted } From 555dae4eaef843a6bfba17e30180ac059e139310 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 5 Feb 2018 19:36:59 -0500 Subject: [PATCH 16/90] :arrow_up: language-mustache@0.14.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7697dd35d..57b1cbd73 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "language-json": "0.19.1", "language-less": "0.34.2", "language-make": "0.22.3", - "language-mustache": "0.14.4", + "language-mustache": "0.14.5", "language-objective-c": "0.15.1", "language-perl": "0.38.1", "language-php": "0.43.1", From 6fc0037077cecfc3c2f8ea72cbb9c6531daf110a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 6 Feb 2018 08:01:28 +0100 Subject: [PATCH 17/90] :arrow_up: exception-reporting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 57b1cbd73..288cc235a 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "deprecation-cop": "0.56.9", "dev-live-reload": "0.48.1", "encoding-selector": "0.23.8", - "exception-reporting": "0.42.0", + "exception-reporting": "0.43.0", "find-and-replace": "0.215.5", "fuzzy-finder": "1.7.5", "github": "0.9.1", From c7f97ad3ad4aee1f0f7f50506c14493eef4dc65e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 6 Feb 2018 10:52:11 +0100 Subject: [PATCH 18/90] :arrow_up: exception-reporting This fixes the failing tests at https://circleci.com/gh/atom/atom/6792, see atom/exception-reporting@5cc4161 for more details. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 288cc235a..ddfdb0cd7 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "deprecation-cop": "0.56.9", "dev-live-reload": "0.48.1", "encoding-selector": "0.23.8", - "exception-reporting": "0.43.0", + "exception-reporting": "0.43.1", "find-and-replace": "0.215.5", "fuzzy-finder": "1.7.5", "github": "0.9.1", From 6296e64e252b4d84c25cb68cf9b248ee63987e90 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 7 Feb 2018 08:36:34 -0500 Subject: [PATCH 19/90] :arrow_up: github --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ddfdb0cd7..74077cdfe 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "exception-reporting": "0.43.1", "find-and-replace": "0.215.5", "fuzzy-finder": "1.7.5", - "github": "0.9.1", + "github": "0.10.0", "git-diff": "1.3.9", "go-to-line": "0.33.0", "grammar-selector": "0.49.9", From 47f17de5f3dd96baa0b025eb26e746dca4305239 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 7 Feb 2018 09:32:18 -0500 Subject: [PATCH 20/90] :arrow_up: github like I mean it this time --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74077cdfe..69629acb4 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "exception-reporting": "0.43.1", "find-and-replace": "0.215.5", "fuzzy-finder": "1.7.5", - "github": "0.10.0", + "github": "0.10.1", "git-diff": "1.3.9", "go-to-line": "0.33.0", "grammar-selector": "0.49.9", From 95e6b3cb475e35ff532127238f23512f8eb52125 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 7 Feb 2018 13:56:32 -0800 Subject: [PATCH 21/90] :arrow_up: command-palette --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 69629acb4..2ad01dbcb 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "background-tips": "0.27.1", "bookmarks": "0.45.1", "bracket-matcher": "0.89.1", - "command-palette": "0.43.0", + "command-palette": "0.43.3", "dalek": "0.2.1", "deprecation-cop": "0.56.9", "dev-live-reload": "0.48.1", From 2f23f7cd945cf6475873200fe909c14c87ec3bc2 Mon Sep 17 00:00:00 2001 From: Hubot Date: Wed, 7 Feb 2018 15:48:54 -0800 Subject: [PATCH 22/90] 1.26.0-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ad01dbcb..19699901c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.25.0-dev", + "version": "1.26.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/main-process/main.js", "repository": { From ef50a52405dafbfb96988102633133096c3e2d2f Mon Sep 17 00:00:00 2001 From: Philip Weiss Date: Thu, 8 Feb 2018 10:33:47 -0800 Subject: [PATCH 23/90] add configurable: true to browserwindow.loadSettingsJSON --- src/main-process/atom-window.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js index 8d700e379..d5d8b867a 100644 --- a/src/main-process/atom-window.js +++ b/src/main-process/atom-window.js @@ -57,8 +57,9 @@ class AtomWindow extends EventEmitter { Object.defineProperty(this.browserWindow, 'loadSettingsJSON', { get: () => JSON.stringify(Object.assign({ - userSettings: this.atomApplication.configFile.get() - }, this.loadSettings)) + userSettings: this.atomApplication.configFile.get(), + }, this.loadSettings)), + configurable: true }) this.handleEvents() From c3309ee9b9f52aa9a4d9fdad67dda81fc9bfe0bd Mon Sep 17 00:00:00 2001 From: Philip Weiss Date: Thu, 8 Feb 2018 12:55:20 -0800 Subject: [PATCH 24/90] remove trailing comma --- src/main-process/atom-window.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js index d5d8b867a..11a2d8f35 100644 --- a/src/main-process/atom-window.js +++ b/src/main-process/atom-window.js @@ -57,7 +57,7 @@ class AtomWindow extends EventEmitter { Object.defineProperty(this.browserWindow, 'loadSettingsJSON', { get: () => JSON.stringify(Object.assign({ - userSettings: this.atomApplication.configFile.get(), + userSettings: this.atomApplication.configFile.get() }, this.loadSettings)), configurable: true }) From c343670e2b7f81869726653a5f904624dc5a2579 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 10 Feb 2018 23:47:01 -0500 Subject: [PATCH 25/90] :arrow_up: archive-view@0.64.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19699901c..dedfdc2c2 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "solarized-dark-syntax": "1.1.4", "solarized-light-syntax": "1.1.4", "about": "1.8.0", - "archive-view": "0.64.2", + "archive-view": "0.64.3", "autocomplete-atom-api": "0.10.7", "autocomplete-css": "0.17.5", "autocomplete-html": "0.8.4", From 50de9345bc952f1ca7ae149bf0f50dbb18a4989d Mon Sep 17 00:00:00 2001 From: Ian Olsen Date: Sun, 11 Feb 2018 18:10:38 -0800 Subject: [PATCH 26/90] Create weekly focus doc for 2018-02-12 --- docs/focus/2018-02-12.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/focus/2018-02-12.md diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md new file mode 100644 index 000000000..5b9fbc13f --- /dev/null +++ b/docs/focus/2018-02-12.md @@ -0,0 +1,13 @@ +## Highlights from the past week + +- Atom IDE +- GitHub Package +- Teletype + +## Focus for week ahead + +- Atom IDE +- GitHub Package +- Teletype +- Treesitter +- Xray From d9993b2dda2a58c912b0af5ccf026cb5a81d29f1 Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 12 Feb 2018 08:26:37 -0500 Subject: [PATCH 27/90] Add Teletype highlights for the past week and focus for the week ahead --- docs/focus/2018-02-12.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 5b9fbc13f..ceef31033 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -3,11 +3,15 @@ - Atom IDE - GitHub Package - Teletype + - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization (https://github.com/atom/teletype/issues/266, https://github.com/atom/teletype/issues/297) + - Opened atom/teletype#323, atom/teletype-client#52, and atom/fuzzy-finder#335 to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host (https://github.com/atom/teletype/issues/268) ## Focus for week ahead - Atom IDE - GitHub Package - Teletype + - Complete initial implementation and merge pull requests (atom/teletype#323, atom/teletype-client#52, and atom/fuzzy-finder#335) allowing guests to use the fuzzy-finder to open any remote editor shared by the host (https://github.com/atom/teletype/issues/268) + - Use fuzzy-finder support internally in our day-to-day workflows to assess usability - Treesitter - Xray From 14e62e54bbd3ed81b4ac8e7187ba7bb262c7b6cb Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 12 Feb 2018 08:30:14 -0500 Subject: [PATCH 28/90] Improve issue links --- docs/focus/2018-02-12.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index ceef31033..278b52acd 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -3,15 +3,15 @@ - Atom IDE - GitHub Package - Teletype - - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization (https://github.com/atom/teletype/issues/266, https://github.com/atom/teletype/issues/297) - - Opened atom/teletype#323, atom/teletype-client#52, and atom/fuzzy-finder#335 to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host (https://github.com/atom/teletype/issues/268) + - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization ([atom/teletype#266](https://github.com/atom/teletype/issues/266), [atom/teletype#297](https://github.com/atom/teletype/issues/297)) + - Opened [atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335) to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268) ## Focus for week ahead - Atom IDE - GitHub Package - Teletype - - Complete initial implementation and merge pull requests (atom/teletype#323, atom/teletype-client#52, and atom/fuzzy-finder#335) allowing guests to use the fuzzy-finder to open any remote editor shared by the host (https://github.com/atom/teletype/issues/268) + - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268) - Use fuzzy-finder support internally in our day-to-day workflows to assess usability - Treesitter - Xray From ef16985bfccb138c00a006319fa719b03531894e Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 12 Feb 2018 08:32:13 -0500 Subject: [PATCH 29/90] :bowtie: --- docs/focus/2018-02-12.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 278b52acd..169849a43 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -4,14 +4,14 @@ - GitHub Package - Teletype - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization ([atom/teletype#266](https://github.com/atom/teletype/issues/266), [atom/teletype#297](https://github.com/atom/teletype/issues/297)) - - Opened [atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335) to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268) + - Opened [atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335) to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) ## Focus for week ahead - Atom IDE - GitHub Package - Teletype - - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268) + - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) - Use fuzzy-finder support internally in our day-to-day workflows to assess usability - Treesitter - Xray From 744d2ce30aa97fb64814e1c585c0a4a15a777526 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 12 Feb 2018 09:28:56 -0500 Subject: [PATCH 30/90] @smashwilson's stuff --- docs/focus/2018-02-12.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 169849a43..dedf3d6ad 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -1,7 +1,16 @@ ## Highlights from the past week - Atom IDE +- @atom/watcher + - Report events related to [symlinks](https://github.com/atom/watcher/pull/111) and [test for symlink-related edge cases.](https://github.com/atom/watcher/pull/114) + - Produce filesystem events with a [consistent parent path](https://github.com/atom/watcher/pull/113) to the one used to create a watcher, even if the watcher was created with a a path containing symlinks. + - Verified correct behavior with regard to [filesystem case sensitivity.](https://github.com/atom/watcher/pull/116) + - Corrected buggy [utf8 to utf16 conversion](https://github.com/atom/watcher/pull/115) on Windows. + - Ran through the MacOS cases in the [testing matrix.](https://github.com/atom/atom/pull/16124) + - Set up a Samba share on @ungb's testing server to exercise Samba network drives. + - Published version 1.0.0 on [npm.](https://www.npmjs.com/package/@atom/watcher) - GitHub Package + - Introduce a package configuration option to [disable the in-editor merge conflict resolution.](https://github.com/atom/github/pull/1305) - Teletype - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization ([atom/teletype#266](https://github.com/atom/teletype/issues/266), [atom/teletype#297](https://github.com/atom/teletype/issues/297)) - Opened [atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335) to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) @@ -9,7 +18,13 @@ ## Focus for week ahead - Atom IDE +- @atom/watcher + - Complete [the testing matrix](https://github.com/atom/atom/pull/16124) on Linux and Windows. + - :shipit: Merge [@atom/watcher support]((https://github.com/atom/atom/pull/16124)) into Atom _(as a non-default `PathWatcher` backend)_. :shipit: - GitHub Package + - Quarterly planning. Which might change all of these :wink: + - Finish tracking down our [freezing CI builds.](https://github.com/atom/github/pull/1289) + - Resurrect the [gargantuan credential helper and GPG pinentry refactoring PR](https://github.com/atom/github/pull/846) and see how much work is needed to get it over the finish line. - Teletype - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) - Use fuzzy-finder support internally in our day-to-day workflows to assess usability From 122849eb92fc644720bf89d456d1bee506c01216 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Mon, 12 Feb 2018 06:32:28 -0800 Subject: [PATCH 31/90] Add Atom IDE focus items --- docs/focus/2018-02-12.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index dedf3d6ad..63bdb7953 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -1,6 +1,7 @@ ## Highlights from the past week - Atom IDE + - Started conversion of atom-languageclient to TypeScript [atom/atom-languageclient#175](https://github.com/atom/atom-languageclient/pull/175) - @atom/watcher - Report events related to [symlinks](https://github.com/atom/watcher/pull/111) and [test for symlink-related edge cases.](https://github.com/atom/watcher/pull/114) - Produce filesystem events with a [consistent parent path](https://github.com/atom/watcher/pull/113) to the one used to create a watcher, even if the watcher was created with a a path containing symlinks. @@ -18,6 +19,9 @@ ## Focus for week ahead - Atom IDE + - Finish conversion of atom-languageclient to TypeScript [atom/atom-languageclient#175](https://github.com/atom/atom-languageclient/pull/175) + - Contribute TypeScript type definitions for Atom IDE to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) + - Contribute missing TypeScript type defintions for Atom to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/atom) - @atom/watcher - Complete [the testing matrix](https://github.com/atom/atom/pull/16124) on Linux and Windows. - :shipit: Merge [@atom/watcher support]((https://github.com/atom/atom/pull/16124)) into Atom _(as a non-default `PathWatcher` backend)_. :shipit: From 83ad524ddf5b693b286e028e64dde409c953abb5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 12 Feb 2018 10:04:14 -0700 Subject: [PATCH 32/90] Add Xray goals --- docs/focus/2018-02-12.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 63bdb7953..3ce1df38c 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -34,3 +34,14 @@ - Use fuzzy-finder support internally in our day-to-day workflows to assess usability - Treesitter - Xray + * @nathansobo (and @as-cii part time) will be focusing the next 12 weeks on a prototype for [a new Electron-based text editor](https://github.com/atom/xray). The goal is to explore the viability of radical performance improvements that could be possible if we make breaking changes to Atom's APIs. At the end of the 12 weeks, we will reassess our plans based on what we have managed to learn and accomplish. + * Week 1 of 12 + * Clarify and document goals for the next 12 weeks. + * Ensure that the guide matches our current plans. + * Refine WebGL based text rendering. + * Make sure ASCII text renders correctly without being clipped + * Render text correctly on high DPI displays + * Use correct API for texture atlas updates + * Add mouse-wheel scrolling support + * Non-ASCII rendering, using the HarfBuzz text shaping library to detect combining characters + * Stretch goal: Switch document encoding to UTF-8 for memory compactness and support multi-byte-aware character indexing. From 7a9bd0d44153b0db8169c9187ac863ba361414ac Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 12 Feb 2018 09:33:27 -0800 Subject: [PATCH 33/90] Add my focus for week fo 2/12 --- docs/focus/2018-02-12.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 3ce1df38c..61c43a88d 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -32,7 +32,10 @@ - Teletype - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) - Use fuzzy-finder support internally in our day-to-day workflows to assess usability -- Treesitter +- Tree-sitter + - Finish and merge [tree-sitter/tree-sitter#128](https://github.com/tree-sitter/tree-sitter/pull/128), which fixes a fundamental performance problem when editing large files. + - Fix syntax highlighting bugs [#16643](https://github.com/atom/atom/issues/16643) and [#16642](https://github.com/atom/atom/issues/16642). + - Fix [#16621](https://github.com/atom/atom/issues/16621) - snippets not working when using Tree-sitter. - Xray * @nathansobo (and @as-cii part time) will be focusing the next 12 weeks on a prototype for [a new Electron-based text editor](https://github.com/atom/xray). The goal is to explore the viability of radical performance improvements that could be possible if we make breaking changes to Atom's APIs. At the end of the 12 weeks, we will reassess our plans based on what we have managed to learn and accomplish. * Week 1 of 12 From fa6c781c2a18dd1587decfa7ddaadbc845897d74 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 12 Feb 2018 12:32:59 -0800 Subject: [PATCH 34/90] Add @kuychaco's work --- docs/focus/2018-02-12.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/focus/2018-02-12.md b/docs/focus/2018-02-12.md index 61c43a88d..345543a9b 100644 --- a/docs/focus/2018-02-12.md +++ b/docs/focus/2018-02-12.md @@ -12,6 +12,10 @@ - Published version 1.0.0 on [npm.](https://www.npmjs.com/package/@atom/watcher) - GitHub Package - Introduce a package configuration option to [disable the in-editor merge conflict resolution.](https://github.com/atom/github/pull/1305) + - Published a new release v0.10.0 + - Investigated and spiked on a fix for amending bug in single-commit repos, which was surfaced by failing cache invalidation tests that were blocking release + - Deferred fixing underlying bug - [atom/github#1303](https://github.com/atom/github/issues/1303) + - Fixed failing tests - [atom/github#1302](https://github.com/atom/github/pull/1302) - Teletype - Released [Teletype 0.7.0](https://github.com/atom/teletype/releases/tag/v0.7.0) with improved diagnostics for errors that occur during package initialization ([atom/teletype#266](https://github.com/atom/teletype/issues/266), [atom/teletype#297](https://github.com/atom/teletype/issues/297)) - Opened [atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335) to pave the way for guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) @@ -29,6 +33,7 @@ - Quarterly planning. Which might change all of these :wink: - Finish tracking down our [freezing CI builds.](https://github.com/atom/github/pull/1289) - Resurrect the [gargantuan credential helper and GPG pinentry refactoring PR](https://github.com/atom/github/pull/846) and see how much work is needed to get it over the finish line. + - Fix issue with diff view popping up unexpectedly - [atom/github#1287](https://github.com/atom/github/issues/1287) - Teletype - Complete initial implementation and merge pull requests ([atom/teletype#323](https://github.com/atom/teletype/pull/323), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52), and [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) allowing guests to use the fuzzy-finder to open any remote editor shared by the host ([atom/teletype#268](https://github.com/atom/teletype/issues/268)) - Use fuzzy-finder support internally in our day-to-day workflows to assess usability From b9e4febf03f29ab4327b3b64d528cfbcbd6fb9b5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 12 Feb 2018 17:58:39 -0800 Subject: [PATCH 35/90] :arrow_up: tree-sitter --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index dedfdc2c2..a066f23f7 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "sinon": "1.17.4", "temp": "^0.8.3", "text-buffer": "13.11.8", - "tree-sitter": "^0.8.6", + "tree-sitter": "^0.9.0", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", @@ -137,18 +137,18 @@ "welcome": "0.36.6", "whitespace": "0.37.5", "wrap-guide": "0.40.3", - "language-c": "0.59.1", + "language-c": "0.59.2", "language-clojure": "0.22.7", "language-coffee-script": "0.49.3", "language-csharp": "1.0.1", "language-css": "0.42.10", "language-gfm": "0.90.3", "language-git": "0.19.1", - "language-go": "0.45.0", + "language-go": "0.45.1", "language-html": "0.49.0", "language-hyperlink": "0.16.3", "language-java": "0.28.0", - "language-javascript": "0.128.1", + "language-javascript": "0.128.2", "language-json": "0.19.1", "language-less": "0.34.2", "language-make": "0.22.3", @@ -157,17 +157,17 @@ "language-perl": "0.38.1", "language-php": "0.43.1", "language-property-list": "0.9.1", - "language-python": "0.49.0", + "language-python": "0.49.1", "language-ruby": "0.71.4", "language-ruby-on-rails": "0.25.3", "language-sass": "0.61.4", - "language-shellscript": "0.26.0", + "language-shellscript": "0.26.1", "language-source": "0.9.0", "language-sql": "0.25.10", "language-text": "0.7.3", "language-todo": "0.29.4", "language-toml": "0.18.2", - "language-typescript": "0.3.0", + "language-typescript": "0.3.1", "language-xml": "0.35.2", "language-yaml": "0.31.2" }, From 6c5365071d452f9403735504829e40c63a89d293 Mon Sep 17 00:00:00 2001 From: Bryant Ung Date: Tue, 13 Feb 2018 17:59:05 -0800 Subject: [PATCH 36/90] :arrow_up: grammar-selector --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a066f23f7..53cf296ae 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "github": "0.10.1", "git-diff": "1.3.9", "go-to-line": "0.33.0", - "grammar-selector": "0.49.9", + "grammar-selector": "0.50.0", "image-view": "0.62.4", "incompatible-packages": "0.27.3", "keybinding-resolver": "0.38.1", From 0b59e5fc5e763827c4772cb629ae40086396e504 Mon Sep 17 00:00:00 2001 From: Bryant Ung Date: Tue, 13 Feb 2018 18:03:59 -0800 Subject: [PATCH 37/90] :arrow_up: UI themes --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 53cf296ae..d351154b1 100644 --- a/package.json +++ b/package.json @@ -79,13 +79,13 @@ }, "packageDependencies": { "atom-dark-syntax": "0.29.0", - "atom-dark-ui": "0.53.1", + "atom-dark-ui": "0.53.2", "atom-light-syntax": "0.29.0", - "atom-light-ui": "0.46.1", + "atom-light-ui": "0.46.2", "base16-tomorrow-dark-theme": "1.5.0", "base16-tomorrow-light-theme": "1.5.0", - "one-dark-ui": "1.10.10", - "one-light-ui": "1.10.10", + "one-dark-ui": "1.10.11", + "one-light-ui": "1.10.11", "one-dark-syntax": "1.8.2", "one-light-syntax": "1.8.2", "solarized-dark-syntax": "1.1.4", From cb783fd15cea1d06b254799e7af8ff71d7d7ed33 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 7 Nov 2017 14:33:27 -0500 Subject: [PATCH 38/90] Use @atom/watcher with a core.fileSystemWatcher setting --- package.json | 1 + src/config-schema.js | 8 + src/path-watcher.js | 505 +++++++++++++++++++++++++------------------ 3 files changed, 301 insertions(+), 213 deletions(-) diff --git a/package.json b/package.json index d351154b1..c31c671aa 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "electronVersion": "1.7.11", "dependencies": { "@atom/nsfw": "^1.0.18", + "@atom/watcher": "0.0.8", "@atom/source-map-support": "^0.3.4", "async": "0.2.6", "atom-keymap": "8.2.9", diff --git a/src/config-schema.js b/src/config-schema.js index 358cf8717..d75777bff 100644 --- a/src/config-schema.js +++ b/src/config-schema.js @@ -337,6 +337,14 @@ const configSchema = { value: 'native', description: 'Native operating system APIs' }, + { + value: 'experimental', + description: 'Experimental filesystem watching library' + }, + { + value: 'poll', + description: 'Polling' + }, { value: 'atom', description: 'Emulated with Atom events' diff --git a/src/path-watcher.js b/src/path-watcher.js index ff7e8fd56..72a798d06 100644 --- a/src/path-watcher.js +++ b/src/path-watcher.js @@ -3,6 +3,7 @@ const path = require('path') const {Emitter, Disposable, CompositeDisposable} = require('event-kit') const nsfw = require('@atom/nsfw') +const watcher = require('@atom/watcher') const {NativeWatcherRegistry} = require('./native-watcher-registry') // Private: Associate native watcher action flags with descriptive String equivalents. @@ -21,145 +22,7 @@ const WATCHER_STATE = { STOPPING: Symbol('stopping') } -// Private: Emulate a "filesystem watcher" by subscribing to Atom events like buffers being saved. This will miss -// any changes made to files outside of Atom, but it also has no overhead. -class AtomBackend { - async start (rootPath, eventCallback, errorCallback) { - const getRealPath = givenPath => { - return new Promise(resolve => { - fs.realpath(givenPath, (err, resolvedPath) => { - err ? resolve(null) : resolve(resolvedPath) - }) - }) - } - - this.subs = new CompositeDisposable() - - this.subs.add(atom.workspace.observeTextEditors(async editor => { - let realPath = await getRealPath(editor.getPath()) - if (!realPath || !realPath.startsWith(rootPath)) { - return - } - - const announce = (action, oldPath) => { - const payload = {action, path: realPath} - if (oldPath) payload.oldPath = oldPath - eventCallback([payload]) - } - - const buffer = editor.getBuffer() - - this.subs.add(buffer.onDidConflict(() => announce('modified'))) - this.subs.add(buffer.onDidReload(() => announce('modified'))) - this.subs.add(buffer.onDidSave(event => { - if (event.path === realPath) { - announce('modified') - } else { - const oldPath = realPath - realPath = event.path - announce('renamed', oldPath) - } - })) - - this.subs.add(buffer.onDidDelete(() => announce('deleted'))) - - this.subs.add(buffer.onDidChangePath(newPath => { - if (newPath !== realPath) { - const oldPath = realPath - realPath = newPath - announce('renamed', oldPath) - } - })) - })) - - // Giant-ass brittle hack to hook files (and eventually directories) created from the TreeView. - const treeViewPackage = await atom.packages.getLoadedPackage('tree-view') - if (!treeViewPackage) return - await treeViewPackage.activationPromise - const treeViewModule = treeViewPackage.mainModule - if (!treeViewModule) return - const treeView = treeViewModule.getTreeViewInstance() - - const isOpenInEditor = async eventPath => { - const openPaths = await Promise.all( - atom.workspace.getTextEditors().map(editor => getRealPath(editor.getPath())) - ) - return openPaths.includes(eventPath) - } - - this.subs.add(treeView.onFileCreated(async event => { - const realPath = await getRealPath(event.path) - if (!realPath) return - - eventCallback([{action: 'added', path: realPath}]) - })) - - this.subs.add(treeView.onEntryDeleted(async event => { - const realPath = await getRealPath(event.path) - if (!realPath || isOpenInEditor(realPath)) return - - eventCallback([{action: 'deleted', path: realPath}]) - })) - - this.subs.add(treeView.onEntryMoved(async event => { - const [realNewPath, realOldPath] = await Promise.all([ - getRealPath(event.newPath), - getRealPath(event.initialPath) - ]) - if (!realNewPath || !realOldPath || isOpenInEditor(realNewPath) || isOpenInEditor(realOldPath)) return - - eventCallback([{action: 'renamed', path: realNewPath, oldPath: realOldPath}]) - })) - } - - async stop () { - this.subs && this.subs.dispose() - } -} - -// Private: Implement a native watcher by translating events from an NSFW watcher. -class NSFWBackend { - async start (rootPath, eventCallback, errorCallback) { - const handler = events => { - eventCallback(events.map(event => { - const action = ACTION_MAP.get(event.action) || `unexpected (${event.action})` - const payload = {action} - - if (event.file) { - payload.path = path.join(event.directory, event.file) - } else { - payload.oldPath = path.join(event.directory, event.oldFile) - payload.path = path.join(event.directory, event.newFile) - } - - return payload - })) - } - - this.watcher = await nsfw( - rootPath, - handler, - {debounceMS: 100, errorCallback} - ) - - await this.watcher.start() - } - - stop () { - return this.watcher.stop() - } -} - -// Private: Map configuration settings from the feature flag to backend implementations. -const BACKENDS = { - atom: AtomBackend, - native: NSFWBackend -} - -// Private: the backend implementation to fall back to if the config setting is invalid. -const DEFAULT_BACKEND = BACKENDS.nsfw - -// Private: Interface with and normalize events from a native OS filesystem watcher. +// Private: Interface with and normalize events from a filesystem watcher implementation. class NativeWatcher { // Private: Initialize a native watcher on a path. @@ -170,37 +33,10 @@ class NativeWatcher { this.emitter = new Emitter() this.subs = new CompositeDisposable() - this.backend = null this.state = WATCHER_STATE.STOPPED this.onEvents = this.onEvents.bind(this) this.onError = this.onError.bind(this) - - this.subs.add(atom.config.onDidChange('core.fileSystemWatcher', async () => { - if (this.state === WATCHER_STATE.STARTING) { - // Wait for this watcher to finish starting. - await new Promise(resolve => { - const sub = this.onDidStart(() => { - sub.dispose() - resolve() - }) - }) - } - - // Re-read the config setting in case it's changed again while we were waiting for the watcher - // to start. - const Backend = this.getCurrentBackend() - if (this.state === WATCHER_STATE.RUNNING && !(this.backend instanceof Backend)) { - await this.stop() - await this.start() - } - })) - } - - // Private: Read the `core.fileSystemWatcher` setting to determine the filesystem backend to use. - getCurrentBackend () { - const setting = atom.config.get('core.fileSystemWatcher') - return BACKENDS[setting] || DEFAULT_BACKEND } // Private: Begin watching for filesystem events. @@ -212,15 +48,16 @@ class NativeWatcher { } this.state = WATCHER_STATE.STARTING - const Backend = this.getCurrentBackend() - - this.backend = new Backend() - await this.backend.start(this.normalizedPath, this.onEvents, this.onError) + await this.doStart() this.state = WATCHER_STATE.RUNNING this.emitter.emit('did-start') } + doStart () { + return Promise.reject('doStart() not overridden') + } + // Private: Return true if the underlying watcher is actively listening for filesystem events. isRunning () { return this.state === WATCHER_STATE.RUNNING @@ -283,8 +120,8 @@ class NativeWatcher { // // * `replacement` the new {NativeWatcher} instance that a live {Watcher} instance should reattach to instead. // * `watchedPath` absolute path watched by the new {NativeWatcher}. - reattachTo (replacement, watchedPath) { - this.emitter.emit('should-detach', {replacement, watchedPath}) + reattachTo (replacement, watchedPath, options) { + this.emitter.emit('should-detach', {replacement, watchedPath, options}) } // Private: Stop the native watcher and release any operating system resources associated with it. @@ -297,12 +134,17 @@ class NativeWatcher { this.state = WATCHER_STATE.STOPPING this.emitter.emit('will-stop') - await this.backend.stop() + await this.doStop() + this.state = WATCHER_STATE.STOPPED this.emitter.emit('did-stop') } + doStop () { + return Promise.resolve() + } + // Private: Detach any event subscribers. dispose () { this.emitter.dispose() @@ -324,6 +166,129 @@ class NativeWatcher { } } +// Private: Emulate a "filesystem watcher" by subscribing to Atom events like buffers being saved. This will miss +// any changes made to files outside of Atom, but it also has no overhead. +class AtomNativeWatcher extends NativeWatcher { + async doStart () { + const getRealPath = givenPath => { + return new Promise(resolve => { + fs.realpath(givenPath, (err, resolvedPath) => { + err ? resolve(null) : resolve(resolvedPath) + }) + }) + } + + this.subs.add(atom.workspace.observeTextEditors(async editor => { + let realPath = await getRealPath(editor.getPath()) + if (!realPath || !realPath.startsWith(this.normalizedPath)) { + return + } + + const announce = (action, oldPath) => { + const payload = {action, path: realPath} + if (oldPath) payload.oldPath = oldPath + this.onEvents([payload]) + } + + const buffer = editor.getBuffer() + + this.subs.add(buffer.onDidConflict(() => announce('modified'))) + this.subs.add(buffer.onDidReload(() => announce('modified'))) + this.subs.add(buffer.onDidSave(event => { + if (event.path === realPath) { + announce('modified') + } else { + const oldPath = realPath + realPath = event.path + announce('renamed', oldPath) + } + })) + + this.subs.add(buffer.onDidDelete(() => announce('deleted'))) + + this.subs.add(buffer.onDidChangePath(newPath => { + if (newPath !== this.normalizedPath) { + const oldPath = this.normalizedPath + this.normalizedPath = newPath + announce('renamed', oldPath) + } + })) + })) + + // Giant-ass brittle hack to hook files (and eventually directories) created from the TreeView. + const treeViewPackage = await atom.packages.getLoadedPackage('tree-view') + if (!treeViewPackage) return + await treeViewPackage.activationPromise + const treeViewModule = treeViewPackage.mainModule + if (!treeViewModule) return + const treeView = treeViewModule.getTreeViewInstance() + + const isOpenInEditor = async eventPath => { + const openPaths = await Promise.all( + atom.workspace.getTextEditors().map(editor => getRealPath(editor.getPath())) + ) + return openPaths.includes(eventPath) + } + + this.subs.add(treeView.onFileCreated(async event => { + const realPath = await getRealPath(event.path) + if (!realPath) return + + this.onEvents([{action: 'added', path: realPath}]) + })) + + this.subs.add(treeView.onEntryDeleted(async event => { + const realPath = await getRealPath(event.path) + if (!realPath || isOpenInEditor(realPath)) return + + this.onEvents([{action: 'deleted', path: realPath}]) + })) + + this.subs.add(treeView.onEntryMoved(async event => { + const [realNewPath, realOldPath] = await Promise.all([ + getRealPath(event.newPath), + getRealPath(event.initialPath) + ]) + if (!realNewPath || !realOldPath || isOpenInEditor(realNewPath) || isOpenInEditor(realOldPath)) return + + this.onEvents([{action: 'renamed', path: realNewPath, oldPath: realOldPath}]) + })) + } +} + +// Private: Implement a native watcher by translating events from an NSFW watcher. +class NSFWNativeWatcher extends NativeWatcher { + async doStart (rootPath, eventCallback, errorCallback) { + const handler = events => { + this.onEvents(events.map(event => { + const action = ACTION_MAP.get(event.action) || `unexpected (${event.action})` + const payload = {action} + + if (event.file) { + payload.path = path.join(event.directory, event.file) + } else { + payload.oldPath = path.join(event.directory, event.oldFile) + payload.path = path.join(event.directory, event.newFile) + } + + return payload + })) + } + + this.watcher = await nsfw( + this.normalizedPath, + handler, + {debounceMS: 100, errorCallback: this.onError} + ) + + await this.watcher.start() + } + + doStop () { + return this.watcher.stop() + } +} + // Extended: Manage a subscription to filesystem events that occur beneath a root directory. Construct these by // calling `watchPath`. To watch for events within active project directories, use {Project::onDidChangeFiles} // instead. @@ -384,6 +349,15 @@ class PathWatcher { this.native = null this.changeCallbacks = new Map() + this.attachedPromise = new Promise(resolve => { + this.resolveAttachedPromise = resolve + }) + + this.startPromise = new Promise((resolve, reject) => { + this.resolveStartPromise = resolve + this.rejectStartPromise = reject + }) + this.normalizedPathPromise = new Promise((resolve, reject) => { fs.realpath(watchedPath, (err, real) => { if (err) { @@ -395,13 +369,7 @@ class PathWatcher { resolve(real) }) }) - - this.attachedPromise = new Promise(resolve => { - this.resolveAttachedPromise = resolve - }) - this.startPromise = new Promise(resolve => { - this.resolveStartPromise = resolve - }) + this.normalizedPathPromise.catch(err => this.rejectStartPromise(err)) this.emitter = new Emitter() this.subs = new CompositeDisposable() @@ -543,46 +511,139 @@ class PathWatcher { } } -// Private: Globally tracked state used to de-duplicate related [PathWatchers]{PathWatcher}. +// Private: Globally tracked state used to de-duplicate related [PathWatchers]{PathWatcher} backed by emulated Atom +// events or NSFW. class PathWatcherManager { - // Private: Access or lazily initialize the singleton manager instance. - // - // Returns the one and only {PathWatcherManager}. - static instance () { - if (!PathWatcherManager.theManager) { - PathWatcherManager.theManager = new PathWatcherManager() + // Private: Access the currently active manager instance, creating one if necessary. + static active () { + if (!this.activeManager) { + this.activeManager = new PathWatcherManager(atom.config.get('core.fileSystemWatcher')) + this.sub = atom.config.onDidChange('core.fileSystemWatcher', ({newValue}) => { this.transitionTo(newValue) }) } - return PathWatcherManager.theManager + return this.activeManager + } + + // Private: Replace the active {PathWatcherManager} with a new one that creates [NativeWatchers]{NativeWatcher} + // based on the value of `setting`. + static async transitionTo (setting) { + const current = this.active() + + if (this.transitionPromise) { + await this.transitionPromise + } + + if (current.setting === setting) { + return + } + current.isShuttingDown = true + + let resolveTransitionPromise = () => {} + this.transitionPromise = new Promise(resolve => { + resolveTransitionPromise = resolve + }) + + const replacement = new PathWatcherManager(setting) + this.activeManager = replacement + + await Promise.all( + Array.from(current.live, async ([root, native]) => { + const w = await replacement.createWatcher(root, {}, () => {}) + native.reattachTo(w.native, root, w.native.options || {}) + }) + ) + + current.stopAllWatchers() + + resolveTransitionPromise() + this.transitionPromise = null } // Private: Initialize global {PathWatcher} state. - constructor () { - this.live = new Set() - this.nativeRegistry = new NativeWatcherRegistry( - normalizedPath => { - const nativeWatcher = new NativeWatcher(normalizedPath) + constructor (setting) { + this.setting = setting + this.live = new Map() - this.live.add(nativeWatcher) - const sub = nativeWatcher.onWillStop(() => { - this.live.delete(nativeWatcher) - sub.dispose() - }) + const initLocal = NativeConstructor => { + this.nativeRegistry = new NativeWatcherRegistry( + normalizedPath => { + const nativeWatcher = new NativeConstructor(normalizedPath) - return nativeWatcher - } - ) + this.live.set(normalizedPath, nativeWatcher) + const sub = nativeWatcher.onWillStop(() => { + this.live.delete(normalizedPath) + sub.dispose() + }) + + return nativeWatcher + } + ) + } + + if (setting === 'atom') { + initLocal(AtomNativeWatcher) + } else if (setting === 'experimental') { + // + } else if (setting === 'poll') { + // + } else { + initLocal(NSFWNativeWatcher) + } + + this.isShuttingDown = false + } + + useExperimentalWatcher () { + return this.setting === 'experimental' || this.setting === 'poll' } // Private: Create a {PathWatcher} tied to this global state. See {watchPath} for detailed arguments. - createWatcher (rootPath, options, eventCallback) { - const watcher = new PathWatcher(this.nativeRegistry, rootPath, options) - watcher.onDidChange(eventCallback) - return watcher + async createWatcher (rootPath, options, eventCallback) { + if (this.isShuttingDown) { + await this.constructor.transitionPromise + return PathWatcherManager.active().createWatcher(rootPath, options, eventCallback) + } + + if (this.useExperimentalWatcher()) { + if (this.setting === 'poll') { + options.poll = true + } + + const w = await watcher.watchPath(rootPath, options, eventCallback) + this.live.set(rootPath, w.native) + return w + } + + const w = new PathWatcher(this.nativeRegistry, rootPath, options) + w.onDidChange(eventCallback) + await w.getStartPromise() + return w + } + + // Private: Directly access the {NativeWatcherRegistry}. + getRegistry () { + if (this.useExperimentalWatcher()) { + return watcher.getRegistry() + } + + return this.nativeRegistry + } + + // Private: Sample watcher usage statistics. Only available for experimental watchers. + status () { + if (this.useExperimentalWatcher()) { + return watcher.status() + } + + return {} } // Private: Return a {String} depicting the currently active native watchers. print () { + if (this.useExperimentalWatcher()) { + return watcher.printWatchers() + } + return this.nativeRegistry.print() } @@ -590,8 +651,12 @@ class PathWatcherManager { // // Returns a {Promise} that resolves when all native watcher resources are disposed. stopAllWatchers () { + if (this.useExperimentalWatcher()) { + return watcher.stopAllWatchers() + } + return Promise.all( - Array.from(this.live, watcher => watcher.stop()) + Array.from(this.live, ([, w]) => w.stop()) ) } } @@ -636,19 +701,33 @@ class PathWatcherManager { // ``` // function watchPath (rootPath, options, eventCallback) { - const watcher = PathWatcherManager.instance().createWatcher(rootPath, options, eventCallback) - return watcher.getStartPromise().then(() => watcher) + return PathWatcherManager.active().createWatcher(rootPath, options, eventCallback) } // Private: Return a Promise that resolves when all {NativeWatcher} instances associated with a FileSystemManager // have stopped listening. This is useful for `afterEach()` blocks in unit tests. function stopAllWatchers () { - return PathWatcherManager.instance().stopAllWatchers() + return PathWatcherManager.active().stopAllWatchers() } -// Private: Show the currently active native watchers. -function printWatchers () { - return PathWatcherManager.instance().print() +// Private: Show the currently active native watchers in a formatted {String}. +watchPath.printWatchers = function () { + return PathWatcherManager.active().print() } -module.exports = {watchPath, stopAllWatchers, printWatchers} +// Private: Access the active {NativeWatcherRegistry}. +watchPath.getRegistry = function () { + return PathWatcherManager.active().getRegistry() +} + +// Private: Sample usage statistics for the active watcher. +watchPath.status = function () { + return PathWatcherManager.active().status() +} + +// Private: Configure @atom/watcher ("experimental") directly. +watchPath.configure = function (...args) { + return watcher.configure(...args) +} + +module.exports = {watchPath, stopAllWatchers} From 73d8471b5c94132b67b3116234058dd1d86954bb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Sun, 11 Feb 2018 10:29:44 -0500 Subject: [PATCH 39/90] :arrow_up: @atom/watcher --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c31c671aa..187184771 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "electronVersion": "1.7.11", "dependencies": { "@atom/nsfw": "^1.0.18", - "@atom/watcher": "0.0.8", + "@atom/watcher": "1.0.1", "@atom/source-map-support": "^0.3.4", "async": "0.2.6", "atom-keymap": "8.2.9", From 3e7e8aecce7c0d63d9c4a0412bb39ea962a466f3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 14 Feb 2018 07:49:02 -0800 Subject: [PATCH 40/90] Handle positions between CR and LF characters in TreeSitterTextBufferInput.seek --- package.json | 2 +- spec/tree-sitter-language-mode-spec.js | 43 ++++++++++++++++++++++++++ src/tree-sitter-language-mode.js | 16 +++++++--- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index a066f23f7..9d9e37f87 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "sinon": "1.17.4", "temp": "^0.8.3", "text-buffer": "13.11.8", - "tree-sitter": "^0.9.0", + "tree-sitter": "^0.9.1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 58a098dca..ae3daf83c 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -170,6 +170,49 @@ describe('TreeSitterLanguageMode', () => { [{text: ')', scopes: []}] ]) }) + + it('handles edits after tokens that end between CR and LF characters (regression)', () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + parser: 'tree-sitter-javascript', + scopes: { + 'comment': 'comment', + 'string': 'string', + 'property_identifier': 'property', + } + }) + + buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + + buffer.setText([ + '// abc', + '', + 'a("b").c' + ].join('\r\n')) + + expectTokensToEqual(editor, [ + [{text: '// abc', scopes: ['comment']}], + [{text: '', scopes: []}], + [ + {text: 'a(', scopes: []}, + {text: '"b"', scopes: ['string']}, + {text: ').', scopes: []}, + {text: 'c', scopes: ['property']} + ] + ]) + + buffer.insert([2, 0], ' ') + expectTokensToEqual(editor, [ + [{text: '// abc', scopes: ['comment']}], + [{text: '', scopes: []}], + [ + {text: ' ', scopes: ['whitespace']}, + {text: 'a(', scopes: []}, + {text: '"b"', scopes: ['string']}, + {text: ').', scopes: []}, + {text: 'c', scopes: ['property']} + ] + ]) + }) }) describe('folding', () => { diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 945af9331..e6d207ebc 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -495,16 +495,22 @@ class TreeSitterHighlightIterator { class TreeSitterTextBufferInput { constructor (buffer) { this.buffer = buffer - this.seek(0) + this.position = {row: 0, column: 0} + this.isBetweenCRLF = false } - seek (characterIndex) { - this.position = this.buffer.positionForCharacterIndex(characterIndex) + seek (offset, position) { + this.position = position + this.isBetweenCRLF = this.position.column > this.buffer.lineLengthForRow(this.position.row) } read () { - const endPosition = this.buffer.clipPosition(this.position.traverse({row: 1000, column: 0})) - const text = this.buffer.getTextInRange([this.position, endPosition]) + const endPosition = this.buffer.clipPosition(new Point(this.position.row + 1000, 0)) + let text = this.buffer.getTextInRange([this.position, endPosition]) + if (this.isBetweenCRLF) { + text = text.slice(1) + this.isBetweenCRLF = false + } this.position = endPosition return text } From 30e1233b11d335313dcde995020f0bf6e535fdc7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 14 Feb 2018 10:01:42 -0800 Subject: [PATCH 41/90] Fix loadGrammar callback argument order Fixes #16733 --- src/grammar-registry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grammar-registry.js b/src/grammar-registry.js index b316bdbb0..c10e1c8b0 100644 --- a/src/grammar-registry.js +++ b/src/grammar-registry.js @@ -429,7 +429,7 @@ class GrammarRegistry { this.readGrammar(grammarPath, (error, grammar) => { if (error) return callback(error) this.addGrammar(grammar) - callback(grammar) + callback(null, grammar) }) } From 53c0f5f4a027d3800e6c6a6d869af6e0210d8011 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Wed, 14 Feb 2018 12:02:17 -0800 Subject: [PATCH 42/90] :bug: Prefer package name from metadata When loading a package prefer the name specified in the package metadata instead of the name of the folder that the package's files reside in. Fixes #16703. --- src/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.js b/src/package.js index 8d5cbc3ca..bbcb0061f 100644 --- a/src/package.js +++ b/src/package.js @@ -43,8 +43,8 @@ class Package { ? params.bundledPackage : this.packageManager.isBundledPackagePath(this.path) this.name = - params.name || (this.metadata && this.metadata.name) || + params.name || path.basename(this.path) this.reset() } From b51f13cc90df049382feb6b8e671854081f46261 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 14 Feb 2018 14:23:35 -0800 Subject: [PATCH 43/90] Shim two private APIs on TreeSitterLanguageMode --- src/tree-sitter-language-mode.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index e6d207ebc..5a3984b62 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -1,5 +1,6 @@ const {Document} = require('tree-sitter') -const {Point, Range, Emitter} = require('atom') +const {Point, Range} = require('text-buffer') +const {Emitter, Disposable} = require('event-kit') const ScopeDescriptor = require('./scope-descriptor') const TokenizedLine = require('./tokenized-line') const TextMateLanguageMode = require('./text-mate-language-mode') @@ -279,10 +280,16 @@ class TreeSitterLanguageMode { if (node) return new Range(node.startPosition, node.endPosition) } + bufferRangeForScopeAtPosition (position) { + return this.getRangeForSyntaxNodeContainingRange(new Range(position, position)) + } + /* Section - Backward compatibility shims */ + onDidTokenize (callback) { return new Disposable(() => {}) } + tokenizedLineForRow (row) { return new TokenizedLine({ openScopes: [], From 98070275b53578d1d131d0e74f4f780e572ffc80 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 14 Feb 2018 17:22:36 -0800 Subject: [PATCH 44/90] Normalize command line paths with windows drive letters --- src/main-process/atom-application.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index c2d40e92b..9678240c9 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -838,13 +838,12 @@ class AtomApplication extends EventEmitter { let existingWindow if (!newWindow) { existingWindow = this.windowForPaths(pathsToOpen, devMode) - const stats = pathsToOpen.map(pathToOpen => fs.statSyncNoException(pathToOpen)) if (!existingWindow) { let lastWindow = window || this.getLastFocusedWindow() if (lastWindow && lastWindow.devMode === devMode) { if (addToLastWindow || ( - stats.every(s => s.isFile && s.isFile()) || - (stats.some(s => s.isDirectory && s.isDirectory()) && !lastWindow.hasProjectPath()))) { + locationsToOpen.every(({stat}) => stat && stat.isFile()) || + (locationsToOpen.some(({stat}) => stat && stat.isDirectory()) && !lastWindow.hasProjectPath()))) { existingWindow = lastWindow } } @@ -1267,11 +1266,11 @@ class AtomApplication extends EventEmitter { initialLine = initialColumn = null } - if (url.parse(pathToOpen).protocol == null) { - pathToOpen = path.resolve(executedFrom, fs.normalize(pathToOpen)) - } + const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(pathToOpen))) + const stat = fs.statSyncNoException(normalizedPath) + if (stat) pathToOpen = normalizedPath - return {pathToOpen, initialLine, initialColumn} + return {pathToOpen, stat, initialLine, initialColumn} } // Opens a native dialog to prompt the user for a path. From daac2c4ee1356ddb09aab91b94770226b6121860 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 14 Feb 2018 21:49:45 -0600 Subject: [PATCH 45/90] return value of sync confirm function --- src/application-delegate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/application-delegate.js b/src/application-delegate.js index f0be70a11..627a2713e 100644 --- a/src/application-delegate.js +++ b/src/application-delegate.js @@ -236,7 +236,7 @@ class ApplicationDelegate { return chosen } else { const callback = buttons[buttonLabels[chosen]] - if (typeof callback === 'function') callback() + if (typeof callback === 'function') return callback() } } } From e3135f19388add6d67674ae5842f7f219aa431b4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 15 Feb 2018 10:16:39 -0800 Subject: [PATCH 46/90] Continue to normalize any non-URL path command line arg Also, remove duplicate file stat'ing in AtomWindow --- src/main-process/atom-application.js | 2 +- src/main-process/atom-window.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 9678240c9..128268353 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -1268,7 +1268,7 @@ class AtomApplication extends EventEmitter { const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(pathToOpen))) const stat = fs.statSyncNoException(normalizedPath) - if (stat) pathToOpen = normalizedPath + if (stat || !url.parse(pathToOpen).protocol) pathToOpen = normalizedPath return {pathToOpen, stat, initialLine, initialColumn} } diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js index 11a2d8f35..57428decd 100644 --- a/src/main-process/atom-window.js +++ b/src/main-process/atom-window.js @@ -74,14 +74,13 @@ class AtomWindow extends EventEmitter { if (!this.loadSettings.initialPaths) { this.loadSettings.initialPaths = [] - for (const {pathToOpen} of locationsToOpen) { + for (const {pathToOpen, stat} of locationsToOpen) { if (!pathToOpen) continue - const stat = fs.statSyncNoException(pathToOpen) || null if (stat && stat.isDirectory()) { this.loadSettings.initialPaths.push(pathToOpen) } else { const parentDirectory = path.dirname(pathToOpen) - if ((stat && stat.isFile()) || fs.existsSync(parentDirectory)) { + if (stat && stat.isFile() || fs.existsSync(parentDirectory)) { this.loadSettings.initialPaths.push(parentDirectory) } else { this.loadSettings.initialPaths.push(pathToOpen) From a433e974eb7047497889e047ccc05bd70be5e2d5 Mon Sep 17 00:00:00 2001 From: Billy Janitsch Date: Thu, 15 Feb 2018 10:42:57 -0800 Subject: [PATCH 47/90] Stop scaling up small scroll wheel events --- spec/text-editor-component-spec.js | 34 ------------------------------ src/text-editor-component.js | 8 ++----- 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index de2b68bb5..bfbb8b8be 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1368,40 +1368,6 @@ describe('TextEditorComponent', () => { } }) - it('always scrolls by a minimum of 1, even when the delta is small or the scroll sensitivity is low', () => { - const scrollSensitivity = 10 - const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) - - { - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -3}) - expect(component.getScrollTop()).toBe(1) - expect(component.getScrollLeft()).toBe(0) - expect(component.refs.content.style.transform).toBe(`translate(0px, -1px)`) - } - - { - component.didMouseWheel({wheelDeltaX: -4, wheelDeltaY: 0}) - expect(component.getScrollTop()).toBe(1) - expect(component.getScrollLeft()).toBe(1) - expect(component.refs.content.style.transform).toBe(`translate(-1px, -1px)`) - } - - editor.update({scrollSensitivity: 100}) - { - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: 0.3}) - expect(component.getScrollTop()).toBe(0) - expect(component.getScrollLeft()).toBe(1) - expect(component.refs.content.style.transform).toBe(`translate(-1px, 0px)`) - } - - { - component.didMouseWheel({wheelDeltaX: 0.1, wheelDeltaY: 0}) - expect(component.getScrollTop()).toBe(0) - expect(component.getScrollLeft()).toBe(0) - expect(component.refs.content.style.transform).toBe(`translate(0px, 0px)`) - } - }) - it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50 const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 5d09ff50f..8f8bd3937 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -1520,15 +1520,11 @@ class TextEditorComponent { let {wheelDeltaX, wheelDeltaY} = event if (Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)) { - wheelDeltaX = (Math.sign(wheelDeltaX) === 1) - ? Math.max(1, wheelDeltaX * scrollSensitivity) - : Math.min(-1, wheelDeltaX * scrollSensitivity) + wheelDeltaX = wheelDeltaX * scrollSensitivity wheelDeltaY = 0 } else { wheelDeltaX = 0 - wheelDeltaY = (Math.sign(wheelDeltaY) === 1) - ? Math.max(1, wheelDeltaY * scrollSensitivity) - : Math.min(-1, wheelDeltaY * scrollSensitivity) + wheelDeltaY = wheelDeltaY * scrollSensitivity } if (this.getPlatform() !== 'darwin' && event.shiftKey) { From adbd5400295494173e59285bbcb6ac967ed3ebfb Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 15 Feb 2018 12:29:48 -0800 Subject: [PATCH 48/90] Only return overridden language ids in .getGrammarOverride --- spec/grammar-registry-spec.js | 2 ++ src/grammar-registry.js | 10 +++++++++- src/text-editor-registry.js | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index e6d815f8d..93f83eb26 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -24,6 +24,7 @@ describe('GrammarRegistry', () => { const buffer = new TextBuffer() expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.js') + expect(grammarRegistry.getAssignedLanguageId(buffer)).toBe('source.js') // Returns true if we found the grammar, even if it didn't change expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true) @@ -47,6 +48,7 @@ describe('GrammarRegistry', () => { expect(grammarRegistry.assignLanguageMode(buffer, null)).toBe(true) expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(grammarRegistry.getAssignedLanguageId(buffer)).toBe(null) }) }) }) diff --git a/src/grammar-registry.js b/src/grammar-registry.js index c10e1c8b0..618e5022e 100644 --- a/src/grammar-registry.js +++ b/src/grammar-registry.js @@ -135,6 +135,14 @@ class GrammarRegistry { return true } + // Extended: Get the `languageId` that has been explicitly assigned to + // to the given buffer, if any. + // + // Returns a {String} id of the language + getAssignedLanguageId (buffer) { + return this.languageOverridesByBufferId.get(buffer.id) + } + // Extended: Remove any language mode override that has been set for the // given {TextBuffer}. This will assign to the buffer the best language // mode available. @@ -293,7 +301,7 @@ class GrammarRegistry { grammarOverrideForPath (filePath) { Grim.deprecate('Use buffer.getLanguageMode().getLanguageId() instead') const buffer = atom.project.findBufferForPath(filePath) - if (buffer) return this.languageOverridesByBufferId.get(buffer.id) + if (buffer) return this.getAssignedLanguageId(buffer) } // Deprecated: Set the grammar override for the given file path. diff --git a/src/text-editor-registry.js b/src/text-editor-registry.js index 9b802f5f8..132b24ffb 100644 --- a/src/text-editor-registry.js +++ b/src/text-editor-registry.js @@ -205,7 +205,7 @@ class TextEditorRegistry { // Returns a {String} scope name, or `null` if no override has been set // for the given editor. getGrammarOverride (editor) { - return editor.getBuffer().getLanguageMode().grammar.scopeName + return atom.grammars.getAssignedLanguageId(editor.getBuffer()) } // Deprecated: Remove any grammar override that has been set for the given {TextEditor}. From ad6b2131d6f66631e14ad657135762bbd6f8fdbf Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Thu, 15 Feb 2018 22:47:33 +0100 Subject: [PATCH 49/90] Style the scrollbar in the test --- spec/text-editor-component-spec.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 69bb4dbe0..ba36b7e0a 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -905,13 +905,20 @@ describe('TextEditorComponent', () => { expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) }) - it('gracefully handles edits that change the maxScrollTop by causing the horizontal scrollbar to disappear', async () => { + fit('gracefully handles edits that change the maxScrollTop by causing the horizontal scrollbar to disappear', async () => { const rowsPerTile = 1 const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) await setEditorHeightInLines(component, 1) await setEditorWidthInCharacters(component, 7) + // Updating scrollbar styles. + const style = document.createElement('style') + style.textContent = '::-webkit-scrollbar { height: 17px; width: 10px; }' + jasmine.attachToDOM(style) + TextEditor.didUpdateScrollbarStyles() + await component.getNextUpdatePromise() + element.focus() component.setScrollTop(component.measurements.lineHeight) From 63326e969a89d4e122993f094c0516ef69137719 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Thu, 15 Feb 2018 22:53:29 +0100 Subject: [PATCH 50/90] Unfocus test and always return false to see if this fails on circle --- spec/text-editor-component-spec.js | 2 +- src/text-editor-component.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index ba36b7e0a..4faeea8ed 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -905,7 +905,7 @@ describe('TextEditorComponent', () => { expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) }) - fit('gracefully handles edits that change the maxScrollTop by causing the horizontal scrollbar to disappear', async () => { + it('gracefully handles edits that change the maxScrollTop by causing the horizontal scrollbar to disappear', async () => { const rowsPerTile = 1 const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 26dbd9f9a..a0406796f 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -418,7 +418,8 @@ class TextEditorComponent { this.linesToMeasure.clear() this.measuredContent = true - return wasHorizontalScrollbarVisible !== isHorizontalScrollbarVisible + return false + // return wasHorizontalScrollbarVisible !== isHorizontalScrollbarVisible } updateSyncAfterMeasuringContent () { From 8cfcdf8c00fa8cc118d3755dde48e452ddba4003 Mon Sep 17 00:00:00 2001 From: Linus Eriksson Date: Thu, 15 Feb 2018 23:12:35 +0100 Subject: [PATCH 51/90] Revert always return false --- src/text-editor-component.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text-editor-component.js b/src/text-editor-component.js index a0406796f..26dbd9f9a 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -418,8 +418,7 @@ class TextEditorComponent { this.linesToMeasure.clear() this.measuredContent = true - return false - // return wasHorizontalScrollbarVisible !== isHorizontalScrollbarVisible + return wasHorizontalScrollbarVisible !== isHorizontalScrollbarVisible } updateSyncAfterMeasuringContent () { From 69af0141a19238ce719c6c867ed462b9a6dd1b76 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 15 Feb 2018 18:35:50 -0500 Subject: [PATCH 52/90] :bug: params -> options --- src/application-delegate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/application-delegate.js b/src/application-delegate.js index f0be70a11..7d90da792 100644 --- a/src/application-delegate.js +++ b/src/application-delegate.js @@ -249,7 +249,7 @@ class ApplicationDelegate { this.getCurrentWindow().showSaveDialog(options, callback) } else { // Sync - if (typeof params === 'string') { + if (typeof options === 'string') { options = {defaultPath: options} } return this.getCurrentWindow().showSaveDialog(options) From cd997e3d774b1bf2406862e12b2e799e4688dd07 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 16 Feb 2018 09:40:57 -0800 Subject: [PATCH 53/90] Simplify TreeSitterHighlightIterator.moveToSuccessor --- src/tree-sitter-language-mode.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 5a3984b62..5c6a91930 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -420,7 +420,7 @@ class TreeSitterHighlightIterator { this.pushCloseTag() const {nextSibling} = this.currentNode - if (nextSibling) { + if (nextSibling && nextSibling.endIndex > this.currentIndex) { this.currentNode = nextSibling this.currentChildIndex++ if (this.currentIndex === nextSibling.startIndex) { @@ -434,19 +434,8 @@ class TreeSitterHighlightIterator { if (!this.currentNode) break } } - } else if (this.currentNode.startIndex < this.currentNode.endIndex) { - this.currentNode = this.currentNode.nextSibling - if (this.currentNode) { - this.currentChildIndex++ - this.currentPosition = this.currentNode.startPosition - this.currentIndex = this.currentNode.startIndex - this.pushOpenTag() - this.descendLeft() - } } else { - this.pushCloseTag() - this.currentNode = this.currentNode.parent - this.currentChildIndex = last(this.containingNodeChildIndices) + this.currentNode = this.currentNode.nextSibling } } while (this.closeTags.length === 0 && this.openTags.length === 0 && this.currentNode) From cda838250b0968a4c1e9f1665c05ceb26a2c3d61 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 16 Feb 2018 13:03:00 -0700 Subject: [PATCH 54/90] Add empty focus template for week of 2018-02-19 --- docs/focus/2018-02-19.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docs/focus/2018-02-19.md diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md new file mode 100644 index 000000000..36ed95b34 --- /dev/null +++ b/docs/focus/2018-02-19.md @@ -0,0 +1,16 @@ +## Highlights from the past week + +- Atom IDE +- @atom/watcher +- GitHub Package +- Teletype +- Xray + +## Focus for week ahead + +- Atom IDE +- @atom/watcher +- GitHub Package +- Teletype +- Tree-sitter +- Xray From 29b8ae2abea9e753ccb98bc5167cfa5b30e939cf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 16 Feb 2018 13:10:24 -0700 Subject: [PATCH 55/90] Add Xray focus stuff --- docs/focus/2018-02-19.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 36ed95b34..697b745e8 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -5,6 +5,9 @@ - GitHub Package - Teletype - Xray + - We made a slight change of plans and decided to spend more time clarifying the overall vision for the project. + - We have a [branch](https://github.com/atom/xray/tree/roadmap) with a new README that matches our current thinking, but the Q1 roadmap is still in progress. + - We did manage to get text rendering with retina displays and non-clipped characters, but there's still work to do. We are also experimenting populating our glyph atlas with up to 4 variants of each glyph at different subpixel positions to more closely match text rendered purely on the CPU. ## Focus for week ahead @@ -14,3 +17,5 @@ - Teletype - Tree-sitter - Xray + - We will continue clarifying the overall vision with a focus on real time collaboration. This may extend beyond the scope of Xray, but is important to get clarity on before comitting to a roadmap. + - We hope to iron out the remaining issues with subpixel-positioning of glyphs to more faithfully reproduce Chrome's behavior when rendering text via the normal DOM-based code path. From f395f2e80d24803accc05ad29e5ad07608441ebc Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 16 Feb 2018 13:07:54 -0800 Subject: [PATCH 56/90] :arrow_up: tree-sitter --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 25df876ab..b83c55eea 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "sinon": "1.17.4", "temp": "^0.8.3", "text-buffer": "13.11.8", - "tree-sitter": "^0.9.1", + "tree-sitter": "^0.9.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", From 2575cf6b1ae63a044cc99dc197ed0dda54a897a7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 16 Feb 2018 13:41:17 -0800 Subject: [PATCH 57/90] Fix path duplication after decaffeinating main process code --- src/main-process/atom-window.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js index 57428decd..ae6e1ccc9 100644 --- a/src/main-process/atom-window.js +++ b/src/main-process/atom-window.js @@ -154,12 +154,13 @@ class AtomWindow extends EventEmitter { containsPath (pathToCheck) { if (!pathToCheck) return false - const stat = fs.statSyncNoException(pathToCheck) - if (stat && stat.isDirectory()) return false - - return this.representedDirectoryPaths.some(projectPath => - pathToCheck === projectPath || pathToCheck.startsWith(path.join(projectPath, path.sep)) - ) + let stat + return this.representedDirectoryPaths.some(projectPath => { + if (pathToCheck === projectPath) return true + if (!pathToCheck.startsWith(path.join(projectPath, path.sep))) return false + if (stat === undefined) stat = fs.statSyncNoException(pathToCheck) + return !stat || !stat.isDirectory() + }) } handleEvents () { From b922430c1d763cda945eee781d34223ec3870ed3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 16 Feb 2018 14:49:59 -0800 Subject: [PATCH 58/90] :arrow_up: language packages for tree-sitter fixes --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b83c55eea..92ac251cd 100644 --- a/package.json +++ b/package.json @@ -145,11 +145,11 @@ "language-css": "0.42.10", "language-gfm": "0.90.3", "language-git": "0.19.1", - "language-go": "0.45.1", + "language-go": "0.45.2", "language-html": "0.49.0", "language-hyperlink": "0.16.3", "language-java": "0.28.0", - "language-javascript": "0.128.2", + "language-javascript": "0.128.3", "language-json": "0.19.1", "language-less": "0.34.2", "language-make": "0.22.3", @@ -158,7 +158,7 @@ "language-perl": "0.38.1", "language-php": "0.43.1", "language-property-list": "0.9.1", - "language-python": "0.49.1", + "language-python": "0.49.2", "language-ruby": "0.71.4", "language-ruby-on-rails": "0.25.3", "language-sass": "0.61.4", @@ -168,7 +168,7 @@ "language-text": "0.7.3", "language-todo": "0.29.4", "language-toml": "0.18.2", - "language-typescript": "0.3.1", + "language-typescript": "0.3.2", "language-xml": "0.35.2", "language-yaml": "0.31.2" }, From 17af5933f9e4b7c7abb37f697ff950e6656cf73b Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 16 Feb 2018 14:53:38 -0800 Subject: [PATCH 59/90] Add some focus items for Atom IDE --- docs/focus/2018-02-19.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 697b745e8..7ac4bafd9 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -1,6 +1,9 @@ ## Highlights from the past week - Atom IDE + - Converted atom-languageclient to TypeScript + - ide-typescript updated to use TypeScript 2.7.2 + - Published updates to ide-typescript, ide-json, and ide-csharp to improve language server stability - @atom/watcher - GitHub Package - Teletype @@ -12,6 +15,7 @@ ## Focus for week ahead - Atom IDE + - Investigate new Atom IDE UI features for rename operations and workspace symbol search - @atom/watcher - GitHub Package - Teletype From 7e2e39c538335ff6281a5878439b62d55db191cc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 16 Feb 2018 21:26:47 -0500 Subject: [PATCH 60/90] @atom/watcher and (a bit of) GitHub package work --- docs/focus/2018-02-19.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 7ac4bafd9..c37f6c4bb 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -5,7 +5,11 @@ - ide-typescript updated to use TypeScript 2.7.2 - Published updates to ide-typescript, ide-json, and ide-csharp to improve language server stability - @atom/watcher + - Gracefully handle the situation where a network share with a watch root is disconnected ([#119](https://github.com/atom/watcher/pull/119)) + - Merged into Atom master behind a feature flag ([#16124](https://github.com/atom/atom/pull/16124)) just after the 1.24.0 / 1.25.0-beta0 release + - Fixed a crash when messages are sent to the worker thread before it's properly initialized ([atom/watcher#121](https://github.com/atom/watcher/pull/121)) - GitHub Package + - Investigate intermittently freezing tests on Travis in [atom/github#1289](https://github.com/atom/github/pull/1289). Not much luck so far - Teletype - Xray - We made a slight change of plans and decided to spend more time clarifying the overall vision for the project. @@ -17,7 +21,10 @@ - Atom IDE - Investigate new Atom IDE UI features for rename operations and workspace symbol search - @atom/watcher + - Diagnose and correct crashes and lock-ups as people report them - GitHub Package + - Establish high-level goals and scope bunds for the GitHub side of the integration + - Document a protocol for the evolution of major features: ensure they contribute to a cohesive experience with the rest of the package, make sure that @simurai is looped in to the conversation, make sure the community has visibility to our goals - Teletype - Tree-sitter - Xray From 0269e98675ed68f0e5d189fb4130008ff5cf98b0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 17 Feb 2018 11:42:34 +0100 Subject: [PATCH 61/90] Add Teletype highlights and focus for next week --- docs/focus/2018-02-19.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index c37f6c4bb..09b185a8d 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -11,6 +11,11 @@ - GitHub Package - Investigate intermittently freezing tests on Travis in [atom/github#1289](https://github.com/atom/github/pull/1289). Not much luck so far - Teletype + - Fixed an unanticipated bug that would cause non-existent selections to appear in the editor of other participants ([atom/teletype#326](https://github.com/atom/teletype/pull/326)). + - Published [version 0.8.0](https://github.com/atom/teletype/releases/tag/v0.8.0). + - Refactored teletype-client and simplified how added/removed editors are broadcasted to participants ([atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52)). + - Polished the design of fuzzy-finder ([atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335)) + - Pushed [atom/teletype#323](https://github.com/atom/teletype/pull/323) over the finish line. - Xray - We made a slight change of plans and decided to spend more time clarifying the overall vision for the project. - We have a [branch](https://github.com/atom/xray/tree/roadmap) with a new README that matches our current thinking, but the Q1 roadmap is still in progress. @@ -26,6 +31,8 @@ - Establish high-level goals and scope bunds for the GitHub side of the integration - Document a protocol for the evolution of major features: ensure they contribute to a cohesive experience with the rest of the package, make sure that @simurai is looped in to the conversation, make sure the community has visibility to our goals - Teletype + - Merge and use [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52) and [atom/teletype#323](https://github.com/atom/teletype/pull/323). + - Publish Teletype v0.9.0 containing the new fuzzy-finder support. - Tree-sitter - Xray - We will continue clarifying the overall vision with a focus on real time collaboration. This may extend beyond the scope of Xray, but is important to get clarity on before comitting to a roadmap. From 05f561849fa2c9c654af2fd81aaa011d1217f418 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 17 Feb 2018 13:02:23 -0500 Subject: [PATCH 62/90] :arrow_up: background-tips@0.27.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92ac251cd..5f6d7d5d7 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "autocomplete-snippets": "1.12.0", "autoflow": "0.29.3", "autosave": "0.24.6", - "background-tips": "0.27.1", + "background-tips": "0.27.2", "bookmarks": "0.45.1", "bracket-matcher": "0.89.1", "command-palette": "0.43.3", From 3545c0140c287adb3b3a39b80a4c08222352b99e Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 17 Feb 2018 14:03:28 -0500 Subject: [PATCH 63/90] :arrow_up: background-tips@0.28.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f6d7d5d7..e424afc5a 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "autocomplete-snippets": "1.12.0", "autoflow": "0.29.3", "autosave": "0.24.6", - "background-tips": "0.27.2", + "background-tips": "0.28.0", "bookmarks": "0.45.1", "bracket-matcher": "0.89.1", "command-palette": "0.43.3", From 9b5506fba6d6bfa0a4d40ea1159e0659224faec3 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 17 Feb 2018 16:31:27 -0500 Subject: [PATCH 64/90] :arrow_up: autocomplete-plus@2.40.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e424afc5a..4b868fb5a 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "autocomplete-atom-api": "0.10.7", "autocomplete-css": "0.17.5", "autocomplete-html": "0.8.4", - "autocomplete-plus": "2.40.2", + "autocomplete-plus": "2.40.3", "autocomplete-snippets": "1.12.0", "autoflow": "0.29.3", "autosave": "0.24.6", From 0bbad9031a1eded3d71c883e68d767e7e1b67c69 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 17 Feb 2018 16:32:04 -0500 Subject: [PATCH 65/90] :arrow_up: command-palette@0.43.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b868fb5a..0070605bc 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "background-tips": "0.28.0", "bookmarks": "0.45.1", "bracket-matcher": "0.89.1", - "command-palette": "0.43.3", + "command-palette": "0.43.4", "dalek": "0.2.1", "deprecation-cop": "0.56.9", "dev-live-reload": "0.48.1", From 2c16ee440d2d2d44c7e8e6532ffd7e35abc5d9d3 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 17 Feb 2018 16:32:42 -0500 Subject: [PATCH 66/90] :arrow_up: fuzzy-finder@1.7.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0070605bc..994eb9711 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "encoding-selector": "0.23.8", "exception-reporting": "0.43.1", "find-and-replace": "0.215.5", - "fuzzy-finder": "1.7.5", + "fuzzy-finder": "1.7.6", "github": "0.10.1", "git-diff": "1.3.9", "go-to-line": "0.33.0", From 9dd40256e9cf5e2a1b3e90e57fcaff3e83bdf9bd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Sun, 18 Feb 2018 22:20:55 -0800 Subject: [PATCH 67/90] :arrow_up: tello --- script/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/package.json b/script/package.json index afc034df3..a4d2a052f 100644 --- a/script/package.json +++ b/script/package.json @@ -32,7 +32,7 @@ "semver": "5.3.0", "standard": "8.4.0", "sync-request": "3.0.1", - "tello": "1.0.5", + "tello": "1.0.7", "webdriverio": "2.4.5", "yargs": "4.8.1" } From 5d69a9fde50bd538c2b41dbb89a7a2c4f0c03aab Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 16 Feb 2018 21:29:52 -0500 Subject: [PATCH 68/90] :arrow_up: @atom/watcher --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 994eb9711..671960c6e 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "electronVersion": "1.7.11", "dependencies": { "@atom/nsfw": "^1.0.18", - "@atom/watcher": "1.0.1", + "@atom/watcher": "1.0.2", "@atom/source-map-support": "^0.3.4", "async": "0.2.6", "atom-keymap": "8.2.9", From 5468e34097e293d390f61c4b33be200c0f30fe21 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 20 Feb 2018 09:05:14 -0800 Subject: [PATCH 69/90] :arrow_up: @atom/watcher --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 671960c6e..c2527fc65 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "electronVersion": "1.7.11", "dependencies": { "@atom/nsfw": "^1.0.18", - "@atom/watcher": "1.0.2", + "@atom/watcher": "1.0.3", "@atom/source-map-support": "^0.3.4", "async": "0.2.6", "atom-keymap": "8.2.9", From 1cdb804824546e8572912df8cf51c9d5072c33ba Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 20 Feb 2018 10:52:16 -0800 Subject: [PATCH 70/90] Tweak config APIs for dealing w/ legacy scope aliases --- spec/config-spec.js | 4 ++-- src/config.js | 33 +++++++++++++++++---------------- src/grammar-registry.js | 4 ++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/spec/config-spec.js b/spec/config-spec.js index 3754e517f..b999d5157 100644 --- a/spec/config-spec.js +++ b/spec/config-spec.js @@ -115,7 +115,7 @@ describe('Config', () => { describe('when the first component of the scope descriptor matches a legacy scope alias', () => it('falls back to properties defined for the legacy scope if no value is found for the original scope descriptor', () => { - atom.config.addLegacyScopeAlias('javascript', '.source.js') + atom.config.setLegacyScopeAliasForNewScope('javascript', '.source.js') atom.config.set('foo', 100, {scopeSelector: '.source.js'}) atom.config.set('foo', 200, {scopeSelector: 'javascript for_statement'}) @@ -154,7 +154,7 @@ describe('Config', () => { describe('when the first component of the scope descriptor matches a legacy scope alias', () => it('includes the values defined for the legacy scope', () => { - atom.config.addLegacyScopeAlias('javascript', '.source.js') + atom.config.setLegacyScopeAliasForNewScope('javascript', '.source.js') expect(atom.config.set('foo', 41)).toBe(true) expect(atom.config.set('foo', 42, {scopeSelector: 'javascript'})).toBe(true) diff --git a/src/config.js b/src/config.js index a589654c9..4753d148d 100644 --- a/src/config.js +++ b/src/config.js @@ -429,7 +429,7 @@ class Config { this.settingsLoaded = false this.transactDepth = 0 this.pendingOperations = [] - this.legacyScopeAliases = {} + this.legacyScopeAliases = new Map() this.requestSave = _.debounce(() => this.save(), 1) } @@ -618,7 +618,7 @@ class Config { keyPath, options ) - legacyScopeDescriptor = this.getLegacyScopeDescriptor(scopeDescriptor) + legacyScopeDescriptor = this.getLegacyScopeDescriptorForNewScopeDescriptor(scopeDescriptor) if (legacyScopeDescriptor) { result.push(...Array.from(this.scopedSettingsStore.getAll( legacyScopeDescriptor.getScopeChain(), @@ -818,12 +818,22 @@ class Config { } } - addLegacyScopeAlias (languageId, legacyScopeName) { - this.legacyScopeAliases[languageId] = legacyScopeName + getLegacyScopeDescriptorForNewScopeDescriptor (scopeDescriptor) { + scopeDescriptor = ScopeDescriptor.fromObject(scopeDescriptor) + const legacyAlias = this.legacyScopeAliases.get(scopeDescriptor.scopes[0]) + if (legacyAlias) { + const scopes = scopeDescriptor.scopes.slice() + scopes[0] = legacyAlias + return new ScopeDescriptor({scopes}) + } } - removeLegacyScopeAlias (languageId) { - delete this.legacyScopeAliases[languageId] + setLegacyScopeAliasForNewScope (languageId, legacyScopeName) { + this.legacyScopeAliases.set(languageId, legacyScopeName) + } + + removeLegacyScopeAliasForNewScope (languageId) { + this.legacyScopeAliases.delete(languageId) } /* @@ -1202,7 +1212,7 @@ class Config { options ) - const legacyScopeDescriptor = this.getLegacyScopeDescriptor(scopeDescriptor) + const legacyScopeDescriptor = this.getLegacyScopeDescriptorForNewScopeDescriptor(scopeDescriptor) if (result != null) { return result } else if (legacyScopeDescriptor) { @@ -1230,15 +1240,6 @@ class Config { } }) } - - getLegacyScopeDescriptor (scopeDescriptor) { - const legacyAlias = this.legacyScopeAliases[scopeDescriptor.scopes[0]] - if (legacyAlias) { - const scopes = scopeDescriptor.scopes.slice() - scopes[0] = legacyAlias - return new ScopeDescriptor({scopes}) - } - } }; // Base schema enforcers. These will coerce raw input into the specified type, diff --git a/src/grammar-registry.js b/src/grammar-registry.js index 618e5022e..20757fb0b 100644 --- a/src/grammar-registry.js +++ b/src/grammar-registry.js @@ -399,7 +399,7 @@ class GrammarRegistry { if (grammar instanceof TreeSitterGrammar) { this.treeSitterGrammarsById[grammar.id] = grammar if (grammar.legacyScopeName) { - this.config.addLegacyScopeAlias(grammar.id, grammar.legacyScopeName) + this.config.setLegacyScopeAliasForNewScope(grammar.id, grammar.legacyScopeName) this.textMateScopeNamesByTreeSitterLanguageId.set(grammar.id, grammar.legacyScopeName) this.treeSitterLanguageIdsByTextMateScopeName.set(grammar.legacyScopeName, grammar.id) } @@ -414,7 +414,7 @@ class GrammarRegistry { if (grammar instanceof TreeSitterGrammar) { delete this.treeSitterGrammarsById[grammar.id] if (grammar.legacyScopeName) { - this.config.removeLegacyScopeAlias(grammar.id) + this.config.removeLegacyScopeAliasForNewScope(grammar.id) this.textMateScopeNamesByTreeSitterLanguageId.delete(grammar.id) this.treeSitterLanguageIdsByTextMateScopeName.delete(grammar.legacyScopeName) } From 4b70a16edd1f8523237b02030e52ec6a438e23f0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 20 Feb 2018 11:29:52 -0800 Subject: [PATCH 71/90] :arrow_up: snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2527fc65..821113eb4 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "open-on-github": "1.3.1", "package-generator": "1.3.0", "settings-view": "0.254.0", - "snippets": "1.3.0", + "snippets": "1.3.1", "spell-check": "0.72.7", "status-bar": "1.8.15", "styleguide": "0.49.10", From df9a4c9226b6ff3dd5a3e044dff551c2f135f7e2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 20 Feb 2018 13:39:19 -0800 Subject: [PATCH 72/90] Add Max's focus --- docs/focus/2018-02-19.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 09b185a8d..693619024 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -20,7 +20,12 @@ - We made a slight change of plans and decided to spend more time clarifying the overall vision for the project. - We have a [branch](https://github.com/atom/xray/tree/roadmap) with a new README that matches our current thinking, but the Q1 roadmap is still in progress. - We did manage to get text rendering with retina displays and non-clipped characters, but there's still work to do. We are also experimenting populating our glyph atlas with up to 4 variants of each glyph at different subpixel positions to more closely match text rendered purely on the CPU. - +- Tree-sitter + - Took some time to fix unrelated regressions from the bug-bash month + - Fixed a bug where atom --wait did not work correctly on Windows (#16740) + - Fixed a bug that prevented Atom from reusing an existing window when the same path was opened twice (#16764) + - Fixed regressions in the behavior of the atom.textEditors.getGrammarOverride and atom.grammars.loadGrammar methods (#16733, #16747) + - Fixed several syntax highlighting bugs (#16642, #16643) ## Focus for week ahead - Atom IDE @@ -34,6 +39,9 @@ - Merge and use [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52) and [atom/teletype#323](https://github.com/atom/teletype/pull/323). - Publish Teletype v0.9.0 containing the new fuzzy-finder support. - Tree-sitter + - Fix an issue where snippets are not available when using tree-sitter (#16621) + - Start work on optimizing editing in the presence of large parse errors (#16590) + - Start work on allowing parsing to take place on a background thread - Xray - We will continue clarifying the overall vision with a focus on real time collaboration. This may extend beyond the scope of Xray, but is important to get clarity on before comitting to a roadmap. - We hope to iron out the remaining issues with subpixel-positioning of glyphs to more faithfully reproduce Chrome's behavior when rendering text via the normal DOM-based code path. From f50e1c9ecbe8d2c5218807c9de582751b754491f Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 20 Feb 2018 13:42:15 -0800 Subject: [PATCH 73/90] :arrow_up: git-utils --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 821113eb4..6f67f79b4 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "fs-plus": "^3.0.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "git-utils": "5.2.1", + "git-utils": "5.3.1", "glob": "^7.1.1", "grim": "1.5.0", "jasmine-json": "~0.0", From 5c8c2b5f9b59fa429a5478680ae5b74151d767a9 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 20 Feb 2018 15:19:43 -0800 Subject: [PATCH 74/90] Add some github package stuff --- docs/focus/2018-02-19.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 693619024..54bd5b3c9 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -10,6 +10,7 @@ - Fixed a crash when messages are sent to the worker thread before it's properly initialized ([atom/watcher#121](https://github.com/atom/watcher/pull/121)) - GitHub Package - Investigate intermittently freezing tests on Travis in [atom/github#1289](https://github.com/atom/github/pull/1289). Not much luck so far + - Fixed issue with diff views popping up unexpectedly [atom/github#1311](https://github.com/atom/github/pull/1311). Just waiting on review - Teletype - Fixed an unanticipated bug that would cause non-existent selections to appear in the editor of other participants ([atom/teletype#326](https://github.com/atom/teletype/pull/326)). - Published [version 0.8.0](https://github.com/atom/teletype/releases/tag/v0.8.0). @@ -33,8 +34,9 @@ - @atom/watcher - Diagnose and correct crashes and lock-ups as people report them - GitHub Package - - Establish high-level goals and scope bunds for the GitHub side of the integration + - Establish high-level goals and scope bounds for the GitHub side of the integration - Document a protocol for the evolution of major features: ensure they contribute to a cohesive experience with the rest of the package, make sure that @simurai is looped in to the conversation, make sure the community has visibility to our goals + - Show recent commits in Git panel - Teletype - Merge and use [atom/fuzzy-finder#335](https://github.com/atom/fuzzy-finder/pull/335), [atom/teletype-client#52](https://github.com/atom/teletype-client/pull/52) and [atom/teletype#323](https://github.com/atom/teletype/pull/323). - Publish Teletype v0.9.0 containing the new fuzzy-finder support. From 1d9d17bc3935246789fdb2d8fed40286431a2bb7 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Tue, 20 Feb 2018 18:40:55 -0800 Subject: [PATCH 75/90] Update 2018-02-19.md --- docs/focus/2018-02-19.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/focus/2018-02-19.md b/docs/focus/2018-02-19.md index 54bd5b3c9..9bc89628a 100644 --- a/docs/focus/2018-02-19.md +++ b/docs/focus/2018-02-19.md @@ -31,6 +31,8 @@ - Atom IDE - Investigate new Atom IDE UI features for rename operations and workspace symbol search + - Publish TypeScript definitions for atom-ide/atom-languageclient to DefinitelyTyped + - Wire up atom-ide-ui console to LSP server logging - @atom/watcher - Diagnose and correct crashes and lock-ups as people report them - GitHub Package From 6b9e87ecd616466b9f24e75f3c87c6cd8d27bdab Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 21 Feb 2018 09:18:15 -0800 Subject: [PATCH 76/90] Serialize settings as JSON when sending them to the main process --- src/application-delegate.js | 2 +- src/main-process/atom-application.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/application-delegate.js b/src/application-delegate.js index 7a6b7250d..fcf8441b6 100644 --- a/src/application-delegate.js +++ b/src/application-delegate.js @@ -182,7 +182,7 @@ class ApplicationDelegate { async setUserSettings (config) { this.pendingSettingsUpdateCount++ try { - await ipcHelpers.call('set-user-settings', config) + await ipcHelpers.call('set-user-settings', JSON.stringify(config)) } finally { this.pendingSettingsUpdateCount-- } diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 128268353..092c46e0f 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -559,7 +559,7 @@ class AtomApplication extends EventEmitter { })) this.disposable.add(ipcHelpers.respondTo('set-user-settings', (window, settings) => - this.configFile.update(settings) + this.configFile.update(JSON.parse(settings)) )) this.disposable.add(ipcHelpers.respondTo('center-window', window => window.center())) From fb85656d8f3642ab573c29afb4e5d836b64285d1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 21 Feb 2018 09:29:02 -0800 Subject: [PATCH 77/90] Don't try to write config file while quitting --- src/main-process/atom-application.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 128268353..69b175af0 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -116,7 +116,9 @@ class AtomApplication extends EventEmitter { this.configFile = new ConfigFile(configFilePath) this.config = new Config({ - saveCallback: settings => this.configFile.update(settings) + saveCallback: settings => { + if (!this.quitting) return this.configFile.update(settings) + } }) this.config.setSchema(null, {type: 'object', properties: _.clone(ConfigSchema)}) From ea8165a1ca9646a93db0483cc4416ccccbe112c2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 21 Feb 2018 10:16:42 -0800 Subject: [PATCH 78/90] Make TreeSitterLanguageMode.scopeDescriptorForPosition accept arrays Fixes #16808 --- spec/tree-sitter-language-mode-spec.js | 2 +- src/tree-sitter-language-mode.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index ae3daf83c..a788fac47 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -542,7 +542,7 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') editor.screenLineForScreenRow(0) - expect(editor.scopeDescriptorForBufferPosition({row: 0, column: 6}).getScopesArray()).toEqual([ + expect(editor.scopeDescriptorForBufferPosition([0, 6]).getScopesArray()).toEqual([ 'javascript', 'program', 'expression_statement', diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 5c6a91930..0d2fab8cf 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -303,6 +303,7 @@ class TreeSitterLanguageMode { } scopeDescriptorForPosition (point) { + point = Point.fromObject(point) const result = [] let node = this.document.rootNode.descendantForPosition(point) From dae1c75235e5d96ab6aa7b04757a613316f0df66 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 21 Feb 2018 10:39:30 -0800 Subject: [PATCH 79/90] :arrow_up: atom-keymap --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f67f79b4..57b81bc1c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@atom/watcher": "1.0.3", "@atom/source-map-support": "^0.3.4", "async": "0.2.6", - "atom-keymap": "8.2.9", + "atom-keymap": "8.2.10", "atom-select-list": "^0.7.0", "atom-ui": "0.4.1", "babel-core": "5.8.38", From 42e3a5015db82aea4f9969f8dc259660e2ef28f5 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 21 Feb 2018 13:14:45 -0800 Subject: [PATCH 80/90] Improve spec spacing --- spec/menu-sort-helpers-spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/menu-sort-helpers-spec.js b/spec/menu-sort-helpers-spec.js index e3daf1d4a..86f00b37e 100644 --- a/spec/menu-sort-helpers-spec.js +++ b/spec/menu-sort-helpers-spec.js @@ -7,12 +7,14 @@ describe('contextMenu', () => { expect(sortMenuItems(items)).toEqual(items) }) }) + describe('dedupes separators', () => { it('trims leading separators', () => { const items = [{ type: 'separator' }, { command: 'core:one' }] const expected = [{ command: 'core:one' }] expect(sortMenuItems(items)).toEqual(expected) }) + it('preserves separators at the begining of set two', () => { const items = [ { command: 'core:one' }, @@ -25,11 +27,13 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it('trims trailing separators', () => { const items = [{ command: 'core:one' }, { type: 'separator' }] const expected = [{ command: 'core:one' }] expect(sortMenuItems(items)).toEqual(expected) }) + it('removes duplicate separators across sets', () => { const items = [ { command: 'core:one' }, { type: 'separator' }, @@ -43,6 +47,7 @@ describe('contextMenu', () => { expect(sortMenuItems(items)).toEqual(expected) }) }) + describe('can move an item to a different group by merging groups', () => { it('can move a group of one item', () => { const items = [ @@ -61,6 +66,7 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it("moves all items in the moving item's group", () => { const items = [ { command: 'core:one' }, @@ -80,6 +86,7 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it("ignores positions relative to commands that don't exist", () => { const items = [ { command: 'core:one' }, @@ -99,6 +106,7 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it('can handle recursive group merging', () => { const items = [ { command: 'core:one', after: ['core:three'] }, @@ -112,6 +120,7 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it('can merge multiple groups when given a list of before/after commands', () => { const items = [ { command: 'core:one' }, @@ -127,6 +136,7 @@ describe('contextMenu', () => { ] expect(sortMenuItems(items)).toEqual(expected) }) + it('can merge multiple groups based on both before/after commands', () => { const items = [ { command: 'core:one' }, @@ -143,6 +153,7 @@ describe('contextMenu', () => { expect(sortMenuItems(items)).toEqual(expected) }) }) + describe('sorts items within their ultimate group', () => { it('does a simple sort', () => { const items = [ @@ -154,6 +165,7 @@ describe('contextMenu', () => { { command: 'core:two', after: ['core:one'] } ]) }) + it('resolves cycles by ignoring things that conflict', () => { const items = [ { command: 'core:two', after: ['core:one'] }, @@ -165,6 +177,7 @@ describe('contextMenu', () => { ]) }) }) + describe('sorts groups', () => { it('does a simple sort', () => { const items = [ @@ -178,6 +191,7 @@ describe('contextMenu', () => { { command: 'core:two', afterGroupContaining: ['core:one'] } ]) }) + it('resolves cycles by ignoring things that conflict', () => { const items = [ { command: 'core:two', afterGroupContaining: ['core:one'] }, @@ -190,6 +204,7 @@ describe('contextMenu', () => { { command: 'core:two', afterGroupContaining: ['core:one'] } ]) }) + it('ignores references to commands that do not exist', () => { const items = [ { command: 'core:one' }, @@ -205,6 +220,7 @@ describe('contextMenu', () => { { command: 'core:two', afterGroupContaining: ['core:does-not-exist'] } ]) }) + it('only respects the first matching [before|after]GroupContaining rule in a given group', () => { const items = [ { command: 'core:one' }, From 2100f90cf4a60a9f58f2c0a030c1d3acc4f0f807 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 21 Feb 2018 14:55:58 -0800 Subject: [PATCH 81/90] Provide a default scope descriptor if language mode doesn't provide them --- spec/text-editor-spec.js | 8 ++++++++ src/text-editor.js | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index a9aa80cd1..69be6be32 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -6747,6 +6747,14 @@ describe('TextEditor', () => { editor.destroy() }) + describe('.scopeDescriptorForBufferPosition(position)', () => { + it('returns a default scope descriptor when no language mode is assigned', () => { + editor = new TextEditor({buffer: new TextBuffer()}) + const scopeDescriptor = editor.scopeDescriptorForBufferPosition([0, 0]) + expect(scopeDescriptor.getScopesArray()).toEqual(['text']) + }) + }) + describe('.shouldPromptToSave()', () => { beforeEach(async () => { editor = await atom.workspace.open('sample.js') diff --git a/src/text-editor.js b/src/text-editor.js index 32d3102c2..9bfa8ff3e 100644 --- a/src/text-editor.js +++ b/src/text-editor.js @@ -11,6 +11,7 @@ const Cursor = require('./cursor') const Selection = require('./selection') const NullGrammar = require('./null-grammar') const TextMateLanguageMode = require('./text-mate-language-mode') +const ScopeDescriptor = require('./scope-descriptor') const TextMateScopeSelector = require('first-mate').ScopeSelector const GutterContainer = require('./gutter-container') @@ -3655,7 +3656,10 @@ class TextEditor { // // Returns a {ScopeDescriptor}. scopeDescriptorForBufferPosition (bufferPosition) { - return this.buffer.getLanguageMode().scopeDescriptorForPosition(bufferPosition) + const languageMode = this.buffer.getLanguageMode() + return languageMode.scopeDescriptorForPosition + ? languageMode.scopeDescriptorForPosition(bufferPosition) + : new ScopeDescriptor({scopes: ['text']}) } // Extended: Get the range in buffer coordinates of all tokens surrounding the From e9d4163899824014bced676d20705aaa8242c7ad Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 21 Feb 2018 16:20:20 -0800 Subject: [PATCH 82/90] Replace csslint with stylelint (#16803) --- script/lib/lint-less-paths.js | 109 +++++++++++++++++----------------- script/package.json | 3 +- static/cursors.less | 2 +- static/docks.less | 14 +++-- stylelint.config.js | 23 +++++++ 5 files changed, 90 insertions(+), 61 deletions(-) create mode 100644 stylelint.config.js diff --git a/script/lib/lint-less-paths.js b/script/lib/lint-less-paths.js index 84e6aa3ae..c46d847c3 100644 --- a/script/lib/lint-less-paths.js +++ b/script/lib/lint-less-paths.js @@ -1,64 +1,63 @@ 'use strict' -const csslint = require('csslint').CSSLint -const expandGlobPaths = require('./expand-glob-paths') -const LessCache = require('less-cache') +const stylelint = require('stylelint') const path = require('path') -const readFiles = require('./read-files') const CONFIG = require('../config') -const LESS_CACHE_VERSION = require('less-cache/package.json').version module.exports = function () { - const globPathsToLint = [ - path.join(CONFIG.repositoryRootPath, 'static/**/*.less') - ] - const lintOptions = { - 'adjoining-classes': false, - 'duplicate-background-images': false, - 'box-model': false, - 'box-sizing': false, - 'bulletproof-font-face': false, - 'compatible-vendor-prefixes': false, - 'display-property-grouping': false, - 'duplicate-properties': false, - 'fallback-colors': false, - 'font-sizes': false, - 'gradients': false, - 'ids': false, - 'important': false, - 'known-properties': false, - 'order-alphabetical': false, - 'outline-none': false, - 'overqualified-elements': false, - 'regex-selectors': false, - 'qualified-headings': false, - 'unique-headings': false, - 'universal-selector': false, - 'vendor-prefix': false - } - for (let rule of csslint.getRules()) { - if (!lintOptions.hasOwnProperty(rule.id)) lintOptions[rule.id] = true - } - const lessCache = new LessCache({ - cacheDir: path.join(CONFIG.intermediateAppPath, 'less-compile-cache'), - fallbackDir: path.join(CONFIG.atomHomeDirPath, 'compile-cache', 'prebuild-less', LESS_CACHE_VERSION), - syncCaches: true, - resourcePath: CONFIG.repositoryRootPath, - importPaths: [ - path.join(CONFIG.intermediateAppPath, 'static', 'variables'), - path.join(CONFIG.intermediateAppPath, 'static') - ] - }) - return expandGlobPaths(globPathsToLint).then(readFiles).then((files) => { - const errors = [] - for (let file of files) { - const css = lessCache.cssForFile(file.path, file.content) - const result = csslint.verify(css, lintOptions) - for (let message of result.messages) { - errors.push({path: file.path.replace(/\.less$/, '.css'), lineNumber: message.line, message: message.message, rule: message.rule.id}) + return stylelint + .lint({ + files: path.join(CONFIG.repositoryRootPath, 'static/**/*.less'), + configBasedir: __dirname, + configFile: path.resolve(__dirname, '..', '..', 'stylelint.config.js') + }) + .then(({results}) => { + const errors = [] + + for (const result of results) { + for (const deprecation of result.deprecations) { + console.log('stylelint encountered deprecation:', deprecation.text) + if (deprecation.reference != null) { + console.log('more information at', deprecation.reference) + } + } + + for (const invalidOptionWarning of result.invalidOptionWarnings) { + console.warn( + 'stylelint encountered invalid option:', + invalidOptionWarning.text + ) + } + + if (result.errored) { + for (const warning of result.warnings) { + if (warning.severity === 'error') { + errors.push({ + path: result.source, + lineNumber: warning.line, + message: warning.text, + rule: warning.rule + }) + } else { + console.warn( + 'stylelint encountered non-critical warning in file', + result.source, + 'at line', + warning.line, + 'for rule', + warning.rule + ':', + warning.text + ) + } + } + } } - } - return errors - }) + + return errors + }) + .catch(err => { + console.error('There was a problem linting LESS:') + throw err + }) } diff --git a/script/package.json b/script/package.json index a4d2a052f..5946496ef 100644 --- a/script/package.json +++ b/script/package.json @@ -6,7 +6,6 @@ "babel-core": "5.8.38", "coffeelint": "1.15.7", "colors": "1.1.2", - "csslint": "1.0.2", "donna": "1.0.16", "electron-chromedriver": "~1.7", "electron-link": "0.1.2", @@ -31,6 +30,8 @@ "season": "5.3.0", "semver": "5.3.0", "standard": "8.4.0", + "stylelint": "^9.0.0", + "stylelint-config-standard": "^18.1.0", "sync-request": "3.0.1", "tello": "1.0.7", "webdriverio": "2.4.5", diff --git a/static/cursors.less b/static/cursors.less index 5cbfadef6..843dab2c6 100644 --- a/static/cursors.less +++ b/static/cursors.less @@ -8,7 +8,7 @@ @ibeam-2x: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC'); .cursor-white() { - cursor: -webkit-image-set(@ibeam-1x 1x, @ibeam-2x 2x) 5 8, text; + cursor: -webkit-image-set(@ibeam-1x 1dppx, @ibeam-2x 2dppx) 5 8, text; } // Editors diff --git a/static/docks.less b/static/docks.less index 283402e09..ccbb4e903 100644 --- a/static/docks.less +++ b/static/docks.less @@ -113,10 +113,16 @@ atom-dock { // Promote to own layer, fixes rendering issue atom/atom#14915 will-change: transform; - &.right { left: 0; } - &.bottom { top: 0; } - &.left { right: 0; } - } + &.right { + left: 0; + } + &.bottom { + top: 0; + } + &.left { + right: 0; + } + } // Hide the button. &:not(.atom-dock-toggle-button-visible) { diff --git a/stylelint.config.js b/stylelint.config.js new file mode 100644 index 000000000..49caab46d --- /dev/null +++ b/stylelint.config.js @@ -0,0 +1,23 @@ +const path = require('path'); + +module.exports = { + "extends": "stylelint-config-standard", + "ignoreFiles": [path.resolve(__dirname, "static", "atom.less")], + "rules": { + "color-hex-case": null, // TODO: enable? + "max-empty-lines": null, // TODO: enable? + "selector-type-no-unknown": null, + "function-comma-space-after": null, // TODO: enable? + "font-family-no-missing-generic-family-keyword": null, // needed for octicons (no sensible fallback) + "declaration-empty-line-before": null, // TODO: enable? + "declaration-block-trailing-semicolon": null, // TODO: enable + "no-descending-specificity": null, + "number-leading-zero": null, // TODO: enable? + "no-duplicate-selectors": null, + "selector-pseudo-element-colon-notation": null, // TODO: enable? + "selector-list-comma-newline-after": null, // TODO: enable? + "rule-empty-line-before": null, // TODO: enable? + "at-rule-empty-line-before": null, // TODO: enable? + "font-family-no-duplicate-names": null, // TODO: enable? + } +} From b42972fa84ecd897e59b48437cf4b0d1e74a69eb Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 21 Feb 2018 19:02:14 -0800 Subject: [PATCH 83/90] Add custom properties to atom-workspace to track editor properties (#16731) * Add custom properties to atom-workspace These track the editor's current font size, font family, and line height. * Move editor styles to text-editor; add monospace fallback * Add default font family So that there will always be a valid value. * Fix specs --- src/config-schema.js | 2 +- src/workspace-element.js | 8 ++++---- static/text-editor.less | 9 ++++++++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/config-schema.js b/src/config-schema.js index d75777bff..97a6d16f3 100644 --- a/src/config-schema.js +++ b/src/config-schema.js @@ -380,7 +380,7 @@ const configSchema = { // These can be used as globals or scoped, thus defaults. fontFamily: { type: 'string', - default: '', + default: 'Menlo, Consolas, DejaVu Sans Mono, monospace', description: 'The name of the font family used for editor text.' }, fontSize: { diff --git a/src/workspace-element.js b/src/workspace-element.js index c9a30af85..cd5c1b746 100644 --- a/src/workspace-element.js +++ b/src/workspace-element.js @@ -56,10 +56,10 @@ class WorkspaceElement extends HTMLElement { } updateGlobalTextEditorStyleSheet () { - const styleSheetSource = `atom-text-editor { - font-size: ${this.config.get('editor.fontSize')}px; - font-family: ${this.config.get('editor.fontFamily')}; - line-height: ${this.config.get('editor.lineHeight')}; + const styleSheetSource = `atom-workspace { + --editor-font-size: ${this.config.get('editor.fontSize')}px; + --editor-font-family: ${this.config.get('editor.fontFamily')}; + --editor-line-height: ${this.config.get('editor.lineHeight')}; }` this.styleManager.addStyleSheet(styleSheetSource, {sourcePath: 'global-text-editor-styles', priority: -1}) } diff --git a/static/text-editor.less b/static/text-editor.less index 21cba8482..99f198512 100644 --- a/static/text-editor.less +++ b/static/text-editor.less @@ -2,10 +2,17 @@ @import "octicon-utf-codes"; @import "octicon-mixins"; +:root { + // Fixes specs + --editor-font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; +} + atom-text-editor { display: flex; - font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; cursor: text; + font-family: var(--editor-font-family); + font-size: var(--editor-font-size); + line-height: var(--editor-line-height); .gutter-container { width: min-content; From c9f9b5d1e5780d7326d5e5df9aeef583e694bab6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 22 Feb 2018 12:51:02 -0800 Subject: [PATCH 84/90] :arrow_up: settings-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 57b81bc1c..1a071cc4d 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "notifications": "0.70.2", "open-on-github": "1.3.1", "package-generator": "1.3.0", - "settings-view": "0.254.0", + "settings-view": "0.254.1", "snippets": "1.3.1", "spell-check": "0.72.7", "status-bar": "1.8.15", From 138115f2a8752e6d7198fefce9e563d994e7b1e2 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Thu, 22 Feb 2018 12:21:21 -0800 Subject: [PATCH 85/90] :bug: Handle empty username If Atom is launched in a shell that is missing the `USER`/`USERNAME` environment variable it locks up due to an unhandled error from `crypto.update`. This switches to using Node.js's built in `os.userInfo()` method to retrieve the current user name, allowing Atom to complete initialization in this scenario. Fixes #16821. --- src/main-process/atom-application.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 8f98ae4a5..43722e401 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -33,7 +33,7 @@ class AtomApplication extends EventEmitter { // Public: The entry point into the Atom application. static open (options) { if (!options.socketPath) { - const username = process.platform === 'win32' ? process.env.USERNAME : process.env.USER + const {username} = os.userInfo() // Lowercasing the ATOM_HOME to make sure that we don't get multiple sockets // on case-insensitive filesystems due to arbitrary case differences in paths. @@ -44,7 +44,7 @@ class AtomApplication extends EventEmitter { .update('|') .update(process.arch) .update('|') - .update(username) + .update(username || '') .update('|') .update(atomHomeUnique) From 74ea91ab2e951537ece1558eab92adb9850f9e5f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 22 Feb 2018 13:26:56 -0800 Subject: [PATCH 86/90] Fix snapshot blacklist for request module --- script/lib/generate-startup-snapshot.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script/lib/generate-startup-snapshot.js b/script/lib/generate-startup-snapshot.js index 1078ab20e..8c33e5494 100644 --- a/script/lib/generate-startup-snapshot.js +++ b/script/lib/generate-startup-snapshot.js @@ -32,6 +32,8 @@ module.exports = function (packagedAppPath) { relativePath.endsWith(path.join('node_modules', 'graceful-fs', 'graceful-fs.js')) || relativePath.endsWith(path.join('node_modules', 'htmlparser2', 'lib', 'index.js')) || relativePath.endsWith(path.join('node_modules', 'minimatch', 'minimatch.js')) || + relativePath.endsWith(path.join('node_modules', 'request', 'index.js')) || + relativePath.endsWith(path.join('node_modules', 'request', 'request.js')) || relativePath === path.join('..', 'exports', 'atom.js') || relativePath === path.join('..', 'src', 'electron-shims.js') || relativePath === path.join('..', 'src', 'safe-clipboard.js') || @@ -50,7 +52,6 @@ module.exports = function (packagedAppPath) { relativePath === path.join('..', 'node_modules', 'node-fetch', 'lib', 'fetch-error.js') || relativePath === path.join('..', 'node_modules', 'superstring', 'index.js') || relativePath === path.join('..', 'node_modules', 'oniguruma', 'src', 'oniguruma.js') || - relativePath === path.join('..', 'node_modules', 'request', 'index.js') || relativePath === path.join('..', 'node_modules', 'resolve', 'index.js') || relativePath === path.join('..', 'node_modules', 'resolve', 'lib', 'core.js') || relativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'glob', 'glob.js') || From 880148259f84a62c7fca39711573de337e0f432c Mon Sep 17 00:00:00 2001 From: Matthew Dapena-Tretter Date: Fri, 23 Feb 2018 14:08:09 -0800 Subject: [PATCH 87/90] Convert PaneContainerElement and PaneElement to JS --- src/pane-container-element.coffee | 28 ---- src/pane-container-element.js | 40 ++++++ src/pane-element.coffee | 139 ------------------- src/pane-element.js | 218 ++++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 167 deletions(-) delete mode 100644 src/pane-container-element.coffee create mode 100644 src/pane-container-element.js delete mode 100644 src/pane-element.coffee create mode 100644 src/pane-element.js diff --git a/src/pane-container-element.coffee b/src/pane-container-element.coffee deleted file mode 100644 index 78e2fbad3..000000000 --- a/src/pane-container-element.coffee +++ /dev/null @@ -1,28 +0,0 @@ -{CompositeDisposable} = require 'event-kit' -_ = require 'underscore-plus' - -module.exports = -class PaneContainerElement extends HTMLElement - createdCallback: -> - @subscriptions = new CompositeDisposable - @classList.add 'panes' - - initialize: (@model, {@views}) -> - throw new Error("Must pass a views parameter when initializing PaneContainerElements") unless @views? - - @subscriptions.add @model.observeRoot(@rootChanged.bind(this)) - this - - rootChanged: (root) -> - focusedElement = document.activeElement if @hasFocus() - @firstChild?.remove() - if root? - view = @views.getView(root) - @appendChild(view) - focusedElement?.focus() - - hasFocus: -> - this is document.activeElement or @contains(document.activeElement) - - -module.exports = PaneContainerElement = document.registerElement 'atom-pane-container', prototype: PaneContainerElement.prototype diff --git a/src/pane-container-element.js b/src/pane-container-element.js new file mode 100644 index 000000000..7a2a88463 --- /dev/null +++ b/src/pane-container-element.js @@ -0,0 +1,40 @@ +const {CompositeDisposable} = require('event-kit') + +class PaneContainerElement extends HTMLElement { + createdCallback () { + this.subscriptions = new CompositeDisposable() + this.classList.add('panes') + } + + initialize (model, {views}) { + this.model = model + this.views = views + if (this.views == null) { + throw new Error('Must pass a views parameter when initializing PaneContainerElements') + } + this.subscriptions.add(this.model.observeRoot(this.rootChanged.bind(this))) + return this + } + + rootChanged (root) { + const focusedElement = this.hasFocus() ? document.activeElement : null + if (this.firstChild != null) { + this.firstChild.remove() + } + if (root != null) { + const view = this.views.getView(root) + this.appendChild(view) + if (focusedElement != null) { + focusedElement.focus() + } + } + } + + hasFocus () { + return this === document.activeElement || this.contains(document.activeElement) + } +} + +module.exports = document.registerElement('atom-pane-container', { + prototype: PaneContainerElement.prototype +}) diff --git a/src/pane-element.coffee b/src/pane-element.coffee deleted file mode 100644 index d68b3b834..000000000 --- a/src/pane-element.coffee +++ /dev/null @@ -1,139 +0,0 @@ -path = require 'path' -{CompositeDisposable} = require 'event-kit' - -class PaneElement extends HTMLElement - attached: false - - createdCallback: -> - @attached = false - @subscriptions = new CompositeDisposable - @inlineDisplayStyles = new WeakMap - - @initializeContent() - @subscribeToDOMEvents() - - attachedCallback: -> - @attached = true - @focus() if @model.isFocused() - - detachedCallback: -> - @attached = false - - initializeContent: -> - @setAttribute 'class', 'pane' - @setAttribute 'tabindex', -1 - @appendChild @itemViews = document.createElement('div') - @itemViews.setAttribute 'class', 'item-views' - - subscribeToDOMEvents: -> - handleFocus = (event) => - @model.focus() unless @isActivating or @model.isDestroyed() or @contains(event.relatedTarget) - if event.target is this and view = @getActiveView() - view.focus() - event.stopPropagation() - - handleBlur = (event) => - @model.blur() unless @contains(event.relatedTarget) - - handleDragOver = (event) -> - event.preventDefault() - event.stopPropagation() - - handleDrop = (event) => - event.preventDefault() - event.stopPropagation() - @getModel().activate() - pathsToOpen = Array::map.call event.dataTransfer.files, (file) -> file.path - @applicationDelegate.open({pathsToOpen}) if pathsToOpen.length > 0 - - @addEventListener 'focus', handleFocus, true - @addEventListener 'blur', handleBlur, true - @addEventListener 'dragover', handleDragOver - @addEventListener 'drop', handleDrop - - initialize: (@model, {@views, @applicationDelegate}) -> - throw new Error("Must pass a views parameter when initializing PaneElements") unless @views? - throw new Error("Must pass an applicationDelegate parameter when initializing PaneElements") unless @applicationDelegate? - - @subscriptions.add @model.onDidActivate(@activated.bind(this)) - @subscriptions.add @model.observeActive(@activeStatusChanged.bind(this)) - @subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this)) - @subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this)) - @subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this)) - @subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this)) - this - - getModel: -> @model - - activated: -> - @isActivating = true - @focus() unless @hasFocus() # Don't steal focus from children. - @isActivating = false - - activeStatusChanged: (active) -> - if active - @classList.add('active') - else - @classList.remove('active') - - activeItemChanged: (item) -> - delete @dataset.activeItemName - delete @dataset.activeItemPath - @changePathDisposable?.dispose() - - return unless item? - - hasFocus = @hasFocus() - itemView = @views.getView(item) - - if itemPath = item.getPath?() - @dataset.activeItemName = path.basename(itemPath) - @dataset.activeItemPath = itemPath - - if item.onDidChangePath? - @changePathDisposable = item.onDidChangePath => - itemPath = item.getPath() - @dataset.activeItemName = path.basename(itemPath) - @dataset.activeItemPath = itemPath - - unless @itemViews.contains(itemView) - @itemViews.appendChild(itemView) - - for child in @itemViews.children - if child is itemView - @showItemView(child) if @attached - else - @hideItemView(child) - - itemView.focus() if hasFocus - - showItemView: (itemView) -> - inlineDisplayStyle = @inlineDisplayStyles.get(itemView) - if inlineDisplayStyle? - itemView.style.display = inlineDisplayStyle - else - itemView.style.display = '' - - hideItemView: (itemView) -> - inlineDisplayStyle = itemView.style.display - unless inlineDisplayStyle is 'none' - @inlineDisplayStyles.set(itemView, inlineDisplayStyle) if inlineDisplayStyle? - itemView.style.display = 'none' - - itemRemoved: ({item, index, destroyed}) -> - if viewToRemove = @views.getView(item) - viewToRemove.remove() - - paneDestroyed: -> - @subscriptions.dispose() - @changePathDisposable?.dispose() - - flexScaleChanged: (flexScale) -> - @style.flexGrow = flexScale - - getActiveView: -> @views.getView(@model.getActiveItem()) - - hasFocus: -> - this is document.activeElement or @contains(document.activeElement) - -module.exports = PaneElement = document.registerElement 'atom-pane', prototype: PaneElement.prototype diff --git a/src/pane-element.js b/src/pane-element.js new file mode 100644 index 000000000..2c9f4eeef --- /dev/null +++ b/src/pane-element.js @@ -0,0 +1,218 @@ +const path = require('path') +const {CompositeDisposable} = require('event-kit') + +class PaneElement extends HTMLElement { + createdCallback () { + this.attached = false + this.subscriptions = new CompositeDisposable() + this.inlineDisplayStyles = new WeakMap() + this.initializeContent() + this.subscribeToDOMEvents() + } + + attachedCallback () { + this.attached = true + if (this.model.isFocused()) { + this.focus() + } + } + + detachedCallback () { + this.attached = false + } + + initializeContent () { + this.setAttribute('class', 'pane') + this.setAttribute('tabindex', -1) + this.itemViews = document.createElement('div') + this.appendChild(this.itemViews) + this.itemViews.setAttribute('class', 'item-views') + } + + subscribeToDOMEvents () { + const handleFocus = event => { + if ( + !( + this.isActivating || + this.model.isDestroyed() || + this.contains(event.relatedTarget) + ) + ) { + this.model.focus() + } + if (event.target !== this) return + const view = this.getActiveView() + if (view) { + view.focus() + event.stopPropagation() + } + } + const handleBlur = event => { + if (!this.contains(event.relatedTarget)) { + this.model.blur() + } + } + const handleDragOver = event => { + event.preventDefault() + event.stopPropagation() + } + const handleDrop = event => { + event.preventDefault() + event.stopPropagation() + this.getModel().activate() + const pathsToOpen = [...event.dataTransfer.files].map(file => file.path) + if (pathsToOpen.length > 0) { + this.applicationDelegate.open({pathsToOpen}) + } + } + this.addEventListener('focus', handleFocus, true) + this.addEventListener('blur', handleBlur, true) + this.addEventListener('dragover', handleDragOver) + this.addEventListener('drop', handleDrop) + } + + initialize (model, {views, applicationDelegate}) { + this.model = model + this.views = views + this.applicationDelegate = applicationDelegate + if (this.views == null) { + throw new Error( + 'Must pass a views parameter when initializing PaneElements' + ) + } + if (this.applicationDelegate == null) { + throw new Error( + 'Must pass an applicationDelegate parameter when initializing PaneElements' + ) + } + this.subscriptions.add(this.model.onDidActivate(this.activated.bind(this))) + this.subscriptions.add( + this.model.observeActive(this.activeStatusChanged.bind(this)) + ) + this.subscriptions.add( + this.model.observeActiveItem(this.activeItemChanged.bind(this)) + ) + this.subscriptions.add( + this.model.onDidRemoveItem(this.itemRemoved.bind(this)) + ) + this.subscriptions.add( + this.model.onDidDestroy(this.paneDestroyed.bind(this)) + ) + this.subscriptions.add( + this.model.observeFlexScale(this.flexScaleChanged.bind(this)) + ) + return this + } + + getModel () { + return this.model + } + + activated () { + this.isActivating = true + if (!this.hasFocus()) { + // Don't steal focus from children. + this.focus() + } + this.isActivating = false + } + + activeStatusChanged (active) { + if (active) { + this.classList.add('active') + } else { + this.classList.remove('active') + } + } + + activeItemChanged (item) { + delete this.dataset.activeItemName + delete this.dataset.activeItemPath + if (this.changePathDisposable != null) { + this.changePathDisposable.dispose() + } + if (item == null) { + return + } + const hasFocus = this.hasFocus() + const itemView = this.views.getView(item) + const itemPath = typeof item.getPath === 'function' ? item.getPath() : null + if (itemPath) { + this.dataset.activeItemName = path.basename(itemPath) + this.dataset.activeItemPath = itemPath + if (item.onDidChangePath != null) { + this.changePathDisposable = item.onDidChangePath(() => { + const itemPath = item.getPath() + this.dataset.activeItemName = path.basename(itemPath) + this.dataset.activeItemPath = itemPath + }) + } + } + if (!this.itemViews.contains(itemView)) { + this.itemViews.appendChild(itemView) + } + for (const child of this.itemViews.children) { + if (child === itemView) { + if (this.attached) { + this.showItemView(child) + } + } else { + this.hideItemView(child) + } + } + if (hasFocus) { + itemView.focus() + } + } + + showItemView (itemView) { + const inlineDisplayStyle = this.inlineDisplayStyles.get(itemView) + if (inlineDisplayStyle != null) { + itemView.style.display = inlineDisplayStyle + } else { + itemView.style.display = '' + } + } + + hideItemView (itemView) { + const inlineDisplayStyle = itemView.style.display + if (inlineDisplayStyle !== 'none') { + if (inlineDisplayStyle != null) { + this.inlineDisplayStyles.set(itemView, inlineDisplayStyle) + } + itemView.style.display = 'none' + } + } + + itemRemoved ({item, index, destroyed}) { + const viewToRemove = this.views.getView(item) + if (viewToRemove) { + viewToRemove.remove() + } + } + + paneDestroyed () { + this.subscriptions.dispose() + if (this.changePathDisposable != null) { + this.changePathDisposable.dispose() + } + } + + flexScaleChanged (flexScale) { + this.style.flexGrow = flexScale + } + + getActiveView () { + return this.views.getView(this.model.getActiveItem()) + } + + hasFocus () { + return ( + this === document.activeElement || this.contains(document.activeElement) + ) + } +} + +module.exports = document.registerElement('atom-pane', { + prototype: PaneElement.prototype +}) From 94fed2f97c2c819724959d319009261f2c240013 Mon Sep 17 00:00:00 2001 From: Jasper David Rogers Date: Mon, 26 Feb 2018 07:28:07 -0500 Subject: [PATCH 88/90] Adding the Discussion --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0c10b1352..1f423cb05 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,10 @@ repeat these steps to upgrade to future releases. * [macOS](https://flight-manual.atom.io/hacking-atom/sections/hacking-on-atom-core/#platform-mac) * [Windows](https://flight-manual.atom.io/hacking-atom/sections/hacking-on-atom-core/#platform-windows) +# discussion +* Post questions and get answers on our [Fourms](https://discuss.atom.io/) +* Real time text, video and voice chat to ask, answer and share your workspace on [Slack](https://atomio.slack.com/) + ## License [MIT](https://github.com/atom/atom/blob/master/LICENSE.md) From 698f06016fffd0c1995badb32dd398c8c279c76b Mon Sep 17 00:00:00 2001 From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com> Date: Mon, 26 Feb 2018 07:13:42 -0800 Subject: [PATCH 89/90] Clarify and clean up --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1f423cb05..b0d8a6504 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,10 @@ repeat these steps to upgrade to future releases. * [macOS](https://flight-manual.atom.io/hacking-atom/sections/hacking-on-atom-core/#platform-mac) * [Windows](https://flight-manual.atom.io/hacking-atom/sections/hacking-on-atom-core/#platform-windows) -# discussion -* Post questions and get answers on our [Fourms](https://discuss.atom.io/) -* Real time text, video and voice chat to ask, answer and share your workspace on [Slack](https://atomio.slack.com/) +## Discussion + +* Discuss Atom on our [forums](https://discuss.atom.io/) +* Chat about Atom on our Slack team -- [instructions for joining](https://discuss.atom.io/t/join-us-on-slack/16638?source_topic_id=25406) ## License From 8cb08edda001deb216944331498eab1b88b2f503 Mon Sep 17 00:00:00 2001 From: Bryant Ung Date: Mon, 26 Feb 2018 13:40:48 -0800 Subject: [PATCH 90/90] :arrow_up: autocomplete-plus --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a071cc4d..2ac3c966b 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "autocomplete-atom-api": "0.10.7", "autocomplete-css": "0.17.5", "autocomplete-html": "0.8.4", - "autocomplete-plus": "2.40.3", + "autocomplete-plus": "2.40.4", "autocomplete-snippets": "1.12.0", "autoflow": "0.29.3", "autosave": "0.24.6",