chore: drop macOS/Windows support and offline nvim tooling
- Remove macOS/Windows clipboard branches, homebrew fzf path from .vimrc - Remove is_macos/is_windows logic from wezterm.lua - Drop scripts/nvim-offline-* and NVIM_OFFLINE plumbing from nvim config - Clean macOS section from .gitignore; simplify .gitattributes to LF-only - Trim README of offline-bundle section
This commit is contained in:
parent
21c315d5f2
commit
84fbb30d82
12 changed files with 20 additions and 728 deletions
|
|
@ -166,13 +166,7 @@ set background=dark
|
||||||
" hi VertSplit guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE
|
" hi VertSplit guibg=NONE guifg=NONE ctermbg=NONE ctermfg=NONE
|
||||||
|
|
||||||
" Sync clipboard with OS
|
" Sync clipboard with OS
|
||||||
if has('win32') || has('win64')
|
set clipboard=unnamedplus
|
||||||
set clipboard=unnamedplus " Windows
|
|
||||||
elseif has('macunix')
|
|
||||||
set clipboard=unnamed " macOS
|
|
||||||
else
|
|
||||||
set clipboard=unnamedplus " Linux/WSL
|
|
||||||
endif
|
|
||||||
|
|
||||||
" True colors
|
" True colors
|
||||||
if !has('gui_running') && &term =~ '\%(screen\|tmux\)'
|
if !has('gui_running') && &term =~ '\%(screen\|tmux\)'
|
||||||
|
|
@ -198,4 +192,3 @@ augroup netrw_setup | au!
|
||||||
au FileType netrw nmap <buffer> l <CR>
|
au FileType netrw nmap <buffer> l <CR>
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
set rtp+=/opt/homebrew/opt/fzf
|
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,6 @@ vim.opt.iskeyword:append '-' -- hyphenated words recognized by searches
|
||||||
vim.opt.formatoptions:remove { 'c', 'r', 'o' } -- don't insert the current comment leader automatically for auto-wrapping comments using 'textwidth', hitting <Enter> in insert mode, or hitting 'o' or 'O' in normal mode.
|
vim.opt.formatoptions:remove { 'c', 'r', 'o' } -- don't insert the current comment leader automatically for auto-wrapping comments using 'textwidth', hitting <Enter> in insert mode, or hitting 'o' or 'O' in normal mode.
|
||||||
vim.opt.runtimepath:remove '/usr/share/vim/vimfiles' -- separate vim plugins from neovim in case vim still in use
|
vim.opt.runtimepath:remove '/usr/share/vim/vimfiles' -- separate vim plugins from neovim in case vim still in use
|
||||||
|
|
||||||
-- Offline mode: set NVIM_OFFLINE=1 to disable all network operations
|
|
||||||
-- (plugin update checks, Mason auto-install, Treesitter auto-install)
|
|
||||||
vim.g.offline_mode = vim.env.NVIM_OFFLINE == '1'
|
|
||||||
|
|
||||||
-- Neovim 0.12 changed directive captures from TSNode to TSNode[] (arrays).
|
-- Neovim 0.12 changed directive captures from TSNode to TSNode[] (arrays).
|
||||||
-- nvim-treesitter predicates do match[capture_id] expecting a single TSNode,
|
-- nvim-treesitter predicates do match[capture_id] expecting a single TSNode,
|
||||||
-- but now receive a table. The nil guard passes, then get_node_text calls
|
-- but now receive a table. The nil guard passes, then get_node_text calls
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,14 @@ if not (vim.uv or vim.loop).fs_stat(lazypath) then
|
||||||
end
|
end
|
||||||
vim.opt.rtp:prepend(lazypath)
|
vim.opt.rtp:prepend(lazypath)
|
||||||
|
|
||||||
local offline = vim.g.offline_mode
|
|
||||||
|
|
||||||
require('lazy').setup {
|
require('lazy').setup {
|
||||||
spec = {
|
spec = {
|
||||||
{ import = 'brian.plugins' },
|
{ import = 'brian.plugins' },
|
||||||
},
|
},
|
||||||
install = { colorscheme = { 'kanagawa' } },
|
install = { colorscheme = { 'kanagawa' } },
|
||||||
checker = { enabled = not offline, notify = false },
|
checker = { enabled = true, notify = false },
|
||||||
change_detection = {
|
change_detection = {
|
||||||
notify = false,
|
notify = false,
|
||||||
},
|
},
|
||||||
git = {
|
|
||||||
timeout = offline and 1 or 120,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
vim.keymap.set('n', '<leader>l', '<cmd>:Lazy<cr>', { desc = 'Plugin Manager' })
|
vim.keymap.set('n', '<leader>l', '<cmd>:Lazy<cr>', { desc = 'Plugin Manager' })
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
local preparing = vim.env.NVIM_OFFLINE_PREPARE == '1'
|
|
||||||
local dap_auto_install = not vim.g.offline_mode and not preparing
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'mfussenegger/nvim-dap',
|
'mfussenegger/nvim-dap',
|
||||||
dependencies = {
|
dependencies = {
|
||||||
|
|
@ -52,13 +49,13 @@ return {
|
||||||
dependencies = 'mason.nvim',
|
dependencies = 'mason.nvim',
|
||||||
cmd = { 'DapInstall', 'DapUninstall' },
|
cmd = { 'DapInstall', 'DapUninstall' },
|
||||||
opts = {
|
opts = {
|
||||||
automatic_installation = dap_auto_install,
|
automatic_installation = true,
|
||||||
handlers = {},
|
handlers = {},
|
||||||
ensure_installed = dap_auto_install and {
|
ensure_installed = {
|
||||||
'python',
|
'python',
|
||||||
'js',
|
'js',
|
||||||
'codelldb',
|
'codelldb',
|
||||||
} or {},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
local offline = vim.g.offline_mode
|
|
||||||
local preparing = vim.env.NVIM_OFFLINE_PREPARE == '1'
|
|
||||||
local online = not offline
|
|
||||||
local auto_install = online and not preparing
|
|
||||||
local skip_prepare_packages = {}
|
|
||||||
|
|
||||||
do
|
|
||||||
local raw = vim.env.PREPARE_SKIP_MASON_PACKAGES or ''
|
|
||||||
for name in string.gmatch(raw, '([^,]+)') do
|
|
||||||
local trimmed = vim.trim(name)
|
|
||||||
if trimmed ~= '' then
|
|
||||||
skip_prepare_packages[trimmed] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local lsp_servers = {
|
local lsp_servers = {
|
||||||
'angularls',
|
'angularls',
|
||||||
'bashls',
|
'bashls',
|
||||||
|
|
@ -68,32 +52,13 @@ local function dedupe(list)
|
||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
local function filter_skips(list)
|
local tool_installer_list = dedupe(vim.list_extend(vim.deepcopy(tools), lsp_servers))
|
||||||
if not preparing or vim.tbl_count(skip_prepare_packages) == 0 then
|
|
||||||
return list
|
|
||||||
end
|
|
||||||
local out = {}
|
|
||||||
for _, item in ipairs(list) do
|
|
||||||
if not skip_prepare_packages[item] then
|
|
||||||
table.insert(out, item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local configured_mason_packages = dedupe(
|
|
||||||
vim.list_extend(vim.deepcopy(tools), lsp_servers)
|
|
||||||
)
|
|
||||||
local prepare_tools = filter_skips(vim.deepcopy(configured_mason_packages))
|
|
||||||
local tool_installer_list = preparing and prepare_tools or configured_mason_packages
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
{
|
{
|
||||||
'mason-org/mason-lspconfig.nvim',
|
'mason-org/mason-lspconfig.nvim',
|
||||||
opts = {
|
opts = {
|
||||||
-- skip auto-install when offline; packages are pre-installed
|
ensure_installed = lsp_servers,
|
||||||
-- during offline prepare we install LSP packages via MasonToolsInstallSync
|
|
||||||
ensure_installed = auto_install and lsp_servers or {},
|
|
||||||
-- Only auto-enable the LSP servers we explicitly manage in this config.
|
-- Only auto-enable the LSP servers we explicitly manage in this config.
|
||||||
-- This avoids accidental multi-server attaches (e.g. ts_ls + vtsls),
|
-- This avoids accidental multi-server attaches (e.g. ts_ls + vtsls),
|
||||||
-- which can produce duplicate Telescope definition results.
|
-- which can produce duplicate Telescope definition results.
|
||||||
|
|
@ -121,14 +86,12 @@ return {
|
||||||
'mason-org/mason.nvim',
|
'mason-org/mason.nvim',
|
||||||
},
|
},
|
||||||
opts = {
|
opts = {
|
||||||
-- skip auto-install when offline; packages are pre-installed
|
|
||||||
-- during offline prepare we install tools + lsp packages in one sync pass
|
|
||||||
ensure_installed = tool_installer_list,
|
ensure_installed = tool_installer_list,
|
||||||
integrations = {
|
integrations = {
|
||||||
-- keep mapping enabled so lspconfig names (e.g. ts_ls) resolve to Mason packages
|
-- keep mapping enabled so lspconfig names (e.g. ts_ls) resolve to Mason packages
|
||||||
['mason-lspconfig'] = true,
|
['mason-lspconfig'] = true,
|
||||||
},
|
},
|
||||||
run_on_start = auto_install,
|
run_on_start = true,
|
||||||
start_delay = 0,
|
start_delay = 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
-- Highlight, edit, and navigate code
|
-- Highlight, edit, and navigate code
|
||||||
local preparing = vim.env.NVIM_OFFLINE_PREPARE == '1'
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'nvim-treesitter/nvim-treesitter',
|
'nvim-treesitter/nvim-treesitter',
|
||||||
branch = 'master',
|
branch = 'master',
|
||||||
-- During offline prepare we run TSUpdateSync explicitly from the script.
|
build = ':TSUpdate',
|
||||||
-- Skipping lazy build here prevents duplicate parser builds in later steps.
|
|
||||||
build = preparing and nil or ':TSUpdate',
|
|
||||||
main = 'nvim-treesitter.configs',
|
main = 'nvim-treesitter.configs',
|
||||||
dependencies = {
|
dependencies = {
|
||||||
'nvim-treesitter/nvim-treesitter-textobjects',
|
'nvim-treesitter/nvim-treesitter-textobjects',
|
||||||
|
|
@ -41,7 +37,7 @@ return {
|
||||||
'html',
|
'html',
|
||||||
'rust',
|
'rust',
|
||||||
},
|
},
|
||||||
auto_install = not vim.g.offline_mode and not preparing,
|
auto_install = true,
|
||||||
highlight = { enable = true },
|
highlight = { enable = true },
|
||||||
indent = { enable = true },
|
indent = { enable = true },
|
||||||
incremental_selection = {
|
incremental_selection = {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,6 @@ if wezterm.config_builder then
|
||||||
config = wezterm.config_builder()
|
config = wezterm.config_builder()
|
||||||
end
|
end
|
||||||
|
|
||||||
local target_triple = wezterm.target_triple or ""
|
|
||||||
local is_macos = target_triple:find("apple%-darwin") ~= nil
|
|
||||||
local is_windows = target_triple:find("windows") ~= nil
|
|
||||||
|
|
||||||
local function env_number(name, fallback)
|
local function env_number(name, fallback)
|
||||||
local raw = os.getenv(name)
|
local raw = os.getenv(name)
|
||||||
local parsed = raw and tonumber(raw) or nil
|
local parsed = raw and tonumber(raw) or nil
|
||||||
|
|
@ -26,16 +22,10 @@ config.use_fancy_tab_bar = false
|
||||||
config.tab_bar_at_bottom = false
|
config.tab_bar_at_bottom = false
|
||||||
config.enable_tab_bar = false
|
config.enable_tab_bar = false
|
||||||
-- Font configuration
|
-- Font configuration
|
||||||
local default_font_size = is_windows and 13 or 16
|
config.font_size = env_number("WEZTERM_FONT_SIZE", 16)
|
||||||
config.font_size = env_number("WEZTERM_FONT_SIZE", default_font_size)
|
|
||||||
config.font = wezterm.font("JetBrains Mono", { weight = "Regular" })
|
config.font = wezterm.font("JetBrains Mono", { weight = "Regular" })
|
||||||
config.bold_brightens_ansi_colors = true
|
config.bold_brightens_ansi_colors = true
|
||||||
config.force_reverse_video_cursor = false
|
config.force_reverse_video_cursor = false
|
||||||
if is_windows then
|
|
||||||
-- Windows GPUs/drivers can show transient render artifacts with the default
|
|
||||||
-- backend. OpenGL is generally more stable here.
|
|
||||||
config.front_end = "OpenGL"
|
|
||||||
end
|
|
||||||
local function resolve_theme_name()
|
local function resolve_theme_name()
|
||||||
local value = (os.getenv("WEZTERM_THEME") or "dragon"):lower()
|
local value = (os.getenv("WEZTERM_THEME") or "dragon"):lower()
|
||||||
local aliases = {
|
local aliases = {
|
||||||
|
|
@ -128,20 +118,11 @@ config.window_padding = {
|
||||||
top = 8,
|
top = 8,
|
||||||
bottom = 8,
|
bottom = 8,
|
||||||
}
|
}
|
||||||
-- Window transparency and blur
|
-- Window transparency
|
||||||
local default_opacity = is_windows and 1.0 or 0.80
|
config.window_background_opacity = env_number("WEZTERM_WINDOW_OPACITY", 0.80)
|
||||||
config.window_background_opacity = env_number("WEZTERM_WINDOW_OPACITY", default_opacity)
|
|
||||||
if is_macos then
|
|
||||||
config.macos_window_background_blur = 60
|
|
||||||
end
|
|
||||||
-- Keep text cells opaque by default; transparent text backgrounds can show
|
-- Keep text cells opaque by default; transparent text backgrounds can show
|
||||||
-- grid/dot artifacts on some GPU/compositor combinations.
|
-- grid/dot artifacts on some GPU/compositor combinations.
|
||||||
config.text_background_opacity = env_number("WEZTERM_TEXT_OPACITY", 1.0)
|
config.text_background_opacity = env_number("WEZTERM_TEXT_OPACITY", 1.0)
|
||||||
if is_windows then
|
|
||||||
-- Disable transparency on Windows to avoid compositor repaint glitches.
|
|
||||||
config.window_background_opacity = 1.0
|
|
||||||
config.text_background_opacity = 1.0
|
|
||||||
end
|
|
||||||
-- Performance
|
-- Performance
|
||||||
config.scrollback_lines = 10000
|
config.scrollback_lines = 10000
|
||||||
config.enable_scroll_bar = false
|
config.enable_scroll_bar = false
|
||||||
|
|
@ -151,10 +132,10 @@ config.cursor_blink_rate = 500
|
||||||
config.cursor_blink_ease_in = "Constant"
|
config.cursor_blink_ease_in = "Constant"
|
||||||
config.cursor_blink_ease_out = "Constant"
|
config.cursor_blink_ease_out = "Constant"
|
||||||
-- Key bindings
|
-- Key bindings
|
||||||
local keys = {
|
config.keys = {
|
||||||
{ key = "Enter", mods = "CTRL", action = wezterm.action({ SendString = "\x1b[13;5u" }) },
|
{ key = "Enter", mods = "CTRL", action = wezterm.action({ SendString = "\x1b[13;5u" }) },
|
||||||
{ key = "Enter", mods = "SHIFT", action = wezterm.action({ SendString = "\x1b[13;2u" }) },
|
{ key = "Enter", mods = "SHIFT", action = wezterm.action({ SendString = "\x1b[13;2u" }) },
|
||||||
-- Navigate splits (via physical Win+Shift)
|
-- Navigate splits
|
||||||
{ key = "h", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Left") },
|
{ key = "h", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Left") },
|
||||||
{ key = "l", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Right") },
|
{ key = "l", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Right") },
|
||||||
{ key = "k", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Up") },
|
{ key = "k", mods = "CTRL|SHIFT", action = wezterm.action.ActivatePaneDirection("Up") },
|
||||||
|
|
@ -168,70 +149,6 @@ local keys = {
|
||||||
{ key = "z", mods = "CTRL|SHIFT", action = wezterm.action.TogglePaneZoomState },
|
{ key = "z", mods = "CTRL|SHIFT", action = wezterm.action.TogglePaneZoomState },
|
||||||
{ key = "f", mods = "SHIFT|CTRL", action = wezterm.action.ToggleFullScreen },
|
{ key = "f", mods = "SHIFT|CTRL", action = wezterm.action.ToggleFullScreen },
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_windows then
|
|
||||||
-- Keep CapsLock->Escape only on Windows; macOS is handled by Karabiner.
|
|
||||||
table.insert(keys, {
|
|
||||||
key = "CapsLock",
|
|
||||||
mods = "NONE",
|
|
||||||
action = wezterm.action.SendKey({ key = "Escape" }),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_macos then
|
|
||||||
local mac_keys = {
|
|
||||||
-- =====================================================
|
|
||||||
-- NuPhy V3 fix: Physical Ctrl sends CMD to macOS.
|
|
||||||
-- Map CMD+key -> Ctrl+key so terminal apps work naturally.
|
|
||||||
-- =====================================================
|
|
||||||
|
|
||||||
-- Tmux prefix: physical Ctrl+Space
|
|
||||||
{ key = "Space", mods = "CMD", action = wezterm.action.SendKey({ key = "Space", mods = "CTRL" }) },
|
|
||||||
|
|
||||||
-- Common terminal control characters
|
|
||||||
{ key = "a", mods = "CMD", action = wezterm.action.SendKey({ key = "a", mods = "CTRL" }) },
|
|
||||||
{ key = "b", mods = "CMD", action = wezterm.action.SendKey({ key = "b", mods = "CTRL" }) },
|
|
||||||
{ key = "c", mods = "CMD", action = wezterm.action.SendKey({ key = "c", mods = "CTRL" }) },
|
|
||||||
{ key = "d", mods = "CMD", action = wezterm.action.SendKey({ key = "d", mods = "CTRL" }) },
|
|
||||||
{ key = "e", mods = "CMD", action = wezterm.action.SendKey({ key = "e", mods = "CTRL" }) },
|
|
||||||
{ key = "f", mods = "CMD", action = wezterm.action.SendKey({ key = "f", mods = "CTRL" }) },
|
|
||||||
{ key = "g", mods = "CMD", action = wezterm.action.SendKey({ key = "g", mods = "CTRL" }) },
|
|
||||||
{ key = "h", mods = "CMD", action = wezterm.action.SendKey({ key = "h", mods = "CTRL" }) },
|
|
||||||
{ key = "j", mods = "CMD", action = wezterm.action.SendKey({ key = "j", mods = "CTRL" }) },
|
|
||||||
{ key = "k", mods = "CMD", action = wezterm.action.SendKey({ key = "k", mods = "CTRL" }) },
|
|
||||||
{ key = "l", mods = "CMD", action = wezterm.action.SendKey({ key = "l", mods = "CTRL" }) },
|
|
||||||
{ key = "n", mods = "CMD", action = wezterm.action.SendKey({ key = "n", mods = "CTRL" }) },
|
|
||||||
{ key = "o", mods = "CMD", action = wezterm.action.SendKey({ key = "o", mods = "CTRL" }) },
|
|
||||||
{ key = "p", mods = "CMD", action = wezterm.action.SendKey({ key = "p", mods = "CTRL" }) },
|
|
||||||
{ key = "r", mods = "CMD", action = wezterm.action.SendKey({ key = "r", mods = "CTRL" }) },
|
|
||||||
{ key = "t", mods = "CMD", action = wezterm.action.SendKey({ key = "t", mods = "CTRL" }) },
|
|
||||||
{ key = "u", mods = "CMD", action = wezterm.action.SendKey({ key = "u", mods = "CTRL" }) },
|
|
||||||
{ key = "v", mods = "CMD", action = wezterm.action.SendKey({ key = "v", mods = "CTRL" }) },
|
|
||||||
{ key = "w", mods = "CMD", action = wezterm.action.SendKey({ key = "w", mods = "CTRL" }) },
|
|
||||||
{ key = "x", mods = "CMD", action = wezterm.action.SendKey({ key = "x", mods = "CTRL" }) },
|
|
||||||
{ key = "z", mods = "CMD", action = wezterm.action.SendKey({ key = "z", mods = "CTRL" }) },
|
|
||||||
{ key = "[", mods = "CMD", action = wezterm.action.SendKey({ key = "[", mods = "CTRL" }) },
|
|
||||||
{ key = "]", mods = "CMD", action = wezterm.action.SendKey({ key = "]", mods = "CTRL" }) },
|
|
||||||
{ key = "\\", mods = "CMD", action = wezterm.action.SendKey({ key = "\\", mods = "CTRL" }) },
|
|
||||||
|
|
||||||
-- Physical Ctrl+Shift combos (CMD+SHIFT -> WezTerm actions)
|
|
||||||
{ key = "f", mods = "CMD|SHIFT", action = wezterm.action.ToggleFullScreen },
|
|
||||||
{ key = "h", mods = "CMD|SHIFT", action = wezterm.action.ActivatePaneDirection("Left") },
|
|
||||||
{ key = "l", mods = "CMD|SHIFT", action = wezterm.action.ActivatePaneDirection("Right") },
|
|
||||||
{ key = "k", mods = "CMD|SHIFT", action = wezterm.action.ActivatePaneDirection("Up") },
|
|
||||||
{ key = "j", mods = "CMD|SHIFT", action = wezterm.action.ActivatePaneDirection("Down") },
|
|
||||||
{ key = "|", mods = "CMD|SHIFT", action = wezterm.action.SplitHorizontal({ domain = "CurrentPaneDomain" }) },
|
|
||||||
{ key = "_", mods = "CMD|SHIFT", action = wezterm.action.SplitVertical({ domain = "CurrentPaneDomain" }) },
|
|
||||||
{ key = "w", mods = "CMD|SHIFT", action = wezterm.action.CloseCurrentPane({ confirm = false }) },
|
|
||||||
{ key = "z", mods = "CMD|SHIFT", action = wezterm.action.TogglePaneZoomState },
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key in ipairs(mac_keys) do
|
|
||||||
table.insert(keys, key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
config.keys = keys
|
|
||||||
-- Hyperlink rules
|
-- Hyperlink rules
|
||||||
config.hyperlink_rules = {
|
config.hyperlink_rules = {
|
||||||
{ regex = "\\((\\w+://\\S+)\\)", format = "$1", highlight = 1 },
|
{ regex = "\\((\\w+://\\S+)\\)", format = "$1", highlight = 1 },
|
||||||
|
|
|
||||||
15
.gitattributes
vendored
15
.gitattributes
vendored
|
|
@ -1,14 +1 @@
|
||||||
* text=auto
|
* text=auto eol=lf
|
||||||
|
|
||||||
# Keep Unix configs LF so copies into WSL don't break parsers.
|
|
||||||
*.sh text eol=lf
|
|
||||||
*.zsh text eol=lf
|
|
||||||
*.conf text eol=lf
|
|
||||||
*.lua text eol=lf
|
|
||||||
*.toml text eol=lf
|
|
||||||
*.vim text eol=lf
|
|
||||||
*.vimrc text eol=lf
|
|
||||||
*.md text eol=lf
|
|
||||||
|
|
||||||
# Keep PowerShell script native on Windows.
|
|
||||||
*.ps1 text eol=crlf
|
|
||||||
|
|
|
||||||
47
.gitignore
vendored
47
.gitignore
vendored
|
|
@ -1,38 +1,5 @@
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/vim,macos
|
# Created by https://www.toptal.com/developers/gitignore/api/vim
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,macos
|
# Edit at https://www.toptal.com/developers/gitignore?templates=vim
|
||||||
|
|
||||||
### macOS ###
|
|
||||||
# General
|
|
||||||
.DS_Store
|
|
||||||
.AppleDouble
|
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
# Icon must end with two \r
|
|
||||||
Icon
|
|
||||||
|
|
||||||
|
|
||||||
# Thumbnails
|
|
||||||
._*
|
|
||||||
|
|
||||||
# Files that might appear in the root of a volume
|
|
||||||
.DocumentRevisions-V100
|
|
||||||
.fseventsd
|
|
||||||
.Spotlight-V100
|
|
||||||
.TemporaryItems
|
|
||||||
.Trashes
|
|
||||||
.VolumeIcon.icns
|
|
||||||
.com.apple.timemachine.donotpresent
|
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share
|
|
||||||
.AppleDB
|
|
||||||
.AppleDesktop
|
|
||||||
Network Trash Folder
|
|
||||||
Temporary Items
|
|
||||||
.apdisk
|
|
||||||
|
|
||||||
### macOS Patch ###
|
|
||||||
# iCloud generated files
|
|
||||||
*.icloud
|
|
||||||
|
|
||||||
### Vim ###
|
### Vim ###
|
||||||
# Swap
|
# Swap
|
||||||
|
|
@ -64,8 +31,6 @@ tags
|
||||||
!.config/zed/
|
!.config/zed/
|
||||||
!.config/zed/settings.json
|
!.config/zed/settings.json
|
||||||
!.config/zed/keymap.json
|
!.config/zed/keymap.json
|
||||||
!.config/karabiner/
|
|
||||||
!.config/karabiner/karabiner.json
|
|
||||||
!.config/tmux/
|
!.config/tmux/
|
||||||
!.config/tmux/nord-theme.conf
|
!.config/tmux/nord-theme.conf
|
||||||
!.config/tmux/dragon-theme.conf
|
!.config/tmux/dragon-theme.conf
|
||||||
|
|
@ -75,9 +40,7 @@ tags
|
||||||
!.config/.vimrc
|
!.config/.vimrc
|
||||||
!.config/.ideavimrc
|
!.config/.ideavimrc
|
||||||
|
|
||||||
# Ignore subfolders in karabiner and tmux
|
# Ignore subfolders in tmux
|
||||||
.config/karabiner/**
|
|
||||||
!.config/karabiner/karabiner.json
|
|
||||||
.config/tmux/**
|
.config/tmux/**
|
||||||
!.config/tmux/nord-theme.conf
|
!.config/tmux/nord-theme.conf
|
||||||
!.config/tmux/dragon-theme.conf
|
!.config/tmux/dragon-theme.conf
|
||||||
|
|
@ -87,7 +50,5 @@ tags
|
||||||
!.config/.vimrc
|
!.config/.vimrc
|
||||||
!.config/.ideavimrc
|
!.config/.ideavimrc
|
||||||
|
|
||||||
scripts/nvim-offline-bundle-output
|
|
||||||
|
|
||||||
.nvimlog
|
.nvimlog
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/vim,macos
|
# End of https://www.toptal.com/developers/gitignore/api/vim
|
||||||
|
|
|
||||||
42
README.md
42
README.md
|
|
@ -49,45 +49,3 @@ Set in shell:
|
||||||
```bash
|
```bash
|
||||||
export KANAGAWA_THEME="wave" # or "dragon"
|
export KANAGAWA_THEME="wave" # or "dragon"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Neovim Offline Setup (Corporate Proxy)
|
|
||||||
|
|
||||||
If you're behind a corporate proxy where Mason, Treesitter, or plugin installs fail, you can pre-download everything on a machine with internet access and deploy offline.
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
On the machine with internet access, make sure you have:
|
|
||||||
|
|
||||||
- Docker (Linux containers enabled)
|
|
||||||
|
|
||||||
### Step 1: Prepare the bundle (with internet)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/nvim-offline-prepare.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Optionally pin Neovim to a specific tag:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
NVIM_RELEASE_TAG=v0.11.6 ./scripts/nvim-offline-prepare.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Output: `scripts/nvim-offline-bundle-output/nvim-offline-bundle.tar.gz`
|
|
||||||
|
|
||||||
### Step 2: Install the bundle (on the proxy machine)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./scripts/nvim-offline-install.sh ./scripts/nvim-offline-bundle-output/nvim-offline-bundle.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Enable offline mode
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export NVIM_OFFLINE=1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Re-enabling network access
|
|
||||||
|
|
||||||
```bash
|
|
||||||
unset NVIM_OFFLINE
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# nvim-offline-install.sh
|
|
||||||
# =======================
|
|
||||||
# Deploys pre-downloaded Neovim dependencies on an offline / corporate proxy machine.
|
|
||||||
# Compatible with the Docker-generated offline bundle.
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
DOTFILES_DIR="$(dirname "$SCRIPT_DIR")"
|
|
||||||
NVIM_CONFIG="$DOTFILES_DIR/.config/nvim"
|
|
||||||
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
info() { echo -e "${GREEN}==>${NC} $*"; }
|
|
||||||
warn() { echo -e "${YELLOW}WARNING:${NC} $*"; }
|
|
||||||
error() { echo -e "${RED}ERROR:${NC} $*" >&2; }
|
|
||||||
|
|
||||||
# ── Archive hygiene (defensive) ──────────────────────────────────────────────
|
|
||||||
export COPYFILE_DISABLE=1
|
|
||||||
|
|
||||||
TARBALL="${1:-}"
|
|
||||||
if [ -z "$TARBALL" ]; then
|
|
||||||
error "Usage: $0 <nvim-offline-bundle.tar.gz>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "$TARBALL" ]; then
|
|
||||||
error "File not found: $TARBALL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
copy_tree() {
|
|
||||||
local src="$1"
|
|
||||||
local dst="$2"
|
|
||||||
rsync -a --delete "$src/" "$dst/"
|
|
||||||
}
|
|
||||||
|
|
||||||
rewrite_mason_paths() {
|
|
||||||
local mason_root="$1"
|
|
||||||
local rewritten=0
|
|
||||||
|
|
||||||
if [ ! -d "$mason_root" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
# Only rewrite text files.
|
|
||||||
if ! LC_ALL=C grep -Iq . "$file"; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if ! grep -q '/mason/packages/' "$file"; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tmp
|
|
||||||
tmp="$(mktemp)"
|
|
||||||
local escaped_root="${mason_root//&/\\&}"
|
|
||||||
sed -E "s|/[^\"'[:space:]]*/mason/packages/|$escaped_root/packages/|g" "$file" >"$tmp"
|
|
||||||
|
|
||||||
if ! cmp -s "$file" "$tmp"; then
|
|
||||||
cat "$tmp" >"$file"
|
|
||||||
chmod +x "$file" || true
|
|
||||||
rewritten=$((rewritten + 1))
|
|
||||||
fi
|
|
||||||
rm -f "$tmp"
|
|
||||||
done < <(find "$mason_root" -type f -print0)
|
|
||||||
|
|
||||||
info "Rewrote $rewritten Mason file(s) in $mason_root"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! command -v rsync >/dev/null 2>&1; then
|
|
||||||
warn "rsync not found; using cp -a fallback."
|
|
||||||
copy_tree() {
|
|
||||||
local src="$1"
|
|
||||||
local dst="$2"
|
|
||||||
rm -rf "$dst"
|
|
||||||
mkdir -p "$dst"
|
|
||||||
cp -a "$src/." "$dst/"
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
|
||||||
NVIM_DATA="$XDG_DATA_HOME/nvim"
|
|
||||||
|
|
||||||
info "Installing offline Neovim bundle..."
|
|
||||||
echo " Source : $TARBALL"
|
|
||||||
echo " Target : $NVIM_DATA"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# ── Extract to temp directory ───────────────────────────────────────────────
|
|
||||||
TMPDIR="$(mktemp -d)"
|
|
||||||
trap 'rm -rf "$TMPDIR"' EXIT
|
|
||||||
|
|
||||||
info "Extracting bundle..."
|
|
||||||
# Note: Docker tarball creates a flat structure (share/ at root)
|
|
||||||
tar \
|
|
||||||
--no-xattrs \
|
|
||||||
--no-acls \
|
|
||||||
--no-selinux \
|
|
||||||
-xzf "$TARBALL" \
|
|
||||||
-C "$TMPDIR"
|
|
||||||
|
|
||||||
# [CRITICAL CHANGE]
|
|
||||||
# The Docker script places 'share' directly in the root of the tarball.
|
|
||||||
# We no longer look for a 'nvim-offline-bundle' subdirectory.
|
|
||||||
BUNDLE_DIR="$TMPDIR"
|
|
||||||
|
|
||||||
if [ ! -d "$BUNDLE_DIR/share/nvim" ]; then
|
|
||||||
error "Invalid bundle structure: 'share/nvim' directory not found."
|
|
||||||
echo " Debug: Extracted contents of $TMPDIR:"
|
|
||||||
ls -F "$TMPDIR"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Sanity check: NO AppleDouble files ──────────────────────────────────────
|
|
||||||
if find "$BUNDLE_DIR" -name '._*' | grep -q .; then
|
|
||||||
error "AppleDouble (._*) files detected in bundle. Refusing to install."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Install lazy.nvim plugins ──────────────────────────────────────────────
|
|
||||||
# Path in bundle: share/nvim/lazy
|
|
||||||
SOURCE_LAZY="$BUNDLE_DIR/share/nvim/lazy"
|
|
||||||
|
|
||||||
if [ -d "$SOURCE_LAZY" ]; then
|
|
||||||
PLUGIN_COUNT=$(ls -1 "$SOURCE_LAZY" | wc -l)
|
|
||||||
info "Installing $PLUGIN_COUNT plugins..."
|
|
||||||
|
|
||||||
if [ -d "$NVIM_DATA/lazy" ]; then
|
|
||||||
warn "Existing lazy/ directory found — backing up to lazy.bak/"
|
|
||||||
rm -rf "$NVIM_DATA/lazy.bak"
|
|
||||||
mv "$NVIM_DATA/lazy" "$NVIM_DATA/lazy.bak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$NVIM_DATA"
|
|
||||||
copy_tree "$SOURCE_LAZY" "$NVIM_DATA/lazy"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Install Mason packages ─────────────────────────────────────────────────
|
|
||||||
# Path in bundle: share/nvim/mason
|
|
||||||
SOURCE_MASON="$BUNDLE_DIR/share/nvim/mason"
|
|
||||||
|
|
||||||
if [ -d "$SOURCE_MASON" ]; then
|
|
||||||
MASON_COUNT=$(ls -1 "$SOURCE_MASON/packages" 2>/dev/null | wc -l)
|
|
||||||
info "Installing $MASON_COUNT Mason packages..."
|
|
||||||
|
|
||||||
if [ -d "$NVIM_DATA/mason" ]; then
|
|
||||||
warn "Existing mason/ directory found — backing up to mason.bak/"
|
|
||||||
rm -rf "$NVIM_DATA/mason.bak"
|
|
||||||
mv "$NVIM_DATA/mason" "$NVIM_DATA/mason.bak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
copy_tree "$SOURCE_MASON" "$NVIM_DATA/mason"
|
|
||||||
rewrite_mason_paths "$NVIM_DATA/mason"
|
|
||||||
|
|
||||||
if rg -n '/tmp/runtime/share/nvim/mason/packages/' "$NVIM_DATA/mason" -S >/dev/null 2>&1; then
|
|
||||||
error "Stale Mason package paths detected after rewrite. Aborting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Install lazy-lock.json ─────────────────────────────────────────────────
|
|
||||||
if [ -f "$BUNDLE_DIR/lazy-lock.json" ] && [ -d "$NVIM_CONFIG" ]; then
|
|
||||||
info "Installing lazy-lock.json..."
|
|
||||||
cp "$BUNDLE_DIR/lazy-lock.json" "$NVIM_CONFIG/lazy-lock.json"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Final verification ─────────────────────────────────────────────────────
|
|
||||||
if find "$NVIM_DATA" -name '._*' | grep -q .; then
|
|
||||||
error "Post-install AppleDouble files detected. Installation aborted."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Summary ────────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
info "Installation complete!"
|
|
||||||
echo ""
|
|
||||||
echo " Plugins : $NVIM_DATA/lazy/"
|
|
||||||
echo " Mason : $NVIM_DATA/mason/"
|
|
||||||
echo ""
|
|
||||||
echo " ┌─────────────────────────────────────────────────────────┐"
|
|
||||||
echo " │ Add the following to your ~/.zshrc or ~/.bashrc: │"
|
|
||||||
echo " │ │"
|
|
||||||
echo " │ export NVIM_OFFLINE=1 │"
|
|
||||||
echo " │ │"
|
|
||||||
echo " │ Then restart your shell or run: source ~/.zshrc │"
|
|
||||||
echo " └─────────────────────────────────────────────────────────┘"
|
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# nvim-offline-prepare.sh
|
|
||||||
# =======================
|
|
||||||
# Build an offline Neovim bundle in a temporary Linux x86_64 container.
|
|
||||||
# The container downloads and compiles all dependencies, then writes only the
|
|
||||||
# final tarball to the host output directory.
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
DOTFILES_DIR="$(dirname "$SCRIPT_DIR")"
|
|
||||||
NVIM_CONFIG="$DOTFILES_DIR/.config/nvim"
|
|
||||||
OUTPUT_DIR="$SCRIPT_DIR/nvim-offline-bundle-output"
|
|
||||||
TARBALL_NAME="nvim-offline-bundle.tar.gz"
|
|
||||||
NVIM_RELEASE_TAG="${NVIM_RELEASE_TAG:-}"
|
|
||||||
NVIM_PREPARE_TIMEOUT="${NVIM_PREPARE_TIMEOUT:-75m}"
|
|
||||||
BUILDER_IMAGE="${BUILDER_IMAGE:-ubuntu:24.04}"
|
|
||||||
ALLOW_EMPTY_MASON="${ALLOW_EMPTY_MASON:-0}"
|
|
||||||
PREPARE_SKIP_MASON_PACKAGES="${PREPARE_SKIP_MASON_PACKAGES:-}"
|
|
||||||
|
|
||||||
# ── Colors & Helpers ────────────────────────────────────────────────────────
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
info() { echo -e "${GREEN}==>${NC} $*"; }
|
|
||||||
warn() { echo -e "${YELLOW}WARNING:${NC} $*"; }
|
|
||||||
error() { echo -e "${RED}ERROR:${NC} $*" >&2; }
|
|
||||||
format_duration() {
|
|
||||||
local total_seconds="$1"
|
|
||||||
local hours=$((total_seconds / 3600))
|
|
||||||
local minutes=$(((total_seconds % 3600) / 60))
|
|
||||||
local seconds=$((total_seconds % 60))
|
|
||||||
printf "%02dh:%02dm:%02ds" "$hours" "$minutes" "$seconds"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ── Checks ──────────────────────────────────────────────────────────────────
|
|
||||||
command -v docker >/dev/null 2>&1 || {
|
|
||||||
error "Docker is required but not installed."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
if ! docker info >/dev/null 2>&1; then
|
|
||||||
error "Docker is not running."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "$NVIM_CONFIG" ]; then
|
|
||||||
error "Neovim config directory not found: $NVIM_CONFIG"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create output directory
|
|
||||||
mkdir -p "$OUTPUT_DIR"
|
|
||||||
# Clear previous run artifacts
|
|
||||||
rm -f "$OUTPUT_DIR/$TARBALL_NAME"
|
|
||||||
|
|
||||||
info "Starting Linux container (x86_64) to build offline bundle..."
|
|
||||||
info " Source Config : $NVIM_CONFIG"
|
|
||||||
info " Output Dir : $OUTPUT_DIR"
|
|
||||||
info " Docker Image : $BUILDER_IMAGE"
|
|
||||||
if [ -n "$NVIM_RELEASE_TAG" ]; then
|
|
||||||
info " Neovim Tag : $NVIM_RELEASE_TAG"
|
|
||||||
else
|
|
||||||
info " Neovim Tag : latest stable"
|
|
||||||
fi
|
|
||||||
info " Nvim Timeout : $NVIM_PREPARE_TIMEOUT"
|
|
||||||
if [ "$ALLOW_EMPTY_MASON" = "1" ]; then
|
|
||||||
warn "ALLOW_EMPTY_MASON=1 (will not fail if Mason installs 0 packages)"
|
|
||||||
fi
|
|
||||||
if [ -n "$PREPARE_SKIP_MASON_PACKAGES" ]; then
|
|
||||||
warn "PREPARE_SKIP_MASON_PACKAGES=$PREPARE_SKIP_MASON_PACKAGES"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Run Builder Container ───────────────────────────────────────────────────
|
|
||||||
# We use --platform linux/amd64 to simulate a standard corporate Linux server.
|
|
||||||
# This ensures binaries (blink.cmp) and parsers (treesitter) are compiled for x86_64.
|
|
||||||
|
|
||||||
PREPARE_STARTED_AT="$(date +%s)"
|
|
||||||
if ! docker run --rm \
|
|
||||||
--platform linux/amd64 \
|
|
||||||
-v "$NVIM_CONFIG:/input/nvim:ro" \
|
|
||||||
-v "$OUTPUT_DIR:/output" \
|
|
||||||
-e HOST_UID="$(id -u)" \
|
|
||||||
-e HOST_GID="$(id -g)" \
|
|
||||||
-e TARBALL_NAME="$TARBALL_NAME" \
|
|
||||||
-e NVIM_RELEASE_TAG="$NVIM_RELEASE_TAG" \
|
|
||||||
-e NVIM_PREPARE_TIMEOUT="$NVIM_PREPARE_TIMEOUT" \
|
|
||||||
-e ALLOW_EMPTY_MASON="$ALLOW_EMPTY_MASON" \
|
|
||||||
-e PREPARE_SKIP_MASON_PACKAGES="$PREPARE_SKIP_MASON_PACKAGES" \
|
|
||||||
"$BUILDER_IMAGE" /bin/bash -c '
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
NVIM_PREPARE_TIMEOUT="${NVIM_PREPARE_TIMEOUT:-75m}"
|
|
||||||
ALLOW_EMPTY_MASON="${ALLOW_EMPTY_MASON:-0}"
|
|
||||||
|
|
||||||
echo ">> [Container] Installing dependencies..."
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
# Build/runtime tools for Lazy, Treesitter, Mason, and common package installers.
|
|
||||||
apt-get update -qq && apt-get install -y -qq \
|
|
||||||
ca-certificates \
|
|
||||||
git \
|
|
||||||
curl \
|
|
||||||
wget \
|
|
||||||
unzip \
|
|
||||||
tar \
|
|
||||||
gzip \
|
|
||||||
jq \
|
|
||||||
build-essential \
|
|
||||||
python3 \
|
|
||||||
python3-venv \
|
|
||||||
python3-pip \
|
|
||||||
lua5.1 \
|
|
||||||
luarocks \
|
|
||||||
nodejs \
|
|
||||||
npm \
|
|
||||||
>/dev/null
|
|
||||||
update-ca-certificates >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
echo ">> [Container] Preparing writable config copy..."
|
|
||||||
mkdir -p /tmp/config
|
|
||||||
cp -a /input/nvim /tmp/config/nvim
|
|
||||||
chmod -R u+rwX /tmp/config/nvim
|
|
||||||
|
|
||||||
echo ">> [Container] Fetching Neovim release..."
|
|
||||||
cd /tmp
|
|
||||||
|
|
||||||
if [ -n "${NVIM_RELEASE_TAG:-}" ]; then
|
|
||||||
TAG="$NVIM_RELEASE_TAG"
|
|
||||||
else
|
|
||||||
TAG="$(curl -fsSL https://api.github.com/repos/neovim/neovim/releases/latest | jq -r .tag_name)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then
|
|
||||||
echo "Error: Could not determine a Neovim release tag."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ">> [Container] Downloading $TAG for x86_64..."
|
|
||||||
ASSET=""
|
|
||||||
for CANDIDATE in nvim-linux-x86_64.tar.gz nvim-linux64.tar.gz; do
|
|
||||||
URL="https://github.com/neovim/neovim/releases/download/${TAG}/${CANDIDATE}"
|
|
||||||
if curl -fL --retry 3 --retry-delay 2 -o nvim-linux.tar.gz "$URL"; then
|
|
||||||
ASSET="$CANDIDATE"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ -z "$ASSET" ]; then
|
|
||||||
echo "Error: Failed to download Neovim archive for tag $TAG."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify download integrity ( > 1MB )
|
|
||||||
FILESIZE=$(stat -c%s nvim-linux.tar.gz)
|
|
||||||
if [ "$FILESIZE" -lt 1000000 ]; then
|
|
||||||
echo "Error: Download failed (file too small)."
|
|
||||||
cat nvim-linux.tar.gz
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
tar -xf nvim-linux.tar.gz
|
|
||||||
NVIM_DIR="${ASSET%.tar.gz}"
|
|
||||||
if [ ! -x "/tmp/$NVIM_DIR/bin/nvim" ]; then
|
|
||||||
NVIM_DIR="$(find /tmp -maxdepth 1 -type d -name "nvim-linux*" | head -n1 | xargs -r basename)"
|
|
||||||
fi
|
|
||||||
if [ -z "$NVIM_DIR" ] || [ ! -x "/tmp/$NVIM_DIR/bin/nvim" ]; then
|
|
||||||
echo "Error: Neovim binary directory not found after extraction."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
export PATH="/tmp/$NVIM_DIR/bin:$PATH"
|
|
||||||
|
|
||||||
# Define isolated runtime paths so host files are never added to the bundle.
|
|
||||||
export XDG_CONFIG_HOME="/tmp/config"
|
|
||||||
export RUNTIME_ROOT="/tmp/runtime"
|
|
||||||
export XDG_DATA_HOME="$RUNTIME_ROOT/share"
|
|
||||||
export XDG_STATE_HOME="$RUNTIME_ROOT/state"
|
|
||||||
export XDG_CACHE_HOME="$RUNTIME_ROOT/cache"
|
|
||||||
export NVIM_OFFLINE_PREPARE=1
|
|
||||||
|
|
||||||
mkdir -p "$XDG_DATA_HOME" "$XDG_STATE_HOME" "$XDG_CACHE_HOME"
|
|
||||||
|
|
||||||
echo ">> [Container] 1/5 Bootstrapping lazy.nvim..."
|
|
||||||
# We bootstrap lazy.nvim manually first
|
|
||||||
git clone --filter=blob:none https://github.com/folke/lazy.nvim.git \
|
|
||||||
"$XDG_DATA_HOME/nvim/lazy/lazy.nvim" || true
|
|
||||||
|
|
||||||
echo ">> [Container] 2/5 Restoring Lazy plugins..."
|
|
||||||
if ! timeout "$NVIM_PREPARE_TIMEOUT" nvim --headless \
|
|
||||||
-c "set nomore" \
|
|
||||||
-c "Lazy! restore" \
|
|
||||||
-c "qa!"; then
|
|
||||||
echo "Error: Lazy restore failed or timed out after $NVIM_PREPARE_TIMEOUT."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ">> [Container] 3/5 Building Treesitter parsers..."
|
|
||||||
if ! timeout "$NVIM_PREPARE_TIMEOUT" nvim --headless \
|
|
||||||
-c "set nomore" \
|
|
||||||
-c "TSUpdateSync" \
|
|
||||||
-c "qa!"; then
|
|
||||||
echo "Error: TSUpdateSync failed or timed out after $NVIM_PREPARE_TIMEOUT."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ">> [Container] 4/5 Installing Mason tools..."
|
|
||||||
if ! timeout "$NVIM_PREPARE_TIMEOUT" nvim --headless \
|
|
||||||
-c "set nomore" \
|
|
||||||
-c "MasonToolsInstallSync" \
|
|
||||||
-c "qa!"; then
|
|
||||||
echo "Error: MasonToolsInstallSync failed or timed out after $NVIM_PREPARE_TIMEOUT."
|
|
||||||
echo "Tip: retry with NVIM_PREPARE_TIMEOUT=120m if needed."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verification (safe with pipefail even when directories are missing)
|
|
||||||
PLUGIN_COUNT=0
|
|
||||||
if [ -d "$XDG_DATA_HOME/nvim/lazy" ]; then
|
|
||||||
PLUGIN_COUNT=$(find "$XDG_DATA_HOME/nvim/lazy" -mindepth 1 -maxdepth 1 -type d | wc -l)
|
|
||||||
fi
|
|
||||||
|
|
||||||
MASON_COUNT=0
|
|
||||||
if [ -d "$XDG_DATA_HOME/nvim/mason/packages" ]; then
|
|
||||||
MASON_COUNT=$(find "$XDG_DATA_HOME/nvim/mason/packages" -mindepth 1 -maxdepth 1 -type d | wc -l)
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ">> [Container] Installed $PLUGIN_COUNT plugins and $MASON_COUNT Mason packages."
|
|
||||||
if [ "$MASON_COUNT" -eq 0 ]; then
|
|
||||||
if [ "$ALLOW_EMPTY_MASON" = "1" ]; then
|
|
||||||
echo ">> [Container] WARNING: No Mason packages detected under $XDG_DATA_HOME/nvim/mason/packages."
|
|
||||||
else
|
|
||||||
echo "Error: No Mason packages were installed. Aborting to avoid an incomplete offline bundle."
|
|
||||||
echo "Tip: set ALLOW_EMPTY_MASON=1 only if you intentionally want a plugins-only bundle."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanup junk
|
|
||||||
echo ">> [Container] 5/5 Packaging & Cleaning..."
|
|
||||||
BUNDLE_ROOT="/tmp/bundle"
|
|
||||||
mkdir -p "$BUNDLE_ROOT"
|
|
||||||
cp -a "$XDG_DATA_HOME" "$BUNDLE_ROOT/share"
|
|
||||||
find "$BUNDLE_ROOT" -name ".git" -type d -exec rm -rf {} +
|
|
||||||
find "$BUNDLE_ROOT" -name "._*" -type f -delete
|
|
||||||
|
|
||||||
# Copy lockfile
|
|
||||||
if [ -f "$XDG_CONFIG_HOME/nvim/lazy-lock.json" ]; then
|
|
||||||
cp "$XDG_CONFIG_HOME/nvim/lazy-lock.json" "$BUNDLE_ROOT/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the Tarball
|
|
||||||
tar --exclude="._*" -czf "/output/$TARBALL_NAME" -C "$BUNDLE_ROOT" .
|
|
||||||
|
|
||||||
# Fix ownership
|
|
||||||
chown "$HOST_UID:$HOST_GID" "/output/$TARBALL_NAME"
|
|
||||||
|
|
||||||
echo ">> [Container] Done."
|
|
||||||
'; then
|
|
||||||
PREPARE_ENDED_AT="$(date +%s)"
|
|
||||||
PREPARE_ELAPSED="$((PREPARE_ENDED_AT - PREPARE_STARTED_AT))"
|
|
||||||
error "Offline prepare container failed after $(format_duration "$PREPARE_ELAPSED"). Review the container logs above."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PREPARE_ENDED_AT="$(date +%s)"
|
|
||||||
PREPARE_ELAPSED="$((PREPARE_ENDED_AT - PREPARE_STARTED_AT))"
|
|
||||||
|
|
||||||
# ── Summary ─────────────────────────────────────────────────────────────────
|
|
||||||
TARBALL="$OUTPUT_DIR/$TARBALL_NAME"
|
|
||||||
|
|
||||||
if [ -f "$TARBALL" ]; then
|
|
||||||
SIZE=$(du -h "$TARBALL" | cut -f1)
|
|
||||||
echo ""
|
|
||||||
info "Success! Bundle created at:"
|
|
||||||
echo " $TARBALL ($SIZE)"
|
|
||||||
echo " Elapsed: $(format_duration "$PREPARE_ELAPSED")"
|
|
||||||
echo ""
|
|
||||||
echo " Target Platform: Linux (x86_64)"
|
|
||||||
else
|
|
||||||
error "Docker container finished but tarball was not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Loading…
Add table
Reference in a new issue