turbo-editors/turbo-golopublic Fork 0
v1.0.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-golo.git
git clone ssh://git@rickub.com/turbo-editors/turbo-golo.git

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

📦 Turbo Golo d710c1b · on v1.0.0 · k33g · 12h ago
gololang.go · 143 lines · 6.2 KBGo Blame HistoryRaw
  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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Package gololang is everything about Turbo Golo that is about *Golo*: how
// the editor names itself, which language server it talks to, what a project's
// starter files say, and how Golo source is coloured.
//
// Everything else the editor does lives in turbo-core, which knows nothing
// about Golo. This package is the whole of the difference between Turbo Golo
// and Turbo MoonBit, which is what makes a sixth editor a matter of writing one
// of these rather than forking anything.
//
//	gololang.Register()              // teach the library to colour Golo
//	editor := app.New(screen, name, gololang.Profile())
package gololang

import (
	"rickub.com/turbo-editors/turbo-core/profile"
	"rickub.com/turbo-editors/turbo-core/syntax"
)

// Name and Slug are what the editor calls itself. The slug is also its binary,
// its project directory (as .turbo-golo) and the stem of its environment
// variables (as TURBO_GOLO_…), so it is not free to change.
const (
	Name = "Turbo Golo"
	Slug = "turbo-golo"
)

// Language is the name Golo is known by: the value LanguageOf returns for a
// .golo file, and what a snippets file writes in its languages key.
//
// It is lower case because every other name in the registry is — "golo"
// beside "toml" and "dockerfile" — while the language's own spelling, the one
// a person reads, is Profile().Language.
const Language syntax.Language = "golo"

// ServerCommand is the language server Turbo Golo talks to, and InstallHint
// the one place a user gets it from.
//
// The server is the interpreter itself: `golo lsp` puts the same binary that
// runs a script into language-server mode, reusing its lexer, parser and AST.
// So a machine that can run Golo can complete Golo, and there is nothing
// separate to install — which is why the hint names the release page that
// ships the binary rather than a package manager's command.
//
// It answers four of the nine questions turbo-core asks — completion, hover,
// definition and the file's symbols — and publishes diagnostics unasked. It
// advertises neither references, typeDefinition and implementation, nor
// workspace/symbol, so those items report nothing found. That is documented
// rather than worked around, and a test asserts it so a future golo gaining
// them is noticed.
const (
	ServerCommand = "golo"
	InstallHint   = "see https://codeberg.org/TypeUnsafe/golo-script/releases"
)

// DefaultInstallDir is where GoloScript's own install.sh puts golo, gogolo and
// wagolo. It is on PATH on almost every machine, and it is searched all the
// same for the one where it is not: "completion silently does nothing" is what
// a user sees when the editor cannot find a server they believe they installed.
const DefaultInstallDir = "/usr/local/bin"

// ServerArgs is what golo is started with.
//
// The lsp is not optional: golo with no argument starts its REPL and reads
// standard input as Golo source, which the editor would see as a server that
// answers nothing and never dies. It is a function rather than a variable so
// that no caller can append to the package's own slice.
func ServerArgs() []string { return []string{"lsp"} }

// Profile returns the editor Turbo Golo is.
//
// It is a function rather than a variable for the same reason as in every other
// editor of this family, even though nothing here reads the environment: a
// caller that mutates what it gets back — appending to Server.Dirs, say — must
// not be mutating the package's one copy.
func Profile() profile.Profile {
	return profile.Profile{
		Name: Name,
		Slug: Slug,
		// The language's own spelling. Golo is the language; GoloScript is
		// the implementation whose binary this editor talks to, the way Go is
		// the language and gc the compiler. This is what the About box and the
		// status bar read out, so it names the language.
		Language: "Golo",
		// G is free: the fixed menus take F, E, S, R, C, O, W, N and H —
		// which rules out the O of Golo but not its first letter — so the hot
		// key lands where a reader expects it. The menu is named after the
		// language and not after golo, gogolo or wagolo, because it holds
		// whatever the project put in its tools file, and the first tools
		// file anybody writes outgrows the language's own toolchain.
		ToolsMenu: "~G~olo",
		// None, on purpose. Golo has no project manifest — no golo.mod, no
		// build file — a script is a file and a program is a directory of
		// them. With nothing to look for, app.ProjectRoot hands the server
		// the directory of the file being edited, which is also all the
		// server needs: golo lsp answers about the file it is given and
		// resolves imports from the modules embedded in the binary, never
		// from disk. A marker would make the walk look like part of the rule
		// when there is no rule.
		RootMarkers: nil,
		Server: profile.Server{
			Command:     ServerCommand,
			Args:        ServerArgs(),
			InstallHint: InstallHint,
			Dirs:        ServerDirs(),
		},
		Templates: profile.Templates{
			Settings: settingsTemplate,
			Snippets: snippetsTemplate,
			Tools:    toolsTemplate,
			Agents:   agentsTemplate,
		},
	}
}

// Register teaches turbo-core to colour Golo.
//
// It is called explicitly at start-up rather than from an init function so that
// "which languages does this editor know?" is answered by reading main, not by
// working out which packages were imported.
//
// A shebang is claimed. A Golo script may open with #!/usr/bin/env golo and be
// run as a command: # opens a comment in Golo, so the interpreter reads the
// line as one, and a file with no extension whose first line names golo is
// Golo and nothing else.
func Register() {
	syntax.Register(syntax.Definition{
		Language:   Language,
		Extensions: []string{".golo"},
		Shebangs:   []string{"golo"},
		Highlight:  Highlight,
	})
}

// ServerDirs returns the directories golo is looked for in after PATH.
//
// There is one: the directory GoloScript's installer writes into. Golo has no
// per-user toolchain directory and no environment variable naming one, so
// there is nothing else to search — and listing a guess would be worse than
// listing nothing, because a directory the server is never in costs a stat
// on every start for no answer.
func ServerDirs() []string {
	return []string{DefaultInstallDir}
}