Skip to content

Commit

Permalink
Add a glossary (#354)
Browse files Browse the repository at this point in the history
* Outline for glossary and initial set of terms

* Add more glossary entries (#635)

---------

Co-authored-by: Cameron Duley <[email protected]>
  • Loading branch information
zachallaun and Moosieus authored Mar 4, 2024
1 parent 1e2aa3e commit 81441fa
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 10 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ faster.

Follow the [Detailed Installation Instructions](pages/installation.md)

```
mix package
```
```
mix package
```

Lexical will now be available in `_build/dev/package/lexical`
Lexical will now be available in `_build/dev/package/lexical`

If you would like to change the output directory, you can do so with the `--path` option

Expand Down Expand Up @@ -112,6 +112,7 @@ mix benchmark /benchmarks/<benchmark_file>.exs
```

### Logging

When lexical starts up, it creates a `.lexical` directory in the root
directory of a project. Inside that directory are two log files,
`lexical.log` and `project.log`. The `.lexical.log` log file contains
Expand Down Expand Up @@ -202,3 +203,8 @@ iex(2)> complete :other, "defmo|"
The same kind of support is available when you run `iex -S mix` in the
lexical directory, and is helpful for narrowing down issues without
disturbing your editor flow.

### Other resources

* [Architecture](pages/architecture.md)
* [Glossary](pages/glossary.md)
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ defmodule Lexical.LanguageServer.MixProject do
README.md
pages/installation.md
pages/architecture.md
pages/glossary.md
),
filter_modules: fn mod_name, _ ->
case Module.split(mod_name) do
Expand Down
20 changes: 14 additions & 6 deletions pages/architecture.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
# Architecture

## Project Structure

Lexical is designed to keep your application isolated from lexical's code. Because of this, lexical is structured as an umbrella app, with the following sub-apps:

* `core`: Contains all code common to the other applications.
* `common`: Contains all code common to the other applications.
* `proto`: Used by `protocol` to generate the Elixir representation of LSP data structures.
* `protocol`: Code related to speaking the language server protocol.
* `remote_control`: The application that's injected into a project's code, which
gives lexical an API to do things in the context of your app.
gives lexical an API to do things in the context of your app.
* `server` The language server itself.

Lexical is an umbrella app so we can control how many dependencies the remote control app has. By separating lexical into sub-applications, each is built as a separate archive, and we can pick and choose which of these applications (and their dependencies) are injected into the project's VM, thus reducing how much contamination the project sees. If lexical was a standard application, adding dependencies to lexical would cause those dependencies to appear in the project's VM, which might cause build issues, version conflicts in mix or other inconsistencies.

Since the `remote_control` app only depends on `common`, `path_glob` and `elixir_sense`, only those applications pollute the project's vm. Keeping `remote_control`'s dependencies to a minimum is a design goal of this architecture.


## Language Server
The language server (the `server` app) is the entry point to Lexical. When started by the `start_lexical.sh` command, it sets up a [transport](`Lexical.Server.Transport`) that [reads JsonRPC from standard input and writes responses to standard output](`Lexical.Server.Transport.StdIO`).

The language server (the `server` app) is the entry point to Lexical. When started by the `start_lexical.sh` command, it sets up a [transport](`Lexical.Server.Transport`) that [reads JsonRPC from standard input and writes responses to standard output](`Lexical.Server.Transport.StdIO`).

When a message is received, it is parsed into either a [LSP Request](`Lexical.Protocol.Requests`) or a [LSP Notification](`Lexical.Protocol.Notifications`) and then it's handed to the [language server](`Lexical.Server`) to process.

The only messages the [lexical server process](`Lexical.Server`) handles directly are those related to the lifecycle of the language server itself. All other messages are delegated to a _Provider Handler_. This delegation is accomplished by the server process adding the request to the [provider queue](`Lexical.Server.Provider.Queue`). The provider queue asks the `Lexical.Server.Provider.Handlers.for_request/1` function which handler is configured to handle the request, creates a task for the handler and starts it.
The only messages the [lexical server process](`Lexical.Server`) handles directly are those related to the lifecycle of the language server itself:

- Synchronizing document states.
- Processing LSP configuration changes.
- Performing initialization and shutdown.

A _Provider Handler_ is just a module that defines a function of arity 2 that takes the request to handle and a `Lexical.Server.Provider.Env`. These functions can reply to the request, ignore it, or do some other action.
All other messages are delegated to a _Provider Handler_. This delegation is accomplished by the server process adding the request to the [provider queue](`Lexical.Server.Provider.Queue`). The provider queue asks the `Lexical.Server.Provider.Handlers.for_request/1` function which handler is configured to handle the request, creates a task for the handler and starts it.

A _Provider Handler_ is just a module that defines a function of arity 2 that takes the request to handle and a `Lexical.Server.Provider.Env`. These functions can reply to the request, ignore it, or do some other action.
86 changes: 86 additions & 0 deletions pages/glossary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Glossary
This project uses a considerable amount of jargon, some adopted from the Language Server Protocol and some specific to Lexical.

This glossary attempts to define jargon used in this codebase.
Though it is not exhaustive, we hope it helps contributors more easily navigate and understand existing code and the goal, and that it provides some guidance for naming new things.

**You can help!** If you run across a new term while working on Lexical and you think it should be defined here, please [open an issue](https://github.com/lexical-lsp/lexical/issues) suggesting it!

## Language Server Protocol (LSP)

This section covers features, names, and abstractions used by Lexical that have a correspondence to the Language Server Protocol. For a definitive reference, see the [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/specification-current).

### Messages, Requests, Responses, and Notifications

LSP defines a general heirarchy of the types of messages langauge servers and clients and may exchange, and the expected behaviours associated with them.

There's 3 top-level types of messages: [Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage), [Responses](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage), and [Notifications](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage):

- [Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) are sent from client to server and vice versa, and must always be answered with a [Response](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage).

- [Notifications](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) are likewise bi-directional and work like events. They expressly do not receive responses per LSP's specification.

From these 3 top-level types, LSP defines more specific more concrete, actionable messages such as:
- [Completion Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion)
- [Goto Definition Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition)
- [WillSaveTextDocument Notifications](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_willSave)

... and many more. These can serve as good reference for the specific features you're working on.

Lexical maps these in the modules [`Lexical.Protocol.Requests`](https://github.com/lexical-lsp/lexical/blob/main/apps/protocol/lib/lexical/protocol/requests.ex), [`Lexical.Protocol.Responses`](https://github.com/lexical-lsp/lexical/blob/main/apps/protocol/lib/lexical/protocol/responses.ex), and[ `Lexical.Protocol.Notifications`](https://github.com/lexical-lsp/lexical/blob/main/apps/protocol/lib/lexical/protocol/notifications.ex).

Finally, it's worth noting all messages are JSON, specifically [JSON-RPC version 2.0](https://www.jsonrpc.org/specification).

### Document(s)

A single file identified by a URI and contains textual content. Formally referred to as [Text Documents](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocuments) in LSP and modeled as [`Lexical.Document`](https://github.com/lexical-lsp/lexical/blob/main/projects/lexical_shared/lib/lexical/document.ex) structs in Lexical.

### Diagnostics

Represents a diagnostic, such as a compiler error or warning. Diagnostic objects are only valid in the scope of a resource.

### Completions and Code Intelligence

Auto-completion suggestions that appear in an editor's IntelliSense. For example, a user that's typed `IO.in|` may be suggested `IO.inspect(|)` as one of a few possible completions.

### Code Actions

A code action represents a change that can be performed in code. In VSCode they typically appear as "quick fixes" next to an error or warning, but they aren't exclusive to that. In fact, VSCode frequently requests available code actions while users are browsing and editing code.

LSP defines a protocol for language servers to tell clients what actions they're capable of performing, and for clients to request those actions be taken. See for example LSP's [CodeActionClientCapabilities interface](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeActionClientCapabilities).

## Concepts exclusive to Lexical

This section briefly summarizes abstractions introduced by Lexical. Detailed information can be found in the respective moduledocs.

### The Project struct

An Elixir struct that represents the current state of an elixir project. See `Lexical.Project`.

### The Convertible protocol

Some LSP data structures cannot be trivially converted to Elixir terms.

The `Lexical.Convertible` protocol helps centralize the necessary conversion logic where this is the case.

### The Transport Behaviour

A behaviour responsible for reading, writing, serializing, and deserializing messages between the LSP client and Lexical language server.

The behaviour is defined in `Lexical.Server.Transport`, with the implementation for stdio in `Lexical.Server.Transport.StdIO`.

### The Translatable protocol and Translation modules

The `Lexical.Completion.Translatable` protocol specifies how Elixir language constructs (such as behaviour callbacks) are converted into LSP constructs (such as [completion items](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem)).

See `Lexical.Server.CodeIntelligence.Completion.Translations` for various implementations.

### Code Mods

A variety of modules that change existing code in some way. They take a document, modify it, and return diffs.

Examples of code mods include:
* Formatting code in a file (`> Format Document`/`shift`+`alt`+`f` in VSCode).
* Prefixing unused variables with an `_`.

Code mods are defined in the `remote_control` sub-app and are executed in the project's virutal machine.

0 comments on commit 81441fa

Please sign in to comment.