-
-
Notifications
You must be signed in to change notification settings - Fork 110
Plugins
If there is a feature you would like to integrate into Ox that doesn't currently come as standard, then the plug-in API may allow you to implement this feature.
As with the rest of the configuration, the language used is Lua and plug-ins are imported in the same configuration file (~/.oxrc
)
You can also use other people's plug-ins as well as making your own.
See the plugins
folder in the repository to see some pre-made plugins, including auto bracket pairs and automatic indentation.
To enable these plug-ins, please see the Plugin Distribution
section below.
The below sub-sections outline the available plug-ins and how to enable them and use them
- Pairs
- Autoindent
- Quickcomment
- Pomodoro Timer
- Update Notification
- Typing Speed
- Todo Lists
- Discord RPC
- Emmet
- Live HTML
- Git
Helps you out when programming by inserting and deleting bracket or quote pairs automatically. For example, if you type (
it will automatically insert a )
after the cursor so that you can immediately start typing between the brackets. You can also insert a space whilst inside a pair to space both of them out e.g. (|)
becomes ( | )
(the cursor is shown as |
)
☑️ Enabled by default
You can install your own local copy in ~/.config/ox
by running the command plugin install pairs
and then entering y
at the prompt asking to reinstall.
You can also disable and uninstall it by running plugin uninstall pairs
.
Helps you out when dealing with indentation, it will detect language-specific indicators of when an indent / decent is required, and it will also correct any indentation when you move lines up and down. Another feature is being able to expand brackets nicely, demonstrated below:
{|}
becomes
{
|
}
when the return key is pressed between two brackets
☑️ Enabled by default
You can install your own local copy in ~/.config/ox
by running the command plugin install autoindent
and then entering y
at the prompt asking to reinstall.
You can also disable and uninstall it by running plugin uninstall autoindent
.
Usage:
You can use the key binding Ctrl + Tab
to indent a line / selection of lines.
You can use the key binding Shift + Tab
to dedent a line / selection of lines.
Helps you to quickly comment and uncomment lines of code.
☑️ Enabled by default
You can install your own local copy in ~/.config/ox
by running the command plugin install quickcomment
and then entering y
at the prompt asking to reinstall.
You can also disable and uninstall it by running plugin uninstall pairs
Usage:
By default, the key Alt + C
will toggle comment / uncomment the current line
This is a simple Pomodoro timer that can be used to break up your work with breaks. It uses the default 25 minute work followed by 5 minute break format, but can be modified using the parameters at the top of the ~/.config/ox/pomodoro.lua
file.
❌ Not installed by default
To install: run the command plugin install pomodoro
To uninstall: run the command plugin uninstall pomodoro
Usage:
The first thing you want to do is add the output of the pomodoro somewhere in your editor (it is recommended to put it in the status line)
To do this, go to your .oxrc
file and in your status line configuration section, add {pomodoro_show}
to a part of your status line.
E.g. status_line.parts = { " {file_name} | {pomodoro_show} " }
will render the file name of the file currently in view and will show the output of the pomodoro timer to the right.
You may need to restart Ox for it all to work correctly
Once everything is up and running, you should now see No Pomodoro Active
To start the pomodoro timer, run the command pomodoro start
To end the pomodoro timer, run the command pomodoro stop
This is a very simple plug-in that will notify you if your currently installed Ox version differs from the latest one
This plug-in uses networking so will require curl
on all systems, including Windows.
To install: run the command plugin install update_notification
To uninstall: run the command plugin uninstall update_notification
A plug-in to track how fast you are typing.
It will use how quickly you press the space bar.
It is limited in accuracy due to Lua's limited date and time API, which only allows measurement of seconds, but it will be roughly correct.
To install: run the command plugin install typing_speed
To uninstall: run the command plugin uninstall typing_speed
Usage:
You will need to add it somewhere to the editor
You can do this in the greeting message, help message, status line or even the tab line.
To do this, simply add in {typing_speed_show}
into the format strings of any of the lines / messages in your .oxrc
file.
E.g.
status_line.parts = { " {typing_speed_show} " }
A plug-in that adds support for todo files.
To install: run the command plugin install todo
To uninstall: run the command plugin uninstall todo
Usage:
Todo files have the extension .todo
.
They are formatted like so:
- [ ] This task is not done
- [X] This task is completed
If you put your cursor over one of the lines, and press Ctrl + Enter you can change a todo from done to not done (and vice versa).
If you change the state of a todo, it will also show you the statistics on how many todos you have done at the bottom of the editor.
If you find yourself writing a lot of web pages, then this plug-in will help you visualise your changes instantly, as soon as you type them.
Install:
Run the command plugin install live_html
You will also need a browser installed, along with Python and the flask
module, which can be installed through the command pip install Flask
Uninstall:
Run the command plugin uninstall live_html
You can also uninstall python and the flask
module if you would like to
Usage:
To use this plug-in, open up the file that is the entry point of your application e.g. index.html
and then run the command html start
.
By default, you will be able to see your website by navigating to localhost:5000
in your browser.
To stop the HTML live server, run the command html stop
.
When you close the editor, the HTML server will automatically stop for you.
Be default, every time you press Ctrl + S
(mirroring the default save command), all browsers currently on localhost:5000
will reload the page, but you can also have it refresh whenever the document is changed in-editor so it updates as you type. To do this, add the line live_html = { refresh_when = "keypress" }
.
If you have a CSS file, for example, and you want livehtml to update the preview when you edit it, you can run the command html track [file name]
e.g. html track style.css
, and when you update style.css, it will refresh the main website too so you can see changes in style instead of waiting for you to edit your main entry point i.e. index.html
where you ran html start
This is a plug-in that will help you in web development through the Emmet library.
Install:
Run the command plugin install emmet
You need to have python and the py-emmet
library installed. You can install the py-emmet
library through the command pip install py-emmet
.
You also need the autoindent
plug-in installed and enabled so that it can correctly provide indented expanded code. Run plugin install autoindent
to ensure that it is enabled
Uninstall:
Run the command plugin uninstall emmet
You can then uninstall python or the py-emmet
module if you desire.
Usage:
E.g. if you type ul>li*5
, you can use the key binding Ctrl + M to activate the emmet plug-in, which will look on the line the cursor is on, take it as emmet code and then expand and insert the expanded HTML as
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
A plug-in that will help you interact with git without needing to leave the editor
It features the following features:
- See and change the current branch
- See which files are staged or modified, and stage/unstage them
- Create commits
- Push and pull changes
- View diffs
Install:
Make sure you have git installed and accessible on the command line. Then you can run the command plugin install git
Uninstall:
Run the command plugin uninstall git
and then you can uninstall git if you'd like.
Usage:
This is a complicated plug-in and there are multiple commands and additions you can put in.
This plug-in provides {git_branch}
and {git_status}
for your status line / tab line.
My personal recommendation is to add {git_status}
to your tab line to see which files are staged / modified. Also add {git_branch}
to your status line see the current branch you're on.
By default, the git plug-in will not use nerd font icons. If you want to enable these, edit the git.lua
file where your extensions are (~/.config/ox/git.lua
on UNIX based systems, ~/ox/git.lua
on windows where ~
is the root of your user home directory).
Set icons = true
in the following table and save your file changes:
git = {
status = {},
icons = false, -- change this to true to enable icons
}
As for the commands that you can use:
-
git add all
- Stage all files -
git add
- Stage currently open file -
git reset all
- Unstage all files -
git reset
- Unstage currently open file -
git diff all
- View the diff before all files in the repository -
git diff
- View the diff in this file in particular -
git stat all
- View the overall statistics of the changes in the repository -
git stat
- View the statistics of the changes of the currently open file -
git commit
- Create a commit -
git push
- Push local commits upstream -
git pull
- Pull commits from upstream -
git checkout [branch name]
- Switch to a different branch
A plug-in that shows your Ox activity to other discord users.
Install:
Make sure this setting is enabled for your Discord account.
Run the command plugin install discord_rpc
After this, you should also make sure you have Python installed and the discord-rpc module installed or the plug-in will not work.
You can install the discord-rpc module through the command pip install discord-rpc
Uninstall:
Run the command plugin uninstall discord_rpc
You can also uninstall python / the discord-rpc
module if you would like.
Some of the above plug-ins are "built-in" which means that you don't actually need to install them as they come with the Ox binary as standard and are enabled.
The built-in plug-ins are: autoindent
and pairs
and quickcomment
.
If you want to run a modified version of a built-in plug-in, then you can place the modified lua file of these plug-ins, and install them just as you would any other plug-in (see distribution of plug-ins).
At the bottom of your user configuration file, add load_plugin("name_of_plugin.lua")
.
If you want to disable a built-in plug-in because you don't like the feature, just create a user configuration and don't include the load_plugin
call for the plug-in you want to disable and ox will recognise your preference and not load it in.
When writing plug-ins, you are very likely going to want to interact with the editor somehow, whether it's displaying a message to the user, or writing some text for them. The way to interact with the editor is through the API. There are a wide range of methods available for you to call, attached to an editor
table.
Here are all the commands that you can run that may come in handy:
Command | Description | Example usage |
---|---|---|
editor:display_error |
This command will display an error message to the user (red by default) |
editor:display_error("file not found") which will display an error message saying "file not found" |
editor:display_warning |
This command will display a warning message to the user (yellow by default) |
editor:display_warning("backup failed") which will show a warning message saying "backup failed" |
editor:display_info |
This command will display an information message to the user (blue by default) |
editor:display_info("time to take a break") which will show info to the user asking them to take a break |
editor:prompt |
This command will ask the user for something and return what they entered |
name = editor:prompt("What's your name") which will ask the user their name and store their answer in the name variable |
editor:insert |
This command will insert specified text at the place where the cursor currently is in the document |
editor:insert("3.141") which will insert PI (the number) where the user's cursor currently is |
editor:remove |
This command will essentially just simulate the user pressing the backspace key, and will delete whatever is behind the cursor |
editor:remove() which will simulate the user pressing backspace |
editor:insert_line |
This command will insert a line at the current position of the cursor, it essentially simulates the user pressing the enter key |
editor:insert_line() which will simulate the user pressing enter |
editor:remove_line |
This command will delete the line that the cursor is currently on |
editor:remove_line() which will remove the line where the cursor is, e.g. line 3 if the cursor is on line 3 |
editor:move_to |
This command will move the cursor to a specified x and y coordinate in the document |
editor:move_to(3, 1) which will move the cursor to the third character (x coordinate) on the first line (y coordinate) |
editor:move_up |
This command will move the cursor one upwards |
editor:move_up() which will move the cursor to the line above where it currently is |
editor:move_down |
This command will move the cursor one downwards |
editor:move_down() which will move the cursor to the line below where it currently is |
editor:move_left |
This command will move the cursor one to the left |
editor:move_left() which will move the cursor to the left |
editor:move_right |
This command will move the cursor one to the right |
editor:move_right() which will move the cursor to the right |
editor:move_home |
This command will move the cursor to the beginning of the current line |
editor:move_home() which will move the cursor to the beginning of the line it is currently on |
editor:move_end |
This command will move the cursor to the end of the current line |
editor:move_end() which will move the cursor to the very end of the line it is currently on |
editor:move_page_up |
This command will scroll up a page e.g. if the viewport is 20 lines in height, then it will scroll 20 lines upwards |
editor:move_page_up() which will move up one page |
editor:move_page_down |
This command will scroll down a page e.g. if the viewport is 20 lines in height, then it will scroll 20 lines downwards |
editor:move_page_down() which will move down one page |
editor:move_top |
This command will move the cursor to the first line in the document |
editor:move_top() which will move to the top of the document |
editor:move_bottom |
This command will move the cursor to the last line in the document |
editor:move_bottom() which will move to the bottom of the document |
editor:move_previous_word |
This command will move the cursor to the previous word (separated by spaces) |
editor:move_previous_word() which will move the cursor to the previous word |
editor:move_next_word |
This command will move the cursor to the next word (separated by spaces) |
editor:move_next_word() which will move the cursor to the next word |
editor:insert_at |
This command will insert text at a certain x and y location |
editor:insert_at("Hello", 2, 3) which will insert the text "hello" at the 2nd character of the 3rd line |
editor:remove_at |
This command will remove the a character at a certain x and y location |
editor:remove_at(4, 1) which will remove the 4th character on the 1st line |
editor:insert_line_at |
This command will insert a line at a certain line number |
editor:insert_line_at("new line", 4) which will create a new line on line 4 of the document with the text "new line" |
editor:remove_line_at |
This command will remove the line at a certain index |
editor:remove_line_at(4) which will remove the 4th line in the document |
editor:open_command_line |
This command will open the command line |
editor:open_command_line() which will open the command line |
editor:previous_tab |
This command will move to the previous document that is currently opened in the editor |
editor:previous_tab() which will move focus to the previous document that is currently opened |
editor:next_tab |
This command will move to the next document that is currently opened in the editor |
editor:next_tab() which will move focus to the next document that is currently opened |
editor:new |
This command will create and open a new document for the user to write in |
editor:new() which will create a new document |
editor:open |
This command will ask the user for a file name and then open that file |
editor:open() which will ask the user for a file to open, and then open it |
editor:save |
This command will save the document the user is currently on |
editor:save() which will save the current document |
editor:save_as |
This command will ask the user for a file name and save the current document to that path |
editor:save_as() which will ask the user for a path to save the current document to |
editor:save_all |
This command will save all currently opened documents |
editor:() which will save all opened documents |
editor:quit |
This command will quit the current document (and the whole editor if all documents are quit out of) |
editor:quit() which will close the current document (and the whole editor if all documents have been closed) |
editor:undo |
This command will trigger an undo action |
editor:undo() which will undo the last change the user made |
editor:redo |
This command will trigger a redo action |
editor:redo() which will redo the last change the user made |
editor:commit |
This command will create a snapshot to restore to on undo/redo |
editor:commit() which will commit changes to the event stack |
editor:search |
This command will trigger the search wizard |
editor:search() which will ask the user for what they wish to search for and move the cursor along all matches |
editor:replace |
This command will open the replace wizard |
editor:replace() which will ask the user what they want to replace and what to replace with, and then provide options to replace certain instances or all instances |
editor:get |
This command will get the entire contents of the file |
editor:get() which will get the entire contents of the currently opened document |
editor:get_character |
This command will get the character that the cursor is currently over |
editor:get_character() which will return e , for example, if the cursor in the editor is next to the letter e in the document |
editor:get_character_at |
This command will get a character at a certain location within the document |
editor:get_character_at(3, 1) which will get the 3rd character on the first line |
editor:get_line |
This command will get the line the cursor is currently on in the document |
editor:get_line() which will get line 2, for example, if the cursor in the document is currently at line 2 |
editor:get_line_at |
This command will get the line at a certain index |
editor:get_line_at(5) which will get the fifth line in the document |
editor:move_to_document |
This command will move to a document that is currently open |
editor:move_to_document(0) which will move to the first document that is open in the editor |
editor:move_previous_match |
This command will move to a previous instance of a certain string |
editor:move_previous_match("self") which will search backwards until it finds the text self , and then move the cursor to where that text is in the document |
editor:move_next_match |
This command will move to the next instance of a certain string |
editor:move_next_match("bar") which will search forwards until it finds the text bar , and then move the cursor to where that text is in the document |
editor:hide_help_message |
This command will hide the in-editor help message |
editor:hide_help_message() which will hide the help message |
editor:show_help_message |
This command will show the in-editor help message |
editor:show_help_message() which will show the help message |
editor:set_read_only |
This command will set the file's read only status |
editor:set_read_only(true) which will make the file that is currently open read only |
editor:set_file_type |
This command will set the file type of the file that is currently open |
editor:set_file_type("Python") which will set the file type of the file currently open to a python file, and enable language-specific features such as syntax highlighting. Note the argument is the file type name in version 0.6.6 and up, and the file extension (e.g. py ) in lower versions |
editor:select_up |
This command will move the cursor up whilst selecting |
editor:select_up() which will move the cursor up whilst selecting |
editor:select_down |
This command will move the cursor down whilst selecting |
editor:select_down() which will move the cursor down whilst selecting |
editor:select_left |
This command will move the cursor left whilst selecting |
editor:select_left() which will move the cursor left whilst selecting |
editor:select_right |
This command will move the cursor right whilst selecting |
editor:select_right() which will move the cursor right whilst selecting |
editor:select_all |
This command will select all the text in the currently open document |
editor:select_all() which will select all the text in the currently open document |
editor:select_to |
This command will select to a certain position within the document |
editor:select_to(x, y) which will move to the x position x and the y position y . |
editor:cancel_selection |
This command will cancel the current selection. |
editor:cancel_selection() which will cancel the current selection. |
editor:cursor_to_viewport |
This command will move the viewport over the cursor. |
editor:cursor_to_viewport() which will move the viewport over the cursor position. |
editor:copy |
This command will copy the currently selected text |
editor:copy() which will copy the currently selected text |
editor:reload_config |
This command will reload the config file for when you want to load in any changes |
editor:reload_config() which will reload the configuration file |
editor:reload_plugins |
This command will reload the plugins for when you want to load in any changes |
editor:reload_plugins() which will reload the plugins |
editor:rerender |
This command will force the editor to re-render its interface |
editor:rerender() which will force a rerender |
editor:rerender_feedback_line |
This command will force the editor to re-render just the feedback line |
editor:rerender_feedback_line() which will force a rerender on just the feedback line |
editor:rerender_status_line |
This command will force the editor to re-render just the status line |
editor:rerender_status_line() which will force a rerender on just the status line |
editor:reset_terminal |
This command will reset the terminal to ensure that everything works correctly after another TUI program hijacks the terminal. |
editor:reset_terminal() which resets the terminal |
editor:cursor_snap |
This command will cache the current y position of the cursor such that when the user moves directly up or down, it will retain that y position. |
editor:cursor_snap() which caches the y position of the cursor. |
editor:move_line_up |
This command will move the current line the user is on upwards. |
editor:move_line_up() which swaps the current line with the line above. |
editor:move_line_down |
This command will move the current line the user is on downwards. |
editor:move_line_down() which swaps the current line with the line below. |
editor:panic |
This command will immediately halt the editor and print the string provided in the argument, this should only be used for debugging purposes. |
editor:panic("This was run") which will purposefully crash the editor and print the text [Error] This was run
|
editor.cursor |
This command will return the current cursor position of the document |
editor.cursor.x which will return the x coordinate of the cursor (the character) and editor.cursor.y which will return the y position of the cursor (line number) |
editor.selection |
This command will return the current position of where the selection starts or ends within the document |
editor.selection.y which will return the line that the selection currently ends / starts on |
editor.file_name |
This command will return the name of the file currently open |
editor.file_name which will return the name of the file that is currently being looked at |
editor.file_extension |
This command will return the extension of the file currently open |
editor.file_extension which will return the extension of the file that is currently being looked at |
editor.file_path |
This command will return the path of the file currently open |
editor.file_path which will return the path of the file that is currently being looked at |
editor.document_name |
This command will return the name of the document |
editor.document_name which will return the name of the document that is currently being looked at |
editor.document_length |
This command will return the number of lines in the document currently open |
editor.document_length which will return 300 if the document currently being looked at is 300 lines in length |
editor.document_type |
This command will return the type of document you're looking at |
editor.document_type which will return "Python", for example, if you are looking at a .py file |
editor.version |
This command will return the version of the editor |
editor.version which will return "0.4.3" if you're using version 0.4.3 of Ox |
editor.current_document_id |
This command will give the ID of the document that the user is currently looking at |
editor.current_document_id which will return 1 for example, if the user is looking at the second document open and 0 if the user is looking at the first one |
editor.document_count |
This command will return the number of documents currently open |
editor.document_count which will return 5 if there are 5 documents currently open in the editor |
editor.pasting |
This command will return true if the editor is currently having text pasted into it |
editor.pasting will return true if the user is currently pasting something into the editor and vice versa for false |
editor.cwd |
Returns the current working directory |
editor.cwd will get the current working directory based on the file the user is currently looking at. |
editor.macro_recording |
Returns true if the user is currently recording a macro. |
editor.macro_recording will return false when the user isn't recording a macro and true otherwise. |
editor.macro_playing |
Returns true if the user is currently playing back a macro. |
editor.macro_recording will return false when the user isn't playing back a macro and true otherwise. |
editor:macro_record_start |
Start recording a macro. |
editor:macro_record_start will start recording a macro. |
editor:macro_record_stop |
Stop recording a macro. |
editor:macro_record_stop will stop recording a macro. |
editor:macro_play |
Play a macro. |
editor:macro_play(2) will play a macro twice one after the other. |
Now you know how to interact and control the editor from your plug-ins, you can get to work writing them.
You can make http get, post, put and delete requests from within your plug-ins.
Every plug-in will have the http
table available to it.
Here is an example of a http get request that checks the version of the latest release of Ox
-- Get the contents of the latest Cargo.toml
local cargo_latest = http.get("https://raw.githubusercontent.com/curlpipe/ox/refs/heads/master/Cargo.toml")
-- Extract the version from the build file
local version = cargo_latest:match("version%s*=%s*\"(%d+.%d+.%d+)\"")
-- Display it to the user
if version ~= nil then
editor:display_info("The latest version of Ox is: " .. version)
end
In full, the available http method calls:
http.get(url)
http.post(url, data)
http.put(url, data)
http.delete(url)
Under the hood, these call either curl
across all operating systems, including windows.
Make sure you have curl
installed if you wish to use networking on Linux or macOS or windows, although most of the time this binary is pre-installed on these systems.
There is a very very simple concurrency API included everywhere you write plug-ins.
There are two functions you can make use of:
-
after(delay, name)
- runs a function called "name" after delay seconds -
every(interval, name)
- runs a function called "name" every interval seconds
Be warned - name
must be a string referring to the name of a globally-available function.
Also, if you make changes that will result in the interface itself updating - run editor:rerender()
to tell the editor to rerender the UI and show any changes.
You can also use editor:rerender_status_line()
or editor:rerender_feedback_line()
to speed up rendering (as it only rerenders a small part of the editor rather than the whole thing)
Here is an example:
function hello()
editor:display_info("Hello!")
-- Rerender just the feedback line as this is the only part that will have changed
editor:rerender_feedback_line()
end
every(1, "hello")
this defines a function hello
that is globally available, which will display hello in the status line, rerender the editor to show the new UI change. hello
is called every second, essentially spamming "Hello!" into the status line.
Another handy trick is this - if you want to run a function that doesn't lock up the entire editor, then you can use after(0, name)
, which itself isn't blocking, however the function given as name
will be run immediately.
This should be enough to get lua code running in the background.
If you want to run shell commands, it is highly recommended that you use the shell API. This API allows for cross-platform commands and it silences commands so they don't mess around with the editor's rendering. This API is built 100% in Lua, it's just a wrapper around Lua's built-in os.execute
and io.popen
methods.
There are two basic methods available to all plug-ins:
-
shell:run(command)
- this will run the command given as a parameter, and return the exit code (0
if successful) -
shell:output(command)
- this will run the command given as a parameter, and return a string of the resulting stdout and stderr
Using these two commands, you can cover 90% of what you'd want to do with shell commands
You can also make use of forked processes and have them run alongside the editor without locking up the editor itself.
There are two main commands here:
-
shell:spawn(command)
- this will run the command given as a parameter, fork off the process and return the PID of the process (store this PID in a variable if you want to kill the process at a later time) -
shell:kill(pid)
- this will kill the process spawned by theshell:spawn
command.
Here is an example:
-- Run an external script
local process = shell:spawn("some_script.sh")
-- Kill the external script when the user presses ctrl + shift + k
event_mapping["ctrl_shift_k"] = function()
shell:kill(process)
end
Please note that you can use all APIs available in the standard library of Lua, e.g. array manipulation / os interaction
You can also access anything you would be able to access in the configuration file (in case you want your plug-in to modify settings)
Note that you will not be able to use external lua libraries without downloding the code for these libraries themselves. Therefore, if you're looking for certain functionality that is just not provided, then be sure to look above at the available APIs for if the functionality has already been implemented, and worst case, open an issue on github to request a certain feature to be provided to plug-ins.
Here is a random list of internal functions that you might find useful:
-
dir_exists("path/to/dir")
- returns true if the directory exists, otherwise false -
file_exists("path/to/file")
- returns true if the file exists, otherwise false
local date = shell:output("date") -- run the "date" command to get the date and time
-- Now display to the user the date and time
editor:display_info("The date and time is currently: " .. date)
-- Alternatively, you could use Lua's standard library `os.date()`
Here, we ask the user for their HTML tag name e.g. body
or h1
and then insert both the starting and ending tags for them to use
tag_name = editor:prompt("Tag name")
editor:insert("<" .. tag_name .. ">\n\n</" .. tag_name .. ">" )
For example, if the user puts in style
, it would write:
<style>
</style>
in their document (at the location of where the cursor currently is)
This would be a quick way to write HTML tags without having to repeat yourself all the time
Now you've been able to understand how to write your plug-ins, we must go over how to start them when in the editor.
There are three ways to trigger plug-ins:
- On key press
- When a command is run (by default, you can access the command line by using the key combination Ctrl + K and then typing in a command there)
- When rendering the status line, greeting message or help message
In the configuration file, key presses are represented with strings.
Modifiers, such as ctrl
, alt
and shift
come first, followed by key codes e.g. backspace
or z
or 4
Here are some examples:
-
a
- the a key on the keyboard is pressed -
ctrl_a
- the control key is held down, followed by the a key being pressed -
ctrl_alt_s
- the control key is held down, then the alt key is held, then the s key is pressed -
esc
- the escape key is pressed
When the user presses a key, Ox will send that key press through to your configuration file. It will check in a table called event_mapping
for a key combination corresponding to the key the user pressed and then run the function that was attached to that key combination.
It's probably better demonstrated with an example:
event_mapping = {
["ctrl_h"] = function()
editor:display_info("You pressed CTRL and H")
end,
}
here you can see the binding of ctrl h to a function which will display an info message to the user.
in the default config file (in config/.oxrc
in the repository) you can see a list of all the key bindings that are used by default.
You are free to use any key binding for whatever purpose you please.
By default, when you bind a key in the event mapping, the function you provide will be executed after the editor has applied it's own edits.
E.g. binding to the a
key means that the code you provide to the event_mapping will inherit an editor state with the a already present. If you were to run editor:get_line()
you would see that a
in there already.
This is not always ideal. For example, say you want to check the existing state of the document before any edits are applied so that you can run some code after the edit that takes into account the previous state of the document.
To do this, you can use the before:
syntax before the key you are binding to:
event_mapping["before:a"] = function()
-- Is there an a already in the document?
if editor:get_character() == "a" then
-- Yes, there is, delete it to avoid duplicate As
editor:remove_character_at(editor.cursor.x, editor.cursor.y)
end
end
This code checks if there is an existing a in the document, and will remove it if there is (before the editor inserts its own a
as per the user's key press)
This is used heavily in the pairs
plug-in because pairs
needs to see if you're in a bracket pair when pressing backspace.
E.g. say our cursor is like this between two brackets: (|)
if we press backspace, it'll look like this |)
, by which point if we had bound a traditional non-before:
event,
we would be missing that (
that was just deleted, and would have absolutely no idea what was just deleted, hence we couldn't verify if we had just deleted the starting pair of a bracket pair, hence we wouldn't be able to tell to delete the corresponding end pair.
You can also bind an event for when the editor exits. This is useful for any cleanup your plug-in needs to do.
event_mapping["exit"] = function()
-- Run code when the editor exits
end
By default, paste events are not given to normal bindings e.g. if you paste the string test
into the editor, it won't issue events for t
, e
and s
and t
(again). To react to paste events, you must use the following:
event_mapping["paste"] = function(paste_text)
-- paste_text contains the text that the user has pasted
end
So, perhaps you don't want to run a plugin on a key press, or you would like your plug-in to act differently depending on what the user inputs. This can be done through custom commands.
Just like with key bindings, you can add custom commands into the configuration file at ~/.oxrc
.
When a command is run, it is shown to the configuration file, which can then determine how to deal with that command.
The command
table defines how to handle various commands to the user. The keys are the command name, and the values are functions.
Here is an example:
commands = {
["greet"] = function(arguments)
editor:display_info("Hello, " .. arguments[1] .. ", nice to meet you")
end,
}
When the user writes a command that starts with greet
, followed by some arguments (separated by spaces), it will take the first argument the user provided, and display a message to greet the user.
For example, if I were to open the command line using Ctrl + K (which is the default key binding for opening the command line), and run the command greet James
then the first argument would be James
, and the editor would display Hello, James, nice to meet you
. Arguments are a list of what the user has put in (after the initial command name, which is greet
in this case)
You could extend on this (to demonstrate multiple arguments) as such:
commands = {
["greet"] = function(arguments)
first_name = arguments[1]
surname = arguments[2]
editor:display_info("Nice to meet you, " .. first_name .. " " .. surname)
end,
}
where we use the first argument as the first name and the second as the surname.
E.g. greet James Smith
would display Nice to meet you, James Smith
to the console (here using both the first and second argument)
In your plugin, if you were to write a function that returned a string, such as:
function show_pomodoro()
return "Time remaining: " .. pomodoro.time_left .. " minutes"
end
then you would be able to put the return value of this function into the status line, by adding {show_pomodoro}
in one of the parts of the status line, greeting message or help message.
Now, every time the editor renders, it will call your lua function, take the string that was returned and then display on the status line.
This makes your plug-ins feel just like a built-in feature!
There may come a time where you want to distribute your plug-in or download someone else's plug-in.
Ensure you have updated to at least Ox 0.6.3 to use the plug-in manager
This is a very simple way to install and uninstall and check which plug-ins are installed.
This can be accessed in the command line (Ctrl + K).
Within the command line, you can use one of the following commands:
-
plugin install [plugin name]
- install a plug-in (make sure you substitute the correct name of the plug-in in without the .lua extension) -
plugin uninstall [plugin name]
- uninstall a plug-in (make sure you substitute the correct name of the plug-in without the .lua extension) -
plugin status
- check which plug-ins are enabled -
plugin update
- check for and update any out-of-date plug-ins
Please open a pull request if you would like to add your own plug-in to Ox, add it to the /plugins
folder at the root of the repository. This folder is where the plugin command gets the code from. By adding your plug-in to that folder, you add it to the plug-in manager within Ox.
If the plug-in manager isn't working, you can use this method, which is essentially doing what the plug-in manager above will do for you.
You can see a list of plug-ins you might want to use in the plugins
folder in the repository. This includes plug-ins such as auto bracket pairs (for quick editing) and auto indentation in code files.
You may also find another plug-in elsewhere, such as on github.
Plug-ins should be in a single lua file (or multiple lua files with a central one that imports the others).
Download all lua files and place them in your ~/.config/ox/
folder (on unix based systems) or in an ox
folder in your user's home directory on windows (e.g. C:/Users/Boris/ox/
).
Then, in your configuration file, you can import plugins by using the load_plugin
function, which takes as argument the file name of the plug-in e.g. pomodoro.lua
: load_plugin("pomodoro.lua")
.
Say you want to install the pairs.lua
plug-in, which is included in the plugins
folder.
- Download it and put it in the
~/.config/ox/
folder as~/.config/ox/pairs.lua
- Load it in your configuration file (it is best to put it at the bottom of the config file)
Ox will look in the directory for the plug-in
load_plugin("pairs.lua")
pairs.lua
, which we downloaded in step 1 - Now when the editor is opened, the plugin should be up and running
If you want to set key bindings in your plug-in, you can do it, for example, like this:
event_mapping["ctrl_h"] = function()
-- Your plugin code goes here
end
This just adds to the same event_mapping
object the user has in their config file.
Similarly, to add in a command, you can do the following:
commands["name"] = function(arguments)
-- Your plugin code goes here
end
To package a plug-in, simply take the lua files where you have written your plug-in and then you are free to distribute them on github or through other means where users can download and import them.
If you want to add it to the plug-in manager (so that users can install your plug-in by simply running the command plugin install [your plugin name]
then please feel free to create a pull request with your plug-in lua code in the plugins
directory in the Ox repository)