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