Skip to content

Commit

Permalink
custom-keybinds: implement version checking
Browse files Browse the repository at this point in the history
custom-keybinds is now part of the addon API and shares a version number
  • Loading branch information
CogentRedTester committed Oct 30, 2022
1 parent ccd4fdf commit acd6619
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 29 deletions.
11 changes: 7 additions & 4 deletions addons/addons.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# How to Write an Addon - API v1.4.0
# How to Write an Addon - API v1.5.0

Addons provide ways for file-browser to parse non-native directory structures. This document describes how one can create their own custom addon.

Expand All @@ -23,10 +23,13 @@ not be loaded.
A minor version number denotes a change to the API that is backwards compatible. This includes additional API functions,
or extra fields in tables that were previously unused. It may also include additional arguments to existing functions that
add additional behaviour without changing the old behaviour.
If the parser's minor version number is greater than the API_VERSION, then a warning is printed to the console.
If the parser's minor version number is greater than the API_VERSION, then an error message will be printed and the parser will
not be loaded.

Patch numbers denote bug fixes, and are ignored when loading an addon.
For this reason addon authors are allowed to leave the patch number out of their version tag and just use `MAJOR.MINOR`.
Patch numbers denote bug fixes, and are mostly ignored when loading an addon.
However if the addon has a patch number greater than the patch number file-browser uses then a warning will
be printed just in case the addon uses a bug that has been fixed in the patches.
Addon authors are allowed to leave the patch number out of their version tag and just use `MAJOR.MINOR`.

## Overview

Expand Down
25 changes: 19 additions & 6 deletions custom-keybinds.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Custom Keybinds

File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item.
File-browser supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item.
This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard.

