Просмотр исходного кода

tree sitter, but not work at all

Johan Rong 1 день назад
Родитель
Сommit
9a08042e4e

+ 4 - 4
go.mod

@@ -5,8 +5,9 @@ go 1.27
 require (
 	github.com/creasty/defaults v1.8.0
 	github.com/davecgh/go-spew v1.1.1
+	github.com/gdamore/tcell/v2 v2.13.10
 	github.com/gdamore/tcell/v3 v3.4.2
-	github.com/malivvan/tree-sitter v0.0.1
+	github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82
 	github.com/yuin/gopher-lua v1.1.2
 	github.com/zyedidia/rope v0.0.0-20210616205215-37fbf22eab3a
 	golang.design/x/clipboard v0.9.0
@@ -18,9 +19,8 @@ require (
 	github.com/ebitengine/purego v0.10.2 // indirect
 	github.com/gdamore/encoding v1.0.1 // indirect
 	github.com/lucasb-eyer/go-colorful v1.4.1 // indirect
-	github.com/mattn/go-pointer v0.0.1 // indirect
-	github.com/tetratelabs/wazero v1.12.0 // indirect
-	github.com/tree-sitter/go-tree-sitter v0.25.0 // indirect
+	github.com/rivo/uniseg v0.4.7 // indirect
+	github.com/stretchr/testify v1.10.0 // indirect
 	golang.design/x/x11 v0.2.0 // indirect
 	golang.org/x/exp/shiny v0.0.0-20260820142414-ca536658362e // indirect
 	golang.org/x/image v0.45.0 // indirect

+ 12 - 10
go.sum

@@ -10,20 +10,20 @@ github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7
 github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
 github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
+github.com/gdamore/tcell/v2 v2.13.10 h1:Afs3JKt83HnhuUKdZ3MnxUgOqQRWftj5JyDqv1LLynA=
+github.com/gdamore/tcell/v2 v2.13.10/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo=
 github.com/gdamore/tcell/v3 v3.4.2 h1:gGW+6z2Bz5Wl2mNwFlm9+eRmg2JQrWcKjSkL1LRfpNU=
 github.com/gdamore/tcell/v3 v3.4.2/go.mod h1:Oe5U3S3jm3NzypswDNUhe+LUnF5CoFq2b4sepD++QHo=
 github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss=
 github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
-github.com/malivvan/tree-sitter v0.0.1 h1:dlU+RIMzizvWygTQ6gCRKeNMrUhV7rw+uxgozE+kw1M=
-github.com/malivvan/tree-sitter v0.0.1/go.mod h1:8P6n6OqHoda94dibHUVYMGEh7cq7z/V3QhNMqdXiW5E=
-github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
-github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
-github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
-github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
-github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
-github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
-github.com/tree-sitter/go-tree-sitter v0.25.0 h1:sx6kcg8raRFCvc9BnXglke6axya12krCJF5xJ2sftRU=
-github.com/tree-sitter/go-tree-sitter v0.25.0/go.mod h1:r77ig7BikoZhHrrsjAnv8RqGti5rtSyvDHPzgTPsUuU=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82 h1:6C8qej6f1bStuePVkLSFxoU22XBS165D3klxlzRg8F4=
+github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82/go.mod h1:xe4pgH49k4SsmkQq5OT8abwhWmnzkhpgnXeekbx2efw=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA=
 github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8=
@@ -75,3 +75,5 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 1 - 3
internal/extension/extension.go

@@ -4,7 +4,6 @@ import (
 	"embed"
 	"fmt"
 	"moose/internal/editor"
-	"moose/internal/extension/highlight"
 	"path/filepath"
 	"strings"
 
@@ -14,7 +13,6 @@ import (
 type ExtensionManager struct {
 	L           *lua.LState
 	M           *editor.Model
-	HE			*highlight.HighlightEngine
 	LoadedFiles []string
 
 	currentDiskDir  string
@@ -28,7 +26,6 @@ func NewExtensionManager(m *editor.Model) *ExtensionManager {
 	em := &ExtensionManager{
 		L: lua.NewState(),
 		M: m,
-		HE: highlight.NewHighlightEngine(),
 	}
 
 	lua.OpenPackage(em.L)
@@ -131,6 +128,7 @@ func (em *ExtensionManager) registerAPI() {
 	moose := em.L.NewTable()
 	em.L.SetGlobal("ms", moose)
 	moose.RawSetString("config", GetConfigTable(em))
+	moose.RawSetString("syntax", GetSyntaxTable(em))
 }
 
 func (em *ExtensionManager) LoadFile(path string) error {

+ 0 - 21
internal/extension/highlight/hightlight.go

@@ -1,21 +0,0 @@
-package highlight
-
-import (
-	"context"
-
-	"github.com/tetratelabs/wazero"
-	//"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
-)
-
-type HighlightEngine struct {
-}
-
-func NewHighlightEngine() *HighlightEngine {
-	ctx := context.Background()
-	r := wazero.NewRuntime(ctx)
-	defer r.Close(ctx)
-
-	return &HighlightEngine {
-		
-	}
-}

+ 109 - 0
internal/extension/highlight/registry.go

@@ -0,0 +1,109 @@
+package highlight
+
+/*
+#cgo LDFLAGS: -ldl
+#include <dlfcn.h>
+#include <stdlib.h>
+
+// Helper to resolve the C function pointer for tree_sitter_<lang>()
+void* load_symbol(void* handle, const char* symbol) {
+    return dlsym(handle, symbol);
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"sync"
+	"unsafe"
+	"strings"
+	"unicode"
+	"path/filepath"
+
+	sitter "github.com/smacker/go-tree-sitter"
+)
+
+type LanguageSpec struct {
+	Name     string
+	Language *sitter.Language
+	Query    *sitter.Query
+}
+
+type Registry struct {
+	mu        sync.RWMutex
+	languages map[string]*LanguageSpec
+}
+
+var GlobalRegistry = &Registry{
+	languages: make(map[string]*LanguageSpec),
+}
+
+func CleanScmQuery(scm string) string {
+	cleaned := strings.Map(func(r rune) rune {
+		if r == '\uFEFF' { // Remove UTF-8 Byte Order Mark (BOM)
+			return -1
+		}
+		if unicode.IsSpace(r) && r != '\n' && r != '\r' && r != '\t' {
+			return ' '
+		}
+		return r
+	}, scm)
+
+	return strings.TrimSpace(cleaned)
+}
+
+func RegisterTreeSitterLang(langName, parserPath, queryScm string) error {
+	absPath, err := filepath.Abs(parserPath)
+	if err == nil {
+		parserPath = absPath
+	}
+
+	cPath := C.CString(parserPath)
+	defer C.free(unsafe.Pointer(cPath))
+
+	handle := C.dlopen(cPath, C.RTLD_NOW)
+	if handle == nil {
+		errStr := C.GoString(C.dlerror())
+		return fmt.Errorf("failed to load parser library at %s: %s", parserPath, errStr)
+	}
+
+	symbolName := C.CString(fmt.Sprintf("tree_sitter_%s", langName))
+	defer C.free(unsafe.Pointer(symbolName))
+
+	sym := C.load_symbol(handle, symbolName)
+	if sym == nil {
+		return fmt.Errorf("symbol 'tree_sitter_%s' not found in %s", langName, parserPath)
+	}
+
+	ptr := unsafe.Pointer(sym)
+	sitterLang := sitter.NewLanguage(ptr)
+	if sitterLang == nil {
+		return fmt.Errorf("invalid TSLanguage pointer returned for %s", langName)
+	}
+
+	cleanScm := CleanScmQuery(queryScm)
+	query, err := sitter.NewQuery([]byte(cleanScm), sitterLang)
+	if err != nil {
+		if qErr, ok := err.(*sitter.QueryError); ok {
+			return fmt.Errorf("query compile error at byte offset %d (type: %v)", qErr.Offset, qErr.Type)
+		}
+		return fmt.Errorf("failed to compile highlight query for %s: %w", langName, err)
+	}
+
+	GlobalRegistry.mu.Lock()
+	GlobalRegistry.languages[langName] = &LanguageSpec{
+		Name:     langName,
+		Language: sitterLang,
+		Query:    query,
+	}
+	GlobalRegistry.mu.Unlock()
+
+	return nil
+}
+
+func (r *Registry) GetLanguage(langName string) (*LanguageSpec, bool) {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	spec, ok := r.languages[langName]
+	return spec, ok
+}

+ 43 - 0
internal/extension/syntax.go

@@ -0,0 +1,43 @@
+package extension
+
+import (
+	lua "github.com/yuin/gopher-lua"
+	"moose/internal/extension/highlight"
+)
+
+func GetSyntaxTable(em *ExtensionManager) *lua.LTable {
+	syntax := em.L.NewTable()
+	em.L.SetFuncs(syntax, map[string]lua.LGFunction{
+		"registerLang": luaRegisterLanguage,
+	})
+	return syntax
+}
+
+func luaRegisterLanguage(L *lua.LState) int {
+	idx := 1
+	if L.GetTop() >= 2 && L.Get(1).Type() == lua.LTTable {
+		tb1 := L.ToTable(1)
+		if tb1.RawGetString("name") == lua.LNil {
+			idx = 2
+		}
+	}
+
+	tb := L.CheckTable(idx)
+
+	langName := tb.RawGetString("name").String()
+	parserPath := tb.RawGetString("parser_path").String()
+	queryScm := tb.RawGetString("query").String()
+
+	if langName == "" || langName == "nil" || parserPath == "" || parserPath == "nil" {
+		L.ArgError(idx, "expected table with 'name' and 'parser_path' fields")
+		return 0
+	}
+
+	err := highlight.RegisterTreeSitterLang(langName, parserPath, queryScm)
+	if err != nil {
+		L.RaiseError("failed to register language %s: %v", langName, err)
+		return 0
+	}
+
+	return 0
+}