mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-19 23:17:16 +03:00
Merge branch 'master' into mb-tree-sitter-parsers
This commit is contained in:
commit
0b6e994ac6
20
README.md
20
README.md
@ -42,27 +42,11 @@ The `.zip` version will not automatically update.
|
||||
|
||||
Using [Chocolatey](https://chocolatey.org)? Run `cinst Atom` to install the latest version of Atom.
|
||||
|
||||
### Debian based (Debian, Ubuntu, Linux Mint)
|
||||
### Linux
|
||||
|
||||
Atom is only available for 64-bit Linux systems.
|
||||
|
||||
1. Download `atom-amd64.deb` from the [Atom releases page](https://github.com/atom/atom/releases/latest).
|
||||
2. Run `sudo dpkg --install atom-amd64.deb` on the downloaded package.
|
||||
3. Launch Atom using the installed `atom` command.
|
||||
|
||||
The Linux version does not currently automatically update so you will need to
|
||||
repeat these steps to upgrade to future releases.
|
||||
|
||||
### RPM based (Red Hat, openSUSE, Fedora, CentOS)
|
||||
|
||||
Atom is only available for 64-bit Linux systems.
|
||||
|
||||
1. Download `atom.x86_64.rpm` from the [Atom releases page](https://github.com/atom/atom/releases/latest).
|
||||
2. Run `sudo rpm -i atom.x86_64.rpm` on the downloaded package.
|
||||
3. Launch Atom using the installed `atom` command.
|
||||
|
||||
The Linux version does not currently automatically update so you will need to
|
||||
repeat these steps to upgrade to future releases.
|
||||
Configure your distribution's package manager to install and update Atom by following the [Linux installation instructions](http://flight-manual.atom.io/getting-started/sections/installing-atom/#platform-linux) in the Flight Manual. You will also find instructions on how to install Atom's official Linux packages without using a package repository, though you will not get automatic updates after installing Atom this way.
|
||||
|
||||
### Archive extraction
|
||||
|
||||
|
@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "1.18.11"
|
||||
"atom-package-manager": "1.18.12"
|
||||
}
|
||||
}
|
||||
|
@ -1,285 +1,3 @@
|
||||
# Atom.io package and update API
|
||||
|
||||
This guide describes the web API used by [apm](https://github.com/atom/apm) and
|
||||
Atom. The vast majority of use cases are met by the `apm` command-line tool,
|
||||
which does other useful things like incrementing your version in `package.json`
|
||||
and making sure you have pushed your git tag. In fact, Atom itself shells out to
|
||||
`apm` rather than hitting the API directly. If you're curious about how Atom
|
||||
uses `apm`, see the [PackageManager class](https://github.com/atom/settings-view/blob/master/lib/package-manager.coffee)
|
||||
in the `settings-view` package.
|
||||
|
||||
*This API should be considered pre-release and is subject to change (though significant breaking changes are unlikely).*
|
||||
|
||||
### Authorization
|
||||
|
||||
For calls to the API that require authentication, provide a valid token from your
|
||||
[Atom.io account page](https://atom.io/account) in the `Authorization` header.
|
||||
|
||||
### Media type
|
||||
|
||||
All requests that take parameters require `application/json`.
|
||||
|
||||
# API Resources
|
||||
|
||||
## Packages
|
||||
|
||||
### Listing packages
|
||||
|
||||
#### GET /api/packages
|
||||
|
||||
Parameters:
|
||||
|
||||
- **page** (optional)
|
||||
- **sort** (optional) - One of `downloads`, `created_at`, `updated_at`, `stars`. Defaults to `downloads`
|
||||
- **direction** (optional) - `asc` or `desc`. Defaults to `desc`. `stars` can only be ordered `desc`
|
||||
|
||||
Returns a list of all packages in the following format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"releases": {
|
||||
"latest": "0.6.0"
|
||||
},
|
||||
"name": "thedaniel-test-package",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
Results are paginated 30 at a time, and links to the next and last pages are
|
||||
provided in the `Link` header:
|
||||
|
||||
```
|
||||
Link: <https://www.atom.io/api/packages?page=1>; rel="self",
|
||||
<https://www.atom.io/api/packages?page=41>; rel="last",
|
||||
<https://www.atom.io/api/packages?page=2>; rel="next"
|
||||
```
|
||||
|
||||
By default, results are sorted by download count, descending.
|
||||
|
||||
### Searching packages
|
||||
|
||||
#### GET /api/packages/search
|
||||
|
||||
Parameters:
|
||||
|
||||
- **q** (required) - Search query
|
||||
- **page** (optional)
|
||||
- **sort** (optional) - One of `downloads`, `created_at`, `updated_at`, `stars`. Defaults to the relevance of the search query.
|
||||
- **direction** (optional) - `asc` or `desc`. Defaults to `desc`.
|
||||
|
||||
Returns results in the same format as [listing packages](#listing-packages).
|
||||
|
||||
### Showing package details
|
||||
|
||||
#### GET /api/packages/:package_name
|
||||
|
||||
Returns package details and versions for a single package
|
||||
|
||||
Parameters:
|
||||
|
||||
- **engine** (optional) - Only show packages with versions compatible with this
|
||||
Atom version. Must be valid [SemVer](http://semver.org).
|
||||
|
||||
Returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"releases": {
|
||||
"latest": "0.6.0"
|
||||
},
|
||||
"name": "thedaniel-test-package",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package"
|
||||
},
|
||||
"versions": [
|
||||
(see single version output below)
|
||||
...,
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a package
|
||||
|
||||
#### POST /api/packages
|
||||
|
||||
Create a new package; requires authentication.
|
||||
|
||||
The name and version will be fetched from the `package.json`
|
||||
file in the specified repository. The authenticating user *must* have access
|
||||
to the indicated repository.
|
||||
|
||||
Parameters:
|
||||
|
||||
- **repository** - String. The repository containing the plugin, in the form "owner/repo"
|
||||
|
||||
Returns:
|
||||
|
||||
- **201** - Successfully created, returns created package.
|
||||
- **400** - Repository is inaccessible, nonexistent, not an atom package. Possible
|
||||
error messages include:
|
||||
- That repo does not exist, isn't an atom package, or atombot does not have access
|
||||
- The package.json at owner/repo isn't valid
|
||||
- **409** - A package by that name already exists
|
||||
|
||||
### Deleting a package
|
||||
|
||||
#### DELETE /api/packages/:package_name
|
||||
|
||||
Delete a package; requires authentication.
|
||||
|
||||
Returns:
|
||||
|
||||
- **204** - Success
|
||||
- **400** - Repository is inaccessible
|
||||
- **401** - Unauthorized
|
||||
|
||||
### Renaming a package
|
||||
|
||||
Packages are renamed by publishing a new version with the name changed in `package.json`
|
||||
See [Creating a new package version](#creating-a-new-package-version) for details.
|
||||
|
||||
Requests made to the previous name will forward to the new name.
|
||||
|
||||
### Package Versions
|
||||
|
||||
#### GET /api/packages/:package_name/versions/:version_name
|
||||
|
||||
Returns `package.json` with `dist` key added for e.g. tarball download:
|
||||
|
||||
```json
|
||||
{
|
||||
"bugs": {
|
||||
"url": "https://github.com/thedaniel/test-package/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.2.6",
|
||||
"pegjs": "~0.7.0",
|
||||
"season": "~0.13.0"
|
||||
},
|
||||
"description": "Expand snippets matching the current prefix with `tab`.",
|
||||
"dist": {
|
||||
"tarball": "https://codeload.github.com/..."
|
||||
},
|
||||
"engines": {
|
||||
"atom": "*"
|
||||
},
|
||||
"main": "./lib/snippets",
|
||||
"name": "thedaniel-test-package",
|
||||
"publishConfig": {
|
||||
"registry": "https://...",
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package.git"
|
||||
},
|
||||
"version": "0.6.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Creating a new package version
|
||||
|
||||
#### POST /api/packages/:package_name/versions
|
||||
|
||||
Creates a new package version from a git tag; requires authentication. If `rename`
|
||||
is not `true`, the `name` field in `package.json` *must* match the current package
|
||||
name.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- **tag** - A git tag for the version you'd like to create. It's important to note
|
||||
that the version name will not be taken from the tag, but from the `version`
|
||||
key in the `package.json` file at that ref. The authenticating user *must* have
|
||||
access to the package repository.
|
||||
- **rename** - Boolean indicating whether this version contains a new name for the package.
|
||||
|
||||
#### Returns
|
||||
|
||||
- **201** - Successfully created. Returns created version.
|
||||
- **400** - Git tag not found / Repository inaccessible / package.json invalid
|
||||
- **409** - Version exists
|
||||
|
||||
### Deleting a version
|
||||
|
||||
#### DELETE /api/packages/:package_name/versions/:version_name
|
||||
|
||||
Deletes a package version; requires authentication.
|
||||
|
||||
Note that a version cannot be republished with a different tag if it is deleted.
|
||||
If you need to delete the latest version of a package for e.g. security reasons,
|
||||
you'll need to increment the version when republishing.
|
||||
|
||||
Returns 204 No Content
|
||||
|
||||
|
||||
## Stars
|
||||
|
||||
### Listing user stars
|
||||
|
||||
#### GET /api/users/:login/stars
|
||||
|
||||
List a user's starred packages.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
#### GET /api/stars
|
||||
|
||||
List the authenticated user's starred packages; requires authentication.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
### Starring a package
|
||||
|
||||
#### POST /api/packages/:name/star
|
||||
|
||||
Star a package; requires authentication.
|
||||
|
||||
Returns a package.
|
||||
|
||||
### Unstarring a package
|
||||
|
||||
#### DELETE /api/packages/:name/star
|
||||
|
||||
Unstar a package; requires authentication.
|
||||
|
||||
Returns 204 No Content.
|
||||
|
||||
### Listing a package's stargazers
|
||||
|
||||
#### GET /api/packages/:name/stargazers
|
||||
|
||||
List the users that have starred a package.
|
||||
|
||||
Returns a list of user objects:
|
||||
|
||||
```json
|
||||
[
|
||||
{"login":"aperson"},
|
||||
{"login":"anotherperson"},
|
||||
]
|
||||
```
|
||||
|
||||
## Atom updates
|
||||
|
||||
### Listing Atom updates
|
||||
|
||||
#### GET /api/updates
|
||||
|
||||
Atom update feed, following the format expected by [Squirrel](https://github.com/Squirrel/).
|
||||
|
||||
Returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "0.96.0",
|
||||
"notes": "[HTML release notes]",
|
||||
"pub_date": "2014-05-19T15:52:06.000Z",
|
||||
"url": "https://www.atom.io/api/updates/download"
|
||||
}
|
||||
```
|
||||
The information that was here has been moved to [a permanent home inside Atom's Flight Manual.](https://flight-manual.atom.io/atom-server-side-apis/)
|
||||
|
@ -97,7 +97,7 @@
|
||||
"autocomplete-html": "0.8.4",
|
||||
"autocomplete-plus": "2.39.1",
|
||||
"autocomplete-snippets": "1.11.2",
|
||||
"autoflow": "0.29.1",
|
||||
"autoflow": "0.29.3",
|
||||
"autosave": "0.24.6",
|
||||
"background-tips": "0.27.1",
|
||||
"bookmarks": "0.45.1",
|
||||
@ -145,7 +145,7 @@
|
||||
"language-gfm": "0.90.3",
|
||||
"language-git": "0.19.1",
|
||||
"language-go": "0.45.0-4",
|
||||
"language-html": "0.48.4",
|
||||
"language-html": "0.48.5",
|
||||
"language-hyperlink": "0.16.3",
|
||||
"language-java": "0.27.6",
|
||||
"language-javascript": "0.128.0-4",
|
||||
@ -160,7 +160,7 @@
|
||||
"language-python": "0.46.0-2",
|
||||
"language-ruby": "0.71.4",
|
||||
"language-ruby-on-rails": "0.25.3",
|
||||
"language-sass": "0.61.3",
|
||||
"language-sass": "0.61.4",
|
||||
"language-shellscript": "0.26.0-3",
|
||||
"language-source": "0.9.0",
|
||||
"language-sql": "0.25.9",
|
||||
|
@ -1,19 +1,14 @@
|
||||
/** @babel */
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const {Emitter, Disposable, CompositeDisposable} = require('event-kit')
|
||||
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
import {Emitter, Disposable, CompositeDisposable} from 'event-kit'
|
||||
|
||||
import {HistoryManager, HistoryProject} from '../src/history-manager'
|
||||
import StateStore from '../src/state-store'
|
||||
const {HistoryManager, HistoryProject} = require('../src/history-manager')
|
||||
const StateStore = require('../src/state-store')
|
||||
|
||||
describe("HistoryManager", () => {
|
||||
let historyManager, commandRegistry, project, stateStore
|
||||
let commandDisposable, projectDisposable
|
||||
|
||||
beforeEach(async () => {
|
||||
// Do not clobber recent project history
|
||||
spyOn(atom.applicationDelegate, 'didChangeHistoryManager')
|
||||
|
||||
commandDisposable = jasmine.createSpyObj('Disposable', ['dispose'])
|
||||
commandRegistry = jasmine.createSpyObj('CommandRegistry', ['add'])
|
||||
commandRegistry.add.andReturn(commandDisposable)
|
||||
@ -185,11 +180,26 @@ describe("HistoryManager", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("saveState" ,() => {
|
||||
describe("saveState", () => {
|
||||
let savedHistory
|
||||
beforeEach(() => {
|
||||
// historyManager.saveState is spied on globally to prevent specs from
|
||||
// modifying the shared project history. Since these tests depend on
|
||||
// saveState, we unspy it but in turn spy on the state store instead
|
||||
// so that no data is actually stored to it.
|
||||
jasmine.unspy(historyManager, 'saveState')
|
||||
|
||||
spyOn(historyManager.stateStore, 'save').andCallFake((name, history) => {
|
||||
savedHistory = history
|
||||
return Promise.resolve()
|
||||
})
|
||||
})
|
||||
|
||||
it("saves the state", async () => {
|
||||
await historyManager.addProject(["/save/state"])
|
||||
await historyManager.saveState()
|
||||
const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry})
|
||||
spyOn(historyManager2.stateStore, 'load').andCallFake(name => Promise.resolve(savedHistory))
|
||||
await historyManager2.loadState()
|
||||
expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state'])
|
||||
})
|
||||
|
@ -63,7 +63,7 @@ else
|
||||
|
||||
beforeEach ->
|
||||
# Do not clobber recent project history
|
||||
spyOn(atom.history, 'saveState').andReturn(Promise.resolve())
|
||||
spyOn(Object.getPrototypeOf(atom.history), 'saveState').andReturn(Promise.resolve())
|
||||
|
||||
atom.project.setPaths([specProjectPath])
|
||||
|
||||
|
@ -2840,83 +2840,149 @@ describe('TextEditorComponent', () => {
|
||||
|
||||
describe('mouse input', () => {
|
||||
describe('on the lines', () => {
|
||||
it('positions the cursor on single-click or when middle/right-clicking', async () => {
|
||||
for (const button of [0, 1, 2]) {
|
||||
describe('when there is only one cursor and no selection', () => {
|
||||
it('positions the cursor on single-click or when middle/right-clicking', async () => {
|
||||
for (const button of [0, 1, 2]) {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
|
||||
const maxRow = editor.getLastScreenRow()
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1,
|
||||
clientY: clientTopForLine(component, maxRow) + 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1,
|
||||
clientY: clientTopForLine(component, 0) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2,
|
||||
clientY: clientTopForLine(component, 1) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1, 0])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 15])
|
||||
|
||||
editor.getBuffer().setTextInRange([[3, 14], [3, 15]], '🐣')
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 16])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is more than one cursor', () => {
|
||||
it('does not move the cursor when right-clicking', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
editor.setCursorScreenPosition([5, 17], {autoscroll: false})
|
||||
editor.addCursorAtScreenPosition([2, 4])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
button: 2,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
expect(editor.getCursorScreenPositions()).toEqual([Point.fromObject([5, 17]), Point.fromObject([2, 4])])
|
||||
})
|
||||
|
||||
const maxRow = editor.getLastScreenRow()
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
it('does move the cursor when middle-clicking', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([5, 17], {autoscroll: false})
|
||||
editor.addCursorAtScreenPosition([2, 4])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1,
|
||||
clientY: clientTopForLine(component, maxRow) + 1
|
||||
button: 1,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)])
|
||||
expect(editor.getCursorScreenPositions()).toEqual([Point.fromObject([0, 0])])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are non-empty selections', () => {
|
||||
it('does not move the cursor when right-clicking', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([5, 17], {autoscroll: false})
|
||||
editor.selectRight(3)
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1,
|
||||
clientY: clientTopForLine(component, 0) + lineHeight / 2
|
||||
button: 2,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)])
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[5, 17], [5, 20]])
|
||||
})
|
||||
|
||||
it('does move the cursor when middle-clicking', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([5, 17], {autoscroll: false})
|
||||
editor.selectRight(3)
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2,
|
||||
clientY: clientTopForLine(component, 1) + lineHeight / 2
|
||||
button: 1,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1, 0])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 15])
|
||||
|
||||
editor.getBuffer().setTextInRange([[3, 14], [3, 15]], '🐣')
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 16])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
}
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[0, 0], [0, 0]])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the input is for the primary mouse button', () => {
|
||||
|
@ -206,12 +206,13 @@ class AtomEnvironment {
|
||||
this.themes.initialize({configDirPath: this.configDirPath, resourcePath, safeMode, devMode})
|
||||
|
||||
this.commandInstaller.initialize(this.getVersion())
|
||||
this.protocolHandlerInstaller.initialize(this.config, this.notifications)
|
||||
this.uriHandlerRegistry.registerHostHandler('core', CoreURIHandlers.create(this))
|
||||
this.autoUpdater.initialize()
|
||||
|
||||
this.config.load()
|
||||
|
||||
this.protocolHandlerInstaller.initialize(this.config, this.notifications)
|
||||
|
||||
this.themes.loadBaseStylesheets()
|
||||
this.initialStyleElements = this.styles.getSnapshot()
|
||||
if (params.onlyLoadBaseStyleSheets) this.themes.initialLoadComplete = true
|
||||
|
@ -8,6 +8,7 @@ FileRecoveryService = require './file-recovery-service'
|
||||
ipcHelpers = require '../ipc-helpers'
|
||||
{BrowserWindow, Menu, app, dialog, ipcMain, shell, screen} = require 'electron'
|
||||
{CompositeDisposable, Disposable} = require 'event-kit'
|
||||
crypto = require 'crypto'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
os = require 'os'
|
||||
@ -33,11 +34,16 @@ class AtomApplication
|
||||
# Public: The entry point into the Atom application.
|
||||
@open: (options) ->
|
||||
unless options.socketPath?
|
||||
username = if process.platform is 'win32' then process.env.USERNAME else process.env.USER
|
||||
# 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.
|
||||
atomHomeUnique = path.resolve(process.env.ATOM_HOME).toLowerCase()
|
||||
hash = crypto.createHash('sha1').update(username).update('|').update(atomHomeUnique)
|
||||
atomInstanceDigest = hash.digest('hex').substring(0, 32)
|
||||
if process.platform is 'win32'
|
||||
userNameSafe = new Buffer(process.env.USERNAME).toString('base64')
|
||||
options.socketPath = "\\\\.\\pipe\\atom-#{options.version}-#{userNameSafe}-#{process.arch}-sock"
|
||||
options.socketPath = "\\\\.\\pipe\\atom-#{options.version}-#{process.arch}-#{atomInstanceDigest}-sock"
|
||||
else
|
||||
options.socketPath = path.join(os.tmpdir(), "atom-#{options.version}-#{process.env.USER}.sock")
|
||||
options.socketPath = path.join(os.tmpdir(), "atom-#{options.version}-#{process.arch}-#{atomInstanceDigest}.sock")
|
||||
|
||||
# FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
|
||||
# take a few seconds to trigger 'error' event, it could be a bug of node
|
||||
|
@ -1762,11 +1762,13 @@ class TextEditorComponent {
|
||||
|
||||
const screenPosition = this.screenPositionForMouseEvent(event)
|
||||
|
||||
// All clicks should set the cursor position, but only left-clicks should
|
||||
// have additional logic.
|
||||
// On macOS, ctrl-click brings up the context menu so also handle that case.
|
||||
if (button !== 0 || (platform === 'darwin' && ctrlKey)) {
|
||||
model.setCursorScreenPosition(screenPosition, {autoscroll: false})
|
||||
// Always set cursor position on middle-click
|
||||
// Only set cursor position on right-click if there is one cursor with no selection
|
||||
const ranges = model.getSelectedBufferRanges()
|
||||
if (button === 1 || (ranges.length === 1 && ranges[0].isEmpty())) {
|
||||
model.setCursorScreenPosition(screenPosition, {autoscroll: false})
|
||||
}
|
||||
|
||||
// On Linux, pasting happens on middle click. A textInput event with the
|
||||
// contents of the selection clipboard will be dispatched by the browser
|
||||
|
@ -3630,14 +3630,15 @@ class TextEditor {
|
||||
return this.buffer.getLanguageMode().rootScopeDescriptor
|
||||
}
|
||||
|
||||
// Essential: Get the syntactic scopeDescriptor for the given position in buffer
|
||||
// Essential: Get the syntactic {ScopeDescriptor} for the given position in buffer
|
||||
// coordinates. Useful with {Config::get}.
|
||||
//
|
||||
// For example, if called with a position inside the parameter list of an
|
||||
// anonymous CoffeeScript function, the method returns the following array:
|
||||
// `["source.coffee", "meta.inline.function.coffee", "variable.parameter.function.coffee"]`
|
||||
// anonymous CoffeeScript function, this method returns a {ScopeDescriptor} with
|
||||
// the following scopes array:
|
||||
// `["source.coffee", "meta.function.inline.coffee", "meta.parameters.coffee", "variable.parameter.function.coffee"]`
|
||||
//
|
||||
// * `bufferPosition` A {Point} or {Array} of [row, column].
|
||||
// * `bufferPosition` A {Point} or {Array} of `[row, column]`.
|
||||
//
|
||||
// Returns a {ScopeDescriptor}.
|
||||
scopeDescriptorForBufferPosition (bufferPosition) {
|
||||
|
@ -16,9 +16,10 @@ atom-dock {
|
||||
.atom-dock-inner {
|
||||
display: flex;
|
||||
|
||||
// Keep the area at least a pixel wide so that you have something to hover
|
||||
// Keep the area at least 2 pixels wide so that you have something to hover
|
||||
// over to trigger the toggle button affordance even when fullscreen.
|
||||
&.left, &.right { min-width: 1px; }
|
||||
// Needs to be 2 pixels to work on Windows when scaled to 150%. See atom/atom #15728
|
||||
&.left, &.right { min-width: 2px; }
|
||||
&.bottom { min-height: 1px; }
|
||||
|
||||
&.bottom { width: 100%; }
|
||||
|
Loading…
Reference in New Issue
Block a user