turbo-editors/turbo-corepublic Fork 0
main
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.

profile.go · 184 lines · 6.8 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 12h ago1// Package profile holds everything that makes one editor built on turbo-core
2// differ from another: what it is called, which language it is for, which
3// language server it talks to, and the starter files it writes.
4//
5// It is the seam the whole library turns on. Turbo Go, Turbo Rust, Turbo
6// Python, Turbo MoonBit, Turbo Golo and Turbo JS are the same editor with six
7// different values of this type, so anything that would otherwise be a
8// hardcoded "turbo-go" or "gopls" is a field here instead.
9//
10// The package is deliberately data and nothing else — no filesystem beyond the
11// user's configuration directory, no processes, no colours — so that every
12// other package in the library can depend on it without acquiring a dependency
13// of its own.
14//
15// p := profile.Profile{
16// Name: "Turbo Go",
17// Slug: "turbo-go",
18// Language: "Go",
19// }
20// p.ProjectDir() // ".turbo-go"
21package profile
22
23import (
24 "os"
25 "path/filepath"
26 "strings"
27)
28
29// Profile is one editor's identity and the language it is built for.
30//
31// The zero value is not useful: Slug is what every derived path is built from,
32// and an editor without one would write its project files into a directory
33// called ".".
34type Profile struct {
35 // Name is what the editor calls itself, in its window titles and its About
36 // box: "Turbo Go", "Turbo Rust".
37 Name string
38
39 // Slug is its one-word name: "turbo-go". The binary, the project directory
40 // (with a dot in front of it), the user's own configuration directory and
41 // the environment variables that override them are all built from it.
42 Slug string
43
44 // Language names what the editor is for, in prose meant to be read: "Go",
45 // "Rust". It appears in messages, not in file formats.
46 Language string
47
48 // ToolsMenu is the label of the menu the project's own commands appear in,
49 // with its hot key marked: "~G~o", "Rus~t~". The plain name — what a tools
50 // file writes in its menu key — is this with the markers taken out.
51 ToolsMenu string
52
53 // RootMarkers are the files that mark the root of a project, in the order
54 // they are looked for: "go.mod", "Cargo.toml". The language server is
55 // started in the first directory above the file being edited that holds
56 // one of them.
57 RootMarkers []string
58
59 // Server is the language server this editor talks to.
60 Server Server
61
62 // Templates are the starter files the editor offers to write.
63 Templates Templates
64}
65
66// Server describes the language server an editor talks to, in enough detail to
67// find it, start it, and say what to do when it is missing.
68type Server struct {
69 // Command is the executable's name: "gopls", "rust-analyzer".
70 Command string
71
72 // Args are the arguments it is started with. gopls wants "serve";
73 // rust-analyzer wants none.
74 Args []string
75
76 // InstallHint is a single command the user can copy when the server is not
77 // installed. It is shown on the status bar, so it has to fit on a line.
78 InstallHint string
79
80 // Dirs are extra directories to look in when PATH has nothing, in the order
81 // they are tried: GOPATH/bin for Go, ~/.cargo/bin for Rust. They are
82 // resolved by the editor at start-up, because working them out means
83 // reading environment variables this package deliberately does not know
84 // about.
85 Dirs []string
86}
87
88// Templates are the files the editor writes into a project's own directory
89// when asked to, one per menu item that offers to create one.
90//
91// They are held here rather than compiled into the packages that write them
92// because their contents are the one part of those files that is about a
93// particular language: a Go project's tools are `go build ./...`, a Rust
94// project's are `cargo build`.
95type Templates struct {
96 // Settings is the starter settings.toml. It is formatted with two
97 // arguments, in this order: the theme name and the autosave delay, both
98 // with %q.
99 Settings string
100
101 // Snippets is the starter snippets.toml. It is formatted with two
102 // arguments, in this order: the name of the group an ungrouped snippet
103 // falls into, and the path to the user's own snippets file, both with %s.
104 Snippets string
105
106 // Tools is the starter tools.toml. It takes no formatting arguments.
107 Tools string
108
109 // Agents is the starter acp.toml, listing the coding agents the editor can
110 // open a window on. It is formatted with two arguments, in this order: the
111 // editor's own project directory — ".turbo-go" — and the path to the
112 // user's own agents file, both with %s.
113 Agents string
114}
115
116// ProjectDir returns the directory this editor keeps a project's own files in:
117// its settings, its snippets, its tools.
118//
119// It is the slug with a dot in front, which is the convention every other tool
120// in a repository follows.
121//
122// profile.Profile{Slug: "turbo-go"}.ProjectDir() // ".turbo-go"
123func (p Profile) ProjectDir() string { return "." + p.Slug }
124
125// UserDir returns the directory this editor keeps the user's own files in — the
126// ones that follow them between projects — or "" when the system cannot say
127// where that would be.
128//
129// The environment variable named by DirEnvVar wins when it is set, which is
130// what lets a test point the editor at a directory of its own instead of at the
131// real one.
132//
133// profile.Profile{Slug: "turbo-go"}.UserDir() // "~/.config/turbo-go"
134func (p Profile) UserDir() string {
135 if dir := os.Getenv(p.DirEnvVar()); dir != "" {
136 return dir
137 }
138
139 config, err := os.UserConfigDir()
140 if err != nil {
141 return ""
142 }
143 return filepath.Join(config, p.Slug)
144}
145
146// ThemeDir returns the directory the user's own themes are read from, or ""
147// when there is nowhere to read them from.
148//
149// The environment variable named by ThemeDirEnvVar wins when it is set, and
150// names the theme directory itself rather than the directory above it — a test
151// wants to say exactly where the themes are.
152func (p Profile) ThemeDir() string {
153 if dir := os.Getenv(p.ThemeDirEnvVar()); dir != "" {
154 return dir
155 }
156
157 user := p.UserDir()
158 if user == "" {
159 return ""
160 }
161 return filepath.Join(user, "themes")
162}
163
164// DirEnvVar names the environment variable that overrides UserDir.
165//
166// profile.Profile{Slug: "turbo-go"}.DirEnvVar() // "TURBO_GO_DIR"
167func (p Profile) DirEnvVar() string { return p.envPrefix() + "_DIR" }
168
169// ThemeDirEnvVar names the environment variable that overrides ThemeDir.
170//
171// profile.Profile{Slug: "turbo-go"}.ThemeDirEnvVar() // "TURBO_GO_THEME_DIR"
172func (p Profile) ThemeDirEnvVar() string { return p.envPrefix() + "_THEME_DIR" }
173
174// SnippetDirEnvVar names the environment variable that overrides where the
175// user's own snippets are read from.
176//
177// profile.Profile{Slug: "turbo-go"}.SnippetDirEnvVar() // "TURBO_GO_SNIPPET_DIR"
178func (p Profile) SnippetDirEnvVar() string { return p.envPrefix() + "_SNIPPET_DIR" }
179
180// envPrefix turns the slug into the shape an environment variable takes:
181// upper case, with dashes as underscores.
182func (p Profile) envPrefix() string {
183 return strings.ToUpper(strings.ReplaceAll(p.Slug, "-", "_"))
184}