Files
sanspie 2744cff481
ci-platforms / build (amd64, darwin, macos-15-intel) (push) Skipped
ci-platforms / build (amd64, windows, windows-2022) (push) Skipped
ci-platforms / build (arm64, darwin, macos-15) (push) Skipped
ci / checks (push) Successful in 21m57s
ci / build (amd64, linux, ubuntu-24.04) (push) Successful in 23m31s
Stage 9.6c1: project refs and refactorings without the editor (D298)
2026-10-20 12:12:18 +03:00

122 lines
2.9 KiB
Go

package assetops
import (
"os"
"path"
"regexp"
"strings"
"aego/core/ids"
"aego/editor/core/context"
"aego/editor/core/history/commands"
"aego/project/refactor"
"aego/scene/scriptcomp"
"aego/schema"
)
var scriptDecl = regexp.MustCompile(`\bscript\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{`)
func shortName(full string) string {
return full[strings.LastIndexByte(full, '.')+1:]
}
func moduleOf(ctx *context.Editor) string {
return refactor.Module(ctx.Project)
}
func ScriptPrefix(ctx *context.Editor, rel string) string {
pkg := moduleOf(ctx)
if dir := strings.TrimPrefix(strings.TrimPrefix(path.Dir(rel), "scripts"), "/"); dir != "" && dir != "." {
pkg += "/" + dir
}
return strings.ReplaceAll(pkg, "/", ".")
}
func ScriptDir(ctx *context.Editor, typeName string) string {
i := strings.LastIndexByte(typeName, '.')
if i < 0 {
return "scripts"
}
pkg := strings.ReplaceAll(typeName[:i], ".", "/")
rel := strings.TrimPrefix(strings.TrimPrefix(pkg, moduleOf(ctx)), "/")
if rel == "" {
return "scripts"
}
return "scripts/" + rel
}
func ScriptTypesIn(ctx *context.Editor, id ids.AssetID) []string {
if ctx.Pipeline == nil {
return nil
}
rel, ok := ctx.Pipeline.PathOf(id)
if !ok {
return nil
}
src, err := os.ReadFile(ctx.Pipeline.Abs(rel))
if err != nil {
return nil
}
prefix := ScriptPrefix(ctx, rel)
reg := ctx.Types.Schema()
var out []string
for _, m := range scriptDecl.FindAllSubmatch(src, -1) {
full := prefix + "." + string(m[1])
if td, ok := reg.ByName(full); ok && td.Kind == schema.TypeScript {
out = append(out, td.FullName)
}
}
return out
}
func AttachScript(ctx *context.Editor, nodes []ids.NodeID, typeName string) error {
d := ctx.Doc()
if d == nil || len(nodes) == 0 {
return nil
}
s := d.Scene()
tx := d.History.Begin("Add " + shortName(typeName))
for _, n := range nodes {
if sc, ok := scriptcomp.ScriptsOf(s, s.Handle(n)); ok && sc.Index(typeName) >= 0 {
continue
}
if err := tx.Exec(&commands.AddScript{Node: n, TypeName: typeName}); err != nil {
tx.Abort()
return err
}
}
tx.Commit()
return nil
}
func AttachScriptAsset(ctx *context.Editor, nodes []ids.NodeID, id ids.AssetID) {
types := ScriptTypesIn(ctx, id)
nodes = append([]ids.NodeID(nil), nodes...)
attach := func(name string) {
if err := AttachScript(ctx, nodes, name); err != nil {
ctx.Notify(context.LevelError, err.Error())
}
}
switch len(types) {
case 0:
ctx.Notify(context.LevelWarn, "The file has no compiled script types, fix its errors first")
case 1:
attach(types[0])
default:
buttons := make([]string, 0, len(types)+1)
for _, t := range types {
buttons = append(buttons, shortName(t))
}
ctx.Ask(context.Question{
Title: "Attach script",
Message: "This file declares several scripts. Which one should be attached?",
Buttons: append(buttons, "Cancel"),
Then: func(choice int) {
if choice >= 0 && choice < len(types) {
attach(types[choice])
}
},
})
}
}