1

Refresh generated nvim config

This commit is contained in:
2024-06-03 21:11:20 +02:00
parent fd506d4921
commit 50723ef645
2114 changed files with 84528 additions and 44473 deletions

View File

@ -94,7 +94,7 @@ require("lazy").setup({
require("nvim-web-devicons").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nvim-web-devicons",
["lazy"] = false,
["lazy"] = true,
["name"] = "web-devicons",
},
{
@ -122,16 +122,6 @@ require("lazy").setup({
["name"] = "better-escape",
["opts"] = { ["mapping"] = { "jk" }, ["timeout"] = 200 },
},
{
"chadtree",
["config"] = function(_, opts)
vim.api.nvim_set_var("chadtree_settings", opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/chadtree",
["lazy"] = false,
["name"] = "chadtree",
["opts"] = { ["theme"] = { ["text_colour_set"] = "nord" }, ["xdg"] = true },
},
{
"clangd-extensions",
["config"] = function(_, opts)
@ -150,45 +140,45 @@ require("lazy").setup({
{
"cmp-async-path",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-async-path",
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-async-path",
},
{
"cmp-buffer",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-buffer",
["enabled"] = false,
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-buffer",
},
{
"cmp-cmdline",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-cmdline",
["enabled"] = false,
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-cmdline",
},
{
"cmp-emoji",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-emoji",
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-emoji",
},
{
"cmp-nvim-lsp",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-nvim-lsp",
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-nvim-lsp",
},
{
"cmp-nvim-lsp-signature-help",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp-nvim-lsp-signature-help",
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-nvim-lsp-signature-help",
},
{
"cmp-luasnip",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/cmp_luasnip",
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-luasnip",
},
},
@ -229,16 +219,22 @@ require("lazy").setup({
},
mapping = cmp.mapping.preset.insert({
["<Down>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
["<Up>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
["<C-e>"] = cmp.mapping.abort(),
["<Esc>"] = cmp.mapping.abort(),
["<C-Up>"] = cmp.mapping.scroll_docs(-4),
["<C-Down>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete({}),
["<C-Up>"] = cmp.mapping.scroll_docs(-4),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Down>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
["<Esc>"] = cmp.mapping.abort(),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
@ -250,16 +246,7 @@ require("lazy").setup({
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
["<Up>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
}),
}
end,
@ -282,12 +269,13 @@ require("lazy").setup({
{
"ts-context-commentstring",
["config"] = function(_, opts)
vim.g.skip_ts_context_commentstring_module = true -- Skip compatibility checks
-- Skip compatibility checks
vim.g.skip_ts_context_commentstring_module = true
require("ts_context_commentstring").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nvim-ts-context-commentstring",
["lazy"] = false,
["lazy"] = true,
["name"] = "ts-context-commentstring",
},
},
@ -335,7 +323,7 @@ require("lazy").setup({
require("flash").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/flash.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "flash",
},
{
@ -501,7 +489,15 @@ require("lazy").setup({
{
"lualine",
["config"] = function(_, opts)
require("lualine").setup(opts)
local lualine = require("lualine")
lualine.setup(opts)
-- Disable tabline/winbar sections
lualine.hide({
place = { "tabline", "winbar" },
unhide = false,
})
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/lualine.nvim",
["lazy"] = false,
@ -518,12 +514,11 @@ require("lazy").setup({
["sections"] = {
["lualine_a"] = { "mode" },
["lualine_b"] = { "branch", "diff", "diagnostics" },
["lualine_c"] = { { ["extraConfig"] = { ["path"] = 1 }, ["name"] = "filename" } },
["lualine_c"] = { { "filename", path = 1 } },
["lualine_x"] = { "filetype", "encoding", "fileformat" },
["lualine_y"] = { "progress", "searchcount", "selectioncount" },
["lualine_z"] = { "location" },
},
["tabline"] = { ["lualine_a"] = { "buffers" }, ["lualine_z"] = { "tabs" } },
},
},
{
@ -556,16 +551,73 @@ require("lazy").setup({
["name"] = "navic",
["opts"] = { ["click"] = true, ["highlight"] = true, ["lsp"] = { ["auto_attach"] = true } },
},
{
"neo-tree",
["cmd"] = "Neotree",
["config"] = function(_, opts)
require("neo-tree").setup(opts)
end,
["dependencies"] = {
{
"plenary",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/plenary.nvim",
["lazy"] = true,
["name"] = "plenary",
},
{
"web-devicons",
["config"] = function(_, opts)
require("nvim-web-devicons").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nvim-web-devicons",
["lazy"] = true,
["name"] = "web-devicons",
},
{
"nui",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nui.nvim",
["lazy"] = true,
["name"] = "nui",
},
},
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/neo-tree.nvim",
["lazy"] = true,
["name"] = "neo-tree",
["opts"] = {
["buffers"] = { ["follow_current_file"] = { ["enabled"] = true, ["leave_dirs_open"] = false } },
["filesystem"] = { ["follow_current_file"] = { ["enabled"] = true, ["leave_dirs_open"] = false } },
["use_default_mappings"] = false,
["window"] = {
["mappings"] = {
["/"] = "fuzzy_finder",
["<CR>"] = "toggle_node",
["<Esc>"] = "cancel",
["<S-CR>"] = "open",
["?"] = "show_help",
},
},
},
},
{
"noice",
["config"] = function(_, opts)
require("noice").setup(opts)
end,
["dependencies"] = {
{
"notify",
["config"] = function(_, opts)
vim.notify = require("notify")
require("notify").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nvim-notify",
["lazy"] = true,
["name"] = "notify",
},
{
"nui",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nui.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "nui",
},
},
@ -605,16 +657,6 @@ require("lazy").setup({
},
},
},
{
"notify",
["config"] = function(_, opts)
vim.notify = require("notify")
require("notify").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/nvim-notify",
["lazy"] = false,
["name"] = "notify",
},
{
"rainbow-delimiters",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/rainbow-delimiters.nvim",
@ -641,6 +683,7 @@ require("lazy").setup({
},
{
"telescope",
["cmd"] = "Telescope",
["config"] = function(_, opts)
local telescope = require("telescope")
telescope.setup(opts)
@ -653,30 +696,30 @@ require("lazy").setup({
{
"plenary",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/plenary.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "plenary",
},
{
"telescope-fzf-native",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/telescope-fzf-native.nvim",
["lazy"] = true,
["name"] = "telescope-fzf-native",
},
{
"telescope-undo",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/telescope-undo.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "telescope-undo",
},
{
"telescope-ui-select",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/telescope-ui-select.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "telescope-ui-select",
},
{
"telescope-fzf-native",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/telescope-fzf-native.nvim",
["lazy"] = false,
["name"] = "telescope-fzf-native",
},
},
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/telescope.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "telescope",
["opts"] = {
["defaults"] = {
@ -692,11 +735,14 @@ require("lazy").setup({
},
{
"todo-comments",
["config"] = function(_, opts)
require("todo-comments").setup(opts)
end,
["dependencies"] = {
{
"plenary",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/plenary.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "plenary",
},
},
@ -784,7 +830,7 @@ require("lazy").setup({
{
"promise",
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/promise-async",
["lazy"] = false,
["lazy"] = true,
["name"] = "promise",
},
},
@ -804,11 +850,12 @@ require("lazy").setup({
},
{
"yanky",
["cmd"] = { "YankyClearHistory", "YankyRingHistory" },
["config"] = function(_, opts)
require("yanky").setup(opts)
end,
["dir"] = "/home/lab/smchurla/Downloads/flake-nixinator/config/neovim/store/lazy-plugins/yanky.nvim",
["lazy"] = false,
["lazy"] = true,
["name"] = "yanky",
},
},
@ -817,25 +864,25 @@ require("lazy").setup({
-- Set up keybinds {{{
do
local __nixvim_binds = {
{ ["action"] = "<cmd>w<CR>", ["key"] = "<C-s>", ["mode"] = "n", ["options"] = {
{ ["action"] = "<CMD>w<CR>", ["key"] = "<C-s>", ["mode"] = "n", ["options"] = {
["desc"] = "Save current buffer",
} },
{ ["action"] = "<cmd>wa<CR>", ["key"] = "<C-S-s>", ["mode"] = "n", ["options"] = {
{ ["action"] = "<CMD>wa<CR>", ["key"] = "<C-S-s>", ["mode"] = "n", ["options"] = {
["desc"] = "Save all buffers",
} },
{ ["action"] = "<gv", ["key"] = "<", ["mode"] = "v", ["options"] = { ["desc"] = "Outdent" } },
{ ["action"] = ">gv", ["key"] = ">", ["mode"] = "v", ["options"] = { ["desc"] = "Indent" } },
{ ["action"] = "v<<Esc>", ["key"] = "<", ["mode"] = "n", ["options"] = { ["desc"] = "Outdent" } },
{ ["action"] = "v><Esc>", ["key"] = ">", ["mode"] = "n", ["options"] = { ["desc"] = "Indent" } },
{ ["action"] = "<C-d>zz", ["key"] = "<C-d>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump down" } },
{ ["action"] = "<C-u>zz", ["key"] = "<C-u>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump up" } },
{ ["action"] = "nzzzv", ["key"] = "n", ["mode"] = "n", ["options"] = { ["desc"] = "Next match" } },
{ ["action"] = "Nzzzv", ["key"] = "N", ["mode"] = "n", ["options"] = { ["desc"] = "Previous match" } },
{ ["action"] = "<C-d>zz", ["key"] = "<C-d>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump down (centered)" } },
{ ["action"] = "<C-u>zz", ["key"] = "<C-u>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump up (centered)" } },
{ ["action"] = "nzzzv", ["key"] = "n", ["mode"] = "n", ["options"] = { ["desc"] = "Next match (centered)" } },
{ ["action"] = "Nzzzv", ["key"] = "N", ["mode"] = "n", ["options"] = { ["desc"] = "Previous match (centered)" } },
{
["action"] = "<cmd>lua require('intellitab').indent()<CR>",
["action"] = "<CMD>lua require('intellitab').indent()<CR>",
["key"] = "<Tab>",
["mode"] = "i",
["options"] = { ["desc"] = "Indent" },
["options"] = { ["desc"] = "Indent (IntelliTab)" },
},
{ ["action"] = "<C-w>", ["key"] = "<C-BS>", ["mode"] = "i", ["options"] = { ["desc"] = "Delete previous word" } },
{ ["action"] = "<C-w>", ["key"] = "<M-BS>", ["mode"] = "i", ["options"] = { ["desc"] = "Delete previous word" } },
@ -850,137 +897,143 @@ do
} },
{ ["action"] = '"+y', ["key"] = "<C-S-c>", ["mode"] = "v", ["options"] = { ["desc"] = "Copy to clipboard" } },
{
["action"] = "<cmd>nohlsearch<CR>",
["action"] = "<CMD>nohlsearch<CR>",
["key"] = "<C-h>",
["mode"] = "n",
["options"] = { ["desc"] = "Clear search highlights" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.hover()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.hover()<CR>",
["key"] = "K",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP hover" },
},
{ ["action"] = "<cmd>quitall<CR>", ["key"] = "<leader>qq", ["mode"] = "n", ["options"] = { ["desc"] = "Quit" } },
{
["action"] = "<cmd>quitall!<CR>",
["key"] = "<leader>q!",
["action"] = "<CMD>Telescope current_buffer_fuzzy_find<CR>",
["key"] = "/",
["mode"] = "n",
["options"] = { ["desc"] = "Forceful quit" },
["options"] = { ["desc"] = "Find in current buffer" },
},
{ ["action"] = "<cmd>Lazy<CR>", ["key"] = "<leader>L", ["mode"] = "n", ["options"] = { ["desc"] = "Show Lazy" } },
{ ["action"] = "<CMD>Lazy<CR>", ["key"] = "<leader>L", ["mode"] = "n", ["options"] = { ["desc"] = "Show Lazy" } },
{
["action"] = "<cmd>Telescope buffers<CR>",
["action"] = "<CMD>Telescope buffers<CR>",
["key"] = "<leader><Space>",
["mode"] = "n",
["options"] = { ["desc"] = "Show open buffers" },
},
{
["action"] = "<cmd>wa<CR>",
["action"] = "<CMD>w<CR>",
["key"] = "<leader>s",
["mode"] = "n",
["options"] = { ["desc"] = "Save current buffer" },
},
{
["action"] = "<CMD>wa<CR>",
["key"] = "<leader>S",
["mode"] = "n",
["options"] = { ["desc"] = "Save all buffers" },
},
{
["action"] = "<cmd>Telescope find_files<CR>",
["action"] = "<CMD>Telescope find_files<CR>",
["key"] = "<leader>f",
["mode"] = "n",
["options"] = { ["desc"] = "Find file" },
},
{
["action"] = "<cmd>Telescope vim_options<CR>",
["action"] = "<CMD>Telescope vim_options<CR>",
["key"] = "<leader>o",
["mode"] = "n",
["options"] = { ["desc"] = "Show Vim options" },
},
{
["action"] = "<cmd>Telescope undo<CR>",
["action"] = "<CMD>Telescope undo<CR>",
["key"] = "<leader>u",
["mode"] = "n",
["options"] = { ["desc"] = "Show undo history" },
},
{
["action"] = "<cmd>Telescope current_buffer_fuzzy_find<CR>",
["action"] = "<CMD>Telescope live_grep<CR>",
["key"] = "<leader>/",
["mode"] = "n",
["options"] = { ["desc"] = "Find in current buffer" },
["options"] = { ["desc"] = "Find in working directory" },
},
{
["action"] = "<cmd>Telescope notify<CR>",
["action"] = "<CMD>Telescope notify<CR>",
["key"] = "<leader>n",
["mode"] = "n",
["options"] = { ["desc"] = "Show notify history" },
},
{
["action"] = "<cmd>Telescope live_grep<CR>",
["key"] = "<leader>s",
["mode"] = "n",
["options"] = { ["desc"] = "Find in working directory" },
},
{
["action"] = "<cmd>Telescope resume<CR>",
["action"] = "<CMD>Telescope resume<CR>",
["key"] = "<leader>r",
["mode"] = "n",
["options"] = { ["desc"] = "Show last telescope picker" },
},
{
["action"] = "<cmd>Telescope keymaps<CR>",
["action"] = "<CMD>Telescope keymaps<CR>",
["key"] = "<leader>?",
["mode"] = "n",
["options"] = { ["desc"] = "Show keymaps" },
},
{
["action"] = "<cmd>Telescope commands<CR>",
["action"] = "<CMD>Telescope commands<CR>",
["key"] = "<leader>:",
["mode"] = "n",
["options"] = { ["desc"] = "Execute command" },
},
{
["action"] = "<cmd>Telescope marks<CR>",
["action"] = "<CMD>Telescope marks<CR>",
["key"] = "<leader>M",
["mode"] = "n",
["options"] = { ["desc"] = "Show marks" },
},
{
["action"] = "<cmd>Telescope jumplist<CR>",
["action"] = "<CMD>Telescope jumplist<CR>",
["key"] = "<leader>J",
["mode"] = "n",
["options"] = { ["desc"] = "Show jumplist" },
},
{
["action"] = "<cmd>Telescope man_pages<CR>",
["action"] = "<CMD>Telescope man_pages<CR>",
["key"] = "<leader>m",
["mode"] = "n",
["options"] = { ["desc"] = "Show manpages" },
},
{
["action"] = "<cmd>Telescope help_tags<CR>",
["action"] = "<CMD>Telescope help_tags<CR>",
["key"] = "<leader>h",
["mode"] = "n",
["options"] = { ["desc"] = "Show help tags" },
},
{ ["action"] = "+quit", ["key"] = "<leader>q", ["mode"] = "n" },
{ ["action"] = "<CMD>quitall<CR>", ["key"] = "<leader>qq", ["mode"] = "n", ["options"] = { ["desc"] = "Quit" } },
{
["action"] = "<CMD>quitall!<CR>",
["key"] = "<leader>q!",
["mode"] = "n",
["options"] = { ["desc"] = "Quit forcefully" },
},
{ ["action"] = "+buffers", ["key"] = "<leader>b", ["mode"] = "n" },
{
["action"] = "<cmd>Telescope buffers<CR>",
["action"] = "<CMD>Telescope buffers<CR>",
["key"] = "<leader>bb",
["mode"] = "n",
["options"] = { ["desc"] = "Show open buffers" },
},
{
["action"] = "<cmd>bnext<CR>",
["action"] = "<CMD>bnext<CR>",
["key"] = "<leader>bn",
["mode"] = "n",
["options"] = { ["desc"] = "Goto next buffer" },
},
{
["action"] = "<cmd>bprevious<CR>",
["action"] = "<CMD>bprevious<CR>",
["key"] = "<leader>bp",
["mode"] = "n",
["options"] = { ["desc"] = "Goto previous buffer" },
},
{
["action"] = "<cmd>Bdelete<CR>",
["action"] = "<CMD>Bdelete<CR>",
["key"] = "<leader>bd",
["mode"] = "n",
["options"] = { ["desc"] = "Close current buffer" },
@ -998,6 +1051,7 @@ do
["mode"] = "n",
["options"] = { ["desc"] = "Split window vertically" },
},
{ ["action"] = "<C-w>=", ["key"] = "<leader>w=", ["mode"] = "n", ["options"] = { ["desc"] = "Balance windows" } },
{
["action"] = "<C-w>c",
["key"] = "<leader>wd",
@ -1017,124 +1071,124 @@ do
} },
{ ["action"] = "+toggle", ["key"] = "<leader>t", ["mode"] = "n" },
{
["action"] = "<cmd>CHADopen --nofocus<CR>",
["action"] = "<CMD>Neotree action=show toggle=true<CR>",
["key"] = "<leader>tt",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle CHADtree" },
["options"] = { ["desc"] = "Toggle NeoTree" },
},
{
["action"] = "<cmd>Navbuddy<CR>",
["action"] = "<CMD>Navbuddy<CR>",
["key"] = "<leader>tn",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle NavBuddy" },
},
{
["action"] = "<cmd>TroubleToggle focus=false<CR>",
["action"] = "<CMD>TroubleToggle focus=false<CR>",
["key"] = "<leader>td",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle Trouble" },
},
{ ["action"] = "+git", ["key"] = "<leader>g", ["mode"] = "n" },
{
["action"] = "<cmd>LazyGit<CR>",
["action"] = "<CMD>LazyGit<CR>",
["key"] = "<leader>gg",
["mode"] = "n",
["options"] = { ["desc"] = "Show LazyGit" },
},
{
["action"] = "<cmd>GitMessenger<CR>",
["action"] = "<CMD>GitMessenger<CR>",
["key"] = "<leader>gm",
["mode"] = "n",
["options"] = { ["desc"] = "Show GitMessenger" },
},
{
["action"] = "<cmd>Telescope git_status<CR>",
["action"] = "<CMD>Telescope git_status<CR>",
["key"] = "<leader>gs",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git status" },
},
{
["action"] = "<cmd>Telescope git_commits<CR>",
["action"] = "<CMD>Telescope git_commits<CR>",
["key"] = "<leader>gc",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git log" },
},
{
["action"] = "<cmd>Telescope git_branches<CR>",
["action"] = "<CMD>Telescope git_branches<CR>",
["key"] = "<leader>gb",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git branches" },
},
{
["action"] = "<cmd>Telescope git_bcommits<CR>",
["action"] = "<CMD>Telescope git_bcommits<CR>",
["key"] = "<leader>gf",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git log for current file" },
},
{ ["action"] = "+lsp", ["key"] = "<leader>l", ["mode"] = "n" },
{
["action"] = "<cmd>Telescope lsp_references<CR>",
["action"] = "<CMD>Telescope lsp_references<CR>",
["key"] = "<leader>lr",
["mode"] = "n",
["options"] = { ["desc"] = "Goto references" },
},
{
["action"] = "<cmd>Telescope lsp_definitions<CR>",
["action"] = "<CMD>Telescope lsp_definitions<CR>",
["key"] = "<leader>ld",
["mode"] = "n",
["options"] = { ["desc"] = "Goto definition" },
},
{
["action"] = "<cmd>Telescope lsp_implementations<CR>",
["action"] = "<CMD>Telescope lsp_implementations<CR>",
["key"] = "<leader>li",
["mode"] = "n",
["options"] = { ["desc"] = "Goto implementation" },
},
{
["action"] = "<cmd>Telescope lsp_type_definitions<CR>",
["action"] = "<CMD>Telescope lsp_type_definitions<CR>",
["key"] = "<leader>lt",
["mode"] = "n",
["options"] = { ["desc"] = "Goto type definition" },
},
{
["action"] = "<cmd>Telescope lsp_incoming_calls<CR>",
["action"] = "<CMD>Telescope lsp_incoming_calls<CR>",
["key"] = "<leader>lI",
["mode"] = "n",
["options"] = { ["desc"] = "Show incoming calls" },
},
{
["action"] = "<cmd>Telescope lsp_outgoing_calls<CR>",
["action"] = "<CMD>Telescope lsp_outgoing_calls<CR>",
["key"] = "<leader>lO",
["mode"] = "n",
["options"] = { ["desc"] = "Show outgoing calls" },
},
{ ["action"] = "+code", ["key"] = "<leader>c", ["mode"] = "n" },
{
["action"] = "<cmd>lua require('conform').format()<CR>",
["action"] = "<CMD>lua require('conform').format()<CR>",
["key"] = "<leader>cf",
["mode"] = "n",
["options"] = { ["desc"] = "Format current buffer" },
},
{
["action"] = "<cmd>Telescope diagnostics<CR>",
["action"] = "<CMD>Telescope diagnostics<CR>",
["key"] = "<leader>cd",
["mode"] = "n",
["options"] = { ["desc"] = "Show diagnostics" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.rename()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.rename()<CR>",
["key"] = "<leader>cr",
["mode"] = "n",
["options"] = { ["desc"] = "Rename LSP symbol" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.code_action()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.code_action()<CR>",
["key"] = "<leader>ca",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP code actions" },
},
{
["action"] = "<cmd>lua vim.diagnostic.open_float()<CR>",
["action"] = "<CMD>lua vim.diagnostic.open_float()<CR>",
["key"] = "<leader>cD",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP line diagnostics" },

View File

@ -67,7 +67,7 @@ vim.cmd([[
]])
require("lazy").setup({
dev = {
path = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins",
path = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins",
patterns = { "." },
fallback = false,
},
@ -82,7 +82,7 @@ require("lazy").setup({
colorscheme catppuccin
]])
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/catppuccin-nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/catppuccin-nvim",
["lazy"] = false,
["name"] = "catppuccin",
["opts"] = { ["background"] = { ["dark"] = "mocha", ["light"] = "latte" }, ["flavour"] = "mocha" },
@ -93,8 +93,8 @@ require("lazy").setup({
["config"] = function(_, opts)
require("nvim-web-devicons").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-web-devicons",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-web-devicons",
["lazy"] = true,
["name"] = "web-devicons",
},
{
@ -102,13 +102,13 @@ require("lazy").setup({
["config"] = function(_, opts)
require("nvim-autopairs").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-autopairs",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-autopairs",
["lazy"] = false,
["name"] = "autopairs",
},
{
"bbye",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/vim-bbye",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/vim-bbye",
["lazy"] = false,
["name"] = "bbye",
},
@ -117,27 +117,17 @@ require("lazy").setup({
["config"] = function(_, opts)
require("better_escape").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/better-escape.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/better-escape.nvim",
["lazy"] = false,
["name"] = "better-escape",
["opts"] = { ["mapping"] = { "jk" }, ["timeout"] = 200 },
},
{
"chadtree",
["config"] = function(_, opts)
vim.api.nvim_set_var("chadtree_settings", opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/chadtree",
["lazy"] = false,
["name"] = "chadtree",
["opts"] = { ["theme"] = { ["text_colour_set"] = "nord" }, ["xdg"] = true },
},
{
"clangd-extensions",
["config"] = function(_, opts)
require("clangd_extensions").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/clangd_extensions.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/clangd_extensions.nvim",
["lazy"] = false,
["name"] = "clangd-extensions",
},
@ -149,50 +139,50 @@ require("lazy").setup({
["dependencies"] = {
{
"cmp-async-path",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-async-path",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-async-path",
["lazy"] = true,
["name"] = "cmp-async-path",
},
{
"cmp-buffer",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-buffer",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-buffer",
["enabled"] = false,
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-buffer",
},
{
"cmp-cmdline",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-cmdline",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-cmdline",
["enabled"] = false,
["lazy"] = false,
["lazy"] = true,
["name"] = "cmp-cmdline",
},
{
"cmp-emoji",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-emoji",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-emoji",
["lazy"] = true,
["name"] = "cmp-emoji",
},
{
"cmp-nvim-lsp",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-nvim-lsp",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-nvim-lsp",
["lazy"] = true,
["name"] = "cmp-nvim-lsp",
},
{
"cmp-nvim-lsp-signature-help",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp-nvim-lsp-signature-help",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp-nvim-lsp-signature-help",
["lazy"] = true,
["name"] = "cmp-nvim-lsp-signature-help",
},
{
"cmp-luasnip",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/cmp_luasnip",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/cmp_luasnip",
["lazy"] = true,
["name"] = "cmp-luasnip",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-cmp",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-cmp",
["lazy"] = false,
["name"] = "cmp",
["opts"] = function()
@ -229,16 +219,22 @@ require("lazy").setup({
},
mapping = cmp.mapping.preset.insert({
["<Down>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
["<Up>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
["<C-e>"] = cmp.mapping.abort(),
["<Esc>"] = cmp.mapping.abort(),
["<C-Up>"] = cmp.mapping.scroll_docs(-4),
["<C-Down>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete({}),
["<C-Up>"] = cmp.mapping.scroll_docs(-4),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Down>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
["<Esc>"] = cmp.mapping.abort(),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
@ -250,16 +246,7 @@ require("lazy").setup({
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
["<Up>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
}),
}
end,
@ -269,7 +256,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("colorizer").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-colorizer.lua",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-colorizer.lua",
["lazy"] = false,
["name"] = "colorizer",
},
@ -282,16 +269,17 @@ require("lazy").setup({
{
"ts-context-commentstring",
["config"] = function(_, opts)
vim.g.skip_ts_context_commentstring_module = true -- Skip compatibility checks
-- Skip compatibility checks
vim.g.skip_ts_context_commentstring_module = true
require("ts_context_commentstring").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-ts-context-commentstring",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-ts-context-commentstring",
["lazy"] = true,
["name"] = "ts-context-commentstring",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/comment.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/comment.nvim",
["lazy"] = false,
["name"] = "comment",
["opts"] = {
@ -308,7 +296,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("conform").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/conform.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/conform.nvim",
["lazy"] = false,
["name"] = "conform",
["opts"] = {
@ -334,8 +322,8 @@ require("lazy").setup({
["config"] = function(_, opts)
require("flash").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/flash.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/flash.nvim",
["lazy"] = true,
["name"] = "flash",
},
{
@ -345,7 +333,7 @@ require("lazy").setup({
vim.g[k] = v
end
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/git-messenger.vim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/git-messenger.vim",
["lazy"] = false,
["name"] = "gitmessenger",
["opts"] = {
@ -358,14 +346,14 @@ require("lazy").setup({
["config"] = function(_, opts)
require("gitsigns").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/gitsigns.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/gitsigns.nvim",
["lazy"] = false,
["name"] = "gitsigns",
["opts"] = { ["current_line_blame"] = false },
},
{
"haskell-tools",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/haskell-tools.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/haskell-tools.nvim",
["lazy"] = false,
["name"] = "haskell-tools",
},
@ -374,7 +362,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("illuminate").configure(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/vim-illuminate",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/vim-illuminate",
["lazy"] = false,
["name"] = "illuminate",
["opts"] = {
@ -393,7 +381,7 @@ require("lazy").setup({
},
{
"intellitab",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/intellitab.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/intellitab.nvim",
["lazy"] = false,
["name"] = "intellitab",
},
@ -402,13 +390,13 @@ require("lazy").setup({
["config"] = function(_, opts)
require("nvim-lastplace").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-lastplace",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-lastplace",
["lazy"] = false,
["name"] = "lastplace",
},
{
"lazygit",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/lazygit.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/lazygit.nvim",
["lazy"] = false,
["name"] = "lazygit",
},
@ -421,7 +409,7 @@ require("lazy").setup({
lint[k] = v
end
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-lint",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-lint",
["lazy"] = false,
["name"] = "lint",
["opts"] = {
@ -489,21 +477,29 @@ require("lazy").setup({
["config"] = function(_, opts)
require("neodev").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/neodev.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/neodev.nvim",
["lazy"] = false,
["name"] = "neodev",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-lspconfig",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-lspconfig",
["lazy"] = false,
["name"] = "lspconfig",
},
{
"lualine",
["config"] = function(_, opts)
require("lualine").setup(opts)
local lualine = require("lualine")
lualine.setup(opts)
-- Disable tabline/winbar sections
lualine.hide({
place = { "tabline", "winbar" },
unhide = false,
})
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/lualine.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/lualine.nvim",
["lazy"] = false,
["name"] = "lualine",
["opts"] = {
@ -518,12 +514,11 @@ require("lazy").setup({
["sections"] = {
["lualine_a"] = { "mode" },
["lualine_b"] = { "branch", "diff", "diagnostics" },
["lualine_c"] = { { ["extraConfig"] = { ["path"] = 1 }, ["name"] = "filename" } },
["lualine_c"] = { { "filename", path = 1 } },
["lualine_x"] = { "filetype", "encoding", "fileformat" },
["lualine_y"] = { "progress", "searchcount", "selectioncount" },
["lualine_z"] = { "location" },
},
["tabline"] = { ["lualine_a"] = { "buffers" }, ["lualine_z"] = { "tabs" } },
},
},
{
@ -531,7 +526,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("luasnip").config.set_config(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/luasnip",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/luasnip",
["lazy"] = false,
["name"] = "luasnip",
},
@ -541,7 +536,7 @@ require("lazy").setup({
local actions = require("nvim-navbuddy.actions") -- ?
require("nvim-navbuddy").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-navbuddy",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-navbuddy",
["lazy"] = false,
["name"] = "navbuddy",
["opts"] = { ["lsp"] = { ["auto_attach"] = true }, ["window"] = { ["border"] = "rounded" } },
@ -551,25 +546,82 @@ require("lazy").setup({
["config"] = function(_, opts)
require("nvim-navic").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-navic",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-navic",
["lazy"] = false,
["name"] = "navic",
["opts"] = { ["click"] = true, ["highlight"] = true, ["lsp"] = { ["auto_attach"] = true } },
},
{
"neo-tree",
["cmd"] = "Neotree",
["config"] = function(_, opts)
require("neo-tree").setup(opts)
end,
["dependencies"] = {
{
"plenary",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/plenary.nvim",
["lazy"] = true,
["name"] = "plenary",
},
{
"web-devicons",
["config"] = function(_, opts)
require("nvim-web-devicons").setup(opts)
end,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-web-devicons",
["lazy"] = true,
["name"] = "web-devicons",
},
{
"nui",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nui.nvim",
["lazy"] = true,
["name"] = "nui",
},
},
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/neo-tree.nvim",
["lazy"] = true,
["name"] = "neo-tree",
["opts"] = {
["buffers"] = { ["follow_current_file"] = { ["enabled"] = true, ["leave_dirs_open"] = false } },
["filesystem"] = { ["follow_current_file"] = { ["enabled"] = true, ["leave_dirs_open"] = false } },
["use_default_mappings"] = false,
["window"] = {
["mappings"] = {
["/"] = "fuzzy_finder",
["<CR>"] = "toggle_node",
["<Esc>"] = "cancel",
["<S-CR>"] = "open",
["?"] = "show_help",
},
},
},
},
{
"noice",
["config"] = function(_, opts)
require("noice").setup(opts)
end,
["dependencies"] = {
{
"notify",
["config"] = function(_, opts)
vim.notify = require("notify")
require("notify").setup(opts)
end,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-notify",
["lazy"] = true,
["name"] = "notify",
},
{
"nui",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nui.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nui.nvim",
["lazy"] = true,
["name"] = "nui",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/noice.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/noice.nvim",
["lazy"] = false,
["name"] = "noice",
["opts"] = {
@ -605,42 +657,33 @@ require("lazy").setup({
},
},
},
{
"notify",
["config"] = function(_, opts)
vim.notify = require("notify")
require("notify").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-notify",
["lazy"] = false,
["name"] = "notify",
},
{
"rainbow-delimiters",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/rainbow-delimiters.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/rainbow-delimiters.nvim",
["lazy"] = false,
["name"] = "rainbow-delimiters",
},
{
"rustaceanvim",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/rustaceanvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/rustaceanvim",
["lazy"] = false,
["name"] = "rustaceanvim",
},
{
"sandwich",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/vim-sandwich",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/vim-sandwich",
["lazy"] = false,
["name"] = "sandwich",
},
{
"sleuth",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/vim-sleuth",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/vim-sleuth",
["lazy"] = false,
["name"] = "sleuth",
},
{
"telescope",
["cmd"] = "Telescope",
["config"] = function(_, opts)
local telescope = require("telescope")
telescope.setup(opts)
@ -652,31 +695,31 @@ require("lazy").setup({
["dependencies"] = {
{
"plenary",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/plenary.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/plenary.nvim",
["lazy"] = true,
["name"] = "plenary",
},
{
"telescope-fzf-native",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/telescope-fzf-native.nvim",
["lazy"] = true,
["name"] = "telescope-fzf-native",
},
{
"telescope-undo",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/telescope-undo.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/telescope-undo.nvim",
["lazy"] = true,
["name"] = "telescope-undo",
},
{
"telescope-ui-select",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/telescope-ui-select.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/telescope-ui-select.nvim",
["lazy"] = true,
["name"] = "telescope-ui-select",
},
{
"telescope-fzf-native",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/telescope-fzf-native.nvim",
["lazy"] = false,
["name"] = "telescope-fzf-native",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/telescope.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/telescope.nvim",
["lazy"] = true,
["name"] = "telescope",
["opts"] = {
["defaults"] = {
@ -692,15 +735,18 @@ require("lazy").setup({
},
{
"todo-comments",
["config"] = function(_, opts)
require("todo-comments").setup(opts)
end,
["dependencies"] = {
{
"plenary",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/plenary.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/plenary.nvim",
["lazy"] = true,
["name"] = "plenary",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/todo-comments.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/todo-comments.nvim",
["lazy"] = false,
["name"] = "todo-comments",
},
@ -709,7 +755,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("toggleterm").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/toggleterm.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/toggleterm.nvim",
["lazy"] = false,
["name"] = "toggleterm",
["opts"] = {
@ -732,13 +778,13 @@ require("lazy").setup({
["config"] = function(_, opts)
-- Fix treesitter grammars/parsers on nix
vim.opt.runtimepath:append(
"/nix/store/a05m2wf9i4lx3010pagz1p5s4vl1dva2-vimplugin-nvim-treesitter-2024-05-25"
"/nix/store/dks5shbpaksflcsig4dspi8vs9a06yqw-vimplugin-nvim-treesitter-2024-05-28"
)
vim.opt.runtimepath:append("/nix/store/7lrj56kr2nj7591m4kjiq03hq9kwabm9-treesitter-parsers")
vim.opt.runtimepath:append("/nix/store/774ydms06ccrb8zybw2y045ajgs9l7jk-treesitter-parsers")
require("nvim-treesitter.configs").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-treesitter",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-treesitter",
["lazy"] = false,
["name"] = "treesitter",
["opts"] = {
@ -754,7 +800,7 @@ require("lazy").setup({
},
},
["indent"] = { ["enable"] = true },
["parser_install_dir"] = "/nix/store/7lrj56kr2nj7591m4kjiq03hq9kwabm9-treesitter-parsers",
["parser_install_dir"] = "/nix/store/774ydms06ccrb8zybw2y045ajgs9l7jk-treesitter-parsers",
},
},
{
@ -762,7 +808,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("trim").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/trim.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/trim.nvim",
["lazy"] = false,
["name"] = "trim",
},
@ -771,7 +817,7 @@ require("lazy").setup({
["config"] = function(_, opts)
require("trouble").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/trouble.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/trouble.nvim",
["lazy"] = false,
["name"] = "trouble",
},
@ -783,12 +829,12 @@ require("lazy").setup({
["dependencies"] = {
{
"promise",
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/promise-async",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/promise-async",
["lazy"] = true,
["name"] = "promise",
},
},
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/nvim-ufo",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/nvim-ufo",
["lazy"] = false,
["name"] = "ufo",
},
@ -797,18 +843,19 @@ require("lazy").setup({
["config"] = function(_, opts)
require("which-key").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/which-key.nvim",
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/which-key.nvim",
["lazy"] = false,
["name"] = "which-key",
["priority"] = 500,
},
{
"yanky",
["cmd"] = { "YankyClearHistory", "YankyRingHistory" },
["config"] = function(_, opts)
require("yanky").setup(opts)
end,
["dir"] = "/nix/store/8m92rbw7hfvgr0i4jvcmlpn1lb1chjq2-lazy-plugins/yanky.nvim",
["lazy"] = false,
["dir"] = "/nix/store/8bx1xnvd173gghqaak7qyfr9ay7vxdw3-lazy-plugins/yanky.nvim",
["lazy"] = true,
["name"] = "yanky",
},
},
@ -817,25 +864,25 @@ require("lazy").setup({
-- Set up keybinds {{{
do
local __nixvim_binds = {
{ ["action"] = "<cmd>w<CR>", ["key"] = "<C-s>", ["mode"] = "n", ["options"] = {
{ ["action"] = "<CMD>w<CR>", ["key"] = "<C-s>", ["mode"] = "n", ["options"] = {
["desc"] = "Save current buffer",
} },
{ ["action"] = "<cmd>wa<CR>", ["key"] = "<C-S-s>", ["mode"] = "n", ["options"] = {
{ ["action"] = "<CMD>wa<CR>", ["key"] = "<C-S-s>", ["mode"] = "n", ["options"] = {
["desc"] = "Save all buffers",
} },
{ ["action"] = "<gv", ["key"] = "<", ["mode"] = "v", ["options"] = { ["desc"] = "Outdent" } },
{ ["action"] = ">gv", ["key"] = ">", ["mode"] = "v", ["options"] = { ["desc"] = "Indent" } },
{ ["action"] = "v<<Esc>", ["key"] = "<", ["mode"] = "n", ["options"] = { ["desc"] = "Outdent" } },
{ ["action"] = "v><Esc>", ["key"] = ">", ["mode"] = "n", ["options"] = { ["desc"] = "Indent" } },
{ ["action"] = "<C-d>zz", ["key"] = "<C-d>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump down" } },
{ ["action"] = "<C-u>zz", ["key"] = "<C-u>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump up" } },
{ ["action"] = "nzzzv", ["key"] = "n", ["mode"] = "n", ["options"] = { ["desc"] = "Next match" } },
{ ["action"] = "Nzzzv", ["key"] = "N", ["mode"] = "n", ["options"] = { ["desc"] = "Previous match" } },
{ ["action"] = "<C-d>zz", ["key"] = "<C-d>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump down (centered)" } },
{ ["action"] = "<C-u>zz", ["key"] = "<C-u>", ["mode"] = "n", ["options"] = { ["desc"] = "Jump up (centered)" } },
{ ["action"] = "nzzzv", ["key"] = "n", ["mode"] = "n", ["options"] = { ["desc"] = "Next match (centered)" } },
{ ["action"] = "Nzzzv", ["key"] = "N", ["mode"] = "n", ["options"] = { ["desc"] = "Previous match (centered)" } },
{
["action"] = "<cmd>lua require('intellitab').indent()<CR>",
["action"] = "<CMD>lua require('intellitab').indent()<CR>",
["key"] = "<Tab>",
["mode"] = "i",
["options"] = { ["desc"] = "Indent" },
["options"] = { ["desc"] = "Indent (IntelliTab)" },
},
{ ["action"] = "<C-w>", ["key"] = "<C-BS>", ["mode"] = "i", ["options"] = { ["desc"] = "Delete previous word" } },
{ ["action"] = "<C-w>", ["key"] = "<M-BS>", ["mode"] = "i", ["options"] = { ["desc"] = "Delete previous word" } },
@ -850,137 +897,143 @@ do
} },
{ ["action"] = '"+y', ["key"] = "<C-S-c>", ["mode"] = "v", ["options"] = { ["desc"] = "Copy to clipboard" } },
{
["action"] = "<cmd>nohlsearch<CR>",
["action"] = "<CMD>nohlsearch<CR>",
["key"] = "<C-h>",
["mode"] = "n",
["options"] = { ["desc"] = "Clear search highlights" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.hover()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.hover()<CR>",
["key"] = "K",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP hover" },
},
{ ["action"] = "<cmd>quitall<CR>", ["key"] = "<leader>qq", ["mode"] = "n", ["options"] = { ["desc"] = "Quit" } },
{
["action"] = "<cmd>quitall!<CR>",
["key"] = "<leader>q!",
["action"] = "<CMD>Telescope current_buffer_fuzzy_find<CR>",
["key"] = "/",
["mode"] = "n",
["options"] = { ["desc"] = "Forceful quit" },
["options"] = { ["desc"] = "Find in current buffer" },
},
{ ["action"] = "<cmd>Lazy<CR>", ["key"] = "<leader>L", ["mode"] = "n", ["options"] = { ["desc"] = "Show Lazy" } },
{ ["action"] = "<CMD>Lazy<CR>", ["key"] = "<leader>L", ["mode"] = "n", ["options"] = { ["desc"] = "Show Lazy" } },
{
["action"] = "<cmd>Telescope buffers<CR>",
["action"] = "<CMD>Telescope buffers<CR>",
["key"] = "<leader><Space>",
["mode"] = "n",
["options"] = { ["desc"] = "Show open buffers" },
},
{
["action"] = "<cmd>wa<CR>",
["action"] = "<CMD>w<CR>",
["key"] = "<leader>s",
["mode"] = "n",
["options"] = { ["desc"] = "Save current buffer" },
},
{
["action"] = "<CMD>wa<CR>",
["key"] = "<leader>S",
["mode"] = "n",
["options"] = { ["desc"] = "Save all buffers" },
},
{
["action"] = "<cmd>Telescope find_files<CR>",
["action"] = "<CMD>Telescope find_files<CR>",
["key"] = "<leader>f",
["mode"] = "n",
["options"] = { ["desc"] = "Find file" },
},
{
["action"] = "<cmd>Telescope vim_options<CR>",
["action"] = "<CMD>Telescope vim_options<CR>",
["key"] = "<leader>o",
["mode"] = "n",
["options"] = { ["desc"] = "Show Vim options" },
},
{
["action"] = "<cmd>Telescope undo<CR>",
["action"] = "<CMD>Telescope undo<CR>",
["key"] = "<leader>u",
["mode"] = "n",
["options"] = { ["desc"] = "Show undo history" },
},
{
["action"] = "<cmd>Telescope current_buffer_fuzzy_find<CR>",
["action"] = "<CMD>Telescope live_grep<CR>",
["key"] = "<leader>/",
["mode"] = "n",
["options"] = { ["desc"] = "Find in current buffer" },
["options"] = { ["desc"] = "Find in working directory" },
},
{
["action"] = "<cmd>Telescope notify<CR>",
["action"] = "<CMD>Telescope notify<CR>",
["key"] = "<leader>n",
["mode"] = "n",
["options"] = { ["desc"] = "Show notify history" },
},
{
["action"] = "<cmd>Telescope live_grep<CR>",
["key"] = "<leader>s",
["mode"] = "n",
["options"] = { ["desc"] = "Find in working directory" },
},
{
["action"] = "<cmd>Telescope resume<CR>",
["action"] = "<CMD>Telescope resume<CR>",
["key"] = "<leader>r",
["mode"] = "n",
["options"] = { ["desc"] = "Show last telescope picker" },
},
{
["action"] = "<cmd>Telescope keymaps<CR>",
["action"] = "<CMD>Telescope keymaps<CR>",
["key"] = "<leader>?",
["mode"] = "n",
["options"] = { ["desc"] = "Show keymaps" },
},
{
["action"] = "<cmd>Telescope commands<CR>",
["action"] = "<CMD>Telescope commands<CR>",
["key"] = "<leader>:",
["mode"] = "n",
["options"] = { ["desc"] = "Execute command" },
},
{
["action"] = "<cmd>Telescope marks<CR>",
["action"] = "<CMD>Telescope marks<CR>",
["key"] = "<leader>M",
["mode"] = "n",
["options"] = { ["desc"] = "Show marks" },
},
{
["action"] = "<cmd>Telescope jumplist<CR>",
["action"] = "<CMD>Telescope jumplist<CR>",
["key"] = "<leader>J",
["mode"] = "n",
["options"] = { ["desc"] = "Show jumplist" },
},
{
["action"] = "<cmd>Telescope man_pages<CR>",
["action"] = "<CMD>Telescope man_pages<CR>",
["key"] = "<leader>m",
["mode"] = "n",
["options"] = { ["desc"] = "Show manpages" },
},
{
["action"] = "<cmd>Telescope help_tags<CR>",
["action"] = "<CMD>Telescope help_tags<CR>",
["key"] = "<leader>h",
["mode"] = "n",
["options"] = { ["desc"] = "Show help tags" },
},
{ ["action"] = "+quit", ["key"] = "<leader>q", ["mode"] = "n" },
{ ["action"] = "<CMD>quitall<CR>", ["key"] = "<leader>qq", ["mode"] = "n", ["options"] = { ["desc"] = "Quit" } },
{
["action"] = "<CMD>quitall!<CR>",
["key"] = "<leader>q!",
["mode"] = "n",
["options"] = { ["desc"] = "Quit forcefully" },
},
{ ["action"] = "+buffers", ["key"] = "<leader>b", ["mode"] = "n" },
{
["action"] = "<cmd>Telescope buffers<CR>",
["action"] = "<CMD>Telescope buffers<CR>",
["key"] = "<leader>bb",
["mode"] = "n",
["options"] = { ["desc"] = "Show open buffers" },
},
{
["action"] = "<cmd>bnext<CR>",
["action"] = "<CMD>bnext<CR>",
["key"] = "<leader>bn",
["mode"] = "n",
["options"] = { ["desc"] = "Goto next buffer" },
},
{
["action"] = "<cmd>bprevious<CR>",
["action"] = "<CMD>bprevious<CR>",
["key"] = "<leader>bp",
["mode"] = "n",
["options"] = { ["desc"] = "Goto previous buffer" },
},
{
["action"] = "<cmd>Bdelete<CR>",
["action"] = "<CMD>Bdelete<CR>",
["key"] = "<leader>bd",
["mode"] = "n",
["options"] = { ["desc"] = "Close current buffer" },
@ -998,6 +1051,7 @@ do
["mode"] = "n",
["options"] = { ["desc"] = "Split window vertically" },
},
{ ["action"] = "<C-w>=", ["key"] = "<leader>w=", ["mode"] = "n", ["options"] = { ["desc"] = "Balance windows" } },
{
["action"] = "<C-w>c",
["key"] = "<leader>wd",
@ -1017,124 +1071,124 @@ do
} },
{ ["action"] = "+toggle", ["key"] = "<leader>t", ["mode"] = "n" },
{
["action"] = "<cmd>CHADopen --nofocus<CR>",
["action"] = "<CMD>Neotree action=show toggle=true<CR>",
["key"] = "<leader>tt",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle CHADtree" },
["options"] = { ["desc"] = "Toggle NeoTree" },
},
{
["action"] = "<cmd>Navbuddy<CR>",
["action"] = "<CMD>Navbuddy<CR>",
["key"] = "<leader>tn",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle NavBuddy" },
},
{
["action"] = "<cmd>TroubleToggle focus=false<CR>",
["action"] = "<CMD>TroubleToggle focus=false<CR>",
["key"] = "<leader>td",
["mode"] = "n",
["options"] = { ["desc"] = "Toggle Trouble" },
},
{ ["action"] = "+git", ["key"] = "<leader>g", ["mode"] = "n" },
{
["action"] = "<cmd>LazyGit<CR>",
["action"] = "<CMD>LazyGit<CR>",
["key"] = "<leader>gg",
["mode"] = "n",
["options"] = { ["desc"] = "Show LazyGit" },
},
{
["action"] = "<cmd>GitMessenger<CR>",
["action"] = "<CMD>GitMessenger<CR>",
["key"] = "<leader>gm",
["mode"] = "n",
["options"] = { ["desc"] = "Show GitMessenger" },
},
{
["action"] = "<cmd>Telescope git_status<CR>",
["action"] = "<CMD>Telescope git_status<CR>",
["key"] = "<leader>gs",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git status" },
},
{
["action"] = "<cmd>Telescope git_commits<CR>",
["action"] = "<CMD>Telescope git_commits<CR>",
["key"] = "<leader>gc",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git log" },
},
{
["action"] = "<cmd>Telescope git_branches<CR>",
["action"] = "<CMD>Telescope git_branches<CR>",
["key"] = "<leader>gb",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git branches" },
},
{
["action"] = "<cmd>Telescope git_bcommits<CR>",
["action"] = "<CMD>Telescope git_bcommits<CR>",
["key"] = "<leader>gf",
["mode"] = "n",
["options"] = { ["desc"] = "Show Git log for current file" },
},
{ ["action"] = "+lsp", ["key"] = "<leader>l", ["mode"] = "n" },
{
["action"] = "<cmd>Telescope lsp_references<CR>",
["action"] = "<CMD>Telescope lsp_references<CR>",
["key"] = "<leader>lr",
["mode"] = "n",
["options"] = { ["desc"] = "Goto references" },
},
{
["action"] = "<cmd>Telescope lsp_definitions<CR>",
["action"] = "<CMD>Telescope lsp_definitions<CR>",
["key"] = "<leader>ld",
["mode"] = "n",
["options"] = { ["desc"] = "Goto definition" },
},
{
["action"] = "<cmd>Telescope lsp_implementations<CR>",
["action"] = "<CMD>Telescope lsp_implementations<CR>",
["key"] = "<leader>li",
["mode"] = "n",
["options"] = { ["desc"] = "Goto implementation" },
},
{
["action"] = "<cmd>Telescope lsp_type_definitions<CR>",
["action"] = "<CMD>Telescope lsp_type_definitions<CR>",
["key"] = "<leader>lt",
["mode"] = "n",
["options"] = { ["desc"] = "Goto type definition" },
},
{
["action"] = "<cmd>Telescope lsp_incoming_calls<CR>",
["action"] = "<CMD>Telescope lsp_incoming_calls<CR>",
["key"] = "<leader>lI",
["mode"] = "n",
["options"] = { ["desc"] = "Show incoming calls" },
},
{
["action"] = "<cmd>Telescope lsp_outgoing_calls<CR>",
["action"] = "<CMD>Telescope lsp_outgoing_calls<CR>",
["key"] = "<leader>lO",
["mode"] = "n",
["options"] = { ["desc"] = "Show outgoing calls" },
},
{ ["action"] = "+code", ["key"] = "<leader>c", ["mode"] = "n" },
{
["action"] = "<cmd>lua require('conform').format()<CR>",
["action"] = "<CMD>lua require('conform').format()<CR>",
["key"] = "<leader>cf",
["mode"] = "n",
["options"] = { ["desc"] = "Format current buffer" },
},
{
["action"] = "<cmd>Telescope diagnostics<CR>",
["action"] = "<CMD>Telescope diagnostics<CR>",
["key"] = "<leader>cd",
["mode"] = "n",
["options"] = { ["desc"] = "Show diagnostics" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.rename()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.rename()<CR>",
["key"] = "<leader>cr",
["mode"] = "n",
["options"] = { ["desc"] = "Rename LSP symbol" },
},
{
["action"] = "<cmd>lua vim.lsp.buf.code_action()<CR>",
["action"] = "<CMD>lua vim.lsp.buf.code_action()<CR>",
["key"] = "<leader>ca",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP code actions" },
},
{
["action"] = "<cmd>lua vim.diagnostic.open_float()<CR>",
["action"] = "<CMD>lua vim.diagnostic.open_float()<CR>",
["key"] = "<leader>cD",
["mode"] = "n",
["options"] = { ["desc"] = "Show LSP line diagnostics" },

View File

@ -439,12 +439,14 @@ native_lsp = {
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,
@ -1038,12 +1040,14 @@ native_lsp = {
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,

View File

@ -366,12 +366,14 @@ directly at the thing (e.g. an error)).
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,
@ -674,12 +676,14 @@ nvim-lspconfig>lua
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,

View File

@ -0,0 +1,15 @@
catppuccin-compile catppuccin.txt /*catppuccin-compile*
catppuccin-configuration catppuccin.txt /*catppuccin-configuration*
catppuccin-customize-highlights catppuccin.txt /*catppuccin-customize-highlights*
catppuccin-customize-highlights-get-catppuccin-colors catppuccin.txt /*catppuccin-customize-highlights-get-catppuccin-colors*
catppuccin-customize-highlights-overwriting-colors catppuccin.txt /*catppuccin-customize-highlights-overwriting-colors*
catppuccin-faq catppuccin.txt /*catppuccin-faq*
catppuccin-faq-wrong-treesitter-highlights catppuccin.txt /*catppuccin-faq-wrong-treesitter-highlights*
catppuccin-features catppuccin.txt /*catppuccin-features*
catppuccin-installation catppuccin.txt /*catppuccin-installation*
catppuccin-integrations catppuccin.txt /*catppuccin-integrations*
catppuccin-links catppuccin.txt /*catppuccin-links*
catppuccin-table-of-contents catppuccin.txt /*catppuccin-table-of-contents*
catppuccin-thanks-to catppuccin.txt /*catppuccin-thanks-to*
catppuccin-usage catppuccin.txt /*catppuccin-usage*
catppuccin.txt catppuccin.txt /*catppuccin.txt*

View File

@ -9,6 +9,7 @@ function M.get()
local warning = C.yellow
local info = C.sky
local hint = C.teal
local ok = C.green
local darkening_percentage = 0.095
return {
@ -40,27 +41,35 @@ function M.get()
fg = hint,
style = virtual_text.hints,
}, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticVirtualTextOk = {
bg = O.transparent_background and C.none or U.darken(hint, darkening_percentage, C.base),
fg = ok,
style = virtual_text.ok,
}, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticError = { bg = C.none, fg = error, style = virtual_text.errors }, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticWarn = { bg = C.none, fg = warning, style = virtual_text.warnings }, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticInfo = { bg = C.none, fg = info, style = virtual_text.information }, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticHint = { bg = C.none, fg = hint, style = virtual_text.hints }, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
DiagnosticOk = { bg = C.none, fg = ok, style = virtual_text.ok }, -- Used as the mantle highlight group. Other Diagnostic highlights link to this by default
-- for nvim nightly
DiagnosticUnderlineError = { style = underlines.errors, sp = error }, -- Used to underline "Error" diagnostics
DiagnosticUnderlineWarn = { style = underlines.warnings, sp = warning }, -- Used to underline "Warn" diagnostics
DiagnosticUnderlineInfo = { style = underlines.information, sp = info }, -- Used to underline "Info" diagnostics
DiagnosticUnderlineHint = { style = underlines.hints, sp = hint }, -- Used to underline "Hint" diagnostics
DiagnosticUnderlineOk = { style = underlines.ok, sp = ok }, -- Used to underline "Ok" diagnostics
DiagnosticFloatingError = { fg = error }, -- Used to color "Error" diagnostic messages in diagnostics float
DiagnosticFloatingWarn = { fg = warning }, -- Used to color "Warn" diagnostic messages in diagnostics float
DiagnosticFloatingInfo = { fg = info }, -- Used to color "Info" diagnostic messages in diagnostics float
DiagnosticFloatingHint = { fg = hint }, -- Used to color "Hint" diagnostic messages in diagnostics float
DiagnosticFloatingOk = { fg = ok }, -- Used to color "Ok" diagnostic messages in diagnostics float
DiagnosticSignError = { fg = error }, -- Used for "Error" signs in sign column
DiagnosticSignWarn = { fg = warning }, -- Used for "Warn" signs in sign column
DiagnosticSignInfo = { fg = info }, -- Used for "Info" signs in sign column
DiagnosticSignHint = { fg = hint }, -- Used for "Hint" signs in sign column
DiagnosticSignOk = { fg = ok }, -- Used for "Ok" signs in sign column
LspDiagnosticsDefaultError = { fg = error }, -- Used as the mantle highlight group. Other LspDiagnostic highlights link to this by default (except Underline)
LspDiagnosticsDefaultWarning = { fg = warning }, -- Used as the mantle highlight group. Other LspDiagnostic highlights link to this by default (except Underline)

View File

@ -1,9 +1,12 @@
local M = {}
function M.get()
return O.transparent_background and {
return O.transparent_background
and {
TreesitterContextBottom = { sp = C.dim, style = { "underline" } },
} or {
TreesitterContextLineNumber = { fg = C.rosewater },
}
or {
TreesitterContextBottom = {
sp = C.surface0,
style = { "underline" },

View File

@ -78,12 +78,14 @@ local M = {
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,

View File

@ -87,14 +87,16 @@
---@field miscs CtpHighlightArgs[]?
---@class CtpNativeLspStyles
-- Change the style of LSP errors.
-- Change the style of LSP error diagnostics.
---@field errors CtpHighlightArgs[]?
-- Change the style of LSP hints.
-- Change the style of LSP hint diagnostics.
---@field hints CtpHighlightArgs[]?
-- Change the style of LSP warnings.
-- Change the style of LSP warning diagnostics.
---@field warnings CtpHighlightArgs[]?
-- Change the style of LSP information.
-- Change the style of LSP information diagnostics.
---@field information CtpHighlightArgs[]?
-- Change the style of LSP ok diagnostics.
---@field ok CtpHighlightArgs[]?
---@class CtpNativeLspInlayHints
-- Toggle the background of inlay hints.

View File

@ -1,7 +0,0 @@
/.git/
/.venv/
__pycache__/
.mypy_cache/
/.vars/
/temp/
/.vscode/

View File

@ -1,25 +0,0 @@
---
name: Artifacts
on:
push:
branches:
- chad
schedule:
- cron: "0 0 * * *" # daily
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v3
- env:
CI_TOKEN: ${{ secrets.CI_TOKEN }}
run: |-
make build

View File

@ -1,33 +0,0 @@
---
name: CI
on:
push:
schedule:
- cron: "0 0 * * *" # daily
jobs:
mypy:
strategy:
matrix:
python_ver:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python_ver }}
- run: |-
make lint

View File

@ -1,57 +0,0 @@
---
name: "CodeQL"
on:
push:
schedule:
- cron: "0 0 * * *" # daily
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,7 +0,0 @@
/.git/
/.venv/
__pycache__/
.mypy_cache/
/.vars/
/temp/
/.vscode/

View File

@ -1,6 +0,0 @@
---
ignored:
# Allow Latest Dockerfile
- DL3007
# Allow Unpinned Apt Packages
- DL3008

View File

@ -1,13 +0,0 @@
FROM ubuntu:focal
ENV TERM=xterm-256color
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends -- python3-venv neovim git ca-certificates && \
rm -rf -- /var/lib/apt/lists/*
COPY ./docker /
WORKDIR /root/.config/nvim/pack/modules/start/chadtree
COPY . .
RUN python3 -m chadtree deps --xdg ~/.local/share/nvim

View File

@ -1,60 +0,0 @@
MAKEFLAGS += --check-symlink-times
MAKEFLAGS += --jobs
MAKEFLAGS += --no-builtin-rules
MAKEFLAGS += --no-builtin-variables
MAKEFLAGS += --shuffle
MAKEFLAGS += --warn-undefined-variables
SHELL := bash
.DELETE_ON_ERROR:
.ONESHELL:
.SHELLFLAGS := --norc --noprofile -Eeuo pipefail -O dotglob -O nullglob -O extglob -O failglob -O globstar -c
.DEFAULT_GOAL := help
.PHONY: clean clobber build lint fmt
clean:
rm -v -rf -- .mypy_cache/ .venv/
clobber: clean
rm -v -rf -- .vars/
.venv/bin/python3:
python3 -m venv -- .venv
define PYDEPS
from itertools import chain
from os import execl
from sys import executable
from tomli import load
toml = load(open("pyproject.toml", "rb"))
project = toml["project"]
execl(
executable,
executable,
"-m",
"pip",
"install",
"--upgrade",
"--",
*project.get("dependencies", ()),
*chain.from_iterable(project["optional-dependencies"].values()),
)
endef
.venv/bin/mypy: .venv/bin/python3
'$<' -m pip install --requirement requirements.txt -- tomli
'$<' <<< '$(PYDEPS)'
lint: .venv/bin/mypy
'$<' -- .
build: .venv/bin/mypy
.venv/bin/python3 -- ci/prepare.py
fmt: .venv/bin/mypy
.venv/bin/isort --profile=black --gitignore -- .
.venv/bin/black -- .

View File

@ -1,157 +0,0 @@
# [CHADTree](https://ms-jpq.github.io/chadtree)
File Manager for Neovim, Better than NERDTree.
## Features Illustrated
**See full list of screen captures [here](https://github.com/ms-jpq/chadtree/tree/chad/docs/FEATURES.md)**
### I like speed
- **Parallel** Filesystem Scan
- **[React Like](https://reactjs.org/docs/reconciliation.html)** Reconciling Difference Minimizing Rendering engine
- **Never** blocks
_You can read more about my [performance optimization](https://github.com/ms-jpq/chadtree/tree/chad/docs/ARCHITECTURE.md) here._
### I like power
- Visual mode selections
- Create, Copy, Paste, Delete, Rename, gotta do them all
- Quickfix integration
- [Bookmarks](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/bookmarks.png)
![visual_select.gif](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/visual_select.gif)
### I like 21st century
- Filtering by glob
- Follow mode
- Session support (save open folders to disk, pick up where you left off)
- Trash support (requires [`trash`](https://formulae.brew.sh/formula/trash) or [`trash-cli`](https://github.com/andreafrancia/trash-cli))
- `ls -l` statistics
- Correct! handling of symlinks
![filtering.gif](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/filtering.gif)
### I like version control
- Asynchronous parse git status (untracked, modified, staged)
- Full support for git submodules
![git.gif](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/git_showcase.gif)
### I like colours
- Full `$LS_COLOR` support! (shows same colours as unix `ls` & `tree` commands)
- [Github coloured](https://github.com/github/linguist) icons (over 600 colours!)
- Three different sets of icons out of the box
- Four built-in themes - nord, solarized, trapdoor, vim-syntax
![ls_colours.png](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/ls_colours.png)
![github_colours.png](https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/github_colours.png)
### I like refinement
- Maintain cursor position on relevant files even when during movements.
- Maintain selection when copying, moving files
- Mimetype warning (so you don't accidentally open an image)
- Validating config parser **(notice, I added an extra `"dog"` param)**
![mime warn.png](https://github.com/ms-jpq/chadtree/raw/chad/docs/img/mimetype.png)
![schema error.png](https://github.com/ms-jpq/chadtree/raw/chad/docs/img/schema_error.png)
### I like documentation
- Built-in help command in a floating window!
- Over 1000 lines of meticulous docs covering every option / function!
**Use `:CHADhelp` to view [documentation](https://github.com/ms-jpq/chadtree/tree/chad/docs)**
**Use `:CHADhelp --web` to open documentation in your browser!** (If you have one installed)
## Install
**Minimum version**: `python`: 3.8.2, `nvim`: `0.4.3`, make sure to have `virtualenv` installed (e.g.: `sudo apt install --yes -- python3-venv`)
Install the usual way, ie. [VimPlug](https://github.com/junegunn/vim-plug), [Vundle](https://github.com/VundleVim/Vundle.vim), etc
```vim
Plug 'ms-jpq/chadtree', {'branch': 'chad', 'do': 'python3 -m chadtree deps'}
```
You will have to run `:CHADdeps` when installing / updating. This will install CHADTree's dependencies locally inside `chadtree/.vars/runtime`.
doing `rm -rf chadtree/` will cleanly remove everything CHADTree uses on your computer.
## Usage
To toggle CHADTree run command `:CHADopen`. Set it to a hotkey for convenience.
```vimL
nnoremap <leader>v <cmd>CHADopen<cr>
```
To see a list of hot keys:
Either use `:CHADhelp keybind` or open in browser using [`:CHADhelp keybind --web`](https://github.com/ms-jpq/chadtree/tree/chad/docs/KEYBIND.md)
### FAQ
Q: Sometimes Windows will get stuck with CHADTree decorations when I do not want them to be, how do I resolve this?
A: Run `:CHADrestore`
### Recommendations
Add a hotkey to clear quickfix list:
```vimL
nnoremap <leader>l <cmd>call setqflist([])<cr>
```
## If you like this...
Also check out
- [`sad`](https://github.com/ms-jpq/sad), its a modern `sed` that does previews with syntax highlighting, and lets you pick and choose which chunks to edit.
- [`coq.nvim`](https://github.com/ms-jpq/coq_nvim), it's a FAST AS FUCK completion client with shit tons of features.
- [isomorphic-copy](https://github.com/ms-jpq/isomorphic-copy), it's a cross platform clipboard that is daemonless, and does not require third party support.
## Special Thanks
CHADTree does not define it's own colours beyond some minimal defaults, all themes are imported from other open source projects.
> The base icons are imported from the [vim-devicon](https://github.com/ryanoasis/vim-devicons)
> All emoji icons are imported from the [vim-emoji-icon-theme](https://github.com/adelarsq/vim-emoji-icon-theme)
> Some themes are imported from [dircolors-solarized](https://github.com/seebi/dircolors-solarized)
> Some themes are imported from [nord-dircolors](https://github.com/arcticicestudio/nord-dircolors)
> Some themes are imported from [LS_COLORS](https://github.com/trapd00r/LS_COLORS)
> Some themes are imported from [vim-nerdtree-syntax-highlight](https://github.com/tiagofumo/vim-nerdtree-syntax-highlight)

View File

@ -1,7 +0,0 @@
---
title: CHADTree
showcase: True
images:
- https://raw.githubusercontent.com/ms-jpq/chadtree/chad/docs/img/visual_select.gif

View File

@ -1,3 +0,0 @@
# DO NOT EDIT
These are code generated jsons.

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
# Used to Generate Artifacts

View File

@ -1,6 +0,0 @@
---
icon_colours: {}
text_colours:
ext_exact: {}
name_exact: {}
name_glob: {}

View File

@ -1,36 +0,0 @@
---
ascii: &ascii
default_icon:
ext_exact: {}
folder:
closed:
open:
link:
broken: -/->
normal: ->
name_exact: {}
name_glob: {}
status:
active: ">"
inactive: " "
not_selected: " "
selected: "*"
ascii_hollow:
<<: *ascii
default_icon:
folder:
closed:
open:
devicons: &devicons
link:
broken: 󰌸
normal: 󰲔
status:
active:
inactive: " "
not_selected: " "
selected:
emoji: *devicons

View File

@ -1,146 +0,0 @@
from dataclasses import dataclass
from enum import Enum, auto
from pathlib import Path
from typing import Mapping
TOP_LEVEL = Path(__file__).resolve(strict=True).parent
ASSETS = TOP_LEVEL / "assets"
ARTIFACT = TOP_LEVEL / "artifacts" / "artifact.json"
"""
Icons
"""
Icon = str
@dataclass(frozen=True)
class _FolderIcons:
open: Icon
closed: Icon
@dataclass(frozen=True)
class _LinkIcons:
normal: Icon
broken: Icon
@dataclass(frozen=True)
class _StatusIcons:
active: Icon
inactive: Icon
selected: Icon
not_selected: Icon
@dataclass(frozen=True)
class IconGlyphs:
default_icon: Icon
folder: _FolderIcons
link: _LinkIcons
status: _StatusIcons
ext_exact: Mapping[str, Icon]
name_exact: Mapping[str, Icon]
name_glob: Mapping[str, Icon]
@dataclass(frozen=True)
class IconGlyphSet:
ascii_hollow: IconGlyphs
ascii: IconGlyphs
devicons: IconGlyphs
emoji: IconGlyphs
class IconGlyphSetEnum(Enum):
ascii_hollow = auto()
ascii = auto()
devicons = auto()
emoji = auto()
"""
Icon Colours
"""
Hex = str
IconColours = Mapping[str, Hex]
@dataclass(frozen=True)
class IconColourSet:
github: IconColours
class IconColourSetEnum(Enum):
github = auto()
none = auto()
"""
LS Colours
"""
LS_COLOR = str
@dataclass(frozen=True)
class LSColourSet:
solarized_dark_256: LS_COLOR
solarized_dark: LS_COLOR
solarized_light: LS_COLOR
solarized_universal: LS_COLOR
nord: LS_COLOR
trapdoor: LS_COLOR
class LSColoursEnum(Enum):
env = auto()
solarized_dark_256 = auto()
solarized_dark = auto()
solarized_light = auto()
solarized_universal = auto()
nord = auto()
trapdoor = auto()
"""
Text Colours
"""
@dataclass(frozen=True)
class TextColours:
ext_exact: Mapping[str, Hex]
name_exact: Mapping[str, Hex]
name_glob: Mapping[str, Hex]
@dataclass(frozen=True)
class TextColourSet:
nerdtree_syntax_light: TextColours
nerdtree_syntax_dark: TextColours
class TextColourSetEnum(Enum):
nerdtree_syntax_light = auto()
nerdtree_syntax_dark = auto()
"""
Artifact
"""
@dataclass(frozen=True)
class Artifact:
icons: IconGlyphSet
ls_colours: LSColourSet
icon_colours: IconColourSet
text_colours: TextColourSet

View File

@ -1,158 +0,0 @@
from argparse import ArgumentParser, Namespace
from asyncio import run as arun
from concurrent.futures import ThreadPoolExecutor
from contextlib import nullcontext, redirect_stderr, redirect_stdout
from io import StringIO
from pathlib import Path, PurePath
from subprocess import DEVNULL, STDOUT, CalledProcessError, run
from sys import (
executable,
exit,
getswitchinterval,
setswitchinterval,
stderr,
version_info,
)
from textwrap import dedent
from typing import Any, Union
from webbrowser import open as open_w
from .consts import GIL_SWITCH, IS_WIN, MIGRATION_URI, REQUIREMENTS, RT_DIR, RT_PY
setswitchinterval(min(getswitchinterval(), GIL_SWITCH))
try:
from typing import Literal
if version_info < (3, 8, 2):
raise ImportError()
except ImportError:
msg = "For python < 3.8.2 please install using the branch -- legacy"
print(msg, file=stderr)
open_w(MIGRATION_URI)
exit(1)
def _socket(arg: str) -> Any:
if arg.startswith("localhost:"):
host, _, port = arg.rpartition(":")
return host, int(port)
else:
return PurePath(arg)
def parse_args() -> Namespace:
parser = ArgumentParser()
sub_parsers = parser.add_subparsers(dest="command", required=True)
with nullcontext(sub_parsers.add_parser("run")) as p:
p.add_argument("--ppid", type=int)
p.add_argument("--socket", required=True, type=_socket)
p.add_argument("--xdg")
with nullcontext(sub_parsers.add_parser("deps")) as p:
p.add_argument("--nvim", action="store_true")
p.add_argument("--xdg", nargs="?")
return parser.parse_args()
args = parse_args()
command: Union[Literal["deps"], Literal["run"]] = args.command
_XDG = Path(args.xdg) if args.xdg is not None else None
_RT_DIR = _XDG / "chadrt" if _XDG else RT_DIR
_RT_PY = (
(_RT_DIR / "Scripts" / "python.exe" if IS_WIN else _RT_DIR / "bin" / "python3")
if _XDG
else RT_PY
)
_LOCK_FILE = _RT_DIR / "requirements.lock"
_EXEC_PATH = Path(executable)
_EXEC_PATH = _EXEC_PATH.parent.resolve(strict=True) / _EXEC_PATH.name
_REQ = REQUIREMENTS.read_text()
_IN_VENV = True
if command == "deps":
assert not _IN_VENV
io_out = StringIO()
try:
from venv import EnvBuilder
print("...", flush=True)
with redirect_stdout(io_out), redirect_stderr(io_out):
EnvBuilder(
system_site_packages=False,
with_pip=True,
upgrade=True,
symlinks=not IS_WIN,
clear=True,
).create(_RT_DIR)
except (ImportError, CalledProcessError):
msg = "Please install python3-venv separately. (apt, yum, apk, etc)"
print(msg, io_out.getvalue(), file=stderr)
exit(1)
else:
proc = run(
(
_RT_PY,
"-m",
"pip",
"install",
"--upgrade",
"--requirement",
REQUIREMENTS,
),
stdin=DEVNULL,
stderr=STDOUT,
)
if proc.returncode:
print("Installation failed, check :message", file=stderr)
exit(proc.returncode)
else:
_LOCK_FILE.write_text(_REQ)
msg = """
---
You can now use :CHADopen
"""
print(dedent(msg), file=stderr)
elif command == "run":
try:
lock = _LOCK_FILE.read_text()
except Exception:
lock = ""
try:
if not _IN_VENV:
raise ImportError()
elif False:
raise ImportError()
else:
import pynvim_pp
import yaml
from .client import init
except ImportError as e:
print(e)
msg = """
Please update dependencies using :CHADdeps
-
-
Dependencies will be installed privately inside `chadtree/.vars`
`rm -rf chadtree/` will cleanly remove everything
"""
msg = dedent(msg)
print(msg, end="", file=stderr)
exit(1)
else:
with ThreadPoolExecutor() as th:
arun(init(args.socket, ppid=args.ppid, th=th))
else:
assert False

View File

@ -1,158 +0,0 @@
from argparse import ArgumentParser, Namespace
from asyncio import run as arun
from concurrent.futures import ThreadPoolExecutor
from contextlib import nullcontext, redirect_stderr, redirect_stdout
from io import StringIO
from pathlib import Path, PurePath
from subprocess import DEVNULL, STDOUT, CalledProcessError, run
from sys import (
executable,
exit,
getswitchinterval,
setswitchinterval,
stderr,
version_info,
)
from textwrap import dedent
from typing import Any, Union
from webbrowser import open as open_w
from .consts import GIL_SWITCH, IS_WIN, MIGRATION_URI, REQUIREMENTS, RT_DIR, RT_PY
setswitchinterval(min(getswitchinterval(), GIL_SWITCH))
try:
from typing import Literal
if version_info < (3, 8, 2):
raise ImportError()
except ImportError:
msg = "For python < 3.8.2 please install using the branch -- legacy"
print(msg, file=stderr)
open_w(MIGRATION_URI)
exit(1)
def _socket(arg: str) -> Any:
if arg.startswith("localhost:"):
host, _, port = arg.rpartition(":")
return host, int(port)
else:
return PurePath(arg)
def parse_args() -> Namespace:
parser = ArgumentParser()
sub_parsers = parser.add_subparsers(dest="command", required=True)
with nullcontext(sub_parsers.add_parser("run")) as p:
p.add_argument("--ppid", type=int)
p.add_argument("--socket", required=True, type=_socket)
p.add_argument("--xdg")
with nullcontext(sub_parsers.add_parser("deps")) as p:
p.add_argument("--nvim", action="store_true")
p.add_argument("--xdg", nargs="?")
return parser.parse_args()
args = parse_args()
command: Union[Literal["deps"], Literal["run"]] = args.command
_XDG = Path(args.xdg) if args.xdg is not None else None
_RT_DIR = _XDG / "chadrt" if _XDG else RT_DIR
_RT_PY = (
(_RT_DIR / "Scripts" / "python.exe" if IS_WIN else _RT_DIR / "bin" / "python3")
if _XDG
else RT_PY
)
_LOCK_FILE = _RT_DIR / "requirements.lock"
_EXEC_PATH = Path(executable)
_EXEC_PATH = _EXEC_PATH.parent.resolve(strict=True) / _EXEC_PATH.name
_REQ = REQUIREMENTS.read_text()
_IN_VENV = _RT_PY == _EXEC_PATH
if command == "deps":
assert not _IN_VENV
io_out = StringIO()
try:
from venv import EnvBuilder
print("...", flush=True)
with redirect_stdout(io_out), redirect_stderr(io_out):
EnvBuilder(
system_site_packages=False,
with_pip=True,
upgrade=True,
symlinks=not IS_WIN,
clear=True,
).create(_RT_DIR)
except (ImportError, CalledProcessError):
msg = "Please install python3-venv separately. (apt, yum, apk, etc)"
print(msg, io_out.getvalue(), file=stderr)
exit(1)
else:
proc = run(
(
_RT_PY,
"-m",
"pip",
"install",
"--upgrade",
"--requirement",
REQUIREMENTS,
),
stdin=DEVNULL,
stderr=STDOUT,
)
if proc.returncode:
print("Installation failed, check :message", file=stderr)
exit(proc.returncode)
else:
_LOCK_FILE.write_text(_REQ)
msg = """
---
You can now use :CHADopen
"""
print(dedent(msg), file=stderr)
elif command == "run":
try:
lock = _LOCK_FILE.read_text()
except Exception:
lock = ""
try:
if not _IN_VENV:
raise ImportError()
elif lock != _REQ:
raise ImportError()
else:
import pynvim_pp
import yaml
from .client import init
except ImportError as e:
print(e)
msg = """
Please update dependencies using :CHADdeps
-
-
Dependencies will be installed privately inside `chadtree/.vars`
`rm -rf chadtree/` will cleanly remove everything
"""
msg = dedent(msg)
print(msg, end="", file=stderr)
exit(1)
else:
with ThreadPoolExecutor() as th:
arun(init(args.socket, ppid=args.ppid, th=th))
else:
assert False

View File

@ -1,54 +0,0 @@
from .transitions import (
autocmds,
click,
collapse,
copy_name,
cut_copy,
delete,
filter,
focus,
help,
link,
marks,
new,
noop,
open_system,
quit,
refresh,
rename,
resize,
schedule_update,
selection,
stat,
toggle_exec,
toggle_open,
toggles,
)
assert autocmds
assert click
assert collapse
assert copy_name
assert cut_copy
assert delete
assert filter
assert focus
assert help
assert link
assert marks
assert new
assert noop
assert open_system
assert quit
assert refresh
assert refresh
assert rename
assert resize
assert schedule_update
assert selection
assert stat
assert toggle_exec
assert toggle_open
assert toggles
____ = None

View File

@ -1,217 +0,0 @@
from asyncio import (
FIRST_COMPLETED,
AbstractEventLoop,
Event,
Lock,
Task,
create_task,
gather,
get_running_loop,
wait,
wrap_future,
)
from concurrent.futures import Future, ThreadPoolExecutor
from contextlib import AbstractAsyncContextManager, suppress
from functools import wraps
from logging import DEBUG as DEBUG_LVL
from logging import INFO
from multiprocessing import cpu_count
from pathlib import Path
from platform import uname
from string import Template
from sys import executable, exit
from textwrap import dedent
from time import monotonic
from typing import Any, Optional, Sequence, cast
from pynvim_pp.highlight import highlight
from pynvim_pp.logging import log, suppress_and_log
from pynvim_pp.nvim import Nvim, conn
from pynvim_pp.rpc_types import (
Method,
MsgType,
NvimError,
RPCallable,
RPClient,
ServerAddr,
)
from pynvim_pp.types import NoneType
from std2.asyncio import cancel
from std2.cell import RefCell
from std2.contextlib import nullacontext
from std2.pickle.types import DecodeError
from std2.platform import OS, os
from std2.sched import aticker
from std2.sys import autodie
from ._registry import ____
from .consts import DEBUG, RENDER_RETRIES
from .registry import autocmd, dequeue_event, enqueue_event, rpc
from .settings.load import initial as initial_settings
from .settings.localization import init as init_locale
from .state.load import initial as initial_state
from .state.types import State
from .timeit import timeit
from .transitions.autocmds import setup
from .transitions.redraw import redraw
from .transitions.schedule_update import scheduled_update
from .transitions.types import Stage
assert ____ or True
_CB = RPCallable[Optional[Stage]]
def _autodie(ppid: int) -> AbstractAsyncContextManager:
if os is OS.windows:
return nullacontext(None)
else:
return autodie(ppid)
async def _profile(t1: float) -> None:
t2 = monotonic()
info = uname()
msg = f"""
First msg {int((t2 - t1) * 1000)}ms
Arch {info.machine}
Processor {info.processor}
Cores {cpu_count()}
System {info.system}
Version {info.version}
Python {Path(executable).resolve(strict=True)}
"""
await Nvim.write(dedent(msg))
async def _sched(ref: RefCell[State]) -> None:
await enqueue_event(False, method=scheduled_update.method, params=(True,))
async for _ in aticker(ref.val.settings.polling_rate, immediately=False):
if ref.val.vim_focus:
await enqueue_event(False, method=scheduled_update.method)
def _trans(handler: _CB) -> _CB:
@wraps(handler)
async def f(*params: Any) -> None:
await enqueue_event(True, method=handler.method, params=params)
return cast(_CB, f)
async def _default(_: MsgType, method: Method, params: Sequence[Any]) -> None:
await enqueue_event(True, method=method, params=params)
async def _go(loop: AbstractEventLoop, client: RPClient) -> None:
th = ThreadPoolExecutor()
atomic, handlers = rpc.drain()
try:
settings = await initial_settings(handlers.values())
except DecodeError as e:
tpl = """
Some options may have changed.
See help doc on Github under [docs/CONFIGURATION.md]
${e}
"""
ms = Template(dedent(tpl)).substitute(e=e)
await Nvim.write(ms, error=True)
exit(1)
else:
hl = highlight(*settings.view.hl_context.groups)
await (atomic + autocmd.drain() + hl).commit(NoneType)
state = RefCell(await initial_state(settings, th=th))
init_locale(settings.lang)
with suppress_and_log():
await setup(settings)
for f in handlers.values():
ff = _trans(f)
client.register(ff)
staged = RefCell[Optional[Stage]](None)
event = Event()
lock = Lock()
async def step(method: Method, params: Sequence[Any]) -> None:
if handler := cast(Optional[_CB], handlers.get(method)):
with suppress_and_log():
async with lock:
if stage := await handler(state.val, *params):
state.val = stage.state
staged.val = stage
event.set()
else:
assert False, (method, params)
async def c1() -> None:
transcient: Optional[Task] = None
get: Optional[Task] = None
try:
while True:
with suppress_and_log():
get = create_task(dequeue_event())
if transcient:
await wait((transcient, get), return_when=FIRST_COMPLETED)
if not transcient.done():
with timeit("transcient"):
await cancel(transcient)
transcient = None
sync, method, params = await get
task = step(method, params=params)
if sync:
with timeit(method):
await task
else:
transcient = create_task(task)
finally:
await cancel(
*(get or loop.create_future(), transcient or loop.create_future())
)
async def c2() -> None:
t1, has_drawn = monotonic(), False
while True:
await event.wait()
with suppress_and_log():
try:
if stage := staged.val:
state = stage.state
for _ in range(RENDER_RETRIES - 1):
with suppress(NvimError):
await redraw(state, focus=stage.focus)
break
else:
try:
await redraw(state, focus=stage.focus)
except NvimError as e:
log.warn("%s", e)
if settings.profiling and not has_drawn:
has_drawn = True
await _profile(t1=t1)
finally:
event.clear()
await gather(c1(), c2(), _sched(state))
async def init(socket: ServerAddr, ppid: int, th: ThreadPoolExecutor) -> None:
loop = get_running_loop()
loop.set_default_executor(th)
log.setLevel(DEBUG_LVL if DEBUG else INFO)
die: Future = Future()
async def cont() -> None:
async with conn(die, socket=socket, default=_default) as client:
await _go(loop, client=client)
await gather(wrap_future(die), cont())

View File

@ -1,65 +0,0 @@
from os import environ, name
from pathlib import Path
from chad_types import TOP_LEVEL
GIL_SWITCH = 1 / 1000
IS_WIN = name == "nt"
REQUIREMENTS = TOP_LEVEL / "requirements.txt"
DEBUG = "CHADTREE_DEBUG" in environ
BATCH_FACTOR = 88
RENDER_RETRIES = 3
FM_FILETYPE = "CHADTree"
FM_HL_PREFIX = "chadtree"
URI_SCHEME = FM_FILETYPE.casefold()
DEFAULT_LANG = "en"
LANG_ROOT = TOP_LEVEL / "locale"
CONFIG_YML = TOP_LEVEL / "config" / "defaults.yml"
SETTINGS_VAR = "chadtree_settings"
"""
STORAGE
"""
_VARS = Path.home() / ".cache/chadtree/vars"
RT_DIR = _VARS / "runtime"
RT_PY = RT_DIR / "Scripts" / "python.exe" if IS_WIN else RT_DIR / "bin" / "python3"
SESSION_DIR = _VARS / "sessions"
"""
Docs
"""
_DOCS_URI_BASE = "https://github.com/ms-jpq/chadtree/blob/chad/docs"
_DOCS_DIR = TOP_LEVEL / "docs"
_README_md = "README.md"
README_MD = _DOCS_DIR / _README_md
README_URI = f"{_DOCS_URI_BASE}"
_FEATURES_md = "FEATURES.md"
FEATURES_MD = _DOCS_DIR / _FEATURES_md
FEATURES_URI = f"{_DOCS_URI_BASE}/{_FEATURES_md}"
_KEYBIND_md = "KEYBIND.md"
KEYBIND_MD = _DOCS_DIR / _KEYBIND_md
KEYBIND_URI = f"{_DOCS_URI_BASE}/{_KEYBIND_md}"
_CONFIGURATION_md = "CONFIGURATION.md"
CONFIGURATION_MD = _DOCS_DIR / _CONFIGURATION_md
CONFIGURATION_URI = f"{_DOCS_URI_BASE}/{_CONFIGURATION_md}"
_THEME_md = "THEME.md"
THEME_MD = _DOCS_DIR / _THEME_md
THEME_URI = f"{_DOCS_URI_BASE}/{_THEME_md}"
_MIGRATION_md = "MIGRATION.md"
MIGRATION_MD = _DOCS_DIR / _MIGRATION_md
MIGRATION_URI = f"{_DOCS_URI_BASE}/{_MIGRATION_md}"

View File

@ -1,230 +0,0 @@
from asyncio import sleep
from concurrent.futures import ThreadPoolExecutor
from contextlib import suppress
from fnmatch import fnmatch
from os import DirEntry, scandir, stat, stat_result
from os.path import normcase
from pathlib import Path, PurePath
from stat import (
S_IFDOOR,
S_ISBLK,
S_ISCHR,
S_ISDIR,
S_ISFIFO,
S_ISGID,
S_ISLNK,
S_ISREG,
S_ISSOCK,
S_ISUID,
S_ISVTX,
S_IWOTH,
S_IXUSR,
)
from typing import (
AbstractSet,
Iterator,
Mapping,
MutableMapping,
Optional,
Tuple,
Union,
cast,
)
from std2.itertools import batched
from std2.pathlib import is_relative_to
from ..consts import BATCH_FACTOR
from ..state.executor import AsyncExecutor
from ..state.types import Index
from ..timeit import timeit
from .nt import is_junction
from .types import Ignored, Mode, Node
_FILE_MODES: Mapping[int, Mode] = {
S_IXUSR: Mode.executable,
S_IFDOOR: Mode.door,
S_ISGID: Mode.set_gid,
S_ISUID: Mode.set_uid,
S_ISVTX: Mode.sticky,
S_IWOTH: Mode.other_writable,
S_IWOTH | S_ISVTX: Mode.sticky_other_writable,
}
def _iter(
dirent: Union[PurePath, DirEntry[str]], follow: bool, index: Index, lv: int = 0
) -> Iterator[PurePath]:
if not lv:
yield PurePath(dirent)
with suppress(NotADirectoryError, FileNotFoundError, PermissionError):
with scandir(dirent) as dirents:
for child in dirents:
yield (path := PurePath(child))
if child.is_dir(follow_symlinks=follow) and path in index:
yield from _iter(child, follow=follow, index=index, lv=lv + 1)
def _fs_modes(stat: stat_result) -> Iterator[Mode]:
st_mode = stat.st_mode
if S_ISDIR(st_mode):
yield Mode.folder
if S_ISREG(st_mode):
yield Mode.file
if S_ISFIFO(st_mode):
yield Mode.pipe
if S_ISSOCK(st_mode):
yield Mode.socket
if S_ISCHR(st_mode):
yield Mode.char_device
if S_ISBLK(st_mode):
yield Mode.block_device
if stat.st_nlink > 1:
yield Mode.multi_hardlink
for bit, mode in _FILE_MODES.items():
if bit and st_mode & bit == bit:
yield mode
def _fs_stat(path: PurePath) -> Tuple[AbstractSet[Mode], Optional[PurePath]]:
try:
info = stat(path, follow_symlinks=False)
except (FileNotFoundError, PermissionError):
return {Mode.orphan_link}, None
else:
if S_ISLNK(info.st_mode) or is_junction(info):
try:
pointed = Path(path).resolve(strict=True)
link_info = stat(pointed, follow_symlinks=False)
except (FileNotFoundError, NotADirectoryError, RuntimeError):
return {Mode.orphan_link}, None
else:
mode = {*_fs_modes(link_info)}
return mode | {Mode.link}, pointed
else:
mode = {*_fs_modes(info)}
return mode, None
def _fs_node(path: PurePath) -> Node:
mode, pointed = _fs_stat(path)
node = Node(
path=path,
mode=mode,
pointed=pointed,
children={},
)
return node
def _iter_single_nodes(
th: ThreadPoolExecutor, root: PurePath, follow: bool, index: Index
) -> Iterator[Node]:
with timeit("fs->_iter"):
dir_stream = batched(_iter(root, index=index, follow=follow), n=BATCH_FACTOR)
for seq in th.map(lambda x: tuple(map(_fs_node, x)), dir_stream):
yield from seq
async def _new(
th: ThreadPoolExecutor, root: PurePath, follow_links: bool, index: Index
) -> Node:
nodes: MutableMapping[PurePath, Node] = {}
for idx, node in enumerate(
_iter_single_nodes(th, root=root, follow=follow_links, index=index), start=1
):
if idx % BATCH_FACTOR == 0:
await sleep(0)
nodes[node.path] = node
if parent := nodes.get(node.path.parent):
if parent == node:
continue
cast(MutableMapping[PurePath, Node], parent.children)[node.path] = node
return nodes[root]
def _cross_over(root: PurePath, invalid: PurePath) -> bool:
return is_relative_to(root, invalid) or is_relative_to(invalid, root)
async def _update(
th: ThreadPoolExecutor,
root: Node,
follow_links: bool,
index: Index,
invalidate_dirs: AbstractSet[PurePath],
) -> Node:
if any((_cross_over(root.path, invalid=invalid) for invalid in invalidate_dirs)):
return await _new(th, root=root.path, follow_links=follow_links, index=index)
else:
children: MutableMapping[PurePath, Node] = {}
for path, node in root.children.items():
new_node = await _update(
th,
root=node,
follow_links=follow_links,
index=index,
invalidate_dirs=invalidate_dirs,
)
children[path] = new_node
return Node(
path=root.path,
mode=root.mode,
pointed=root.pointed,
children=children,
)
async def new(
exec: AsyncExecutor, root: PurePath, follow_links: bool, index: Index
) -> Node:
with timeit("fs->new"):
return await exec.submit(
_new(exec.threadpool, root=root, follow_links=follow_links, index=index)
)
async def update(
exec: AsyncExecutor,
root: Node,
*,
follow_links: bool,
index: Index,
invalidate_dirs: AbstractSet[PurePath],
) -> Node:
with timeit("fs->_update"):
try:
return await exec.submit(
_update(
exec.threadpool,
root=root,
follow_links=follow_links,
index=index,
invalidate_dirs=invalidate_dirs,
)
)
except FileNotFoundError:
return await new(
exec, follow_links=follow_links, root=root.path, index=index
)
def user_ignored(node: Node, ignores: Ignored) -> bool:
return (
node.path.name in ignores.name_exact
or any(fnmatch(node.path.name, pattern) for pattern in ignores.name_glob)
or any(fnmatch(normcase(node.path), pattern) for pattern in ignores.path_glob)
)
def is_dir(node: Node) -> bool:
return Mode.folder in node.mode
def act_like_dir(node: Node, follow_links: bool) -> bool:
if node.pointed and not follow_links:
return False
else:
return is_dir(node)

View File

@ -1,13 +0,0 @@
import sys
from os import stat_result
from stat import S_ISDIR
if sys.platform == "win32":
def is_junction(st: stat_result) -> bool:
return bool(S_ISDIR(st.st_mode) and st.st_reparse_tag)
else:
def is_junction(st: stat_result) -> bool:
return False

View File

@ -1,242 +0,0 @@
from asyncio import Lock, gather
from dataclasses import dataclass
from datetime import datetime
from functools import lru_cache
from itertools import chain
from os import makedirs, readlink
from os import remove as rm
from os import stat, symlink
from os.path import isdir, isfile, normpath
from pathlib import Path, PurePath
from shutil import copy2, copytree
from shutil import move as mv
from shutil import rmtree
from shutil import which as _which
from stat import S_ISDIR, S_ISLNK, filemode
from typing import AbstractSet, Iterable, Mapping, Optional
from std2.asyncio import to_thread
from std2.stat import RW_R__R__, RWXR_XR_X
from .nt import is_junction
_FOLDER_MODE = RWXR_XR_X
_FILE_MODE = RW_R__R__
def ancestors(*paths: PurePath) -> AbstractSet[PurePath]:
return {*chain.from_iterable(path.parents for path in paths)}
def unify_ancestors(paths: AbstractSet[PurePath]) -> AbstractSet[PurePath]:
return {p for p in paths if ancestors(p).isdisjoint(paths)}
@dataclass(frozen=True)
class FSstat:
permissions: str
user: str
group: str
date_mod: datetime
size: int
link: Optional[PurePath]
@lru_cache(maxsize=None)
def lock() -> Lock:
return Lock()
try:
from grp import getgrgid
from pwd import getpwuid
def _get_username(uid: int) -> str:
try:
return getpwuid(uid).pw_name
except KeyError:
return str(uid)
def _get_groupname(gid: int) -> str:
try:
return getgrgid(gid).gr_name
except KeyError:
return str(gid)
except ImportError:
def _get_username(uid: int) -> str:
return str(uid)
def _get_groupname(gid: int) -> str:
return str(gid)
@lru_cache(maxsize=None)
def which(path: PurePath) -> Optional[PurePath]:
if bin := _which(path):
return PurePath(bin)
else:
return None
async def fs_stat(path: PurePath) -> FSstat:
def cont() -> FSstat:
stats = stat(path, follow_symlinks=False)
permissions = filemode(stats.st_mode)
user = _get_username(stats.st_uid)
group = _get_groupname(stats.st_gid)
date_mod = datetime.fromtimestamp(stats.st_mtime)
size = stats.st_size
try:
link = (
readlink(path) if S_ISLNK(stats.st_mode) or is_junction(stats) else None
)
except OSError:
plink = None
else:
plink = PurePath(link) if link else None
fs_stat = FSstat(
permissions=permissions,
user=user,
group=group,
date_mod=date_mod,
size=size,
link=plink,
)
return fs_stat
return await to_thread(cont)
async def resolve(path: PurePath, strict: bool) -> Path:
def cont() -> Path:
return Path(path).resolve(strict=strict)
return await to_thread(cont)
async def exists(path: PurePath, follow: bool) -> bool:
def cont() -> bool:
try:
stat(path, follow_symlinks=follow)
except (OSError, ValueError):
return False
else:
return True
return await to_thread(cont)
async def exists_many(
paths: Iterable[PurePath], follow: bool
) -> Mapping[PurePath, bool]:
existence = await gather(*(exists(path, follow=follow) for path in paths))
return {path: exi for path, exi in zip(paths, existence)}
async def is_dir(path: PurePath) -> bool:
return await to_thread(lambda: isdir(path))
async def is_file(path: PurePath) -> bool:
return await to_thread(lambda: isfile(path))
def _mkdir_p(path: PurePath) -> None:
makedirs(path, mode=_FOLDER_MODE, exist_ok=True)
async def _mkdir(path: PurePath) -> None:
def cont() -> None:
_mkdir_p(path)
await to_thread(cont)
async def mkdir(paths: Iterable[PurePath]) -> None:
await gather(*map(_mkdir, paths))
async def _new(path: PurePath) -> None:
def cont() -> None:
makedirs(path.parent, mode=_FOLDER_MODE, exist_ok=True)
Path(path).touch(mode=_FILE_MODE, exist_ok=True)
await to_thread(cont)
async def new(paths: Iterable[PurePath]) -> None:
async with lock():
await gather(*map(_new, paths))
async def _rename(src: PurePath, dst: PurePath) -> None:
def cont() -> None:
makedirs(dst.parent, mode=_FOLDER_MODE, exist_ok=True)
mv(normpath(src), normpath(dst))
await to_thread(cont)
async def rename(operations: Mapping[PurePath, PurePath]) -> None:
async with lock():
await gather(*(_rename(src, dst) for src, dst in operations.items()))
async def _remove(path: PurePath) -> None:
def cont() -> None:
stats = stat(path, follow_symlinks=False)
if S_ISDIR(stats.st_mode):
rmtree(path)
else:
rm(path)
await to_thread(cont)
async def remove(paths: Iterable[PurePath]) -> None:
async with lock():
await gather(*map(_remove, paths))
async def _cut(src: PurePath, dst: PurePath) -> None:
def cont() -> None:
mv(normpath(src), normpath(dst))
await to_thread(cont)
async def cut(operations: Mapping[PurePath, PurePath]) -> None:
async with lock():
await gather(*(_cut(src, dst) for src, dst in operations.items()))
async def _copy(src: PurePath, dst: PurePath) -> None:
def cont() -> None:
stats = stat(src, follow_symlinks=False)
if S_ISDIR(stats.st_mode):
copytree(src, dst, symlinks=True, dirs_exist_ok=True)
else:
copy2(src, dst, follow_symlinks=False)
await to_thread(cont)
async def copy(operations: Mapping[PurePath, PurePath]) -> None:
async with lock():
await gather(*(_copy(src, dst) for src, dst in operations.items()))
async def _link(src: PurePath, dst: PurePath) -> None:
def cont() -> None:
target_is_directory = isdir(src)
_mkdir_p(dst.parent)
symlink(normpath(src), normpath(dst), target_is_directory=target_is_directory)
await to_thread(cont)
async def link(operations: Mapping[PurePath, PurePath]) -> None:
async with lock():
await gather(*(_link(src, dst) for dst, src in operations.items()))

View File

@ -1,52 +0,0 @@
from __future__ import annotations
from dataclasses import dataclass, field
from enum import IntEnum, auto, unique
from pathlib import PurePath
from typing import AbstractSet, Any, Mapping, Optional, Sequence
# https://github.com/coreutils/coreutils/blob/master/src/ls.c
@unique
class Mode(IntEnum):
orphan_link = auto()
link = auto()
pipe = auto()
socket = auto()
block_device = auto()
char_device = auto()
door = auto()
sticky_other_writable = auto()
other_writable = auto()
sticky = auto()
folder = auto()
set_uid = auto()
set_gid = auto()
file_w_capacity = auto()
executable = auto()
multi_hardlink = auto()
file = auto()
@dataclass
class _RenderCache:
sort_by: Optional[Sequence[Any]] = None
@dataclass(frozen=True)
class Node:
mode: AbstractSet[Mode]
path: PurePath
pointed: Optional[PurePath]
children: Mapping[PurePath, Node]
cache: _RenderCache = field(default_factory=_RenderCache)
@dataclass(frozen=True)
class Ignored:
name_exact: AbstractSet[str]
name_glob: Sequence[str]
path_glob: Sequence[str]

View File

@ -1,30 +0,0 @@
(function(_)
if vim.diagnostic then
local diagnostics = vim.diagnostic.get(nil, nil)
vim.validate({diagnostics = {diagnostics, "table"}})
local acc = {}
for _, row in pairs(diagnostics) do
local buf = row.bufnr
local severity = tostring(row.severity)
vim.validate(
{
buf = {buf, "number"},
row_severity = {row.severity, "number"}
}
)
if not acc[buf] then
acc[buf] = {}
end
if not acc[buf][severity] then
acc[buf][severity] = 0
end
acc[buf][severity] = acc[buf][severity] + 1
end
local acc2 = {}
for buf, warnings in pairs(acc) do
local path = vim.api.nvim_buf_get_name(buf)
acc2[path] = warnings
end
return acc2
end
end)(...)

View File

@ -1,44 +0,0 @@
import sys
from collections import Counter
from pathlib import Path, PurePath
from typing import Mapping, MutableMapping, cast
from pynvim_pp.nvim import Nvim
from pynvim_pp.types import NoneType
from ..fs.ops import ancestors
from ..state.types import Diagnostics
_LUA = (
Path(__file__).resolve(strict=True).with_name("diagnostics.lua").read_text("UTF-8")
)
if sys.version_info < (3, 9):
_C = Counter
else:
_C = Counter[int]
async def poll(min_severity: int) -> Diagnostics:
diagnostics: Mapping[str, Mapping[str, int]] = cast(
Mapping[str, Mapping[str, int]], await Nvim.fn.luaeval(NoneType, _LUA, ())
)
raw = {
PurePath(path): Counter(
{
s: count
for severity, count in (counts or {}).items()
if (s := int(severity)) <= min_severity
}
)
for path, counts in (diagnostics or {}).items()
}
acc: MutableMapping[PurePath, _C] = {}
for path, counts in raw.items():
for parent in ancestors(path):
c = acc.setdefault(parent, Counter())
c += counts
return {**acc, **raw}

View File

@ -1,9 +0,0 @@
(function(args)
local method, params = unpack(args)
if vim.lsp then
local clients = (vim.lsp.get_clients or vim.lsp.get_active_clients)()
for _, client in pairs(clients) do
client.notify(method, params)
end
end
end)(...)

View File

@ -1,31 +0,0 @@
from pathlib import Path, PurePath
from typing import Any, Iterable, Mapping
from pynvim_pp.nvim import Nvim
from pynvim_pp.types import NoneType
_LUA = Path(__file__).resolve(strict=True).with_name("notify.lua").read_text("UTF-8")
async def _notify(method: str, params: Any) -> None:
await Nvim.fn.luaeval(NoneType, _LUA, (method, params))
async def lsp_created(paths: Iterable[PurePath]) -> None:
params = {"files": tuple({"uri": path.as_uri()} for path in paths)}
await _notify("workspace/didCreateFiles", params=params)
async def lsp_removed(paths: Iterable[PurePath]) -> None:
params = {"files": tuple({"uri": path.as_uri()} for path in paths)}
await _notify("workspace/didDeleteFiles", params=params)
async def lsp_moved(paths: Mapping[PurePath, PurePath]) -> None:
params = {
"files": tuple(
{"oldUri": old.as_uri(), "newUri": new.as_uri()}
for old, new in paths.items()
)
}
await _notify("workspace/didRenameFiles", params=params)

View File

@ -1,48 +0,0 @@
from asyncio import gather
from collections import Counter
from itertools import chain
from pathlib import PurePath
from typing import AbstractSet, Mapping, MutableMapping, MutableSet, Sequence, cast
from pynvim_pp.atomic import Atomic
from pynvim_pp.buffer import Buffer
from pynvim_pp.nvim import Marker, Nvim
from pynvim_pp.types import NoneType
from ..fs.ops import ancestors
from .types import Markers
async def _bookmarks() -> Mapping[PurePath, AbstractSet[Marker]]:
acc: MutableMapping[PurePath, MutableSet[Marker]] = {}
bookmarks = await Nvim.list_bookmarks()
for marker, (path, _, _) in bookmarks.items():
if path:
for marked_path in chain((path,), ancestors(path)):
marks = acc.setdefault(marked_path, set())
marks.add(marker)
return acc
async def _quickfix() -> Mapping[PurePath, int]:
qflist = cast(Sequence[Mapping[str, int]], await Nvim.fn.getqflist(NoneType))
atomic = Atomic()
for q in qflist:
bufnr = q["bufnr"]
buf = Buffer.from_int(bufnr)
atomic.buf_get_name(buf)
bufnames = cast(Sequence[str], await atomic.commit(NoneType))
filenames = tuple(map(PurePath, bufnames))
parents = (ancestor for fullname in filenames for ancestor in ancestors(fullname))
locations = Counter(chain(filenames, parents))
return locations
async def markers() -> Markers:
qf, bm = await gather(_quickfix(), _bookmarks())
markers = Markers(quick_fix=qf, bookmarks=bm)
return markers

View File

@ -1,11 +0,0 @@
from dataclasses import dataclass
from pathlib import PurePath
from typing import AbstractSet, Mapping
from pynvim_pp.nvim import Marker
@dataclass(frozen=True)
class Markers:
quick_fix: Mapping[PurePath, int]
bookmarks: Mapping[PurePath, AbstractSet[Marker]]

View File

@ -1,34 +0,0 @@
from asyncio import Queue
from functools import lru_cache
from typing import Any, Awaitable, Callable, Sequence, Tuple
from pynvim_pp.autocmd import AutoCMD
from pynvim_pp.handler import RPC
from pynvim_pp.rpc_types import Method
_MSG = Tuple[bool, Method, Sequence[Any]]
NAMESPACE = "CHAD"
def _name_gen(fn: Callable[..., Awaitable[Any]]) -> str:
return fn.__qualname__.lstrip("_").capitalize()
@lru_cache(maxsize=None)
def queue() -> Queue:
return Queue()
autocmd = AutoCMD()
rpc = RPC(NAMESPACE, name_gen=_name_gen)
async def enqueue_event(sync: bool, method: Method, params: Sequence[Any] = ()) -> None:
msg = (sync, method, params)
await queue().put(msg)
async def dequeue_event() -> _MSG:
msg: _MSG = await queue().get()
return msg

View File

@ -1,178 +0,0 @@
from dataclasses import dataclass
from enum import Enum, auto
from locale import strxfrm
from typing import (
AbstractSet,
Any,
Iterable,
Mapping,
Optional,
Sequence,
SupportsFloat,
Union,
cast,
)
from pynvim_pp.atomic import Atomic
from pynvim_pp.nvim import Nvim
from pynvim_pp.rpc_types import RPCallable
from pynvim_pp.types import NoneType
from pynvim_pp.window import Window
from std2.configparser import hydrate
from std2.graphlib import merge
from std2.pickle.decoder import new_decoder
from std2.pickle.types import DecodeError
from yaml import safe_load
from chad_types import (
ARTIFACT,
Artifact,
IconColourSetEnum,
IconGlyphSetEnum,
LSColoursEnum,
TextColourSetEnum,
)
from ..consts import CONFIG_YML, SETTINGS_VAR
from ..fs.types import Ignored
from ..registry import NAMESPACE
from ..view.load import load_theme
from ..view.types import HLGroups, Sortby, ViewOptions
from .types import MimetypeOptions, Settings, VersionCtlOpts
class _OpenDirection(Enum):
left = auto()
right = auto()
@dataclass(frozen=True)
class _UserOptions:
close_on_open: bool
follow: bool
follow_links: bool
follow_ignore: bool
lang: Optional[str]
mimetypes: MimetypeOptions
page_increment: int
polling_rate: SupportsFloat
session: bool
show_hidden: bool
min_diagnostics_severity: int
version_control: VersionCtlOpts
@dataclass(frozen=True)
class _UserTheme:
highlights: HLGroups
icon_glyph_set: IconGlyphSetEnum
icon_colour_set: IconColourSetEnum
text_colour_set: Union[LSColoursEnum, TextColourSetEnum]
discrete_colour_map: Mapping[str, str]
@dataclass(frozen=True)
class _UserView:
open_direction: _OpenDirection
width: int
sort_by: Sequence[Sortby]
time_format: str
window_options: Mapping[str, Union[bool, str]]
@dataclass(frozen=True)
class _UserConfig:
keymap: Mapping[str, AbstractSet[str]]
options: _UserOptions
idle_timeout: SupportsFloat
ignore: Ignored
view: _UserView
theme: _UserTheme
xdg: bool
profiling: bool
async def initial(specs: Iterable[RPCallable]) -> Settings:
a_decode = new_decoder[Artifact](Artifact)
c_decode = new_decoder[_UserConfig](_UserConfig)
win = await Window.get_current()
artifacts = a_decode(safe_load(ARTIFACT.read_text("UTF-8")))
user_config = cast(
Mapping[str, Any], await Nvim.vars.get(NoneType, SETTINGS_VAR) or {}
)
config = c_decode(
merge(
safe_load(CONFIG_YML.read_text("UTF-8")), hydrate(user_config), replace=True
)
)
options, view, theme = config.options, config.view, config.theme
atomic = Atomic()
for opt in view.window_options:
atomic.win_get_option(win, opt)
win_opts = cast(Sequence[Union[bool, str]], await atomic.commit(NoneType))
win_actual_opts = {k: v for k, v in zip(view.window_options, win_opts)}
icons, hl_context = load_theme(
artifact=artifacts,
particular_mappings=theme.highlights,
discrete_colours=theme.discrete_colour_map,
icon_set=theme.icon_glyph_set,
icon_colour_set=theme.icon_colour_set,
text_colour_set=theme.text_colour_set,
)
use_icons = theme.icon_glyph_set not in {
IconGlyphSetEnum.ascii,
IconGlyphSetEnum.ascii_hollow,
}
view_opts = ViewOptions(
hl_context=hl_context,
icons=icons,
sort_by=tuple(view.sort_by),
use_icons=use_icons,
time_fmt=view.time_format,
)
keymap = {f"{NAMESPACE}.{k.capitalize()}": v for k, v in config.keymap.items()}
legal_keys = {f"{NAMESPACE}.{spec.method.capitalize()}" for spec in specs}
extra_keys = keymap.keys() - legal_keys
if extra_keys:
raise DecodeError(
path=(_UserOptions, sorted(legal_keys, key=strxfrm)),
actual=None,
missing_keys=(),
extra_keys=sorted(extra_keys, key=strxfrm),
)
else:
settings = Settings(
close_on_open=options.close_on_open,
follow=options.follow,
follow_links=options.follow_links,
follow_ignore=options.follow_ignore,
ignores=config.ignore,
idle_timeout=float(config.idle_timeout),
keymap=keymap,
lang=options.lang,
mime=options.mimetypes,
min_diagnostics_severity=options.min_diagnostics_severity,
open_left=view.open_direction is _OpenDirection.left,
page_increment=options.page_increment,
polling_rate=float(options.polling_rate),
session=options.session,
show_hidden=options.show_hidden,
version_ctl=options.version_control,
view=view_opts,
width=view.width,
win_actual_opts=win_actual_opts,
win_local_opts=view.window_options,
xdg=config.xdg,
profiling=config.profiling,
)
return settings

View File

@ -1,46 +0,0 @@
from locale import getlocale
from string import Template
from typing import Mapping, MutableMapping, Optional, Union
from std2.pickle.decoder import new_decoder
from yaml import safe_load
from ..consts import DEFAULT_LANG, LANG_ROOT
def _get_lang(code: Optional[str], fallback: str) -> str:
if code:
return code.casefold()
else:
tag, _ = getlocale()
tag = (tag or fallback).casefold()
primary, _, _ = tag.partition("-")
lang, _, _ = primary.partition("_")
return lang
class _Lang:
def __init__(self, specs: MutableMapping[str, str]) -> None:
self._specs = specs
def __call__(self, key: str, **kwds: Union[int, float, str]) -> str:
spec = self._specs[key]
return Template(spec).substitute(kwds)
LANG = _Lang({})
def init(code: Optional[str]) -> None:
decode = new_decoder[Mapping[str, str]](Mapping[str, str])
lang = _get_lang(code, fallback=DEFAULT_LANG)
lang_path = (LANG_ROOT / lang).with_suffix(".yml")
yml_path = (
lang_path
if lang_path.exists()
else (LANG_ROOT / DEFAULT_LANG).with_suffix(".yml")
)
specs = decode(safe_load(yml_path.read_text("UTF-8")))
LANG._specs.update(specs)

View File

@ -1,42 +0,0 @@
from dataclasses import dataclass
from typing import AbstractSet, Mapping, Optional, Union
from ..fs.types import Ignored
from ..view.types import ViewOptions
@dataclass(frozen=True)
class VersionCtlOpts:
enable: bool
@dataclass(frozen=True)
class MimetypeOptions:
warn: AbstractSet[str]
allow_exts: AbstractSet[str]
@dataclass(frozen=True)
class Settings:
close_on_open: bool
follow: bool
follow_links: bool
follow_ignore: bool
ignores: Ignored
keymap: Mapping[str, AbstractSet[str]]
lang: Optional[str]
mime: MimetypeOptions
open_left: bool
page_increment: int
polling_rate: float
idle_timeout: float
profiling: bool
session: bool
show_hidden: bool
version_ctl: VersionCtlOpts
view: ViewOptions
width: int
win_actual_opts: Mapping[str, Union[bool, str]]
win_local_opts: Mapping[str, Union[bool, str]]
min_diagnostics_severity: int
xdg: bool

View File

@ -1,25 +0,0 @@
from functools import cached_property
from ..timeit import timeit
from ..view.render import render
from ..view.types import Derived
from .types import State
class DeepState(State):
@cached_property
def derived(self) -> Derived:
with timeit("render"):
return render(
self.root,
settings=self.settings,
index=self.index,
selection=self.selection,
filter_pattern=self.filter_pattern,
markers=self.markers,
diagnostics=self.diagnostics,
vc=self.vc,
follow_links=self.follow_links,
show_hidden=self.show_hidden,
current=self.current,
)

View File

@ -1,56 +0,0 @@
from asyncio import (
AbstractEventLoop,
get_running_loop,
run,
run_coroutine_threadsafe,
wrap_future,
)
from concurrent.futures import Future, InvalidStateError, ThreadPoolExecutor
from contextlib import suppress
from threading import Thread
from typing import Any, Awaitable, Callable, Coroutine, TypeVar
_T = TypeVar("_T")
class AsyncExecutor:
def __init__(self, threadpool: ThreadPoolExecutor) -> None:
f: Future = Future()
self._fut: Future = Future()
async def cont() -> None:
loop = get_running_loop()
if threadpool:
loop.set_default_executor(threadpool)
f.set_result(loop)
main: Coroutine = await wrap_future(self._fut)
await main
self._th = Thread(daemon=True, target=lambda: run(cont()))
self._th.start()
self.threadpool = threadpool
self.loop: AbstractEventLoop = f.result()
def run(self, main: Awaitable[Any]) -> None:
self._fut.set_result(main)
def fsubmit(self, f: Callable[..., Any], *args: Any, **kwargs: Any) -> Future:
fut: Future = Future()
def cont() -> None:
if fut.set_running_or_notify_cancel():
try:
ret = f(*args, **kwargs)
except BaseException as e:
with suppress(InvalidStateError):
fut.set_exception(e)
else:
with suppress(InvalidStateError):
fut.set_result(ret)
self.loop.call_soon_threadsafe(cont)
return fut
def submit(self, co: Awaitable[_T]) -> Awaitable[_T]:
f = run_coroutine_threadsafe(co, loop=self.loop)
return wrap_future(f)

View File

@ -1,72 +0,0 @@
from asyncio import gather
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from pynvim_pp.nvim import Nvim
from ..consts import SESSION_DIR
from ..fs.cartographer import new
from ..nvim.markers import markers
from ..settings.types import Settings
from ..version_ctl.types import VCStatus
from .cache import DeepState
from .executor import AsyncExecutor
from .ops import load_session
from .types import Selection, Session, State
async def initial(settings: Settings, th: ThreadPoolExecutor) -> State:
executor = AsyncExecutor(threadpool=th)
cwd, marks = await gather(Nvim.getcwd(), markers())
storage = (
Path(await Nvim.fn.stdpath(str, "cache")) / "chad_sessions"
if settings.xdg
else SESSION_DIR
)
session = Session(workdir=cwd, storage=storage)
stored = await load_session(session) if settings.session else None
index = {cwd} | (stored.index if stored else frozenset())
show_hidden = (
stored.show_hidden
if stored and stored.show_hidden is not None
else settings.show_hidden
)
enable_vc = (
stored.enable_vc
if stored and stored.enable_vc is not None
else settings.version_ctl.enable
)
selection: Selection = frozenset()
node = await new(
executor, follow_links=settings.follow_links, root=cwd, index=index
)
vc = VCStatus()
current = None
filter_pattern = None
state = DeepState(
executor=executor,
settings=settings,
session=session,
vim_focus=True,
index=index,
selection=selection,
filter_pattern=filter_pattern,
show_hidden=show_hidden,
follow=settings.follow,
follow_links=settings.follow_links,
follow_ignore=settings.follow_ignore,
enable_vc=enable_vc,
width=settings.width,
root=node,
markers=marks,
diagnostics={},
vc=vc,
current=current,
window_order={},
)
return state

View File

@ -1,85 +0,0 @@
from pathlib import PurePath
from typing import AbstractSet, Mapping, Optional, Union, cast
from pynvim_pp.rpc_types import ExtData
from std2.types import Void, VoidType, or_else
from ..fs.cartographer import update
from ..fs.types import Node
from ..nvim.types import Markers
from ..version_ctl.types import VCStatus
from .cache import DeepState
from .types import Diagnostics, FilterPattern, Index, Selection, Session, State
async def forward(
state: State,
*,
root: Union[Node, VoidType] = Void,
index: Union[Index, VoidType] = Void,
selection: Union[Selection, VoidType] = Void,
filter_pattern: Union[Optional[FilterPattern], VoidType] = Void,
show_hidden: Union[bool, VoidType] = Void,
follow: Union[bool, VoidType] = Void,
follow_links: Union[bool, VoidType] = Void,
follow_ignore: Union[bool, VoidType] = Void,
enable_vc: Union[bool, VoidType] = Void,
width: Union[int, VoidType] = Void,
markers: Union[Markers, VoidType] = Void,
diagnostics: Union[Diagnostics, VoidType] = Void,
vc: Union[VCStatus, VoidType] = Void,
current: Union[PurePath, VoidType] = Void,
invalidate_dirs: Union[AbstractSet[PurePath], VoidType] = Void,
window_order: Union[Mapping[ExtData, None], VoidType] = Void,
session: Union[Session, VoidType] = Void,
vim_focus: Union[bool, VoidType] = Void,
trace: bool = True,
) -> State:
new_index = or_else(index, state.index)
new_selection = or_else(selection, state.selection)
new_filter_pattern = or_else(filter_pattern, state.filter_pattern)
new_current = or_else(current, state.current)
new_follow_links = or_else(follow_links, state.follow_links)
new_root = cast(
Node,
root
or (
await update(
state.executor,
root=state.root,
follow_links=new_follow_links,
index=new_index,
invalidate_dirs=invalidate_dirs,
)
if not isinstance(invalidate_dirs, VoidType)
else state.root
),
)
new_markers = or_else(markers, state.markers)
new_vc = or_else(vc, state.vc)
new_hidden = or_else(show_hidden, state.show_hidden)
new_vim_focus = or_else(vim_focus, state.vim_focus)
new_state = DeepState(
executor=state.executor,
settings=state.settings,
session=or_else(session, state.session),
vim_focus=new_vim_focus,
index=new_index,
selection=new_selection,
filter_pattern=new_filter_pattern,
show_hidden=new_hidden,
follow=or_else(follow, state.follow),
follow_links=new_follow_links,
follow_ignore=or_else(follow_ignore, state.follow_ignore),
enable_vc=or_else(enable_vc, state.enable_vc),
width=or_else(width, state.width),
root=new_root,
markers=new_markers,
diagnostics=or_else(diagnostics, state.diagnostics),
vc=new_vc,
current=new_current,
window_order=or_else(window_order, state.window_order),
)
return new_state

View File

@ -1,69 +0,0 @@
from hashlib import sha1
from json import dumps, loads
from os.path import normcase
from pathlib import Path, PurePath
from tempfile import NamedTemporaryFile
from typing import Any, MutableMapping, Optional
from pynvim_pp.lib import decode, encode
from std2.asyncio import to_thread
from std2.pickle.decoder import new_decoder
from std2.pickle.encoder import new_encoder
from .types import Session, State, StoredSession
_DECODER = new_decoder[StoredSession](StoredSession)
_ENCODER = new_encoder[StoredSession](StoredSession)
def _session_path(cwd: PurePath, storage: Path) -> Path:
hashed = sha1(normcase(cwd).encode()).hexdigest()
part = storage / hashed
return part.with_suffix(".json")
async def _load_json(path: Path) -> Optional[Any]:
def cont() -> Optional[Any]:
try:
json = decode(path.read_bytes())
except FileNotFoundError:
return None
else:
return loads(json)
return await to_thread(cont)
async def load_session(session: Session) -> StoredSession:
load_path = _session_path(session.workdir, storage=session.storage)
try:
json = await _load_json(load_path)
if isinstance(json, MutableMapping):
json.pop("bookmarks", None)
sessions = _DECODER(json)
except Exception:
return StoredSession(index=frozenset(), show_hidden=None, enable_vc=None)
else:
return sessions
async def dump_session(state: State) -> None:
stored = StoredSession(
index=state.index,
show_hidden=state.show_hidden,
enable_vc=state.enable_vc,
)
json = _ENCODER(stored)
path = _session_path(state.session.workdir, storage=state.session.storage)
parent = path.parent
dumped = encode(dumps(json, ensure_ascii=False, check_circular=False, indent=2))
def cont() -> None:
parent.mkdir(parents=True, exist_ok=True)
with NamedTemporaryFile(dir=parent, delete=False) as f:
f.write(dumped)
Path(f.name).replace(path)
await to_thread(cont)

View File

@ -1,63 +0,0 @@
from dataclasses import dataclass
from pathlib import Path, PurePath
from typing import AbstractSet, Mapping, Optional
from pynvim_pp.rpc_types import ExtData
from ..fs.types import Node
from ..nvim.types import Markers
from ..settings.types import Settings
from ..version_ctl.types import VCStatus
from ..view.types import Derived
from .executor import AsyncExecutor
Index = AbstractSet[PurePath]
Selection = Index
Diagnostics = Mapping[PurePath, Mapping[int, int]]
@dataclass(frozen=True)
class FilterPattern:
pattern: str
@dataclass(frozen=True)
class Session:
workdir: PurePath
storage: Path
@dataclass(frozen=True)
class State:
executor: AsyncExecutor
settings: Settings
session: Session
follow_links: bool
follow_ignore: bool
vim_focus: bool
current: Optional[PurePath]
enable_vc: bool
filter_pattern: Optional[FilterPattern]
follow: bool
index: Index
markers: Markers
root: Node
selection: Selection
show_hidden: bool
vc: VCStatus
width: int
diagnostics: Diagnostics
window_order: Mapping[ExtData, None]
@property
def derived(self) -> Derived:
raise NotImplementedError()
@dataclass(frozen=True)
class StoredSession:
# TODO: sync across sessions
# pid: int
index: Index
show_hidden: Optional[bool]
enable_vc: Optional[bool]

View File

@ -1,35 +0,0 @@
from contextlib import contextmanager
from typing import Any, Iterator, MutableMapping, Optional, Tuple
from pynvim_pp.logging import log
from std2.locale import si_prefixed_smol
from std2.timeit import timeit as _timeit
from .consts import DEBUG
_RECORDS: MutableMapping[str, Tuple[int, float]] = {}
@contextmanager
def timeit(
name: str, *args: Any, force: bool = False, warn: Optional[float] = None
) -> Iterator[None]:
if DEBUG or force or warn is not None:
with _timeit() as t:
yield None
delta = t().total_seconds()
if DEBUG or force or delta >= (warn or 0):
times, cum = _RECORDS.get(name, (0, 0))
tt, c = times + 1, cum + delta
_RECORDS[name] = tt, c
label = name.ljust(50)
time = f"{si_prefixed_smol(delta, precision=0)}s".ljust(8)
ttime = f"{si_prefixed_smol(c / tt, precision=0)}s".ljust(8)
msg = f"TIME -- {label} :: {time} @ {ttime} {' '.join(map(str, args))}"
if force:
log.info("%s", msg)
else:
log.debug("%s", msg)
else:
yield None

View File

@ -1,199 +0,0 @@
from asyncio import Task, create_task, sleep
from collections.abc import Sequence
from itertools import chain
from typing import Optional
from pynvim_pp.buffer import Buffer
from pynvim_pp.nvim import Nvim
from pynvim_pp.rpc_types import NvimError
from pynvim_pp.window import Window
from std2.asyncio import cancel
from std2.cell import RefCell
from ..consts import FM_FILETYPE, URI_SCHEME
from ..fs.ops import ancestors, is_file
from ..lsp.diagnostics import poll
from ..nvim.markers import markers
from ..registry import NAMESPACE, autocmd, rpc
from ..settings.types import Settings
from ..state.next import forward
from ..state.ops import dump_session
from ..state.types import State
from .shared.current import new_current_file, new_root
from .shared.wm import (
find_current_buffer_path,
find_fm_buffers,
is_fm_buf_name,
is_fm_buffer,
restore_non_fm_win,
setup_fm_buf,
)
from .types import Stage
_CELL = RefCell[Optional[Task]](None)
async def _setup_fm_win(settings: Settings, win: Window) -> None:
for key, val in settings.win_local_opts.items():
await win.opts.set(key, val=val)
async def setup(settings: Settings) -> None:
async for buf in find_fm_buffers():
await setup_fm_buf(settings, buf=buf)
for win in await Window.list():
buf = await win.get_buf()
if await is_fm_buffer(buf):
await _setup_fm_win(settings, win=win)
@rpc(blocking=False)
async def _when_idle(state: State) -> None:
if task := _CELL.val:
_CELL.val = None
await cancel(task)
async def cont() -> None:
await sleep(state.settings.idle_timeout)
diagnostics = await poll(state.settings.min_diagnostics_severity)
await forward(state, diagnostics=diagnostics)
_CELL.val = create_task(cont())
_ = autocmd("CursorHold", "CursorHoldI") << f"lua {NAMESPACE}.{_when_idle.method}()"
@rpc(blocking=False)
async def save_session(state: State) -> None:
"""
Save CHADTree state
"""
await dump_session(state)
_ = autocmd("ExitPre") << f"lua {NAMESPACE}.{save_session.method}()"
_ = (
autocmd("User", modifiers=("CHADSave",))
<< f"lua {NAMESPACE}.{save_session.method}()"
)
@rpc(blocking=False)
async def focus_lost(state: State) -> Stage:
"""
Save CHADTree state
"""
await dump_session(state)
new_state = await forward(state, vim_focus=False)
return Stage(new_state)
_ = autocmd("FocusLost") << f"lua {NAMESPACE}.{focus_lost.method}()"
@rpc(blocking=False)
async def _focus_gained(state: State) -> Stage:
""" """
new_state = await forward(state, vim_focus=True)
return Stage(new_state)
_ = autocmd("FocusGained") << f"lua {NAMESPACE}.{_focus_gained.method}()"
@rpc(blocking=False)
async def _record_win_pos(state: State) -> Stage:
"""
Record last windows
"""
win = await Window.get_current()
win_id = win.data
window_order = {
wid: None
for wid in chain(
(wid for wid in state.window_order if wid != win_id), (win_id,)
)
}
new_state = await forward(state, window_order=window_order)
return Stage(new_state)
_ = autocmd("WinEnter") << f"lua {NAMESPACE}.{_record_win_pos.method}()"
@rpc(blocking=False)
async def _changedir(state: State) -> Stage:
"""
Follow cwd update
"""
cwd = await Nvim.getcwd()
new_state = await new_root(state, new_cwd=cwd, indices=frozenset())
return Stage(new_state)
_ = autocmd("DirChanged") << f"lua {NAMESPACE}.{_changedir.method}()"
@rpc(blocking=False)
async def _restore(state: State, args: Sequence[str]) -> None:
win = await Window.get_current()
await restore_non_fm_win(state.settings.win_actual_opts, win=win)
@rpc(blocking=False)
async def _update_follow(state: State) -> Optional[Stage]:
"""
Follow buffer
"""
win = await Window.get_current()
buf = await Buffer.get_current()
name = await buf.get_name()
is_fm_win = await win.vars.get(bool, URI_SCHEME)
is_fm_buf = await buf.filetype() == FM_FILETYPE
is_fm_uri = name and is_fm_buf_name(name)
if is_fm_win and not is_fm_buf:
await restore_non_fm_win(state.settings.win_actual_opts, win=win)
if is_fm_uri or is_fm_buf and not is_fm_win:
await _setup_fm_win(state.settings, win=win)
if is_fm_uri and not is_fm_buf:
await setup_fm_buf(state.settings, buf=buf)
try:
if (current := await find_current_buffer_path(name)) and await is_file(current):
if state.vc.ignored & {current, *ancestors(current)}:
return None
else:
stage = await new_current_file(state, current=current)
return stage
else:
return None
except NvimError:
return None
_ = autocmd("BufEnter") << f"lua {NAMESPACE}.{_update_follow.method}()"
@rpc(blocking=False)
async def _update_markers(state: State) -> Stage:
"""
Update markers
"""
mks = await markers()
new_state = await forward(state, markers=mks)
return Stage(new_state)
_ = autocmd("QuickfixCmdPost") << f"lua {NAMESPACE}.{_update_markers.method}()"

View File

@ -1,108 +0,0 @@
from typing import Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from ..fs.cartographer import is_dir
from ..fs.types import Mode
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from .shared.index import indices
from .shared.open_file import open_file
from .shared.wm import find_fm_windows
from .types import ClickType, Stage
async def _click(
state: State, is_visual: bool, click_type: ClickType
) -> Optional[Stage]:
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
if Mode.orphan_link in node.mode:
await Nvim.write(LANG("dead_link", name=node.path.name), error=True)
return None
else:
if is_dir(node):
if node.path == state.root.path:
return None
elif node.pointed and not state.follow_links:
return None
elif state.filter_pattern:
await Nvim.write(LANG("filter_click"))
return None
else:
index = state.index ^ {node.path}
invalidate_dirs = {node.path}
new_state = await forward(
state,
index=index,
invalidate_dirs=invalidate_dirs,
)
return Stage(new_state)
else:
nxt = await open_file(
state,
path=node.path,
click_type=click_type,
)
if state.settings.close_on_open and click_type != ClickType.secondary:
async for win, _ in find_fm_windows():
await win.close()
return nxt
@rpc(blocking=False)
async def _primary(state: State, is_visual: bool) -> Optional[Stage]:
"""
Folders -> toggle
File -> open
"""
return await _click(state, is_visual=is_visual, click_type=ClickType.primary)
@rpc(blocking=False)
async def _secondary(state: State, is_visual: bool) -> Optional[Stage]:
"""
Folders -> toggle
File -> preview
"""
return await _click(state, is_visual=is_visual, click_type=ClickType.secondary)
@rpc(blocking=False)
async def _tertiary(state: State, is_visual: bool) -> Optional[Stage]:
"""
Folders -> toggle
File -> open in new tab
"""
return await _click(state, is_visual=is_visual, click_type=ClickType.tertiary)
@rpc(blocking=False)
async def _v_split(state: State, is_visual: bool) -> Optional[Stage]:
"""
Folders -> toggle
File -> open in vertical split
"""
return await _click(state, is_visual=is_visual, click_type=ClickType.v_split)
@rpc(blocking=False)
async def _h_split(state: State, is_visual: bool) -> Optional[Stage]:
"""
Folders -> toggle
File -> open in horizontal split
"""
return await _click(state, is_visual=is_visual, click_type=ClickType.h_split)

View File

@ -1,38 +0,0 @@
from typing import Optional
from std2 import anext
from ..fs.cartographer import act_like_dir
from ..fs.ops import ancestors
from ..registry import rpc
from ..state.next import forward
from ..state.types import State
from .shared.index import indices
from .types import Stage
@rpc(blocking=False)
async def _collapse(state: State, is_visual: bool) -> Optional[Stage]:
"""
Collapse folder
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
if act_like_dir(node, follow_links=state.follow_links):
path = node.path if node.path in state.index else node.path.parent
else:
path = node.path.parent
paths = {
indexed
for indexed in state.index
if path in (ancestors(indexed) | {indexed})
}
index = (state.index - paths) | {state.root.path}
invalidate_dirs = {path}
new_state = await forward(state, index=index, invalidate_dirs=invalidate_dirs)
return Stage(new_state, focus=path)

View File

@ -1,75 +0,0 @@
from locale import strxfrm
from os import linesep
from os.path import normpath, sep
from pathlib import PurePath
from typing import AsyncIterator, Callable
from pynvim_pp.nvim import Nvim
from pynvim_pp.types import NoneType
from ..fs.cartographer import is_dir
from ..fs.ops import is_dir as iis_dir
from ..registry import rpc
from ..settings.localization import LANG
from ..state.types import State
from .shared.index import indices
async def _cn(state: State, is_visual: bool, proc: Callable[[PurePath], str]) -> None:
async def gen_paths() -> AsyncIterator[str]:
if selection := state.selection:
for path in selection:
suffix = sep if await iis_dir(path) else ""
yield proc(path) + suffix
else:
nodes = indices(state, is_visual=is_visual)
async for node in nodes:
suffix = sep if is_dir(node) else ""
yield proc(node.path) + suffix
paths = sorted([path async for path in gen_paths()], key=strxfrm)
clip = linesep.join(paths)
copied_paths = ", ".join(paths)
await Nvim.fn.setreg(NoneType, "+", clip)
await Nvim.fn.setreg(NoneType, "*", clip)
await Nvim.write(LANG("copy_paths", copied_paths=copied_paths))
@rpc(blocking=False)
async def _copy_name(state: State, is_visual: bool) -> None:
"""
Copy dirname / filename
"""
await _cn(
state,
is_visual=is_visual,
proc=lambda p: normpath(p.name),
)
@rpc(blocking=False)
async def _copy_basename(state: State, is_visual: bool) -> None:
"""
Copy basename of dirname / filename
"""
await _cn(
state,
is_visual=is_visual,
proc=normpath,
)
@rpc(blocking=False)
async def _copy_relname(state: State, is_visual: bool) -> None:
"""
Copy relname of dirname / filename
"""
await _cn(
state,
is_visual=is_visual,
proc=lambda p: normpath(p.relative_to(state.root.path)),
)

View File

@ -1,171 +0,0 @@
from itertools import chain
from os import linesep
from pathlib import PurePath
from typing import AbstractSet, Awaitable, Callable, Mapping, MutableMapping, Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from std2.locale import pathsort_key
from ..fs.cartographer import act_like_dir
from ..fs.ops import ancestors, copy, cut, exists, unify_ancestors
from ..fs.types import Node
from ..lsp.notify import lsp_created, lsp_moved
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from ..view.ops import display_path
from .shared.index import indices
from .shared.refresh import refresh
from .shared.wm import kill_buffers
from .types import Stage
def _find_dest(src: PurePath, node: Node, follow_links: bool) -> PurePath:
parent = (
node.path if act_like_dir(node, follow_links=follow_links) else node.path.parent
)
dst = parent / src.name
return dst
async def _operation(
*,
state: State,
is_visual: bool,
nono: AbstractSet[PurePath],
op_name: str,
is_move: bool,
action: Callable[[Mapping[PurePath, PurePath]], Awaitable[None]],
) -> Optional[Stage]:
node = await anext(indices(state, is_visual=is_visual), None)
selection = state.selection
unified = unify_ancestors(selection)
if not unified or not node:
await Nvim.write(LANG("nothing_select"), error=True)
return None
elif not unified.isdisjoint(nono):
await Nvim.write(LANG("operation not permitted on root"), error=True)
return None
else:
pre_operations = {
src: _find_dest(src, node=node, follow_links=state.follow_links)
for src in unified
}
pre_existing = {
s: d for s, d in pre_operations.items() if await exists(d, follow=False)
}
new_operations: MutableMapping[PurePath, PurePath] = {}
while pre_existing:
source, dest = pre_existing.popitem()
resp = await Nvim.input(question=LANG("path_exists_err"), default=dest.name)
new_dest = dest.parent / resp if resp else None
if not new_dest:
pre_existing[source] = dest
break
elif await exists(new_dest, follow=False):
pre_existing[source] = new_dest
else:
new_operations[source] = new_dest
if pre_existing:
msg = linesep.join(
f"{display_path(s, state=state)} -> {display_path(d, state=state)}"
for s, d in sorted(
pre_existing.items(), key=lambda t: pathsort_key(t[0])
)
)
await Nvim.write(
LANG("paths already exist", operation=op_name, paths=msg),
error=True,
)
return None
else:
operations = {**pre_operations, **new_operations}
msg = linesep.join(
f"{display_path(s, state=state)} -> {display_path(d, state=state)}"
for s, d in sorted(operations.items(), key=lambda t: pathsort_key(t[0]))
)
question = LANG("confirm op", operation=op_name, paths=msg)
ans = await Nvim.confirm(
question=question,
answers=LANG("ask_yesno"),
answer_key={1: True, 2: False},
)
if not ans:
return None
else:
try:
await action(operations)
except Exception as e:
await Nvim.write(e, error=True)
return await refresh(state)
else:
parents = {
p.parent for p in chain(operations.keys(), operations.values())
}
invalidate_dirs = parents
index = state.index | parents
new_selection = {*operations.values()}
new_state = await forward(
state,
index=index,
selection=new_selection if is_move else selection,
invalidate_dirs=invalidate_dirs,
)
focus = next(
iter(sorted(new_selection, key=pathsort_key)),
None,
)
if is_move:
await kill_buffers(
last_used=new_state.window_order,
paths=selection,
reopen={},
)
await lsp_moved(operations)
else:
await lsp_created(new_selection)
return Stage(new_state, focus=focus)
@rpc(blocking=False)
async def _cut(state: State, is_visual: bool) -> Optional[Stage]:
"""
Cut selected
"""
cwd, root = await Nvim.getcwd(), state.root.path
nono = {cwd, root} | ancestors(cwd, root)
return await _operation(
state=state,
is_visual=is_visual,
nono=nono,
op_name=LANG("cut"),
action=cut,
is_move=True,
)
@rpc(blocking=False)
async def _copy(state: State, is_visual: bool) -> Optional[Stage]:
"""
Copy selected
"""
return await _operation(
state=state,
is_visual=is_visual,
nono=frozenset(),
op_name=LANG("copy"),
action=copy,
is_move=False,
)

View File

@ -1,102 +0,0 @@
from locale import strxfrm
from os import linesep
from pathlib import PurePath
from subprocess import CalledProcessError
from typing import Awaitable, Callable, Iterable, Optional
from pynvim_pp.nvim import Nvim
from std2.asyncio.subprocess import call
from ..fs.ops import ancestors, remove, unify_ancestors, which
from ..lsp.notify import lsp_removed
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from ..view.ops import display_path
from .shared.index import indices
from .shared.refresh import refresh
from .shared.wm import kill_buffers
from .types import Stage
async def _remove(
state: State,
is_visual: bool,
yeet: Callable[[Iterable[PurePath]], Awaitable[None]],
) -> Optional[Stage]:
cwd, root = await Nvim.getcwd(), state.root.path
nono = {cwd, root} | ancestors(cwd, root)
selection = state.selection or {
node.path async for node in indices(state, is_visual=is_visual)
}
unified = unify_ancestors(selection)
if not unified:
return None
elif not unified.isdisjoint(nono):
await Nvim.write(LANG("operation not permitted on root"), error=True)
return None
else:
display_paths = linesep.join(
sorted((display_path(path, state=state) for path in unified), key=strxfrm)
)
question = LANG("ask_trash", display_paths=display_paths)
ans = await Nvim.confirm(
question=question,
answers=LANG("ask_yesno"),
answer_key={1: True, 2: False},
)
if not ans:
return None
else:
try:
await yeet(unified)
except Exception as e:
await Nvim.write(e, error=True)
return await refresh(state)
else:
invalidate_dirs = {path.parent for path in unified}
new_state = await forward(
state, selection=frozenset(), invalidate_dirs=invalidate_dirs
)
await kill_buffers(
last_used=new_state.window_order, paths=selection, reopen={}
)
await lsp_removed(unified)
return Stage(new_state)
@rpc(blocking=False)
async def _delete(state: State, is_visual: bool) -> Optional[Stage]:
"""
Delete selected
"""
return await _remove(state, is_visual=is_visual, yeet=remove)
async def _sys_trash(paths: Iterable[PurePath]) -> None:
cwd = await Nvim.getcwd()
if arg0 := which("trash"):
try:
await call(arg0, "--", *map(str, paths), cwd=cwd)
except CalledProcessError as e:
await Nvim.write(e, e.stderr, e.stdout, error=True)
else:
await Nvim.write(LANG("sys_trash_err"), error=True)
@rpc(blocking=False)
async def _trash(state: State, is_visual: bool) -> Optional[Stage]:
"""
Delete selected
"""
return await _remove(state, is_visual=is_visual, yeet=_sys_trash)

View File

@ -1,48 +0,0 @@
from typing import Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import FilterPattern, Selection, State
from .shared.index import indices
from .types import Stage
@rpc(blocking=False)
async def _clear_filter(state: State, is_visual: bool) -> Optional[Stage]:
"""
Clear filter
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
focus = node.path
new_state = await forward(state, filter_pattern=None)
return Stage(new_state, focus=focus)
@rpc(blocking=False)
async def _filter(state: State, is_visual: bool) -> Optional[Stage]:
"""
Update filter
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
focus = node.path
old_p = state.filter_pattern.pattern if state.filter_pattern else ""
pattern = await Nvim.input(question=LANG("new_filter"), default=old_p)
filter_pattern = FilterPattern(pattern=pattern) if pattern else None
selection: Selection = state.selection if filter_pattern else frozenset()
new_state = await forward(
state, selection=selection, filter_pattern=filter_pattern
)
return Stage(new_state, focus=focus)

View File

@ -1,105 +0,0 @@
from os.path import normcase, normpath
from pathlib import PurePath
from typing import Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from ..fs.cartographer import act_like_dir
from ..registry import rpc
from ..settings.localization import LANG
from ..state.types import State
from .shared.current import maybe_path_above, new_current_file, new_root
from .shared.index import indices
from .types import Stage
async def _jump(state: State, path: PurePath) -> Optional[Stage]:
if new_state := await maybe_path_above(state, paths={path}):
return Stage(new_state, focus=path)
elif stage := await new_current_file(state, current=path):
return Stage(stage.state, focus=path)
else:
return None
@rpc(blocking=False)
async def _jump_to_current(state: State, is_visual: bool) -> Optional[Stage]:
"""
Jump to active file
"""
if not (curr := state.current):
return None
else:
return await _jump(state, path=curr)
@rpc(blocking=False)
async def _refocus(state: State, is_visual: bool) -> Stage:
"""
Follow cwd update
"""
cwd = await Nvim.getcwd()
new_state = await new_root(state, new_cwd=cwd, indices=frozenset())
focus = new_state.root.path
return Stage(new_state, focus=focus)
@rpc(blocking=False)
async def _change_dir(state: State, is_visual: bool) -> Optional[Stage]:
"""
Change root directory
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
cwd = (
node.path
if act_like_dir(node, follow_links=state.follow_links)
else node.path.parent
)
new_state = await new_root(state, new_cwd=cwd, indices=frozenset())
escaped = await Nvim.fn.fnameescape(str, normcase(new_state.root.path))
await Nvim.exec(f"chdir {escaped}")
await Nvim.write(LANG("new cwd", cwd=normpath(new_state.root.path)))
return Stage(new_state, focus=new_state.root.path)
@rpc(blocking=False)
async def _change_focus(state: State, is_visual: bool) -> Optional[Stage]:
"""
Refocus root directory
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
new_base = (
node.path
if act_like_dir(node, follow_links=state.follow_links)
else node.path.parent
)
new_state = await new_root(state, new_cwd=new_base, indices=frozenset())
focus = node.path
return Stage(new_state, focus=focus)
@rpc(blocking=False)
async def _change_focus_up(state: State, is_visual: bool) -> Optional[Stage]:
"""
Refocus root directory up
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
new_state = await new_root(
state, new_cwd=state.root.path.parent, indices=frozenset()
)
return Stage(new_state, focus=node.path)

View File

@ -1,95 +0,0 @@
from enum import Enum, auto
from pathlib import Path
from typing import Sequence, Tuple
from uuid import uuid4
from webbrowser import open as open_w
from pynvim_pp.buffer import Buffer
from pynvim_pp.float_win import list_floatwins, open_float_win
from pynvim_pp.nvim import Nvim
from std2.argparse import ArgparseError, ArgParser
from std2.types import never
from ..consts import (
CONFIGURATION_MD,
CONFIGURATION_URI,
FEATURES_MD,
FEATURES_URI,
KEYBIND_MD,
KEYBIND_URI,
MIGRATION_MD,
MIGRATION_URI,
README_MD,
README_URI,
THEME_MD,
THEME_URI,
)
from ..registry import rpc
from ..state.types import State
_NS = uuid4()
class _Topics(Enum):
index = auto()
features = auto()
keybind = auto()
config = auto()
theme = auto()
migration = auto()
def _directory(topic: _Topics) -> Tuple[Path, str]:
if topic is _Topics.index:
return README_MD, README_URI
elif topic is _Topics.features:
return FEATURES_MD, FEATURES_URI
elif topic is _Topics.keybind:
return KEYBIND_MD, KEYBIND_URI
elif topic is _Topics.config:
return CONFIGURATION_MD, CONFIGURATION_URI
elif topic is _Topics.theme:
return THEME_MD, THEME_URI
elif topic is _Topics.migration:
return MIGRATION_MD, MIGRATION_URI
else:
never(topic)
def _parse_args(args: Sequence[str]) -> Tuple[_Topics, bool]:
parser = ArgParser()
parser.add_argument(
"topic",
nargs="?",
choices=tuple(topic.name for topic in _Topics),
default=_Topics.index.name,
)
parser.add_argument("-w", "--web", action="store_true", default=False)
ns = parser.parse_args(args)
return _Topics[ns.topic], ns.web
@rpc(blocking=False)
async def _help(state: State, args: Sequence[str]) -> None:
"""
Open help doc
"""
try:
topic, use_web = _parse_args(args)
except ArgparseError as e:
await Nvim.write(e, error=True)
else:
md, uri = _directory(topic)
web_d = open_w(uri) if use_web else False
if not web_d:
async for win in list_floatwins(_NS):
await win.close()
lines = md.read_text("UTF-8").splitlines()
buf = await Buffer.create(
listed=False, scratch=True, wipe=True, nofile=True, noswap=True
)
await buf.set_lines(lines=lines)
await buf.opts.set("modifiable", val=False)
await buf.opts.set("syntax", val="markdown")
await open_float_win(_NS, margin=0, relsize=0.95, buf=buf, border="rounded")

View File

@ -1,79 +0,0 @@
from os.path import normpath, relpath
from pathlib import PurePath
from typing import MutableMapping, Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from std2.locale import pathsort_key
from ..fs.cartographer import act_like_dir
from ..fs.ops import ancestors, exists, link, resolve
from ..lsp.notify import lsp_created
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from ..view.ops import display_path
from .shared.current import maybe_path_above
from .shared.index import indices
from .shared.refresh import refresh
from .types import Stage
@rpc(blocking=False)
async def _link(state: State, is_visual: bool) -> Optional[Stage]:
"""
Symlink selected
"""
node = await anext(indices(state, is_visual=is_visual), None)
if node is None:
return None
else:
parent = (
node.path
if act_like_dir(node, follow_links=state.follow_links)
else node.path.parent
)
selection = state.selection or {node.path}
operations: MutableMapping[PurePath, PurePath] = {}
for selected in selection:
display = display_path(selected, state=state)
if child := await Nvim.input(
question=LANG("link", src=display), default=""
):
try:
dst = await resolve(parent / child, strict=False)
except Exception as e:
await Nvim.write(e, error=True)
return None
else:
if dst in operations or await exists(dst, follow=False):
await Nvim.write(
LANG("already_exists", name=normpath(dst)), error=True
)
return None
else:
src = PurePath(relpath(selected, start=dst.parent))
operations[dst] = src
else:
return None
try:
await link(operations)
except Exception as e:
await Nvim.write(e, error=True)
return await refresh(state)
else:
paths = operations.keys()
new_state = await maybe_path_above(state, paths=paths) or state
await lsp_created(paths)
focus, *_ = sorted(paths, key=pathsort_key)
invalidate_dirs = {path.parent for path in paths}
index = state.index | ancestors(*paths)
next_state = await forward(
new_state,
index=index,
invalidate_dirs=invalidate_dirs,
)
return Stage(next_state, focus=focus)

View File

@ -1,57 +0,0 @@
from locale import strxfrm
from pathlib import PurePath
from typing import Any, Iterator, MutableMapping, MutableSet, Optional, Tuple
from pynvim_pp.nvim import Nvim
from std2.locale import pathsort_key
from std2.pathlib import is_relative_to
from ..registry import rpc
from ..settings.localization import LANG
from ..state.types import State
from ..view.ops import display_path
from .focus import _jump
from .types import Stage
def _order(root: PurePath, marks: str, path: PurePath) -> Tuple[bool, str, Any]:
return not is_relative_to(path, root), "", pathsort_key(path)
def _display_path(state: State, marks: str, path: PurePath, idx: int) -> str:
display = display_path(path, state=state)
return f"{idx}. [{marks}] {display}"
@rpc(blocking=False)
async def _bookmark_goto(state: State, is_visual: bool) -> Optional[Stage]:
"""
Goto bookmark
"""
def cont() -> Iterator[Tuple[str, PurePath]]:
root = state.root.path
markers: MutableMapping[str, PurePath] = {}
for path, marks in state.markers.bookmarks.items():
for mark in marks:
if m := markers.get(mark):
markers[mark] = max(m, path)
else:
markers[mark] = path
seen: MutableSet[PurePath] = set()
for _, path in sorted(markers.items(), key=lambda kv: _order(root, *kv)):
if path not in seen:
ms = sorted(state.markers.bookmarks.get(path, ()), key=strxfrm)
yield "".join(ms), path
opts = {
_display_path(state, marks=marks, path=path, idx=idx): path
for idx, (marks, path) in enumerate(cont(), start=1)
}
if mark := await Nvim.input_list(opts):
return await _jump(state, path=mark)
else:
await Nvim.write(LANG("no_bookmarks"), error=True)
return None

View File

@ -1,68 +0,0 @@
from os import sep
from os.path import abspath, normpath
from pathlib import PurePath
from typing import Optional
from pynvim_pp.nvim import Nvim
from std2 import anext
from ..fs.cartographer import act_like_dir
from ..fs.ops import ancestors, exists, mkdir, new
from ..lsp.notify import lsp_created
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from .shared.current import maybe_path_above
from .shared.index import indices
from .shared.refresh import refresh
from .types import Stage
@rpc(blocking=False)
async def _new(state: State, is_visual: bool) -> Optional[Stage]:
"""
new file / folder
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
parent = (
node.path
if act_like_dir(node, follow_links=state.follow_links)
else node.path.parent
)
child = await Nvim.input(question=LANG("pencil"), default="")
if not child:
return None
else:
path = PurePath(abspath(parent / child))
if await exists(path, follow=False):
await Nvim.write(
LANG("already_exists", name=normpath(path)), error=True
)
return None
else:
try:
if child.endswith(sep):
await mkdir((path,))
else:
await new((path,))
except Exception as e:
await Nvim.write(e, error=True)
return await refresh(state=state)
else:
new_state = await maybe_path_above(state, paths={path}) or state
invalidate_dirs = {path.parent}
index = state.index | ancestors(path)
next_state = await forward(
new_state,
index=index,
invalidate_dirs=invalidate_dirs,
)
await lsp_created((path,))
return Stage(next_state, focus=path)

View File

@ -1,11 +0,0 @@
from typing import Any
from ..registry import rpc
from ..state.types import State
@rpc(blocking=False)
async def _noop(state: State, *_: Any) -> None:
"""
NOOP
"""

View File

@ -1,52 +0,0 @@
import sys
from asyncio import create_task
from pathlib import PurePath
from subprocess import CalledProcessError
from pynvim_pp.logging import suppress_and_log
from pynvim_pp.nvim import Nvim
from std2 import anext
from std2.asyncio.subprocess import call
from std2.pathlib import AnyPath
from std2.platform import OS, os
from ..fs.ops import which
from ..registry import rpc
from ..settings.localization import LANG
from ..state.types import State
from .shared.index import indices
async def _call(cwd: PurePath, arg0: AnyPath, *args: AnyPath) -> None:
try:
await call(arg0, *args, cwd=cwd)
except CalledProcessError as e:
await Nvim.write(e, e.stderr, e.stdout, error=True)
async def _open_gui(path: PurePath, cwd: PurePath) -> None:
with suppress_and_log():
if sys.platform == "win32":
from os import startfile
startfile(path, cwd=cwd)
elif os is OS.macos and (arg0 := which("open")):
await _call(cwd, arg0, "--", path)
elif os is OS.linux and (arg0 := which("xdg-open")):
await _call(cwd, arg0, path)
else:
await Nvim.write(LANG("sys_open_err"))
@rpc(blocking=False)
async def _open_sys(state: State, is_visual: bool) -> None:
"""
Open using finder / dolphin, etc
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
cwd = await Nvim.getcwd()
create_task(_open_gui(node.path, cwd=cwd))

View File

@ -1,20 +0,0 @@
from pynvim_pp.nvim import Nvim
from pynvim_pp.window import Window
from ..registry import rpc
from ..state.types import State
from .shared.wm import find_fm_windows_in_tab
@rpc(blocking=False)
async def _quit(state: State, is_visual: bool) -> None:
"""
Close sidebar
"""
wins = await Window.list()
if len(wins) <= 1:
await Nvim.exec("quit")
else:
async for win in find_fm_windows_in_tab(state.window_order):
await win.close()

View File

@ -1,145 +0,0 @@
from pathlib import Path, PurePath
from posixpath import sep
from typing import Optional, Sequence
from uuid import uuid4
from pynvim_pp.atomic import Atomic
from pynvim_pp.buffer import Buffer
from pynvim_pp.nvim import Nvim
from pynvim_pp.operators import operator_marks
from pynvim_pp.rpc_types import NvimError
from pynvim_pp.types import NoneType
from std2.difflib import trans_inplace
from std2.pickle.decoder import new_decoder
from std2.pickle.types import DecodeError
from ..consts import URI_SCHEME
from ..state.types import State
from ..view.types import Derived
from .shared.wm import find_fm_windows
class UnrecoverableError(Exception):
...
_NS = uuid4()
_DECODER = new_decoder[Sequence[str]](Sequence[str])
_HOME = Path.home()
def _buf_name(root: PurePath) -> str:
try:
rel = root.relative_to(_HOME)
except ValueError:
name = root.as_posix()
else:
name = f"~{sep}{rel.as_posix()}"
return name
def _update(
use_extmarks: bool,
buf: Buffer,
ns: int,
derived: Derived,
hashed_lines: Sequence[str],
) -> Atomic:
atomic = Atomic()
for (i1, i2), (j1, j2) in trans_inplace(
src=hashed_lines, dest=derived.hashed, unifying=10
):
atomic.buf_clear_namespace(buf, ns, i1, i2)
atomic.buf_set_lines(buf, i1, i2, True, derived.lines[j1:j2])
for idx, highlights in enumerate(derived.highlights[j1:j2], start=i1):
for hl in highlights:
atomic.buf_add_highlight(buf, ns, hl.group, idx, hl.begin, hl.end)
for idx, badges in enumerate(derived.badges[j1:j2], start=i1):
vtxt = tuple((bdg.text, bdg.group) for bdg in badges)
if use_extmarks:
atomic.buf_set_extmark(
buf, ns, idx, -1, {"virt_text": vtxt, "hl_mode": "combine"}
)
else:
atomic.buf_set_virtual_text(buf, ns, idx, vtxt, {})
atomic.buf_set_var(buf, str(_NS), derived.hashed)
return atomic
async def redraw(state: State, focus: Optional[PurePath]) -> None:
focus_row = state.derived.path_row_lookup.get(focus) if focus else None
buf_name = _buf_name(state.root.path)
ns = await Nvim.create_namespace(_NS)
use_extmarks = await Nvim.api.has("nvim-0.6")
async for win, buf in find_fm_windows():
is_fm_win = await win.vars.get(bool, URI_SCHEME)
p_count = await buf.line_count()
n_count = len(state.derived.lines)
row, col = await win.get_cursor()
(r1, c1), (r2, c2) = await operator_marks(buf, visual_type=None)
buf_var = await buf.vars.get(NoneType, str(_NS))
try:
hashed_lines = _DECODER(buf_var)
except DecodeError:
hashed_lines = ("",)
if focus_row is not None:
new_row: Optional[int] = focus_row + 1
elif row >= n_count:
new_row = n_count
elif p_count != n_count:
new_row = row + 1
else:
new_row = None
a1 = Atomic()
a1.buf_set_option(buf, "modifiable", True)
a2 = _update(
use_extmarks,
buf=buf,
ns=ns,
derived=state.derived,
hashed_lines=hashed_lines,
)
a3 = Atomic()
a3.buf_set_option(buf, "modifiable", False)
a3.call_function("setpos", ("'<", (buf.number, r1 + 1, c1 + 1, 0)))
a3.call_function("setpos", ("'>", (buf.number, r2 + 1, c2, 0)))
if new_row is not None:
win_height = await win.get_height()
win_lo = await Nvim.fn.line(int, "w0", win)
win_hi = await Nvim.fn.line(int, "w$", win)
lo = max(1, new_row - win_height // 2)
hi = min(n_count, new_row + win_height // 2)
if new_row < win_lo or new_row > win_hi:
a3.win_set_cursor(win, (lo, 0))
a3.win_set_cursor(win, (hi, 0))
a3.win_set_cursor(win, (lo, 0))
a3.win_set_cursor(win, (hi, 0))
a3.win_set_cursor(win, (new_row, col))
a3.buf_set_name(buf, f"{URI_SCHEME}://{buf_name}")
a3.win_set_var(win, URI_SCHEME, True)
if not is_fm_win:
for key, val in state.settings.win_local_opts.items():
a3.win_set_option(win, key, val)
a4 = a1 + a2 + a3
try:
await a4.commit(NoneType)
except NvimError as e:
raise UnrecoverableError(e)

View File

@ -1,23 +0,0 @@
from contextlib import asynccontextmanager
from typing import AsyncIterator
from pynvim_pp.nvim import Nvim
from ..registry import rpc
from ..settings.localization import LANG
from ..state.types import State
from .shared.refresh import refresh as _refresh
from .types import Stage
@asynccontextmanager
async def with_manual() -> AsyncIterator[None]:
await Nvim.write(LANG("hourglass"))
yield None
await Nvim.write(LANG("ok_sym"))
@rpc(blocking=False)
async def refresh(state: State, is_visual: bool) -> Stage:
async with with_manual():
return await _refresh(state)

View File

@ -1,75 +0,0 @@
from os.path import abspath, normpath
from pathlib import PurePath
from typing import Optional
from pynvim_pp.hold import hold_win
from pynvim_pp.nvim import Nvim
from pynvim_pp.window import Window
from std2 import anext
from ..fs.ops import ancestors, exists, rename
from ..lsp.notify import lsp_moved
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import State
from .shared.current import maybe_path_above
from .shared.index import indices
from .shared.refresh import refresh
from .shared.wm import kill_buffers
from .types import Stage
@rpc(blocking=False)
async def _rename(state: State, is_visual: bool) -> Optional[Stage]:
"""
rename file / folder
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
old_path = node.path
child = await Nvim.input(question=LANG("pencil"), default=old_path.name)
if not child:
return None
else:
new_path = PurePath(abspath(old_path.parent / child))
operations = {old_path: new_path}
if await exists(new_path, follow=False):
await Nvim.write(
LANG("already_exists", name=normpath(new_path)), error=True
)
return None
else:
killed = await kill_buffers(
last_used=state.window_order,
paths={old_path},
reopen={old_path: new_path},
)
try:
await rename(operations)
except Exception as e:
await Nvim.write(e, error=True)
return await refresh(state=state)
else:
async with hold_win(win=None):
for win, new_path in killed.items():
await Window.set_current(win)
escaped = await Nvim.fn.fnameescape(str, normpath(new_path))
await Nvim.exec(f"edit! {escaped}")
new_state = await maybe_path_above(state, paths={new_path}) or state
parents = ancestors(new_path)
invalidate_dirs = {old_path.parent, new_path.parent}
index = state.index | parents
new_selection = {new_path} if state.selection else frozenset()
next_state = await forward(
new_state,
index=index,
invalidate_dirs=invalidate_dirs,
selection=new_selection,
)
await lsp_moved(operations)
return Stage(next_state, focus=new_path)

View File

@ -1,42 +0,0 @@
from operator import add, sub
from typing import Callable, Optional
from pynvim_pp.window import Window
from ..registry import rpc
from ..state.next import forward
from ..state.types import State
from .shared.wm import is_fm_window, resize_fm_windows
from .types import Stage
async def _resize(
state: State, direction: Callable[[int, int], int]
) -> Optional[Stage]:
win = await Window.get_current()
if not await is_fm_window(win):
return None
else:
old_width = await win.get_width()
new_width = max(direction(old_width, 10), 1)
new_state = await forward(state, width=new_width)
await resize_fm_windows(new_state.window_order, width=new_state.width)
return Stage(new_state)
@rpc(blocking=False)
async def _bigger(state: State, is_visual: bool) -> Optional[Stage]:
"""
Bigger sidebar
"""
return await _resize(state, direction=add)
@rpc(blocking=False)
async def _smaller(state: State, is_visual: bool) -> Optional[Stage]:
"""
Smaller sidebar
"""
return await _resize(state, direction=sub)

View File

@ -1,37 +0,0 @@
from asyncio import gather
from typing import Optional
from pynvim_pp.nvim import Nvim
from pynvim_pp.rpc_types import NvimError
from std2.asyncio import pure
from ..lsp.diagnostics import poll
from ..registry import rpc
from ..state.next import forward
from ..state.ops import dump_session
from ..state.types import State
from ..version_ctl.git import status
from ..version_ctl.types import VCStatus
from .shared.refresh import refresh
from .types import Stage
@rpc(blocking=False)
async def scheduled_update(state: State, init: bool = False) -> Optional[Stage]:
cwd = await Nvim.getcwd()
store = dump_session(state) if state.vim_focus else pure(None)
try:
stage, diagnostics, vc, _ = await gather(
refresh(state=state),
poll(state.settings.min_diagnostics_severity),
status(cwd, prev=state.vc)
if not init and state.enable_vc
else pure(VCStatus()),
store,
)
except NvimError:
return None
else:
new_state = await forward(stage.state, diagnostics=diagnostics, vc=vc)
return Stage(new_state, focus=stage.focus)

View File

@ -1,27 +0,0 @@
from ..registry import rpc
from ..state.next import forward
from ..state.types import State
from .shared.index import indices
from .types import Stage
@rpc(blocking=False)
async def _clear_selection(state: State, is_visual: bool) -> Stage:
"""
Clear selected
"""
new_state = await forward(state, selection=frozenset())
return Stage(new_state)
@rpc(blocking=False)
async def _select(state: State, is_visual: bool) -> Stage:
"""
Folder / File -> select
"""
nodes = indices(state, is_visual=is_visual)
selection = state.selection ^ {node.path async for node in nodes}
new_state = await forward(state, selection=selection)
return Stage(new_state)

View File

@ -1,65 +0,0 @@
from pathlib import PurePath
from typing import AbstractSet, Iterator, Optional
from std2.locale import pathsort_key
from std2.pathlib import is_relative_to, longest_common_path
from ...fs.cartographer import new
from ...fs.ops import ancestors
from ...state.next import forward
from ...state.types import State
from ..types import Stage
async def new_current_file(state: State, current: PurePath) -> Stage:
"""
New file focused in buf
"""
parents = ancestors(current)
if state.root.path in parents:
invalidate_dirs = {current.parent}
index = state.index | parents
new_state = await forward(
state,
index=index,
invalidate_dirs=invalidate_dirs,
current=current,
)
else:
new_state = await forward(state, current=current)
focus = current if state.follow else None
return Stage(new_state, focus=focus)
async def new_root(
state: State,
new_cwd: PurePath,
indices: AbstractSet[PurePath],
) -> State:
index = state.index | ancestors(new_cwd) | {new_cwd} | indices
root = await new(
state.executor, follow_links=state.follow_links, root=new_cwd, index=index
)
selection = {path for path in state.selection if root.path in ancestors(path)}
return await forward(state, root=root, selection=selection, index=index)
async def maybe_path_above(
state: State, paths: AbstractSet[PurePath]
) -> Optional[State]:
root = state.root.path
if all(is_relative_to(path, root) for path in paths):
return None
else:
def cont() -> Iterator[PurePath]:
for path in paths:
lcp = longest_common_path(path, root)
yield lcp if lcp else path.parent
ordered = sorted(cont(), key=pathsort_key)
indices = ancestors(*ordered)
new_cwd, *_ = ordered
return await new_root(state=state, new_cwd=new_cwd, indices=indices)

View File

@ -1,35 +0,0 @@
from typing import AsyncIterator, Optional
from pynvim_pp.operators import operator_marks
from pynvim_pp.window import Window
from ...fs.types import Node
from ...state.types import State
from .wm import is_fm_buffer
def _row_index(state: State, row: int) -> Optional[Node]:
if (row >= 0) and (row < len(state.derived.node_row_lookup)):
return state.derived.node_row_lookup[row]
else:
return None
async def indices(state: State, is_visual: bool) -> AsyncIterator[Node]:
win = await Window.get_current()
buf = await win.get_buf()
if not await is_fm_buffer(buf):
return
else:
row, _ = await win.get_cursor()
if node := _row_index(state, row):
yield node
if is_visual:
(row1, _), (row2, _) = await operator_marks(buf, visual_type=None)
for r in range(row1, row2 + 1):
if r != row:
if node := _row_index(state, r):
yield node

View File

@ -1,117 +0,0 @@
from contextlib import suppress
from mimetypes import guess_type
from os.path import getsize, normpath
from pathlib import PurePath
from posixpath import sep
from typing import AsyncContextManager, Optional, cast
from pynvim_pp.buffer import Buffer
from pynvim_pp.hold import hold_win
from pynvim_pp.nvim import Nvim
from pynvim_pp.window import Window
from std2 import anext
from std2.aitertools import achain, to_async
from std2.contextlib import nullacontext
from ...settings.localization import LANG
from ...state.next import forward
from ...state.types import State
from ..types import ClickType, Stage
from .wm import (
find_buffers_with_file,
find_non_fm_windows_in_tab,
find_window_with_file_in_tab,
new_window,
resize_fm_windows,
)
async def _show_file(*, state: State, click_type: ClickType) -> None:
if click_type is ClickType.tertiary:
await Nvim.exec("tabnew")
win = await Window.get_current()
for key, val in state.settings.win_actual_opts.items():
await win.opts.set(key, val=val)
if path := state.current:
mgr = (
cast(AsyncContextManager[None], hold_win(win=None))
if click_type is ClickType.secondary
else nullacontext(None)
)
async with mgr:
non_fm_windows = [
win
async for win in find_non_fm_windows_in_tab(
last_used=state.window_order
)
]
buf = await anext(find_buffers_with_file(file=path), None)
win = await anext(
achain(
find_window_with_file_in_tab(
last_used=state.window_order, file=path
),
to_async(non_fm_windows),
),
cast(Window, None),
) or await new_window(
last_used=state.window_order,
win_local=state.settings.win_actual_opts,
open_left=not state.settings.open_left,
width=None
if len(non_fm_windows)
else await Nvim.opts.get(int, "columns") - state.width - 1,
)
await Window.set_current(win)
non_fm_count = len(non_fm_windows)
if click_type is ClickType.v_split and non_fm_count:
await Nvim.exec("vnew")
temp_buf = await Buffer.get_current()
await temp_buf.opts.set("bufhidden", val="wipe")
elif click_type is ClickType.h_split and non_fm_count:
await Nvim.exec("new")
temp_buf = await Buffer.get_current()
await temp_buf.opts.set("bufhidden", val="wipe")
win = await Window.get_current()
if buf:
await win.set_buf(buf)
else:
escaped = await Nvim.fn.fnameescape(str, normpath(path))
await Nvim.exec(f"edit! {escaped}")
await resize_fm_windows(last_used=state.window_order, width=state.width)
async def open_file(
state: State, path: PurePath, click_type: ClickType
) -> Optional[Stage]:
mime, _ = guess_type(path.name, strict=False)
m_type, _, _ = (mime or "").partition(sep)
with suppress(OSError):
size = getsize(path)
question = LANG("mime_warn", name=path.name, mime=str(mime))
go = (
await Nvim.confirm(
question=question,
answers=LANG("ask_yesno"),
answer_key={1: True, 2: False},
)
if m_type in state.settings.mime.warn
and path.suffix not in state.settings.mime.allow_exts
else True
)
if go:
new_state = await forward(state, current=path)
await _show_file(state=new_state, click_type=click_type)
return Stage(new_state, focus=path)
else:
return None

View File

@ -1,78 +0,0 @@
from asyncio import gather
from pathlib import PurePath
from typing import AbstractSet, Mapping
from pynvim_pp.rpc_types import ExtData
from pynvim_pp.window import Window
from std2.types import Void
from ...fs.ops import ancestors, exists_many
from ...nvim.markers import markers
from ...state.next import forward
from ...state.types import State
from ..shared.wm import find_current_buffer_path
from ..types import Stage
async def _index(state: State, paths: AbstractSet[PurePath]) -> AbstractSet[PurePath]:
index = {
path
for path, exists in (await exists_many(state.index, follow=True)).items()
if exists
} | paths
return index
async def _selection(state: State) -> AbstractSet[PurePath]:
selection = {
selected
for selected, exists in (
await exists_many(state.selection, follow=False)
).items()
if exists
}
return selection
async def _window_order(state: State) -> Mapping[ExtData, None]:
window_ids = {w.data for w in await Window.list()}
window_order = {
win_id: None for win_id in state.window_order if win_id in window_ids
}
return window_order
async def refresh(state: State) -> Stage:
cwd = state.root.path
invalidate_dirs = {cwd}
current, index, selection, window_order, mks = await gather(
find_current_buffer_path(),
_index(state, paths=invalidate_dirs),
_selection(state),
_window_order(state),
markers(),
)
current_ancestors = ancestors(current) if current else frozenset()
new_current = current if cwd in current_ancestors else None
parent_paths: AbstractSet[PurePath] = (
current_ancestors if state.follow else frozenset()
)
new_index = index if new_current else index | parent_paths
focus = current if state.follow else None
new_state = await forward(
state,
index=new_index,
selection=selection,
markers=mks,
invalidate_dirs=invalidate_dirs,
current=new_current or Void,
window_order=window_order,
trace=False,
)
return Stage(new_state, focus=focus)

View File

@ -1,254 +0,0 @@
from contextlib import suppress
from math import inf
from pathlib import PurePath
from typing import (
AbstractSet,
AsyncIterator,
Mapping,
Optional,
Sequence,
Tuple,
Union,
cast,
)
from urllib.parse import urlsplit
from pynvim_pp.atomic import Atomic
from pynvim_pp.buffer import Buffer
from pynvim_pp.keymap import Keymap
from pynvim_pp.lib import resolve_path
from pynvim_pp.nvim import Nvim
from pynvim_pp.rpc_types import ExtData
from pynvim_pp.tabpage import Tabpage
from pynvim_pp.types import NoneType
from pynvim_pp.window import Window
from ...consts import FM_FILETYPE, URI_SCHEME
from ...fs.ops import ancestors
from ...settings.types import Settings
def is_fm_buf_name(name: str) -> bool:
with suppress(ValueError):
uri = urlsplit(name)
return uri.scheme == URI_SCHEME
return False
async def is_fm_buffer(buf: Buffer) -> bool:
ft = await buf.filetype()
if ft == FM_FILETYPE:
return True
elif name := await buf.get_name():
return is_fm_buf_name(name)
return False
async def is_fm_window(win: Window) -> bool:
buf = await win.get_buf()
return await is_fm_buffer(buf)
async def find_windows_in_tab(
last_used: Mapping[ExtData, None], no_secondary: bool
) -> AsyncIterator[Window]:
ordering = {win_id: idx for idx, win_id in enumerate(reversed(last_used.keys()))}
tab = await Tabpage.get_current()
wins = await tab.list_wins()
atomic = Atomic()
for win in wins:
atomic.win_get_position(win)
pos = cast(Sequence[Tuple[int, int]], await atomic.commit(NoneType))
positions = {win.data: rc for win, rc in zip(wins, pos)}
def key_by(win: Window) -> Tuple[float, float, float]:
"""
-> sort by last_used, then row, then col
"""
order = ordering.get(win.data, inf)
row, col = positions.get(win.data, (inf, inf))
return order, col, row
ordered = sorted(wins, key=key_by)
for win in ordered:
is_preview = await win.opts.get(bool, "previewwindow")
buf = await win.get_buf()
ft = await buf.filetype()
is_secondary = is_preview or ft == "qf"
if not is_secondary or not no_secondary:
yield win
async def find_fm_windows() -> AsyncIterator[Tuple[Window, Buffer]]:
for win in await Window.list():
buf = await win.get_buf()
if await is_fm_buffer(buf):
yield win, buf
async def find_fm_windows_in_tab(
last_used: Mapping[ExtData, None]
) -> AsyncIterator[Window]:
async for win in find_windows_in_tab(last_used, no_secondary=True):
buf = await win.get_buf()
if await is_fm_buffer(buf):
yield win
async def find_non_fm_windows_in_tab(
last_used: Mapping[ExtData, None]
) -> AsyncIterator[Window]:
async for win in find_windows_in_tab(last_used, no_secondary=True):
buf = await win.get_buf()
if not await is_fm_buffer(buf):
yield win
async def find_window_with_file_in_tab(
last_used: Mapping[ExtData, None], file: PurePath
) -> AsyncIterator[Window]:
async for win in find_windows_in_tab(last_used, no_secondary=True):
buf = await win.get_buf()
if name := await buf.get_name():
if PurePath(name) == file:
yield win
async def find_fm_buffers() -> AsyncIterator[Buffer]:
for buf in await Buffer.list(listed=True):
if await is_fm_buffer(buf):
yield buf
async def find_buffers_with_file(file: PurePath) -> AsyncIterator[Buffer]:
for buf in await Buffer.list(listed=True):
if name := await buf.get_name():
if PurePath(name) == file:
yield buf
async def find_current_buffer_path(
buf_name: Optional[str] = None,
) -> Optional[PurePath]:
if buf_name is None:
buf = await Buffer.get_current()
buf_name = await buf.get_name()
if buf_name and not is_fm_buf_name(buf_name):
return await resolve_path(None, path=buf_name)
return None
async def setup_fm_buf(settings: Settings, buf: Buffer) -> None:
await buf.opts.set("modifiable", val=False)
await buf.opts.set("filetype", val=FM_FILETYPE)
await buf.opts.set("undolevels", val=-1)
km = Keymap()
_ = km.n("{") << f"{settings.page_increment}g<up>"
_ = km.n("}") << f"{settings.page_increment}g<down>"
for function, mappings in settings.keymap.items():
for mapping in mappings:
_ = (
km.n(mapping, noremap=True, silent=True, nowait=True)
<< f"<cmd>lua {function}(false)<cr>"
)
_ = (
km.v(mapping, noremap=True, silent=True, nowait=True)
<< rf"<c-\><c-n><cmd>lua {function}(true)<cr>"
)
await km.drain(buf=buf).commit(NoneType)
async def new_fm_buffer(settings: Settings) -> Buffer:
buf = await Buffer.create(
listed=False, scratch=True, wipe=False, nofile=True, noswap=True
)
await setup_fm_buf(settings, buf=buf)
return buf
async def restore_non_fm_win(
win_local: Mapping[str, Union[bool, str]], win: Window
) -> None:
await win.vars.set(URI_SCHEME, False)
for key, val in win_local.items():
await win.opts.set(key, val=val)
async def new_window(
*,
last_used: Mapping[ExtData, None],
win_local: Mapping[str, Union[bool, str]],
open_left: bool,
width: Optional[int],
) -> Window:
split_r = await Nvim.opts.get(bool, "splitright")
wins = [win async for win in find_windows_in_tab(last_used, no_secondary=False)]
focus_win = wins[0] if open_left else wins[-1]
direction = False if open_left else True
await Nvim.opts.set("splitright", val=direction)
await Window.set_current(focus_win)
await Nvim.exec(f"{width}vnew" if width else "vnew")
await Nvim.opts.set("splitright", val=split_r)
win = await Window.get_current()
buf = await win.get_buf()
await restore_non_fm_win(win_local, win=win)
await buf.opts.set("bufhidden", val="wipe")
return win
async def resize_fm_windows(last_used: Mapping[ExtData, None], width: int) -> None:
async for win in find_fm_windows_in_tab(last_used):
await win.set_width(width)
async def kill_buffers(
last_used: Mapping[ExtData, None],
paths: AbstractSet[PurePath],
reopen: Mapping[PurePath, PurePath],
) -> Mapping[Window, PurePath]:
active = (
{
await win.get_buf(): win
async for win in find_non_fm_windows_in_tab(
last_used,
)
}
if reopen
else {}
)
async def cont() -> AsyncIterator[Tuple[Window, PurePath]]:
for buf in await Buffer.list(listed=True):
if bufname := await buf.get_name():
name = PurePath(bufname)
buf_paths = ancestors(name) | {name}
if not buf_paths.isdisjoint(paths):
if (
reopen
and (win := active.get(buf))
and (new_path := reopen.get(name))
):
tmp = await Buffer.create(
listed=False,
scratch=True,
wipe=True,
nofile=True,
noswap=True,
)
await win.set_buf(tmp)
yield win, new_path
await buf.delete()
return {win: path async for win, path in cont()}

View File

@ -1,35 +0,0 @@
from pynvim_pp.nvim import Nvim
from std2 import anext
from std2.locale import si_prefixed
from ..fs.ops import fs_stat
from ..registry import rpc
from ..state.types import State
from ..view.ops import display_path
from .shared.index import indices
@rpc(blocking=False)
async def _stat(state: State, is_visual: bool) -> None:
"""
Print file stat to cmdline
"""
node = await anext(indices(state, is_visual=is_visual), None)
if not node:
return None
else:
try:
stat = await fs_stat(node.path)
except Exception as e:
await Nvim.write(e, error=True)
else:
permissions = stat.permissions
size = si_prefixed(stat.size, precision=2)
user = stat.user
group = stat.group
mtime = stat.date_mod.strftime(state.settings.view.time_fmt)
name = display_path(node.path, state=state)
full_name = f"{name} -> {stat.link}" if stat.link else name
mode_line = f"{permissions} {size}b {user} {group} {mtime} {full_name}"
await Nvim.write(mode_line)

View File

@ -1,43 +0,0 @@
from os import chmod, stat, stat_result
from pathlib import PurePath
from stat import S_ISDIR, S_IXGRP, S_IXOTH, S_IXUSR
from typing import Iterator, Tuple
from ..fs.cartographer import act_like_dir
from ..registry import rpc
from ..state.next import forward
from ..state.types import State
from .shared.index import indices
from .types import Stage
@rpc(blocking=False)
async def _toggle_exec(state: State, is_visual: bool) -> Stage:
"""
Toggle chmod +-x
"""
selected = state.selection or {
node.path
async for node in indices(state, is_visual=is_visual)
if not act_like_dir(node, follow_links=state.follow_links)
}
def cont() -> Iterator[Tuple[PurePath, stat_result]]:
for path in selected:
try:
st = stat(path)
except FileNotFoundError:
pass
else:
if not S_ISDIR(st.st_mode):
yield path, st
stats = {path: st for path, st in cont()}
for path, st in stats.items():
chmod(path, st.st_mode ^ S_IXUSR ^ S_IXGRP ^ S_IXOTH)
invalidate_dirs = {path.parent for path in stats.keys()}
new_state = await forward(state, invalidate_dirs=invalidate_dirs)
return Stage(state=new_state)

View File

@ -1,184 +0,0 @@
from dataclasses import dataclass
from pathlib import PurePath
from subprocess import CalledProcessError
from typing import Mapping, Optional, Sequence
from pynvim_pp.nvim import Nvim
from pynvim_pp.rpc_types import ExtData
from pynvim_pp.window import Window
from std2 import anext
from std2.argparse import ArgparseError, ArgParser
from ..fs.ops import exists, new, which
from ..registry import rpc
from ..settings.localization import LANG
from ..settings.types import Settings
from ..state.types import State
from ..version_ctl.git import root as version_ctl_toplv
from .shared.current import maybe_path_above, new_current_file, new_root
from .shared.open_file import open_file
from .shared.wm import (
find_current_buffer_path,
find_fm_buffers,
find_fm_windows_in_tab,
find_windows_in_tab,
new_fm_buffer,
new_window,
resize_fm_windows,
)
from .types import ClickType, Stage
@dataclass(frozen=True)
class _Args:
path: Optional[PurePath]
version_ctl: bool
toggle: bool
focus: bool
def _parse_args(args: Sequence[str]) -> _Args:
parser = ArgParser()
parser.add_argument("path", nargs="?", type=PurePath)
parser.add_argument("--version-ctl", action="store_true")
focus_group = parser.add_mutually_exclusive_group()
focus_group.add_argument(
"--always-focus", dest="toggle", action="store_false", default=True
)
focus_group.add_argument(
"--nofocus", dest="focus", action="store_false", default=True
)
ns = parser.parse_args(args=args)
opts = _Args(
path=ns.path,
version_ctl=ns.version_ctl,
toggle=False if ns.version_ctl or ns.path else ns.toggle,
focus=ns.focus,
)
return opts
async def _ensure_side_window(
*,
settings: Settings,
window_order: Mapping[ExtData, None],
width: int,
window: Window,
) -> None:
open_left = settings.open_left
windows = [
win
async for win in find_windows_in_tab(last_used=window_order, no_secondary=False)
]
target = windows[0] if open_left else windows[-1]
if window.data != target.data:
if open_left:
await Nvim.exec("wincmd H")
else:
await Nvim.exec("wincmd L")
await resize_fm_windows(last_used=window_order, width=width)
async def _open_fm_window(
settings: Settings,
window_order: Mapping[ExtData, None],
opts: _Args,
width: int,
) -> None:
cwin = await Window.get_current()
win = await anext(find_fm_windows_in_tab(last_used=window_order), None)
if win:
if opts.toggle:
wins = await Window.list()
if len(wins) > 1:
await win.close()
else:
await Window.set_current(win)
else:
buf = await anext(find_fm_buffers(), None)
if not buf:
buf = await new_fm_buffer(settings=settings)
win = await new_window(
last_used=window_order,
win_local=settings.win_actual_opts,
open_left=settings.open_left,
width=width,
)
await win.set_buf(buf)
await _ensure_side_window(
window=win, settings=settings, window_order=window_order, width=width
)
if not opts.focus:
await Window.set_current(cwin)
@rpc(blocking=False)
async def _open(state: State, args: Sequence[str]) -> Optional[Stage]:
"""
Toggle sidebar
"""
try:
opts = _parse_args(args)
except ArgparseError as e:
await Nvim.write(e, error=True)
return None
else:
if opts.version_ctl:
if git := which("git"):
try:
cwd = await version_ctl_toplv(git, cwd=state.root.path)
new_state = await new_root(
state=state, new_cwd=cwd, indices=frozenset()
)
except CalledProcessError:
await Nvim.write(LANG("cannot find version ctl root"), error=True)
return None
else:
await Nvim.write(LANG("cannot find version ctl root"), error=True)
return None
else:
new_state = state
if opts.path:
path = (
opts.path
if opts.path.is_absolute()
else await Nvim.getcwd() / opts.path
)
if not await exists(path, follow=True):
await new((path,))
next_state = await maybe_path_above(new_state, paths={path}) or new_state
await _open_fm_window(
state.settings,
opts=opts,
window_order=new_state.window_order,
width=next_state.width,
)
await open_file(
state=state,
path=path,
click_type=ClickType.primary,
)
return Stage(next_state, focus=path)
else:
curr = await find_current_buffer_path()
stage = (
await new_current_file(state=new_state, current=curr) if curr else None
)
await _open_fm_window(
state.settings,
opts=opts,
window_order=new_state.window_order,
width=new_state.width,
)
return (
Stage(stage.state, focus=curr)
if stage
else Stage(new_state, focus=curr)
)

View File

@ -1,78 +0,0 @@
from typing import Optional, Union
from pynvim_pp.nvim import Nvim
from std2 import anext
from std2.types import Void, VoidType
from ..registry import rpc
from ..settings.localization import LANG
from ..state.next import forward
from ..state.types import Selection, State
from ..version_ctl.types import VCStatus
from .shared.index import indices
from .types import Stage
@rpc(blocking=False)
async def _toggle_hidden(state: State, is_visual: bool) -> Optional[Stage]:
"""
Toggle hidden
"""
node = await anext(indices(state, is_visual=is_visual))
if not node:
return None
else:
focus = node.path
show_hidden = not state.show_hidden
selection: Selection = state.selection if show_hidden else frozenset()
new_state = await forward(state, show_hidden=show_hidden, selection=selection)
return Stage(new_state, focus=focus)
@rpc(blocking=False)
async def _toggle_follow(state: State, is_visual: bool) -> Stage:
"""
Toggle follow
"""
new_state = await forward(state, follow=not state.follow)
await Nvim.write(LANG("follow_mode_indi", follow=str(new_state.follow)))
return Stage(new_state)
@rpc(blocking=False)
async def _toggle_follow_links(state: State, is_visual: bool) -> Stage:
"""
Toggle --follow
"""
follow_links = not state.follow_links
new_state = await forward(state, follow_links=follow_links)
await Nvim.write(LANG("follow_links_indi", follow=str(new_state.follow_links)))
return Stage(new_state)
@rpc(blocking=False)
async def _toggle_follow_ignore(state: State, is_visual: bool) -> Stage:
"""
Toggle --follow
"""
follow_links = not state.follow_links
new_state = await forward(state, follow_links=follow_links)
await Nvim.write(LANG("follow_ignore_indi", follow=str(new_state.follow_links)))
return Stage(new_state)
@rpc(blocking=False)
async def _toggle_version_control(state: State, is_visual: bool) -> Stage:
"""
Toggle version control
"""
enable_vc = not state.enable_vc
vc: Union[VoidType, VCStatus] = Void if enable_vc else VCStatus()
new_state = await forward(state, enable_vc=enable_vc, vc=vc)
await Nvim.write(LANG("version_control_indi", enable_vc=str(new_state.enable_vc)))
return Stage(new_state)

View File

@ -1,20 +0,0 @@
from dataclasses import dataclass
from enum import Enum, auto
from pathlib import PurePath
from typing import Optional
from ..state.types import State
class ClickType(Enum):
primary = auto()
secondary = auto()
tertiary = auto()
v_split = auto()
h_split = auto()
@dataclass(frozen=True)
class Stage:
state: State
focus: Optional[PurePath] = None

View File

@ -1,189 +0,0 @@
from asyncio import gather
from functools import lru_cache
from itertools import chain
from locale import strxfrm
from os import linesep
from os.path import normpath
from pathlib import PurePath
from string import whitespace
from subprocess import CalledProcessError
from typing import (
Iterable,
Iterator,
MutableMapping,
MutableSequence,
MutableSet,
Sequence,
Tuple,
)
from std2.asyncio import to_thread
from std2.pathlib import ROOT
from std2.string import removeprefix, removesuffix
from ..fs.ops import ancestors, which
from .nice import nice_call
from .types import VCStatus
_Stats = Iterable[Tuple[str, PurePath]]
_WHITE_SPACES = {*whitespace}
_GIT_LIST_CMD = (
"--no-optional-locks",
"status",
"--ignored",
"--renames",
"--porcelain",
"-z",
)
_GIT_SUBMODULE_MARKER = "Entering "
_SUBMODULE_MARKER = "S"
_IGNORED_MARKER = "I"
_UNTRACKED_MARKER = "?"
async def root(git: PurePath, cwd: PurePath) -> PurePath:
stdout = await nice_call(
(
git,
"--no-optional-locks",
"rev-parse",
"--path-format=relative",
"--show-toplevel",
),
cwd=cwd,
)
return PurePath(normpath(cwd / stdout.rstrip()))
@lru_cache(maxsize=1)
def _parse_stats_main(stdout: str) -> Sequence[Tuple[str, PurePath]]:
def cont() -> Iterator[Tuple[str, PurePath]]:
it = iter(stdout.split("\0"))
for line in it:
prefix, file = line[:2], line[3:]
yield prefix, PurePath(file)
if "R" in prefix:
next(it, None)
return tuple(cont())
async def _stat_main(git: PurePath, cwd: PurePath) -> str:
stdout = await nice_call((git, *_GIT_LIST_CMD), cwd=cwd)
return stdout
@lru_cache(maxsize=1)
def _parse_sub_modules(stdout: str) -> Sequence[Tuple[str, PurePath]]:
def cont() -> Iterator[Tuple[str, PurePath]]:
it = iter(stdout)
sub_module = ROOT
acc: MutableSequence[str] = []
for char in it:
if char == linesep:
line = "".join(acc)
acc.clear()
if not line.startswith(_GIT_SUBMODULE_MARKER):
raise ValueError(stdout)
else:
quoted = removeprefix(line, prefix=_GIT_SUBMODULE_MARKER)
if not (quoted.startswith("'") and quoted.endswith("'")):
raise ValueError(stdout)
else:
sub_module = PurePath(
removesuffix(removeprefix(quoted, prefix="'"), suffix="'")
)
yield _SUBMODULE_MARKER, sub_module
elif char == "\0":
line = "".join(acc)
acc.clear()
if not sub_module:
raise ValueError(stdout)
else:
prefix, file = line[:2], line[3:]
yield prefix, sub_module / file
if "R" in prefix:
next(it, None)
else:
acc.append(char)
return tuple(cont())
async def _stat_sub_modules(git: PurePath, cwd: PurePath) -> str:
stdout = await nice_call(
(
git,
"--no-optional-locks",
"submodule",
"foreach",
"--recursive",
git,
*_GIT_LIST_CMD,
),
cwd=cwd,
)
return stdout
def _stat_name(stat: str) -> str:
markers = {
"!!": _IGNORED_MARKER,
"??": _UNTRACKED_MARKER,
}
return markers.get(stat, stat)
def _parse(root: PurePath, stats: _Stats) -> VCStatus:
above = ancestors(root)
ignored: MutableSet[PurePath] = set()
status: MutableMapping[PurePath, str] = {}
directories: MutableMapping[PurePath, MutableSet[str]] = {}
for stat, name in stats:
path = root / name
status[path] = _stat_name(stat)
if "!" in stat:
ignored.add(path)
else:
for ancestor in ancestors(path):
parents = directories.setdefault(ancestor, set())
if stat != _SUBMODULE_MARKER:
for sym in stat:
parents.add(sym)
for directory, syms in directories.items():
pre_existing = {*status.get(directory, "")}
symbols = pre_existing | syms - _WHITE_SPACES
consoildated = sorted(symbols, key=strxfrm)
status[directory] = "".join(consoildated)
trimmed = {path: stat for path, stat in status.items() if path not in above}
return VCStatus(ignored=ignored, status=trimmed)
async def status(cwd: PurePath, prev: VCStatus) -> VCStatus:
if git := which("git"):
bin = PurePath(git)
try:
raw_root, main, submodules = await gather(
root(bin, cwd=cwd),
_stat_main(bin, cwd=cwd),
_stat_sub_modules(bin, cwd=cwd),
)
stats = chain((_parse_stats_main(main)), _parse_sub_modules(submodules))
except CalledProcessError:
return VCStatus()
else:
return await to_thread(lambda: _parse(raw_root, stats=stats))
else:
return VCStatus()

View File

@ -1,42 +0,0 @@
import sys
from contextlib import suppress
from os import environ
from pathlib import PurePath
from typing import Optional, Sequence
from pynvim_pp.lib import decode
from std2.asyncio.subprocess import call
from std2.pathlib import AnyPath
if sys.platform == "win32":
from subprocess import BELOW_NORMAL_PRIORITY_CLASS
nice = lambda _: None
else:
from os import nice
BELOW_NORMAL_PRIORITY_CLASS = 0
_ENV = {**environ, "LC_ALL": "C"}
def _nice() -> None:
with suppress(PermissionError):
nice(19)
async def nice_call(
argv: Sequence[AnyPath],
stdin: Optional[bytes] = None,
cwd: Optional[PurePath] = None,
) -> str:
proc = await call(
*argv,
cwd=cwd,
stdin=stdin,
env=_ENV,
preexec_fn=_nice,
creationflags=BELOW_NORMAL_PRIORITY_CLASS,
)
return decode(proc.stdout)

View File

@ -1,12 +0,0 @@
from dataclasses import dataclass, field
from pathlib import PurePath
from typing import AbstractSet, Mapping, MutableMapping
@dataclass(frozen=True)
class VCStatus:
main: str = ""
submodules: str = ""
ignored: AbstractSet[PurePath] = frozenset()
status: Mapping[PurePath, str] = field(default_factory=dict)
ignore_cache: MutableMapping[PurePath, bool] = field(default_factory=dict)

View File

@ -1,27 +0,0 @@
from typing import Iterator, Mapping, Tuple
from uuid import uuid4
from pynvim_pp.highlight import HLgroup
from ..consts import FM_HL_PREFIX
LEGAL_CTERM = {
"bold",
"underline",
"undercurl",
"strikethrough",
"reverse",
"italic",
"standout",
}
LEGAL_CTERM_COLOURS = range(8)
def gen_hl(name_prefix: str, mapping: Mapping[str, str]) -> Mapping[str, HLgroup]:
def cont() -> Iterator[Tuple[str, HLgroup]]:
for key, val in mapping.items():
name = f"{FM_HL_PREFIX}_{name_prefix}_{uuid4().hex}"
yield key, HLgroup(name=name, guifg=val)
return {k: v for k, v in cont()}

View File

@ -1,118 +0,0 @@
from itertools import chain
from os import environ
from typing import Mapping, Tuple, TypeVar, Union
from pynvim_pp.highlight import HLgroup
from std2.types import never
from chad_types import (
Artifact,
IconColourSetEnum,
IconGlyphs,
IconGlyphSetEnum,
LSColoursEnum,
TextColourSetEnum,
)
from ..consts import FM_HL_PREFIX
from .highlight import gen_hl
from .ls_colours import parse_lsc
from .types import HLcontext, HLGroups
T = TypeVar("T")
def _trans(mapping: Mapping[T, HLgroup]) -> Mapping[T, str]:
return {k: v.name for k, v in mapping.items()}
def load_theme(
artifact: Artifact,
particular_mappings: HLGroups,
discrete_colours: Mapping[str, str],
icon_set: IconGlyphSetEnum,
icon_colour_set: IconColourSetEnum,
text_colour_set: Union[LSColoursEnum, TextColourSetEnum],
) -> Tuple[IconGlyphs, HLcontext]:
if icon_set is IconGlyphSetEnum.ascii:
icons = artifact.icons.ascii
elif icon_set is IconGlyphSetEnum.ascii_hollow:
icons = artifact.icons.ascii_hollow
elif icon_set is IconGlyphSetEnum.devicons:
icons = artifact.icons.devicons
elif icon_set is IconGlyphSetEnum.emoji:
icons = artifact.icons.emoji
else:
never(icon_set)
if text_colour_set is LSColoursEnum.env and "LS_COLORS" not in environ:
text_colour_set = LSColoursEnum.solarized_dark_256
if isinstance(text_colour_set, LSColoursEnum):
if text_colour_set is LSColoursEnum.env:
_lsc = environ.get("LS_COLORS", "")
elif text_colour_set is LSColoursEnum.solarized_dark_256:
_lsc = artifact.ls_colours.solarized_dark_256
elif text_colour_set is LSColoursEnum.solarized_light:
_lsc = artifact.ls_colours.solarized_light
elif text_colour_set is LSColoursEnum.solarized_dark:
_lsc = artifact.ls_colours.solarized_dark
elif text_colour_set is LSColoursEnum.solarized_universal:
_lsc = artifact.ls_colours.solarized_universal
elif text_colour_set is LSColoursEnum.nord:
_lsc = artifact.ls_colours.nord
elif text_colour_set is LSColoursEnum.trapdoor:
_lsc = artifact.ls_colours.trapdoor
else:
never(text_colour_set)
lsc = parse_lsc(_lsc, discrete_colours=discrete_colours)
mode_pre = lsc.mode_pre
mode_post = lsc.mode_post
ext_exact = lsc.exts
name_exact: Mapping[str, HLgroup] = {}
name_glob = lsc.name_glob
else:
if text_colour_set is TextColourSetEnum.nerdtree_syntax_light:
text_colour = artifact.text_colours.nerdtree_syntax_light
elif text_colour_set is TextColourSetEnum.nerdtree_syntax_dark:
text_colour = artifact.text_colours.nerdtree_syntax_dark
else:
never(text_colour_set)
mode_pre = {}
mode_post = {}
ext_exact = gen_hl(FM_HL_PREFIX, mapping=text_colour.ext_exact)
name_exact = gen_hl(FM_HL_PREFIX, mapping=text_colour.name_exact)
name_glob = gen_hl(FM_HL_PREFIX, mapping=text_colour.name_glob)
if icon_colour_set is IconColourSetEnum.github:
icon_exts = gen_hl(FM_HL_PREFIX, mapping=artifact.icon_colours.github)
elif icon_colour_set is IconColourSetEnum.none:
icon_exts = gen_hl(FM_HL_PREFIX, mapping={})
else:
never(icon_colour_set)
groups = tuple(
chain(
icon_exts.values(),
mode_pre.values(),
mode_post.values(),
ext_exact.values(),
name_exact.values(),
name_glob.values(),
),
)
context = HLcontext(
groups=groups,
icon_exts=_trans(icon_exts),
mode_pre=_trans(mode_pre),
mode_post=_trans(mode_post),
ext_exact=_trans(ext_exact),
name_exact=_trans(name_exact),
name_glob=_trans(name_glob),
particular_mappings=particular_mappings,
)
return icons, context

View File

@ -1,303 +0,0 @@
from dataclasses import dataclass
from enum import Enum, IntEnum, auto
from itertools import chain, repeat
from typing import (
AbstractSet,
Callable,
Iterator,
Mapping,
MutableMapping,
MutableSet,
Optional,
Tuple,
Union,
)
from uuid import uuid4
from pynvim_pp.highlight import HLgroup
from std2.coloursys import rgb_to_hex
from ..consts import FM_HL_PREFIX
from ..fs.types import Mode
class _Style(IntEnum):
bold = auto()
dimmed = auto()
italic = auto()
underline = auto()
blink = auto()
blink_fast = auto()
reverse = auto()
hidden = auto()
strikethrough = auto()
class _Ground(Enum):
fore = auto()
back = auto()
class _AnsiColour(IntEnum):
black = auto()
red = auto()
green = auto()
yellow = auto()
blue = auto()
magenta = auto()
cyan = auto()
white = auto()
bright_black = auto()
bright_red = auto()
bright_green = auto()
bright_yellow = auto()
bright_blue = auto()
bright_magenta = auto()
bright_cyan = auto()
bright_white = auto()
@dataclass(frozen=True)
class _Colour:
r: int
g: int
b: int
@dataclass(frozen=True)
class _Styling:
styles: AbstractSet[_Style]
foreground: Union[_AnsiColour, _Colour, None]
background: Union[_AnsiColour, _Colour, None]
@dataclass(frozen=True)
class LSC:
mode_pre: Mapping[Mode, HLgroup]
mode_post: Mapping[Optional[Mode], HLgroup]
exts: Mapping[str, HLgroup]
name_glob: Mapping[str, HLgroup]
_ANSI_RANGE = range(256)
_RGB_RANGE = range(256)
_STYLE_TABLE: Mapping[str, _Style] = {str(code + 0): code for code in _Style}
_GROUND_TABLE: Mapping[str, _Ground] = {
str(code): ground
for code, ground in chain(
zip(chain(range(30, 39), range(90, 98)), repeat(_Ground.fore)),
zip(chain(range(40, 49), range(100, 108)), repeat(_Ground.back)),
)
}
_COLOUR_TABLE: Mapping[str, _AnsiColour] = {
str(code): colour
for code, colour in chain(
((c + 29 if c <= 8 else c + 31, c) for c in _AnsiColour),
((c + 89 if c <= 8 else c + 91, c) for c in _AnsiColour),
)
}
_RGB_TABLE: AbstractSet[str] = {"38", "48"}
_E_BASIC_TABLE: Mapping[int, _AnsiColour] = {i: c for i, c in enumerate(_AnsiColour)}
_E_GREY_TABLE: Mapping[int, _Colour] = {
i: _Colour(r=s, g=s, b=s)
for i, s in enumerate((round(step / 23 * 255) for step in range(24)), 232)
}
def _parse_8(codes: Iterator[str]) -> Union[_AnsiColour, _Colour, None]:
try:
ansi_code = int(next(codes, ""))
except ValueError:
return None
else:
if ansi_code in _ANSI_RANGE:
basic = _E_BASIC_TABLE.get(ansi_code)
if basic:
return basic
grey = _E_GREY_TABLE.get(ansi_code)
if grey:
return grey
ratio = 255 / 5
code = ansi_code - 16
r = code // 36
g = code % 36 // 6
b = code % 36 % 6
return _Colour(r=round(r * ratio), g=round(g * ratio), b=round(b * ratio))
else:
return None
def _parse_24(codes: Iterator[str]) -> Optional[_Colour]:
try:
r, g, b = int(next(codes, "")), int(next(codes, "")), int(next(codes, ""))
except ValueError:
return None
else:
if r in _RGB_RANGE and g in _RGB_RANGE and b in _RGB_RANGE:
return _Colour(r=r, g=g, b=b)
else:
return None
_PARSE_TABLE: Mapping[
str, Callable[[Iterator[str]], Union[_AnsiColour, _Colour, None]]
] = {
"5": _parse_8,
"2": _parse_24,
}
_SPECIAL_PRE_TABLE: Mapping[str, Mode] = {
"bd": Mode.block_device,
"ca": Mode.file_w_capacity,
"cd": Mode.char_device,
"di": Mode.folder,
"do": Mode.door,
"ex": Mode.executable,
"ln": Mode.link,
"mh": Mode.multi_hardlink,
"or": Mode.orphan_link,
"ow": Mode.other_writable,
"pi": Mode.pipe,
"sg": Mode.set_gid,
"so": Mode.socket,
"st": Mode.sticky,
"su": Mode.set_uid,
"tw": Mode.sticky_other_writable,
}
_SPECIAL_POST_TABLE: Mapping[str, Optional[Mode]] = {
"fi": Mode.file,
"no": None,
}
_UNUSED = {
"mi": "colour of missing symlink pointee",
"cl": "ANSI clear",
"ec": "ANSI end_code",
"lc": "ANSI left_code",
"rc": "ANSI right_code",
"rs": "ANSI reset",
}
assert _UNUSED
_HL_STYLE_TABLE: Mapping[_Style, Optional[str]] = {
_Style.bold: "bold",
_Style.dimmed: None,
_Style.italic: "italic",
_Style.underline: "underline",
_Style.blink: None,
_Style.blink_fast: None,
_Style.reverse: "reverse",
_Style.hidden: None,
_Style.strikethrough: "strikethrough",
}
def _parse_codes(
codes: str,
) -> Iterator[Union[_Style, Tuple[_Ground, Union[_AnsiColour, _Colour]]]]:
it = (code.lstrip("0") for code in codes.split(";"))
for code in it:
style = _STYLE_TABLE.get(code)
if style:
yield style
continue
ground = _GROUND_TABLE.get(code)
ansi_colour = _COLOUR_TABLE.get(code)
if ground and ansi_colour:
yield ground, ansi_colour
elif ground and code in _RGB_TABLE:
code = next(it, "")
parse = _PARSE_TABLE.get(code)
if parse:
colour = parse(it)
if colour:
yield ground, colour
def _parse_styling(codes: str) -> _Styling:
styles: MutableSet[_Style] = set()
colours: MutableMapping[_Ground, Union[_AnsiColour, _Colour]] = {}
for ret in _parse_codes(codes):
if isinstance(ret, _Style):
styles.add(ret)
elif isinstance(ret, tuple):
ground, colour = ret
colours[ground] = colour
styling = _Styling(
styles=styles,
foreground=colours.get(_Ground.fore),
background=colours.get(_Ground.back),
)
return styling
def _parseHLGroup(styling: _Styling, discrete_colours: Mapping[str, str]) -> HLgroup:
fg, bg = styling.foreground, styling.background
name = f"{FM_HL_PREFIX}_ls_{uuid4().hex}"
cterm = {
style
for style in (_HL_STYLE_TABLE.get(style) for style in styling.styles)
if style
}
ctermfg = fg.value - 1 if isinstance(fg, _AnsiColour) else None
ctermbg = bg.value - 1 if isinstance(bg, _AnsiColour) else None
guifg = (
rgb_to_hex(fg.r, fg.g, fg.b)
if isinstance(fg, _Colour)
else (discrete_colours.get(fg.name) if isinstance(fg, _AnsiColour) else None)
)
guibg = (
rgb_to_hex(bg.r, bg.g, bg.b)
if isinstance(bg, _Colour)
else (discrete_colours.get(bg.name) if isinstance(bg, _AnsiColour) else None)
)
group = HLgroup(
name=name,
cterm=cterm,
ctermfg=ctermfg,
ctermbg=ctermbg,
guifg=guifg,
guibg=guibg,
)
return group
def parse_lsc(ls_colours: str, discrete_colours: Mapping[str, str]) -> LSC:
hl_lookup = {
key: _parseHLGroup(_parse_styling(val), discrete_colours=discrete_colours)
for key, _, val in (
segment.partition("=") for segment in ls_colours.strip(":").split(":")
)
}
mode_pre = {
mode: hl
for indicator, mode in _SPECIAL_PRE_TABLE.items()
if (hl := hl_lookup.pop(indicator, None))
}
mode_post = {
mode: hl
for indicator, mode in _SPECIAL_POST_TABLE.items()
if (hl := hl_lookup.pop(indicator, None))
}
_ext_keys = tuple(
key for key in hl_lookup if key.startswith("*.") and key.count(".") == 1
)
exts = {key[1:]: hl_lookup.pop(key) for key in _ext_keys}
lsc = LSC(exts=exts, mode_pre=mode_pre, mode_post=mode_post, name_glob=hl_lookup)
return lsc

View File

@ -1,25 +0,0 @@
from os import sep
from os.path import relpath
from pathlib import Path, PurePath
from string import whitespace
from ..state.types import State
_WS = {*whitespace} - {"\t"}
def encode_for_display(text: str) -> str:
encoded = "".join(
char.encode("unicode_escape").decode("utf-8") if char in _WS else char
for char in text
)
return encoded
def display_path(path: PurePath, state: State) -> str:
raw = relpath(path, start=state.root.path)
name = encode_for_display(raw)
if Path(path).is_dir():
return f"{name}{sep}"
else:
return name

View File

@ -1,345 +0,0 @@
from collections import UserString
from enum import IntEnum, auto
from fnmatch import fnmatch
from functools import lru_cache
from locale import strxfrm
from os.path import extsep, sep
from pathlib import PurePath
from typing import Any, Callable, Iterator, Optional, Sequence, Tuple, Union, cast
from pynvim_pp.lib import encode
from std2.platform import OS, os
from std2.types import never
from ..fs.cartographer import is_dir, user_ignored
from ..fs.types import Mode, Node
from ..nvim.types import Markers
from ..settings.types import Settings
from ..state.types import Diagnostics, FilterPattern, Index, Selection
from ..version_ctl.types import VCStatus
from .ops import encode_for_display
from .types import Badge, Derived, Highlight, Sortby
class _CompVals(IntEnum):
FOLDER = auto()
FILE = auto()
_Str = Union[str, UserString]
_Render = Tuple[str, Sequence[Highlight], Sequence[Badge]]
_NRender = Tuple[Node, str, Sequence[Highlight], Sequence[Badge]]
class _str(UserString):
def __lt__(self, _: _Str) -> bool:
return False
def __gt__(self, _: _Str) -> bool:
return True
_EMPTY = _str("")
def _suffixx(path: PurePath) -> _Str:
if path.suffix:
return strxfrm(path.suffix)
elif path.stem.startswith(extsep):
return strxfrm(path.stem)
else:
return _EMPTY
def _lax_suffix(path: PurePath) -> str:
return path.suffix or path.name
@lru_cache(maxsize=None)
def _gen_comp(sortby: Sequence[Sortby]) -> Callable[[Node], Any]:
def comp(node: Node) -> Sequence[Any]:
if node.cache.sort_by is None:
def cont() -> Iterator[Any]:
for sb in sortby:
if sb is Sortby.is_folder:
yield _CompVals.FOLDER if is_dir(node) else _CompVals.FILE
elif sb is Sortby.ext:
yield "" if is_dir(node) else _suffixx(node.path)
elif sb is Sortby.file_name_lower:
yield strxfrm(node.path.name.casefold())
elif sb is Sortby.file_name:
yield strxfrm(node.path.name)
else:
never(sb)
node.cache.sort_by = tuple(cont())
return node.cache.sort_by
return comp
def _vc_ignored(node: Node, vc: VCStatus) -> bool:
path = node.path
if (ignored := vc.ignore_cache.get(path, None)) is not None:
return ignored
else:
ignored = not vc.ignored.isdisjoint({path} | {*map(PurePath, path.parents)})
vc.ignore_cache[path] = ignored
return ignored
def _gen_spacer(depth: int) -> str:
return (depth * 2 - 1) * " "
def _paint(
settings: Settings,
index: Index,
selection: Selection,
markers: Markers,
diagnostics: Diagnostics,
vc: VCStatus,
follow_links: bool,
show_hidden: bool,
current: Optional[PurePath],
) -> Callable[[Node, int], Optional[_Render]]:
icons = settings.view.icons
context = settings.view.hl_context
def search_icon_hl(node: Node, ignored: bool) -> Optional[str]:
if ignored:
return context.particular_mappings.ignored
else:
return context.icon_exts.get(_lax_suffix(node.path))
def search_text_hl(node: Node, ignored: bool) -> Optional[str]:
if ignored:
return context.particular_mappings.ignored
s_modes = sorted(node.mode)
for mode in s_modes:
if os is OS.windows and mode is Mode.other_writable:
pass
elif hl := context.mode_pre.get(mode):
return hl
if hl := context.name_exact.get(node.path.name):
return hl
for pattern, hl in context.name_glob.items():
if fnmatch(node.path.name, pattern):
return hl
if hl := context.ext_exact.get(_lax_suffix(node.path)):
return hl
for mode in s_modes:
if hl := context.mode_post.get(mode):
return hl
else:
return context.mode_post.get(None)
def gen_status(path: PurePath) -> str:
selected = (
icons.status.selected if path in selection else icons.status.not_selected
)
active = icons.status.active if path == current else icons.status.inactive
return f"{selected}{active}"
def gen_decor_pre(node: Node, depth: int) -> Iterator[str]:
yield _gen_spacer(depth)
yield gen_status(node.path)
def gen_icon(node: Node) -> Iterator[str]:
yield " "
if is_dir(node):
if node.pointed and not follow_links:
yield icons.link.normal
elif node.path in index:
yield icons.folder.open
else:
yield icons.folder.closed
else:
yield (
(
icons.name_exact.get(node.path.name, "")
or icons.ext_exact.get(_lax_suffix(node.path), "")
or next(
(
v
for k, v in icons.name_glob.items()
if fnmatch(node.path.name, k)
),
icons.default_icon,
)
)
if settings.view.use_icons
else icons.default_icon
)
yield " "
def gen_name(node: Node) -> Iterator[str]:
yield encode_for_display(node.path.name)
if not settings.view.use_icons and is_dir(node):
yield sep
def gen_decor_post(node: Node) -> Iterator[str]:
mode = node.mode
if Mode.orphan_link in mode:
yield " "
yield icons.link.broken
elif Mode.link in mode:
yield " "
if is_dir(node) and not follow_links:
if node.path in index:
yield icons.folder.open
else:
yield icons.folder.closed
else:
yield icons.link.normal
def gen_badges(path: PurePath) -> Iterator[Badge]:
l = ""
if diagnostic := diagnostics.get(path, {}):
l = " "
dl = len(diagnostic)
for idx, (severity, count) in enumerate(sorted(diagnostic.items())):
group = context.particular_mappings.diagnostics.get(
severity, context.particular_mappings.diagnostic_unknown
)
lhs, rhs = not idx, idx + 1 == dl
r = " " if dl > 1 and not rhs else ""
if lhs:
yield Badge(
text="{", group=context.particular_mappings.diagnostic_context
)
yield Badge(text=f"{count}{r}", group=group)
if rhs:
yield Badge(
text="}", group=context.particular_mappings.diagnostic_context
)
if marks := markers.bookmarks.get(path):
ordered = "".join(sorted(marks))
yield Badge(
text=f"{l}<{ordered}>",
group=context.particular_mappings.bookmarks,
)
if qf_count := markers.quick_fix.get(path):
yield Badge(
text=f"{l}({qf_count})",
group=context.particular_mappings.quickfix,
)
if stat := vc.status.get(path):
yield Badge(
text=f"{l}[{stat}]",
group=context.particular_mappings.version_control,
)
def gen_highlights(
node: Node, pre: str, icon: str, name: str, ignored: bool
) -> Iterator[Highlight]:
icon_begin = len(encode(pre))
icon_end = icon_begin + len(encode(icon))
text_begin = icon_end
text_end = len(encode(name)) + text_begin
if icon_group := search_icon_hl(node, ignored=ignored):
hl = Highlight(group=icon_group, begin=icon_begin, end=icon_end)
yield hl
if text_group := search_text_hl(node, ignored=ignored):
hl = Highlight(group=text_group, begin=text_begin, end=text_end)
yield hl
def show(node: Node, depth: int) -> Optional[_Render]:
_user_ignored = user_ignored(node, ignores=settings.ignores)
vc_ignored = _vc_ignored(node, vc=vc)
ignored = vc_ignored or _user_ignored
if depth and _user_ignored and not show_hidden:
return None
else:
pre = "".join(gen_decor_pre(node, depth=depth))
icon = "".join(gen_icon(node))
name = "".join(gen_name(node))
post = "".join(gen_decor_post(node))
line = f"{pre}{icon}{name}{post}"
badges = tuple(gen_badges(node.path))
highlights = tuple(
gen_highlights(node, pre=pre, icon=icon, name=name, ignored=ignored)
)
return line, highlights, badges
return show
def render(
node: Node,
*,
settings: Settings,
index: Index,
selection: Selection,
filter_pattern: Optional[FilterPattern],
markers: Markers,
diagnostics: Diagnostics,
vc: VCStatus,
follow_links: bool,
show_hidden: bool,
current: Optional[PurePath],
) -> Derived:
show = _paint(
settings,
index=index,
selection=selection,
markers=markers,
diagnostics=diagnostics,
vc=vc,
follow_links=follow_links,
show_hidden=show_hidden,
current=current,
)
comp = _gen_comp(settings.view.sort_by)
keep_open = {node.path}
def render(node: Node, *, depth: int, cleared: bool) -> Iterator[_NRender]:
clear = (
cleared
or not filter_pattern
or fnmatch(node.path.name, filter_pattern.pattern)
)
if rend := show(node, depth):
def gen_children() -> Iterator[_NRender]:
for child in sorted(node.children.values(), key=comp):
yield from render(child, depth=depth + 1, cleared=clear)
children = tuple(gen_children())
if clear or children or node.path in keep_open:
yield (node, *rend)
yield from iter(children)
rendered = render(node, depth=0, cleared=False)
_nodes, _lines, _highlights, _badges = zip(*rendered)
nodes, lines, highlights, badges = (
cast(Sequence[Node], _nodes),
cast(Sequence[str], _lines),
cast(Sequence[Sequence[Highlight]], _highlights),
cast(Sequence[Sequence[Badge]], _badges),
)
hashed = tuple(str(hash(zipped)) for zipped in zip(lines, highlights, badges))
path_row_lookup = {node.path: idx for idx, node in enumerate(nodes)}
derived = Derived(
lines=lines,
highlights=highlights,
badges=badges,
hashed=hashed,
node_row_lookup=nodes,
path_row_lookup=path_row_lookup,
)
return derived

View File

@ -1,74 +0,0 @@
from dataclasses import dataclass
from enum import Enum, auto
from pathlib import PurePath
from typing import Mapping, Optional, Sequence
from pynvim_pp.highlight import HLgroup
from chad_types import IconGlyphs
from ..fs.types import Mode, Node
@dataclass(frozen=True)
class HLGroups:
bookmarks: str
ignored: str
marks: str
quickfix: str
diagnostics: Mapping[int, str]
diagnostic_unknown: str
diagnostic_context: str
version_control: str
@dataclass(frozen=True)
class HLcontext:
groups: Sequence[HLgroup]
icon_exts: Mapping[str, str]
mode_pre: Mapping[Mode, str]
mode_post: Mapping[Optional[Mode], str]
name_exact: Mapping[str, str]
name_glob: Mapping[str, str]
ext_exact: Mapping[str, str]
particular_mappings: HLGroups
class Sortby(Enum):
is_folder = auto()
ext = auto()
file_name_lower = auto()
file_name = auto()
@dataclass(frozen=True)
class ViewOptions:
hl_context: HLcontext
icons: IconGlyphs
sort_by: Sequence[Sortby]
time_fmt: str
use_icons: bool
@dataclass(frozen=True)
class Badge:
text: str
group: str
@dataclass(frozen=True)
class Highlight:
begin: int
end: int
group: str
@dataclass(frozen=True)
class Derived:
lines: Sequence[str]
highlights: Sequence[Sequence[Highlight]]
badges: Sequence[Sequence[Badge]]
hashed: Sequence[str]
node_row_lookup: Sequence[Node]
path_row_lookup: Mapping[PurePath, int]

Some files were not shown because too many files have changed in this diff Show More