From 6fe20fb30581c8384559238dadf7363bf102fbcb Mon Sep 17 00:00:00 2001 From: Florian Sundermann Date: Mon, 19 Sep 2016 13:23:47 +0200 Subject: [PATCH 1/7] some additions to the plugin API Those changes were originally used for the snippet plugin which may not be part of the core. --- cmd/micro/eventhandler.go | 13 +++++++++++++ cmd/micro/micro.go | 9 +++++++++ cmd/micro/rtfiles.go | 4 ++-- runtime/help/plugins.md | 8 ++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/cmd/micro/eventhandler.go b/cmd/micro/eventhandler.go index eed62484..efeca821 100644 --- a/cmd/micro/eventhandler.go +++ b/cmd/micro/eventhandler.go @@ -1,9 +1,11 @@ package main import ( + "strings" "time" dmp "github.com/sergi/go-diff/diffmatchpatch" + "github.com/yuin/gopher-lua" ) const ( @@ -114,6 +116,17 @@ func (eh *EventHandler) Execute(t *TextEvent) { eh.RedoStack = new(Stack) } eh.UndoStack.Push(t) + + for _, pl := range loadedPlugins { + ret, err := Call(pl+".onBeforeTextEvent", t) + if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") { + TermMessage(err) + } + if val, ok := ret.(lua.LBool); ok && val == lua.LFalse { + return + } + } + ExecuteTextEvent(t, eh.buf) } diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 4930aef0..0ce90310 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "runtime" "strings" @@ -310,6 +311,14 @@ func main() { L.SetGlobal("GetLeadingWhitespace", luar.New(L, GetLeadingWhitespace)) L.SetGlobal("MakeCompletion", luar.New(L, MakeCompletion)) L.SetGlobal("NewBuffer", luar.New(L, NewBuffer)) + L.SetGlobal("RuneStr", luar.New(L, func(r rune) string { + return string(r) + })) + L.SetGlobal("Loc", luar.New(L, func(x, y int) Loc { + return Loc{x, y} + })) + L.SetGlobal("JoinPaths", luar.New(L, filepath.Join)) + L.SetGlobal("configDir", luar.New(L, configDir)) // Used for asynchronous jobs L.SetGlobal("JobStart", luar.New(L, JobStart)) diff --git a/cmd/micro/rtfiles.go b/cmd/micro/rtfiles.go index 3d0ea574..ac03b7a2 100644 --- a/cmd/micro/rtfiles.go +++ b/cmd/micro/rtfiles.go @@ -145,11 +145,11 @@ func PluginListRuntimeFiles(fileType string) []string { // PluginAddRuntimeFile adds a file to the runtime files for a plugin func PluginAddRuntimeFile(plugin, filetype, path string) { - fullpath := configDir + "/plugins/" + plugin + "/" + path + fullpath := filepath.Join(configDir, "plugins", plugin, path) if _, err := os.Stat(fullpath); err == nil { AddRuntimeFile(filetype, realFile(fullpath)) } else { - fullpath = "runtime/plugins/" + plugin + "/" + path + fullpath = path.Join("runtime", "plugins", plugin, path) AddRuntimeFile(filetype, assetFile(fullpath)) } } diff --git a/runtime/help/plugins.md b/runtime/help/plugins.md index 7feb3c5b..efdcec5b 100644 --- a/runtime/help/plugins.md +++ b/runtime/help/plugins.md @@ -43,12 +43,20 @@ for functions are given using Go's type system): * `OS`: variable which gives the OS micro is currently running on (this is the same as Go's GOOS variable, so `darwin`, `windows`, `linux`, `freebsd`...) +* `configDir`: contains the path to the micro configuration files + * `tabs`: a list of all the tabs currently in use * `curTab`: the index of the current tabs in the tabs list * `messenger`: lets you send messages to the user or create prompts +* `RuneStr(r rune) string`: returns a string containing the given rune + +* `Loc(x, y int) Loc`: returns a new `Loc` struct + +* `JoinPaths(dir... string) string` combines multiple directories to a full path + * `GetOption(name string)`: returns the value of the requested option * `AddOption(name string, value interface{})`: sets the given option with the given From da6ab783847403a4a7b31297bcbacfde350ae764 Mon Sep 17 00:00:00 2001 From: Florian Sundermann Date: Mon, 19 Sep 2016 13:28:14 +0200 Subject: [PATCH 2/7] fixed build --- cmd/micro/rtfiles.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/micro/rtfiles.go b/cmd/micro/rtfiles.go index ac03b7a2..0e537dee 100644 --- a/cmd/micro/rtfiles.go +++ b/cmd/micro/rtfiles.go @@ -144,12 +144,12 @@ func PluginListRuntimeFiles(fileType string) []string { } // PluginAddRuntimeFile adds a file to the runtime files for a plugin -func PluginAddRuntimeFile(plugin, filetype, path string) { - fullpath := filepath.Join(configDir, "plugins", plugin, path) +func PluginAddRuntimeFile(plugin, filetype, filePath string) { + fullpath := filepath.Join(configDir, "plugins", plugin, filePath) if _, err := os.Stat(fullpath); err == nil { AddRuntimeFile(filetype, realFile(fullpath)) } else { - fullpath = path.Join("runtime", "plugins", plugin, path) + fullpath = path.Join("runtime", "plugins", plugin, filePath) AddRuntimeFile(filetype, assetFile(fullpath)) } } From 1720d4023fcaf1346a0f2690e06c297979322736 Mon Sep 17 00:00:00 2001 From: Florian Sundermann Date: Mon, 19 Sep 2016 14:40:56 +0200 Subject: [PATCH 3/7] load plugins as rt-files --- cmd/micro/plugin.go | 39 ++++++--------------------------------- cmd/micro/rtfiles.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/cmd/micro/plugin.go b/cmd/micro/plugin.go index e728c3dd..d77baea9 100644 --- a/cmd/micro/plugin.go +++ b/cmd/micro/plugin.go @@ -4,7 +4,6 @@ import ( "errors" "io/ioutil" "os" - "path/filepath" "strings" "github.com/layeh/gopher-luar" @@ -13,12 +12,6 @@ import ( var loadedPlugins []string -var preInstalledPlugins = []string{ - "go", - "linter", - "autoclose", -} - // Call calls the lua function 'function' // If it does not exist nothing happens, if there is an error, // the error is returned @@ -121,48 +114,28 @@ func LuaFunctionJob(function string) func(string, ...string) { // LoadPlugins loads the pre-installed plugins and the plugins located in ~/.config/micro/plugins func LoadPlugins() { - files, _ := ioutil.ReadDir(configDir + "/plugins") - for _, plugin := range files { - if plugin.IsDir() { - pluginName := plugin.Name() - files, _ := ioutil.ReadDir(configDir + "/plugins/" + pluginName) - for _, f := range files { - fullPath := filepath.Join(configDir, "plugins", pluginName, f.Name()) - if f.Name() == pluginName+".lua" { - data, _ := ioutil.ReadFile(fullPath) - pluginDef := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n" - - if err := L.DoString(pluginDef + string(data)); err != nil { - TermMessage(err) - continue - } - loadedPlugins = append(loadedPlugins, pluginName) - } - } - } - } - - for _, pluginName := range preInstalledPlugins { + for _, plugin := range ListRuntimeFiles(RTPlugin) { alreadyExists := false + pluginName := plugin.Name() for _, pl := range loadedPlugins { if pl == pluginName { alreadyExists = true break } } + if !alreadyExists { - plugin := "runtime/plugins/" + pluginName + "/" + pluginName + ".lua" - data, err := Asset(plugin) + data, err := plugin.Data() if err != nil { - TermMessage("Error loading pre-installed plugin: " + pluginName) + TermMessage("Error loading plugin: " + pluginName) continue } pluginDef := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n" + if err := L.DoString(pluginDef + string(data)); err != nil { TermMessage(err) continue } - loadedPlugins = append(loadedPlugins, pluginName) } } diff --git a/cmd/micro/rtfiles.go b/cmd/micro/rtfiles.go index 3d0ea574..64d8571b 100644 --- a/cmd/micro/rtfiles.go +++ b/cmd/micro/rtfiles.go @@ -11,6 +11,7 @@ const ( RTColorscheme = "colorscheme" RTSyntax = "syntax" RTHelp = "help" + RTPlugin = "plugin" ) // RuntimeFile allows the program to read runtime data like colorschemes or syntax files @@ -121,6 +122,26 @@ func InitRuntimeFiles() { add(RTColorscheme, "colorschemes", "*.micro") add(RTSyntax, "syntax", "*.micro") add(RTHelp, "help", "*.md") + + // Search configDir for plugin-scripts + files, _ := ioutil.ReadDir(filepath.Join(configDir, "plugins")) + for _, f := range files { + if f.IsDir() { + scriptPath := filepath.Join(configDir, "plugins", f.Name(), f.Name()+".lua") + if _, err := os.Stat(scriptPath); err == nil { + AddRuntimeFile(RTPlugin, realFile(scriptPath)) + } + } + } + + if files, err := AssetDir("runtime/plugins"); err == nil { + for _, f := range files { + scriptPath := path.Join("runtime/plugins", f, f+".lua") + if _, err := AssetInfo(scriptPath); err == nil { + AddRuntimeFile(RTPlugin, assetFile(scriptPath)) + } + } + } } // PluginReadRuntimeFile allows plugin scripts to read the content of a runtime file From 8172ebf62bd370d049af17d371b4c5b377f15b7b Mon Sep 17 00:00:00 2001 From: Florian Sundermann Date: Mon, 19 Sep 2016 16:04:59 +0200 Subject: [PATCH 4/7] fixed loading order plugins were not able to provide colorschemes --- cmd/micro/micro.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 4930aef0..aa822bf1 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -242,9 +242,6 @@ func main() { InitCommands() InitBindings() - // Load the syntax files, including the colorscheme - LoadSyntaxFiles() - // Start the screen InitScreen() @@ -321,11 +318,14 @@ func main() { L.SetGlobal("ListRuntimeFiles", luar.New(L, PluginListRuntimeFiles)) L.SetGlobal("AddRuntimeFile", luar.New(L, PluginAddRuntimeFile)) - LoadPlugins() - jobs = make(chan JobFunction, 100) events = make(chan tcell.Event, 100) + LoadPlugins() + + // Load the syntax files, including the colorscheme + LoadSyntaxFiles() + for _, t := range tabs { for _, v := range t.views { for _, pl := range loadedPlugins { From 64fd96611c61feed97d80d806fb4b3054592611c Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sat, 24 Sep 2016 14:30:35 -0400 Subject: [PATCH 5/7] Check buffer filetype after loading plugins --- cmd/micro/micro.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 0befdbee..2d2829c8 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -337,6 +337,8 @@ func main() { for _, t := range tabs { for _, v := range t.views { + v.Buf.FindFileType() + v.Buf.UpdateRules() for _, pl := range loadedPlugins { _, err := Call(pl+".onViewOpen", v) if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") { From 292df7a9f791d61abd81fabd7ad598f2d179604f Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sat, 24 Sep 2016 15:26:19 -0400 Subject: [PATCH 6/7] Add mouse support and binding support to prompts Closes #244 --- cmd/micro/messenger.go | 97 +++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 29 deletions(-) diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 2e0a59ea..7e641735 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -269,36 +269,58 @@ func (m *Messenger) Prompt(prompt, historyType string, completionTypes ...Comple func (m *Messenger) HandleEvent(event tcell.Event, history []string) { switch e := event.(type) { case *tcell.EventKey: + if e.Key() != tcell.KeyRune || e.Modifiers() != 0 { + for key, actions := range bindings { + if e.Key() == key.keyCode { + if e.Key() == tcell.KeyRune { + if e.Rune() != key.r { + continue + } + } + if e.Modifiers() == key.modifiers { + for _, action := range actions { + funcName := FuncName(action) + switch funcName { + case "main.(*View).CursorUp": + if m.historyNum > 0 { + m.historyNum-- + m.response = history[m.historyNum] + m.cursorx = Count(m.response) + } + case "main.(*View).CursorDown": + if m.historyNum < len(history)-1 { + m.historyNum++ + m.response = history[m.historyNum] + m.cursorx = Count(m.response) + } + case "main.(*View).CursorLeft": + if m.cursorx > 0 { + m.cursorx-- + } + case "main.(*View).CursorRight": + if m.cursorx < Count(m.response) { + m.cursorx++ + } + case "main.(*View).CursorStart", "main.(*View).StartOfLine": + m.cursorx = 0 + case "main.(*View).CursorEnd", "main.(*View).EndOfLine": + m.cursorx = Count(m.response) + case "main.(*View).Backspace": + if m.cursorx > 0 { + m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:]) + m.cursorx-- + } + case "main.(*View).Paste": + clip, _ := clipboard.ReadAll("clipboard") + m.response = Insert(m.response, m.cursorx, clip) + m.cursorx += Count(clip) + } + } + } + } + } + } switch e.Key() { - case tcell.KeyUp: - if m.historyNum > 0 { - m.historyNum-- - m.response = history[m.historyNum] - m.cursorx = Count(m.response) - } - case tcell.KeyDown: - if m.historyNum < len(history)-1 { - m.historyNum++ - m.response = history[m.historyNum] - m.cursorx = Count(m.response) - } - case tcell.KeyLeft: - if m.cursorx > 0 { - m.cursorx-- - } - case tcell.KeyRight: - if m.cursorx < Count(m.response) { - m.cursorx++ - } - case tcell.KeyBackspace2, tcell.KeyBackspace: - if m.cursorx > 0 { - m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:]) - m.cursorx-- - } - case tcell.KeyCtrlV: - clip, _ := clipboard.ReadAll("clipboard") - m.response = Insert(m.response, m.cursorx, clip) - m.cursorx += Count(clip) case tcell.KeyRune: m.response = Insert(m.response, m.cursorx, string(e.Rune())) m.cursorx++ @@ -309,6 +331,23 @@ func (m *Messenger) HandleEvent(event tcell.Event, history []string) { clip := e.Text() m.response = Insert(m.response, m.cursorx, clip) m.cursorx += Count(clip) + case *tcell.EventMouse: + x, y := e.Position() + x -= Count(m.message) + button := e.Buttons() + _, screenH := screen.Size() + + if y == screenH-1 { + switch button { + case tcell.Button1: + m.cursorx = x + if m.cursorx < 0 { + m.cursorx = 0 + } else if m.cursorx > Count(m.response) { + m.cursorx = Count(m.response) + } + } + } } } From 22ebbcfd8981ba38166aad5ad3bab73f887af333 Mon Sep 17 00:00:00 2001 From: Camille Date: Sun, 25 Sep 2016 19:05:58 +0200 Subject: [PATCH 7/7] Add ` to autoclose --- runtime/plugins/autoclose/autoclose.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/plugins/autoclose/autoclose.lua b/runtime/plugins/autoclose/autoclose.lua index ba902fa9..aed2ec63 100644 --- a/runtime/plugins/autoclose/autoclose.lua +++ b/runtime/plugins/autoclose/autoclose.lua @@ -6,7 +6,7 @@ if GetOption("autoclose") == nil then AddOption("autoclose", true) end -local autoclosePairs = {"\"\"", "''", "()", "{}", "[]"} +local autoclosePairs = {"\"\"", "''", "``", "()", "{}", "[]"} local autoNewlinePairs = {"()", "{}", "[]"} function onRune(r, v)