turbo-editors/turbo-corepublic Fork 0
v0.9.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

🛟 Updated. 28d5985 · on v0.9.0 · k33g · 16h ago
app.md · 129 lines · 8.7 KBmarkdown
Blame HistoryOpen raw

Reference: the app API

Neutral description of what a command may call on an editor built on turbo-core. This is not the whole of app; it is the part a command and its tests use.

Construction

Function Description
New(screen tcell.Screen, themeName string, p profile.Profile) *App An editor drawing on screen, being the editor p describes. An unknown theme name falls back to the default rather than failing.
ProjectRoot(p profile.Profile, files []string) string The directory a language server should work in: the nearest directory at or above the first file holding one of p.RootMarkers, or the working directory.

Running it

Method Description
Run() error Draws and handles events until the user leaves. Returns nil when the screen was finalised.
Quitting() bool Whether the editor is on its way out.
Tick() One turn of the loop's state-driven work, without waiting for an event.
Handle(event tcell.Event) Routes one event through the whole chain, as the loop does.
Render() Lays out and paints one frame.

Tick, Handle and Render are exported so an editor can drive itself end to end from a test, with no terminal and no event loop.

Files

Method Description
NewFile() Opens an empty window.
Open(path string) Opens a file, raising the window when it is already open.
SaveFile(), SaveFileAs(), CloseFile() As the File menu.
Undo(), Redo(), Cut(), Copy(), Paste(), SelectAll() As the Edit menu. Redo is Ctrl-R; Ctrl-Y deletes a line.
InsertLine(), DeleteLine() Turbo C's Ctrl-N and Ctrl-Y: a blank line opened above the cursor, and the cursor's own line removed.
ActiveView() *editor.View The editing view of the front window, or nil when it is a terminal, the tree, or nothing.

Settings

Method Description
UseSettings(s settings.Settings, path string) Applies a project's settings and remembers where they came from. The theme is not applied here — the caller resolves it, because a -theme flag overrides the project's choice.
SettingsPath() string The settings file being followed, or "".
SetAutosave(on bool, delay time.Duration) Turns autosave on or off.

The settings file is also re-read after every save that writes it, from either save path, so a change made in the editor takes effect without a restart. Autosave and its delay are re-applied; the theme is not. A file that no longer parses reports Saved, but not applied: … and leaves the previous values in force.

The project's three files

settings.toml, snippets.toml and tools.toml behave alike, and exactly one of each create/open pair is ever available: you can create the file the project has not got, and open the one it has. The menus grey out the other.

Method Description
CreateProjectSettings(), CreateSnippets(), CreateTools() Write the starter file from the profile's template and open it. Creating over an existing file reports Already there and opens it unchanged — unreachable from the menu, which greys the item out.
OpenProjectSettings(), OpenSnippets(), OpenTools() Open the project's file. Never writes: a project without one is told which item makes it. OpenSnippets opens the project's file, never the user's.
HasProjectSettings() bool, HasProjectSnippets() bool, HasProjectTools() bool Whether the project has each file. What decides, for all six menu items, which of the pair is greyed out.

The language server

Method Description
StartLanguageServer(ctx context.Context, root string) Starts it in the background, so a slow start-up does not hold the first keystroke up.
Language() *Language The language-server side. Every method on it is a no-op when nothing is connected.
RequestCompletion() Asks for a completion at the cursor.
DescribeSymbol(), GoToDefinition(), GoToTypeDefinition(), FindImplementations(), FindReferences() The Code menu's questions about the symbol under the cursor. Each jumps when there is one answer, offers a list when there are several, and distinguishes "nothing found" from "the server is not ready".
SymbolInFile(), SymbolInProject() The file's own outline, and a search across the project. Both always offer the list, even for a single match: finding which thing has a name is the answer.
ShowProblems() Every diagnostic the server has reported, for every file it has spoken about.

Language

Method Description
Ready() bool Whether a server is connected and initialised.
Knows(path string) bool Whether the server has been told the document is open. Spelling-independent: a file opened by a relative path is known by its absolute one too.
Status() string The one-line state shown on the status bar.
Report() Report Status, server path, root and readiness together.
Stop(ctx context.Context) Shuts the server down.
TypeDefinition, Implementation, References The three location requests beside Definition. References counts the declaration as one of the answers.
DocumentSymbols(ctx, path) ([]lsp.Symbol, error) What one file declares, flattened, in file order.
WorkspaceSymbols(ctx, query) ([]lsp.Symbol, error) Symbols matching a query anywhere in the project. What "matching" means belongs to the server.
Diagnostics(path string) []lsp.Diagnostic What the server reported for a file. The path is resolved to an absolute one first: a server publishes absolute URIs and a buffer may hold the relative path the command line gave it.
FirstError(path string) (lsp.Diagnostic, bool) The first error-level diagnostic.
AllDiagnostics() []FileDiagnostic Every problem for every file, sorted by file then line.

Saving keeps the server's set of open documents true. Writing a file the server knows sends didSave; writing one it does not know — a window that began Untitled, saved for the first time — sends didOpen, so the document works from that save on. Save As under a genuinely different name also closes the old document on the server first; a mere change of spelling of the same file does not count as a rename.

