Something went wrong. Try again.
Fork of micro-editor/micro
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318package config
import ( "errors" "log" "os" "path/filepath" "regexp" "strings"
"github.com/micro-editor/micro/v2/pkg/syntax" rt "github.com/micro-editor/micro/v2/runtime")
const ( RTColorscheme = 0 RTHelp = 2 RTPlugin = 3)
// NumTypes preserves the numeric slots used before the syntax engine was// removed. Slots 1 (RTSyntax) and 4 (RTSyntaxHeader) are intentionally unused.var NumTypes = 5
type RTFiletype int
// RuntimeFile allows the program to read runtime data like colorschemes or help filestype RuntimeFile interface { // Name returns a name of the file without paths or extensions Name() string // Data returns the content of the file. Data() ([]byte, error)}
// allFiles contains all available files, mapped by filetypevar allFiles [][]RuntimeFilevar realFiles [][]RuntimeFile
func init() { initRuntimeVars()}
func initRuntimeVars() { allFiles = make([][]RuntimeFile, NumTypes) realFiles = make([][]RuntimeFile, NumTypes)}
// NewRTFiletype creates a new RTFiletypefunc NewRTFiletype() int { NumTypes++ allFiles = append(allFiles, []RuntimeFile{}) realFiles = append(realFiles, []RuntimeFile{}) return NumTypes - 1}
// some file on filesystemtype realFile string
// some asset filetype assetFile string
// a file with the data stored in memorytype memoryFile struct { name string data []byte}
func (mf memoryFile) Name() string { return mf.name}func (mf memoryFile) Data() ([]byte, error) { return mf.data, nil}
func (rf realFile) Name() string { fn := filepath.Base(string(rf)) return fn[:len(fn)-len(filepath.Ext(fn))]}
func (rf realFile) Data() ([]byte, error) { return os.ReadFile(string(rf))}
func (af assetFile) Name() string { fn := filepath.Base(string(af)) return fn[:len(fn)-len(filepath.Ext(fn))]}
func (af assetFile) Data() ([]byte, error) { return rt.Asset(string(af))}
// AddRuntimeFile registers a file for the given filetypefunc AddRuntimeFile(fileType RTFiletype, file RuntimeFile) { allFiles[fileType] = append(allFiles[fileType], file)}
// AddRealRuntimeFile registers a file for the given filetypefunc AddRealRuntimeFile(fileType RTFiletype, file RuntimeFile) { allFiles[fileType] = append(allFiles[fileType], file) realFiles[fileType] = append(realFiles[fileType], file)}
// AddRuntimeFilesFromDirectory registers each file from the given directory for// the filetype which matches the file-patternfunc AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string) { files, _ := os.ReadDir(directory) for _, f := range files { if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok { fullPath := filepath.Join(directory, f.Name()) AddRealRuntimeFile(fileType, realFile(fullPath)) } }}
// AddRuntimeFilesFromAssets registers each file from the given asset-directory for// the filetype which matches the file-patternfunc AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern string) { files, err := rt.AssetDir(directory) if err != nil { return }
assetLoop: for _, f := range files { if ok, _ := filepath.Match(pattern, f); ok { af := assetFile(filepath.Join(directory, f)) for _, rf := range realFiles[fileType] { if af.Name() == rf.Name() { continue assetLoop } } AddRuntimeFile(fileType, af) } }}
// FindRuntimeFile finds a runtime file of the given filetype and name// will return nil if no file was foundfunc FindRuntimeFile(fileType RTFiletype, name string) RuntimeFile { for _, f := range ListRuntimeFiles(fileType) { if f.Name() == name { return f } } return nil}
// ListRuntimeFiles lists all known runtime files for the given filetypefunc ListRuntimeFiles(fileType RTFiletype) []RuntimeFile { return allFiles[fileType]}
// ListRealRuntimeFiles lists all real runtime files (on disk) for a filetype// these runtime files will be ones defined by the user and loaded from the config directoryfunc ListRealRuntimeFiles(fileType RTFiletype) []RuntimeFile { return realFiles[fileType]}
// InitRuntimeFiles initializes all assets files and the config directory.// If `user` is false, InitRuntimeFiles ignores the config directory and// initializes asset files only.func InitRuntimeFiles(user bool) { add := func(fileType RTFiletype, dir, pattern string) { if user { AddRuntimeFilesFromDirectory(fileType, filepath.Join(ConfigDir, dir), pattern) } AddRuntimeFilesFromAssets(fileType, filepath.Join("runtime", dir), pattern) }
initRuntimeVars()
add(RTColorscheme, "colorschemes", "*.micro") add(RTHelp, "help", "*.md")}
// InitPlugins initializes the pluginsfunc InitPlugins() { syntax.Clear() Plugins = Plugins[:0] initlua := filepath.Join(ConfigDir, "init.lua")
if _, err := os.Stat(initlua); !os.IsNotExist(err) { p := new(Plugin) p.Name = "initlua" p.DirName = "initlua" p.Srcs = append(p.Srcs, realFile(initlua)) p.Builtin = false Plugins = append(Plugins, p) }
// Search ConfigDir for plugin-scripts plugdir := filepath.Join(ConfigDir, "plug") files, _ := os.ReadDir(plugdir)
isID := regexp.MustCompile(`^[_A-Za-z0-9]+$`).MatchString
for _, d := range files { plugpath := filepath.Join(plugdir, d.Name()) if stat, err := os.Stat(plugpath); err == nil && stat.IsDir() { srcs, _ := os.ReadDir(plugpath) p := new(Plugin) p.Name = d.Name() p.DirName = d.Name() for _, f := range srcs { if strings.HasSuffix(f.Name(), ".lua") { p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, d.Name(), f.Name()))) } else if f.Name() == "repo.json" { data, err := os.ReadFile(filepath.Join(plugdir, d.Name(), f.Name())) if err != nil { continue } p.Info, err = NewPluginInfo(data) if err != nil { continue } p.Name = p.Info.Name } }
if !isID(p.Name) || len(p.Srcs) <= 0 { log.Println(p.Name, "is not a plugin") continue } Plugins = append(Plugins, p) } }
plugdir = filepath.Join("runtime", "plugins") if files, err := rt.AssetDir(plugdir); err == nil { outer: for _, d := range files { for _, p := range Plugins { if p.Name == d { log.Println(p.Name, "built-in plugin overridden by user-defined one") continue outer } }
if srcs, err := rt.AssetDir(filepath.Join(plugdir, d)); err == nil { p := new(Plugin) p.Name = d p.DirName = d p.Builtin = true for _, f := range srcs { if strings.HasSuffix(f, ".lua") { p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, d, f))) } } if !isID(p.Name) || len(p.Srcs) <= 0 { log.Println(p.Name, "is not a plugin") continue } Plugins = append(Plugins, p) } } }}
// PluginReadRuntimeFile allows plugin scripts to read the content of a runtime filefunc PluginReadRuntimeFile(fileType RTFiletype, name string) string { if file := FindRuntimeFile(fileType, name); file != nil { if data, err := file.Data(); err == nil { return string(data) } } return ""}
// PluginListRuntimeFiles allows plugins to lists all runtime files of the given typefunc PluginListRuntimeFiles(fileType RTFiletype) []string { files := ListRuntimeFiles(fileType) result := make([]string, len(files)) for i, f := range files { result[i] = f.Name() } return result}
// PluginAddRuntimeFile adds a file to the runtime files for a pluginfunc PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) error { pl := FindPlugin(plugin) if pl == nil { return errors.New("Plugin " + plugin + " does not exist") } pldir := pl.DirName fullpath := filepath.Join(ConfigDir, "plug", pldir, filePath) if _, err := os.Stat(fullpath); err == nil { AddRealRuntimeFile(filetype, realFile(fullpath)) } else { fullpath = filepath.Join("runtime", "plugins", pldir, filePath) AddRuntimeFile(filetype, assetFile(fullpath)) } return nil}
// PluginAddRuntimeFilesFromDirectory adds files from a directory to the runtime files for a pluginfunc PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, directory, pattern string) error { pl := FindPlugin(plugin) if pl == nil { return errors.New("Plugin " + plugin + " does not exist") } pldir := pl.DirName fullpath := filepath.Join(ConfigDir, "plug", pldir, directory) if _, err := os.Stat(fullpath); err == nil { AddRuntimeFilesFromDirectory(filetype, fullpath, pattern) } else { fullpath = filepath.Join("runtime", "plugins", pldir, directory) AddRuntimeFilesFromAssets(filetype, fullpath, pattern) } return nil}
// PluginAddRuntimeFileFromMemory adds a file to the runtime files for a plugin from a given stringfunc PluginAddRuntimeFileFromMemory(filetype RTFiletype, filename, data string) { AddRealRuntimeFile(filetype, memoryFile{filename, []byte(data)})}