Skip to content

Commit

Permalink
feat: user defined handlers (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianMoesl authored Mar 13, 2024
1 parent 78070bb commit 32963dc
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 45 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* dependencies from `package.json` (e.g. line `"express": "^4.18.2",` in the `package.json` opens `https://www.npmjs.com/package/express`)
* formulae and casks from `Brewfile` (e.g. line `brew "neovim"` in the `Brewfile` opens `https://formulae.brew.sh/formula/neovim`)
* if there is no url found under the cursor, the word/selection is automatically searched on the web
* supports user defined handlers to extend the functionality
* support for macOS, Linux and Windows
* more to come (jira issues, ..)

Expand Down Expand Up @@ -50,6 +51,15 @@ require("lazy").setup({
brewfile = true, -- open Homebrew formulaes and casks
package_json = true, -- open dependencies from package.json
search = true, -- search the web/selection on the web if nothing else is found
jira = { -- custom handler to open Jira tickets (these have higher precedence than builtin handlers)
handle = function(mode, line, _)
local ticket = require("gx.helper").find(line, mode, "(%u+-%d+)")
if ticket and #ticket < 20 then
return "http://jira.company.com/browse/" .. ticket
end
end,
},
},
},
handler_options = {
search_engine = "google", -- you can select between google, bing, duckduckgo, and ecosia
Expand Down
59 changes: 35 additions & 24 deletions lua/gx/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,57 @@ local M = {}

local function add_handler(handlers, handler, active)
if
not active
active == false
or not helper.check_filetype(handler.filetype)
or not helper.check_filename(handler.filename)
then
return
end
table.insert(handlers, handler)
handlers[#handlers + 1] = handler
end

-- handler function
function M.get_url(mode, line, activated_handlers, handler_options)
local url
local handlers = {}
local tkeys = {}
---@param handlers { [string]: (boolean | GxHandler)[] }
---@return GxHandler[]
local function resolve_handlers(handlers)
local resolved = {}
local exists = {}

for name, config in pairs(handlers) do
if type(config) == "table" then
add_handler(resolved, config, true)
exists[name] = true
end
end

-- ### add here new handlers
add_handler(handlers, brewfile_handler, activated_handlers.brewfile)
add_handler(handlers, package_json_handler, activated_handlers.package_json)
add_handler(handlers, plugin_handler, activated_handlers.plugin)
add_handler(handlers, github_handler, activated_handlers.github)
add_handler(handlers, commit_handler, activated_handlers.github)
add_handler(handlers, markdown_handler, true)
add_handler(handlers, url_handler, true)
add_handler(handlers, search_handler, activated_handlers.search)
add_handler(resolved, brewfile_handler, handlers.brewfile and exists.brewfile == nil)
add_handler(resolved, package_json_handler, handlers.package_json and exists.package_json == nil)
add_handler(resolved, plugin_handler, handlers.plugin and exists.plugin == nil)
add_handler(resolved, github_handler, handlers.github and exists.github == nil)
add_handler(resolved, commit_handler, handlers.commit and exists.commit == nil)
add_handler(resolved, markdown_handler, handlers.markdown and exists.markdown == nil)
add_handler(resolved, url_handler, handlers.url and exists.url == nil)
add_handler(resolved, search_handler, handlers.search and exists.search == nil)
-- ###

for k in pairs(handlers) do
table.insert(tkeys, k)
end
table.sort(tkeys)
return resolved
end

-- handler function
---@param mode string
---@param line string
---@param configured_handlers { [string]: (boolean | GxHandler)[] }
---@return string | nil
function M.get_url(mode, line, configured_handlers, handler_options)
local handlers = resolve_handlers(configured_handlers)

for _, k in ipairs(tkeys) do
url = handlers[k].handle(mode, line, handler_options)
for _, handler in ipairs(handlers) do
local url = handler.handle(mode, line, handler_options)

if url then
break
return url
end
end

return url
end

return M
30 changes: 17 additions & 13 deletions lua/gx/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ local sysname = vim.loop.os_uname().sysname

local M = {}

---@class GxHandlerOptions
---@field search_engine string

---@class GxHandler
---@field filetypes string[] | nil
---@field filename string | nil
---@field handle fun(mode: string, line: string, handler_options: GxHandlerOptions | nil)

---@class GxOptions
---@field open_browser_app string
---@field open_browser_args string[]
---@field handlers (boolean | GxHandler)[]
---@field handler_options GxHandlerOptions | nil

-- search for url with handler
function M.open(mode, line)
if not line then
Expand Down Expand Up @@ -52,23 +66,12 @@ end

local function with_defaults(options)
options = options or {}
options.handlers = options.handlers or {}
options.handler_options = options.handler_options or {}

return {
open_browser_app = options.open_browser_app or get_open_browser_app(),
open_browser_args = get_open_browser_args(options.open_browser_args or {}),
handlers = {
brewfile = helper.ternary(options.handlers.brewfile ~= nil, options.handlers.brewfile, true),
plugin = helper.ternary(options.handlers.plugin ~= nil, options.handlers.plugin, true),
github = helper.ternary(options.handlers.github ~= nil, options.handlers.github, true),
package_json = helper.ternary(
options.handlers.package_json ~= nil,
options.handlers.package_json,
true
),
search = helper.ternary(options.handlers.search ~= nil, options.handlers.search, true),
},
handlers = options.handlers or {},
handler_options = {
search_engine = options.handler_options.search_engine or "google",
},
Expand All @@ -93,12 +96,13 @@ local function bind_command()
end, { nargs = "?", range = 1 })
end

-- setup function
---@param options GxOptions
function M.setup(options)
M.options = with_defaults(options)
bind_command()
end

---@type GxOptions
M.options = nil

return M
41 changes: 33 additions & 8 deletions test/spec/gx/handler_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ local handler = require("gx.handler")
local stub = require("luassert.stub")

describe("test handler", function()
local activated_handlers = {
plugin = false,
github = false,
package_json = false,
}
local activated_handlers

before_each(function()
before_mock_filetype = vim.bo.filetype
activated_handlers = {
plugin = false,
github = false,
package_json = false,
search = false,
}
end)

after_each(function()
Expand All @@ -26,8 +28,8 @@ describe("test handler", function()
"https://github.com",
handler.get_url("v", "https://github.com", activated_handlers)
)
assert.equals(nil, handler.get_url("v", '"example_user/example_plugin"', activated_handlers))
assert.equals(nil, handler.get_url("v", "Fixes #22", activated_handlers))
assert.is.Nil(handler.get_url("v", '"example_user/example_plugin"', activated_handlers))
assert.is.Nil(handler.get_url("v", "Fixes #22", activated_handlers))
end)

it("plugin handler on", function()
Expand All @@ -48,6 +50,7 @@ describe("test handler", function()
end)

it("plugin handler on and filetype vim", function()
activated_handlers.plugin = true
activated_handlers.github = true

-- mock filetype
Expand Down Expand Up @@ -75,7 +78,7 @@ describe("test handler", function()
"https://github.com",
handler.get_url("v", "https://github.com", activated_handlers)
)
assert.equals(nil, handler.get_url("v", '"example_user/example_plugin"', activated_handlers))
assert.is.Nil(handler.get_url("v", '"example_user/example_plugin"', activated_handlers))
end)

it("github handler on", function()
Expand Down Expand Up @@ -111,4 +114,26 @@ describe("test handler", function()

helper.get_filename:revert()
end)

it("user defined handler has precedence", function()
activated_handlers.commit = true
activated_handlers.custom = {
handle = function()
return "https://from.user.handler"
end,
}

assert.equals("https://from.user.handler", handler.get_url("v", "1a2b3c4", activated_handlers))
end)

it("user defined handler instead of builtin handler", function()
activated_handlers.commit = true
activated_handlers.commit = {
handle = function()
return "https://from.user.handler"
end,
}

assert.equals("https://from.user.handler", handler.get_url("v", "1a2b3c4", activated_handlers))
end)
end)

0 comments on commit 32963dc

Please sign in to comment.