What is on screen

Method Description
Profile() profile.Profile Which editor this is.
Theme() *theme.Theme, ThemeName() string The theme in use.
Desktop() *ui.Desktop The windows.
MenuBar() *ui.MenuBar The bar.
StatusBar() *ui.StatusBar The bar along the bottom.
Completion() *CompletionBox The completion popup.
Modals() int, TopModal() *ui.Dialog The dialog stack.
Message(text string) A one-line note on the status bar.
ShowMessage(title, message string) A modal box.

Tool parameters

A command may ask for values before it runs, by writing {{label}} where the value goes. app.RunTool opens a box for them; nothing here draws anything.

Function or method Description
(Tool) Placeholders() []Placeholder The values the command asks for, in first-appearance order, a repeated label reported once. Nil when it asks for none.
(Tool) Fill(values map[string]string) string The command with every placeholder replaced. A value is shell-quoted unless its placeholder is Raw; a label with no entry becomes empty.
ShellQuote(value string) string Wraps a string so sh -c sees exactly one argument, whatever is in it.
Placeholder field Type Description
Label string What to ask for: the text between the braces, trimmed, without a trailing ....
Raw bool The value goes in verbatim rather than shell-quoted.

Load refuses a command with an unclosed {{ or a placeholder with no label, so a Tool that came from a file always parses.

Function Description
app.MaxParameterFields(screenHeight int) int How many values a box can ask for on a screen that tall. A caller with more to ask must say so rather than opening one.
app.NewParametersDialog(title string, labels []string, initial map[string]string, screen ui.Rect) *ParametersDialog The box. initial pre-fills a field by label.
(*ParametersDialog) Dialog() *ui.Dialog The modal to push.
(*ParametersDialog) Values() map[string]string What was typed, by label.

Errors

app returns no errors from its actions: everything that can fail is reported to the user on the status bar or in a dialog, because the editor is what they would use to fix it.

See also

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Reference: the app API

> Neutral description of what a command may call on an editor built on turbo-core. This is not the whole of `app`; it is the part a command and its tests use.

## Construction

| Function | Description |
| --- | --- |
| `New(screen tcell.Screen, themeName string, p profile.Profile) *App` | An editor drawing on `screen`, being the editor `p` describes. An unknown theme name falls back to the default rather than failing. |
| `ProjectRoot(p profile.Profile, files []string) string` | The directory a language server should work in: the nearest directory at or above the first file holding one of `p.RootMarkers`, or the working directory. |

## Running it

| Method | Description |
| --- | --- |
| `Run() error` | Draws and handles events until the user leaves. Returns nil when the screen was finalised. |
| `Quitting() bool` | Whether the editor is on its way out. |
| `Tick()` | One turn of the loop's state-driven work, without waiting for an event. |
| `Handle(event tcell.Event)` | Routes one event through the whole chain, as the loop does. |
| `Render()` | Lays out and paints one frame. |

`Tick`, `Handle` and `Render` are exported so an editor can drive itself end to end from a test, with no terminal and no event loop.

## Files

| Method | Description |
| --- | --- |
| `NewFile()` | Opens an empty window. |
| `Open(path string)` | Opens a file, raising the window when it is already open. |
| `SaveFile()`, `SaveFileAs()`, `CloseFile()` | As the File menu. |
| `Undo()`, `Redo()`, `Cut()`, `Copy()`, `Paste()`, `SelectAll()` | As the Edit menu. Redo is `Ctrl-R`; `Ctrl-Y` deletes a line. |
| `InsertLine()`, `DeleteLine()` | Turbo C's `Ctrl-N` and `Ctrl-Y`: a blank line opened above the cursor, and the cursor's own line removed. |
| `ActiveView() *editor.View` | The editing view of the front window, or nil when it is a terminal, the tree, or nothing. |

## Settings

| Method | Description |
| --- | --- |
| `UseSettings(s settings.Settings, path string)` | Applies a project's settings and remembers where they came from. The theme is not applied here — the caller resolves it, because a `-theme` flag overrides the project's choice. |
| `SettingsPath() string` | The settings file being followed, or `""`. |
| `SetAutosave(on bool, delay time.Duration)` | Turns autosave on or off. |

The settings file is also re-read **after every save that writes it**, from either save path, so a change made in the editor takes effect without a restart. Autosave and its delay are re-applied; the theme is not. A file that no longer parses reports `Saved, but not applied: …` and leaves the previous values in force.

## The project's three files

`settings.toml`, `snippets.toml` and `tools.toml` behave alike, and exactly one of each create/open pair is ever available: you can create the file the project has not got, and open the one it has. The menus grey out the other.

| Method | Description |
| --- | --- |
| `CreateProjectSettings()`, `CreateSnippets()`, `CreateTools()` | Write the starter file from the profile's template and open it. Creating over an existing file reports `Already there` and opens it unchanged — unreachable from the menu, which greys the item out. |
| `OpenProjectSettings()`, `OpenSnippets()`, `OpenTools()` | Open the project's file. Never writes: a project without one is told which item makes it. `OpenSnippets` opens the **project's** file, never the user's. |
| `HasProjectSettings() bool`, `HasProjectSnippets() bool`, `HasProjectTools() bool` | Whether the project has each file. What decides, for all six menu items, which of the pair is greyed out. |

## The language server

| Method | Description |
| --- | --- |
| `StartLanguageServer(ctx context.Context, root string)` | Starts it in the background, so a slow start-up does not hold the first keystroke up. |
| `Language() *Language` | The language-server side. Every method on it is a no-op when nothing is connected. |
| `RequestCompletion()` | Asks for a completion at the cursor. |
| `DescribeSymbol()`, `GoToDefinition()`, `GoToTypeDefinition()`, `FindImplementations()`, `FindReferences()` | The Code menu's questions about the symbol under the cursor. Each jumps when there is one answer, offers a list when there are several, and distinguishes "nothing found" from "the server is not ready". |
| `SymbolInFile()`, `SymbolInProject()` | The file's own outline, and a search across the project. Both always offer the list, even for a single match: finding *which* thing has a name is the answer. |
| `ShowProblems()` | Every diagnostic the server has reported, for every file it has spoken about. |

### Language

| Method | Description |
| --- | --- |
| `Ready() bool` | Whether a server is connected and initialised. |
| `Knows(path string) bool` | Whether the server has been told the document is open. Spelling-independent: a file opened by a relative path is known by its absolute one too. |
| `Status() string` | The one-line state shown on the status bar. |
| `Report() Report` | Status, server path, root and readiness together. |
| `Stop(ctx context.Context)` | Shuts the server down. |
| `TypeDefinition`, `Implementation`, `References` | The three location requests beside `Definition`. `References` counts the declaration as one of the answers. |
| `DocumentSymbols(ctx, path) ([]lsp.Symbol, error)` | What one file declares, flattened, in file order. |
| `WorkspaceSymbols(ctx, query) ([]lsp.Symbol, error)` | Symbols matching a query anywhere in the project. What "matching" means belongs to the server. |
| `Diagnostics(path string) []lsp.Diagnostic` | What the server reported for a file. The path is resolved to an absolute one first: a server publishes absolute URIs and a buffer may hold the relative path the command line gave it. |
| `FirstError(path string) (lsp.Diagnostic, bool)` | The first error-level diagnostic. |
| `AllDiagnostics() []FileDiagnostic` | Every problem for every file, sorted by file then line. |

Saving keeps the server's set of open documents true. Writing a file the server knows sends `didSave`; writing one it does not know — a window that began Untitled, saved for the first time — sends `didOpen`, so the document works from that save on. Save As under a genuinely different name also closes the old document on the server first; a mere change of spelling of the same file does not count as a rename.

## What is on screen

| Method | Description |
| --- | --- |
| `Profile() profile.Profile` | Which editor this is. |
| `Theme() *theme.Theme`, `ThemeName() string` | The theme in use. |
| `Desktop() *ui.Desktop` | The windows. |
| `MenuBar() *ui.MenuBar` | The bar. |
| `StatusBar() *ui.StatusBar` | The bar along the bottom. |
| `Completion() *CompletionBox` | The completion popup. |
| `Modals() int`, `TopModal() *ui.Dialog` | The dialog stack. |
| `Message(text string)` | A one-line note on the status bar. |
| `ShowMessage(title, message string)` | A modal box. |

## Tool parameters

A command may ask for values before it runs, by writing `{{label}}` where the value goes. `app.RunTool` opens a box for them; nothing here draws anything.

| Function or method | Description |
| --- | --- |
| `(Tool) Placeholders() []Placeholder` | The values the command asks for, in first-appearance order, a repeated label reported once. Nil when it asks for none. |
| `(Tool) Fill(values map[string]string) string` | The command with every placeholder replaced. A value is shell-quoted unless its placeholder is `Raw`; a label with no entry becomes empty. |
| `ShellQuote(value string) string` | Wraps a string so `sh -c` sees exactly one argument, whatever is in it. |

| `Placeholder` field | Type | Description |
| --- | --- | --- |
| `Label` | `string` | What to ask for: the text between the braces, trimmed, without a trailing `...`. |
| `Raw` | `bool` | The value goes in verbatim rather than shell-quoted. |

`Load` refuses a command with an unclosed `{{` or a placeholder with no label, so a `Tool` that came from a file always parses.

| Function | Description |
| --- | --- |
| `app.MaxParameterFields(screenHeight int) int` | How many values a box can ask for on a screen that tall. A caller with more to ask must say so rather than opening one. |
| `app.NewParametersDialog(title string, labels []string, initial map[string]string, screen ui.Rect) *ParametersDialog` | The box. `initial` pre-fills a field by label. |
| `(*ParametersDialog) Dialog() *ui.Dialog` | The modal to push. |
| `(*ParametersDialog) Values() map[string]string` | What was typed, by label. |

## Errors

`app` returns no errors from its actions: everything that can fail is reported to the user on the status bar or in a dialog, because the editor is what they would use to fix it.

## See also

- [Build an editor](../tutorials/build-an-editor.md)
- [Profile reference](profile.md)