X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=runtime%2Fhelp%2Fplugins.md;h=e68df426b0fbe7c904ff5a3c173be0c02a11ae37;hb=f3e8413e772924947238bdb9f928375e24ff7213;hp=4b11beeec8ae7efb4a18842f168b533201d3b85e;hpb=1c43bb572a65e4f49b8dc29ce8a2c171fb7c0066;p=micro.git diff --git a/runtime/help/plugins.md b/runtime/help/plugins.md index 4b11beee..e68df426 100644 --- a/runtime/help/plugins.md +++ b/runtime/help/plugins.md @@ -1,196 +1,213 @@ # 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 ``` - -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. - -For callbacks to mouse actions, you are also given the event info: - -```lua -function onMousePress(view, event) - local x, y = event:Position() - - return false -end +~/.config/micro/plug/go-plugin/ + go.lua + info.json + help/ + go-plugin.md ``` -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. +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: -Another useful callback to know about which is not an 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. +* Colorschemes +* Syntax files +* Help files +* Plugin files +* Syntax header 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. -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): +# Info file -* `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`...) +The `info.json` for the Go plugin is the following: -* `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 - -* `NewBuffer(text, path string) *Buffer`: creates a new buffer from a given - reader with a given path - -* `GetLeadingWhitespace() bool`: returns the leading whitespace of the given - string - -* `IsWordChar(str string) bool`: returns whether or not the string is a 'word - character' +``` +{ + "name": "go", + "description": "Go formatting and tool support", + "website": "https://github.com/micro-editor/go-plugin", + "install": "https://github.com/micro-editor/go-plugin", + "version": "1.0.0", + "require": [ + "micro >= 2.0.0" + ] +} +``` -* `RuneStr(r rune) string`: returns a string containing the given rune +All fields are simply interpreted as strings, so the version does not +need to be a semantic version, and the dependencies are also only +meant to be parsed by humans. The name should be an identifier, and +the website should point to a valid website. The install field should +provide info about installing the plugin, or point to a website that +provides information. -* `Loc(x, y int) Loc`: returns a new `Loc` struct +Note that the name of the plugin is defined by the name field in +the `info.json` and not by the installation path. Some functions micro +exposes to plugins require passing the name of the plugin. -* `WorkingDirectory() string`: returns a rooted path name to the current working - directory +## Lua callbacks -* `JoinPaths(dir... string) string`: combines multiple directories to a full - path +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: -* `DirectoryName(path string)`: returns all but the last element of path, - typically the path's directory +* `init()`: this function should be used for your plugin initialization. -* `GetOption(name string)`: returns the value of the requested option +* `onBufferOpen(buf)`: runs when a buffer is opened. The input contains + the buffer object. -* `AddOption(name string, value interface{})`: sets the given option with the - given value (`interface{}` means any type in Go) +* `onBufPaneOpen(bufpane)`: runs when a bufpane is opened. The input + contains the bufpane object. -* `SetOption(option, value string)`: sets the given option to the value. This - will set the option globally, unless it is a local only option. +* `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. -* `SetLocalOption(option, value string, view *View)`: sets the given option to - the value locally in the given buffer +* `preAction(bufpane)`: runs immediately before `Action` is triggered + by the user. Returns a boolean which defines whether the action should + be canceled. -* `BindKey(key, action string)`: binds `key` to `action` +For example a function which is run every time the user saves the buffer +would be: -* `MakeCommand(name, function string, completions ...Completion)`: - creates a command with `name` which will call `function` when executed. Use 0 - for completions to get NoCompletion. +```lua +function onSave(bp) + ... + return false +end +``` -* `MakeCompletion(function string)`: - creates a `Completion` to use with `MakeCommand` +The `bp` variable is a reference to the bufpane the action is being executed within. +This is almost always the current bufpane. -* `CurView()`: returns the current view +All available actions are listed in the keybindings section of the help. -* `HandleCommand(cmd string)`: runs the given command +For callbacks to mouse actions, you are also given the event info: -* `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. +```lua +function onMousePress(view, event) + local x, y = event:Position() -* `ToCharPos(loc Loc, buf *Buffer) int`: returns the character position of a - given x, y location + return false +end +``` -* `Reload`: (Re)load everything +These functions should also return a boolean specifying whether the bufpane should +be relocated to the cursor or not after the action is complete. -* `ByteOffset(loc Loc, buf *Buffer) int`: exactly like `ToCharPos` except it it - counts bytes instead of runes +## Accessing micro functions -* `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 +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: -* `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`. +```lua +local micro = import("micro") +micro.Log("Hello") +``` -* `JobSend(cmd *exec.Cmd, data string)`: send a string into the stdin of the job - process +The packages and functions are listed below (in Go type signatures): + +* `micro` + - `TermMessage(msg interface{}...)` + - `TermError()` + - `InfoBar()` + - `Log(msg interface{}...)` + - `SetStatusInfoFn(fn string)` +* `micro/config` + - `MakeCommand` + - `FileComplete` + - `HelpComplete` + - `OptionComplete` + - `OptionValueComplete` + - `NoComplete` + - `TryBindKey` + - `Reload` + - `AddRuntimeFilesFromDirectory` + - `AddRuntimeFileFromMemory` + - `AddRuntimeFile` + - `ListRuntimeFiles` + - `ReadRuntimeFile` + - `RTColorscheme` + - `RTSyntax` + - `RTHelp` + - `RTPlugin` + - `RegisterCommonOption` + - `RegisterGlobalOption` +* `micro/shell` + - `ExecCommand` + - `RunCommand` + - `RunBackgroundShell` + - `RunInteractiveShell` + - `JobStart` + - `JobSpawn` + - `JobStop` + - `JobStop` + - `RunTermEmulator` + - `TermEmuSupported` +* `micro/buffer` + - `NewMessage` + - `NewMessageAtLine` + - `MTInfo` + - `MTWarning` + - `MTError` + - `Loc` + - `BTDefault` + - `BTLog` + - `BTRaw` + - `BTInfo` + - `NewBufferFromFile` + - `ByteOffset` +* `micro/util` + - `RuneAt` + - `GetLeadingWhitespace` + - `IsWordChar` -* `JobStop(cmd *exec.Cmd)`: kill a job 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. - -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`... - -The possible methods which you can call using the `messenger` variable are: - -* `messenger.Message(msg ...interface{})` -* `messenger.Error(msg ...interface{})` -* `messenger.YesNoPrompt(prompt string) (bool,bool)` -* `messenger.Prompt(prompt, historyType string, completionType Completion) (string, bool)` -* `messenger.AddLog(msg ...interface{})` +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. -#### Note +For example, with a BufPane object called `bp`, you could call the `Save` function +in Lua with `bp:Save()`. -Go function signatures use `.` and lua uses `:` so +Note that Lua uses the `:` syntax to call a function rather than Go's `.` syntax. ```go -messenger.Message() +micro.InfoBar().Message() ``` turns to ```lua -messenger:Message() +micro.InfoBar():Message() ``` -If you want a standard prompt, just use - -```lua -messenger:Prompt(prompt, "", 0) -``` - -Debug or logging your plugin can be done with below lua example code. - -```lua -messenger:AddLog("Message goes here ",pluginVariableToPrintHere) -``` - -In Micro to see your plugin logging output press `CtrlE` then type `log`, a -logging window will open and any logging sent from your plugin will be displayed -here. - - ## Accessing the Go standard library It is possible for your lua code to access many of the functions in the Go @@ -201,11 +218,12 @@ Simply import the package you'd like and then you can use it. For example: ```lua local ioutil = import("io/ioutil") local fmt = import("fmt") +local micro = import("micro") local data, err = ioutil.ReadFile("SomeFile.txt") if err ~= nil then - messenger:Error("Error reading file: SomeFile.txt") + 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 @@ -238,102 +256,54 @@ errors time ``` -For documentation for each of these functions, you can simply look -through the Go standard library documentation. +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 -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. - - -## Autocomplete command arguments - -See this example to learn how to use `MakeCompletion` and `MakeCommand` - -```lua -local function StartsWith(String,Start) - String = String:upper() - Start = Start:upper() - return string.sub(String,1,string.len(Start))==Start -end - -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 - -function foo(arg) - messenger:Message(arg) -end - -MakeCommand("foo", "example.foo", MakeCompletion("example.complete")) -``` - +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. ## 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). +There are 6 default plugins that come pre-installed with micro. These are +* `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). -## Plugin Manager +These are good examples for many use-cases if you are looking to write +your own plugins. -Micro also has a built in plugin manager which you can invoke with the -`> plugin ...` command. - -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. - -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", - "Tags": ["python", "linting"], - "Versions": [ - { - "Version": "1.0.0", - "Url": "https://github.com/user/plugin/archive/v1.0.0.zip", - "Require": { - "micro": ">=1.0.3" - } - } - ] -}] -``` +## Plugin Manager -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. +Micro's plugin manager is you! Ultimately the plugins that are created +for micro are quite simple and don't require a complex automated tool +to manage them. They should be "git cloned" or somehow placed in the +`~/.config/micro/plug` directory, and that is all that's necessary +for installation. In the rare case that a more complex installation +process is needed (such as dependencies, or additional setup) the +plugin creator should provide the additional instructions on their +website and point to the link using the `install` field in the `info.json` +file.