mirror of
https://github.com/boxpositron/absolute-vim.git
synced 2026-02-28 03:30:36 +00:00
feat(lua): add utility functions to detect Lua, OS, Python environment, TypeScript environment, Git root, and safe function invocation.
This commit is contained in:
39
lua/absolute/utils/detect-lua.lua
Normal file
39
lua/absolute/utils/detect-lua.lua
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
function GetLuaPath(version)
|
||||||
|
local path = vim.fn.expand("$HOME") .. "/.luarocks/share/lua/" .. version .. "/?.lua;"
|
||||||
|
path = path .. vim.fn.expand("$HOME") .. "/.luarocks/share/lua/" .. version .. "/?/init.lua;"
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetInstalledLuaVersion()
|
||||||
|
-- List the directory contents of the lua rocks directory
|
||||||
|
local rocks = vim.fn.glob(vim.fn.expand("$HOME") .. "/.luarocks/share/lua/")
|
||||||
|
|
||||||
|
-- Split the string into a table
|
||||||
|
|
||||||
|
rocks = vim.split(rocks, "\n")
|
||||||
|
|
||||||
|
-- Sort the table highest to lowest
|
||||||
|
|
||||||
|
table.sort(rocks, function(a, b)
|
||||||
|
return tonumber(a) > tonumber(b)
|
||||||
|
end)
|
||||||
|
|
||||||
|
return rocks
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetLatestLuaVersion()
|
||||||
|
local rocks = GetInstalledLuaVersion()
|
||||||
|
local preferredVersion = rocks[1]
|
||||||
|
|
||||||
|
local path = GetLuaPath(preferredVersion)
|
||||||
|
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
M = {}
|
||||||
|
|
||||||
|
M.GetLuaPath = GetLuaPath
|
||||||
|
M.GetInstalledLuaVersion = GetInstalledLuaVersion
|
||||||
|
M.GetLatestLuaVersion = GetLatestLuaVersion
|
||||||
|
|
||||||
|
return M
|
||||||
43
lua/absolute/utils/detect-os.lua
Normal file
43
lua/absolute/utils/detect-os.lua
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
SUPPORTED_OS = {
|
||||||
|
WINDOWS = "Windows",
|
||||||
|
UNIX = "Unix",
|
||||||
|
MACOS = "macOS",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function isMacOS()
|
||||||
|
-- Try to execute `sw_vers` command which is specific to macOS
|
||||||
|
local result = os.execute("sw_vers > /dev/null 2>&1")
|
||||||
|
|
||||||
|
-- `os.execute` returns true on success for Lua versions 5.2 and above
|
||||||
|
-- For Lua 5.1 and below, it returns the exit code of the command. On success, it should be zero.
|
||||||
|
-- Adjust the check if you're using Lua 5.1 or below:
|
||||||
|
-- if result == 0 then
|
||||||
|
if result then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function detectOS()
|
||||||
|
if os.getenv("OS") ~= nil then
|
||||||
|
return os.getenv("OS") -- This can be useful in Windows environments
|
||||||
|
elseif os.getenv("PATH"):find(";") then
|
||||||
|
return SUPPORTED_OS.WINDOWS
|
||||||
|
else
|
||||||
|
local is_macos = isMacOS()
|
||||||
|
|
||||||
|
if is_macos then
|
||||||
|
return SUPPORTED_OS.MACOS
|
||||||
|
else
|
||||||
|
return SUPPORTED_OS.UNIX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
M = {}
|
||||||
|
|
||||||
|
M.detect = detectOS
|
||||||
|
M.supported = SUPPORTED_OS
|
||||||
|
|
||||||
|
return M
|
||||||
47
lua/absolute/utils/detect-python-env.lua
Normal file
47
lua/absolute/utils/detect-python-env.lua
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
function CheckPoetryVirtualEnv()
|
||||||
|
local poetry = vim.fn.system("poetry env info -p 2>/dev/null")
|
||||||
|
if poetry == "" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return poetry
|
||||||
|
end
|
||||||
|
|
||||||
|
function ResolvePythonEnvironment()
|
||||||
|
-- Check if asdf is installed
|
||||||
|
|
||||||
|
-- Get system global python env
|
||||||
|
local python = vim.fn.system("which python3")
|
||||||
|
-- Check of virtual environments exists
|
||||||
|
local virtual = os.getenv("VIRTUAL_ENV") or CheckPoetryVirtualEnv()
|
||||||
|
|
||||||
|
if virtual == nil then
|
||||||
|
return {
|
||||||
|
"--python-executable",
|
||||||
|
python,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
"--python-executable",
|
||||||
|
virtual .. "/bin/python",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ResolvePythonEnvironmentAsString()
|
||||||
|
local env = ResolvePythonEnvironment()
|
||||||
|
if env == nil then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local path = table.concat(env, " ")
|
||||||
|
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
M = {}
|
||||||
|
|
||||||
|
M.ResolvePythonEnvironmentAsString = ResolvePythonEnvironmentAsString
|
||||||
|
M.ResolvePythonEnvironment = ResolvePythonEnvironment
|
||||||
|
M.CheckPoetryVirtualEnv = CheckPoetryVirtualEnv
|
||||||
|
|
||||||
|
return M
|
||||||
67
lua/absolute/utils/detect-typescript-env.lua
Normal file
67
lua/absolute/utils/detect-typescript-env.lua
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
M = {}
|
||||||
|
local function trim(s)
|
||||||
|
return s:gsub("^%s*(.-)%s*$", "%1")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ResolveTypescriptServer = function()
|
||||||
|
-- Find the package.json file
|
||||||
|
local viable = vim.fn.system("find . -name 'package.json' -maxdepth 3 | xargs dirname")
|
||||||
|
viable = trim(viable)
|
||||||
|
|
||||||
|
if viable == "" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for lock files
|
||||||
|
local find_npm_result = trim(vim.fn.system("find . -name 'package-lock.json' -maxdepth 3 | wc -l"))
|
||||||
|
local find_pnpm_result = trim(vim.fn.system("find . -name 'pnpm-lock.yaml' -maxdepth 3 | wc -l"))
|
||||||
|
local find_yarn_result = trim(vim.fn.system("find . -name 'yarn.lock' -maxdepth 3 | wc -l"))
|
||||||
|
|
||||||
|
local is_npm = find_npm_result == "1"
|
||||||
|
local is_pnpm = find_pnpm_result == "1"
|
||||||
|
local is_yarn = find_yarn_result == "1"
|
||||||
|
|
||||||
|
-- if no package lock files are found, end early
|
||||||
|
if not is_npm and not is_pnpm and not is_yarn then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Determine the preferred package manager
|
||||||
|
local ppm = "pnpm" -- Default to pnpm
|
||||||
|
if is_npm then
|
||||||
|
ppm = "npm"
|
||||||
|
end
|
||||||
|
if is_yarn then
|
||||||
|
ppm = "yarn"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resolve TypeScript server path
|
||||||
|
local base_command = ppm .. " list typescript --dir " .. viable .. " --json"
|
||||||
|
local base_result = trim(vim.fn.system(base_command))
|
||||||
|
|
||||||
|
if base_result == "" then
|
||||||
|
vim.notify("Failed to run " .. base_command, vim.log.levels.ERROR)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local typescript_path = nil
|
||||||
|
|
||||||
|
if ppm == "pnpm" or ppm == "npm" or ppm == "yarn" then
|
||||||
|
local ok, parsed = pcall(vim.fn.json_decode, base_result)
|
||||||
|
if ok and parsed and #parsed > 0 and parsed[1].path then
|
||||||
|
typescript_path = parsed[1].path .. "/node_modules/typescript/lib"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not typescript_path or typescript_path == "" then
|
||||||
|
vim.notify("TypeScript not found. Please install TypeScript globally or in the project.", vim.log.levels.ERROR)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return typescript_path
|
||||||
|
end
|
||||||
|
|
||||||
|
M.ResolveTypescriptServer = ResolveTypescriptServer
|
||||||
|
M.trim = trim
|
||||||
|
|
||||||
|
return M
|
||||||
10
lua/absolute/utils/get-git-root.lua
Normal file
10
lua/absolute/utils/get-git-root.lua
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
function GetProjectRoot()
|
||||||
|
local git_root = vim.fn.systemlist("git rev-parse --show-toplevel")[1]
|
||||||
|
if git_root == nil then
|
||||||
|
return vim.fn.getcwd()
|
||||||
|
else
|
||||||
|
return git_root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return GetProjectRoot
|
||||||
15
lua/absolute/utils/safe-invoke.lua
Normal file
15
lua/absolute/utils/safe-invoke.lua
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
function SafeInvoke(func)
|
||||||
|
-- safely invoke a functions
|
||||||
|
-- if the function returns an error, return an empty string
|
||||||
|
-- otherwise return the result of the function
|
||||||
|
|
||||||
|
local ok, result = pcall(func)
|
||||||
|
|
||||||
|
if ok then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return SafeInvoke
|
||||||
127
lua/absolute/utils/telescope_image_preview.lua
Normal file
127
lua/absolute/utils/telescope_image_preview.lua
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
-- Sourced from github
|
||||||
|
-- https://github.com/3rd/image.nvim/issues/183#issuecomment-2572606511
|
||||||
|
|
||||||
|
M = {}
|
||||||
|
|
||||||
|
local supported_images = { "svg", "png", "jpg", "jpeg", "gif", "webp", "avif" }
|
||||||
|
local from_entry = require("telescope.from_entry")
|
||||||
|
local Path = require("plenary.path")
|
||||||
|
local conf = require("telescope.config").values
|
||||||
|
local Previewers = require("telescope.previewers")
|
||||||
|
|
||||||
|
local previewers = require("telescope.previewers")
|
||||||
|
local image_api = require("image")
|
||||||
|
|
||||||
|
local is_image_preview = false
|
||||||
|
local image = nil
|
||||||
|
local last_file_path = ""
|
||||||
|
|
||||||
|
local is_supported_image = function(filepath)
|
||||||
|
local split_path = vim.split(filepath:lower(), ".", { plain = true })
|
||||||
|
local extension = split_path[#split_path]
|
||||||
|
return vim.tbl_contains(supported_images, extension)
|
||||||
|
end
|
||||||
|
|
||||||
|
local delete_image = function()
|
||||||
|
if not image then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
image:clear()
|
||||||
|
|
||||||
|
is_image_preview = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local create_image = function(filepath, winid, bufnr)
|
||||||
|
image = image_api.hijack_buffer(filepath, winid, bufnr)
|
||||||
|
|
||||||
|
if not image then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.schedule(function()
|
||||||
|
image:render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
is_image_preview = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function defaulter(f, default_opts)
|
||||||
|
default_opts = default_opts or {}
|
||||||
|
return {
|
||||||
|
new = function(opts)
|
||||||
|
if conf.preview == false and not opts.preview then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
opts.preview = type(opts.preview) ~= "table" and {} or opts.preview
|
||||||
|
if type(conf.preview) == "table" then
|
||||||
|
for k, v in pairs(conf.preview) do
|
||||||
|
opts.preview[k] = vim.F.if_nil(opts.preview[k], v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return f(opts)
|
||||||
|
end,
|
||||||
|
__call = function()
|
||||||
|
local ok, err = pcall(f(default_opts))
|
||||||
|
if not ok then
|
||||||
|
error(debug.traceback(err))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE: Add teardown to cat previewer to clear image when close Telescope
|
||||||
|
local file_previewer = defaulter(function(opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local cwd = opts.cwd or vim.fn.getcwd()
|
||||||
|
return Previewers.new_buffer_previewer({
|
||||||
|
title = "File Preview",
|
||||||
|
dyn_title = function(_, entry)
|
||||||
|
return Path:new(from_entry.path(entry, true)):normalize(cwd)
|
||||||
|
end,
|
||||||
|
|
||||||
|
get_buffer_by_name = function(_, entry)
|
||||||
|
return from_entry.path(entry, true)
|
||||||
|
end,
|
||||||
|
|
||||||
|
define_preview = function(self, entry, _)
|
||||||
|
local p = from_entry.path(entry, true)
|
||||||
|
if p == nil or p == "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
conf.buffer_previewer_maker(p, self.state.bufnr, {
|
||||||
|
bufname = self.state.bufname,
|
||||||
|
winid = self.state.winid,
|
||||||
|
preview = opts.preview,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
|
||||||
|
teardown = function(_)
|
||||||
|
if is_image_preview then
|
||||||
|
delete_image()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end, {})
|
||||||
|
|
||||||
|
local buffer_previewer_maker = function(filepath, bufnr, opts)
|
||||||
|
-- NOTE: Clear image when preview other file
|
||||||
|
if is_image_preview and last_file_path ~= filepath then
|
||||||
|
delete_image()
|
||||||
|
end
|
||||||
|
|
||||||
|
last_file_path = filepath
|
||||||
|
|
||||||
|
if is_supported_image(filepath) then
|
||||||
|
filepath = string.gsub(filepath, " ", "%%20"):gsub("\\", "")
|
||||||
|
create_image(filepath, opts.winid, bufnr)
|
||||||
|
else
|
||||||
|
previewers.buffer_previewer_maker(filepath, bufnr, opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
M.buffer_previewer_maker = buffer_previewer_maker
|
||||||
|
M.file_previewer = file_previewer.new
|
||||||
|
|
||||||
|
return M
|
||||||
Reference in New Issue
Block a user