mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-16 22:07:09 +09:00
@@ -84,7 +84,8 @@ func CommandComplete(input string) (string, []string) {
|
||||
func HelpComplete(input string) (string, []string) {
|
||||
var suggestions []string
|
||||
|
||||
for topic, _ := range helpPages {
|
||||
for _, file := range ListRuntimeFiles(FILE_Help) {
|
||||
topic := file.Name()
|
||||
if strings.HasPrefix(topic, input) {
|
||||
suggestions = append(suggestions, topic)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -16,66 +15,53 @@ type Colorscheme map[string]tcell.Style
|
||||
// The current colorscheme
|
||||
var colorscheme Colorscheme
|
||||
|
||||
var preInstalledColors = []string{"default", "simple", "solarized", "solarized-tc", "atom-dark-tc", "monokai", "gruvbox", "zenburn", "bubblegum"}
|
||||
|
||||
// ColorschemeExists checks if a given colorscheme exists
|
||||
func ColorschemeExists(colorschemeName string) bool {
|
||||
files, _ := ioutil.ReadDir(configDir + "/colorschemes")
|
||||
for _, f := range files {
|
||||
if f.Name() == colorschemeName+".micro" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range preInstalledColors {
|
||||
if name == colorschemeName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return FindRuntimeFile(FILE_ColorScheme, colorschemeName) != nil
|
||||
}
|
||||
|
||||
// InitColorscheme picks and initializes the colorscheme when micro starts
|
||||
func InitColorscheme() {
|
||||
colorscheme = make(Colorscheme)
|
||||
if screen != nil {
|
||||
screen.SetStyle(tcell.StyleDefault.
|
||||
Foreground(tcell.ColorDefault).
|
||||
Background(tcell.ColorDefault))
|
||||
}
|
||||
|
||||
LoadDefaultColorscheme()
|
||||
}
|
||||
|
||||
// LoadDefaultColorscheme loads the default colorscheme from $(configDir)/colorschemes
|
||||
func LoadDefaultColorscheme() {
|
||||
LoadColorscheme(globalSettings["colorscheme"].(string), configDir+"/colorschemes")
|
||||
LoadColorscheme(globalSettings["colorscheme"].(string))
|
||||
}
|
||||
|
||||
// LoadColorscheme loads the given colorscheme from a directory
|
||||
func LoadColorscheme(colorschemeName, dir string) {
|
||||
files, _ := ioutil.ReadDir(dir)
|
||||
found := false
|
||||
for _, f := range files {
|
||||
if f.Name() == colorschemeName+".micro" {
|
||||
text, err := ioutil.ReadFile(dir + "/" + f.Name())
|
||||
if err != nil {
|
||||
fmt.Println("Error loading colorscheme:", err)
|
||||
continue
|
||||
}
|
||||
colorscheme = ParseColorscheme(string(text))
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range preInstalledColors {
|
||||
if name == colorschemeName {
|
||||
data, err := Asset("runtime/colorschemes/" + name + ".micro")
|
||||
if err != nil {
|
||||
TermMessage("Unable to load pre-installed colorscheme " + name)
|
||||
continue
|
||||
}
|
||||
colorscheme = ParseColorscheme(string(data))
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
func LoadColorscheme(colorschemeName string) {
|
||||
file := FindRuntimeFile(FILE_ColorScheme, colorschemeName)
|
||||
if file == nil {
|
||||
TermMessage(colorschemeName, "is not a valid colorscheme")
|
||||
} else {
|
||||
if data, err := file.Data(); err != nil {
|
||||
fmt.Println("Error loading colorscheme:", err)
|
||||
} else {
|
||||
colorscheme = ParseColorscheme(string(data))
|
||||
|
||||
// Default style
|
||||
defStyle = tcell.StyleDefault.
|
||||
Foreground(tcell.ColorDefault).
|
||||
Background(tcell.ColorDefault)
|
||||
|
||||
// There may be another default style defined in the colorscheme
|
||||
// In that case we should use that one
|
||||
if style, ok := colorscheme["default"]; ok {
|
||||
defStyle = style
|
||||
}
|
||||
if screen != nil {
|
||||
screen.SetStyle(defStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ func Help(args []string) {
|
||||
CurView().openHelp("help")
|
||||
} else {
|
||||
helpPage := args[0]
|
||||
if _, ok := helpPages[helpPage]; ok {
|
||||
if FindRuntimeFile(FILE_Help, helpPage) != nil {
|
||||
CurView().openHelp(helpPage)
|
||||
} else {
|
||||
messenger.Error("Sorry, no help for ", helpPage)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type HelpPage interface {
|
||||
HelpFile() ([]byte, error)
|
||||
}
|
||||
|
||||
var helpPages map[string]HelpPage = map[string]HelpPage{
|
||||
"help": assetHelpPage("help"),
|
||||
"keybindings": assetHelpPage("keybindings"),
|
||||
"plugins": assetHelpPage("plugins"),
|
||||
"colors": assetHelpPage("colors"),
|
||||
"options": assetHelpPage("options"),
|
||||
"commands": assetHelpPage("commands"),
|
||||
"tutorial": assetHelpPage("tutorial"),
|
||||
}
|
||||
|
||||
type assetHelpPage string
|
||||
|
||||
func (file assetHelpPage) HelpFile() ([]byte, error) {
|
||||
return Asset("runtime/help/" + string(file) + ".md")
|
||||
}
|
||||
|
||||
type fileHelpPage string
|
||||
|
||||
func (file fileHelpPage) HelpFile() ([]byte, error) {
|
||||
return ioutil.ReadFile(string(file))
|
||||
}
|
||||
|
||||
func AddPluginHelp(name, file string) {
|
||||
if _, exists := helpPages[name]; exists {
|
||||
return
|
||||
}
|
||||
helpPages[name] = fileHelpPage(file)
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -30,150 +28,16 @@ type SyntaxRule struct {
|
||||
|
||||
var syntaxFiles map[[2]*regexp.Regexp]FileTypeRules
|
||||
|
||||
// These syntax files are pre installed and embedded in the resulting binary by go-bindata
|
||||
var preInstalledSynFiles = []string{
|
||||
"Dockerfile",
|
||||
"apacheconf",
|
||||
"arduino",
|
||||
"asciidoc",
|
||||
"asm",
|
||||
"awk",
|
||||
"c",
|
||||
"caddyfile",
|
||||
"cmake",
|
||||
"coffeescript",
|
||||
"colortest",
|
||||
"conf",
|
||||
"conky",
|
||||
"csharp",
|
||||
"css",
|
||||
"cython",
|
||||
"d",
|
||||
"dart",
|
||||
"dot",
|
||||
"erb",
|
||||
"fish",
|
||||
"fortran",
|
||||
"gdscript",
|
||||
"gentoo-ebuild",
|
||||
"gentoo-etc-portage",
|
||||
"git-commit",
|
||||
"git-config",
|
||||
"git-rebase-todo",
|
||||
"glsl",
|
||||
"go",
|
||||
"golo",
|
||||
"groff",
|
||||
"haml",
|
||||
"haskell",
|
||||
"html",
|
||||
"ini",
|
||||
"inputrc",
|
||||
"java",
|
||||
"javascript",
|
||||
"json",
|
||||
"keymap",
|
||||
"kickstart",
|
||||
"ledger",
|
||||
"lilypond",
|
||||
"lisp",
|
||||
"lua",
|
||||
"makefile",
|
||||
"man",
|
||||
"markdown",
|
||||
"mpdconf",
|
||||
"micro",
|
||||
"nanorc",
|
||||
"nginx",
|
||||
"ocaml",
|
||||
"pascal",
|
||||
"patch",
|
||||
"peg",
|
||||
"perl",
|
||||
"perl6",
|
||||
"php",
|
||||
"pkg-config",
|
||||
"po",
|
||||
"pov",
|
||||
"privoxy-action",
|
||||
"privoxy-config",
|
||||
"privoxy-filter",
|
||||
"puppet",
|
||||
"python",
|
||||
"r",
|
||||
"reST",
|
||||
"rpmspec",
|
||||
"ruby",
|
||||
"rust",
|
||||
"scala",
|
||||
"sed",
|
||||
"sh",
|
||||
"sls",
|
||||
"sql",
|
||||
"swift",
|
||||
"systemd",
|
||||
"tcl",
|
||||
"tex",
|
||||
"vala",
|
||||
"vi",
|
||||
"xml",
|
||||
"xresources",
|
||||
"yaml",
|
||||
"yum",
|
||||
"zsh",
|
||||
}
|
||||
|
||||
// LoadSyntaxFiles loads the syntax files from the default directory (configDir)
|
||||
func LoadSyntaxFiles() {
|
||||
// Load the user's custom syntax files, if there are any
|
||||
LoadSyntaxFilesFromDir(configDir + "/syntax")
|
||||
|
||||
// Load the pre-installed syntax files from inside the binary
|
||||
for _, filetype := range preInstalledSynFiles {
|
||||
data, err := Asset("runtime/syntax/" + filetype + ".micro")
|
||||
if err != nil {
|
||||
TermMessage("Unable to load pre-installed syntax file " + filetype)
|
||||
continue
|
||||
}
|
||||
|
||||
LoadSyntaxFile(string(data), filetype+".micro")
|
||||
}
|
||||
}
|
||||
|
||||
// LoadSyntaxFilesFromDir loads the syntax files from a specified directory
|
||||
// To load the syntax files, we must fill the `syntaxFiles` map
|
||||
// This involves finding the regex for syntax and if it exists, the regex
|
||||
// for the header. Then we must get the text for the file and the filetype.
|
||||
func LoadSyntaxFilesFromDir(dir string) {
|
||||
colorscheme = make(Colorscheme)
|
||||
InitColorscheme()
|
||||
|
||||
// Default style
|
||||
defStyle = tcell.StyleDefault.
|
||||
Foreground(tcell.ColorDefault).
|
||||
Background(tcell.ColorDefault)
|
||||
|
||||
// There may be another default style defined in the colorscheme
|
||||
// In that case we should use that one
|
||||
if style, ok := colorscheme["default"]; ok {
|
||||
defStyle = style
|
||||
}
|
||||
if screen != nil {
|
||||
screen.SetStyle(defStyle)
|
||||
}
|
||||
|
||||
syntaxFiles = make(map[[2]*regexp.Regexp]FileTypeRules)
|
||||
files, _ := ioutil.ReadDir(dir)
|
||||
for _, f := range files {
|
||||
if filepath.Ext(f.Name()) == ".micro" {
|
||||
filename := dir + "/" + f.Name()
|
||||
text, err := ioutil.ReadFile(filename)
|
||||
|
||||
if err != nil {
|
||||
TermMessage("Error loading syntax file " + filename + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
LoadSyntaxFile(string(text), filename)
|
||||
for _, f := range ListRuntimeFiles(FILE_Syntax) {
|
||||
data, err := f.Data()
|
||||
if err != nil {
|
||||
TermMessage("Error loading syntax file " + f.Name() + ": " + err.Error())
|
||||
} else {
|
||||
LoadSyntaxFile(string(data), f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +233,9 @@ func main() {
|
||||
// Find the user's configuration directory (probably $XDG_CONFIG_HOME/micro)
|
||||
InitConfigDir()
|
||||
|
||||
// Build a list of available Extensions (Syntax, Colorscheme etc.)
|
||||
InitRuntimeFiles()
|
||||
|
||||
// Load the user's settings
|
||||
InitGlobalSettings()
|
||||
|
||||
@@ -313,6 +316,10 @@ func main() {
|
||||
L.SetGlobal("JobSend", luar.New(L, JobSend))
|
||||
L.SetGlobal("JobStop", luar.New(L, JobStop))
|
||||
|
||||
// Extension Files
|
||||
L.SetGlobal("ReadRuntimeFile", luar.New(L, PluginReadRuntimeFile))
|
||||
L.SetGlobal("ListRuntimeFiles", luar.New(L, PluginListRuntimeFiles))
|
||||
|
||||
LoadPlugins()
|
||||
|
||||
jobs = make(chan JobFunction, 100)
|
||||
|
||||
@@ -138,7 +138,7 @@ func LoadPlugins() {
|
||||
}
|
||||
loadedPlugins = append(loadedPlugins, pluginName)
|
||||
} else if f.Name() == "help.md" {
|
||||
AddPluginHelp(pluginName, fullPath)
|
||||
AddRuntimeFile(FILE_Help, namedFile{realFile(fullPath), pluginName})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
144
cmd/micro/rtfiles.go
Normal file
144
cmd/micro/rtfiles.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
FILE_ColorScheme = "colorscheme"
|
||||
FILE_Syntax = "syntax"
|
||||
FILE_Help = "help"
|
||||
)
|
||||
|
||||
// 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 string
|
||||
|
||||
// some asset file
|
||||
type assetFile string
|
||||
|
||||
// some file on filesystem but with a different name
|
||||
type namedFile struct {
|
||||
realFile
|
||||
name string
|
||||
}
|
||||
|
||||
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 ioutil.ReadFile(string(rf))
|
||||
}
|
||||
|
||||
func (af assetFile) Name() string {
|
||||
fn := path.Base(string(af))
|
||||
return fn[:len(fn)-len(path.Ext(fn))]
|
||||
}
|
||||
|
||||
func (af assetFile) Data() ([]byte, error) {
|
||||
return Asset(string(af))
|
||||
}
|
||||
|
||||
func (nf namedFile) Name() string {
|
||||
return nf.name
|
||||
}
|
||||
|
||||
// AddRuntimeFile registers a file for the given filetype
|
||||
func AddRuntimeFile(fileType string, file RuntimeFile) {
|
||||
if allFiles == nil {
|
||||
allFiles = make(map[string][]RuntimeFile)
|
||||
}
|
||||
allFiles[fileType] = append(allFiles[fileType], file)
|
||||
}
|
||||
|
||||
// AddRuntimeFilesFromDirectory registers each file from the given directory for
|
||||
// the filetype which matches the file-pattern
|
||||
func AddRuntimeFilesFromDirectory(fileType, directory, pattern string) {
|
||||
files, _ := ioutil.ReadDir(directory)
|
||||
for _, f := range files {
|
||||
if ok, _ := filepath.Match(pattern, f.Name()); !f.IsDir() && ok {
|
||||
fullPath := filepath.Join(directory, f.Name())
|
||||
AddRuntimeFile(fileType, realFile(fullPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddRuntimeFilesFromDirectory registers each file from the given asset-directory for
|
||||
// the filetype which matches the file-pattern
|
||||
func AddRuntimeFilesFromAssets(fileType, directory, pattern string) {
|
||||
files, err := AssetDir(directory)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
if ok, _ := path.Match(pattern, f); ok {
|
||||
AddRuntimeFile(fileType, assetFile(path.Join(directory, f)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FindRuntimeFile finds a runtime file of the given filetype and name
|
||||
// will return nil if no file was found
|
||||
func FindRuntimeFile(fileType, name string) RuntimeFile {
|
||||
for _, f := range ListRuntimeFiles(fileType) {
|
||||
if f.Name() == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lists all known runtime files for the given filetype
|
||||
func ListRuntimeFiles(fileType string) []RuntimeFile {
|
||||
if files, ok := allFiles[fileType]; ok {
|
||||
return files
|
||||
} else {
|
||||
return []RuntimeFile{}
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes all assets file and the config directory
|
||||
func InitRuntimeFiles() {
|
||||
add := func(fileType, dir, pattern string) {
|
||||
AddRuntimeFilesFromDirectory(fileType, filepath.Join(configDir, dir), pattern)
|
||||
AddRuntimeFilesFromAssets(fileType, path.Join("runtime", dir), pattern)
|
||||
}
|
||||
|
||||
add(FILE_ColorScheme, "colorschemes", "*.micro")
|
||||
add(FILE_Syntax, "syntax", "*.micro")
|
||||
add(FILE_Help, "help", "*.md")
|
||||
}
|
||||
|
||||
// Allows plugin scripts to read the content of a runtime file
|
||||
func PluginReadRuntimeFile(fileType, name string) string {
|
||||
if file := FindRuntimeFile(fileType, name); file != nil {
|
||||
if data, err := file.Data(); err == nil {
|
||||
return string(data)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Allows plugins to lists all runtime files of the given type
|
||||
func PluginListRuntimeFiles(fileType string) []string {
|
||||
files := ListRuntimeFiles(fileType)
|
||||
result := make([]string, len(files))
|
||||
for i, f := range files {
|
||||
result[i] = f.Name()
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -529,7 +529,7 @@ func (v *View) ClearAllGutterMessages() {
|
||||
|
||||
// Opens the given help page in a new horizontal split
|
||||
func (v *View) openHelp(helpPage string) {
|
||||
if data, err := helpPages[helpPage].HelpFile(); err != nil {
|
||||
if data, err := FindRuntimeFile(FILE_Help, helpPage).Data(); err != nil {
|
||||
TermMessage("Unable to load help text", helpPage, "\n", err)
|
||||
} else {
|
||||
helpBuffer := NewBuffer(data, helpPage+".md")
|
||||
|
||||
Reference in New Issue
Block a user