-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
2,855 additions
and
1,452 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"neodev": { | ||
"library": { | ||
"plugins": [ | ||
"plenary.nvim", | ||
"nvim-web-devicons" | ||
] | ||
} | ||
}, | ||
"lspconfig": { | ||
"lua_ls": { | ||
"Lua.runtime.version": "LuaJIT", | ||
"Lua.workspace.checkThirdParty": false | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
local M = {} | ||
|
||
M.budget = 1 | ||
local Scheduler = {} | ||
Scheduler._queue = {} | ||
Scheduler._executor = assert(vim.loop.new_check()) | ||
|
||
function Scheduler.step() | ||
local budget = M.budget * 1e6 | ||
local start = vim.loop.hrtime() | ||
while #Scheduler._queue > 0 and vim.loop.hrtime() - start < budget do | ||
local a = table.remove(Scheduler._queue, 1) | ||
a:_step() | ||
if a.running then | ||
table.insert(Scheduler._queue, a) | ||
end | ||
end | ||
if #Scheduler._queue == 0 then | ||
return Scheduler._executor:stop() | ||
end | ||
end | ||
|
||
---@param a Async | ||
function Scheduler.add(a) | ||
table.insert(Scheduler._queue, a) | ||
if not Scheduler._executor:is_active() then | ||
Scheduler._executor:start(vim.schedule_wrap(Scheduler.step)) | ||
end | ||
end | ||
|
||
--- @alias AsyncCallback fun(result?:any, error?:string) | ||
|
||
--- @class Async | ||
--- @field running boolean | ||
--- @field result? any | ||
--- @field error? string | ||
--- @field callbacks AsyncCallback[] | ||
--- @field thread thread | ||
local Async = {} | ||
Async.__index = Async | ||
|
||
function Async.new(fn) | ||
local self = setmetatable({}, Async) | ||
self.callbacks = {} | ||
self.running = true | ||
self.thread = coroutine.create(fn) | ||
Scheduler.add(self) | ||
return self | ||
end | ||
|
||
---@param result? any | ||
---@param error? string | ||
function Async:_done(result, error) | ||
if self.running then | ||
self.running = false | ||
self.result = result | ||
self.error = error | ||
end | ||
for _, callback in ipairs(self.callbacks) do | ||
callback(result, error) | ||
end | ||
-- only run each callback once. | ||
-- _done can possibly be called multiple times. | ||
-- so we need to clear callbacks after executing them. | ||
self.callbacks = {} | ||
end | ||
|
||
function Async:_step() | ||
local ok, res = coroutine.resume(self.thread) | ||
if not ok then | ||
return self:_done(nil, res) | ||
elseif res == "abort" then | ||
return self:_done(nil, "abort") | ||
elseif coroutine.status(self.thread) == "dead" then | ||
return self:_done(res) | ||
end | ||
end | ||
|
||
function Async:cancel() | ||
self:_done(nil, "abort") | ||
end | ||
|
||
---@param cb AsyncCallback | ||
function Async:await(cb) | ||
if not cb then | ||
error("callback is required") | ||
end | ||
if self.running then | ||
table.insert(self.callbacks, cb) | ||
else | ||
cb(self.result, self.error) | ||
end | ||
end | ||
|
||
function Async:sync() | ||
while self.running do | ||
vim.wait(10) | ||
end | ||
return self.error and error(self.error) or self.result | ||
end | ||
|
||
--- @return boolean | ||
function M.is_async(obj) | ||
return obj and type(obj) == "table" and getmetatable(obj) == Async | ||
end | ||
|
||
---@generic F | ||
---@param fn F | ||
---@return F|fun(...): Async | ||
function M.wrap(fn) | ||
return function(...) | ||
local args = { ... } | ||
return Async.new(function() | ||
return fn(unpack(args)) | ||
end) | ||
end | ||
end | ||
|
||
-- This will yield when called from a coroutine | ||
---@async | ||
function M.yield(...) | ||
if coroutine.running() == nil then | ||
error("Trying to yield from a non-yieldable context") | ||
return ... | ||
end | ||
return coroutine.yield(...) | ||
end | ||
|
||
---@async | ||
function M.abort() | ||
return M.yield("abort") | ||
end | ||
|
||
return M |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
---@class trouble.CacheM: {[string]: trouble.Cache} | ||
local M = {} | ||
|
||
---@type table<string, {name:string, hit: number, miss: number, ratio?:number}> | ||
M.stats = {} | ||
|
||
---@class trouble.Cache: {[string]: any} | ||
---@field data table<string, any> | ||
---@field name string | ||
local C = {} | ||
|
||
function C:__index(key) | ||
local ret = C[key] | ||
if ret then | ||
return ret | ||
end | ||
ret = self.data[key] | ||
M.stats[self.name] = M.stats[self.name] or { name = self.name, hit = 0, miss = 0 } | ||
local stats = M.stats[self.name] | ||
if ret ~= nil then | ||
stats.hit = stats.hit + 1 | ||
else | ||
stats.miss = stats.miss + 1 | ||
end | ||
return ret | ||
end | ||
|
||
function C:__newindex(key, value) | ||
self.data[key] = value | ||
end | ||
|
||
function C:clear() | ||
self.data = {} | ||
end | ||
|
||
function M.new(name) | ||
return setmetatable({ data = {}, name = name }, C) | ||
end | ||
|
||
function M.report() | ||
for _, v in pairs(M.stats) do | ||
v.ratio = math.ceil(v.hit / (v.hit + v.miss) * 100) | ||
end | ||
return M.stats | ||
end | ||
|
||
function M.__index(_, k) | ||
M[k] = M.new(k) | ||
return M[k] | ||
end | ||
|
||
local ret = setmetatable(M, M) | ||
return ret |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
local Config = require("trouble.config") | ||
local Util = require("trouble.util") | ||
|
||
local M = {} | ||
|
||
---@param input string | ||
function M.parse(input) | ||
local source, args = input:match("%s*(%S+)%s*(.*)$") | ||
if not source then | ||
Util.error("Invalid arguments: " .. input) | ||
return | ||
end | ||
local parts = vim.split(args, "%s+") | ||
---@type trouble.Config | ||
local opts = {} | ||
|
||
for _, part in ipairs(parts) do | ||
local key, value = part:match("([^=]+)=(.*)") | ||
if not key then | ||
key = part | ||
value = true | ||
elseif value == "true" then | ||
value = true | ||
elseif value == "false" then | ||
value = false | ||
elseif tonumber(value) then | ||
value = tonumber(value) | ||
end | ||
-- remove quotes | ||
if type(value) == "string" then | ||
---@diagnostic disable-next-line: no-unknown | ||
value = value:gsub("^['\"]", ""):gsub("['\"]$", "") | ||
end | ||
---@diagnostic disable-next-line: no-unknown | ||
opts[key] = value | ||
end | ||
return source, opts | ||
end | ||
|
||
---@param line string | ||
---@param col number | ||
function M.complete(_, line, col) | ||
line = line:sub(1, col) | ||
local candidates = {} ---@type string[] | ||
local prefix = "" | ||
local source = line:match("Trouble%s+(%S*)$") | ||
if source then | ||
prefix = source | ||
candidates = Config.modes() | ||
else | ||
local args = line:match("Trouble%s+%S+%s*.*%s+(%S*)$") | ||
if args then | ||
prefix = args | ||
candidates = vim.tbl_keys(Config.get()) | ||
candidates = vim.tbl_map(function(x) | ||
return x .. "=" | ||
end, candidates) | ||
end | ||
end | ||
|
||
candidates = vim.tbl_filter(function(x) | ||
return tostring(x):find(prefix, 1, true) ~= nil | ||
end, candidates) | ||
table.sort(candidates) | ||
return candidates | ||
end | ||
|
||
function M.execute(input) | ||
local mode, opts = M.parse(input.args) | ||
if mode and opts then | ||
opts.mode = mode | ||
require("trouble").open(opts) | ||
end | ||
end | ||
|
||
return M |
Oops, something went wrong.