Merge branch 'master' into fb-pw-simple-project-config

This commit is contained in:
Philip Weiss
2018-03-09 14:06:14 -08:00
committed by GitHub
21 changed files with 383 additions and 112 deletions

43
docs/focus/2018-02-26.md Normal file
View File

@@ -0,0 +1,43 @@
## Highlights from the past week
- Atom IDE
- TypeScript conversion fully cleaned up, types ready for definitely typed
- Started work on AutoComplete rewrites to address poor filtering and over-eager pop-up
- Review of code actions integration (currently on ide-java)
- @atom/watcher
- GitHub Package
- Loads of [planning and process](https://github.com/atom/github/blob/master/docs/how-we-work.md)
- Recent commit history [RFC](https://github.com/atom/github/pull/1318) and [implementation](https://github.com/atom/github/pull/1322)
- Port another few components from Etch to React in preparation for :point_up:
- Wrestle with a few [flaky](https://github.com/atom/github/pull/1289) [tests](https://github.com/atom/github/pull/1320) to get our [build](https://github.com/atom/github/pull/1317) under control.
- Teletype
- Tree-sitter
- Finally wrote some documentation about Tree-sitter and how to develop parsers, now that members of the Atom community are starting to contribute to parsers.
- Xray
- We finished off some up-front planning around Xray's support for real time collaboration.
- We're now comfortably scrolling a dev-build of React at 60 frames per second. Frames are rendered in about 1.2ms per frame on our hardware, and rendering is looking identical to Chrome's CPU backend for basic ASCII text, modulo ligatures and kerning. We still have a lot of features to add, but we don't any of them will dramatically impact frame computation time.
- Reactor Duty
- Discovered root cause of Windows test failures in [atom/tree-view#1203](https://github.com/atom/tree-view/issues/1203), discussed in-progress fix with @50wliu
## Focus for week ahead
- Atom IDE
- Complete work on AutoComplete improvements
- Stop cancellations for autocomplete and outline throwing errors in the logs
- Investigate workspace symbol user interface
- @atom/watcher
- Diagnose crashes and lockups on Atom launch
- GitHub Package
- Recent commit implementation: land a [read-only view of the most recent commits](https://github.com/atom/github/pull/1322).
- Port [CommitViewController and CommitView to React](https://github.com/atom/github/pull/1325).
- Write up `docs/vision` from meeting notes.
- Begin on ["remember me"](https://github.com/atom/github/issues/861) for the git credential helper.
- Teletype
- Tree-sitter
- Optimizing syntax tree updates in the presence of syntax errors. This will improve performance across the board but also make Tree-sitter usable in edge cases where the wrong language is being used to parse a document.
- Xray
- @as-cii will be focused on more sophisticated text-shaping to extend our support beyond basic ASCII. We're working on a [glyph-renderer](https://github.com/atom/xray/tree/glyph-renderer) module that handles text layout and glyph rasterization. To support a standalone web-based component, we're starting with a WebAssembly module based on HarfBuzz and FreeType, but we can always explore using platform-specific frameworks for the Electron use case.
- @nathansobo will be focused on implementing selections. We're introducing a new "anchor" abstraction that creates a stable reference to a buffer location, along with methods for converting anchors to offsets or points. Each editor will store selections as a sorted array of anchor ranges. To move a selection, we'll convert its anchors to concrete points, adjust their rows/columns, then convert the points back to anchors. We're curious how long it will take us to do this for thousands of selections. Hopefully it's fast. Then we'll focus on inserting text inside the selections.
- Reactor Duty
- Investigate dock pane dragging regression [atom/atom#16769](https://github.com/atom/atom/issues/16769)
- Merge PR [atom/node-keytar#67](https://github.com/atom/node-keytar/pull/67)

55
docs/focus/2018-03-05.md Normal file
View File

@@ -0,0 +1,55 @@
## Highlights from the past week
- Atom IDE
- Console logging started
- IDE-Java/PHP/TypeScript updates and fixes
- GitHub Package
- Recent commits view, read-only mode :tm: (@kuychaco, @smashwilson, @simurai) [#1322](https://github.com/atom/github/pull/1322)
- Recent commits view: show co-authors (@kuychaco, @simurai)
- Commit interactions research spike: undo most recent, amend (@kuychaco) [#1328](https://github.com/atom/github/pull/1328)
- Port CommitView and CommitController to React. (@smashwilson) [#1325](https://github.com/atom/github/pull/1325)
- Begin "Remember me" within the credential dialog [#1327](https://github.com/atom/github/pull/1327)
- Tree-sitter
- Shifted focus to address some open-source contributions to parsers:
- Wrote documentation about how to create parsers: http://tree-sitter.github.io/tree-sitter
- Fixed issues with the Bash parser
- Fixed a bug found during constant fuzzing by the security team: https://github.com/tree-sitter/tree-sitter/issues/133
- Xray
- Decided not to run all text through HarfBuzz for performance reasons, and came up with a plan for addressing mandatory text shaping issues in the future.
- Implemented anchors, selections, and basic selection movement.
- Partially implemented selection rendering.
- For more details, see the [detailed update](https://github.com/atom/xray/blob/master/docs/updates/2018_03_05.md) in the Xray repository.
- Engineering Improvements
- Automated Linux package repository publishing as part of Atom release process
- Reactor Duty
- Shipped node-keytar update, primary feature being prebuilt node modules ([atom/node-keytar#67](https://github.com/atom/node-keytar/pull/67))
- Merged community pull requests to atom/atom-select-list, atom/command-palette, and atom/tree-view
## Focus for week ahead
- Atom IDE
- Console logging completion
- Investigate language server process hanging on deactivation in ide-typescript
- Investigate using the new native LSP support in omnisharp-roslyn in ide-csharp
- @atom/watcher
- Diagnose crashes and lockups on Atom launch (@smashwilson)
- GitHub Package
- Finish "Remember me" within the credential dialog (@smashwilson) [#1327](https://github.com/atom/github/pull/1327)
- Write up `docs/vision` from meeting notes (@smashwilson)
- Kick-start our GPG pinentry handling (@smashwilson) [#846](https://github.com/atom/github/pull/846)
- Build UI for adding co-authors, much like Desktop's UI/UX - desktop.github.com/features/co-authors/
- Teletype
- Open pull request for the avatar UX enhancements described in ([atom/teletype#268](https://github.com/atom/teletype/issues/268))
- Tree-sitter
- Carrying over goals from previous weeks:
- Optimize syntax tree updates in the presence of syntax errors. This will improve performance across the board but also make Tree-sitter usable in edge cases where the wrong language is being used to parse a document.
- Start work on allowing parsing to take place on a background thread
- Xray
- Finish selection rendering
- Wire up enough of the key bindings / commands system to move cursors/selections
- Start on editing
- For more details, see [the detailed update](https://github.com/atom/xray/blob/master/docs/updates/2018_03_05.md)
- Engineering Improvements
- Finish new Atom release publishing automation
- Reactor Duty

103
docs/focus/README.md Normal file
View File

@@ -0,0 +1,103 @@
# Near-term plans
In this directory, you'll find weekly progress and plans from the core Atom team at GitHub. In addition, this document summarizes the work we're intending to prioritize within the next several months.
* [Atom IDE](#atom-ide)
* [GitHub package](#github-package)
* [Teletype](#teletype)
* [Tree-sitter](#tree-sitter)
* [Xray](#xray)
---
# Atom IDE
## Roadmap
## Looking ahead
---
# GitHub package
- [atom/github](http://github.com/atom/github) (Atom package)
## Roadmap
Watch our progress on the [short-term roadmap project](https://github.com/atom/github/projects/8).
##### Recent commit history
_Near-term goal:_ An informational view that displays the most recent 1-3 commits beneath the mini commit message editor. Design and discussion in: [#554](https://github.com/atom/github/issues/554), [#86](https://github.com/atom/github/issues/86).
_Longer-term goals:_ Introduce interactivity to the commits shown in the recent history list. Right-click on the top click to amend it, or on prior commits to reset. Overhaul the "amend button" functionality and implementation.
##### Commit co-authoring
_Near-term goal:_ Allow users to specify co-authors when committing. Draw inspiration from [Desktop's implementation](https://github.com/desktop/desktop/pull/3879) for UI. Tracking issue: [#1309](https://github.com/atom/github/issues/1309).
_Longer-term goals:_ Expose an API so that packages like teletype can add portal participants to commits automatically. Tangentially related to [#1089](https://github.com/atom/github/issues/1089).
##### Pull request workflow - Create Pull Request
_Near-term goal:_ Add buttons in the GitHub panel to allow users to push any unpushed changes and open new pull requests. The "Open new pull request" button will link to the github.com compare view in browser. Open pull request: [#1138](https://github.com/atom/github/pull/1138).
_Longer-term goals:_ Offer a complete in-editor experience. Compose pull request titles and descriptions in the GitHub dock item. However, we wish to avoid needing replicating the full .com experience, so to specify labels, projects, or milestones, we will preserve the "navigate browser to compare view" functionality, and focus on text composition.
This will require building out UI in the GitHub panel and adding GraphQL API support to create pull requests.
UI/UX considerations include:
* Offer a pop-out editor to craft PR descriptions in a full pane, similar to the commit editor pop out.
* Allow the user to specify the merge target.
* Show a preview of the list of commits that would be introduced by PR.
##### Build stability
_Near-term goal:_ Fix that damn Travis hang documented in [#1119](https://github.com/atom/github/issues/1119). Resume the diagnosis work in [#1289](https://github.com/atom/github/pull/1289) and find a way to bring our build success rate back under control.
##### GPG and credential handler overhaul
_Near-term goals:_ Passphrase prompting from git credential helpers and GPG has been a significant pain point since public release; unsurprisingly, because those are the areas where we need to leverage binaries and configuration from the users' system if present.
* Implement a "remember me" checkbox backed by keytar. This is probably our top feature request. [#861](https://github.com/atom/github/issues/861)
_Longer-term goals:_ Finish the credential handler refactor begun in [#846](https://github.com/atom/github/pull/846) to handle GPG 1.x through 2.3 and include diagnostic logging and testing.
* Improve our handling of 2FA credentials. Ideally we could detect when a user has 2FA enabled and prompt for a one-time code. [#844](https://github.com/atom/github/issues/844)
## Looking ahead
In no particular order:
- Git Virtual File System support.
- Improved branch management. [#556](https://github.com/atom/github/issues/556)
- Introduce an overview dock item that summarizes and navigates to other functionality. [#1018](https://github.com/atom/github/issues/1018)
- Code review. [#269](https://github.com/atom/github/issues/269), [#268](https://github.com/atom/github/issues/268)
- `git log` pane.
- Merge or close pull requests.
- Browse and check out pull requests.
---
# Teletype
## Roadmap
## Looking ahead
---
# Tree-sitter
## Roadmap
## Looking ahead
---
# Xray
## Roadmap
## Looking ahead

View File

@@ -85,8 +85,8 @@
"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.11",
"one-light-ui": "1.10.11",
"one-dark-ui": "1.11.0",
"one-light-ui": "1.11.0",
"one-dark-syntax": "1.8.2",
"one-light-syntax": "1.8.2",
"solarized-dark-syntax": "1.1.4",
@@ -96,22 +96,22 @@
"autocomplete-atom-api": "0.10.7",
"autocomplete-css": "0.17.5",
"autocomplete-html": "0.8.4",
"autocomplete-plus": "2.40.4",
"autocomplete-plus": "2.40.5",
"autocomplete-snippets": "1.12.0",
"autoflow": "0.29.3",
"autosave": "0.24.6",
"background-tips": "0.28.0",
"bookmarks": "0.45.1",
"bracket-matcher": "0.89.1",
"command-palette": "0.43.4",
"dalek": "0.2.1",
"command-palette": "0.43.5",
"dalek": "0.2.2",
"deprecation-cop": "0.56.9",
"dev-live-reload": "0.48.1",
"encoding-selector": "0.23.8",
"exception-reporting": "0.43.1",
"find-and-replace": "0.215.5",
"fuzzy-finder": "1.7.6",
"github": "0.10.1",
"fuzzy-finder": "1.8.0",
"github": "0.11.0",
"git-diff": "1.3.9",
"go-to-line": "0.33.0",
"grammar-selector": "0.50.0",
@@ -125,7 +125,7 @@
"notifications": "0.70.2",
"open-on-github": "1.3.1",
"package-generator": "1.3.0",
"settings-view": "0.254.1",
"settings-view": "0.254.2",
"snippets": "1.3.1",
"spell-check": "0.72.7",
"status-bar": "1.8.15",
@@ -148,29 +148,29 @@
"language-go": "0.45.2",
"language-html": "0.49.0",
"language-hyperlink": "0.16.3",
"language-java": "0.28.0",
"language-javascript": "0.128.3",
"language-java": "0.29.0",
"language-javascript": "0.128.4",
"language-json": "0.19.1",
"language-less": "0.34.2",
"language-make": "0.22.3",
"language-mustache": "0.14.5",
"language-objective-c": "0.15.1",
"language-perl": "0.38.1",
"language-php": "0.43.1",
"language-php": "0.43.2",
"language-property-list": "0.9.1",
"language-python": "0.49.2",
"language-ruby": "0.71.4",
"language-ruby-on-rails": "0.25.3",
"language-sass": "0.61.4",
"language-shellscript": "0.26.1",
"language-shellscript": "0.26.2",
"language-source": "0.9.0",
"language-sql": "0.25.10",
"language-text": "0.7.3",
"language-text": "0.7.4",
"language-todo": "0.29.4",
"language-toml": "0.18.2",
"language-typescript": "0.3.2",
"language-xml": "0.35.2",
"language-yaml": "0.31.2"
"language-yaml": "0.32.0"
},
"private": true,
"scripts": {

View File

@@ -8,3 +8,4 @@ Type=Application
StartupNotify=true
Categories=GNOME;GTK;Utility;TextEditor;Development;
MimeType=text/plain;
StartupWMClass=Atom

View File

@@ -1,6 +1,6 @@
Package: <%= appFileName %>
Version: <%= version %>
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils, libcap2
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3 (>= 2:3.22), python, gvfs-bin, xdg-utils, libcap2, libx11-xcb1, libxss1, libasound2 (>= 1.0.16), libxkbfile1
Recommends: lsb-release
Suggests: libsecret-1-0, gir1.2-gnomekeyring-1.0
Section: devel

View File

@@ -237,3 +237,30 @@ describe "PaneContainerElement", ->
atom.commands.dispatch(rightPane.getElement(), 'pane:decrease-size')
expect(leftPane.getFlexScale()).toBe 1/1.1
expect(rightPane.getFlexScale()).toBe 1/1.1
describe "when only a single pane is present", ->
[singlePane] = []
beforeEach ->
container = new PaneContainer(params)
singlePane = container.getActivePane()
describe "when pane:increase-size is triggered", ->
it "does not increases the size of the pane", ->
expect(singlePane.getFlexScale()).toBe 1
atom.commands.dispatch(singlePane.getElement(), 'pane:increase-size')
expect(singlePane.getFlexScale()).toBe 1
atom.commands.dispatch(singlePane.getElement(), 'pane:increase-size')
expect(singlePane.getFlexScale()).toBe 1
describe "when pane:decrease-size is triggered", ->
it "does not decreases the size of the pane", ->
expect(singlePane.getFlexScale()).toBe 1
atom.commands.dispatch(singlePane.getElement(), 'pane:decrease-size')
expect(singlePane.getFlexScale()).toBe 1
atom.commands.dispatch(singlePane.getElement(), 'pane:decrease-size')
expect(singlePane.getFlexScale()).toBe 1

View File

@@ -905,46 +905,6 @@ 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)
// 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)
component.scheduleUpdate()
await component.getNextUpdatePromise()
editor.setSelectedBufferRange([[0, 1], [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
@@ -961,7 +921,7 @@ describe('TextEditorComponent', () => {
const initialSeed = Date.now()
for (var i = 0; i < 20; i++) {
let seed = initialSeed + i
// seed = 1507231571985
// seed = 1520247533732
const failureMessage = 'Randomized test failed with seed: ' + seed
const random = Random(seed)
@@ -971,6 +931,11 @@ describe('TextEditorComponent', () => {
await setEditorWidthInCharacters(component, random(20))
await setEditorHeightInLines(component, random(10))
element.style.fontSize = random(20) + 'px'
element.style.lineHeight = random.floatBetween(0.1, 2.0)
TextEditor.didUpdateStyles()
await component.getNextUpdatePromise()
element.focus()
for (var j = 0; j < 5; j++) {

View File

@@ -189,12 +189,12 @@ class BufferedProcess {
output += data
})
wmicProcess.stdout.on('close', () => {
const pidsToKill = output.split(/\s+/)
.filter((pid) => /^\d+$/.test(pid))
.map((pid) => parseInt(pid))
.filter((pid) => pid !== parentPid && pid > 0 && pid < Infinity)
for (let pid of output.split(/\s+/)) {
if (!/^\d{1,10}$/.test(pid)) continue
pid = parseInt(pid, 10)
if (!pid || pid === parentPid) continue
for (let pid of pidsToKill) {
try {
process.kill(pid)
} catch (error) {}

View File

@@ -1106,7 +1106,7 @@ class Config {
deepClone (object) {
if (object instanceof Color) {
return object.clone()
} else if (_.isArray(object)) {
} else if (Array.isArray(object)) {
return object.map(value => this.deepClone(value))
} else if (isPlainObject(object)) {
return _.mapObject(object, (key, value) => [key, this.deepClone(value)])
@@ -1467,7 +1467,7 @@ Config.addSchemaEnforcers({
}
})
let isPlainObject = value => _.isObject(value) && !_.isArray(value) && !_.isFunction(value) && !_.isString(value) && !(value instanceof Color)
let isPlainObject = value => _.isObject(value) && !Array.isArray(value) && !_.isFunction(value) && !_.isString(value) && !(value instanceof Color)
let sortObject = value => {
if (!isPlainObject(value)) { return value }

View File

@@ -1,4 +1,3 @@
const _ = require('underscore-plus')
const {Emitter} = require('event-kit')
let idCounter = 0
@@ -49,7 +48,7 @@ class Decoration {
// 'line-number' is a 'gutter', but a 'gutter' is not a 'line-number'.
static isType (decorationProperties, type) {
// 'line-number' is a special case of 'gutter'.
if (_.isArray(decorationProperties.type)) {
if (Array.isArray(decorationProperties.type)) {
if (decorationProperties.type.includes(type)) {
return true
}

View File

@@ -153,7 +153,10 @@ module.exports = class Dock {
this.state = nextState
this.render(this.state)
const {visible} = this.state
const {hovered, visible} = this.state
if (hovered !== prevState.hovered) {
this.emitter.emit('did-change-hovered', hovered)
}
if (visible !== prevState.visible) {
this.emitter.emit('did-change-visible', visible)
}
@@ -296,7 +299,7 @@ module.exports = class Dock {
}
handleDrag (event) {
if (!this.pointWithinHoverArea({x: event.pageX, y: event.pageY}, false)) {
if (!this.pointWithinHoverArea({x: event.pageX, y: event.pageY}, true)) {
this.draggedOut()
}
}
@@ -313,9 +316,13 @@ module.exports = class Dock {
// Determine whether the cursor is within the dock hover area. This isn't as simple as just using
// mouseenter/leave because we want to be a little more forgiving. For example, if the cursor is
// over the footer, we want to show the bottom dock's toggle button.
pointWithinHoverArea (point, includeButtonWidth = this.state.hovered) {
// over the footer, we want to show the bottom dock's toggle button. Also note that our criteria
// for detecting entry are different than detecting exit but, in order for us to avoid jitter, the
// area considered when detecting exit MUST fully encompass the area considered when detecting
// entry.
pointWithinHoverArea (point, detectingExit) {
const dockBounds = this.innerElement.getBoundingClientRect()
// Copy the bounds object since we can't mutate it.
const bounds = {
top: dockBounds.top,
@@ -324,39 +331,67 @@ module.exports = class Dock {
left: dockBounds.left
}
// Include all panels that are closer to the edge than the dock in our calculations.
// To provide a minimum target, expand the area toward the center a bit.
switch (this.location) {
case 'right':
bounds.left = Math.min(bounds.left, bounds.right - 2)
break
case 'bottom':
bounds.top = Math.min(bounds.top, bounds.bottom - 1)
break
case 'left':
bounds.right = Math.max(bounds.right, bounds.left + 2)
break
}
// Further expand the area to include all panels that are closer to the edge than the dock.
switch (this.location) {
case 'right':
if (!this.isVisible()) bounds.left = bounds.right - 2
bounds.right = Number.POSITIVE_INFINITY
break
case 'bottom':
if (!this.isVisible()) bounds.top = bounds.bottom - 1
bounds.bottom = Number.POSITIVE_INFINITY
break
case 'left':
if (!this.isVisible()) bounds.right = bounds.left + 2
bounds.left = Number.NEGATIVE_INFINITY
break
}
// The area used when detecting "leave" events is actually larger than when detecting entrances.
if (includeButtonWidth) {
// If we're in this area, we know we're within the hover area without having to take further
// measurements.
if (rectContainsPoint(bounds, point)) return true
// If we're within the toggle button, we're definitely in the hover area. Unfortunately, we
// can't do this measurement conditionally (e.g. only if the toggle button is visible) because
// our knowledge of the toggle's button is incomplete due to CSS animations. (We may think the
// toggle button isn't visible when in actuality it is, but is animating to its hidden state.)
//
// Since `point` is always the current mouse position, one possible optimization would be to
// remove it as an argument and determine whether we're inside the toggle button using
// mouseenter/leave events on it. This class would still need to keep track of the mouse
// position (via a mousemove listener) for the other measurements, though.
const toggleButtonBounds = this.toggleButton.getBounds()
if (rectContainsPoint(toggleButtonBounds, point)) return true
// The area used when detecting exit is actually larger than when detecting entrances. Expand
// our bounds and recheck them.
if (detectingExit) {
const hoverMargin = 20
const {width, height} = this.toggleButton.getBounds()
switch (this.location) {
case 'right':
bounds.left -= width + hoverMargin
bounds.left = Math.min(bounds.left, toggleButtonBounds.left) - hoverMargin
break
case 'bottom':
bounds.top -= height + hoverMargin
bounds.top = Math.min(bounds.top, toggleButtonBounds.top) - hoverMargin
break
case 'left':
bounds.right += width + hoverMargin
bounds.right = Math.max(bounds.right, toggleButtonBounds.right) + hoverMargin
break
}
if (rectContainsPoint(bounds, point)) return true
}
return rectContainsPoint(bounds, point)
return false
}
getInitialSize () {
@@ -577,6 +612,16 @@ module.exports = class Dock {
return this.paneContainer.onDidDestroyPaneItem(callback)
}
// Extended: Invoke the given callback when the hovered state of the dock changes.
//
// * `callback` {Function} to be called when the hovered state changes.
// * `hovered` {Boolean} Is the dock now hovered?
//
// Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeHovered (callback) {
return this.emitter.on('did-change-hovered', callback)
}
/*
Section: Pane Items
*/
@@ -726,10 +771,7 @@ class DockToggleButton {
}
getBounds () {
if (this.bounds == null) {
this.bounds = this.element.getBoundingClientRect()
}
return this.bounds
return this.innerElement.getBoundingClientRect()
}
update (newProps) {

View File

@@ -201,7 +201,7 @@ class ApplicationMenu {
if (item.command) {
item.accelerator = this.acceleratorForCommand(item.command, keystrokesByCommand)
item.click = () => global.atomApplication.sendCommand(item.command, item.commandDetail)
if (!/^application:/.test(item.command, item.commandDetail)) {
if (!/^application:/.test(item.command)) {
item.metadata.windowSpecific = true
}
}

View File

@@ -58,7 +58,9 @@ class AtomWindow extends EventEmitter {
Object.defineProperty(this.browserWindow, 'loadSettingsJSON', {
get: () => JSON.stringify(Object.assign({
userSettings: this.atomApplication.configFile.get(),
userSettings: !this.isSpec
? this.atomApplication.configFile.get()
: null,
projectSpecification: this.projectSpecification
}, this.loadSettings))
})

View File

@@ -21,7 +21,7 @@ class Notification {
throw new Error(`Notification must be created with string message: ${this.message}`)
}
if (!_.isObject(this.options) || _.isArray(this.options)) {
if (!_.isObject(this.options) || Array.isArray(this.options)) {
throw new Error(`Notification must be created with an options object: ${this.options}`)
}
}

View File

@@ -155,9 +155,17 @@ class Pane {
getFlexScale () { return this.flexScale }
increaseSize () { this.setFlexScale(this.getFlexScale() * 1.1) }
increaseSize () {
if (this.getContainer().getPanes().length > 1) {
this.setFlexScale(this.getFlexScale() * 1.1)
}
}
decreaseSize () { this.setFlexScale(this.getFlexScale() / 1.1) }
decreaseSize () {
if (this.getContainer().getPanes().length > 1) {
this.setFlexScale(this.getFlexScale() / 1.1)
}
}
/*
Section: Event Subscription

View File

@@ -171,6 +171,10 @@ class NativeWatcher {
class AtomNativeWatcher extends NativeWatcher {
async doStart () {
const getRealPath = givenPath => {
if (!givenPath) {
return Promise.resolve(null)
}
return new Promise(resolve => {
fs.realpath(givenPath, (err, resolvedPath) => {
err ? resolve(null) : resolve(resolvedPath)
@@ -239,7 +243,7 @@ class AtomNativeWatcher extends NativeWatcher {
this.subs.add(treeView.onEntryDeleted(async event => {
const realPath = await getRealPath(event.path)
if (!realPath || isOpenInEditor(realPath)) return
if (!realPath || await isOpenInEditor(realPath)) return
this.onEvents([{action: 'deleted', path: realPath}])
}))
@@ -249,7 +253,7 @@ class AtomNativeWatcher extends NativeWatcher {
getRealPath(event.newPath),
getRealPath(event.initialPath)
])
if (!realNewPath || !realOldPath || isOpenInEditor(realNewPath) || isOpenInEditor(realOldPath)) return
if (!realNewPath || !realOldPath || await isOpenInEditor(realNewPath) || await isOpenInEditor(realOldPath)) return
this.onEvents([{action: 'renamed', path: realNewPath, oldPath: realOldPath}])
}))
@@ -492,7 +496,29 @@ class PathWatcher {
// events may include events for paths above this watcher's root path, so filter them to only include the relevant
// ones, then re-broadcast them to our subscribers.
onNativeEvents (events, callback) {
const filtered = events.filter(event => event.path.startsWith(this.normalizedPath))
const isWatchedPath = eventPath => eventPath.startsWith(this.normalizedPath)
const filtered = []
for (let i = 0; i < events.length; i++) {
const event = events[i]
if (event.action === 'renamed') {
const srcWatched = isWatchedPath(event.oldPath)
const destWatched = isWatchedPath(event.path)
if (srcWatched && destWatched) {
filtered.push(event)
} else if (srcWatched && !destWatched) {
filtered.push({action: 'deleted', kind: event.kind, path: event.oldPath})
} else if (!srcWatched && destWatched) {
filtered.push({action: 'created', kind: event.kind, path: event.path})
}
} else {
if (isWatchedPath(event.path)) {
filtered.push(event)
}
}
}
if (filtered.length > 0) {
callback(filtered)

View File

@@ -216,7 +216,7 @@ class Project extends Model {
// To watch paths outside of open projects, use the `watchPaths` function instead; see {PathWatcher}.
//
// When writing tests against functionality that uses this method, be sure to wait for the
// {Promise} returned by {getWatcherPromise()} before manipulating the filesystem to ensure that
// {Promise} returned by {::getWatcherPromise} before manipulating the filesystem to ensure that
// the watcher is receiving events.
//
// * `callback` {Function} to be called with batches of filesystem events reported by

View File

@@ -2811,7 +2811,7 @@ class TextEditorComponent {
setScrollTop (scrollTop) {
if (Number.isNaN(scrollTop) || scrollTop == null) return false
scrollTop = Math.round(Math.max(0, Math.min(this.getMaxScrollTop(), scrollTop)))
scrollTop = roundToPhysicalPixelBoundary(Math.max(0, Math.min(this.getMaxScrollTop(), scrollTop)))
if (scrollTop !== this.scrollTop) {
this.derivedDimensionsCache = {}
this.scrollTopPending = true
@@ -2842,7 +2842,7 @@ class TextEditorComponent {
setScrollLeft (scrollLeft) {
if (Number.isNaN(scrollLeft) || scrollLeft == null) return false
scrollLeft = Math.round(Math.max(0, Math.min(this.getMaxScrollLeft(), scrollLeft)))
scrollLeft = roundToPhysicalPixelBoundary(Math.max(0, Math.min(this.getMaxScrollLeft(), scrollLeft)))
if (scrollLeft !== this.scrollLeft) {
this.scrollLeftPending = true
this.scrollLeft = scrollLeft

View File

@@ -103,7 +103,7 @@ class ThemeManager {
warnForNonExistentThemes () {
let themeNames = this.config.get('core.themes') || []
if (!_.isArray(themeNames)) { themeNames = [themeNames] }
if (!Array.isArray(themeNames)) { themeNames = [themeNames] }
for (let themeName of themeNames) {
if (!themeName || (typeof themeName !== 'string') || !this.packageManager.resolvePackagePath(themeName)) {
console.warn(`Enabled theme '${themeName}' is not installed.`)
@@ -116,7 +116,7 @@ class ThemeManager {
// Returns an array of theme names in the order that they should be activated.
getEnabledThemeNames () {
let themeNames = this.config.get('core.themes') || []
if (!_.isArray(themeNames)) { themeNames = [themeNames] }
if (!Array.isArray(themeNames)) { themeNames = [themeNames] }
themeNames = themeNames.filter((themeName) =>
(typeof themeName === 'string') && this.packageManager.resolvePackagePath(themeName)
)
@@ -138,7 +138,7 @@ class ThemeManager {
if (themeNames.length === 0) {
themeNames = ['one-dark-syntax', 'one-dark-ui']
} else if (themeNames.length === 1) {
if (_.endsWith(themeNames[0], '-ui')) {
if (themeNames[0].endsWith('-ui')) {
themeNames.unshift('one-dark-syntax')
} else {
themeNames.push('one-dark-ui')

View File

@@ -92,7 +92,13 @@ class WorkspaceElement extends HTMLElement {
window.removeEventListener('dragstart', this.handleDragStart)
window.removeEventListener('dragend', this.handleDragEnd, true)
window.removeEventListener('drop', this.handleDrop, true)
})
}),
...[this.model.getLeftDock(), this.model.getRightDock(), this.model.getBottomDock()]
.map(dock => dock.onDidChangeHovered(hovered => {
if (hovered) this.hoveredDock = dock
else if (dock === this.hoveredDock) this.hoveredDock = null
this.checkCleanupDockHoverEvents()
}))
)
this.initializeContent()
this.observeScrollbarStyle()
@@ -186,19 +192,13 @@ class WorkspaceElement extends HTMLElement {
}
updateHoveredDock (mousePosition) {
this.hoveredDock = null
for (let location in this.model.paneContainers) {
if (location !== 'center') {
const dock = this.model.paneContainers[location]
if (!this.hoveredDock && dock.pointWithinHoverArea(mousePosition)) {
this.hoveredDock = dock
dock.setHovered(true)
} else {
dock.setHovered(false)
}
}
}
this.checkCleanupDockHoverEvents()
// If we haven't left the currently hovered dock, don't change anything.
if (this.hoveredDock && this.hoveredDock.pointWithinHoverArea(mousePosition, true)) return
const docks = [this.model.getLeftDock(), this.model.getRightDock(), this.model.getBottomDock()]
const nextHoveredDock =
docks.find(dock => dock !== this.hoveredDock && dock.pointWithinHoverArea(mousePosition))
docks.forEach(dock => { dock.setHovered(dock === nextHoveredDock) })
}
checkCleanupDockHoverEvents () {