mirror of
https://github.com/harivansh-afk/nix.git
synced 2026-04-15 10:05:17 +00:00
commit
03302eaf08
27 changed files with 4940 additions and 860 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,3 +4,4 @@ result
|
|||
.bw-session
|
||||
config/karabiner/assets/
|
||||
config/karabiner/automatic_backups/
|
||||
tmp/
|
||||
|
|
|
|||
|
|
@ -1,34 +1,25 @@
|
|||
local lsp = require('config.lsp')
|
||||
pcall(vim.cmd.packadd, "blink.cmp")
|
||||
|
||||
vim.lsp.config('*', {
|
||||
capabilities = lsp.capabilities(),
|
||||
local lsp = require "config.lsp"
|
||||
|
||||
vim.lsp.config("*", {
|
||||
on_attach = lsp.on_attach,
|
||||
capabilities = lsp.capabilities(),
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
|
||||
callback = function(ev)
|
||||
local client = vim.lsp.get_client_by_id(ev.data.client_id)
|
||||
if client then
|
||||
lsp.on_attach(client, ev.buf)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
for _, server in ipairs({
|
||||
'lua_ls',
|
||||
'pyright',
|
||||
'ts_ls',
|
||||
'rust_analyzer',
|
||||
'gopls',
|
||||
'clangd',
|
||||
'bashls',
|
||||
'jsonls',
|
||||
'html',
|
||||
'cssls',
|
||||
}) do
|
||||
local ok, config = pcall(require, 'lsp.' .. server)
|
||||
if ok then
|
||||
vim.lsp.config(server, config)
|
||||
end
|
||||
vim.lsp.enable(server)
|
||||
for _, server in ipairs {
|
||||
"lua_ls",
|
||||
"pyright",
|
||||
"ts_ls",
|
||||
"rust_analyzer",
|
||||
"gopls",
|
||||
"clangd",
|
||||
"bashls",
|
||||
"jsonls",
|
||||
"html",
|
||||
"cssls",
|
||||
} do
|
||||
local ok, config = pcall(require, "lsp." .. server)
|
||||
if ok and config then vim.lsp.config(server, config) end
|
||||
vim.lsp.enable(server)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,68 +1,56 @@
|
|||
vim.g.mapleader = ' '
|
||||
vim.g.maplocalleader = ','
|
||||
vim.g.mapleader = " "
|
||||
vim.g.maplocalleader = ","
|
||||
|
||||
local home = os.getenv('HOME') or ''
|
||||
local local_bin = home .. '/.local/bin'
|
||||
if not (os.getenv('PATH') or ''):find(local_bin, 1, true) then
|
||||
local new_path = local_bin .. ':' .. (os.getenv('PATH') or '')
|
||||
vim.env.PATH = new_path
|
||||
vim.uv.os_setenv('PATH', new_path)
|
||||
local home = os.getenv "HOME" or ""
|
||||
local local_bin = home .. "/.local/bin"
|
||||
if not (os.getenv "PATH" or ""):find(local_bin, 1, true) then
|
||||
local new_path = local_bin .. ":" .. (os.getenv "PATH" or "")
|
||||
vim.env.PATH = new_path
|
||||
vim.uv.os_setenv("PATH", new_path)
|
||||
end
|
||||
|
||||
function _G.map(mode, lhs, rhs, opts)
|
||||
vim.keymap.set(mode, lhs, rhs, vim.tbl_extend('keep', opts or {}, { silent = true }))
|
||||
vim.keymap.set(mode, lhs, rhs, vim.tbl_extend("keep", opts or {}, { silent = true }))
|
||||
end
|
||||
|
||||
function _G.bmap(mode, lhs, rhs, opts)
|
||||
_G.map(mode, lhs, rhs, vim.tbl_extend('force', opts or {}, { buffer = 0 }))
|
||||
end
|
||||
function _G.bmap(mode, lhs, rhs, opts) _G.map(mode, lhs, rhs, vim.tbl_extend("force", opts or {}, { buffer = 0 })) end
|
||||
|
||||
local disabled_plugins = {
|
||||
'2html_plugin',
|
||||
'bugreport',
|
||||
'getscript',
|
||||
'getscriptPlugin',
|
||||
'gzip',
|
||||
'logipat',
|
||||
'matchit',
|
||||
'netrw',
|
||||
'netrwFileHandlers',
|
||||
'netrwPlugin',
|
||||
'netrwSettings',
|
||||
'optwin',
|
||||
'rplugin',
|
||||
'rrhelper',
|
||||
'synmenu',
|
||||
'tar',
|
||||
'tarPlugin',
|
||||
'tohtml',
|
||||
'tutor',
|
||||
'vimball',
|
||||
'vimballPlugin',
|
||||
'zip',
|
||||
'zipPlugin',
|
||||
"2html_plugin",
|
||||
"bugreport",
|
||||
"getscript",
|
||||
"getscriptPlugin",
|
||||
"gzip",
|
||||
"logipat",
|
||||
"matchit",
|
||||
"netrw",
|
||||
"netrwFileHandlers",
|
||||
"netrwPlugin",
|
||||
"netrwSettings",
|
||||
"optwin",
|
||||
"rplugin",
|
||||
"rrhelper",
|
||||
"synmenu",
|
||||
"tar",
|
||||
"tarPlugin",
|
||||
"tohtml",
|
||||
"tutor",
|
||||
"vimball",
|
||||
"vimballPlugin",
|
||||
"zip",
|
||||
"zipPlugin",
|
||||
}
|
||||
|
||||
for _, plugin in ipairs(disabled_plugins) do
|
||||
vim.g['loaded_' .. plugin] = 1
|
||||
vim.g["loaded_" .. plugin] = 1
|
||||
end
|
||||
|
||||
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
|
||||
local lazylock = vim.fn.stdpath('state') .. '/lazy-lock.json'
|
||||
if not vim.uv.fs_stat(lazypath) then
|
||||
vim.fn.system({
|
||||
'git',
|
||||
'clone',
|
||||
'--filter=blob:none',
|
||||
'--branch=stable',
|
||||
'https://github.com/folke/lazy.nvim.git',
|
||||
lazypath,
|
||||
})
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
vim.g.lz_n = {
|
||||
load = function(name) vim.cmd.packadd(name:match "[^/]+$" or name) end,
|
||||
}
|
||||
|
||||
require('lazy').setup('plugins', {
|
||||
defaults = { lazy = false },
|
||||
change_detection = { enabled = false },
|
||||
lockfile = lazylock,
|
||||
})
|
||||
vim.pack.add {
|
||||
"https://github.com/lumen-oss/lz.n",
|
||||
}
|
||||
|
||||
require("lz.n").load "plugins"
|
||||
|
|
|
|||
|
|
@ -1,28 +1,45 @@
|
|||
local M = {}
|
||||
local cached_capabilities
|
||||
|
||||
local function load_blink()
|
||||
pcall(vim.cmd.packadd, "blink.cmp")
|
||||
|
||||
local ok_blink, blink = pcall(require, "blink.cmp")
|
||||
if ok_blink then return blink end
|
||||
|
||||
local ok_lz, lz = pcall(require, "lz.n")
|
||||
if ok_lz then
|
||||
pcall(lz.trigger_load, "saghen/blink.cmp")
|
||||
ok_blink, blink = pcall(require, "blink.cmp")
|
||||
if ok_blink then return blink end
|
||||
end
|
||||
end
|
||||
|
||||
function M.on_attach(_, bufnr)
|
||||
local function buf(mode, lhs, rhs)
|
||||
bmap(mode, lhs, rhs, { buffer = bufnr })
|
||||
end
|
||||
local function buf(mode, lhs, rhs) bmap(mode, lhs, rhs, { buffer = bufnr }) end
|
||||
|
||||
buf('n', 'gd', vim.lsp.buf.definition)
|
||||
buf('n', 'gD', vim.lsp.buf.declaration)
|
||||
buf('n', '<C-]>', vim.lsp.buf.definition)
|
||||
buf('n', 'gi', vim.lsp.buf.implementation)
|
||||
buf('n', 'gr', vim.lsp.buf.references)
|
||||
buf('n', 'K', vim.lsp.buf.hover)
|
||||
buf('n', '<leader>rn', vim.lsp.buf.rename)
|
||||
buf({ 'n', 'v' }, '<leader>ca', vim.lsp.buf.code_action)
|
||||
buf('n', '<leader>f', function() vim.lsp.buf.format({ async = true }) end)
|
||||
buf("n", "gd", vim.lsp.buf.definition)
|
||||
buf("n", "gD", vim.lsp.buf.declaration)
|
||||
buf("n", "<C-]>", vim.lsp.buf.definition)
|
||||
buf("n", "gi", vim.lsp.buf.implementation)
|
||||
buf("n", "gr", vim.lsp.buf.references)
|
||||
buf("n", "K", vim.lsp.buf.hover)
|
||||
buf("n", "<leader>rn", vim.lsp.buf.rename)
|
||||
buf({ "n", "v" }, "<leader>ca", vim.lsp.buf.code_action)
|
||||
buf("n", "<leader>f", function() vim.lsp.buf.format { async = true } end)
|
||||
end
|
||||
|
||||
function M.capabilities()
|
||||
local caps = vim.lsp.protocol.make_client_capabilities()
|
||||
local ok, blink = pcall(require, 'blink.cmp')
|
||||
if ok then
|
||||
caps = blink.get_lsp_capabilities(caps)
|
||||
end
|
||||
return caps
|
||||
if cached_capabilities then return vim.deepcopy(cached_capabilities) end
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
local blink = load_blink()
|
||||
if blink and blink.get_lsp_capabilities then
|
||||
capabilities = vim.tbl_deep_extend("force", capabilities, blink.get_lsp_capabilities({}, false))
|
||||
end
|
||||
|
||||
cached_capabilities = capabilities
|
||||
return vim.deepcopy(cached_capabilities)
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
|||
|
|
@ -1,48 +1,54 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/saghen/blink.cmp",
|
||||
}, { load = function() end })
|
||||
|
||||
return {
|
||||
'saghen/blink.cmp',
|
||||
version = '*',
|
||||
event = { 'InsertEnter', 'LspAttach' },
|
||||
opts = {
|
||||
keymap = {
|
||||
['<Tab>'] = { 'select_and_accept', 'snippet_forward', 'fallback' },
|
||||
['<S-Tab>'] = { 'snippet_backward', 'fallback' },
|
||||
['<c-p>'] = { 'select_prev', 'fallback' },
|
||||
['<c-n>'] = { 'show', 'select_next', 'fallback' },
|
||||
['<c-y>'] = { 'select_and_accept', 'fallback' },
|
||||
['<c-e>'] = { 'cancel', 'fallback' },
|
||||
['<c-u>'] = { 'scroll_documentation_up', 'fallback' },
|
||||
['<c-d>'] = { 'scroll_documentation_down', 'fallback' },
|
||||
"saghen/blink.cmp",
|
||||
event = { "InsertEnter", "LspAttach" },
|
||||
keys = { { "<c-n>", mode = "i" } },
|
||||
after = function()
|
||||
require("blink.cmp").setup {
|
||||
keymap = {
|
||||
["<Tab>"] = { "select_and_accept", "snippet_forward", "fallback" },
|
||||
["<S-Tab>"] = { "snippet_backward", "fallback" },
|
||||
["<c-p>"] = { "select_prev", "fallback" },
|
||||
["<c-n>"] = { "show", "select_next", "fallback" },
|
||||
["<c-y>"] = { "select_and_accept", "fallback" },
|
||||
["<c-e>"] = { "cancel", "fallback" },
|
||||
["<c-u>"] = { "scroll_documentation_up", "fallback" },
|
||||
["<c-d>"] = { "scroll_documentation_down", "fallback" },
|
||||
},
|
||||
cmdline = { enabled = false },
|
||||
completion = {
|
||||
accept = {
|
||||
auto_brackets = { enabled = true },
|
||||
},
|
||||
cmdline = { enabled = false },
|
||||
completion = {
|
||||
accept = {
|
||||
auto_brackets = { enabled = true },
|
||||
},
|
||||
documentation = {
|
||||
auto_show = true,
|
||||
window = {
|
||||
border = 'single',
|
||||
scrollbar = false,
|
||||
winhighlight = 'Normal:BlinkCmpDoc,FloatBorder:BlinkCmpDocBorder',
|
||||
},
|
||||
},
|
||||
menu = {
|
||||
auto_show = true,
|
||||
border = 'single',
|
||||
scrollbar = false,
|
||||
winhighlight = 'Normal:BlinkCmpMenu,FloatBorder:BlinkCmpMenuBorder,CursorLine:BlinkCmpMenuSelection',
|
||||
draw = {
|
||||
treesitter = { 'lsp' },
|
||||
columns = {
|
||||
{ 'kind_icon', gap = 1 },
|
||||
{ 'label', 'label_description', gap = 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
ghost_text = { enabled = true },
|
||||
documentation = {
|
||||
auto_show = true,
|
||||
window = {
|
||||
border = "single",
|
||||
scrollbar = false,
|
||||
winhighlight = "Normal:BlinkCmpDoc,FloatBorder:BlinkCmpDocBorder",
|
||||
},
|
||||
},
|
||||
sources = {
|
||||
default = { 'lsp', 'path', 'buffer', 'snippets' },
|
||||
menu = {
|
||||
auto_show = true,
|
||||
border = "single",
|
||||
scrollbar = false,
|
||||
winhighlight = "Normal:BlinkCmpMenu,FloatBorder:BlinkCmpMenuBorder,CursorLine:BlinkCmpMenuSelection",
|
||||
draw = {
|
||||
treesitter = { "lsp" },
|
||||
columns = {
|
||||
{ "kind_icon", gap = 1 },
|
||||
{ "label", "label_description", gap = 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ghost_text = { enabled = true },
|
||||
},
|
||||
sources = {
|
||||
default = { "lsp", "path", "buffer", "snippets" },
|
||||
},
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,171 +1,108 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/windwp/nvim-autopairs",
|
||||
"https://github.com/folke/flash.nvim",
|
||||
"https://github.com/kylechui/nvim-surround",
|
||||
"https://github.com/kevinhwang91/nvim-ufo",
|
||||
"https://github.com/kevinhwang91/promise-async",
|
||||
"https://github.com/barrettruth/pending.nvim",
|
||||
"https://github.com/barrettruth/preview.nvim",
|
||||
}, { load = function() end })
|
||||
|
||||
return {
|
||||
{
|
||||
'windwp/nvim-autopairs',
|
||||
config = true,
|
||||
},
|
||||
{
|
||||
'folke/flash.nvim',
|
||||
opts = {
|
||||
modes = { search = { enabled = true } },
|
||||
},
|
||||
config = function(_, opts)
|
||||
require('flash').setup(opts)
|
||||
map({ 'n', 'x', 'o' }, 's', function() require('flash').jump() end)
|
||||
map({ 'n', 'x', 'o' }, 'S', function() require('flash').treesitter() end)
|
||||
map('o', 'r', function() require('flash').remote() end)
|
||||
map({ 'o', 'x' }, 'R', function() require('flash').treesitter_search() end)
|
||||
map('c', '<c-s>', function() require('flash').toggle() end)
|
||||
end,
|
||||
},
|
||||
{
|
||||
'kylechui/nvim-surround',
|
||||
config = true,
|
||||
},
|
||||
{
|
||||
'kevinhwang91/nvim-ufo',
|
||||
dependencies = { 'kevinhwang91/promise-async' },
|
||||
opts = {
|
||||
provider_selector = function()
|
||||
return { 'treesitter', 'indent' }
|
||||
end,
|
||||
},
|
||||
config = function(_, opts)
|
||||
require('ufo').setup(opts)
|
||||
map('n', 'zR', require('ufo').openAllFolds)
|
||||
map('n', 'zM', require('ufo').closeAllFolds)
|
||||
end,
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
'barrettruth/cp.nvim',
|
||||
dependencies = { 'ibhagwan/fzf-lua' },
|
||||
init = function()
|
||||
-- Keep uv cache in-project so cp.nvim scraping works in restricted environments.
|
||||
if vim.env.UV_CACHE_DIR == nil or vim.env.UV_CACHE_DIR == '' then
|
||||
local uv_cache_dir = vim.fn.getcwd() .. '/.uv-cache'
|
||||
vim.fn.mkdir(uv_cache_dir, 'p')
|
||||
vim.env.UV_CACHE_DIR = uv_cache_dir
|
||||
end
|
||||
|
||||
vim.g.cp = {
|
||||
languages = {
|
||||
python = {
|
||||
extension = 'py',
|
||||
commands = {
|
||||
run = { 'python3', '{source}' },
|
||||
debug = { 'python3', '{source}' },
|
||||
},
|
||||
},
|
||||
},
|
||||
platforms = {
|
||||
codeforces = {
|
||||
enabled_languages = { 'python' },
|
||||
default_language = 'python',
|
||||
},
|
||||
atcoder = {
|
||||
enabled_languages = { 'python' },
|
||||
default_language = 'python',
|
||||
},
|
||||
cses = {
|
||||
enabled_languages = { 'python' },
|
||||
default_language = 'python',
|
||||
},
|
||||
},
|
||||
open_url = true,
|
||||
ui = {
|
||||
picker = 'fzf-lua',
|
||||
},
|
||||
}
|
||||
end,
|
||||
config = function()
|
||||
local function open_url(url)
|
||||
local ok_ui_open, opened = pcall(vim.ui.open, url)
|
||||
if ok_ui_open and opened ~= false then
|
||||
return
|
||||
end
|
||||
|
||||
local opener = nil
|
||||
if vim.fn.has('macunix') == 1 then
|
||||
opener = 'open'
|
||||
elseif vim.fn.has('unix') == 1 then
|
||||
opener = 'xdg-open'
|
||||
end
|
||||
|
||||
if opener then
|
||||
vim.fn.jobstart({ opener, url }, { detach = true })
|
||||
end
|
||||
end
|
||||
|
||||
local function open_current_cp_problem_url()
|
||||
local ok_state, state = pcall(require, 'cp.state')
|
||||
local ok_cache, cache = pcall(require, 'cp.cache')
|
||||
if not (ok_state and ok_cache) then
|
||||
return
|
||||
end
|
||||
|
||||
local platform = state.get_platform()
|
||||
local contest_id = state.get_contest_id()
|
||||
local problem_id = state.get_problem_id()
|
||||
if not (platform and contest_id and problem_id) then
|
||||
return
|
||||
end
|
||||
|
||||
cache.load()
|
||||
local contest = cache.get_contest_data(platform, contest_id)
|
||||
if contest and contest.url then
|
||||
open_url(contest.url:format(problem_id))
|
||||
end
|
||||
end
|
||||
|
||||
-- cp.nvim only opens URLs when first entering a contest; extend this locally for next/prev.
|
||||
local ok_setup, setup = pcall(require, 'cp.setup')
|
||||
local ok_config, cp_config = pcall(require, 'cp.config')
|
||||
if ok_setup and ok_config and not setup._url_open_patch_applied then
|
||||
local original_navigate_problem = setup.navigate_problem
|
||||
setup.navigate_problem = function(direction, language)
|
||||
local ok_state, state = pcall(require, 'cp.state')
|
||||
local old_problem_id = ok_state and state.get_problem_id() or nil
|
||||
original_navigate_problem(direction, language)
|
||||
|
||||
local cfg = cp_config.get_config()
|
||||
local new_problem_id = ok_state and state.get_problem_id() or nil
|
||||
local moved = old_problem_id ~= nil and new_problem_id ~= nil and old_problem_id ~= new_problem_id
|
||||
if cfg and cfg.open_url and moved then
|
||||
vim.schedule(open_current_cp_problem_url)
|
||||
end
|
||||
end
|
||||
setup._url_open_patch_applied = true
|
||||
end
|
||||
|
||||
map('n', '<leader>cr', '<cmd>CP run<cr>', { desc = 'CP run' })
|
||||
map('n', '<leader>cp', '<cmd>CP panel<cr>', { desc = 'CP panel' })
|
||||
map('n', '<leader>ce', '<cmd>CP edit<cr>', { desc = 'CP edit tests' })
|
||||
map('n', '<leader>cn', '<cmd>CP next<cr>', { desc = 'CP next problem' })
|
||||
map('n', '<leader>cN', '<cmd>CP prev<cr>', { desc = 'CP previous problem' })
|
||||
map('n', '<leader>cc', '<cmd>CP pick<cr>', { desc = 'CP contest picker' })
|
||||
map('n', '<leader>ci', '<cmd>CP interact<cr>', { desc = 'CP interact' })
|
||||
map('n', '<leader>co', open_current_cp_problem_url, { desc = 'CP open problem url' })
|
||||
end,
|
||||
},
|
||||
{
|
||||
'barrettruth/pending.nvim',
|
||||
init = function()
|
||||
map('n', '<leader>p', '<cmd>Pending<cr><cmd>only<cr>')
|
||||
end,
|
||||
},
|
||||
{
|
||||
'barrettruth/preview.nvim',
|
||||
init = function()
|
||||
vim.g.preview = {
|
||||
typst = true,
|
||||
latex = true,
|
||||
github = {
|
||||
output = function(ctx)
|
||||
return '/tmp/' .. vim.fn.fnamemodify(ctx.file, ':t:r') .. '.html'
|
||||
end,
|
||||
{
|
||||
"windwp/nvim-autopairs",
|
||||
event = "InsertEnter",
|
||||
after = function() require("nvim-autopairs").setup() end,
|
||||
},
|
||||
{
|
||||
"folke/flash.nvim",
|
||||
after = function()
|
||||
require("flash").setup {
|
||||
modes = { search = { enabled = true } },
|
||||
}
|
||||
end,
|
||||
keys = {
|
||||
{
|
||||
"s",
|
||||
function() require("flash").jump() end,
|
||||
mode = { "n", "x", "o" },
|
||||
},
|
||||
mermaid = true,
|
||||
}
|
||||
end,
|
||||
},
|
||||
{
|
||||
"S",
|
||||
function() require("flash").treesitter() end,
|
||||
mode = { "n", "x", "o" },
|
||||
},
|
||||
{
|
||||
"r",
|
||||
function() require("flash").remote() end,
|
||||
mode = "o",
|
||||
},
|
||||
{
|
||||
"R",
|
||||
function() require("flash").treesitter_search() end,
|
||||
mode = { "o", "x" },
|
||||
},
|
||||
{
|
||||
"<c-s>",
|
||||
function() require("flash").toggle() end,
|
||||
mode = "c",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"kylechui/nvim-surround",
|
||||
after = function() require("nvim-surround").setup() end,
|
||||
keys = {
|
||||
{ "cs", mode = "n" },
|
||||
{ "ds", mode = "n" },
|
||||
{ "ys", mode = "n" },
|
||||
{ "yS", mode = "n" },
|
||||
{ "yss", mode = "n" },
|
||||
{ "ySs", mode = "n" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"kevinhwang91/nvim-ufo",
|
||||
event = "BufReadPost",
|
||||
before = function() vim.cmd.packadd "promise-async" end,
|
||||
after = function()
|
||||
require("ufo").setup {
|
||||
provider_selector = function() return { "treesitter", "indent" } end,
|
||||
}
|
||||
end,
|
||||
keys = {
|
||||
{
|
||||
"zR",
|
||||
function() require("ufo").openAllFolds() end,
|
||||
mode = "n",
|
||||
},
|
||||
{
|
||||
"zM",
|
||||
function() require("ufo").closeAllFolds() end,
|
||||
mode = "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"barrettruth/pending.nvim",
|
||||
cmd = "Pending",
|
||||
keys = {
|
||||
{ "<leader>p", "<cmd>Pending<cr><cmd>only<cr>" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"barrettruth/preview.nvim",
|
||||
cmd = "Preview",
|
||||
ft = { "markdown", "tex", "typst" },
|
||||
before = function()
|
||||
vim.g.preview = {
|
||||
typst = true,
|
||||
latex = true,
|
||||
github = {
|
||||
output = function(ctx) return "/tmp/" .. vim.fn.fnamemodify(ctx.file, ":t:r") .. ".html" end,
|
||||
},
|
||||
mermaid = true,
|
||||
}
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/ibhagwan/fzf-lua",
|
||||
}, { load = function() end })
|
||||
|
||||
---@param kind 'issue'|'pr'
|
||||
---@param state 'all'|'open'|'closed'
|
||||
local function gh_picker(kind, state)
|
||||
|
|
@ -5,8 +9,10 @@ local function gh_picker(kind, state)
|
|||
vim.notify("gh CLI not found", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local next_state = ({ all = "open", open = "closed", closed = "all" })[state]
|
||||
local label = kind == "pr" and "PRs" or "Issues"
|
||||
|
||||
require("fzf-lua").fzf_exec(("gh %s list --limit 100 --state %s"):format(kind, state), {
|
||||
prompt = ("%s (%s)> "):format(label, state),
|
||||
header = ":: <c-o> to toggle all/open/closed",
|
||||
|
|
@ -22,9 +28,27 @@ end
|
|||
|
||||
return {
|
||||
"ibhagwan/fzf-lua",
|
||||
dependencies = { "nvim-tree/nvim-web-devicons" },
|
||||
config = function(_, opts)
|
||||
cmd = "FzfLua",
|
||||
before = function()
|
||||
pcall(vim.cmd.packadd, "nvim-web-devicons")
|
||||
pcall(vim.cmd.packadd, "nonicons.nvim")
|
||||
end,
|
||||
after = function()
|
||||
local fzf = require "fzf-lua"
|
||||
local opts = {
|
||||
"default-title",
|
||||
winopts = {
|
||||
border = "single",
|
||||
preview = {
|
||||
layout = "vertical",
|
||||
vertical = "down:50%",
|
||||
},
|
||||
},
|
||||
fzf_opts = {
|
||||
["--layout"] = "reverse",
|
||||
},
|
||||
}
|
||||
|
||||
fzf.setup(opts)
|
||||
|
||||
local ok, fzf_reload = pcall(require, "config.fzf_reload")
|
||||
|
|
@ -32,45 +56,43 @@ return {
|
|||
fzf_reload.setup(opts)
|
||||
fzf_reload.reload()
|
||||
end
|
||||
|
||||
map("n", "<C-f>", function()
|
||||
local git_dir = vim.fn.system("git rev-parse --git-dir 2>/dev/null"):gsub("\n", "")
|
||||
if vim.v.shell_error == 0 and git_dir ~= "" then
|
||||
fzf.git_files()
|
||||
else
|
||||
fzf.files()
|
||||
end
|
||||
end)
|
||||
map("n", "<leader>ff", "<cmd>FzfLua files<cr>")
|
||||
map("n", "<leader>fg", "<cmd>FzfLua live_grep<cr>")
|
||||
map("n", "<leader>fb", "<cmd>FzfLua buffers<cr>")
|
||||
map("n", "<leader>fh", "<cmd>FzfLua help_tags<cr>")
|
||||
map("n", "<leader>fr", "<cmd>FzfLua resume<cr>")
|
||||
map("n", "<leader>fo", "<cmd>FzfLua oldfiles<cr>")
|
||||
map("n", "<leader>fc", "<cmd>FzfLua commands<cr>")
|
||||
map("n", "<leader>fk", "<cmd>FzfLua keymaps<cr>")
|
||||
map("n", "<leader>f/", "<cmd>FzfLua search_history<cr>")
|
||||
map("n", "<leader>f:", "<cmd>FzfLua command_history<cr>")
|
||||
map("n", "<leader>fe", "<cmd>FzfLua files cwd=~/.config<cr>")
|
||||
map("n", "gq", "<cmd>FzfLua quickfix<cr>")
|
||||
map("n", "gl", "<cmd>FzfLua loclist<cr>")
|
||||
map("n", "<leader>GB", "<cmd>FzfLua git_branches<cr>")
|
||||
map("n", "<leader>Gc", "<cmd>FzfLua git_commits<cr>")
|
||||
map("n", "<leader>Gs", "<cmd>FzfLua git_status<cr>")
|
||||
map("n", "<leader>Gp", function() gh_picker("pr", "open") end)
|
||||
map("n", "<leader>Gi", function() gh_picker("issue", "open") end)
|
||||
end,
|
||||
opts = {
|
||||
"default-title",
|
||||
winopts = {
|
||||
border = "single",
|
||||
preview = {
|
||||
layout = "vertical",
|
||||
vertical = "down:50%",
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
"<C-f>",
|
||||
function()
|
||||
local fzf = require "fzf-lua"
|
||||
local git_dir = vim.fn.system("git rev-parse --git-dir 2>/dev/null"):gsub("\n", "")
|
||||
if vim.v.shell_error == 0 and git_dir ~= "" then
|
||||
fzf.git_files()
|
||||
else
|
||||
fzf.files()
|
||||
end
|
||||
end,
|
||||
},
|
||||
fzf_opts = {
|
||||
["--layout"] = "reverse",
|
||||
{ "<leader>ff", "<cmd>FzfLua files<cr>" },
|
||||
{ "<leader>fg", "<cmd>FzfLua live_grep<cr>" },
|
||||
{ "<leader>fb", "<cmd>FzfLua buffers<cr>" },
|
||||
{ "<leader>fh", "<cmd>FzfLua help_tags<cr>" },
|
||||
{ "<leader>fr", "<cmd>FzfLua resume<cr>" },
|
||||
{ "<leader>fo", "<cmd>FzfLua oldfiles<cr>" },
|
||||
{ "<leader>fc", "<cmd>FzfLua commands<cr>" },
|
||||
{ "<leader>fk", "<cmd>FzfLua keymaps<cr>" },
|
||||
{ "<leader>f/", "<cmd>FzfLua search_history<cr>" },
|
||||
{ "<leader>f:", "<cmd>FzfLua command_history<cr>" },
|
||||
{ "<leader>fe", "<cmd>FzfLua files cwd=~/.config<cr>" },
|
||||
{ "gq", "<cmd>FzfLua quickfix<cr>" },
|
||||
{ "gl", "<cmd>FzfLua loclist<cr>" },
|
||||
{ "<leader>GB", "<cmd>FzfLua git_branches<cr>" },
|
||||
{ "<leader>Gc", "<cmd>FzfLua git_commits<cr>" },
|
||||
{ "<leader>Gs", "<cmd>FzfLua git_status<cr>" },
|
||||
{
|
||||
"<leader>Gp",
|
||||
function() gh_picker("pr", "open") end,
|
||||
},
|
||||
{
|
||||
"<leader>Gi",
|
||||
function() gh_picker("issue", "open") end,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,102 +1,68 @@
|
|||
local function file_loc()
|
||||
local root = vim.trim(vim.fn.system('git rev-parse --show-toplevel'))
|
||||
if vim.v.shell_error ~= 0 or root == '' then
|
||||
return nil
|
||||
end
|
||||
local path = vim.api.nvim_buf_get_name(0)
|
||||
if path == '' or path:sub(1, #root + 1) ~= root .. '/' then
|
||||
return nil
|
||||
end
|
||||
return ('%s:%d'):format(path:sub(#root + 2), vim.fn.line('.'))
|
||||
end
|
||||
|
||||
local function gh_browse()
|
||||
if vim.fn.executable('gh') ~= 1 then
|
||||
vim.notify('gh CLI not found', vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
local loc = file_loc()
|
||||
if loc then
|
||||
vim.system({ 'gh', 'browse', loc })
|
||||
else
|
||||
vim.system({ 'gh', 'browse' })
|
||||
end
|
||||
end
|
||||
vim.pack.add({
|
||||
"https://github.com/lewis6991/gitsigns.nvim",
|
||||
"https://github.com/barrettruth/forge.nvim",
|
||||
"https://github.com/barrettruth/diffs.nvim",
|
||||
}, { load = function() end })
|
||||
|
||||
return {
|
||||
{
|
||||
'tpope/vim-fugitive',
|
||||
config = function()
|
||||
map('n', '<leader>gg', '<cmd>Git<cr><cmd>only<cr>')
|
||||
map('n', '<leader>gc', '<cmd>Git commit<cr>')
|
||||
map('n', '<leader>gp', '<cmd>Git push<cr>')
|
||||
map('n', '<leader>gl', '<cmd>Git pull<cr>')
|
||||
map('n', '<leader>gb', '<cmd>Git blame<cr>')
|
||||
map('n', '<leader>gd', '<cmd>Gvdiffsplit<cr>')
|
||||
map('n', '<leader>gr', '<cmd>Gread<cr>')
|
||||
map('n', '<leader>gw', '<cmd>Gwrite<cr>')
|
||||
map({ 'n', 'v' }, '<leader>go', gh_browse)
|
||||
end,
|
||||
},
|
||||
{
|
||||
'lewis6991/gitsigns.nvim',
|
||||
opts = {
|
||||
signs = {
|
||||
add = { text = '██' },
|
||||
change = { text = '██' },
|
||||
delete = { text = '▄▄' },
|
||||
topdelete = { text = '▀▀' },
|
||||
changedelete = { text = '██' },
|
||||
},
|
||||
signs_staged = {
|
||||
add = { text = '▓▓' },
|
||||
change = { text = '▓▓' },
|
||||
delete = { text = '▄▄' },
|
||||
topdelete = { text = '▀▀' },
|
||||
changedelete = { text = '▓▓' },
|
||||
},
|
||||
signs_staged_enable = true,
|
||||
{
|
||||
"lewis6991/gitsigns.nvim",
|
||||
event = "BufReadPre",
|
||||
after = function()
|
||||
require("gitsigns").setup {
|
||||
signs = {
|
||||
add = { text = "██" },
|
||||
change = { text = "██" },
|
||||
delete = { text = "▄▄" },
|
||||
topdelete = { text = "▀▀" },
|
||||
changedelete = { text = "██" },
|
||||
},
|
||||
config = function(_, opts)
|
||||
require('gitsigns').setup(opts)
|
||||
map('n', ']g', '<cmd>Gitsigns next_hunk<cr>')
|
||||
map('n', '[g', '<cmd>Gitsigns prev_hunk<cr>')
|
||||
map('n', '<leader>ghs', '<cmd>Gitsigns stage_hunk<cr>')
|
||||
map('n', '<leader>ghr', '<cmd>Gitsigns reset_hunk<cr>')
|
||||
map('n', '<leader>ghp', '<cmd>Gitsigns preview_hunk<cr>')
|
||||
map('n', '<leader>gB', '<cmd>Gitsigns toggle_current_line_blame<cr>')
|
||||
end,
|
||||
},
|
||||
{
|
||||
'barrettruth/forge.nvim',
|
||||
dependencies = { 'ibhagwan/fzf-lua' },
|
||||
init = function()
|
||||
vim.g.forge = vim.g.forge or {}
|
||||
end,
|
||||
config = function()
|
||||
map('n', '<c-t>', '<cmd>Forge<cr>', { desc = 'Forge picker' })
|
||||
end,
|
||||
},
|
||||
{
|
||||
'barrettruth/diffs.nvim',
|
||||
enabled = true,
|
||||
init = function()
|
||||
vim.g.diffs = {
|
||||
integrations = {
|
||||
fugitive = {
|
||||
enabled = true,
|
||||
horizontal = false,
|
||||
vertical = false,
|
||||
},
|
||||
},
|
||||
hide_prefix = true,
|
||||
highlights = {
|
||||
warn_max_lines = false,
|
||||
gutter = true,
|
||||
blend_alpha = 0.5,
|
||||
intra = { enabled = true },
|
||||
},
|
||||
}
|
||||
end,
|
||||
signs_staged = {
|
||||
add = { text = "▓▓" },
|
||||
change = { text = "▓▓" },
|
||||
delete = { text = "▄▄" },
|
||||
topdelete = { text = "▀▀" },
|
||||
changedelete = { text = "▓▓" },
|
||||
},
|
||||
signs_staged_enable = true,
|
||||
}
|
||||
|
||||
map("n", "]g", "<cmd>Gitsigns next_hunk<cr>")
|
||||
map("n", "[g", "<cmd>Gitsigns prev_hunk<cr>")
|
||||
map("n", "<leader>ghs", "<cmd>Gitsigns stage_hunk<cr>")
|
||||
map("n", "<leader>ghr", "<cmd>Gitsigns reset_hunk<cr>")
|
||||
map("n", "<leader>ghp", "<cmd>Gitsigns preview_hunk<cr>")
|
||||
map("n", "<leader>gB", "<cmd>Gitsigns toggle_current_line_blame<cr>")
|
||||
end,
|
||||
},
|
||||
{
|
||||
"barrettruth/forge.nvim",
|
||||
cmd = "Forge",
|
||||
before = function() vim.g.forge = vim.g.forge or {} end,
|
||||
after = function() pcall(vim.cmd.packadd, "fzf-lua") end,
|
||||
keys = {
|
||||
{ "<c-t>", "<cmd>Forge<cr>", desc = "Forge picker" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"barrettruth/diffs.nvim",
|
||||
before = function()
|
||||
vim.g.diffs = {
|
||||
integrations = {
|
||||
fugitive = {
|
||||
enabled = true,
|
||||
horizontal = false,
|
||||
vertical = false,
|
||||
},
|
||||
},
|
||||
hide_prefix = true,
|
||||
highlights = {
|
||||
warn_max_lines = false,
|
||||
gutter = true,
|
||||
blend_alpha = 0.5,
|
||||
intra = { enabled = true },
|
||||
},
|
||||
}
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/neovim/nvim-lspconfig",
|
||||
}, { load = function() end })
|
||||
|
||||
return {
|
||||
'neovim/nvim-lspconfig',
|
||||
lazy = false,
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +1,144 @@
|
|||
return {
|
||||
{
|
||||
'barrettruth/canola.nvim',
|
||||
branch = 'canola',
|
||||
dependencies = { 'nvim-tree/nvim-web-devicons' },
|
||||
init = function()
|
||||
vim.g.canola = {
|
||||
columns = { 'icon' },
|
||||
delete = { wipe = false, recursive = true },
|
||||
hidden = { enabled = false },
|
||||
keymaps = {
|
||||
['g?'] = { callback = 'actions.show_help', mode = 'n' },
|
||||
['<CR>'] = 'actions.select',
|
||||
['<C-v>'] = { callback = 'actions.select', opts = { vertical = true } },
|
||||
['<C-x>'] = { callback = 'actions.select', opts = { horizontal = true } },
|
||||
['<C-p>'] = 'actions.preview',
|
||||
['<C-c>'] = { callback = 'actions.close', mode = 'n' },
|
||||
['-'] = { callback = 'actions.parent', mode = 'n' },
|
||||
['g.'] = { callback = 'actions.toggle_hidden', mode = 'n' },
|
||||
['<C-t>'] = false,
|
||||
},
|
||||
}
|
||||
map('n', '-', '<cmd>Canola<cr>')
|
||||
map('n', '<leader>e', '<cmd>Canola<cr>')
|
||||
vim.pack.add({
|
||||
"https://github.com/barrettruth/canola.nvim",
|
||||
"https://github.com/barrettruth/canola-collection",
|
||||
}, { load = function() end })
|
||||
|
||||
local ns = vim.api.nvim_create_namespace('canola_git_trailing')
|
||||
local symbols = {
|
||||
M = { 'M', 'DiagnosticWarn' },
|
||||
A = { 'A', 'DiagnosticOk' },
|
||||
D = { 'D', 'DiagnosticError' },
|
||||
R = { 'R', 'DiagnosticWarn' },
|
||||
['?'] = { '?', 'DiagnosticInfo' },
|
||||
['!'] = { '!', 'Comment' },
|
||||
}
|
||||
|
||||
local function apply_git_status(buf)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then return end
|
||||
vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
||||
|
||||
local ok, canola = pcall(require, 'canola')
|
||||
if not ok then return end
|
||||
|
||||
local dir = canola.get_current_dir(buf)
|
||||
if not dir then return end
|
||||
|
||||
local git_ok, git = pcall(require, 'canola-git')
|
||||
if not git_ok then return end
|
||||
|
||||
local dir_cache = git._cache[dir]
|
||||
if not dir_cache or not dir_cache.status then return end
|
||||
|
||||
local lines = vim.api.nvim_buf_line_count(buf)
|
||||
for lnum = 0, lines - 1 do
|
||||
local entry = canola.get_entry_on_line(buf, lnum + 1)
|
||||
if entry then
|
||||
local status = dir_cache.status[entry.name]
|
||||
if status then
|
||||
local ch = status:sub(1, 1)
|
||||
if ch == ' ' then ch = status:sub(2, 2) end
|
||||
local sym = symbols[ch]
|
||||
if sym then
|
||||
vim.api.nvim_buf_set_extmark(buf, ns, lnum, 0, {
|
||||
virt_text = { { ' ' .. sym[1], sym[2] } },
|
||||
virt_text_pos = 'eol',
|
||||
invalidate = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd('User', {
|
||||
pattern = 'CanolaReadPost',
|
||||
callback = function(args)
|
||||
local buf = args.buf
|
||||
apply_git_status(buf)
|
||||
vim.defer_fn(function() apply_git_status(buf) end, 500)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
'barrettruth/canola-collection',
|
||||
dependencies = { 'barrettruth/canola.nvim' },
|
||||
},
|
||||
local ns = vim.api.nvim_create_namespace("canola_git_trailing")
|
||||
local symbols = {
|
||||
M = { "M", "DiagnosticWarn" },
|
||||
A = { "A", "DiagnosticOk" },
|
||||
D = { "D", "DiagnosticError" },
|
||||
R = { "R", "DiagnosticWarn" },
|
||||
["?"] = { "?", "DiagnosticInfo" },
|
||||
["!"] = { "!", "Comment" },
|
||||
}
|
||||
|
||||
local function apply_git_status(buf)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then return end
|
||||
vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
||||
|
||||
local ok, canola = pcall(require, "canola")
|
||||
if not ok then return end
|
||||
|
||||
local dir = canola.get_current_dir(buf)
|
||||
if not dir then return end
|
||||
|
||||
local git_ok, git = pcall(require, "canola-git")
|
||||
if not git_ok then return end
|
||||
|
||||
local dir_cache = git._cache[dir]
|
||||
if not dir_cache or not dir_cache.status then return end
|
||||
|
||||
local lines = vim.api.nvim_buf_line_count(buf)
|
||||
for lnum = 0, lines - 1 do
|
||||
local entry = canola.get_entry_on_line(buf, lnum + 1)
|
||||
if entry then
|
||||
local status = dir_cache.status[entry.name]
|
||||
if status then
|
||||
local ch = status:sub(1, 1)
|
||||
if ch == " " then ch = status:sub(2, 2) end
|
||||
local sym = symbols[ch]
|
||||
if sym then
|
||||
vim.api.nvim_buf_set_extmark(buf, ns, lnum, 0, {
|
||||
virt_text = { { " " .. sym[1], sym[2] } },
|
||||
virt_text_pos = "eol",
|
||||
invalidate = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
{
|
||||
"barrettruth/canola.nvim",
|
||||
cmd = "Canola",
|
||||
before = function()
|
||||
pcall(vim.cmd.packadd, "nvim-web-devicons")
|
||||
pcall(vim.cmd.packadd, "nonicons.nvim")
|
||||
|
||||
vim.g.canola = {
|
||||
columns = { "icon" },
|
||||
hidden = { enabled = false },
|
||||
highlights = { filename = {}, columns = true },
|
||||
save = "auto",
|
||||
extglob = true,
|
||||
delete = { wipe = false, recursive = true },
|
||||
float = { border = "single" },
|
||||
keymaps = {
|
||||
["g?"] = { callback = "actions.show_help", mode = "n" },
|
||||
["<CR>"] = "actions.select",
|
||||
["<C-v>"] = { callback = "actions.select", opts = { vertical = true } },
|
||||
["<C-x>"] = { callback = "actions.select", opts = { horizontal = true } },
|
||||
["<C-p>"] = "actions.preview",
|
||||
["<C-c>"] = { callback = "actions.close", mode = "n" },
|
||||
["-"] = { callback = "actions.parent", mode = "n" },
|
||||
["g."] = { callback = "actions.toggle_hidden", mode = "n" },
|
||||
["<C-t>"] = false,
|
||||
},
|
||||
}
|
||||
end,
|
||||
after = function()
|
||||
vim.cmd.packadd("canola-collection")
|
||||
|
||||
local augroup = vim.api.nvim_create_augroup("UserCanolaConfig", { clear = true })
|
||||
local detail_columns = { "git_status", "permissions", "owner", "size", "mtime" }
|
||||
local base_columns = vim.deepcopy(vim.g.canola.columns or {})
|
||||
local show_all = false
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
group = augroup,
|
||||
pattern = "canola",
|
||||
callback = function(args)
|
||||
local bufnr = args.buf
|
||||
|
||||
vim.keymap.set("n", "gC", function()
|
||||
show_all = not show_all
|
||||
require("canola").set_columns(show_all and detail_columns or base_columns)
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
desc = "toggle canola columns",
|
||||
})
|
||||
|
||||
vim.keymap.set("n", "gX", function()
|
||||
local canola = require("canola")
|
||||
local entry = canola.get_cursor_entry()
|
||||
local dir = canola.get_current_dir()
|
||||
if not entry or not dir then return end
|
||||
|
||||
vim.ui.input({ prompt = "chmod: ", default = "755" }, function(mode)
|
||||
if not mode then return end
|
||||
|
||||
vim.uv.fs_chmod(dir .. entry.name, tonumber(mode, 8), function(err)
|
||||
if err then
|
||||
vim.schedule(function() vim.notify(err, vim.log.levels.ERROR) end)
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule(function() require("canola.actions").refresh.callback() end)
|
||||
end)
|
||||
end)
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
desc = "chmod entry",
|
||||
})
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("User", {
|
||||
group = augroup,
|
||||
pattern = "CanolaReadPost",
|
||||
callback = function(args)
|
||||
local buf = args.buf
|
||||
apply_git_status(buf)
|
||||
vim.defer_fn(function() apply_git_status(buf) end, 500)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keys = {
|
||||
{ "-", "<cmd>Canola<cr>" },
|
||||
{ "<leader>e", "<cmd>Canola<cr>" },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,71 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/nvim-treesitter/nvim-treesitter",
|
||||
"https://github.com/nvim-treesitter/nvim-treesitter-textobjects",
|
||||
}, { load = function() end })
|
||||
|
||||
vim.api.nvim_create_autocmd("PackChanged", {
|
||||
callback = function(ev)
|
||||
local name, kind = ev.data.spec.name, ev.data.kind
|
||||
if kind == "delete" then return end
|
||||
if name == "nvim-treesitter" then vim.schedule(function() vim.cmd "TSUpdate all" end) end
|
||||
end,
|
||||
})
|
||||
|
||||
return {
|
||||
{
|
||||
'nvim-treesitter/nvim-treesitter',
|
||||
build = ':TSUpdate',
|
||||
dependencies = { 'nvim-treesitter/nvim-treesitter-textobjects' },
|
||||
config = function()
|
||||
require('nvim-treesitter-textobjects').setup({
|
||||
select = {
|
||||
enable = true,
|
||||
lookahead = true,
|
||||
keymaps = {
|
||||
['af'] = '@function.outer',
|
||||
['if'] = '@function.inner',
|
||||
['ac'] = '@class.outer',
|
||||
['ic'] = '@class.inner',
|
||||
['aa'] = '@parameter.outer',
|
||||
['ia'] = '@parameter.inner',
|
||||
['ai'] = '@conditional.outer',
|
||||
['ii'] = '@conditional.inner',
|
||||
['al'] = '@loop.outer',
|
||||
['il'] = '@loop.inner',
|
||||
['ab'] = '@block.outer',
|
||||
['ib'] = '@block.inner',
|
||||
},
|
||||
},
|
||||
move = {
|
||||
enable = true,
|
||||
set_jumps = true,
|
||||
goto_next_start = {
|
||||
[']f'] = '@function.outer',
|
||||
[']c'] = '@class.outer',
|
||||
[']a'] = '@parameter.inner',
|
||||
},
|
||||
goto_next_end = {
|
||||
[']F'] = '@function.outer',
|
||||
[']C'] = '@class.outer',
|
||||
},
|
||||
goto_previous_start = {
|
||||
['[f'] = '@function.outer',
|
||||
['[c'] = '@class.outer',
|
||||
['[a'] = '@parameter.inner',
|
||||
},
|
||||
goto_previous_end = {
|
||||
['[F'] = '@function.outer',
|
||||
['[C'] = '@class.outer',
|
||||
},
|
||||
},
|
||||
swap = {
|
||||
enable = true,
|
||||
swap_next = { ['<leader>sn'] = '@parameter.inner' },
|
||||
swap_previous = { ['<leader>sp'] = '@parameter.inner' },
|
||||
},
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
after = function() require("nvim-treesitter").setup { auto_install = true } end,
|
||||
},
|
||||
{
|
||||
"nvim-treesitter/nvim-treesitter-textobjects",
|
||||
after = function()
|
||||
require("nvim-treesitter-textobjects").setup {
|
||||
select = {
|
||||
enable = true,
|
||||
lookahead = true,
|
||||
keymaps = {
|
||||
["af"] = "@function.outer",
|
||||
["if"] = "@function.inner",
|
||||
["ac"] = "@class.outer",
|
||||
["ic"] = "@class.inner",
|
||||
["aa"] = "@parameter.outer",
|
||||
["ia"] = "@parameter.inner",
|
||||
["ai"] = "@conditional.outer",
|
||||
["ii"] = "@conditional.inner",
|
||||
["al"] = "@loop.outer",
|
||||
["il"] = "@loop.inner",
|
||||
["ab"] = "@block.outer",
|
||||
["ib"] = "@block.inner",
|
||||
},
|
||||
},
|
||||
move = {
|
||||
enable = true,
|
||||
set_jumps = true,
|
||||
goto_next_start = {
|
||||
["]f"] = "@function.outer",
|
||||
["]c"] = "@class.outer",
|
||||
["]a"] = "@parameter.inner",
|
||||
},
|
||||
goto_next_end = {
|
||||
["]F"] = "@function.outer",
|
||||
["]C"] = "@class.outer",
|
||||
},
|
||||
goto_previous_start = {
|
||||
["[f"] = "@function.outer",
|
||||
["[c"] = "@class.outer",
|
||||
["[a"] = "@parameter.inner",
|
||||
},
|
||||
goto_previous_end = {
|
||||
["[F"] = "@function.outer",
|
||||
["[C"] = "@class.outer",
|
||||
},
|
||||
},
|
||||
swap = {
|
||||
enable = true,
|
||||
swap_next = { ["<leader>sn"] = "@parameter.inner" },
|
||||
swap_previous = { ["<leader>sp"] = "@parameter.inner" },
|
||||
},
|
||||
}
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,29 @@
|
|||
vim.pack.add({
|
||||
"https://github.com/harivansh-afk/cozybox.nvim",
|
||||
"https://github.com/nvim-lualine/lualine.nvim",
|
||||
"https://github.com/barrettruth/nonicons.nvim",
|
||||
"https://github.com/nvim-tree/nvim-web-devicons",
|
||||
}, { load = function() end })
|
||||
|
||||
return {
|
||||
{
|
||||
"harivansh-afk/cozybox.nvim",
|
||||
lazy = false,
|
||||
priority = 1000,
|
||||
config = function() require("theme").setup() end,
|
||||
after = function() require("theme").setup() end,
|
||||
},
|
||||
{
|
||||
"nvim-tree/nvim-web-devicons",
|
||||
},
|
||||
{
|
||||
"barrettruth/nonicons.nvim",
|
||||
before = function() vim.cmd.packadd "nvim-web-devicons" end,
|
||||
},
|
||||
{
|
||||
"nvim-lualine/lualine.nvim",
|
||||
dependencies = { "nvim-tree/nvim-web-devicons" },
|
||||
config = function()
|
||||
local theme_status = function() return require("theme").statusline_label() end
|
||||
before = function()
|
||||
vim.cmd.packadd "nvim-web-devicons"
|
||||
pcall(vim.cmd.packadd, "nonicons.nvim")
|
||||
end,
|
||||
after = function()
|
||||
local theme = {
|
||||
normal = {
|
||||
a = { gui = "bold" },
|
||||
|
|
@ -24,6 +38,7 @@ return {
|
|||
a = { gui = "bold" },
|
||||
},
|
||||
}
|
||||
|
||||
require("lualine").setup {
|
||||
options = {
|
||||
icons_enabled = false,
|
||||
|
|
@ -42,8 +57,4 @@ return {
|
|||
}
|
||||
end,
|
||||
},
|
||||
{
|
||||
"barrettruth/nonicons.nvim",
|
||||
dependencies = { "nvim-tree/nvim-web-devicons" },
|
||||
},
|
||||
}
|
||||
|
|
|
|||
96
config/nvim/nvim-pack-lock.json
Normal file
96
config/nvim/nvim-pack-lock.json
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"plugins": {
|
||||
"blink.cmp": {
|
||||
"rev": "451168851e8e2466bc97ee3e026c3dcb9141ce07",
|
||||
"src": "https://github.com/saghen/blink.cmp"
|
||||
},
|
||||
"canola-collection": {
|
||||
"rev": "888ee61c54873e0c57df07d35e38284e23bb978c",
|
||||
"src": "https://github.com/barrettruth/canola-collection"
|
||||
},
|
||||
"canola.nvim": {
|
||||
"rev": "4a0dd41ca39793342177b2cdb8e784243da5a936",
|
||||
"src": "https://github.com/barrettruth/canola.nvim"
|
||||
},
|
||||
"cozybox.nvim": {
|
||||
"rev": "be246810d74e3030cc5790685db3b9b8aacda5e3",
|
||||
"src": "https://github.com/harivansh-afk/cozybox.nvim"
|
||||
},
|
||||
"diffs.nvim": {
|
||||
"rev": "0cb16a0e2384f1d3dd6330f6ea517de8e07aa8e8",
|
||||
"src": "https://github.com/barrettruth/diffs.nvim"
|
||||
},
|
||||
"flash.nvim": {
|
||||
"rev": "fcea7ff883235d9024dc41e638f164a450c14ca2",
|
||||
"src": "https://github.com/folke/flash.nvim"
|
||||
},
|
||||
"forge.nvim": {
|
||||
"rev": "0dc433a32c1dac7bdfc313cf73070f03f27b2ef2",
|
||||
"src": "https://github.com/barrettruth/forge.nvim"
|
||||
},
|
||||
"fzf-lua": {
|
||||
"rev": "bde73a6886b607246095aa59f396de5e0d036890",
|
||||
"src": "https://github.com/ibhagwan/fzf-lua"
|
||||
},
|
||||
"gitsigns.nvim": {
|
||||
"rev": "50c205548d8b037b7ff6378fca6d21146f0b6161",
|
||||
"src": "https://github.com/lewis6991/gitsigns.nvim"
|
||||
},
|
||||
"lualine.nvim": {
|
||||
"rev": "47f91c416daef12db467145e16bed5bbfe00add8",
|
||||
"src": "https://github.com/nvim-lualine/lualine.nvim"
|
||||
},
|
||||
"lz.n": {
|
||||
"rev": "3a696418821fa8e4963a0a59dd1f8d40fedb6824",
|
||||
"src": "https://github.com/lumen-oss/lz.n"
|
||||
},
|
||||
"nonicons.nvim": {
|
||||
"rev": "2c5fad40a79d80338b49e6fbd3db9b2c1141a4ed",
|
||||
"src": "https://github.com/barrettruth/nonicons.nvim"
|
||||
},
|
||||
"nvim-autopairs": {
|
||||
"rev": "59bce2eef357189c3305e25bc6dd2d138c1683f5",
|
||||
"src": "https://github.com/windwp/nvim-autopairs"
|
||||
},
|
||||
"nvim-lspconfig": {
|
||||
"rev": "16812abf0e8d8175155f26143a8504e8253e92b0",
|
||||
"src": "https://github.com/neovim/nvim-lspconfig"
|
||||
},
|
||||
"nvim-surround": {
|
||||
"rev": "61319d4bd1c5e336e197defa15bd104c51f0fb29",
|
||||
"src": "https://github.com/kylechui/nvim-surround"
|
||||
},
|
||||
"nvim-treesitter": {
|
||||
"rev": "cf12346a3414fa1b06af75c79faebe7f76df080a",
|
||||
"src": "https://github.com/nvim-treesitter/nvim-treesitter"
|
||||
},
|
||||
"nvim-treesitter-textobjects": {
|
||||
"rev": "93d60a475f0b08a8eceb99255863977d3a25f310",
|
||||
"src": "https://github.com/nvim-treesitter/nvim-treesitter-textobjects"
|
||||
},
|
||||
"nvim-ufo": {
|
||||
"rev": "ab3eb124062422d276fae49e0dd63b3ad1062cfc",
|
||||
"src": "https://github.com/kevinhwang91/nvim-ufo"
|
||||
},
|
||||
"nvim-web-devicons": {
|
||||
"rev": "d7462543c9e366c0d196c7f67a945eaaf5d99414",
|
||||
"src": "https://github.com/nvim-tree/nvim-web-devicons"
|
||||
},
|
||||
"pending.nvim": {
|
||||
"rev": "e58cf6665b2d12cc63e1fd7a87169a9d2c20f7b5",
|
||||
"src": "https://github.com/barrettruth/pending.nvim"
|
||||
},
|
||||
"preview.nvim": {
|
||||
"rev": "ddf9b14c7f0fe00bb47833304625b648a97018a6",
|
||||
"src": "https://github.com/barrettruth/preview.nvim"
|
||||
},
|
||||
"promise-async": {
|
||||
"rev": "119e8961014c9bfaf1487bf3c2a393d254f337e2",
|
||||
"src": "https://github.com/kevinhwang91/promise-async"
|
||||
},
|
||||
"vim-fugitive": {
|
||||
"rev": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0",
|
||||
"src": "https://github.com/tpope/vim-fugitive"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,47 @@
|
|||
local api = vim.api
|
||||
local augroup = api.nvim_create_augroup('UserAutocmds', { clear = true })
|
||||
local augroup = api.nvim_create_augroup("UserAutocmds", { clear = true })
|
||||
|
||||
api.nvim_create_autocmd('TextYankPost', {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
vim.highlight.on_yank({ higroup = 'Visual', timeout = 200 })
|
||||
end,
|
||||
local function maybe_load_canola(bufnr)
|
||||
local name = api.nvim_buf_get_name(bufnr)
|
||||
if name == "" or vim.bo[bufnr].filetype == "canola" or vim.fn.isdirectory(name) == 0 then return end
|
||||
|
||||
pcall(vim.cmd.packadd, "canola.nvim")
|
||||
pcall(vim.cmd, "silent keepalt Canola " .. vim.fn.fnameescape(name))
|
||||
end
|
||||
|
||||
api.nvim_create_autocmd("TextYankPost", {
|
||||
group = augroup,
|
||||
callback = function() vim.highlight.on_yank { higroup = "Visual", timeout = 200 } end,
|
||||
})
|
||||
|
||||
api.nvim_create_autocmd('BufReadPost', {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
if ({ gitcommit = true, gitrebase = true })[vim.bo.filetype] then
|
||||
return
|
||||
end
|
||||
local mark = api.nvim_buf_get_mark(0, '"')
|
||||
if mark[1] > 0 and mark[1] <= api.nvim_buf_line_count(0) then
|
||||
pcall(api.nvim_win_set_cursor, 0, mark)
|
||||
end
|
||||
end,
|
||||
api.nvim_create_autocmd("BufReadPost", {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
if ({ gitcommit = true, gitrebase = true })[vim.bo.filetype] then return end
|
||||
local mark = api.nvim_buf_get_mark(0, '"')
|
||||
if mark[1] > 0 and mark[1] <= api.nvim_buf_line_count(0) then pcall(api.nvim_win_set_cursor, 0, mark) end
|
||||
end,
|
||||
})
|
||||
|
||||
api.nvim_create_autocmd('VimResized', {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
local tab = vim.fn.tabpagenr()
|
||||
vim.cmd('tabdo wincmd =')
|
||||
vim.cmd('tabnext ' .. tab)
|
||||
end,
|
||||
api.nvim_create_autocmd("BufEnter", {
|
||||
group = augroup,
|
||||
nested = true,
|
||||
callback = function(args)
|
||||
if vim.v.vim_did_enter == 1 then maybe_load_canola(args.buf) end
|
||||
end,
|
||||
})
|
||||
|
||||
api.nvim_create_autocmd("VimEnter", {
|
||||
group = augroup,
|
||||
nested = true,
|
||||
callback = function() maybe_load_canola(0) end,
|
||||
})
|
||||
|
||||
api.nvim_create_autocmd("VimResized", {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
local tab = vim.fn.tabpagenr()
|
||||
vim.cmd "tabdo wincmd ="
|
||||
vim.cmd("tabnext " .. tab)
|
||||
end,
|
||||
})
|
||||
|
|
|
|||
42
config/nvim/plugin/git.lua
Normal file
42
config/nvim/plugin/git.lua
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
vim.pack.add({
|
||||
'https://github.com/tpope/vim-fugitive',
|
||||
})
|
||||
|
||||
local function file_loc()
|
||||
local root = vim.trim(vim.fn.system('git rev-parse --show-toplevel'))
|
||||
if vim.v.shell_error ~= 0 or root == '' then
|
||||
return nil
|
||||
end
|
||||
|
||||
local path = vim.api.nvim_buf_get_name(0)
|
||||
if path == '' or path:sub(1, #root + 1) ~= root .. '/' then
|
||||
return nil
|
||||
end
|
||||
|
||||
return ('%s:%d'):format(path:sub(#root + 2), vim.fn.line('.'))
|
||||
end
|
||||
|
||||
local function gh_browse()
|
||||
if vim.fn.executable('gh') ~= 1 then
|
||||
vim.notify('gh CLI not found', vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local loc = file_loc()
|
||||
if loc then
|
||||
vim.system({ 'gh', 'browse', loc })
|
||||
else
|
||||
vim.system({ 'gh', 'browse' })
|
||||
end
|
||||
end
|
||||
|
||||
map('n', '<C-g>', '<cmd>Git<cr><cmd>only<cr>')
|
||||
map('n', '<leader>gg', '<cmd>Git<cr><cmd>only<cr>')
|
||||
map('n', '<leader>gc', '<cmd>Git commit<cr>')
|
||||
map('n', '<leader>gp', '<cmd>Git push<cr>')
|
||||
map('n', '<leader>gl', '<cmd>Git pull<cr>')
|
||||
map('n', '<leader>gb', '<cmd>Git blame<cr>')
|
||||
map('n', '<leader>gd', '<cmd>Gvdiffsplit<cr>')
|
||||
map('n', '<leader>gr', '<cmd>Gread<cr>')
|
||||
map('n', '<leader>gw', '<cmd>Gwrite<cr>')
|
||||
map({ 'n', 'v' }, '<leader>go', gh_browse)
|
||||
|
|
@ -1,21 +1,20 @@
|
|||
map('n', '<leader>w', '<cmd>w<cr>')
|
||||
map('n', '<leader>q', '<cmd>q<cr>')
|
||||
map('n', '<C-g>', '<cmd>Git<cr><cmd>only<cr>')
|
||||
map("n", "<leader>w", "<cmd>w<cr>")
|
||||
map("n", "<leader>q", "<cmd>q<cr>")
|
||||
|
||||
map('n', '<Tab>', '<cmd>bnext<cr>')
|
||||
map('n', '<S-Tab>', '<cmd>bprev<cr>')
|
||||
map('n', '<leader>x', '<cmd>bdelete<cr>')
|
||||
map('n', '<leader>b', '<cmd>enew<cr>')
|
||||
map("n", "<Tab>", "<cmd>bnext<cr>")
|
||||
map("n", "<S-Tab>", "<cmd>bprev<cr>")
|
||||
map("n", "<leader>x", "<cmd>bdelete<cr>")
|
||||
map("n", "<leader>b", "<cmd>enew<cr>")
|
||||
|
||||
map('n', '<C-h>', '<C-w>h')
|
||||
map('n', '<C-j>', '<C-w>j')
|
||||
map('n', '<C-k>', '<C-w>k')
|
||||
map('n', '<C-l>', '<C-w>l')
|
||||
map("n", "<C-h>", "<C-w>h")
|
||||
map("n", "<C-j>", "<C-w>j")
|
||||
map("n", "<C-k>", "<C-w>k")
|
||||
map("n", "<C-l>", "<C-w>l")
|
||||
|
||||
map('n', 'J', 'mzJ`z')
|
||||
map('x', 'x', '"_x')
|
||||
map('x', 'p', '"_dP')
|
||||
map('n', '<Esc>', '<cmd>nohlsearch<cr>')
|
||||
map('n', '<leader>t', '<cmd>setlocal wrap!<cr>')
|
||||
map("n", "J", "mzJ`z")
|
||||
map("x", "x", '"_x')
|
||||
map("x", "p", '"_dP')
|
||||
map("n", "<Esc>", "<cmd>nohlsearch<cr>")
|
||||
map("n", "<leader>t", "<cmd>setlocal wrap!<cr>")
|
||||
|
||||
map('t', '<Esc>', '<C-\\><C-n>')
|
||||
map("t", "<Esc>", "<C-\\><C-n>")
|
||||
|
|
|
|||
60
flake.lock
generated
60
flake.lock
generated
|
|
@ -76,6 +76,27 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"neovim-nightly",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772408722,
|
||||
"narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
|
@ -153,6 +174,44 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"neovim-nightly": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts_2",
|
||||
"neovim-src": "neovim-src",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1774915815,
|
||||
"narHash": "sha256-LocQzkSjVS4G0AKMBiEIVdBKCNTMZXQFjQMWFId4Jpg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "neovim-nightly-overlay",
|
||||
"rev": "9001416dc5d0ca24c8e4b5a44bfe7cd6fbeb1dd1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "neovim-nightly-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"neovim-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1774915197,
|
||||
"narHash": "sha256-yor+eo8CVi7wBp7CjAMQnVoK+m197gsl7MvUzaqicns=",
|
||||
"owner": "neovim",
|
||||
"repo": "neovim",
|
||||
"rev": "dbc4800dda2b0dc3290dc79955f857256e0694e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "neovim",
|
||||
"repo": "neovim",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-darwin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
|
@ -264,6 +323,7 @@
|
|||
"flake-parts": "flake-parts",
|
||||
"googleworkspace-cli": "googleworkspace-cli",
|
||||
"home-manager": "home-manager",
|
||||
"neovim-nightly": "neovim-nightly",
|
||||
"nix-darwin": "nix-darwin",
|
||||
"nix-homebrew": "nix-homebrew",
|
||||
"nixpkgs": "nixpkgs",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@
|
|||
url = "github:nix-community/disko";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
neovim-nightly = {
|
||||
url = "github:nix-community/neovim-nightly-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
|
|
|
|||
|
|
@ -8,10 +8,14 @@ let
|
|||
nvimConfig = lib.cleanSourceWith {
|
||||
src = ../config/nvim;
|
||||
filter =
|
||||
path: type: builtins.baseNameOf path != ".git" && builtins.baseNameOf path != "lazy-lock.json";
|
||||
path: type:
|
||||
let
|
||||
baseName = builtins.baseNameOf path;
|
||||
in
|
||||
baseName != ".git" && baseName != "lazy-lock.json" && baseName != "nvim-pack-lock.json";
|
||||
};
|
||||
lazyLockSeed = ../config/nvim/lazy-lock.json;
|
||||
lazyLockPath = "${config.xdg.stateHome}/nvim/lazy-lock.json";
|
||||
packLockSeed = ../config/nvim/nvim-pack-lock.json;
|
||||
packLockPath = "${config.xdg.stateHome}/nvim/nvim-pack-lock.json";
|
||||
python = pkgs.writeShellScriptBin "python" ''
|
||||
exec ${pkgs.python3}/bin/python3 "$@"
|
||||
'';
|
||||
|
|
@ -60,13 +64,15 @@ in
|
|||
recursive = true;
|
||||
};
|
||||
|
||||
home.activation.seedNvimLazyLock = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
xdg.configFile."nvim/nvim-pack-lock.json".source = config.lib.file.mkOutOfStoreSymlink packLockPath;
|
||||
|
||||
home.activation.seedNvimPackLock = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
state_dir="${config.xdg.stateHome}/nvim"
|
||||
lockfile="${lazyLockPath}"
|
||||
lockfile="${packLockPath}"
|
||||
|
||||
if [ ! -e "$lockfile" ]; then
|
||||
mkdir -p "$state_dir"
|
||||
cp ${lazyLockSeed} "$lockfile"
|
||||
cp ${packLockSeed} "$lockfile"
|
||||
chmod u+w "$lockfile"
|
||||
fi
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@
|
|||
setopt localoptions noshwordsplit
|
||||
unset prompt_pure_async_render_requested
|
||||
|
||||
prompt_pure_set_colors
|
||||
_codex_pure_default_arrow=$prompt_pure_colors[git:arrow]
|
||||
_codex_pure_default_success=$prompt_pure_colors[prompt:success]
|
||||
|
||||
typeset -g prompt_pure_git_branch_color=$prompt_pure_colors[git:branch]
|
||||
[[ -n ''${prompt_pure_git_last_dirty_check_timestamp+x} ]] && prompt_pure_git_branch_color=$prompt_pure_colors[git:branch:cached]
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,89 @@
|
|||
}:
|
||||
let
|
||||
packageSets = import ../../lib/package-sets.nix { inherit inputs lib pkgs; };
|
||||
sandboxDomain = "netty.harivan.sh";
|
||||
forgejoDomain = "git.harivan.sh";
|
||||
forgejoApiUrl = "http://127.0.0.1:3000";
|
||||
sandboxAgentPackage = pkgs.callPackage ../../pkgs/sandbox-agent { };
|
||||
sandboxAgentDir = "/home/${username}/.config/sandbox-agent";
|
||||
sandboxAgentPath =
|
||||
packageSets.core
|
||||
++ packageSets.extras
|
||||
++ [
|
||||
pkgs.bubblewrap
|
||||
pkgs.git
|
||||
pkgs.nodejs
|
||||
pkgs.pnpm
|
||||
sandboxAgentPackage
|
||||
];
|
||||
sandboxAgentEnvCheck = pkgs.writeShellScript "sandbox-agent-env-check" ''
|
||||
[ -f "${sandboxAgentDir}/agent.env" ] && [ -f "${sandboxAgentDir}/public.env" ]
|
||||
'';
|
||||
sandboxAgentWrapper = pkgs.writeShellScript "sandbox-agent-public" ''
|
||||
set -euo pipefail
|
||||
set -a
|
||||
. "${sandboxAgentDir}/public.env"
|
||||
. "${sandboxAgentDir}/agent.env"
|
||||
set +a
|
||||
exec sandbox-agent server \
|
||||
--host 127.0.0.1 \
|
||||
--port "''${SANDBOX_AGENT_PORT}" \
|
||||
--token "''${SANDBOX_AGENT_TOKEN}"
|
||||
'';
|
||||
sandboxCorsProxy = pkgs.writeText "sandbox-agent-cors-proxy.mjs" ''
|
||||
import http from "node:http";
|
||||
|
||||
const listenHost = "127.0.0.1";
|
||||
const listenPort = 2468;
|
||||
const targetHost = "127.0.0.1";
|
||||
const targetPort = 2470;
|
||||
|
||||
function setCorsHeaders(headers, req) {
|
||||
headers["access-control-allow-origin"] = "*";
|
||||
headers["access-control-allow-methods"] = "GET,POST,PUT,PATCH,DELETE,OPTIONS";
|
||||
headers["access-control-allow-headers"] =
|
||||
req.headers["access-control-request-headers"] || "authorization,content-type";
|
||||
headers["access-control-max-age"] = "86400";
|
||||
return headers;
|
||||
}
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.method === "OPTIONS") {
|
||||
res.writeHead(204, setCorsHeaders({}, req));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const proxyReq = http.request(
|
||||
{
|
||||
host: targetHost,
|
||||
port: targetPort,
|
||||
method: req.method,
|
||||
path: req.url,
|
||||
headers: {
|
||||
...req.headers,
|
||||
host: `''${targetHost}:''${targetPort}`,
|
||||
},
|
||||
},
|
||||
(proxyRes) => {
|
||||
res.writeHead(
|
||||
proxyRes.statusCode || 502,
|
||||
setCorsHeaders({ ...proxyRes.headers }, req),
|
||||
);
|
||||
proxyRes.pipe(res);
|
||||
},
|
||||
);
|
||||
|
||||
proxyReq.on("error", () => {
|
||||
res.writeHead(502, setCorsHeaders({ "content-type": "text/plain" }, req));
|
||||
res.end("Upstream request failed");
|
||||
});
|
||||
|
||||
req.pipe(proxyReq);
|
||||
});
|
||||
|
||||
server.listen(listenPort, listenHost);
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
|
|
@ -103,6 +186,7 @@ in
|
|||
pkgs.bubblewrap
|
||||
pkgs.pnpm
|
||||
pkgs.nodejs
|
||||
sandboxAgentPackage
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
|
|
@ -122,13 +206,13 @@ in
|
|||
recommendedTlsSettings = true;
|
||||
clientMaxBodySize = "512m";
|
||||
|
||||
virtualHosts."sandbox.example.dev" = {
|
||||
virtualHosts.${sandboxDomain} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".proxyPass = "http://127.0.0.1:2470";
|
||||
};
|
||||
|
||||
virtualHosts."git.example.dev" = {
|
||||
virtualHosts.${forgejoDomain} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".proxyPass = "http://127.0.0.1:3000";
|
||||
|
|
@ -150,10 +234,10 @@ in
|
|||
group = "git";
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = "git.example.dev";
|
||||
ROOT_URL = "https://git.example.dev/";
|
||||
DOMAIN = forgejoDomain;
|
||||
ROOT_URL = "https://${forgejoDomain}/";
|
||||
HTTP_PORT = 3000;
|
||||
SSH_DOMAIN = "git.example.dev";
|
||||
SSH_DOMAIN = forgejoDomain;
|
||||
};
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
session.COOKIE_SECURE = true;
|
||||
|
|
@ -177,53 +261,87 @@ in
|
|||
pkgs.curl
|
||||
pkgs.jq
|
||||
pkgs.coreutils
|
||||
pkgs.gnused
|
||||
];
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
# Fetch all GitHub repos
|
||||
api_call() {
|
||||
local response http_code body
|
||||
response=$(curl -sS -w "\n%{http_code}" "$@")
|
||||
http_code=$(printf '%s\n' "$response" | tail -n1)
|
||||
body=$(printf '%s\n' "$response" | sed '$d')
|
||||
if [ "$http_code" -ge 400 ]; then
|
||||
printf '[forgejo-mirror-sync] HTTP %s\n' "$http_code" >&2
|
||||
printf '%s\n' "$body" >&2
|
||||
return 1
|
||||
fi
|
||||
printf '%s' "$body"
|
||||
}
|
||||
|
||||
gh_user=$(api_call -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/user" | jq -r '.login')
|
||||
|
||||
repos_file=$(mktemp)
|
||||
trap 'rm -f "$repos_file"' EXIT
|
||||
|
||||
page=1
|
||||
repos=""
|
||||
while true; do
|
||||
batch=$(curl -sf -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/user/repos?per_page=100&page=$page&affiliation=owner")
|
||||
count=$(echo "$batch" | jq length)
|
||||
batch=$(api_call -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/user/repos?per_page=100&page=$page&visibility=all&affiliation=owner,organization_member")
|
||||
count=$(printf '%s' "$batch" | jq length)
|
||||
[ "$count" -eq 0 ] && break
|
||||
repos="$repos$batch"
|
||||
printf '%s' "$batch" | jq -r '.[] | [.full_name, .clone_url] | @tsv' >> "$repos_file"
|
||||
page=$((page + 1))
|
||||
done
|
||||
|
||||
echo "$repos" | jq -r '.[].clone_url' | while read -r clone_url; do
|
||||
repo_name=$(basename "$clone_url" .git)
|
||||
sort -u "$repos_file" -o "$repos_file"
|
||||
|
||||
# Check if mirror already exists in Forgejo
|
||||
status=$(curl -sf -o /dev/null -w '%{http_code}' \
|
||||
while IFS=$'\t' read -r full_name clone_url; do
|
||||
repo_owner="''${full_name%%/*}"
|
||||
repo_name="''${full_name#*/}"
|
||||
|
||||
if [ "$repo_owner" = "$gh_user" ]; then
|
||||
forgejo_repo_name="$repo_name"
|
||||
else
|
||||
forgejo_repo_name="$repo_owner--$repo_name"
|
||||
fi
|
||||
|
||||
status=$(curl -sS -o /dev/null -w '%{http_code}' \
|
||||
-H "Authorization: token $FORGEJO_TOKEN" \
|
||||
"$FORGEJO_URL/api/v1/repos/$FORGEJO_OWNER/$repo_name")
|
||||
"${forgejoApiUrl}/api/v1/repos/$FORGEJO_OWNER/$forgejo_repo_name" || true)
|
||||
|
||||
if [ "$status" = "404" ]; then
|
||||
# Create mirror
|
||||
curl -sf -X POST \
|
||||
api_call -X POST \
|
||||
-H "Authorization: token $FORGEJO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"$FORGEJO_URL/api/v1/repos/migrate" \
|
||||
-d "{
|
||||
\"clone_addr\": \"$clone_url\",
|
||||
\"auth_token\": \"$GITHUB_TOKEN\",
|
||||
\"uid\": $(curl -sf -H "Authorization: token $FORGEJO_TOKEN" "$FORGEJO_URL/api/v1/user" | jq .id),
|
||||
\"repo_name\": \"$repo_name\",
|
||||
\"mirror\": true,
|
||||
\"service\": \"github\"
|
||||
}"
|
||||
echo "Created mirror: $repo_name"
|
||||
"${forgejoApiUrl}/api/v1/repos/migrate" \
|
||||
-d "$(jq -n \
|
||||
--arg addr "$clone_url" \
|
||||
--arg name "$forgejo_repo_name" \
|
||||
--arg owner "$FORGEJO_OWNER" \
|
||||
--arg token "$GITHUB_TOKEN" \
|
||||
'{
|
||||
clone_addr: $addr,
|
||||
repo_name: $name,
|
||||
repo_owner: $owner,
|
||||
mirror: true,
|
||||
auth_token: $token,
|
||||
service: "github"
|
||||
}')" \
|
||||
> /dev/null
|
||||
echo "Created mirror: $full_name -> $FORGEJO_OWNER/$forgejo_repo_name"
|
||||
else
|
||||
# Trigger sync on existing mirror
|
||||
curl -sf -X POST \
|
||||
if ! api_call -X POST \
|
||||
-H "Authorization: token $FORGEJO_TOKEN" \
|
||||
"$FORGEJO_URL/api/v1/repos/$FORGEJO_OWNER/$repo_name/mirror-sync" || true
|
||||
echo "Synced mirror: $repo_name"
|
||||
"${forgejoApiUrl}/api/v1/repos/$FORGEJO_OWNER/$forgejo_repo_name/mirror-sync" \
|
||||
> /dev/null; then
|
||||
echo "Failed mirror sync: $full_name -> $FORGEJO_OWNER/$forgejo_repo_name" >&2
|
||||
continue
|
||||
fi
|
||||
echo "Synced mirror: $full_name -> $FORGEJO_OWNER/$forgejo_repo_name"
|
||||
fi
|
||||
done
|
||||
done < "$repos_file"
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -239,14 +357,17 @@ in
|
|||
# --- Sandbox Agent (declarative systemd services) ---
|
||||
systemd.services.sandbox-agent = {
|
||||
description = "Sandbox Agent";
|
||||
after = [ "network.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = sandboxAgentPath;
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = username;
|
||||
Group = "users";
|
||||
EnvironmentFile = "/home/${username}/.config/sandbox-agent/agent.env";
|
||||
ExecStart = "/home/${username}/.local/bin/sandbox-agent";
|
||||
WorkingDirectory = "/home/${username}";
|
||||
ExecCondition = sandboxAgentEnvCheck;
|
||||
ExecStart = sandboxAgentWrapper;
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
};
|
||||
|
|
@ -255,12 +376,15 @@ in
|
|||
systemd.services.sandbox-cors-proxy = {
|
||||
description = "Sandbox CORS Proxy";
|
||||
after = [ "sandbox-agent.service" ];
|
||||
requires = [ "sandbox-agent.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = username;
|
||||
Group = "users";
|
||||
ExecStart = "${pkgs.nodejs}/bin/node /home/${username}/.config/sandbox-agent/cors-proxy.js";
|
||||
WorkingDirectory = "/home/${username}";
|
||||
ExecCondition = sandboxAgentEnvCheck;
|
||||
ExecStart = "${pkgs.nodejs}/bin/node ${sandboxCorsProxy}";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
};
|
||||
|
|
|
|||
17
leverage.md
Normal file
17
leverage.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Nix Leveraging
|
||||
|
||||
[flake.nix](./flake.nix) is the root lever: one flake, one lockfile, one graph for both macOS and Linux. [modules/hosts/darwin.nix](./modules/hosts/darwin.nix) composes `nix-darwin`, `home-manager`, and `nix-homebrew`; [modules/hosts/netty.nix](./modules/hosts/netty.nix) composes `nixosSystem`, `disko`, and `home-manager`. The point is not “using Nix”; it is collapsing laptop state and VPS state into one reproducible interface.
|
||||
|
||||
[modules/nixpkgs.nix](./modules/nixpkgs.nix) and [lib/hosts.nix](./lib/hosts.nix) are the next leverage layer. They define the global `username`, per-host metadata, feature flags, and the `specialArgs` boundary. That removes random `isDarwin` checks from leaf modules and turns host differences into data.
|
||||
|
||||
[lib/package-sets.nix](./lib/package-sets.nix), [modules/base.nix](./modules/base.nix), [modules/packages.nix](./modules/packages.nix), and [modules/homebrew.nix](./modules/homebrew.nix) are the package policy. `core`, `extras`, and `fonts` give one place to reason about the machine surface; custom inputs like `googleworkspace-cli`, `claude-code-nix`, `OpenSpec`, `neovim-nightly`, `nix-homebrew`, and `disko` are pinned in [flake.nix](./flake.nix) instead of installed ad hoc.
|
||||
|
||||
[home/default.nix](./home/default.nix) and [home/common.nix](./home/common.nix) turn Home Manager into the userland control plane. [home/xdg.nix](./home/xdg.nix) pushes Rust, Go, Node, Python, AWS, Claude, npm, wget, psql, and sqlite into XDG paths; [home/security.nix](./home/security.nix) fixes SSH and GPG permissions on activation; [home/migration.nix](./home/migration.nix) cleans legacy `~/dots` links during the cutover instead of relying on manual cleanup.
|
||||
|
||||
[lib/theme.nix](./lib/theme.nix), [home/ghostty.nix](./home/ghostty.nix), [home/tmux.nix](./home/tmux.nix), [home/zsh.nix](./home/zsh.nix), and [home/scripts.nix](./home/scripts.nix) are the ergonomic leverage. One palette renders Ghostty, tmux, fzf, zsh highlights, bat, and delta. The generated `theme` script hot-swaps light/dark across those surfaces. tmux gets session restore, directory-based window names, and a generated session list; zsh gets vi mode, cursor-shape switching, XDG history, prompt theming, and deterministic PATH assembly.
|
||||
|
||||
[home/nvim.nix](./home/nvim.nix), [home/codex.nix](./home/codex.nix), [home/claude.nix](./home/claude.nix), and [home/skills.nix](./home/skills.nix) are the agent/editor layer. Neovim is pinned with the nightly overlay and seeded lockfile state; Codex and Claude configs are repo-owned; global skills are installed declaratively via `npx skills add -g` and hash-stamped so the activation only resyncs when the manifest changes.
|
||||
|
||||
[scripts/default.nix](./scripts/default.nix), [justfile](./justfile), [scripts/render-bw-shell-secrets.sh](./scripts/render-bw-shell-secrets.sh), and [scripts/restore-bw-files.sh](./scripts/restore-bw-files.sh) are the operational leverage. `writeShellApplication` turns local scripts into managed tools (`ga`, `ghpr`, `gpr`, `ni`, `theme`, `wt`, `wtc`); Bitwarden stays the secret source of truth; `just switch`, `just switch-netty`, and `nixos-anywhere` keep deployment small.
|
||||
|
||||
Finally, [hosts/netty/configuration.nix](./hosts/netty/configuration.nix) turns the VPS into a declarative service bundle: static networking, nginx + ACME, Forgejo with GitHub mirror sync, sandbox-agent plus its CORS proxy, bounded GC/journald retention, and a machine that can be rebuilt instead of repaired.
|
||||
|
|
@ -46,6 +46,7 @@ in
|
|||
);
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
nixpkgs.overlays = [ inputs.neovim-nightly.overlays.default ];
|
||||
|
||||
programs.zsh.enable = true;
|
||||
environment.shells = [ pkgs.zsh ];
|
||||
|
|
|
|||
|
|
@ -11,19 +11,16 @@
|
|||
|
||||
taps = [
|
||||
"humanlayer/humanlayer"
|
||||
"gromgit/fuse"
|
||||
"mutagen-io/mutagen"
|
||||
];
|
||||
|
||||
brews = [
|
||||
"gromgit/fuse/sshfs-mac"
|
||||
"mutagen-io/mutagen/mutagen"
|
||||
];
|
||||
|
||||
casks = [
|
||||
"cap"
|
||||
"karabiner-elements"
|
||||
"macfuse"
|
||||
"rectangle"
|
||||
"raycast"
|
||||
"riptide-beta"
|
||||
|
|
|
|||
173
nix-maxxing.txt
173
nix-maxxing.txt
|
|
@ -1,173 +0,0 @@
|
|||
Nix Config - Architecture and Operations Guide
|
||||
================================================
|
||||
|
||||
1. STATIC IP
|
||||
----------------------------
|
||||
DHCP on a VPS is dangerous. If the DHCP lease expires or the server
|
||||
reboots while the DHCP server is unreachable, the machine loses its IP
|
||||
and becomes inaccessible via SSH.
|
||||
|
||||
Static config in hosts/netty/configuration.nix:
|
||||
- IP: 152.53.195.59/22
|
||||
- Gateway: 152.53.192.1
|
||||
- Interface: ens3
|
||||
- DNS: 1.1.1.1, 8.8.8.8
|
||||
|
||||
Always verify the interface name with `ip link show` before changing
|
||||
network config. Keep VNC console access available as a fallback.
|
||||
|
||||
|
||||
2. HOST ABSTRACTION (hostConfig)
|
||||
---------------------------------
|
||||
lib/hosts.nix defines each machine with:
|
||||
- isDarwin / isLinux / isNixOS booleans
|
||||
- features map (rust, go, node, python, aws, claude, docker, tex)
|
||||
|
||||
modules/nixpkgs.nix passes hostConfig via specialArgs so all home-manager
|
||||
modules can use it. This replaces scattered `pkgs.stdenv.isDarwin` checks.
|
||||
|
||||
To add a new host:
|
||||
1. Add entry to lib/hosts.nix with all fields
|
||||
2. Create hosts/<name>/configuration.nix (NixOS) or add darwin case
|
||||
3. Add host output in modules/hosts/<name>.nix
|
||||
4. home/default.nix auto-selects modules based on hostConfig flags
|
||||
|
||||
home/default.nix is the unified entry point - no separate per-host home
|
||||
modules needed.
|
||||
|
||||
|
||||
3. XDG COMPLIANCE
|
||||
------------------
|
||||
home/xdg.nix sets environment variables so tools respect XDG dirs:
|
||||
|
||||
CARGO_HOME -> $XDG_DATA_HOME/cargo
|
||||
RUSTUP_HOME -> $XDG_DATA_HOME/rustup
|
||||
GOPATH -> $XDG_DATA_HOME/go
|
||||
GOMODCACHE -> $XDG_CACHE_HOME/go/mod
|
||||
NPM_CONFIG_USERCONFIG -> $XDG_CONFIG_HOME/npm/npmrc
|
||||
NODE_REPL_HISTORY -> $XDG_STATE_HOME/node_repl_history
|
||||
PYTHON_HISTORY -> $XDG_STATE_HOME/python_history
|
||||
AWS_CONFIG_FILE -> $XDG_CONFIG_HOME/aws/config
|
||||
DOCKER_CONFIG -> $XDG_CONFIG_HOME/docker
|
||||
CLAUDE_CONFIG_DIR -> $XDG_CONFIG_HOME/claude
|
||||
PSQL_HISTORY -> $XDG_STATE_HOME/psql_history
|
||||
SQLITE_HISTORY -> $XDG_STATE_HOME/sqlite_history
|
||||
LESSHISTFILE -> "-" (disabled)
|
||||
|
||||
All gated by hostConfig.features so tools only get configured when
|
||||
the feature flag is set for that host.
|
||||
|
||||
|
||||
4. SECURITY MODULE
|
||||
-------------------
|
||||
home/security.nix runs activation scripts on every `home-manager switch`:
|
||||
- ~/.ssh/ dir: 700, private keys: 600, pub/known_hosts/config: 644
|
||||
- ~/.gnupg/ dirs: 700, files: 600
|
||||
|
||||
No manual chmod needed after restoring keys from Bitwarden.
|
||||
|
||||
|
||||
5. THEME SYSTEM
|
||||
----------------
|
||||
lib/theme.nix is the single source of truth for colors.
|
||||
|
||||
Shared palette (gruvbox-inspired) used across:
|
||||
- Ghostty terminal (renderGhostty)
|
||||
- Tmux status bar (renderTmux)
|
||||
- fzf color scheme (renderFzf)
|
||||
- Zsh syntax highlighting (renderZshHighlights)
|
||||
- Bat (batTheme)
|
||||
- Git delta (deltaTheme)
|
||||
|
||||
Runtime toggle: `theme toggle` writes "light" or "dark" to
|
||||
$XDG_STATE_HOME/theme/current, then updates Ghostty, tmux, fzf,
|
||||
and Neovim (via RPC) live. Bat and delta are static at build time.
|
||||
|
||||
|
||||
6. SHELL SETUP
|
||||
---------------
|
||||
Pure prompt with gruvbox-colored git integration. Async git status
|
||||
(no blocking on large repos). Colors defined in lib/theme.nix via
|
||||
renderPurePrompt - adapts to light/dark mode at runtime.
|
||||
Vim mode via defaultKeymap = "viins" with cursor shape switching
|
||||
(beam for insert, block for normal).
|
||||
|
||||
History: 50k entries, dedup, ignoreSpace, extended format, stored at
|
||||
$XDG_STATE_HOME/zsh_history.
|
||||
|
||||
zoxide: declarative via programs.zoxide (no manual eval).
|
||||
|
||||
PATH: managed via home.sessionPath in xdg.nix + initContent block
|
||||
in zsh.nix for entries that need conditional logic.
|
||||
|
||||
|
||||
7. SERVER SERVICES (netty)
|
||||
---------------------------
|
||||
All in hosts/netty/configuration.nix:
|
||||
|
||||
Nginx reverse proxy with ACME SSL:
|
||||
- sandbox.example.dev -> 127.0.0.1:2470 (sandbox agent)
|
||||
- git.example.dev -> 127.0.0.1:3000 (forgejo)
|
||||
|
||||
Forgejo:
|
||||
- Self-hosted git, registration disabled
|
||||
- Runs as git user on port 3000
|
||||
- GitHub mirror sync via hourly systemd timer
|
||||
- Requires /etc/forgejo-mirror.env with GITHUB_TOKEN, FORGEJO_TOKEN,
|
||||
FORGEJO_URL, FORGEJO_OWNER
|
||||
|
||||
Sandbox Agent:
|
||||
- System-level systemd services (not user units)
|
||||
- sandbox-agent on :2470, env from ~/.config/sandbox-agent/agent.env
|
||||
- sandbox-cors-proxy on :2468 (Node.js)
|
||||
- No cloudflared - nginx handles SSL termination
|
||||
|
||||
Garbage collection: 3-day retention (vs 14-day on darwin).
|
||||
Disk guards: min-free 100MB, max-free 1GB.
|
||||
Journald: 1-week retention.
|
||||
|
||||
|
||||
8. DEPLOY COMMANDS
|
||||
-------------------
|
||||
Darwin (local):
|
||||
just switch
|
||||
|
||||
Netty (from mac):
|
||||
just switch-netty
|
||||
|
||||
First-time netty install:
|
||||
nix run github:nix-community/nixos-anywhere -- \
|
||||
--flake .#netty --target-host netty --build-on-remote
|
||||
|
||||
|
||||
9. ROLLBACK
|
||||
-------------
|
||||
Each phase is a separate git commit.
|
||||
|
||||
NixOS rollback:
|
||||
ssh netty "nixos-rebuild switch --rollback"
|
||||
|
||||
Or boot previous generation from GRUB (3 kept).
|
||||
|
||||
Darwin rollback:
|
||||
git revert <commit> && just switch
|
||||
|
||||
Home Manager rollback:
|
||||
home-manager generations # list
|
||||
home-manager switch --flake .#<host> # after git revert
|
||||
|
||||
|
||||
10. FEATURE FLAGS REFERENCE
|
||||
-----------------------------
|
||||
| Feature | darwin | netty |
|
||||
|---------|--------|-------|
|
||||
| rust | yes | yes |
|
||||
| go | yes | yes |
|
||||
| node | yes | yes |
|
||||
| python | yes | yes |
|
||||
| aws | yes | yes |
|
||||
| claude | yes | yes |
|
||||
| docker | yes | no |
|
||||
| tex | yes | no |
|
||||
|
||||
Set in lib/hosts.nix, consumed by home/xdg.nix and lib/package-sets.nix.
|
||||
3832
pkgs/sandbox-agent/Cargo.lock
generated
Normal file
3832
pkgs/sandbox-agent/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
38
pkgs/sandbox-agent/default.nix
Normal file
38
pkgs/sandbox-agent/default.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
lib,
|
||||
fetchFromGitHub,
|
||||
rustPlatform,
|
||||
}:
|
||||
rustPlatform.buildRustPackage {
|
||||
pname = "sandbox-agent";
|
||||
version = "0.5.0-rc.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "rivet-dev";
|
||||
repo = "sandbox-agent";
|
||||
rev = "v0.5.0-rc.1";
|
||||
hash = "sha256-oeOpWjaQlQZZzwQGts4yJgL3STDCd3Hz2qbOJ4N2HBM=";
|
||||
};
|
||||
|
||||
cargoLock.lockFile = ./Cargo.lock;
|
||||
|
||||
prePatch = ''
|
||||
cp ${./Cargo.lock} Cargo.lock
|
||||
'';
|
||||
|
||||
cargoBuildFlags = [
|
||||
"-p"
|
||||
"sandbox-agent"
|
||||
];
|
||||
|
||||
env.SANDBOX_AGENT_SKIP_INSPECTOR = "1";
|
||||
doCheck = false;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Universal API for coding agents in sandboxes";
|
||||
homepage = "https://sandboxagent.dev";
|
||||
license = licenses.asl20;
|
||||
mainProgram = "sandbox-agent";
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue