Skip to content
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ cppman.nvim adds a few mappings on top:
* `K` on a table-of-contents entry: jump to that section
* `<C-T>` or right-click: go back to the previous cppman page/search
* `<Tab>`: go forward again after going back
* `<M-m>`: toggle between the configured size and a maximized view
* `q`: close the viewer

Visual mode works too:
Expand Down
1 change: 1 addition & 0 deletions doc/cppman.txt
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ cppman.nvim adds a few mappings on top:
- `K` on a table-of-contents entry: jump to that section
- `<C-T>` or right-click: go back to the previous cppman page/search
- `<Tab>`: go forward again after going back
- `<M-m>`: toggle between the configured size and a maximized view
- `q`: close the viewer

Visual mode works too:
Expand Down
7 changes: 6 additions & 1 deletion lua/cppman/health.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ function M.check()
end

local fzf_status = statuses["fzf-lua"]
if fzf_status and fzf_status.available and vim.fn.executable("fzf") == 0 and not picker_opts.fzf_lua.fzf_bin then
if
fzf_status
and fzf_status.available
and vim.fn.executable("fzf") == 0
and not (picker_opts.fzf_lua or {}).fzf_bin
then
h.warn("fzf executable not found", { "Install fzf, or configure fzf-lua to use another fzf-compatible binary" })
end

Expand Down
32 changes: 14 additions & 18 deletions lua/cppman/index.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
local M = {}

local uv = vim.uv or vim.loop
local SOURCE_PRIORITY = { "cppreference.com", "cplusplus.com" }
local VALID_SOURCES = { ["cppreference.com"] = true, ["cplusplus.com"] = true, ["both"] = true }

local _cache = {}
local _exact_map = {}
local _db_path = nil

M.last_load_ms = nil

local function now_ms()
return uv.hrtime() / 1e6
end

local function validate_source(source)
if not VALID_SOURCES[source] then
error(
Expand Down Expand Up @@ -197,7 +190,12 @@ local function run_sqlite(db_path, query, separator)
end
args[#args + 1] = db_path
args[#args + 1] = query
local res = vim.system(args, { text = true }):wait()
local ok, res = pcall(function()
return vim.system(args, { text = true }):wait()
end)
if not ok then
return nil, "failed to run sqlite3: " .. tostring(res)
end
if res.code ~= 0 then
return nil, (res.stderr ~= "" and res.stderr) or "sqlite3 exited " .. res.code
end
Expand Down Expand Up @@ -227,12 +225,14 @@ local function cppman_base_dir()
return _cppman_base_dir
end
_cppman_base_dir_resolved = true
local res = vim.system(
{ "python3", "-c", "import cppman, os; print(os.path.dirname(cppman.__file__))" },
{ text = true }
)
:wait()
if res.code == 0 then
local ok, res = pcall(function()
return vim.system(
{ "python3", "-c", "import cppman, os; print(os.path.dirname(cppman.__file__))" },
{ text = true }
)
:wait()
end)
if ok and res.code == 0 then
local base = vim.trim(res.stdout or "")
if base ~= "" then
_cppman_base_dir = base
Expand Down Expand Up @@ -412,11 +412,9 @@ function M.load(source)
source = get_source_mode(source)

if _cache[source] then
M.last_load_ms = nil
return _cache[source]
end

local t0 = now_ms()
if source == "both" then
local items = {}
local exact_map = {}
Expand Down Expand Up @@ -444,7 +442,6 @@ function M.load(source)
load_single_source(source)
end

M.last_load_ms = now_ms() - t0
return _cache[source] or {}
end

Expand All @@ -469,7 +466,6 @@ function M.reset()
_cppman_paths = nil
_cppman_base_dir = nil
_cppman_base_dir_resolved = false
M.last_load_ms = nil
end

return M
15 changes: 3 additions & 12 deletions lua/cppman/picker.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local M = {}

local uv = vim.uv or vim.loop
local util = require("cppman.util")

local AUTO_ORDER = { "snacks", "fzf-lua" }
local PROVIDERS = {
Expand All @@ -14,12 +14,6 @@ local PROVIDERS = {
},
}

M.last_pattern = ""

local function now_ms()
return uv.hrtime() / 1e6
end

local function picker_options()
local config = require("cppman.config")
return config.options.picker or {}
Expand Down Expand Up @@ -137,9 +131,9 @@ function M.open(opts)
local source = opts.source or config.options.source or "both"

local index = require("cppman.index")
local t0 = now_ms()
local t0 = util.now_ms()
local items = index.load(source)
local load_ms = now_ms() - t0
local load_ms = util.now_ms() - t0
if #items == 0 then
vim.notify("[cppman] no items loaded - check cppman and sqlite3 installation", vim.log.levels.ERROR)
return
Expand All @@ -151,9 +145,6 @@ function M.open(opts)
source = source,
items = items,
load_ms = load_ms,
set_last_pattern = function(pattern)
M.last_pattern = pattern or ""
end,
}))
end

Expand Down
11 changes: 3 additions & 8 deletions lua/cppman/pickers/common.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
local M = {}

local NBSP = vim.fn.nr2char(160)
local util = require("cppman.util")

function M.format_timing(elapsed)
if elapsed < 10 then
return string.format("%.1fms", elapsed)
end
return string.format("%dms", math.floor(elapsed + 0.5))
end
local NBSP = vim.fn.nr2char(160)

function M.source_badge(source)
if source == "cppreference.com" then
Expand All @@ -29,7 +24,7 @@ end
function M.search_title(load_ms)
return {
{ "keyword", "Title" },
{ NBSP .. "search • " .. M.format_timing(load_ms), "Comment" },
{ NBSP .. "search • " .. util.format_ms(load_ms), "Comment" },
{ " ", "FloatTitle" },
}
end
Expand Down
6 changes: 2 additions & 4 deletions lua/cppman/pickers/fzf_lua.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local M = {}

