mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Merge branch 'master' into fb-pw-simple-project-config
This commit is contained in:
43
docs/focus/2018-02-26.md
Normal file
43
docs/focus/2018-02-26.md
Normal 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
55
docs/focus/2018-03-05.md
Normal 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
103
docs/focus/README.md
Normal 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
|
||||
28
package.json
28
package.json
@@ -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": {
|
||||
|
||||
@@ -8,3 +8,4 @@ Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Utility;TextEditor;Development;
|
||||
MimeType=text/plain;
|
||||
StartupWMClass=Atom
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
80
src/dock.js
80
src/dock.js
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
|
||||
@@ -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}`)
|
||||
}
|
||||
}
|
||||
|
||||
12
src/pane.js
12
src/pane.js
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
Reference in New Issue
Block a user