Bladeren bron

extensions

Johan Rong 4 dagen geleden
bovenliggende
commit
bb603967e5

+ 4 - 7
internal/editor/config.go

@@ -12,9 +12,9 @@ type Config struct {
 }
 
 type Properties struct {
-	GutterWidth int    `default:"4"`
-	TabSpaces 	bool   `default:"false"`
-	TabWidthSpaces int `default:"4"`
+	GutterWidth    int  `default:"4"`
+	TabSpaces      bool `default:"false"`
+	TabWidthSpaces int  `default:"4"`
 }
 
 type Colors struct {
@@ -55,7 +55,4 @@ func DefaultConfig() Config {
 	return config
 }
 
-func (m *Model) ReloadConfig() {
-	m.Config.StyleDefault = m.Config.StyleDefault.Background(tcell.GetColor(m.Config.Colors.MainBackground)).Foreground(tcell.GetColor(m.Config.Colors.MainForeground))
-	m.Screen.SetStyle(m.Config.StyleDefault)
-}
+

+ 6 - 0
internal/editor/model.go

@@ -38,6 +38,12 @@ func NewModel(screen tcell.Screen) Model {
 
 	return model
 }
+
+func (m *Model) ReloadConfig() {
+	m.Config.StyleDefault = m.Config.StyleDefault.Background(tcell.GetColor(m.Config.Colors.MainBackground)).Foreground(tcell.GetColor(m.Config.Colors.MainForeground))
+	m.Screen.SetStyle(m.Config.StyleDefault)
+}
+
 func (m *Model) CurrentActionSet() []Action {
 	switch m.Mode {
 	case ModeNormal:

+ 207 - 156
internal/extension/config.go

@@ -1,179 +1,230 @@
 package extension
 
 import (
-    "fmt"
-    "reflect"
-    "strings"
+	"fmt"
+	"reflect"
+	"strings"
 
-    "moose/internal/editor"
+	"moose/internal/editor"
 
-    "github.com/creasty/defaults"
-    lua "github.com/yuin/gopher-lua"
+	"github.com/creasty/defaults"
+	"github.com/gdamore/tcell/v3"
+	lua "github.com/yuin/gopher-lua"
 )
 
+type Config struct {
+	StyleDefault tcell.Style
+	Colors       Colors
+	Properties   Properties
+}
+
+type Properties struct {
+	GutterWidth    int  `default:"4"`
+	TabSpaces      bool `default:"false"`
+	TabWidthSpaces int  `default:"4"`
+}
+
+type Colors struct {
+	MainBackground            string `default:"#0E142E"`
+	MainForeground            string `default:"#dddddd"`
+	LineNumberBackground      string `default:"#090603"`
+	LineNumberForeground      string `default:"#dddddd"`
+	CursorColor               string `default:"#777777"`
+	CursorColorWrite          string `default:"#dddddd"`
+	PaletteBarBackground      string `default:"#3b3b3b"`
+	PaletteBarForeground      string `default:"#dddddd"`
+	PaletteInputBackground    string `default:"#090603"`
+	PaletteInputForeground    string `default:"#dddddd"`
+	InfoMsgBackground         string `default:"#090603"`
+	InfoMsgForeground         string `default:"#dddddd"`
+	WarnMsgBackground         string `default:"#090603"`
+	WarnMsgForeground         string `default:"#efc541"`
+	ErrorMsgBackground        string `default:"#090603"`
+	ErrorMsgForeground        string `default:"#ff5e56"`
+	WorkspaceBackground       string `default:"#3b3b3b"`
+	WorkspaceForeground       string `default:"#b9b9b9"`
+	WorkspaceBackgroundActive string `default:"#dddddd"`
+	WorkspaceForegroundActive string `default:"#3b3b3b"`
+	TabBackground             string `default:"#3b3b3b"`
+	TabForeground             string `default:"#b9b9b9"`
+	TabBackgroundActive       string `default:"#3b3b3b"`
+	TabForegroundActive       string `default:"#dddddd"`
+}
+
+func DefaultConfig() Config {
+	config := Config{}
+	if err := defaults.Set(&config); err != nil {
+		panic(err)
+	}
+
+	config.StyleDefault = tcell.StyleDefault.Background(tcell.GetColor(config.Colors.MainBackground)).Foreground(tcell.GetColor(config.Colors.MainForeground))
+
+	return config
+}
+
 func snakeToCamel(s string) string {
-    parts := strings.Split(strings.ToLower(s), "_")
-    for i, part := range parts {
-        if part == "" {
-            continue
-        }
-        parts[i] = strings.ToUpper(part[:1]) + part[1:]
-    }
-    return strings.Join(parts, "")
+	parts := strings.Split(strings.ToLower(s), "_")
+	for i, part := range parts {
+		if part == "" {
+			continue
+		}
+		parts[i] = strings.ToUpper(part[:1]) + part[1:]
+	}
+	return strings.Join(parts, "")
 }
 
 func parseStructTable(dst any, table *lua.LTable) error {
-    if err := defaults.Set(dst); err != nil {
-        return err
-    }
-
-    val := reflect.ValueOf(dst)
-    if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
-        return fmt.Errorf("dst must be a pointer to struct")
-    }
-
-    val = val.Elem()
-    typ := val.Type()
-
-    for i := 0; i < val.NumField(); i++ {
-        fieldVal := val.Field(i)
-        fieldType := typ.Field(i)
-
-        luaValue := table.RawGetString(fieldType.Name)
-        if luaValue == lua.LNil {
-            continue
-        }
-
-        switch fieldVal.Kind() {
-        case reflect.String:
-            if v, ok := luaValue.(lua.LString); ok {
-                fieldVal.SetString(string(v))
-            }
-
-        case reflect.Bool:
-            if v, ok := luaValue.(lua.LBool); ok {
-                fieldVal.SetBool(bool(v))
-            }
-
-        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-            if v, ok := luaValue.(lua.LNumber); ok {
-                fieldVal.SetInt(int64(v))
-            }
-
-        case reflect.Float32, reflect.Float64:
-            if v, ok := luaValue.(lua.LNumber); ok {
-                fieldVal.SetFloat(float64(v))
-            }
-
-        case reflect.Struct:
-            if tbl, ok := luaValue.(*lua.LTable); ok {
-                nested := fieldVal.Addr().Interface()
-                if err := parseStructTable(nested, tbl); err != nil {
-                    return err
-                }
-            }
-        }
-    }
-
-    return nil
+	if err := defaults.Set(dst); err != nil {
+		return err
+	}
+
+	val := reflect.ValueOf(dst)
+	if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
+		return fmt.Errorf("dst must be a pointer to struct")
+	}
+
+	val = val.Elem()
+	typ := val.Type()
+
+	for i := 0; i < val.NumField(); i++ {
+		fieldVal := val.Field(i)
+		fieldType := typ.Field(i)
+
+		luaValue := table.RawGetString(fieldType.Name)
+		if luaValue == lua.LNil {
+			continue
+		}
+
+		switch fieldVal.Kind() {
+		case reflect.String:
+			if v, ok := luaValue.(lua.LString); ok {
+				fieldVal.SetString(string(v))
+			}
+
+		case reflect.Bool:
+			if v, ok := luaValue.(lua.LBool); ok {
+				fieldVal.SetBool(bool(v))
+			}
+
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			if v, ok := luaValue.(lua.LNumber); ok {
+				fieldVal.SetInt(int64(v))
+			}
+
+		case reflect.Float32, reflect.Float64:
+			if v, ok := luaValue.(lua.LNumber); ok {
+				fieldVal.SetFloat(float64(v))
+			}
+
+		case reflect.Struct:
+			if tbl, ok := luaValue.(*lua.LTable); ok {
+				nested := fieldVal.Addr().Interface()
+				if err := parseStructTable(nested, tbl); err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	return nil
 }
 
 func parseColors(table *lua.LTable) (editor.Colors, error) {
-    var colors editor.Colors
-    err := parseStructTable(&colors, table)
-    return colors, err
+	var colors editor.Colors
+	err := parseStructTable(&colors, table)
+	return colors, err
 }
 
 func parseProperties(table *lua.LTable) (editor.Properties, error) {
-    var properties editor.Properties
-    err := parseStructTable(&properties, table)
-    return properties, err
+	var properties editor.Properties
+	err := parseStructTable(&properties, table)
+	return properties, err
 }
 
 func HandleSet(em *ExtensionManager, L *lua.LState) int {
-    key := L.CheckString(1)
-
-    switch key {
-    case "colors":
-        luaTable := L.CheckTable(2)
-        colors, err := parseColors(luaTable)
-        if err != nil {
-            L.RaiseError(err.Error())
-            return 0
-        }
-        em.M.Config.Colors = colors
-        em.M.ReloadConfig()
-        return 0
-
-    case "properties":
-        luaTable := L.CheckTable(2)
-        properties, err := parseProperties(luaTable)
-        if err != nil {
-            L.RaiseError(err.Error())
-            return 0
-        }
-        em.M.Config.Properties = properties
-        em.M.ReloadConfig()
-        return 0
-
-    default:
-        fieldName := snakeToCamel(key)
-        cfgVal := reflect.ValueOf(&em.M.Config).Elem()
-
-        propsVal := cfgVal.FieldByName("Properties")
-        if propsVal.IsValid() {
-            field := propsVal.FieldByName(fieldName)
-            if field.IsValid() && field.CanSet() {
-                value := L.CheckAny(2)
-
-                switch field.Kind() {
-                case reflect.String:
-                    if v, ok := value.(lua.LString); ok {
-                        field.SetString(string(v))
-                        em.M.ReloadConfig()
-                        return 0
-                    }
-
-                case reflect.Bool:
-                    if v, ok := value.(lua.LBool); ok {
-                        field.SetBool(bool(v))
-                        em.M.ReloadConfig()
-                        return 0
-                    }
-
-                case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                    if v, ok := value.(lua.LNumber); ok {
-                        field.SetInt(int64(v))
-                        em.M.ReloadConfig()
-                        return 0
-                    }
-
-                case reflect.Float32, reflect.Float64:
-                    if v, ok := value.(lua.LNumber); ok {
-                        field.SetFloat(float64(v))
-                        em.M.ReloadConfig()
-                        return 0
-                    }
-                }
-            }
-        }
-
-        L.RaiseError("unknown config key: %s", key)
-        return 0
-    }
+	key := L.CheckString(1)
+
+	switch key {
+	case "colors":
+		luaTable := L.CheckTable(2)
+		colors, err := parseColors(luaTable)
+		if err != nil {
+			L.RaiseError(err.Error())
+			return 0
+		}
+		em.M.Config.Colors = colors
+		em.M.ReloadConfig()
+		return 0
+
+	case "properties":
+		luaTable := L.CheckTable(2)
+		properties, err := parseProperties(luaTable)
+		if err != nil {
+			L.RaiseError(err.Error())
+			return 0
+		}
+		em.M.Config.Properties = properties
+		em.M.ReloadConfig()
+		return 0
+
+	default:
+		fieldName := snakeToCamel(key)
+		cfgVal := reflect.ValueOf(&em.M.Config).Elem()
+
+		propsVal := cfgVal.FieldByName("Properties")
+		if propsVal.IsValid() {
+			field := propsVal.FieldByName(fieldName)
+			if field.IsValid() && field.CanSet() {
+				value := L.CheckAny(2)
+
+				switch field.Kind() {
+				case reflect.String:
+					if v, ok := value.(lua.LString); ok {
+						field.SetString(string(v))
+						em.M.ReloadConfig()
+						return 0
+					}
+
+				case reflect.Bool:
+					if v, ok := value.(lua.LBool); ok {
+						field.SetBool(bool(v))
+						em.M.ReloadConfig()
+						return 0
+					}
+
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					if v, ok := value.(lua.LNumber); ok {
+						field.SetInt(int64(v))
+						em.M.ReloadConfig()
+						return 0
+					}
+
+				case reflect.Float32, reflect.Float64:
+					if v, ok := value.(lua.LNumber); ok {
+						field.SetFloat(float64(v))
+						em.M.ReloadConfig()
+						return 0
+					}
+				}
+			}
+		}
+
+		L.RaiseError("unknown config key: %s", key)
+		return 0
+	}
 }
 
 func GetConfigTable(em *ExtensionManager) *lua.LTable {
-    config := em.L.NewTable()
-    em.L.SetFuncs(config, map[string]lua.LGFunction{
-        "set": func(L *lua.LState) int {
-            return HandleSet(em, L)
-        },
-        "reload": func(L *lua.LState) int {
-            em.M.ReloadConfig()
-            return 0
-        },
-    })
-
-    return config
-}
+	config := em.L.NewTable()
+	em.L.SetFuncs(config, map[string]lua.LGFunction{
+		"set": func(L *lua.LState) int {
+			return HandleSet(em, L)
+		},
+		"reload": func(L *lua.LState) int {
+			em.M.ReloadConfig()
+			return 0
+		},
+	})
+
+	return config
+}

+ 59 - 17
internal/extension/extension.go

@@ -13,6 +13,9 @@ type ExtensionManager struct {
 	L           *lua.LState
 	M           *editor.Model
 	LoadedFiles []string
+	
+	currentDiskDir  string
+	currentEmbedDir string
 }
 
 //go:embed lua
@@ -24,8 +27,10 @@ func NewExtensionManager(m *editor.Model) *ExtensionManager {
 		M: m,
 	}
 
+	lua.OpenPackage(em.L) 
+
 	em.registerAPI()
-	em.registerEmbedSearcher()
+	em.registerExtensionSearcher()
 
 	if err := em.LoadEmbeddedFile("init.lua"); err != nil {
 		m.Mode = editor.ModeNormal
@@ -33,10 +38,16 @@ func NewExtensionManager(m *editor.Model) *ExtensionManager {
 		m.BM.PaletteBuffer.Insert("moose.error:Lua error " + err.Error())
 	}
 
+	if err := em.LoadFile("/home/johron/.config/moose/moose.lua"); err != nil {
+		m.Mode = editor.ModeNormal
+		m.BM.PaletteBuffer.Clear()
+		m.BM.PaletteBuffer.Insert("moose.error:Lua error " + err.Error())
+	}
+
 	return em
 }
 
-func (em *ExtensionManager) registerEmbedSearcher() {
+func (em *ExtensionManager) registerExtensionSearcher() {
 	if em.L == nil {
 		return
 	}
@@ -52,29 +63,53 @@ func (em *ExtensionManager) registerEmbedSearcher() {
 		return
 	}
 
-	embedSearcher := em.L.NewFunction(func(L *lua.LState) int {
+	extensionSearcher := em.L.NewFunction(func(L *lua.LState) int {
 		modName := L.CheckString(1)
-
 		fileName := strings.ReplaceAll(modName, ".", "/") + ".lua"
-		embedPath := filepath.Join("lua", fileName)
-
-		bytes, err := embeddedScripts.ReadFile(embedPath)
-		if err != nil {
-			L.Push(lua.LString(fmt.Sprintf("\n\tno embedded file: %s", embedPath)))
-			return 1
+		var errorsLogged []string
+
+		if em.currentDiskDir != "" {
+			targetDiskFile := filepath.Join(em.currentDiskDir, fileName)
+			if fn, loadErr := L.LoadFile(targetDiskFile); loadErr == nil {
+				return pushAndReturn(L, fn)
+			} else {
+				errorsLogged = append(errorsLogged, fmt.Sprintf("no relative file: %s", targetDiskFile))
+			}
 		}
 
-		fn, err := L.LoadString(string(bytes))
-		if err != nil {
-			L.RaiseError("failed to compile embedded module %s: %v", modName, err)
-			return 0
+		if em.currentEmbedDir != "" {
+			targetEmbedFile := filepath.Join(em.currentEmbedDir, fileName)
+			if bytes, err := embeddedScripts.ReadFile(targetEmbedFile); err == nil {
+				if fn, err := L.LoadString(string(bytes)); err == nil {
+					return pushAndReturn(L, fn)
+				} else {
+					L.RaiseError("failed to compile embedded module %s: %v", modName, err)
+					return 0
+				}
+			} else {
+				errorsLogged = append(errorsLogged, fmt.Sprintf("no relative embed file: %s", targetEmbedFile))
+			}
 		}
 
-		L.Push(fn)
+		L.Push(lua.LString("\n\t" + strings.Join(errorsLogged, "\n\t")))
 		return 1
 	})
 
-	packageLoaders.Append(embedSearcher)
+	idx2 := packageLoaders.RawGetInt(2)
+	idx3 := packageLoaders.RawGetInt(3)
+	idx4 := packageLoaders.RawGetInt(4)
+
+	packageLoaders.RawSetInt(2, extensionSearcher)
+	packageLoaders.RawSetInt(3, idx2)
+	packageLoaders.RawSetInt(4, idx3)
+	if idx4 != lua.LNil {
+		packageLoaders.RawSetInt(5, idx4)
+	}
+}
+
+func pushAndReturn(L *lua.LState, fn *lua.LFunction) int {
+	L.Push(fn)
+	return 1
 }
 
 func (em *ExtensionManager) Close() {
@@ -95,6 +130,10 @@ func (em *ExtensionManager) registerAPI() {
 }
 
 func (em *ExtensionManager) LoadFile(path string) error {
+	oldDiskDir := em.currentDiskDir
+	em.currentDiskDir = filepath.Dir(path)
+	defer func() { em.currentDiskDir = oldDiskDir }()
+
 	if err := em.L.DoFile(path); err != nil {
 		return err
 	}
@@ -109,12 +148,15 @@ func (em *ExtensionManager) LoadEmbeddedFile(path string) error {
 	}
 
 	embedPath := filepath.Join("lua", path)
-
 	bytes, err := embeddedScripts.ReadFile(embedPath)
 	if err != nil {
 		return fmt.Errorf("failed to read embedded script %s: %w", path, err)
 	}
 
+	oldEmbedDir := em.currentEmbedDir
+	em.currentEmbedDir = filepath.Dir(embedPath)
+	defer func() { em.currentEmbedDir = oldEmbedDir }()
+
 	if err := em.L.DoString(string(bytes)); err != nil {
 		return err
 	}

+ 0 - 3
internal/extension/lua/init.lua

@@ -1,6 +1,3 @@
-test = require("test")
-test.run()
-
 colors = {
 	MainBackground = "#0E142E",
 	MainForeground = "#dddddd",

+ 0 - 7
internal/extension/lua/test.lua

@@ -1,7 +0,0 @@
-local test = {}
-
-test.run = function()
-    print("hihi")
-end
-
-return test