local common = require("cppman.pickers.common")
local util = require("cppman.util")

function M.is_available()
local ok, FzfLua = pcall(require, "fzf-lua")
Expand Down Expand Up @@ -68,9 +69,6 @@ function M.open(opts)
end

local used_pattern = last_query(FzfLua, pattern)
if opts.set_last_pattern then
opts.set_last_pattern(used_pattern)
end
if on_select then
on_select(item, used_pattern)
end
Expand Down Expand Up @@ -99,7 +97,7 @@ function M.open(opts)
winopts = {
backdrop = 100,
border = "rounded",
title = " keyword search - " .. common.format_timing(opts.load_ms or 0) .. " ",
title = " keyword search - " .. util.format_ms(opts.load_ms or 0) .. " ",
title_pos = "center",
width = picker_opts.width or 0.4,
height = picker_opts.height or 0.4,
Expand Down
3 changes: 0 additions & 3 deletions lua/cppman/pickers/snacks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ function M.open(opts)
return picker.input.filter.pattern
end)
local used_pattern = (ok_pattern and current) or pattern
if opts.set_last_pattern then
opts.set_last_pattern(used_pattern)
end
picker:close()
if on_select then
on_select(item, used_pattern)
Expand Down
60 changes: 32 additions & 28 deletions lua/cppman/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
-- never re-spawn cppman. Owns no window state — viewer.lua handles UI.
local M = {}

local uv = vim.uv or vim.loop
local util = require("cppman.util")
local index = require("cppman.index")

local plugin_cache_dir = vim.fn.stdpath("cache") .. "/cppman_plugin"
Expand Down Expand Up @@ -41,10 +41,6 @@ local resolve_cache = new_lru()
resolve_cache.max = RESOLVE_CACHE_MAX
local _pager_script = nil

local function now_ms()
return uv.hrtime() / 1e6
end

local function get_source(source)
return index.get_sources(source)[1]
end
Expand Down Expand Up @@ -84,14 +80,20 @@ local function cppman_args(extra)
end

local function run_cppman(source, args, stdin)
return vim.system(args, {
env = {
XDG_CACHE_HOME = plugin_cache_dir,
XDG_CONFIG_HOME = get_config_dir(get_source(source)),
},
stdin = stdin,
text = true,
}):wait()
local ok, res = pcall(function()
return vim.system(args, {
env = {
XDG_CACHE_HOME = plugin_cache_dir,
XDG_CONFIG_HOME = get_config_dir(get_source(source)),
},
stdin = stdin,
text = true,
}):wait()
end)
if not ok then
return { code = -1, stdout = "", stderr = tostring(res) }
end
return res
end

local function normalize_page_name(name)
Expand Down Expand Up @@ -141,8 +143,10 @@ local function render_cached_page(page_path, width, page)
if not pager_script then
return nil
end
local res = vim.system({ pager_script, "pipe", page_path, tostring(width), "", page }, { text = true }):wait()
if res.code ~= 0 or not res.stdout or res.stdout == "" then
local ok, res = pcall(function()
return vim.system({ pager_script, "pipe", page_path, tostring(width), "", page }, { text = true }):wait()
end)
if not ok or res.code ~= 0 or not res.stdout or res.stdout == "" then
return nil
end
return res.stdout
Expand Down Expand Up @@ -194,8 +198,7 @@ function M.render_page(page, query, width, source)
return cached or nil, nil
end

local t0 = now_ms()
local external_t0 = now_ms()
local t0 = util.now_ms()

local stdout = nil
local page_path = get_cached_page_path(page, source)
Expand All @@ -208,16 +211,16 @@ function M.render_page(page, query, width, source)
if res.code ~= 0 or not res.stdout or res.stdout == "" then
lru_set(page_cache, key, false)
return nil, {
cppman_ms = now_ms() - external_t0,
cppman_ms = util.now_ms() - t0,
our_ms = 0,
total_ms = now_ms() - t0,
total_ms = util.now_ms() - t0,
}
end
stdout = res.stdout
end

local cppman_ms = now_ms() - external_t0
local internal_t0 = now_ms()
local cppman_ms = util.now_ms() - t0
local internal_t0 = util.now_ms()

local lines = vim.split(stdout, "\n", { plain = true })
if lines[#lines] == "" then
Expand All @@ -228,19 +231,20 @@ function M.render_page(page, query, width, source)

if #lines == 0 then
lru_set(page_cache, key, false)
return nil, {
cppman_ms = cppman_ms,
our_ms = now_ms() - internal_t0,
total_ms = now_ms() - t0,
}
return nil,
{
cppman_ms = cppman_ms,
our_ms = util.now_ms() - internal_t0,
total_ms = util.now_ms() - t0,
}
end

local our_ms = now_ms() - internal_t0
local our_ms = util.now_ms() - internal_t0
lru_set(page_cache, key, lines)
return lines, {
cppman_ms = cppman_ms,
our_ms = our_ms,
total_ms = now_ms() - t0,
total_ms = util.now_ms() - t0,
}
end

Expand Down
22 changes: 22 additions & 0 deletions lua/cppman/util.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- Small shared helpers with no plugin state.
local M = {}

local uv = vim.uv or vim.loop

function M.now_ms()
return uv.hrtime() / 1e6
end

-- Format an elapsed-milliseconds value for display.
-- nil means "no measurement" (e.g. an in-memory cache hit).
function M.format_ms(elapsed)
if elapsed == nil then
return "cached"
end
if elapsed < 10 then
return string.format("%.1fms", elapsed)
end
return string.format("%dms", math.floor(elapsed + 0.5))
end

return M
Loading
Loading