X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=runtime%2Fhelp%2Fplugins.md;h=dd76f8c6b48bce24d1d98c4ace0e9d017991a3e3;hb=4f628bf30b7d9f8727257983d5455102aa7ca774;hp=b79b4149b71b539c35683b290af68c2d6aa0271b;hpb=5a9a7a3835fdda978e734b7edbf878ccee275eae;p=micro.git diff --git a/runtime/help/plugins.md b/runtime/help/plugins.md index b79b4149..dd76f8c6 100644 --- a/runtime/help/plugins.md +++ b/runtime/help/plugins.md @@ -1,211 +1,431 @@ # Plugins -Micro supports creating plugins with a simple Lua system. Every plugin has a -main script which is run at startup which should be placed in -`~/.config/micro/plugins/pluginName/pluginName.lua`. +Micro supports creating plugins with a simple Lua system. Plugins are +folders containing Lua files and possibly other source files placed +in `~/.config/micro/plug`. The plugin directory (within `plug`) should +contain at least one Lua file and an `info.json` file. The info file +provides additional information such as the name of the plugin, the +plugin's website, dependencies, etc... Here is an example info file +from the go plugin, which has the following file structure: -There are a number of callback functions which you can create in your -plugin to run code at times other than startup. The naming scheme is -`onAction(view)`. For example a function which is run every time the user saves -the buffer would be: - -```lua -function onSave(view) - ... - return false -end +``` +~/.config/micro/plug/go-plugin/ + go.lua + repo.json + help/ + go-plugin.md ``` -The `view` variable is a reference to the view the action is being executed on. -This is almost always the current view, which you can get with `CurView()` as well. - -All available actions are listed in the keybindings section of the help. - -These functions should also return a boolean specifying whether the view -should be relocated to the cursor or not after the action is complete. - -Note that these callbacks occur after the action has been completed. If you -want a callback before the action is executed, use `preAction()`. In this case -the boolean returned specifies whether or not the action should be executed -after the lua code completes. - -Another useful callback to know about which is not a action is -`onViewOpen(view)` which is called whenever a new view is opened and the new -view is passed in. This is useful for setting local options based on the filetype, -for example turning off `tabstospaces` only for Go files when they are opened. - ---- - -There are a number of functions and variables that are available to you in -order to access the inner workings of micro. Here is a list (the type signatures -for functions are given using Go's type system): +The `go.lua` file contains the main code for the plugin, though the +code may be distributed across multiple Lua files. The `info.json` +file contains information about the plugin such as the website, +description, version, and any requirements. Plugins may also +have additional files which can be added to micro's runtime files, +of which there are 5 types: -* `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`...) +* Colorschemes +* Syntax files +* Help files +* Plugin files +* Syntax header files -* `configDir`: contains the path to the micro configuration files +In most cases, a plugin will want to add help files, but in certain +cases a plugin may also want to add colorschemes or syntax files. It +is unlikely for a plugin to need to add plugin files at runtime or +syntax header files. No directory structure is enforced but keeping +runtime files in their own directories is good practice. -* `tabs`: a list of all the tabs currently in use +## Lua callbacks -* `curTab`: the index of the current tabs in the tabs list +Plugins use Lua but also have access to many functions both from micro +and from the Go standard library. Many callbacks are also defined which +are called when certain events happen. Here is the list of callbacks +which micro defines: -* `messenger`: lets you send messages to the user or create prompts +* `init()`: this function should be used for your plugin initialization. -* `NewBuffer(text, path string) *Buffer`: creates a new buffer from a given reader with a given path +* `onBufferOpen(buf)`: runs when a buffer is opened. The input contains + the buffer object. -* `GetLeadingWhitespace() bool`: returns the leading whitespace of the given string +* `onBufPaneOpen(bufpane)`: runs when a bufpane is opened. The input + contains the bufpane object. -* `IsWordChar(str string) bool`: returns whether or not the string is a 'word character' +* `onAction(bufpane)`: runs when `Action` is triggered by the user, where + `Action` is a bindable action (see `> help keybindings`). A bufpane + is passed as input and the function should return a boolean defining + whether the view should be relocated after this action is performed. -* `RuneStr(r rune) string`: returns a string containing the given rune +* `preAction(bufpane)`: runs immediately before `Action` is triggered + by the user. Returns a boolean which defines whether the action should + be canceled. -* `Loc(x, y int) Loc`: returns a new `Loc` struct +For example a function which is run every time the user saves the buffer +would be: -* `JoinPaths(dir... string) string` combines multiple directories to a full path +```lua +function onSave(bp) + ... + return false +end +``` -* `DirectoryName(path string)` returns all but the last element of path ,typically the path's directory +The `bp` variable is a reference to the bufpane the action is being executed +within. This is almost always the current bufpane. -* `GetOption(name string)`: returns the value of the requested option +All available actions are listed in the keybindings section of the help. -* `AddOption(name string, value interface{})`: sets the given option with the given - value (`interface{}` means any type in Go) +For callbacks to mouse actions, you are also given the event info: -* `SetOption(option, value string)`: sets the given option to the value. This will - set the option globally, unless it is a local only option. +```lua +function onMousePress(view, event) + local x, y = event:Position() -* `SetLocalOption(option, value string, buffer *Buffer)`: sets the given option to - the value locally in the given buffer + return false +end +``` -* `BindKey(key, action string)`: binds `key` to `action` +These functions should also return a boolean specifying whether the bufpane +should be relocated to the cursor or not after the action is complete. -* `MakeCommand(name, function string, completions ...Completion)`: - creates a command with `name` which will call `function` when executed. - Use 0 for completions to get NoCompletion. +## Accessing micro functions -* `MakeCompletion(function string)`: - creates a `Completion` to use with `MakeCommand` +Some of micro's internal information is exposed in the form of packages which +can be imported by Lua plugins. A package can be imported in Lua and a value +within it can be accessed using the following syntax: -* `CurView()`: returns the current view +```lua +local micro = import("micro") +micro.Log("Hello") +``` -* `HandleCommand(cmd string)`: runs the given command +The packages and functions are listed below (in Go type signatures): + +* `micro` + - `TermMessage(msg interface{}...)`: temporarily close micro and print a + message + + - `TermError(filename string, lineNum int, err string)`: temporarily close + micro and print an error formatted as `filename, lineNum: err`. + + - `InfoBar()`: return the infobar BufPane object. + + - `Log(msg interface{}...)`: write a message to `log.txt` (requires + `-debug` flag, or binary built with `build-dbg`). + + - `SetStatusInfoFn(fn string)`: register the given lua function as + accessible from the statusline formatting options +* `micro/config` + - `MakeCommand(name string, action func(bp *BufPane, args[]string), + completer buffer.Completer)`: + create a command with the given name, and lua callback function when + the command is run. A completer may also be given to specify how + autocompletion should work with the custom command. + + - `FileComplete`: autocomplete using files in the current directory + - `HelpComplete`: autocomplete using names of help documents + - `OptionComplete`: autocomplete using names of options + - `OptionValueComplete`: autocomplete using names of options, and valid + values afterwards + - `NoComplete`: no autocompletion suggestions + + - `TryBindKey(k, v string, overwrite bool) (bool, error)`: bind the key + `k` to the string `v` in the `bindings.json` file. If `overwrite` is + true, this will overwrite any existing binding to key `k`. Returns true + if the binding was made, and a possible error (for example writing to + `bindings.json` can cause an error). + + - `Reload()`: reload configuration files. + + - `AddRuntimeFileFromMemory(filetype RTFiletype, filename, data string)`: + add a runtime file to the `filetype` runtime filetype, with name + `filename` and data `data`. + + - `AddRuntimeFilesFromDirectory(plugin string, filetype RTFiletype, + directory, pattern string)`: + add runtime files for the given plugin with the given RTFiletype from + a directory within the plugin root. Only adds files that match the + pattern using Go's `filepath.Match` + + - `AddRuntimeFile(plugin string, filetype RTFiletype, filepath string)`: + add a given file inside the plugin root directory as a runtime file + to the given RTFiletype category. + + - `ListRuntimeFiles(fileType RTFiletype) []string`: returns a list of + names of runtime files of the given type. + + - `ReadRuntimeFile(fileType RTFiletype, name string) string`: returns the + contents of a given runtime file. + + - `NewRTFiletype() int`: creates a new RTFiletype, and returns its value. + + - `RTColorscheme`: runtime files for colorschemes. + - `RTSyntax`: runtime files for syntax files. + - `RTHelp`: runtime files for help documents. + - `RTPlugin`: runtime files for plugin source code. + + - `RegisterCommonOption(pl string, name string, defaultvalue interface{})`: + registers a new option with for the given plugin. The name of the + option will be `pl.name`, and will have the given default value. Since + this registers a common option, the option will be modifiable on a + per-buffer basis, while also having a global value (in the + GlobalSettings map). + + - `RegisterGlobalOption(pl string, name string, defaultvalue interface{})`: + same as `RegisterCommonOption` but the option cannot be modified + locally to each buffer. + + - `GetGlobalOption(name string) interface{}`: returns the value of a + given plugin in the `GlobalSettings` map. + + - `SetGlobalOption(option, value string) error`: sets an option to a + given value. Same as using the `> set` command. This will parse the + value to the actual value type. + + - `SetGlobalOptionNative(option string, value interface{}) error`: sets + an option to a given value, where the type of value is the actual + type of the value internally. +* `micro/shell` + - `ExecCommand(name string, arg ...string) (string, error)`: runs an + executable with the given arguments, and pipes the output (stderr + and stdout) of the executable to an internal buffer, which is + returned as a string, along with a possible error. + + - `RunCommand(input string) (string, error)`: same as `ExecCommand`, + except this uses micro's argument parser to parse the arguments from + the input. For example `cat 'hello world.txt' file.txt`, will pass + two arguments in the `ExecCommand` argument list (quoting arguments + will preserve spaces). + + - `RunBackgroundShell(input string) (func() string, error)`: returns a + function that will run the given shell command and return its output. + + - `RunInteractiveShell(input string, wait bool, getOutput bool) + (string, error)`: + temporarily closes micro and runs the given command in the terminal. + If `wait` is true, micro will wait for the user to press enter before + returning to text editing. If `getOutput` is true, micro redirect + stdout from the command to the returned string. + + - `JobStart(cmd string, onStdout, onStderr, + onExit func(string, []interface{}), userargs ...interface{}) + *exec.Cmd`: + Starts a background job by running the shell on the given command + (using `sh -c`). Three callbacks can be provided which will be called + when the command generates stdout, stderr, or exits. The userargs will + be passed to the callbacks, along with the output as the first + argument of the callback. + + - `JobSpawn(cmd string, cmdArgs []string, onStdout, onStderr, + onExit func(string, []interface{}), userargs ...interface{}) + *exec.Cmd`: + same as `JobStart`, except doesn't run the command through the shell + and instead takes as inputs the list of arguments. + + - `JobStop(cmd *exec.Cmd)`: kills a job. + - `JobSend(cmd *exec.Cmd, data string)`: sends some data to a job's stdin. + + - `RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, + callback func(out string, userargs []interface{}), + userargs []interface{}) error`: + starts a terminal emulator from a given BufPane with the input command. + If `wait` is true it will wait for the user to exit by pressing enter + once the executable has terminated and if `getOutput` is true it will + redirect the stdout of the process to a pipe which will be passed to + the callback which is a function that takes a string and a list of + optional user arguments. This function returns an error on systems + where the terminal emulator is not supported. + + - `TermEmuSupported`: true on systems where the terminal emulator is + supported and false otherwise. Supported systems: + * Linux + * MacOS + * Dragonfly + * OpenBSD + * FreeBSD + +* `micro/buffer` + - `NewMessage(owner string, msg string, start, end, Loc, kind MsgType) + *Message`: + creates a new message with an owner over a range given by the start + and end locations. + + - `NewMessageAtLine(owner string, msg string, line int, kindMsgType) + *Message`: + creates a new message with owner, type and message at a given line. + + - `MTInfo`: info message. + - `MTWarning`: warning message. + - `MTError` error message. + + - `Loc(x, y int) Loc`: creates a new location struct. + + - `BTDefault`: default buffer type. + - `BTLog`: log buffer type. + - `BTRaw`: raw buffer type. + - `BTInfo`: info buffer type. + + - `NewBuffer(text, path string) *Buffer`: creates a new buffer with the + given text at a certain path. + + - `NewBufferFromFile(path string) (*Buffer, error)`: creates a new + buffer by reading from disk at the given path. + + - `ByteOffset(pos Loc, buf *Buffer) int`: returns the byte index of the + given position in a buffer. + + - `Log(s string)`: writes a string to the log buffer. + - `LogBuf() *Buffer`: returns the log buffer. +* `micro/util` + - `RuneAt(str string, idx int) string`: returns the utf8 rune at a + given index within a string. + - `GetLeadingWhitespace(s string) string`: returns the leading + whitespace of a string. + - `IsWordChar(s string) bool`: returns true if the first rune in a + string is a word character. + - `String(b []byte) string`: converts a byte array to a string. + - `RuneStr(r rune) string`: converts a rune to a string. -* `HandleShellCommand(shellCmd string, interactive bool, waitToClose bool)`: runs the given shell - command. The `interactive` bool specifies whether the command should run in the background. The - `waitToClose` bool only applies if `interactive` is true and means that it should wait before - returning to the editor. +This may seem like a small list of available functions but some of the objects +returned by the functions have many methods. The Lua plugin may access any +public methods of an object returned by any of the functions above. +Unfortunately it is not possible to list all the available functions on this +page. Please go to the internal documentation at +https://godoc.org/github.com/zyedidia/micro to see the full list of available +methods. Note that only methods of types that are available to plugins via +the functions above can be called from a plugin. For an even more detailed +reference see the source code on Github. + +For example, with a BufPane object called `bp`, you could call the `Save` +function in Lua with `bp:Save()`. + +Note that Lua uses the `:` syntax to call a function rather than Go's `.` +syntax. + +```go +micro.InfoBar().Message() +``` -* `ToCharPos(loc Loc, buf *Buffer) int`: returns the character position of a given x, y location +turns to -* `Reload`: (Re)load everything +```lua +micro.InfoBar():Message() +``` -* `ByteOffset(loc Loc, buf *Buffer) int`: exactly like `ToCharPos` except it it counts bytes instead of runes +## Accessing the Go standard library -* `JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit string, userargs ...string)`: - Starts running the given process in the background. `onStdout` `onStderr` and `onExit` - are callbacks to lua functions which will be called when the given actions happen - to the background process. - `userargs` are the arguments which will get passed to the callback functions +It is possible for your lua code to access many of the functions in the Go +standard library. -* `JobStart(cmd string, onStdout, onStderr, onExit string, userargs ...string)`: - Starts running the given shell command in the background. Note that the command execute - is first parsed by a shell when using this command. It is executed with `sh -c`. +Simply import the package you'd like and then you can use it. For example: -* `JobSend(cmd *exec.Cmd, data string)`: send a string into the stdin of the job process +```lua +local ioutil = import("io/ioutil") +local fmt = import("fmt") +local micro = import("micro") -* `JobStop(cmd *exec.Cmd)`: kill a job +local data, err = ioutil.ReadFile("SomeFile.txt") -This may seem like a small list of available functions but some of the objects -returned by the functions have many methods. `CurView()` returns a view object -which has all the actions which you can call. For example `CurView():Save(false)`. -You can see the full list of possible actions in the keybindings help topic. -The boolean on all the actions indicates whether or not the lua callbacks should -be run. I would recommend generally sticking to false when making a plugin to -avoid recursive problems, for example if you call `CurView():Save(true)` in `onSave()`. -Just use `CurView():Save(false)` so that it won't call `onSave()` again. +if err ~= nil then + micro.InfoBar():Error("Error reading file: SomeFile.txt") +else + -- Data is returned as an array of bytes + -- Using Sprintf will convert it to a string + local str = fmt.Sprintf("%s", data) -Using the view object, you can also access the buffer associated with that view -by using `CurView().Buf`, which lets you access the `FileType`, `Path`, `Name`... + -- Do something with the file you just read! + -- ... +end +``` -The possible methods which you can call using the `messenger` variable are: +Here are the packages from the Go standard library that you can access. +Nearly all functions from these packages are supported. For an exact +list of which functions are supported you can look through `lua.go` +(which should be easy to understand). -* `messenger.Message(msg ...interface{})` -* `messenger.Error(msg ...interface{})` -* `messenger.YesNoPrompt(prompt string) (bool, bool)` -* `messenger.Prompt(prompt, historyType string, completionType Completion) (string, bool)` +``` +fmt +io +io/ioutil +net +math +math/rand +os +runtime +path +filepath +strings +regexp +errors +time +``` -If you want a standard prompt, just use `messenger.Prompt(prompt, "", 0)` +For documentation for each of these functions, see the Go standard +library documentation at https://golang.org/pkg/ (for the packages +exposed to micro plugins). The Lua standard library is also available +to plugins though it is rather small. -# Adding help files, syntax files, or colorschemes in your plugin +## Adding help files, syntax files, or colorschemes in your plugin -You can use the `AddRuntimeFile(name, type, path string)` function to add various kinds of -files to your plugin. For example, if you'd like to add a help topic to your plugin -called `test`, you would create a `test.md` file, and call the function: +You can use the `AddRuntimeFile(name string, type config.RTFiletype, + path string)` +function to add various kinds of files to your plugin. For example, if you'd +like to add a help topic to your plugin called `test`, you would create a +`test.md` file, and call the function: ```lua -AddRuntimeFile("test", "help", "test.md") +config = import("micro/config") +config.AddRuntimeFile("test", config.RTHelp, "test.md") ``` -Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of files -to the runtime. -To read the content of a runtime file use `ReadRuntimeFile(fileType, name string)` -or `ListRuntimeFiles(fileType string)` for all runtime files. +Use `AddRuntimeFilesFromDirectory(name, type, dir, pattern)` to add a number of +files to the runtime. To read the content of a runtime file use +`ReadRuntimeFile(fileType, name string)` or `ListRuntimeFiles(fileType string)` +for all runtime files. In addition, there is `AddRuntimeFileFromMemory` which +adds a runtime file based on a string that may have been constructed at +runtime. -# Autocomplete command arguments +## Default plugins -See this example to learn how to use `MakeCompletion` and `MakeCommand` +There are 6 default plugins that come pre-installed with micro. These are -```lua -local function StartsWith(String,Start) - String = String:upper() - Start = Start:upper() - return string.sub(String,1,string.len(Start))==Start -end +* `autoclose`: automatically closes brackets, quotes, etc... +* `comment`: provides automatic commenting for a number of languages +* `ftoptions`: alters some default options depending on the filetype +* `linter`: provides extensible linting for many languages +* `literate`: provides advanced syntax highlighting for the Literate + programming tool. +* `status`: provides some extensions to the status line (integration with + Git and more). -function complete(input) - local allCompletions = {"Hello", "World", "Foo", "Bar"} - local result = {} - - for i,v in pairs(allCompletions) do - if StartsWith(v, input) then - table.insert(result, v) - end - end - return result -end +See `> help linter`, `> help comment`, and `> help status` for additional +documentation specific to those plugins. -function foo(arg) - messenger:Message(arg) -end +These are good examples for many use-cases if you are looking to write +your own plugins. -MakeCommand("foo", "example.foo", MakeCompletion("example.complete")) -``` - -# Default plugins - -For examples of plugins, see the default `autoclose` and `linter` plugins -(stored in the normal micro core repo under `runtime/plugins`) as well as -any plugins that are stored in the official channel [here](https://github.com/micro-editor/plugin-channel). +## Plugin Manager -# Plugin Manager - -Micro also has a built in plugin manager which you can invoke with the `> plugin ...` command. +Micro also has a built in plugin manager which you can invoke with the +`> plugin ...` command, or in the shell with `micro -plugin ...`. For the valid commands you can use, see the `command` help topic. -The manager fetches plugins from the channels (which is simply a list of plugin metadata) -which it knows about. By default, micro only knows about the official channel which is located -at github.com/micro-editor/plugin-channel but you can add your own third-party channels using -the `pluginchannels` option and you can directly link third-party plugins to allow installation -through the plugin manager with the `pluginrepos` option. +The manager fetches plugins from the channels (which is simply a list of plugin +metadata) which it knows about. By default, micro only knows about the official +channel which is located at github.com/micro-editor/plugin-channel but you can +add your own third-party channels using the `pluginchannels` option and you can +directly link third-party plugins to allow installation through the plugin +manager with the `pluginrepos` option. -If you'd like to publish a plugin you've made as an official plugin, you should upload your -plugin online (to Github preferably) and add a `repo.json` file. This file will contain the -metadata for your plugin. Here is an example: +If you'd like to publish a plugin you've made as an official plugin, you should +upload your plugin online (to Github preferably) and add a `repo.json` file. +This file will contain the metadata for your plugin. Here is an example: ```json [{ "Name": "pluginname", "Description": "Here is a nice concise description of my plugin", + "Website": "https://github.com/user/plugin", "Tags": ["python", "linting"], "Versions": [ { @@ -219,7 +439,9 @@ metadata for your plugin. Here is an example: }] ``` -Then open a pull request at github.com/micro-editor/plugin-channel adding a link to the -raw `repo.json` that is in your plugin repository. -To make updating the plugin work, the first line of your plugins lua code should contain the version of the plugin. (Like this: `VERSION = "1.0.0"`) +Then open a pull request at github.com/micro-editor/plugin-channel adding a +link to the raw `repo.json` that is in your plugin repository. + +To make updating the plugin work, the first line of your plugins lua code +should contain the version of the plugin. (Like this: `VERSION = "1.0.0"`) Please make sure to use [semver](http://semver.org/) for versioning.