-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathrtfiles.go
142 lines (120 loc) · 3.44 KB
/
rtfiles.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package femto
import (
"io/ioutil"
"net/http"
"os"
"path/filepath"
)
const (
RTColorscheme = "colorscheme"
RTSyntax = "syntax"
)
func readDir(fs http.FileSystem, path string) ([]os.FileInfo, error) {
if fs == nil {
return nil, os.ErrNotExist
}
dir, err := fs.Open(path)
if err != nil {
return nil, err
}
defer dir.Close()
return dir.Readdir(0)
}
func readFile(fs http.FileSystem, path string) ([]byte, error) {
if fs == nil {
return nil, os.ErrNotExist
}
f, err := fs.Open(path)
if err != nil {
return nil, err
}
return ioutil.ReadAll(f)
}
// RuntimeFile allows the program to read runtime data like colorschemes or syntax files
type 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 filetype
var allFiles map[string][]RuntimeFile
// some file on filesystem
type realFile struct {
fs http.FileSystem
path string
}
// some file on filesystem but with a different name
type namedFile struct {
realFile
name string
}
// a file with the data stored in memory
type 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(rf.path)
return fn[:len(fn)-len(filepath.Ext(fn))]
}
func (rf realFile) Data() ([]byte, error) {
return readFile(rf.fs, rf.path)
}
func (nf namedFile) Name() string {
return nf.name
}
// RuntimeFiles tracks a set of runtime files.
type RuntimeFiles struct {
allFiles map[string][]RuntimeFile
}
// NewRuntimeFiles creates a new set of runtime files from the colorscheme and syntax files present in the given
// http.Filesystme. Colorschemes should be located under "/colorschemes" and must end with a "micro" extension.
// Syntax files should be located under "/syntax" and must end with a "yaml" extension.
func NewRuntimeFiles(fs http.FileSystem) *RuntimeFiles {
rfs := &RuntimeFiles{}
rfs.AddFilesFromDirectory(fs, RTColorscheme, "/colorschemes", "*.micro")
rfs.AddFilesFromDirectory(fs, RTSyntax, "/syntax", "*.yaml")
return rfs
}
// AddRuntimeFile registers a file for the given filetype
func (rfs *RuntimeFiles) AddFile(fileType string, file RuntimeFile) {
if rfs.allFiles == nil {
rfs.allFiles = make(map[string][]RuntimeFile)
}
rfs.allFiles[fileType] = append(rfs.allFiles[fileType], file)
}
// AddFilesFromDirectory registers each file from the given directory for
// the filetype which matches the file-pattern
func (rfs *RuntimeFiles) AddFilesFromDirectory(fs http.FileSystem, fileType, directory, pattern string) {
files, _ := readDir(fs, directory)
for _, f := range files {
if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok {
fullPath := filepath.Join(directory, f.Name())
rfs.AddFile(fileType, realFile{fs, fullPath})
}
}
}
// FindFile finds a runtime file of the given filetype and name
// will return nil if no file was found
func (rfs RuntimeFiles) FindFile(fileType, name string) RuntimeFile {
for _, f := range rfs.ListRuntimeFiles(fileType) {
if f.Name() == name {
return f
}
}
return nil
}
// ListRuntimeFiles lists all known runtime files for the given filetype
func (rfs RuntimeFiles) ListRuntimeFiles(fileType string) []RuntimeFile {
if files, ok := rfs.allFiles[fileType]; ok {
return files
}
return []RuntimeFile{}
}