]> git.lizzy.rs Git - micro.git/blob - internal/config/rtfiles.go
Add linter plugin support
[micro.git] / internal / config / rtfiles.go
1 package config
2
3 import (
4         "io/ioutil"
5         "log"
6         "os"
7         "path"
8         "path/filepath"
9         "strings"
10 )
11
12 const (
13         RTColorscheme = 0
14         RTSyntax      = 1
15         RTHelp        = 2
16         RTPlugin      = 3
17         NumTypes      = 4 // How many filetypes are there
18 )
19
20 type RTFiletype byte
21
22 // RuntimeFile allows the program to read runtime data like colorschemes or syntax files
23 type RuntimeFile interface {
24         // Name returns a name of the file without paths or extensions
25         Name() string
26         // Data returns the content of the file.
27         Data() ([]byte, error)
28 }
29
30 // allFiles contains all available files, mapped by filetype
31 var allFiles [NumTypes][]RuntimeFile
32
33 // some file on filesystem
34 type realFile string
35
36 // some asset file
37 type assetFile string
38
39 // some file on filesystem but with a different name
40 type namedFile struct {
41         realFile
42         name string
43 }
44
45 // a file with the data stored in memory
46 type memoryFile struct {
47         name string
48         data []byte
49 }
50
51 func (mf memoryFile) Name() string {
52         return mf.name
53 }
54 func (mf memoryFile) Data() ([]byte, error) {
55         return mf.data, nil
56 }
57
58 func (rf realFile) Name() string {
59         fn := filepath.Base(string(rf))
60         return fn[:len(fn)-len(filepath.Ext(fn))]
61 }
62
63 func (rf realFile) Data() ([]byte, error) {
64         return ioutil.ReadFile(string(rf))
65 }
66
67 func (af assetFile) Name() string {
68         fn := path.Base(string(af))
69         return fn[:len(fn)-len(path.Ext(fn))]
70 }
71
72 func (af assetFile) Data() ([]byte, error) {
73         return Asset(string(af))
74 }
75
76 func (nf namedFile) Name() string {
77         return nf.name
78 }
79
80 // AddRuntimeFile registers a file for the given filetype
81 func AddRuntimeFile(fileType RTFiletype, file RuntimeFile) {
82         allFiles[fileType] = append(allFiles[fileType], file)
83 }
84
85 // AddRuntimeFilesFromDirectory registers each file from the given directory for
86 // the filetype which matches the file-pattern
87 func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, pattern string) {
88         files, _ := ioutil.ReadDir(directory)
89         for _, f := range files {
90                 if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok {
91                         fullPath := filepath.Join(directory, f.Name())
92                         AddRuntimeFile(fileType, realFile(fullPath))
93                 }
94         }
95 }
96
97 // AddRuntimeFilesFromAssets registers each file from the given asset-directory for
98 // the filetype which matches the file-pattern
99 func AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern string) {
100         files, err := AssetDir(directory)
101         if err != nil {
102                 return
103         }
104         for _, f := range files {
105                 if ok, _ := path.Match(pattern, f); ok {
106                         AddRuntimeFile(fileType, assetFile(path.Join(directory, f)))
107                 }
108         }
109 }
110
111 // FindRuntimeFile finds a runtime file of the given filetype and name
112 // will return nil if no file was found
113 func FindRuntimeFile(fileType RTFiletype, name string) RuntimeFile {
114         for _, f := range ListRuntimeFiles(fileType) {
115                 if f.Name() == name {
116                         return f
117                 }
118         }
119         return nil
120 }
121
122 // ListRuntimeFiles lists all known runtime files for the given filetype
123 func ListRuntimeFiles(fileType RTFiletype) []RuntimeFile {
124         return allFiles[fileType]
125 }
126
127 // InitRuntimeFiles initializes all assets file and the config directory
128 func InitRuntimeFiles() {
129         add := func(fileType RTFiletype, dir, pattern string) {
130                 AddRuntimeFilesFromDirectory(fileType, filepath.Join(ConfigDir, dir), pattern)
131                 AddRuntimeFilesFromAssets(fileType, path.Join("runtime", dir), pattern)
132         }
133
134         add(RTColorscheme, "colorschemes", "*.micro")
135         add(RTSyntax, "syntax", "*.yaml")
136         add(RTHelp, "help", "*.md")
137
138         // Search ConfigDir for plugin-scripts
139         plugdir := filepath.Join(ConfigDir, "plugins")
140         files, _ := ioutil.ReadDir(plugdir)
141         log.Println("reading", plugdir)
142         for _, d := range files {
143                 if d.IsDir() {
144                         srcs, _ := ioutil.ReadDir(filepath.Join(plugdir, d.Name()))
145                         p := new(Plugin)
146                         p.Name = d.Name()
147                         for _, f := range srcs {
148                                 if strings.HasSuffix(f.Name(), ".lua") {
149                                         p.Srcs = append(p.Srcs, realFile(filepath.Join(plugdir, d.Name(), f.Name())))
150                                 } else if f.Name() == "info.json" {
151                                         p.Info = realFile(filepath.Join(plugdir, d.Name(), "info.json"))
152                                 }
153                         }
154                         Plugins = append(Plugins, p)
155                 }
156         }
157
158         plugdir = filepath.Join("runtime", "plugins")
159         if files, err := AssetDir(plugdir); err == nil {
160                 for _, d := range files {
161                         if srcs, err := AssetDir(filepath.Join(plugdir, d)); err == nil {
162                                 p := new(Plugin)
163                                 p.Name = d
164                                 for _, f := range srcs {
165                                         if strings.HasSuffix(f, ".lua") {
166                                                 p.Srcs = append(p.Srcs, assetFile(filepath.Join(plugdir, d, f)))
167                                         } else if f == "info.json" {
168                                                 p.Info = assetFile(filepath.Join(plugdir, d, "info.json"))
169                                         }
170                                 }
171                                 Plugins = append(Plugins, p)
172                         }
173                 }
174         }
175 }
176
177 // PluginReadRuntimeFile allows plugin scripts to read the content of a runtime file
178 func PluginReadRuntimeFile(fileType RTFiletype, name string) string {
179         if file := FindRuntimeFile(fileType, name); file != nil {
180                 if data, err := file.Data(); err == nil {
181                         return string(data)
182                 }
183         }
184         return ""
185 }
186
187 // PluginListRuntimeFiles allows plugins to lists all runtime files of the given type
188 func PluginListRuntimeFiles(fileType RTFiletype) []string {
189         files := ListRuntimeFiles(fileType)
190         result := make([]string, len(files))
191         for i, f := range files {
192                 result[i] = f.Name()
193         }
194         return result
195 }
196
197 // PluginAddRuntimeFile adds a file to the runtime files for a plugin
198 func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath string) {
199         fullpath := filepath.Join(ConfigDir, "plugins", plugin, filePath)
200         if _, err := os.Stat(fullpath); err == nil {
201                 AddRuntimeFile(filetype, realFile(fullpath))
202         } else {
203                 fullpath = path.Join("runtime", "plugins", plugin, filePath)
204                 AddRuntimeFile(filetype, assetFile(fullpath))
205         }
206 }
207
208 // PluginAddRuntimeFilesFromDirectory adds files from a directory to the runtime files for a plugin
209 func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, directory, pattern string) {
210         fullpath := filepath.Join(ConfigDir, "plugins", plugin, directory)
211         if _, err := os.Stat(fullpath); err == nil {
212                 AddRuntimeFilesFromDirectory(filetype, fullpath, pattern)
213         } else {
214                 fullpath = path.Join("runtime", "plugins", plugin, directory)
215                 AddRuntimeFilesFromAssets(filetype, fullpath, pattern)
216         }
217 }
218
219 // PluginAddRuntimeFileFromMemory adds a file to the runtime files for a plugin from a given string
220 func PluginAddRuntimeFileFromMemory(plugin string, filetype RTFiletype, filename, data string) {
221         AddRuntimeFile(filetype, memoryFile{filename, []byte(data)})
222 }