Skip to content
This repository has been archived by the owner on Sep 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #4 from savetheclocktower/apd-rewrite
Browse files Browse the repository at this point in the history
Reformat the Markdown
  • Loading branch information
confused-Techie authored May 12, 2024
2 parents 2cd9a2f + 8daae36 commit 5b53684
Show file tree
Hide file tree
Showing 89 changed files with 1,238 additions and 1,641 deletions.
3 changes: 3 additions & 0 deletions _partial_docs/community-supported-package-manager-warning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
::: warning
Please remember that these installation methods are community-supported. Any errors specific to that platform will need to be reported to, and addressed by, the community members that maintain them. The Pulsar team is not responsible for any community-supported installations.
:::
1 change: 0 additions & 1 deletion _partial_docs/native-module-versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ Currently the following **exact** versions of these programs need to be installe
* Visual Studio 2019
- Windows 10 SDK
* Python version 3.10

:::
4 changes: 2 additions & 2 deletions docs/behind-pulsar/behind-pulsar.11tydata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
"link": "/behind-pulsar/configuration-api"
},
{
"text": "Keymaps in-depth",
"text": "Keymaps in depth",
"link": "/behind-pulsar/keymaps-in-depth"
},
{
"text": "Scoped settings, scopes and scope descriptors",
"text": "Scoped settings, scopes, and scope descriptors",
"link": "/behind-pulsar/scoped-settings"
},
{
Expand Down
4 changes: 1 addition & 3 deletions docs/behind-pulsar/configuration-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ layout: doc.ejs

## Reading Config Settings

If you are writing a package that you want to make configurable, you'll need to
read config settings via the `atom.config` global. You can read the current
value of a namespaced config key with `atom.config.get`:
If you are writing a package that you want to make configurable, you'll need to read config settings via the `atom.config` global. You can read the current value of a namespaced config key with `atom.config.get`:

```js
// read a value with `config.get`
Expand Down
2 changes: 1 addition & 1 deletion docs/behind-pulsar/developing-node-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ packages. If you want to make changes to the Node modules, for instance
`atom-keymap`, you have to link them into the development environment
differently than you would a normal Pulsar package.

## Linking a Node Module Into Your Pulsar Dev Environment
## Linking a Node module into your Pulsar dev environment

Here are the steps to run a local version of a Node module within Pulsar. We're
using `atom-keymap` as an example:
Expand Down
86 changes: 86 additions & 0 deletions docs/behind-pulsar/interacting-with-other-packages-via-services.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: Interacting with other packages via services
layout: doc.ejs
---

You might want your package to interact with another package. It’s tempting to target the other package by name and call some of its internal methods, but a much safer and more powerful way for two packages to communiate is via a versioned API called a _service_.

Ultimately, packages can see and inspect one another via the {PackageManager} defined at `atom.packages`. But services have some major upsides:

* They don’t make assumptions about package names, so a package is free to rename itself as long as its service name does not change.
* They don’t make assumptions about a package’s implementation details; a service defines a contract and is therefore safer to rely upon.
* Services define “middleware” that can be fulfilled by any number of packages. (For example: any package that wants to improve upon `autocomplete-plus` can implement the `autocomplete.provider` service and instantly talk to all the packages built to provide data to `autocomplete-plus`.)
* Services can evolve their contracts over time via versioning, and any package can fulfill any number of different versions of a given service at once.

During the package activation phase, Pulsar acts as a matchmaker to providers and consumers of services — “introducing” them to one another whenever two packages match on service name and version.

To provide a service, specify a `providedServices` field in your `package.json`. You should include one or more version numbers, each paired with the name of a method on your package's main module:

```json
{
"providedServices": {
"my-service": {
"description": "Does a useful thing",
"versions": {
"1.2.3": "provideMyServiceV1",
"2.3.4": "provideMyServiceV2"
}
}
}
}
```

In your package's main module, implement the methods named above. These methods will be called any time a package is activated that consumes their corresponding service. They should return a value that implements the service's API.

```js
module.exports = {
activate() {
// ...
},

provideMyServiceV1() {
return adaptToLegacyAPI(myService);
},

provideMyServiceV2() {
return myService;
},
};
```

Similarly, to consume a service, specify one or more [version _ranges_](https://docs.npmjs.com/cli/v6/using-npm/semver#ranges), each paired with the name of a method on the package's main module:

```json
{
"consumedServices": {
"another-service": {
"versions": {
"^1.2.3": "consumeAnotherServiceV1",
">=2.3.4 <2.5": "consumeAnotherServiceV2"
}
}
}
}
```

These methods will be called any time a package is activated that _provides_ their corresponding service. They will receive the service object as an argument. You will usually need to perform some kind of cleanup in the event that the package providing the service is deactivated. To do this, return a {Disposable} from your service-consuming method:

```js
const { Disposable } = require("atom");

module.exports = {
activate() {
// ...
},

consumeAnotherServiceV1(service) {
useService(adaptServiceFromLegacyAPI(service));
return new Disposable(() => stopUsingService(service));
},

consumeAnotherServiceV2(service) {
useService(service);
return new Disposable(() => stopUsingService(service));
},
};
```

This file was deleted.

6 changes: 1 addition & 5 deletions docs/behind-pulsar/keymaps-in-depth.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ layout: doc.ejs

## Structure of a Keymap File

Keymap files are encoded as JSON or CSON files containing nested hashes. They
work much like style sheets, but instead of applying style properties to
elements matching the selector, they specify the meaning of keystrokes on
elements matching the selector. Here is an example of some bindings that apply
when keystrokes pass through `atom-text-editor` elements:
Keymap files are encoded as JSON or CSON files containing nested hashes. They work much like style sheets, but instead of applying style properties to elements matching the selector, they specify the meaning of keystrokes on elements matching the selector. Here is an example of some bindings that apply when keystrokes pass through `atom-text-editor` elements:

::: tabs#behind-pulsar

Expand Down
77 changes: 44 additions & 33 deletions docs/behind-pulsar/scoped-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@ title: Scoped settings, scopes and scope descriptors
layout: doc.ejs
---

Pulsar supports language-specific settings. You can soft wrap only Markdown
files, or set the tab length to 4 in Python files.
Pulsar supports language-specific settings. For instance, you can choose to enable soft-wrap for Markdown files and disable it for all other files; or you can set the tab length to 4 for Python files and 2 for everything else.

Language-specific settings are a subset of something more general we call
"scoped settings". Scoped settings allow targeting down to a specific syntax
token type. For example, you could conceivably set a setting to target only Ruby
comments, only code inside Markdown files, or even only JavaScript function
names.
Language-specific settings are a subset of something more general we call _scoped settings_. Scoped settings allow targeting down to a specific syntax token type. For example, you could conceivably set a setting to target only Ruby comments, only code inside Markdown files, or even only JavaScript function names.

## Scope Names in Syntax Tokens
## Scope names in syntax tokens

Each token in the editor has a collection of scope names. For example, the
aforementioned JavaScript function name might have the scope names `function`
and `name`. An open paren might have the scope names `punctuation`,
`parameters`, `begin`.
The scope system is one of the many systems that Pulsar (and Atom before it) inherited from TextMate. Here’s how it works:

Scope names work just like CSS classes. In fact, in the editor, scope names are
attached to a token's DOM node as CSS classes.
* The entire contents of a source file has a scope name specific to that language: for instance, `source.js` or `text.html.basic`.
* Regions of the source file might have their own scope names: for instance, `meta.class.js` or `entity.name.tag.body.html`.
* Those regions might have _further_ scope names defined inside them: for instance, `entity.name.function.js` or `punctuation.definition.tag.begin.html`.

As a result, a given position in a source code file may contain a cascade of scope names, moving from the general to the specific:

<!-- TODO: Screenshot -->

You can see this yourself by placing a cursor in one of your own buffers and invoking the **Editor: Log Cursor Scope** command from the command palette.

In Pulsar, scope names work just like CSS classes. In fact, in the editor, scope names are _implemented_ as CSS classes.

Take this piece of JavaScript:

Expand All @@ -32,12 +33,15 @@ function functionName() {

In the dev tools, the first line's markup looks like this.

<!-- TODO: This screenshot is out of date; we need one that shows the `syntax--`-style class names. -->
![Markup](/img/atom/markup.png)

You can see that each segment of a scope name is prepended with `syntax--` to minimize the chances of naming collisions, but the effect is the same.

All the class names on the spans are scope names. Any scope name can be used to
target a setting's value.

## Scope Selectors
## Scope selectors

Scope selectors allow you to target specific tokens just like a CSS selector
targets specific nodes in the DOM. Some examples:
Expand All @@ -48,21 +52,25 @@ targets specific nodes in the DOM. Some examples:
'.function.name' # selects all function names in any language
```

[`Config::set`](/api/pulsar/latest/Config/#essential-set) accepts a
`scopeSelector`. If you'd like to set a setting for JavaScript function names,
you can give it the JavaScript function name `scopeSelector`:
{Config::set} accepts a `scopeSelector`. If you wanted to create a scoped setting dynamically — in your init file or in a package — you can use the `scopeSelector` option:

```js
atom.config.set("my-package.my-setting", "special value", {
atom.config.set("my-package.mySetting", "special value", {
scopeSelector: ".source.js .function.name",
});
```

## Scope Descriptors
But if you wanted to specify that setting more simply, you could open your `config.cson` and add it in its own section at the bottom of the file:

A scope descriptor is an [Object](/api/pulsar/latest/ScopeDescriptor/)
that wraps an `Array` of `String`s. The Array describes a path from the root of
the syntax tree to a token including _all_ scope names for the entire path.
```coffee
".source.js .function.name":
"my-package":
"mySetting": "special value"
```

## Scope descriptors

A _scope descriptor_ is an object that wraps an array of strings. The array describes a path from the root of the syntax tree to a token including _all_ scope names for the entire path. You can read the {ScopeDescriptor} API documentation to learn more.

In our JavaScript example above, a scope descriptor for the function name token
would be:
Expand All @@ -71,9 +79,7 @@ would be:
["source.js", "meta.function.js", "entity.name.function.js"];
```

[`Config::get`](/api/pulsar/latest/Config/#essential-get) accepts a
`scopeDescriptor`. You can get the value for your setting scoped to JavaScript
function names via:
{Config::get} accepts a `scopeDescriptor`. You can retrieve a scoped setting by passing a {ScopeDescriptor} — or the equivalent plain array:

```js
const scopeDescriptor = [
Expand All @@ -89,13 +95,18 @@ const value = atom.config.get("my-package.my-setting", {
But, you do not need to generate scope descriptors by hand. There are a couple
methods available to get the scope descriptor from the editor:

- [`Editor::getRootScopeDescriptor`](/api/pulsar/latest/TextEditor/#essential-getrootscopedescriptor)
to get the language's descriptor. For example: `[".source.js"]`
- [`Editor::scopeDescriptorForBufferPosition`](/api/pulsar/latest/TextEditor/#essential-scopedescriptorforbufferposition)
to get the descriptor at a specific position in the buffer.
- [`Cursor::getScopeDescriptor`](/api/pulsar/latest/Cursor/#public-getscopedescriptor)
to get a cursor's descriptor based on position. eg. if the cursor were in the
name of the method in our example it would return `["source.js", "meta.function.js", "entity.name.function.js"]`
- {TextEditor::getRootScopeDescriptor} to get the language’s descriptor; for example, `[".source.js"]`.
- {TextEditor::scopeDescriptorForBufferPosition} to get the descriptor at a specific position in the buffer.
- {Cursor::getScopeDescriptor} to get a cursor’s descriptor based on position; this method (and the method above) will return a {ScopeDescriptor} with multiple scopes. For instance, if the cursor were in the name of a function in a class definition, the descriptor might contain an array of scopes like `["source.js", "meta.function.js", "entity.name.function.js"]`.

:::note Why the asymmetry?
You may wonder why you set config values with a _scope selector_ (a single string) but retrieve them with a _scope descriptor_ (an array of multiple scopes).

The scope selector for setting a configuration value will usually be determined by a human, and a CSS selector is a natural, human-readable way of expressing that context. If necessary, you can express complex hierarchies in the selector you pass to {Config::set}… but usually you won’t need to.

Retrieval of scope-specific settings via {Config::get} will usually be performed with scope contexts retrieved by one of the methods above, rather than by something “hand-crafted” by a human. These APIs could return a scope context to you as one very long string instead of a {ScopeDescriptor}, but we don’t think you’d appreciate it. It’s much easier to comprehend as a list.

:::

Let's revisit our example using these methods:

Expand Down
Loading

0 comments on commit 5b53684

Please sign in to comment.