The custom-keybind API shares a version number with the [addon API](addons/addons.md#api-version).

The feature is disabled by default, but is enabled with the `custom_keybinds` script-opt.
Keybinds are declared in the `~~/script-opts/file-browser-keybinds.json` file, the config takes the form of an array of json objects, with the following keys:

Expand All @@ -11,6 +13,7 @@ Keybinds are declared in the `~~/script-opts/file-browser-keybinds.json` file, t
| key | yes | - | the key to bind the command to - same syntax as input.conf |
| command | yes | - | json array of commands and arguments |
| name | no | numeric id | name of the script-binding - see [modifying default keybinds](#modifying-default-keybinds) |
| version | no | `1.0.0` | the minimum API version required for the keybind - will warn the user if they are using an invalid keybind for their file-browser version |
| condition | no | - | a Lua [expression](#expressions) - the keybind will only run if this evaluates to true |
| flags | no | - | flags to send to the mpv add_keybind function - see [here](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) |
| filter | no | - | run the command on just a file (`file`) or folder (`dir`) |
Expand Down Expand Up @@ -55,7 +58,8 @@ You can set the filter to match multiple parsers by separating the names with sp
{
"key": "KP2",
"command": [ ["print-text", "example3"] ],
"parser": "ftp file"
"parser": "ftp file",
"version": "1.5.0"
}
```

Expand Down Expand Up @@ -184,12 +188,14 @@ the selected item is a matroska file:
{
"key": "KP1",
"command": ["print-text", "in my C:/ drive!"],
"condition": "(%P):find('C:/') == 1"
"condition": "(%P):find('C:/') == 1",
"version": "1.5.0"
},
{
"key": "KP2",
"command": ["print-text", "Matroska File!"],
"condition": "fb.get_extension(%N) == 'mkv'"
"condition": "fb.get_extension(%N) == 'mkv'",
"version": "1.5.0"
}
]
```
Expand All @@ -216,7 +222,8 @@ Any `=>` string will be substituted for `script-message`.
{
"key": "KP1",
"command": ["script-message", "=>", "delay-command", "%j * 2", "=>", "evaluate-expressions", "print-text", "!{%j * 2}"],
"multiselect": true
"multiselect": true,
"version": "1.5.0"
}
```

Expand All @@ -230,6 +237,7 @@ This example command will only run if the player is currently paused:
{
"key": "KP1",
"command": ["script-message", "conditional-command", "mp.get_property_bool('pause')", "print-text", "is paused"],
"version": "1.5.0"
}
```

Expand All @@ -241,6 +249,7 @@ This example only runs if the currently selected item in the browser has a `.mkv
{
"key": "KP1",
"command": ["script-message", "conditional-command", "fb.get_extension(%N) == 'mkv'", "print-text", "a matroska file"],
"version": "1.5.0"
}
```

Expand All @@ -255,6 +264,7 @@ The following example will send the `print-text` command after 5 seconds:
{
"key": "KP1",
"command": ["script-message", "delay-command", "5", "print-text", "example"],
"version": "1.5.0"
}
```

Expand All @@ -272,6 +282,7 @@ For example the following keybind will print 3 to the console:
{
"key": "KP1",
"command": ["script-message", "evaluate-expressions", "print-text", "!{1 + 2}"],
"version": "1.5.0"
}
```

Expand All @@ -282,6 +293,7 @@ This example replaces all `/` characters in the path with `\`
{
"key": "KP1",
"command": ["script-message", "evaluate-expressions", "print-text", "!{ string.gsub(%F, '/', '\\\\') }"],
"version": "1.5.0"
}
```

Expand Down Expand Up @@ -316,7 +328,8 @@ rename items in file-browser:
"fb.rescan()"
],
"parser": "file",
"multiselect": true
"multiselect": true,
"version": "1.5.0"
}
```

Expand Down
58 changes: 39 additions & 19 deletions file-browser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,29 @@ local ABORT_ERROR = {
msg = "browser is no longer waiting for list - aborting parse"
}

local API_MAJOR, API_MINOR, API_PATCH = API_VERSION:match("(%d+)%.(%d+)%.(%d+)")

--checks if the given table has a valid version number
function API.check_version(version)
version = version or "1.0.0"

local major, minor = version:match("(%d+)%.(%d+)")
local patch = version:match("%d+%.%d+%.(%d+)")

if not major or not minor then
return false, ("Invalid version number: %s"):format(version)
elseif major ~= API_MAJOR then
return false, ("wrong major version number - expected v%d.x.x got v%s"):format(API_MAJOR, version)
-- return msg.error("parser", parser.name, "has wrong major version number, expected", ("v%d.x.x"):format(API_MAJOR), "got", 'v'..version)
elseif minor > API_MINOR then
return false, ("wrong minor version number - expected v%d.0.x - v%d.%d.x got v%s"):format(API_MAJOR, API_MAJOR, API_MINOR, version)
-- msg.warn("parser", parser.name, "has newer minor version number than API, expected", ("v%d.%d.x"):format(API_MAJOR, API_MINOR), "got", 'v'..version)
elseif patch and patch > API_PATCH then
return true, ("wrong patch number - expected v%d.%d.0 - v%d.%d.%d got v%s"):format(API_MAJOR, API_MINOR, API_MAJOR, API_MINOR, API_PATCH, version)
end
return true
end

--implements table.pack if on lua 5.1
if not table.pack then
table.unpack = unpack
Expand Down Expand Up @@ -1728,6 +1751,15 @@ end
--inserting the custom keybind into the keybind array for declaration when file-browser is opened
--custom keybinds with matching names will overwrite eachother
local function insert_custom_keybind(keybind)
local success, err = API.check_version(keybind.version)
if not success then
msg.warn(utils.to_string(keybind))
msg.error(('failed to load keybind %s: %s'):format(keybind.name, err))
return
elseif err then
msg.warn(('%s\nwarning loading keybind %s: %s'):format(utils.to_string(keybind), keybind.name, err))
end

--we'll always save the keybinds as either an array of command arrays or a function
if type(keybind.command) == "table" and type(keybind.command[1]) ~= "table" then
keybind.command = {keybind.command}
Expand Down Expand Up @@ -1945,24 +1977,6 @@ end
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------

local API_MAJOR, API_MINOR, API_PATCH = API_VERSION:match("(%d+)%.(%d+)%.(%d+)")

--checks if the given parser has a valid version number
local function check_api_version(parser)
local version = parser.version or "1.0.0"

local major, minor = version:match("(%d+)%.(%d+)")

if not major or not minor then
return msg.error("Invalid version number")
elseif major ~= API_MAJOR then
return msg.error("parser", parser.name, "has wrong major version number, expected", ("v%d.x.x"):format(API_MAJOR), "got", 'v'..version)
elseif minor > API_MINOR then
msg.warn("parser", parser.name, "has newer minor version number than API, expected", ("v%d.%d.x"):format(API_MAJOR, API_MINOR), "got", 'v'..version)
end
return true
end

--create a unique id for the given parser
local function set_parser_id(parser)
local name = parser.name
Expand Down Expand Up @@ -2027,7 +2041,13 @@ local function setup_parser(parser, file)
parser.name = parser.name or file:gsub("%-browser%.lua$", ""):gsub("%.lua$", "")

set_parser_id(parser)
if not check_api_version(parser) then return msg.error("aborting load of parser", parser:get_id(), "from", file) end
local valid_version, err = API.check_version(parser.version)
if not valid_version then
msg.error(parser:get_id()..':', err)
return msg.error("aborting load of parser", parser:get_id(), "from", file)
elseif err then
msg.warn(("warning loading parser %s: %s"):format(parser:get_id(), err))
end

msg.verbose("imported parser", parser:get_id(), "from", file)

Expand Down

0 comments on commit acd6619

Please sign in to comment.