mirror of
https://github.com/iofq/nvim.nix.git
synced 2026-03-26 03:30:50 -05:00
Compare commits
1 commit
9a955d86a0
...
7fbcfa7c54
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fbcfa7c54 |
22 changed files with 1532 additions and 631 deletions
48
flake.lock
generated
48
flake.lock
generated
|
|
@ -6,17 +6,14 @@
|
|||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1757895736,
|
||||
"narHash": "sha256-BBjs+YCOzgb6N2lew4vEmyS6s70y0z5xStKjGQaf55g=",
|
||||
"owner": "iofq",
|
||||
"repo": "dart.nvim",
|
||||
"rev": "f059335a22811374d5a7e22c97889ea712db58d7",
|
||||
"type": "github"
|
||||
"lastModified": 1758080529,
|
||||
"narHash": "sha256-Sup4+HacL6Xe6mTk23N6sD4uXoU9dcoqRgc9Mu0oQ5E=",
|
||||
"path": "/home/e/dev/dart.nvim",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"owner": "iofq",
|
||||
"repo": "dart.nvim",
|
||||
"type": "github"
|
||||
"path": "/home/e/dev/dart.nvim",
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
|
|
@ -413,11 +410,11 @@
|
|||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1759381078,
|
||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||
"lastModified": 1757745802,
|
||||
"narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||
"rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -430,11 +427,11 @@
|
|||
"nvim-treesitter": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1759376029,
|
||||
"narHash": "sha256-Cu6Wg9SKJpYAkp8DPAXe4Rf9OSSWW2wNdmCkYtl//fw=",
|
||||
"lastModified": 1757840001,
|
||||
"narHash": "sha256-9LcVSwWfOvp+1fLWqQtSohGax40gD9sGz9t0amySyDk=",
|
||||
"owner": "nvim-treesitter",
|
||||
"repo": "nvim-treesitter",
|
||||
"rev": "99bd52ba56a4b7c9a8cc50a6140180755e76fac6",
|
||||
"rev": "7aa24acae3a288e442e06928171f360bbdf75ba4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -447,21 +444,17 @@
|
|||
"nvim-treesitter-main": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"nvim-treesitter": "nvim-treesitter",
|
||||
"nvim-treesitter-textobjects": "nvim-treesitter-textobjects"
|
||||
"nvim-treesitter": "nvim-treesitter"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1759559567,
|
||||
"narHash": "sha256-cNu8MIRumBeW1HJK8c8IM6ge1yalz4xS5j5RCDbhf0Y=",
|
||||
"owner": "iofq",
|
||||
"repo": "nvim-treesitter-main",
|
||||
"rev": "1f19cc0a907328d8dbf467ee9fe216277628d366",
|
||||
"type": "github"
|
||||
"lastModified": 1759471274,
|
||||
"narHash": "sha256-jZxiszCE/g7oRLHmR8+aNqzP5w53wnfJ84D+AWhIwUk=",
|
||||
"path": "/home/e/dev/nvim-treesitter-main",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"owner": "iofq",
|
||||
"repo": "nvim-treesitter-main",
|
||||
"type": "github"
|
||||
"path": "/home/e/dev/nvim-treesitter-main",
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"nvim-treesitter-textobjects": {
|
||||
|
|
@ -488,7 +481,8 @@
|
|||
"gen-luarc": "gen-luarc",
|
||||
"neovim-nightly-overlay": "neovim-nightly-overlay",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nvim-treesitter-main": "nvim-treesitter-main"
|
||||
"nvim-treesitter-main": "nvim-treesitter-main",
|
||||
"nvim-treesitter-textobjects": "nvim-treesitter-textobjects"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
|
|||
12
flake.nix
12
flake.nix
|
|
@ -10,10 +10,14 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
dart = {
|
||||
url = "github:iofq/dart.nvim";
|
||||
url = "path:/home/e/dev/dart.nvim";
|
||||
};
|
||||
nvim-treesitter-main = {
|
||||
url = "github:iofq/nvim-treesitter-main";
|
||||
url = "path:/home/e/dev/nvim-treesitter-main";
|
||||
};
|
||||
nvim-treesitter-textobjects = {
|
||||
url = "github:nvim-treesitter/nvim-treesitter-textobjects/main";
|
||||
flake = false;
|
||||
};
|
||||
# Add bleeding-edge plugins here.
|
||||
# They can be updated with `nix flake update` (make sure to commit the generated flake.lock)
|
||||
|
|
@ -33,6 +37,7 @@
|
|||
systems = builtins.attrNames nixpkgs.legacyPackages;
|
||||
|
||||
# This is where the Neovim derivation is built.
|
||||
plugin-overlay = import ./nix/plugin-overlay.nix { inherit inputs; };
|
||||
neovim-overlay = import ./nix/neovim-overlay.nix { inherit inputs; };
|
||||
in
|
||||
flake-utils.lib.eachSystem systems (
|
||||
|
|
@ -44,6 +49,7 @@
|
|||
overlays = [
|
||||
inputs.neovim-nightly-overlay.overlays.default
|
||||
inputs.nvim-treesitter-main.overlays.default
|
||||
plugin-overlay
|
||||
neovim-overlay
|
||||
# This adds a function can be used to generate a .luarc.json
|
||||
# containing the Neovim API all plugins in the workspace directory.
|
||||
|
|
@ -81,6 +87,6 @@
|
|||
}
|
||||
)
|
||||
// {
|
||||
overlays.default = final: prev: (neovim-overlay final prev);
|
||||
overlays.default = final: prev: (plugin-overlay final prev) // (neovim-overlay final prev);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
201
nix/mkNeovim.nix
201
nix/mkNeovim.nix
|
|
@ -1,40 +1,197 @@
|
|||
# Function for creating a Neovim derivation
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
stdenv,
|
||||
# Set by the overlay to ensure we use a compatible version of `wrapNeovimUnstable`
|
||||
pkgs-wrapNeovim ? pkgs,
|
||||
}:
|
||||
with lib;
|
||||
{
|
||||
name ? "nvim",
|
||||
plugins ? [ ],
|
||||
packages ? [ ],
|
||||
# NVIM_APPNAME - Defaults to 'nvim' if not set.
|
||||
# If set to something else, this will also rename the binary.
|
||||
appName ? "nvim",
|
||||
# The Neovim package to wrap
|
||||
neovim-unwrapped ? pkgs-wrapNeovim.neovim-unwrapped,
|
||||
plugins ? [ ], # List of plugins
|
||||
# List of dev plugins (will be bootstrapped) - useful for plugin developers
|
||||
# { name = <plugin-name>; url = <git-url>; }
|
||||
devPlugins ? [ ],
|
||||
# Regexes for config files to ignore, relative to the nvim directory.
|
||||
# e.g. [ "^plugin/neogit.lua" "^ftplugin/.*.lua" ]
|
||||
ignoreConfigRegexes ? [ ],
|
||||
extraPackages ? [ ], # Extra runtime dependencies (e.g. ripgrep, ...)
|
||||
# The below arguments can typically be left as their defaults
|
||||
# Additional lua packages (not plugins), e.g. from luarocks.org.
|
||||
# e.g. p: [p.jsregexp]
|
||||
extraLuaPackages ? p: [ ],
|
||||
extraPython3Packages ? p: [ ], # Additional python 3 packages
|
||||
withPython3 ? false, # Build Neovim with Python 3 support?
|
||||
withRuby ? false, # Build Neovim with Ruby support?
|
||||
withNodeJs ? false, # Build Neovim with NodeJS support?
|
||||
withSqlite ? true, # Add sqlite? This is a dependency for some plugins
|
||||
# You probably don't want to create vi or vim aliases
|
||||
# if the appName is something different than "nvim"
|
||||
viAlias ? appName == "nvim", # Add a "vi" binary to the build output as an alias?
|
||||
vimAlias ? appName == "nvim", # Add a "vim" binary to the build output as an alias?
|
||||
wrapRc ? true,
|
||||
}:
|
||||
let
|
||||
isNvim = (name == "nvim");
|
||||
nvimRtp = pkgs.stdenv.mkDerivation {
|
||||
name = "nvim-rtp";
|
||||
# This is the structure of a plugin definition.
|
||||
# Each plugin in the `plugins` argument list can also be defined as this attrset
|
||||
defaultPlugin = {
|
||||
plugin = null; # e.g. nvim-lspconfig
|
||||
config = null; # plugin config
|
||||
# If `optional` is set to `false`, the plugin is installed in the 'start' packpath
|
||||
# set to `true`, it is installed in the 'opt' packpath, and can be lazy loaded with
|
||||
# ':packadd! {plugin-name}
|
||||
optional = false;
|
||||
runtime = { };
|
||||
};
|
||||
|
||||
externalPackages = extraPackages ++ (optionals withSqlite [ pkgs.sqlite ]);
|
||||
|
||||
# Map all plugins to an attrset { plugin = <plugin>; config = <config>; optional = <tf>; ... }
|
||||
normalizedPlugins = map (x: defaultPlugin // (if x ? plugin then x else { plugin = x; })) plugins;
|
||||
|
||||
# This nixpkgs util function creates an attrset
|
||||
# that pkgs.wrapNeovimUnstable uses to configure the Neovim build.
|
||||
neovimConfig = pkgs-wrapNeovim.neovimUtils.makeNeovimConfig {
|
||||
inherit
|
||||
extraPython3Packages
|
||||
withPython3
|
||||
withRuby
|
||||
withNodeJs
|
||||
viAlias
|
||||
vimAlias
|
||||
;
|
||||
plugins = normalizedPlugins;
|
||||
};
|
||||
|
||||
packDir = pkgs.neovimUtils.packDir {
|
||||
myNeovimPackages = pkgs.neovimUtils.normalizedPluginsToVimPackage normalizedPlugins;
|
||||
};
|
||||
|
||||
# This uses the ignoreConfigRegexes list to filter
|
||||
# the nvim directory
|
||||
nvimRtpSrc =
|
||||
let
|
||||
src = ../nvim;
|
||||
installPhase = ''
|
||||
in
|
||||
lib.cleanSourceWith {
|
||||
inherit src;
|
||||
name = "nvim-rtp-src";
|
||||
filter =
|
||||
path: tyoe:
|
||||
let
|
||||
srcPrefix = toString src + "/";
|
||||
relPath = lib.removePrefix srcPrefix (toString path);
|
||||
in
|
||||
lib.all (regex: builtins.match regex relPath == null) ignoreConfigRegexes;
|
||||
};
|
||||
|
||||
# Split runtimepath into 3 directories:
|
||||
# - lua, to be prepended to the rtp at the beginning of init.lua
|
||||
# - nvim, containing plugin, ftplugin, ... subdirectories
|
||||
# - after, to be sourced last in the startup initialization
|
||||
# See also: https://neovim.io/doc/user/starting.html
|
||||
nvimRtp = stdenv.mkDerivation {
|
||||
name = "nvim-rtp";
|
||||
src = nvimRtpSrc;
|
||||
|
||||
buildPhase = ''
|
||||
mkdir -p $out/
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
cp -r . $out/
|
||||
'';
|
||||
};
|
||||
|
||||
wrapperArgs = ''
|
||||
--set NVIM_APPNAME "${name}"
|
||||
--prefix PATH : "${lib.makeBinPath packages}"
|
||||
--set LIBSQLITE_CLIB_PATH "${pkgs.sqlite.out}/lib/libsqlite3.so"
|
||||
--set LIBSQLITE "${pkgs.sqlite.out}/lib/libsqlite3.so"
|
||||
'';
|
||||
# The final init.lua content that we pass to the Neovim wrapper.
|
||||
# It wraps the user init.lua, prepends the lua lib directory to the RTP
|
||||
# and prepends the nvim and after directory to the RTP
|
||||
initLua = ''
|
||||
LAZY_OPTS = {
|
||||
performance = {
|
||||
reset_packpath = false,
|
||||
rtp = {
|
||||
reset = false,
|
||||
disabled_plugins = {
|
||||
"netrwPlugin",
|
||||
"tutor",
|
||||
},
|
||||
},
|
||||
},
|
||||
dev = {
|
||||
path = "${packDir}/pack/myNeovimPackages/start",
|
||||
patterns = {""},
|
||||
},
|
||||
checker = {
|
||||
enabled = false,
|
||||
},
|
||||
install = { missing = false, },
|
||||
spec = {{ import = "plugins" }},
|
||||
}
|
||||
vim.opt.rtp:prepend('${nvimRtp}')
|
||||
''
|
||||
+ (builtins.readFile ../nvim/init.lua);
|
||||
|
||||
neovimConfig = pkgs.neovimUtils.makeNeovimConfig {
|
||||
# Add arguments to the Neovim wrapper script
|
||||
extraMakeWrapperArgs = builtins.concatStringsSep " " (
|
||||
# Set the NVIM_APPNAME environment variable
|
||||
(optional (
|
||||
appName != "nvim" && appName != null && appName != ""
|
||||
) ''--set NVIM_APPNAME "${appName}"'')
|
||||
# Add external packages to the PATH
|
||||
++ (optional (externalPackages != [ ]) ''--prefix PATH : "${makeBinPath externalPackages}"'')
|
||||
# Set the LIBSQLITE_CLIB_PATH if sqlite is enabled
|
||||
++ (optional withSqlite ''--set LIBSQLITE_CLIB_PATH "${pkgs.sqlite.out}/lib/libsqlite3.so"'')
|
||||
# Set the LIBSQLITE environment variable if sqlite is enabled
|
||||
++ (optional withSqlite ''--set LIBSQLITE "${pkgs.sqlite.out}/lib/libsqlite3.so"'')
|
||||
);
|
||||
|
||||
luaPackages = neovim-unwrapped.lua.pkgs;
|
||||
resolvedExtraLuaPackages = extraLuaPackages luaPackages;
|
||||
|
||||
# Native Lua libraries
|
||||
extraMakeWrapperLuaCArgs =
|
||||
optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_CPATH ";" "${
|
||||
concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
|
||||
# Lua libraries
|
||||
extraMakeWrapperLuaArgs =
|
||||
optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_PATH ";" "${
|
||||
concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
|
||||
# wrapNeovimUnstable is the nixpkgs utility function for building a Neovim derivation.
|
||||
neovim-wrapped = pkgs-wrapNeovim.wrapNeovimUnstable neovim-unwrapped (
|
||||
neovimConfig
|
||||
// {
|
||||
luaRcContent = initLua;
|
||||
wrapperArgs =
|
||||
escapeShellArgs neovimConfig.wrapperArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaCArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaArgs;
|
||||
wrapRc = wrapRc;
|
||||
withPython3 = false;
|
||||
vimAlias = isNvim;
|
||||
plugins = (pkgs.neovimUtils.normalizePlugins plugins);
|
||||
customLuaRC = ''vim.opt.rtp:prepend('${nvimRtp}')'' + builtins.readFile ../nvim/init.lua;
|
||||
extraMakeWrapperArgs = wrapperArgs;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
isCustomAppName = appName != null && appName != "nvim";
|
||||
in
|
||||
(pkgs.wrapNeovimUnstable pkgs.neovim-unwrapped (neovimConfig)).overrideAttrs (oa: {
|
||||
buildPhase = oa.buildPhase + lib.optionalString (!isNvim) ''mv $out/bin/nvim $out/bin/${name}'';
|
||||
neovim-wrapped.overrideAttrs (oa: {
|
||||
buildPhase =
|
||||
oa.buildPhase
|
||||
# If a custom NVIM_APPNAME has been set, rename the `nvim` binary
|
||||
+ lib.optionalString isCustomAppName ''
|
||||
mv $out/bin/nvim $out/bin/${lib.escapeShellArg appName}
|
||||
'';
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,20 +1,25 @@
|
|||
# This overlay, when applied to nixpkgs, adds the final neovim derivation to nixpkgs.
|
||||
{ inputs }:
|
||||
final: prev:
|
||||
with final.pkgs.lib;
|
||||
let
|
||||
mkNeovim = prev.callPackage ./mkNeovim.nix { pkgs = prev; };
|
||||
dart-nvim = inputs.dart.packages.x86_64-linux.default;
|
||||
mkNeovim = prev.callPackage ./mkNeovim.nix { pkgs-wrapNeovim = prev; };
|
||||
|
||||
plugins = with prev.vimPlugins; [
|
||||
plugins = with final.vimPlugins; [
|
||||
blink-cmp
|
||||
blink-ripgrep-nvim
|
||||
conform-nvim
|
||||
dart-nvim
|
||||
diffview-nvim
|
||||
eyeliner-nvim
|
||||
friendly-snippets
|
||||
lazy-nvim
|
||||
mini-nvim
|
||||
nvim-autopairs
|
||||
nvim-lint
|
||||
nvim-lspconfig
|
||||
nvim-treesitter.withAllGrammars
|
||||
nvim-treesitter-context
|
||||
nvim-treesitter-textobjects
|
||||
quicker-nvim
|
||||
refactoring-nvim
|
||||
|
|
@ -22,13 +27,12 @@ let
|
|||
snacks-nvim
|
||||
];
|
||||
|
||||
basePackages = with prev; [
|
||||
sqlite
|
||||
basePackages = with final; [
|
||||
ripgrep
|
||||
fd
|
||||
];
|
||||
# Extra packages that should be included on nixos but don't need to be bundled
|
||||
extraPackages = with prev; [
|
||||
extraPackages = with final; [
|
||||
# linters
|
||||
yamllint
|
||||
jq
|
||||
|
|
@ -40,28 +44,35 @@ let
|
|||
# LSPs
|
||||
gopls
|
||||
lua-language-server
|
||||
nixd
|
||||
nil
|
||||
basedpyright
|
||||
|
||||
#other
|
||||
jujutsu
|
||||
];
|
||||
in
|
||||
{
|
||||
nvim-pkg = mkNeovim {
|
||||
inherit plugins;
|
||||
packages = basePackages ++ extraPackages;
|
||||
extraPackages = basePackages ++ extraPackages;
|
||||
};
|
||||
|
||||
nvim-min-pkg = mkNeovim {
|
||||
inherit plugins;
|
||||
packages = basePackages;
|
||||
extraPackages = basePackages;
|
||||
};
|
||||
|
||||
# This is meant to be used within a devshell.
|
||||
# Instead of loading the lua Neovim configuration from
|
||||
# the Nix store, it is loaded from $XDG_CONFIG_HOME/nvim-dev
|
||||
nvim-dev = mkNeovim {
|
||||
inherit plugins;
|
||||
packages = basePackages ++ extraPackages;
|
||||
name = "nvim-dev";
|
||||
extraPackages = basePackages ++ extraPackages;
|
||||
appName = "nvim-dev";
|
||||
wrapRc = false;
|
||||
};
|
||||
|
||||
# This can be symlinked in the devShell's shellHook
|
||||
nvim-luarc-json = final.mk-luarc-json {
|
||||
inherit plugins;
|
||||
};
|
||||
|
|
|
|||
18
nix/plugin-overlay.nix
Normal file
18
nix/plugin-overlay.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{ inputs, ... }:
|
||||
final: prev:
|
||||
let
|
||||
mkNvimPlugin =
|
||||
src: pname:
|
||||
prev.vimUtils.buildVimPlugin {
|
||||
inherit pname src;
|
||||
version = src.lastModifiedDate;
|
||||
};
|
||||
in
|
||||
{
|
||||
vimPlugins = prev.vimPlugins.extend (
|
||||
final': prev': {
|
||||
dart-nvim = inputs.dart.packages.${prev.system}.default;
|
||||
nvim-treesitter-textobjects = mkNvimPlugin inputs.nvim-treesitter-textobjects "nvim-treesitter-textobjects";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,65 +1,34 @@
|
|||
vim.cmd('colorscheme iofq')
|
||||
|
||||
vim.g.mapleader = ' '
|
||||
vim.opt.autowrite = true
|
||||
vim.opt.backspace = 'indent,eol,start'
|
||||
vim.opt.confirm = true
|
||||
vim.opt.completeopt = 'menuone,popup,noselect,fuzzy'
|
||||
vim.opt.diffopt = 'internal,filler,closeoff,inline:char'
|
||||
vim.opt.expandtab = true -- insert tabs as spaces
|
||||
vim.opt.inccommand = 'split' -- incremental live completion
|
||||
vim.opt.laststatus = 1 -- statusline only if split
|
||||
vim.opt.nrformats:append('alpha') -- let Ctrl-a do letters as well
|
||||
vim.opt.path:append('**') -- enable fuzzy :find ing
|
||||
vim.opt.relativenumber = true
|
||||
vim.opt.shadafile = 'NONE' -- disable shada (unless session)
|
||||
vim.opt.shiftwidth = 0 -- >> shifts by tabstop
|
||||
vim.opt.showmatch = true -- highlight matching brackets
|
||||
vim.opt.showmode = true
|
||||
vim.opt.signcolumn = 'no'
|
||||
vim.opt.softtabstop = -1 -- backspace removes tabstop
|
||||
vim.opt.swapfile = false
|
||||
vim.opt.tabstop = 2 -- 2 space tabs are based
|
||||
vim.opt.updatetime = 250 -- decrease update time
|
||||
vim.opt.virtualedit = 'onemore'
|
||||
vim.opt.winborder = 'rounded'
|
||||
|
||||
-- Configure Neovim diagnostic messages
|
||||
vim.diagnostic.config {
|
||||
virtual_text = true,
|
||||
underline = true,
|
||||
severity_sort = true,
|
||||
float = {
|
||||
focusable = false,
|
||||
style = 'minimal',
|
||||
source = 'if_many',
|
||||
-- If lazy_opts is set, we're running in wrapped neovim via nix
|
||||
if not LAZY_OPTS then
|
||||
-- Bootstrapping lazy.nvim
|
||||
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
|
||||
if not vim.loop.fs_stat(lazypath) then
|
||||
vim.fn.system {
|
||||
'git',
|
||||
'clone',
|
||||
'--filter=blob:none',
|
||||
'https://github.com/folke/lazy.nvim.git',
|
||||
'--branch=stable', -- latest stable release
|
||||
lazypath,
|
||||
}
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
LAZY_OPTS = {
|
||||
spec = { { import = 'plugins' } },
|
||||
performance = {
|
||||
reset_packpath = false,
|
||||
rtp = {
|
||||
reset = false,
|
||||
disabled_plugins = {
|
||||
'netrwPlugin',
|
||||
'tutor',
|
||||
},
|
||||
}
|
||||
|
||||
vim.lsp.enable {
|
||||
'nixd',
|
||||
'phpactor',
|
||||
'gopls',
|
||||
'lua_ls',
|
||||
'basedpyright',
|
||||
}
|
||||
|
||||
local map = vim.keymap.set
|
||||
map('n', '\\t', function() -- Switch tab length on the fly
|
||||
vim.o.tabstop = vim.o.tabstop == 8 and 2 or 2 * vim.o.tabstop
|
||||
vim.notify('tabstop: ' .. vim.o.tabstop)
|
||||
end)
|
||||
map({ 'v', 'i' }, 'wq', '<esc>l')
|
||||
map('v', '<', '<gv')
|
||||
map('v', '>', '>gv')
|
||||
map('n', 'n', 'nzz', { noremap = true })
|
||||
map('n', 'N', 'Nzz', { noremap = true })
|
||||
map('n', '<C-u>', '<C-u>zz', { noremap = true })
|
||||
map('n', '<C-d>', '<C-d>zz', { noremap = true })
|
||||
map('n', 'gq', vim.cmd.bdelete, { noremap = true })
|
||||
map('n', 'gQ', function()
|
||||
vim.cmd('bufdo bdelete')
|
||||
end, { noremap = true })
|
||||
|
||||
require('autocmd')
|
||||
require('plugins')
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
vim.cmd('packadd cfilter')
|
||||
vim.cmd('colorscheme iofq')
|
||||
require('lazy').setup(LAZY_OPTS)
|
||||
require('config')
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ return {
|
|||
end,
|
||||
settings = {
|
||||
Lua = {
|
||||
codeLens = {
|
||||
enable = true,
|
||||
},
|
||||
hint = {
|
||||
enable = true,
|
||||
arrayIndex = 'Enable',
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
local cmd = vim.api.nvim_create_autocmd
|
||||
-- open :h in buffers
|
||||
cmd('FileType', {
|
||||
group = vim.api.nvim_create_augroup('help', { clear = true }),
|
||||
pattern = 'help',
|
||||
callback = function(_)
|
||||
vim.cmd.only()
|
||||
vim.keymap.set('n', 'q', vim.cmd.bdelete, { noremap = true })
|
||||
vim.bo.buflisted = false
|
||||
end,
|
||||
})
|
||||
|
||||
-- resize splits if window got resized
|
||||
cmd({ 'VimResized' }, {
|
||||
group = vim.api.nvim_create_augroup('resize_splits', { clear = true }),
|
||||
callback = function()
|
||||
vim.cmd('tabdo wincmd =')
|
||||
vim.cmd('tabnext ' .. vim.fn.tabpagenr())
|
||||
end,
|
||||
})
|
||||
|
||||
-- Check if we need to reload the file when it changed
|
||||
cmd({ 'FocusGained', 'TermClose', 'TermLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('check_reload', { clear = true }),
|
||||
callback = function()
|
||||
if vim.o.buftype ~= 'nofile' then
|
||||
vim.cmd('checktime')
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Init treesitter
|
||||
cmd('FileType', {
|
||||
callback = function(event)
|
||||
local bufnr = event.buf
|
||||
|
||||
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
|
||||
pcall(vim.treesitter.start, bufnr)
|
||||
|
||||
vim.keymap.set({ 'v', 'n' }, ']]', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_next_start('@function.outer', 'textobjects')
|
||||
end, { buffer = bufnr })
|
||||
vim.keymap.set({ 'v', 'n' }, '[[', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_previous_start('@function.outer', 'textobjects')
|
||||
end, { buffer = bufnr })
|
||||
vim.keymap.set({ 'v', 'n' }, ']a', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_next_start('@parameter.inner', 'textobjects')
|
||||
end, { buffer = bufnr })
|
||||
vim.keymap.set({ 'v', 'n' }, '[a', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_previous_start('@parameter.inner', 'textobjects')
|
||||
end, { buffer = bufnr })
|
||||
vim.keymap.set({ 'v', 'n' }, ']A', function()
|
||||
require('nvim-treesitter-textobjects.swap').swap_next('@parameter.inner')
|
||||
end, { buffer = bufnr })
|
||||
vim.keymap.set({ 'v', 'n' }, '[A', function()
|
||||
require('nvim-treesitter-textobjects.swap').swap_previous('@parameter.inner')
|
||||
end, { buffer = bufnr })
|
||||
end,
|
||||
})
|
||||
|
||||
-- Init LSP
|
||||
cmd('LspAttach', {
|
||||
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
|
||||
callback = function(ev)
|
||||
local client = vim.lsp.get_client_by_id(ev.data.client_id)
|
||||
if not client then
|
||||
return
|
||||
end
|
||||
vim.keymap.set('n', 'gO', function()
|
||||
Snacks.picker.lsp_symbols { focus = 'list' }
|
||||
end, { buffer = ev.buf })
|
||||
|
||||
vim.keymap.set('n', 'grh', function()
|
||||
vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
|
||||
end, { buffer = ev.buf })
|
||||
vim.keymap.set('n', 'grl', vim.lsp.codelens.run, { buffer = ev.buf })
|
||||
|
||||
vim.keymap.set('n', 'gre', vim.diagnostic.setloclist, { buffer = ev.buf })
|
||||
vim.keymap.set('n', 'grE', vim.diagnostic.setqflist, { buffer = ev.buf })
|
||||
|
||||
-- Auto-refresh code lenses
|
||||
if client:supports_method('textDocument/codeLens') or client.server_capabilities.codeLensProvider then
|
||||
vim.lsp.codelens.refresh { bufnr = ev.buf }
|
||||
cmd({ 'InsertLeave', 'TextChanged' }, {
|
||||
callback = function()
|
||||
vim.lsp.codelens.refresh { bufnr = ev.buf }
|
||||
end,
|
||||
buffer = ev.buf,
|
||||
})
|
||||
end
|
||||
end,
|
||||
})
|
||||
112
nvim/lua/config/autocmd.lua
Normal file
112
nvim/lua/config/autocmd.lua
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
-- create undopath
|
||||
local undopath = vim.fn.stdpath('data') .. 'undo'
|
||||
vim.api.nvim_create_autocmd('VimEnter', {
|
||||
command = 'silent !mkdir -p ' .. undopath,
|
||||
group = vim.api.nvim_create_augroup('Init', {}),
|
||||
})
|
||||
|
||||
-- open :h in buffers
|
||||
vim.api.nvim_create_autocmd('BufWinEnter', {
|
||||
pattern = '*',
|
||||
callback = function(event)
|
||||
if vim.bo[event.buf].filetype == 'help' then
|
||||
vim.cmd.only()
|
||||
vim.keymap.set('n', 'q', vim.cmd.bdelete, { noremap = true, silent = true })
|
||||
vim.bo.buflisted = false
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Allow basic deletion in qflist
|
||||
vim.api.nvim_create_autocmd({ 'FileType' }, {
|
||||
pattern = 'qf',
|
||||
callback = function()
|
||||
vim.keymap.set({ 'n', 'i' }, 'dd', function()
|
||||
local ln = vim.fn.line('.')
|
||||
local qf = vim.fn.getqflist()
|
||||
if #qf == 0 then
|
||||
return
|
||||
end
|
||||
table.remove(qf, ln)
|
||||
vim.fn.setqflist(qf, 'r')
|
||||
vim.cmd('copen')
|
||||
-- move cursor to stay at same index (or up one if at EOF)
|
||||
vim.api.nvim_win_set_cursor(vim.fn.win_getid(), { ln < #qf and ln or math.max(ln - 1, 1), 0 })
|
||||
require('quicker').refresh()
|
||||
end, { buffer = true })
|
||||
end,
|
||||
})
|
||||
|
||||
-- resize splits if window got resized
|
||||
vim.api.nvim_create_autocmd({ 'VimResized' }, {
|
||||
group = vim.api.nvim_create_augroup('resize_splits', { clear = true }),
|
||||
callback = function()
|
||||
local current_tab = vim.fn.tabpagenr()
|
||||
vim.cmd('tabdo wincmd =')
|
||||
vim.cmd('tabnext ' .. current_tab)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Check if we need to reload the file when it changed
|
||||
vim.api.nvim_create_autocmd({ 'FocusGained', 'TermClose', 'TermLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('check_reload', { clear = true }),
|
||||
callback = function()
|
||||
if vim.o.buftype ~= 'nofile' then
|
||||
vim.cmd('checktime')
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Init treesitter
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
callback = function(event)
|
||||
local bufnr = event.buf
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
|
||||
if filetype == '' then
|
||||
return
|
||||
end
|
||||
|
||||
local parser_name = vim.treesitter.language.get_lang(filetype)
|
||||
if not parser_name then
|
||||
return
|
||||
end
|
||||
local parser_installed = pcall(vim.treesitter.get_parser, bufnr, parser_name)
|
||||
if not parser_installed then
|
||||
return
|
||||
end
|
||||
|
||||
local function map(lhs, rhs, opts)
|
||||
if lhs == '' then
|
||||
return
|
||||
end
|
||||
opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})
|
||||
vim.keymap.set({ 'v', 'n' }, lhs, rhs, opts)
|
||||
end
|
||||
|
||||
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
|
||||
vim.treesitter.start()
|
||||
|
||||
map('[c', function()
|
||||
require('treesitter-context').go_to_context(vim.v.count1)
|
||||
end, { buffer = bufnr, desc = 'jump to TS context' })
|
||||
map(']f', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_next_start('@function.outer', 'textobjects')
|
||||
end, { buffer = bufnr, desc = 'next function def' })
|
||||
map('[f', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_previous_start('@function.outer', 'textobjects')
|
||||
end, { buffer = bufnr, desc = 'prev function def' })
|
||||
map(']a', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_next_start('@parameter.inner', 'textobjects')
|
||||
end, { buffer = bufnr, desc = 'next param def' })
|
||||
map('[a', function()
|
||||
require('nvim-treesitter-textobjects.move').goto_previous_start('@parameter.inner', 'textobjects')
|
||||
end, { buffer = bufnr, desc = 'prev param def' })
|
||||
map('a]', function()
|
||||
require('nvim-treesitter-textobjects.swap').swap_next('@parameter.inner')
|
||||
end, { buffer = bufnr, desc = 'swap next arg' })
|
||||
map('a[', function()
|
||||
require('nvim-treesitter-textobjects.swap').swap_previous('@parameter.inner')
|
||||
end, { buffer = bufnr, desc = 'swap prev arg' })
|
||||
end,
|
||||
})
|
||||
37
nvim/lua/config/init.lua
Normal file
37
nvim/lua/config/init.lua
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
vim.opt.autowrite = true
|
||||
vim.opt.backspace = 'indent,eol,start'
|
||||
vim.opt.confirm = true
|
||||
vim.opt.diffopt = 'internal,filler,closeoff,inline:char'
|
||||
vim.opt.expandtab = true -- insert tabs as spaces
|
||||
vim.opt.inccommand = 'split' -- incremental live completion
|
||||
vim.opt.laststatus = 1 -- statusline only if split
|
||||
vim.opt.nrformats:append('alpha') -- let Ctrl-a do letters as well
|
||||
vim.opt.path:append('**') -- enable fuzzy :find ing
|
||||
vim.opt.relativenumber = true
|
||||
vim.opt.shadafile = 'NONE' -- disable shada (unless session)
|
||||
vim.opt.shiftwidth = 0 -- >> shifts by tabstop
|
||||
vim.opt.showmatch = true -- highlight matching brackets
|
||||
vim.opt.showmode = true
|
||||
vim.opt.signcolumn = 'no'
|
||||
vim.opt.softtabstop = -1 -- backspace removes tabstop
|
||||
vim.opt.swapfile = false
|
||||
vim.opt.tabstop = 2 -- 2 space tabs are based
|
||||
vim.opt.updatetime = 250 -- decrease update time
|
||||
vim.opt.virtualedit = 'onemore'
|
||||
vim.opt.winborder = 'rounded'
|
||||
|
||||
-- Configure Neovim diagnostic messages
|
||||
vim.diagnostic.config {
|
||||
virtual_text = true,
|
||||
underline = true,
|
||||
severity_sort = true,
|
||||
float = {
|
||||
focusable = false,
|
||||
style = 'minimal',
|
||||
source = 'if_many',
|
||||
},
|
||||
}
|
||||
vim.schedule(function()
|
||||
require('config.autocmd')
|
||||
require('config.keymaps')
|
||||
end)
|
||||
18
nvim/lua/config/keymaps.lua
Normal file
18
nvim/lua/config/keymaps.lua
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
-- Switch tab length on the fly
|
||||
vim.keymap.set('n', '\\t', function()
|
||||
vim.o.tabstop = vim.o.tabstop == 8 and 2 or 2 * vim.o.tabstop
|
||||
vim.notify('tabstop: ' .. vim.o.tabstop)
|
||||
end, { silent = true, desc = 'toggle tabstop' })
|
||||
vim.keymap.set({ 'v', 'i' }, 'wq', '<esc>l', { noremap = true, silent = true })
|
||||
vim.keymap.set('v', '<', '<gv')
|
||||
vim.keymap.set('v', '>', '>gv')
|
||||
vim.keymap.set('n', 'n', 'nzz', { noremap = true })
|
||||
vim.keymap.set('n', 'N', 'Nzz', { noremap = true })
|
||||
vim.keymap.set('n', '<C-u>', '<C-u>zz', { noremap = true })
|
||||
vim.keymap.set('n', '<C-d>', '<C-d>zz', { noremap = true })
|
||||
vim.keymap.set('v', '<A-j>', ":m '>+1<CR>gv=gv", { desc = 'move selection down' })
|
||||
vim.keymap.set('v', '<A-k>', ":m '<-2<CR>gv=gv", { desc = 'move selection up' })
|
||||
vim.keymap.set('n', 'gq', vim.cmd.bdelete, { noremap = true, silent = true, desc = 'close buffer' })
|
||||
vim.keymap.set('n', 'gQ', function()
|
||||
vim.cmd('bufdo bdelete')
|
||||
end, { noremap = true, silent = true, desc = 'close all buffers' })
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
local diff = require('mini.diff')
|
||||
local M = {
|
||||
cache = {},
|
||||
}
|
||||
|
||||
M.get_buf_realpath = function(buf_id)
|
||||
local path = vim.loop.fs_realpath(vim.api.nvim_buf_get_name(buf_id)) or ''
|
||||
local cwd, basename = vim.fn.fnamemodify(path, ':h'), vim.fn.fnamemodify(path, ':t')
|
||||
return path, cwd, basename
|
||||
end
|
||||
|
||||
M.jj_start_watching_tree_state = function(buf_id, path)
|
||||
local on_not_in_jj = vim.schedule_wrap(function()
|
||||
if not vim.api.nvim_buf_is_valid(buf_id) then
|
||||
M.cache[buf_id] = nil
|
||||
return false
|
||||
end
|
||||
diff.fail_attach(buf_id)
|
||||
M.cache[buf_id] = {}
|
||||
end)
|
||||
|
||||
vim.system(
|
||||
{ 'jj', 'workspace', 'root', '--ignore-working-copy' },
|
||||
{cwd = vim.fn.fnamemodify(path, ':h')},
|
||||
function(obj)
|
||||
if obj.code ~= 0 then
|
||||
return on_not_in_jj()
|
||||
end
|
||||
|
||||
-- Set up index watching
|
||||
local root = obj.stdout:gsub('\n+$', '') .. '/.jj/working_copy/tree_state'
|
||||
local buf_fs_event = vim.loop.new_fs_event()
|
||||
|
||||
buf_fs_event:start(root, { stat = true }, function()
|
||||
M.jj_set_ref_text(buf_id)
|
||||
end)
|
||||
M.cache[buf_id] = { fs_event = buf_fs_event }
|
||||
|
||||
-- Set reference text immediately
|
||||
M.jj_set_ref_text(buf_id)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
M.jj_set_ref_text = vim.schedule_wrap(function(buf_id)
|
||||
if not vim.api.nvim_buf_is_valid(buf_id) then
|
||||
return
|
||||
end
|
||||
|
||||
local buf_set_ref_text = function(text)
|
||||
pcall(diff.set_ref_text, buf_id, text)
|
||||
end
|
||||
|
||||
-- react to possible rename
|
||||
local path, cwd, basename = M.get_buf_realpath(buf_id)
|
||||
if path == '' then
|
||||
return buf_set_ref_text {}
|
||||
end
|
||||
|
||||
vim.system(
|
||||
{ 'jj', 'file', 'show', '--no-pager', '--ignore-working-copy', '-r', '@-', './' .. basename },
|
||||
{ cwd = cwd },
|
||||
vim.schedule_wrap(function(obj)
|
||||
if obj.code ~= 0 then return buf_set_ref_text {} end
|
||||
buf_set_ref_text(obj.stdout:gsub('\r\n', '\n'))
|
||||
end)
|
||||
)
|
||||
end)
|
||||
|
||||
M.jj_invalidate_cache = function(buf_id)
|
||||
pcall(vim.loop.fs_event_stop, M.cache[buf_id].fs_event)
|
||||
M.cache[buf_id] = nil
|
||||
end
|
||||
|
||||
M.gen_source = function()
|
||||
local attach = function(buf_id)
|
||||
-- Try attaching to a buffer only once
|
||||
if M.cache[buf_id] ~= nil then
|
||||
return false
|
||||
end
|
||||
-- - Possibly resolve symlinks to get data from the original repo
|
||||
local path = M.get_buf_realpath(buf_id)
|
||||
if path == '' then
|
||||
return false
|
||||
end
|
||||
|
||||
M.cache[buf_id] = {}
|
||||
M.jj_start_watching_tree_state(buf_id, path)
|
||||
end
|
||||
|
||||
local detach = function(buf_id)
|
||||
M.jj_invalidate_cache(buf_id)
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
name = 'jj',
|
||||
attach = attach,
|
||||
detach = detach,
|
||||
apply_hunks = function(_, _) end -- staging does not apply for jj
|
||||
}
|
||||
end
|
||||
return M
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
local M = {}
|
||||
|
||||
function M.status()
|
||||
local function get_files()
|
||||
local status_raw = vim.fn.system('jj diff --no-pager --quiet --summary')
|
||||
local files = {}
|
||||
|
||||
for status in status_raw:gmatch('[^\r\n]+') do
|
||||
local state, file = string.match(status, '^(%a)%s(.+)$')
|
||||
|
||||
if state and file then
|
||||
local hl = ''
|
||||
if state == 'A' then
|
||||
hl = 'SnacksPickerGitStatusAdded'
|
||||
elseif state == 'M' then
|
||||
hl = 'SnacksPickerGitStatusModified'
|
||||
elseif state == 'D' then
|
||||
hl = 'SnacksPickerGitStatusDeleted'
|
||||
elseif state == 'R' then
|
||||
hl = 'SnacksPickerGitStatusRenamed'
|
||||
file = string.match(file, '{.-=>%s*(.-)}')
|
||||
end
|
||||
|
||||
local diff = vim.fn.system('jj diff ' .. file .. ' --no-pager --stat --git')
|
||||
table.insert(files, {
|
||||
file = file,
|
||||
filename_hl = hl,
|
||||
diff = diff,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return files
|
||||
end
|
||||
|
||||
Snacks.picker.pick {
|
||||
source = 'jj_status',
|
||||
items = get_files(),
|
||||
format = 'file',
|
||||
title = 'jj status',
|
||||
preview = function(ctx)
|
||||
if ctx.item.file then
|
||||
Snacks.picker.preview.diff(ctx)
|
||||
else
|
||||
ctx.preview:reset()
|
||||
ctx.preview:set_title('No preview')
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
local map = vim.keymap.set
|
||||
|
||||
require('mini.basics').setup { mappings = { windows = true } }
|
||||
require('mini.icons').setup()
|
||||
|
||||
require('dart').setup {
|
||||
tabline = {
|
||||
label_marked_fg = 'cyan',
|
||||
},
|
||||
}
|
||||
|
||||
require('snacks').setup {
|
||||
bigfile = { enabled = true },
|
||||
terminal = { enabled = true },
|
||||
indent = { enabled = true },
|
||||
input = { enabled = true },
|
||||
notifier = { enabled = true },
|
||||
styles = {
|
||||
notification = {
|
||||
wo = { wrap = true },
|
||||
},
|
||||
},
|
||||
picker = {
|
||||
enabled = true,
|
||||
matcher = {
|
||||
frecency = true,
|
||||
cwd_bonus = true,
|
||||
},
|
||||
layout = 'ivy_split',
|
||||
sources = {
|
||||
grep = { hidden = true },
|
||||
lsp_symbols = {
|
||||
filter = { default = true },
|
||||
layout = 'left',
|
||||
},
|
||||
smart = {
|
||||
multi = {
|
||||
'buffers',
|
||||
{ source = 'files', hidden = true },
|
||||
{ source = 'git_files', untracked = true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
map({ 'n', 't' }, '<C-\\>', Snacks.terminal.toggle)
|
||||
map('n', '<leader>ff', Snacks.picker.smart)
|
||||
map('n', '<leader><leader>', Snacks.picker.smart)
|
||||
map('n', '<leader>fa', Snacks.picker.grep)
|
||||
map('n', '<leader>f8', Snacks.picker.grep_word)
|
||||
map('n', '<leader>f?', Snacks.picker.pickers)
|
||||
map('n', '<leader>fu', Snacks.picker.undo)
|
||||
map('n', '<leader>fj', Snacks.picker.jumps)
|
||||
map('n', '<leader>f.', Snacks.picker.resume)
|
||||
map('n', '<leader>fb', Snacks.picker.buffers)
|
||||
map('n', '<leader>fq', Snacks.picker.qflist)
|
||||
map('n', '<leader>jf', require('lib.snacks_jj').status)
|
||||
|
||||
vim.schedule(function()
|
||||
require('nvim-treesitter').setup()
|
||||
require('nvim-treesitter-textobjects').setup()
|
||||
require('render-markdown').setup()
|
||||
|
||||
require('refactoring').setup()
|
||||
map('n', '<leader>rr', require('refactoring').select_refactor)
|
||||
map('n', '<leader>rv', function()
|
||||
require('refactoring').refactor('Inline Variable')
|
||||
end)
|
||||
|
||||
require('quicker').setup()
|
||||
map('n', '<leader>qf', function()
|
||||
require('quicker').toggle { max_height = 20 }
|
||||
end)
|
||||
|
||||
local close = { { { 'n' }, 'q', vim.cmd.DiffviewClose, { desc = 'Close Diffview' } } }
|
||||
require('diffview').setup {
|
||||
enhanced_diff_hl = true,
|
||||
default_args = { DiffviewOpen = { '--imply-local' } },
|
||||
view = {
|
||||
merge_tool = {
|
||||
layout = 'diff4_mixed',
|
||||
disable_diagnostics = true,
|
||||
},
|
||||
},
|
||||
keymaps = {
|
||||
view = close,
|
||||
file_panel = close,
|
||||
file_history_panel = close,
|
||||
},
|
||||
}
|
||||
|
||||
map('n', '<leader>nb', vim.cmd.DiffviewOpen)
|
||||
map('n', '<leader>nH', vim.cmd.DiffviewFileHistory)
|
||||
map('n', '<leader>nh', '<cmd>DiffviewFileHistory %<cr>')
|
||||
map('n', '<leader>go', function()
|
||||
local id = vim.fn.expand('<cword>')
|
||||
vim.cmd('DiffviewOpen ' .. id .. '~1' .. '..' .. id)
|
||||
end)
|
||||
|
||||
require('conform').setup {
|
||||
notify_no_formatters = false,
|
||||
formatters_by_ft = {
|
||||
json = { 'jq' },
|
||||
lua = { 'stylua' },
|
||||
python = { 'ruff' },
|
||||
nix = { 'nixfmt' },
|
||||
fish = { 'fish_indent' },
|
||||
['*'] = { 'trim_whitespace' },
|
||||
},
|
||||
format_on_save = function(bufnr)
|
||||
-- Disable with a global or buffer-local variable
|
||||
if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then
|
||||
return
|
||||
end
|
||||
return { timeout_ms = 1500, lsp_format = 'fallback' }
|
||||
end,
|
||||
}
|
||||
map('n', '\\f', function()
|
||||
vim.b.disable_autoformat = not vim.b.disable_autoformat
|
||||
vim.notify(string.format('Buffer formatting disabled: %s', vim.b.disable_autoformat))
|
||||
end)
|
||||
map('n', '\\F', function()
|
||||
vim.g.disable_autoformat = not vim.g.disable_autoformat
|
||||
vim.notify(string.format('Global formatting disabled: %s', vim.g.disable_autoformat))
|
||||
end)
|
||||
|
||||
require('lint').linters_by_ft = {
|
||||
docker = { 'hadolint' },
|
||||
yaml = { 'yamllint' },
|
||||
sh = { 'shellcheck' },
|
||||
go = { 'golangcilint' },
|
||||
ruby = { 'rubocop' },
|
||||
fish = { 'fish' },
|
||||
bash = { 'bash' },
|
||||
nix = { 'nix' },
|
||||
php = { 'php' },
|
||||
}
|
||||
vim.api.nvim_create_autocmd({ 'BufWritePost', 'InsertLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('lint', { clear = true }),
|
||||
callback = function()
|
||||
if vim.bo.modifiable then
|
||||
require('lint').try_lint(nil, { ignore_errors = true })
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
vim.treesitter.language.register('markdown', 'blink-cmp-documentation')
|
||||
require('blink.cmp').setup {
|
||||
enabled = function()
|
||||
return not vim.tbl_contains({ 'snacks_picker_input' }, vim.bo.filetype)
|
||||
end,
|
||||
sources = {
|
||||
default = { 'lsp', 'snippets', 'ripgrep', 'buffer' },
|
||||
providers = {
|
||||
lsp = { fallbacks = {} }, -- include buffer even when LSP is active
|
||||
ripgrep = {
|
||||
module = 'blink-ripgrep',
|
||||
name = 'rg',
|
||||
score_offset = -10,
|
||||
async = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
cmdline = {
|
||||
completion = { menu = { auto_show = true } },
|
||||
},
|
||||
completion = {
|
||||
documentation = { auto_show = true },
|
||||
menu = {
|
||||
draw = {
|
||||
columns = {
|
||||
{ 'label', 'label_description', gap = 1 },
|
||||
{ 'source_name', 'kind', gap = 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
signature = {
|
||||
enabled = true,
|
||||
trigger = { show_on_insert = true },
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
vim.schedule(function()
|
||||
require('mini.align').setup()
|
||||
require('mini.pairs').setup()
|
||||
require('mini.surround').setup()
|
||||
require('mini.splitjoin').setup { detect = { separator = '[,;\n]' } }
|
||||
|
||||
local ai = require('mini.ai')
|
||||
ai.setup {
|
||||
n_lines = 300,
|
||||
custom_textobjects = {
|
||||
i = require('mini.extra').gen_ai_spec.indent(),
|
||||
a = ai.gen_spec.treesitter { a = '@parameter.outer', i = '@parameter.inner' },
|
||||
f = ai.gen_spec.treesitter { a = '@function.outer', i = '@function.inner' },
|
||||
},
|
||||
}
|
||||
|
||||
require('mini.git').setup()
|
||||
map('n', '<leader>gb', '<Cmd>Git blame -- %<CR>')
|
||||
|
||||
local jump = require('mini.jump2d')
|
||||
jump.setup {
|
||||
view = { n_steps_ahead = 1, dim = true },
|
||||
spotter = jump.gen_spotter.vimpattern(),
|
||||
}
|
||||
|
||||
local diff = require('mini.diff')
|
||||
diff.setup {
|
||||
source = {
|
||||
require('lib.minidiff_jj').gen_source(),
|
||||
diff.gen_source.git(),
|
||||
},
|
||||
}
|
||||
map('n', '<leader>gp', MiniDiff.toggle_overlay)
|
||||
|
||||
require('mini.files').setup {
|
||||
mappings = { go_in_plus = '<CR>' },
|
||||
windows = {
|
||||
preview = true,
|
||||
width_preview = 50,
|
||||
},
|
||||
}
|
||||
map('n', '<leader>nc', function()
|
||||
MiniFiles.open(vim.api.nvim_buf_get_name(0), false) -- open current buffer's dir
|
||||
MiniFiles.reveal_cwd()
|
||||
end)
|
||||
vim.api.nvim_create_autocmd('User', {
|
||||
pattern = 'MiniFilesBufferCreate',
|
||||
callback = function(args)
|
||||
map('n', '<leader>nc', function()
|
||||
MiniFiles.synchronize()
|
||||
MiniFiles.close()
|
||||
end, { buffer = args.data.buf_id })
|
||||
map('n', '`', function()
|
||||
local _, cur_entry_path = pcall(MiniFiles.get_fs_entry().path)
|
||||
local cur_directory = vim.fs.dirname(cur_entry_path)
|
||||
if cur_directory ~= '' then
|
||||
vim.fn.chdir(cur_directory)
|
||||
end
|
||||
end, { buffer = args.data.buf_id })
|
||||
end,
|
||||
})
|
||||
|
||||
-- pass file rename events to LSP
|
||||
vim.api.nvim_create_autocmd('User', {
|
||||
group = vim.api.nvim_create_augroup('snacks_rename', { clear = true }),
|
||||
pattern = 'MiniFilesActionRename',
|
||||
callback = function(event)
|
||||
Snacks.rename.on_rename_file(event.data.from, event.data.to)
|
||||
end,
|
||||
})
|
||||
end)
|
||||
87
nvim/lua/plugins/completion.lua
Normal file
87
nvim/lua/plugins/completion.lua
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
return {
|
||||
{
|
||||
'saghen/blink.cmp',
|
||||
event = 'VeryLazy',
|
||||
dependencies = {
|
||||
'mikavilpas/blink-ripgrep.nvim',
|
||||
},
|
||||
opts = {
|
||||
enabled = function()
|
||||
return not vim.tbl_contains({ 'snacks_picker_input' }, vim.bo.filetype)
|
||||
end,
|
||||
fuzzy = {
|
||||
sorts = {
|
||||
'exact',
|
||||
'score',
|
||||
'sort_text',
|
||||
},
|
||||
},
|
||||
sources = {
|
||||
default = {
|
||||
'lsp',
|
||||
'path',
|
||||
'snippets',
|
||||
'ripgrep',
|
||||
'buffer',
|
||||
},
|
||||
providers = {
|
||||
lsp = {
|
||||
fallbacks = {}, -- include buffer even when LSP is active
|
||||
score_offset = 10,
|
||||
},
|
||||
snippets = {
|
||||
score_offset = -10,
|
||||
},
|
||||
path = {
|
||||
opts = {
|
||||
get_cwd = function(_)
|
||||
return vim.fn.getcwd() -- use nvim pwd instead of current file pwd
|
||||
end,
|
||||
},
|
||||
},
|
||||
ripgrep = {
|
||||
module = 'blink-ripgrep',
|
||||
name = 'rg',
|
||||
score_offset = -10,
|
||||
async = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
cmdline = {
|
||||
completion = {
|
||||
menu = {
|
||||
auto_show = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
completion = {
|
||||
documentation = {
|
||||
auto_show = true,
|
||||
auto_show_delay_ms = 500,
|
||||
},
|
||||
menu = {
|
||||
draw = {
|
||||
treesitter = { 'lsp' },
|
||||
columns = {
|
||||
{ 'label', 'label_description', gap = 1 },
|
||||
{ 'source_name', 'kind', gap = 1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
trigger = {
|
||||
show_on_keyword = true,
|
||||
},
|
||||
},
|
||||
signature = {
|
||||
enabled = true,
|
||||
trigger = {
|
||||
show_on_insert = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
config = function(_, opts)
|
||||
require('blink.cmp').setup(opts)
|
||||
vim.treesitter.language.register('markdown', 'blink-cmp-documentation')
|
||||
end,
|
||||
},
|
||||
}
|
||||
162
nvim/lua/plugins/lib/minidiff_jj.lua
Normal file
162
nvim/lua/plugins/lib/minidiff_jj.lua
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
local diff = require('mini.diff')
|
||||
local M = {
|
||||
cache = {},
|
||||
}
|
||||
|
||||
M.get_buf_realpath = function(buf_id)
|
||||
return vim.loop.fs_realpath(vim.api.nvim_buf_get_name(buf_id)) or ''
|
||||
end
|
||||
|
||||
M.jj_start_watching_tree_state = function(buf_id, path)
|
||||
local stdout = vim.loop.new_pipe()
|
||||
local args = { 'workspace', 'root', '--ignore-working-copy' }
|
||||
local spawn_opts = {
|
||||
args = args,
|
||||
cwd = vim.fn.fnamemodify(path, ':h'),
|
||||
stdio = { nil, stdout, nil },
|
||||
}
|
||||
|
||||
local on_not_in_jj = vim.schedule_wrap(function()
|
||||
if not vim.api.nvim_buf_is_valid(buf_id) then
|
||||
M.cache[buf_id] = nil
|
||||
return false
|
||||
end
|
||||
diff.fail_attach(buf_id)
|
||||
M.cache[buf_id] = {}
|
||||
end)
|
||||
|
||||
local process, stdout_feed = nil, {}
|
||||
local on_exit = function(exit_code)
|
||||
process:close()
|
||||
|
||||
-- Watch index only if there was no error retrieving path to it
|
||||
if exit_code ~= 0 or stdout_feed[1] == nil then
|
||||
return on_not_in_jj()
|
||||
end
|
||||
|
||||
-- Set up index watching
|
||||
local jj_dir_path = table.concat(stdout_feed, ''):gsub('\n+$', '') .. '/.jj/working_copy'
|
||||
M.jj_setup_tree_state_watch(buf_id, jj_dir_path)
|
||||
|
||||
-- Set reference text immediately
|
||||
M.jj_set_ref_text(buf_id)
|
||||
end
|
||||
|
||||
process = vim.loop.spawn('jj', spawn_opts, on_exit)
|
||||
M.jj_read_stream(stdout, stdout_feed)
|
||||
end
|
||||
|
||||
M.jj_setup_tree_state_watch = function(buf_id, jj_dir_path)
|
||||
local buf_fs_event, timer = vim.loop.new_fs_event(), vim.loop.new_timer()
|
||||
local buf_jj_set_ref_text = function()
|
||||
M.jj_set_ref_text(buf_id)
|
||||
end
|
||||
|
||||
local watch_tree_state = function(_, filename, _)
|
||||
if filename ~= 'tree_state' then
|
||||
return
|
||||
end
|
||||
-- Debounce to not overload during incremental staging (like in script)
|
||||
timer:stop()
|
||||
timer:start(50, 0, buf_jj_set_ref_text)
|
||||
end
|
||||
buf_fs_event:start(jj_dir_path, { stat = true }, watch_tree_state)
|
||||
|
||||
M.jj_invalidate_cache(M.cache[buf_id])
|
||||
M.cache[buf_id] = { fs_event = buf_fs_event, timer = timer }
|
||||
end
|
||||
M.jj_set_ref_text = vim.schedule_wrap(function(buf_id)
|
||||
if not vim.api.nvim_buf_is_valid(buf_id) then
|
||||
return
|
||||
end
|
||||
|
||||
local buf_set_ref_text = vim.schedule_wrap(function(text)
|
||||
pcall(diff.set_ref_text, buf_id, text)
|
||||
end)
|
||||
|
||||
-- NOTE: Do not cache buffer's name to react to its possible rename
|
||||
local path = M.get_buf_realpath(buf_id)
|
||||
if path == '' then
|
||||
return buf_set_ref_text {}
|
||||
end
|
||||
local cwd, basename = vim.fn.fnamemodify(path, ':h'), vim.fn.fnamemodify(path, ':t')
|
||||
|
||||
-- Set
|
||||
local stdout = vim.loop.new_pipe()
|
||||
local spawn_opts = {
|
||||
args = { 'file', 'show', '--no-pager', '--ignore-working-copy', '-r', '@-', './' .. basename },
|
||||
cwd = cwd,
|
||||
stdio = { nil, stdout, nil },
|
||||
}
|
||||
|
||||
local process, stdout_feed = nil, {}
|
||||
process = vim.loop.spawn('jj', spawn_opts, function(exit_code)
|
||||
process:close()
|
||||
|
||||
if exit_code ~= 0 or stdout_feed[1] == nil then
|
||||
return buf_set_ref_text {}
|
||||
end
|
||||
|
||||
-- Set reference text accounting for possible 'crlf' end of line in index
|
||||
local text = table.concat(stdout_feed, ''):gsub('\r\n', '\n')
|
||||
buf_set_ref_text(text)
|
||||
end)
|
||||
|
||||
M.jj_read_stream(stdout, stdout_feed)
|
||||
end)
|
||||
|
||||
M.jj_read_stream = function(stream, feed)
|
||||
local callback = function(err, data)
|
||||
if data ~= nil then
|
||||
return table.insert(feed, data)
|
||||
end
|
||||
if err then
|
||||
feed[1] = nil
|
||||
end
|
||||
stream:close()
|
||||
end
|
||||
stream:read_start(callback)
|
||||
end
|
||||
|
||||
M.jj_invalidate_cache = function(cache)
|
||||
if cache == nil then
|
||||
return
|
||||
end
|
||||
pcall(vim.loop.fs_event_stop, cache.fs_event)
|
||||
pcall(vim.loop.timer_stop, cache.timer)
|
||||
end
|
||||
|
||||
M.gen_source = function()
|
||||
local attach = function(buf_id)
|
||||
-- Try attaching to a buffer only once
|
||||
if M.cache[buf_id] ~= nil then
|
||||
return false
|
||||
end
|
||||
-- - Possibly resolve symlinks to get data from the original repo
|
||||
local path = M.get_buf_realpath(buf_id)
|
||||
if path == '' then
|
||||
return false
|
||||
end
|
||||
|
||||
M.cache[buf_id] = {}
|
||||
M.jj_start_watching_tree_state(buf_id, path)
|
||||
end
|
||||
|
||||
local detach = function(buf_id)
|
||||
local cache = M.cache[buf_id]
|
||||
M.cache[buf_id] = nil
|
||||
M.jj_invalidate_cache(cache)
|
||||
end
|
||||
|
||||
local apply_hunks = function(_, _)
|
||||
-- staging does not apply for jj
|
||||
end
|
||||
|
||||
return {
|
||||
name = 'jj',
|
||||
attach = attach,
|
||||
detach = detach,
|
||||
apply_hunks = apply_hunks,
|
||||
}
|
||||
end
|
||||
return M
|
||||
71
nvim/lua/plugins/lib/session_jj.lua
Normal file
71
nvim/lua/plugins/lib/session_jj.lua
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
local M = {}
|
||||
|
||||
M.setup = function()
|
||||
local id = M.get_id()
|
||||
if M.check_exists(id) then
|
||||
vim.notify('Existing session for ' .. id)
|
||||
end
|
||||
|
||||
vim.keymap.set('n', '<leader>fs', function()
|
||||
require('plugins.lib.session_jj').load()
|
||||
end, { noremap = true, desc = 'mini session select' })
|
||||
end
|
||||
|
||||
M.get_id = function()
|
||||
local jj_root = vim.system({ 'jj', 'workspace', 'root' }):wait()
|
||||
|
||||
if jj_root.code ~= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local result = vim
|
||||
.system({
|
||||
'jj',
|
||||
'log',
|
||||
'-r',
|
||||
'latest(heads(::@ & bookmarks()))',
|
||||
'--template',
|
||||
'bookmarks',
|
||||
'--no-pager',
|
||||
'--no-graph',
|
||||
})
|
||||
:wait()
|
||||
local branch = vim.trim(string.gsub(result.stdout, '[\n*]', '')) -- trim newlines and unpushed indicator
|
||||
local root = vim.trim(string.gsub(jj_root.stdout, '\n', ''))
|
||||
local id = string.gsub(string.format('jj:%s:%s', root, branch), '[./]', '-') -- slugify
|
||||
return id
|
||||
end
|
||||
|
||||
M.check_exists = function(id)
|
||||
for name, _ in pairs(MiniSessions.detected) do
|
||||
if name == id then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
M.load = function()
|
||||
local id = M.get_id()
|
||||
if id == '' then
|
||||
return
|
||||
end
|
||||
vim.opt.shadafile = vim.fn.stdpath('data') .. '/myshada/' .. id .. '.shada'
|
||||
if M.check_exists(id) then
|
||||
vim.ui.select({
|
||||
'Yes',
|
||||
'No',
|
||||
}, { prompt = 'Session found at ' .. id .. ', load it?' }, function(c)
|
||||
if c == 'Yes' then
|
||||
-- load session (buffers, etc) as well as shada (marks)
|
||||
MiniSessions.read(id)
|
||||
vim.notify('loaded jj session: ' .. id)
|
||||
end
|
||||
end)
|
||||
else
|
||||
MiniSessions.write(id)
|
||||
end
|
||||
end
|
||||
|
||||
_G.M = M
|
||||
return M
|
||||
121
nvim/lua/plugins/lib/snacks_jj.lua
Normal file
121
nvim/lua/plugins/lib/snacks_jj.lua
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
local M = {}
|
||||
|
||||
function M.status()
|
||||
local function get_files()
|
||||
local status_raw = vim.fn.system('jj diff --no-pager --quiet --summary')
|
||||
local files = {}
|
||||
|
||||
for status in status_raw:gmatch('[^\r\n]+') do
|
||||
local state, text = string.match(status, '^(%a)%s(.+)$')
|
||||
|
||||
if state and text then
|
||||
local file = text
|
||||
|
||||
local hl = ''
|
||||
if state == 'A' then
|
||||
hl = 'SnacksPickerGitStatusAdded'
|
||||
elseif state == 'M' then
|
||||
hl = 'SnacksPickerGitStatusModified'
|
||||
elseif state == 'D' then
|
||||
hl = 'SnacksPickerGitStatusDeleted'
|
||||
elseif state == 'R' then
|
||||
hl = 'SnacksPickerGitStatusRenamed'
|
||||
file = string.match(text, '{.-=>%s*(.-)}')
|
||||
end
|
||||
|
||||
local diff = vim.fn.system('jj diff ' .. file .. ' --ignore-working-copy --no-pager --stat --git')
|
||||
table.insert(files, {
|
||||
text = text,
|
||||
file = file,
|
||||
filename_hl = hl,
|
||||
state = state,
|
||||
diff = diff,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return files
|
||||
end
|
||||
|
||||
local files = get_files()
|
||||
|
||||
Snacks.picker.pick {
|
||||
source = 'jj_status',
|
||||
items = files,
|
||||
format = 'file',
|
||||
title = 'jj status',
|
||||
preview = function(ctx)
|
||||
if ctx.item.file then
|
||||
Snacks.picker.preview.diff(ctx)
|
||||
else
|
||||
ctx.preview:reset()
|
||||
ctx.preview:set_title('No preview')
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function M.revs()
|
||||
local function jj_new(picker, item)
|
||||
picker:close()
|
||||
if item then
|
||||
if not item.rev then
|
||||
vim.notify.warn('No branch or commit found', { title = 'Snacks Picker' })
|
||||
return
|
||||
end
|
||||
local cmd = { 'jj', 'new', '-r', item.rev }
|
||||
Snacks.picker.util.cmd(cmd, function()
|
||||
vim.notify('Checking out revision: ' .. item.rev, { title = 'Snacks Picker' })
|
||||
vim.cmd.checktime()
|
||||
require('plugins.lib.session_jj').load()
|
||||
end, { cwd = item.cwd })
|
||||
end
|
||||
end
|
||||
|
||||
local function jj_rev_cmd(ctx)
|
||||
if ctx.item.rev then
|
||||
Snacks.picker.preview.cmd({ 'jj', 'show', '--ignore-working-copy', '--git', '-r', ctx.item.rev }, ctx)
|
||||
else
|
||||
ctx.preview:reset()
|
||||
return 'No preview available.'
|
||||
end
|
||||
end
|
||||
|
||||
local function jj_log(revset)
|
||||
if revset == nil then
|
||||
revset = '-r "ancestors(@,25)"'
|
||||
else
|
||||
revset = '-r ' .. revset
|
||||
end
|
||||
local status_raw = vim.fn.system(
|
||||
'jj log --ignore-working-copy '
|
||||
.. revset
|
||||
..
|
||||
' --template \'if(root, format_root_commit(self), label(if(current_working_copy, "working_copy"), concat(separate(" ", self.change_id().shortest(8), self.bookmarks()), " | ", if(empty, label("empty", "(empty)")), if(description, description.first_line(), label(if(empty, "empty"), description_placeholder),),) ++ "\n",),)\''
|
||||
)
|
||||
local lines = {}
|
||||
|
||||
for line in status_raw:gmatch('[^\r\n]+') do
|
||||
local sign, rev = string.match(line, '(.)%s(%a+)%s.*')
|
||||
table.insert(lines, {
|
||||
text = line,
|
||||
sign = sign,
|
||||
rev = rev,
|
||||
})
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
Snacks.picker.pick {
|
||||
source = 'jj_revs',
|
||||
layout = 'ivy',
|
||||
format = 'text',
|
||||
title = 'jj log',
|
||||
items = jj_log(),
|
||||
confirm = jj_new,
|
||||
preview = jj_rev_cmd,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
131
nvim/lua/plugins/lsp.lua
Normal file
131
nvim/lua/plugins/lsp.lua
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
return {
|
||||
{
|
||||
'neovim/nvim-lspconfig',
|
||||
event = 'VeryLazy',
|
||||
config = function()
|
||||
vim.lsp.enable {
|
||||
'nil_ls',
|
||||
'phpactor',
|
||||
'gopls',
|
||||
'lua_ls',
|
||||
'basedpyright',
|
||||
}
|
||||
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
|
||||
callback = function(ev)
|
||||
local client = vim.lsp.get_client_by_id(ev.data.client_id)
|
||||
if not client then
|
||||
return
|
||||
end
|
||||
vim.keymap.set('n', 'gO', function()
|
||||
Snacks.picker.lsp_symbols { focus = 'list' }
|
||||
end, { buffer = ev.buf, desc = 'LSP symbols' })
|
||||
|
||||
vim.keymap.set('n', 'grh', function()
|
||||
vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
|
||||
end, { buffer = ev.buf, desc = 'LSP hints toggle' })
|
||||
vim.keymap.set('n', 'grl', vim.lsp.codelens.run, { buffer = ev.buf, desc = 'vim.lsp.codelens.run()' })
|
||||
|
||||
vim.keymap.set('n', 'gre', function()
|
||||
vim.diagnostic.setloclist()
|
||||
end, { buffer = ev.buf, desc = 'LSP buffer diagnostics' })
|
||||
vim.keymap.set('n', 'grE', function()
|
||||
vim.diagnostic.setqflist()
|
||||
end, { buffer = ev.buf, desc = 'LSP diagnostics' })
|
||||
|
||||
vim.keymap.set('n', 'grc', function()
|
||||
vim.lsp.buf.incoming_calls()
|
||||
end, { buffer = ev.buf, desc = 'LSP incoming_calls' })
|
||||
vim.keymap.set('n', 'gro', function()
|
||||
vim.lsp.buf.outgoing_calls()
|
||||
end, { buffer = ev.buf, desc = 'LSP outgoing_calls' })
|
||||
|
||||
-- Auto-refresh code lenses
|
||||
if client:supports_method('textDocument/codeLens') or client.server_capabilities.codeLensProvider then
|
||||
vim.api.nvim_create_autocmd({ 'InsertLeave', 'TextChanged' }, {
|
||||
group = vim.api.nvim_create_augroup(string.format('lsp-%s-%s', ev.buf, client.id), {}),
|
||||
callback = function()
|
||||
vim.lsp.codelens.refresh { bufnr = ev.buf }
|
||||
end,
|
||||
buffer = ev.buf,
|
||||
})
|
||||
vim.lsp.codelens.refresh()
|
||||
end
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_exec_autocmds('FileType', {})
|
||||
end,
|
||||
},
|
||||
{
|
||||
'stevearc/conform.nvim',
|
||||
event = 'VeryLazy',
|
||||
keys = {
|
||||
{
|
||||
'\\f',
|
||||
function()
|
||||
vim.b.disable_autoformat = not vim.b.disable_autoformat
|
||||
Snacks.notify(string.format('Buffer formatting disabled: %s', vim.b.disable_autoformat))
|
||||
end,
|
||||
mode = { 'n', 'x' },
|
||||
desc = 'toggle buffer formatting',
|
||||
},
|
||||
{
|
||||
'\\F',
|
||||
function()
|
||||
vim.g.disable_autoformat = not vim.g.disable_autoformat
|
||||
Snacks.notify(string.format('Global formatting disabled: %s', vim.g.disable_autoformat))
|
||||
end,
|
||||
mode = { 'n', 'x' },
|
||||
desc = 'toggle global formatting',
|
||||
},
|
||||
},
|
||||
opts = {
|
||||
notify_no_formatters = false,
|
||||
formatters_by_ft = {
|
||||
json = { 'jq' },
|
||||
lua = { 'stylua' },
|
||||
python = { 'ruff' },
|
||||
nix = { 'nixfmt' },
|
||||
fish = { 'fish_indent' },
|
||||
['*'] = { 'trim_whitespace' },
|
||||
},
|
||||
format_on_save = function(bufnr)
|
||||
-- Disable with a global or buffer-local variable
|
||||
if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then
|
||||
return
|
||||
end
|
||||
return { timeout_ms = 1500, lsp_format = 'fallback' }
|
||||
end,
|
||||
default_format_opts = {
|
||||
timeout_ms = 1500,
|
||||
lsp_format = 'fallback',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'mfussenegger/nvim-lint',
|
||||
event = 'VeryLazy',
|
||||
config = function()
|
||||
require('lint').linters_by_ft = {
|
||||
docker = { 'hadolint' },
|
||||
yaml = { 'yamllint' },
|
||||
sh = { 'shellcheck' },
|
||||
go = { 'golangcilint' },
|
||||
ruby = { 'rubocop' },
|
||||
fish = { 'fish' },
|
||||
bash = { 'bash' },
|
||||
nix = { 'nix' },
|
||||
php = { 'php' },
|
||||
}
|
||||
vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('lint', { clear = true }),
|
||||
callback = function()
|
||||
if vim.bo.modifiable then
|
||||
require('lint').try_lint(nil, { ignore_errors = true })
|
||||
end
|
||||
end,
|
||||
})
|
||||
end,
|
||||
},
|
||||
}
|
||||
163
nvim/lua/plugins/mini.lua
Normal file
163
nvim/lua/plugins/mini.lua
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
return {
|
||||
{
|
||||
'echasnovski/mini.nvim',
|
||||
lazy = false,
|
||||
keys = {
|
||||
{
|
||||
'<leader>gp',
|
||||
function()
|
||||
MiniDiff.toggle_overlay(0)
|
||||
end,
|
||||
noremap = true,
|
||||
desc = 'git diff overlay',
|
||||
},
|
||||
{
|
||||
'<leader>go',
|
||||
function()
|
||||
return MiniGit.show_at_cursor()
|
||||
end,
|
||||
noremap = true,
|
||||
desc = 'git show at cursor',
|
||||
},
|
||||
{
|
||||
'<leader>gb',
|
||||
'<Cmd>Git blame -- %<CR>',
|
||||
desc = 'git blame',
|
||||
},
|
||||
{
|
||||
'<leader>gg',
|
||||
':Git ',
|
||||
desc = 'git command',
|
||||
},
|
||||
},
|
||||
config = function()
|
||||
require('mini.basics').setup { mappings = { windows = true } }
|
||||
require('mini.icons').setup()
|
||||
vim.schedule(function()
|
||||
local ai = require('mini.ai')
|
||||
local extra_ai = require('mini.extra').gen_ai_spec
|
||||
ai.setup {
|
||||
n_lines = 300,
|
||||
custom_textobjects = {
|
||||
i = extra_ai.indent(),
|
||||
g = extra_ai.buffer(),
|
||||
l = extra_ai.line(),
|
||||
u = ai.gen_spec.function_call(),
|
||||
a = ai.gen_spec.treesitter { a = '@parameter.outer', i = '@parameter.inner' },
|
||||
k = ai.gen_spec.treesitter { a = '@assignment.lhs', i = '@assignment.lhs' },
|
||||
v = ai.gen_spec.treesitter { a = '@assignment.rhs', i = '@assignment.rhs' },
|
||||
f = ai.gen_spec.treesitter { a = '@function.outer', i = '@function.inner' },
|
||||
o = ai.gen_spec.treesitter {
|
||||
a = { '@block.outer', '@conditional.outer', '@loop.outer' },
|
||||
i = { '@block.inner', '@conditional.inner', '@loop.inner' },
|
||||
},
|
||||
},
|
||||
}
|
||||
require('mini.align').setup()
|
||||
require('mini.bracketed').setup { file = { suffix = 'm' } }
|
||||
require('mini.git').setup()
|
||||
require('mini.surround').setup()
|
||||
require('mini.splitjoin').setup { detect = { separator = '[,;\n]' } }
|
||||
|
||||
require('mini.sessions').setup {
|
||||
file = '',
|
||||
autowrite = true,
|
||||
hooks = {
|
||||
pre = {
|
||||
read = function(session) -- load Dart state *before* buffers are loaded
|
||||
vim.cmd('rshada')
|
||||
Dart.read_session(session['name'])
|
||||
end,
|
||||
write = function(session)
|
||||
vim.cmd('wshada')
|
||||
Dart.write_session(session['name'])
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
require('plugins.lib.session_jj').setup()
|
||||
|
||||
local jump = require('mini.jump2d')
|
||||
jump.setup {
|
||||
view = { n_steps_ahead = 1, dim = true },
|
||||
spotter = jump.gen_spotter.vimpattern(),
|
||||
}
|
||||
|
||||
local diff = require('mini.diff')
|
||||
diff.setup {
|
||||
options = { wrap_goto = true },
|
||||
source = {
|
||||
require('plugins.lib.minidiff_jj').gen_source(),
|
||||
diff.gen_source.git(),
|
||||
},
|
||||
}
|
||||
local miniclue = require('mini.clue')
|
||||
miniclue.setup {
|
||||
triggers = {
|
||||
{ mode = 'n', keys = '<Leader>' },
|
||||
{ mode = 'n', keys = 'g' },
|
||||
{ mode = 'n', keys = "'" },
|
||||
{ mode = 'n', keys = '`' },
|
||||
{ mode = 'n', keys = '"' },
|
||||
{ mode = 'n', keys = '<C-w>' },
|
||||
{ mode = 'n', keys = 'z' },
|
||||
{ mode = 'n', keys = ']' },
|
||||
{ mode = 'n', keys = '[' },
|
||||
{ mode = 'n', keys = '\\' },
|
||||
},
|
||||
window = {
|
||||
config = { width = 'auto' },
|
||||
},
|
||||
clues = {
|
||||
miniclue.gen_clues.g(),
|
||||
miniclue.gen_clues.marks(),
|
||||
miniclue.gen_clues.registers(),
|
||||
miniclue.gen_clues.windows(),
|
||||
miniclue.gen_clues.z(),
|
||||
},
|
||||
}
|
||||
local files = require('mini.files')
|
||||
files.setup {
|
||||
mappings = {
|
||||
go_in_plus = '<CR>',
|
||||
},
|
||||
windows = {
|
||||
preview = true,
|
||||
width_focus = 30,
|
||||
width_preview = 50,
|
||||
},
|
||||
}
|
||||
vim.keymap.set('n', '<leader>nc', function()
|
||||
files.open(vim.api.nvim_buf_get_name(0), false) -- open current buffer's dir
|
||||
files.reveal_cwd()
|
||||
end, { desc = 'minifiles open' })
|
||||
vim.api.nvim_create_autocmd('User', {
|
||||
pattern = 'MiniFilesBufferCreate',
|
||||
callback = function(args)
|
||||
vim.keymap.set('n', '<leader>nc', function()
|
||||
files.synchronize()
|
||||
files.close()
|
||||
end, { buffer = args.data.buf_id })
|
||||
vim.keymap.set('n', '`', function()
|
||||
local cur_entry_path = MiniFiles.get_fs_entry().path
|
||||
local cur_directory = vim.fs.dirname(cur_entry_path)
|
||||
if cur_directory ~= '' then
|
||||
vim.fn.chdir(cur_directory)
|
||||
end
|
||||
end, { buffer = args.data.buf_id })
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd('User', {
|
||||
pattern = 'MiniFilesActionRename',
|
||||
callback = function(event)
|
||||
Snacks.rename.on_rename_file(event.data.from, event.data.to)
|
||||
end,
|
||||
})
|
||||
|
||||
local multi = require('mini.keymap').map_multistep
|
||||
multi({ 'i', 's' }, '<Tab>', { 'blink_accept', 'vimsnippet_next', 'increase_indent' })
|
||||
multi({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev', 'decrease_indent' })
|
||||
end)
|
||||
end,
|
||||
},
|
||||
}
|
||||
146
nvim/lua/plugins/misc.lua
Normal file
146
nvim/lua/plugins/misc.lua
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
return {
|
||||
{
|
||||
'iofq/dart.nvim',
|
||||
lazy = false,
|
||||
priority = 1001,
|
||||
dependencies = 'echasnovski/mini.nvim',
|
||||
opts = {
|
||||
label_marked_fg = 'cyan'
|
||||
},
|
||||
},
|
||||
{
|
||||
'windwp/nvim-autopairs',
|
||||
event = 'VeryLazy',
|
||||
config = true,
|
||||
},
|
||||
{
|
||||
'nvim-treesitter/nvim-treesitter',
|
||||
event = 'VeryLazy',
|
||||
branch = 'main',
|
||||
dependencies = {
|
||||
{
|
||||
'nvim-treesitter/nvim-treesitter-textobjects',
|
||||
branch = 'main',
|
||||
config = true,
|
||||
},
|
||||
{
|
||||
'nvim-treesitter/nvim-treesitter-context',
|
||||
opts = {
|
||||
max_lines = 5,
|
||||
min_window_height = 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'jinh0/eyeliner.nvim',
|
||||
event = 'VeryLazy',
|
||||
config = true,
|
||||
},
|
||||
{
|
||||
'MeanderingProgrammer/render-markdown.nvim',
|
||||
event = 'VeryLazy',
|
||||
opts = {
|
||||
completions = {
|
||||
blink = { enabled = true },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'sindrets/diffview.nvim',
|
||||
event = 'VeryLazy',
|
||||
opts = {
|
||||
use_icons = false,
|
||||
enhanced_diff_hl = true,
|
||||
default_args = {
|
||||
DiffviewOpen = { '--imply-local' },
|
||||
},
|
||||
view = {
|
||||
merge_tool = {
|
||||
layout = 'diff4_mixed',
|
||||
disable_diagnostics = true,
|
||||
},
|
||||
},
|
||||
keymaps = {
|
||||
view = {
|
||||
{ { 'n' }, 'q', vim.cmd.DiffviewClose, { desc = 'Close Diffview' } },
|
||||
},
|
||||
file_panel = {
|
||||
{ { 'n' }, 'q', vim.cmd.DiffviewClose, { desc = 'Close Diffview' } },
|
||||
},
|
||||
file_history_panel = {
|
||||
{ { 'n' }, 'q', vim.cmd.DiffviewClose, { desc = 'Close Diffview' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
keys = {
|
||||
{ '<leader>nb', vim.cmd.DiffviewOpen, desc = 'diffview open' },
|
||||
{
|
||||
'<leader>nh',
|
||||
'<cmd>DiffviewFileHistory %<cr>',
|
||||
mode = { 'n', 'v' },
|
||||
desc = 'diffview history',
|
||||
},
|
||||
{
|
||||
'<leader>nH',
|
||||
'<cmd>DiffviewFileHistory<cr>',
|
||||
mode = { 'n', 'v' },
|
||||
desc = 'diffview history',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'ThePrimeagen/refactoring.nvim',
|
||||
event = 'VeryLazy',
|
||||
config = true,
|
||||
keys = {
|
||||
{ '<leader>rv', '<cmd>Refactor inline_var<cr>dd', mode = { 'n', 'x' } },
|
||||
{
|
||||
'<leader>rr',
|
||||
function()
|
||||
require('refactoring').select_refactor { prefer_ex_cmd = true }
|
||||
end,
|
||||
mode = { 'n', 'x' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'stevearc/quicker.nvim',
|
||||
event = 'VeryLazy',
|
||||
opts = {
|
||||
follow = {
|
||||
enabled = true,
|
||||
},
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
'<leader>qf',
|
||||
function()
|
||||
require('quicker').toggle { max_height = 20 }
|
||||
end,
|
||||
desc = 'Toggle qflist',
|
||||
},
|
||||
{
|
||||
'<leader>qr',
|
||||
function()
|
||||
require('quicker').refresh()
|
||||
end,
|
||||
desc = 'Refresh qflist',
|
||||
},
|
||||
{
|
||||
'<leader>q>',
|
||||
function()
|
||||
require('quicker').expand { before = 2, after = 2, add_to_existing = true }
|
||||
end,
|
||||
desc = 'Expand quickfix context',
|
||||
},
|
||||
{
|
||||
'<leader>q<',
|
||||
function()
|
||||
require('quicker').collapse()
|
||||
end,
|
||||
desc = 'Collapse quickfix context',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
198
nvim/lua/plugins/snacks.lua
Normal file
198
nvim/lua/plugins/snacks.lua
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
return {
|
||||
{
|
||||
'folke/snacks.nvim',
|
||||
lazy = false,
|
||||
priority = 1000,
|
||||
opts = {
|
||||
bigfile = { enabled = true },
|
||||
notifier = {
|
||||
enabled = true,
|
||||
timeout = 4000,
|
||||
},
|
||||
styles = {
|
||||
notification = {
|
||||
wo = { wrap = true },
|
||||
},
|
||||
terminal = {
|
||||
border = 'rounded',
|
||||
},
|
||||
},
|
||||
terminal = { enabled = true },
|
||||
indent = { enabled = true },
|
||||
input = { enabled = true },
|
||||
picker = {
|
||||
enabled = true,
|
||||
jump = { reuse_win = true },
|
||||
matcher = {
|
||||
frecency = true,
|
||||
history_bonus = true,
|
||||
cwd_bonus = true,
|
||||
},
|
||||
layout = 'ivy_split',
|
||||
sources = {
|
||||
grep = { hidden = true },
|
||||
explorer = { hidden = true },
|
||||
lsp_symbols = {
|
||||
filter = { default = true },
|
||||
layout = 'left',
|
||||
},
|
||||
smart = {
|
||||
sort = {
|
||||
fields = {
|
||||
'score:desc',
|
||||
'idx',
|
||||
'#text',
|
||||
},
|
||||
},
|
||||
multi = {
|
||||
'marks',
|
||||
{ source = 'buffers', current = false },
|
||||
{ source = 'files', hidden = true },
|
||||
{ source = 'git_files', untracked = true },
|
||||
},
|
||||
},
|
||||
},
|
||||
win = {
|
||||
input = {
|
||||
keys = { ['wq'] = { 'close', mode = 'i' } },
|
||||
},
|
||||
list = {
|
||||
keys = { ['wq'] = { 'close', mode = 'i' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
'<C-\\>',
|
||||
function()
|
||||
Snacks.terminal.toggle()
|
||||
end,
|
||||
mode = { 'n', 't' },
|
||||
desc = 'terminal open',
|
||||
},
|
||||
{
|
||||
'<C-/>',
|
||||
function()
|
||||
Snacks.terminal.toggle('command -v fish >/dev/null && exec fish || exec bash')
|
||||
end,
|
||||
mode = { 'n', 't' },
|
||||
desc = 'terminal open',
|
||||
},
|
||||
{
|
||||
'<leader><leader>',
|
||||
function()
|
||||
vim.cmd.delmarks { args = { '0-9' } }
|
||||
vim.cmd.delmarks { args = { '"' } }
|
||||
Snacks.picker.smart()
|
||||
end,
|
||||
desc = 'Fuzzy find smart',
|
||||
},
|
||||
{
|
||||
'<leader>fe',
|
||||
function()
|
||||
Snacks.explorer()
|
||||
end,
|
||||
desc = 'snacks explorer',
|
||||
},
|
||||
{
|
||||
'<leader>ff',
|
||||
function()
|
||||
Snacks.picker.files()
|
||||
end,
|
||||
desc = 'Fuzzy find files',
|
||||
},
|
||||
{
|
||||
'<leader>fa',
|
||||
function()
|
||||
Snacks.picker.grep()
|
||||
end,
|
||||
desc = 'Fuzzy find grep',
|
||||
},
|
||||
{
|
||||
'<leader>f8',
|
||||
function()
|
||||
Snacks.picker.grep_word()
|
||||
end,
|
||||
desc = 'Fuzzy find grep word',
|
||||
},
|
||||
{
|
||||
'<leader>f?',
|
||||
function()
|
||||
Snacks.picker.pickers()
|
||||
end,
|
||||
desc = 'See all pickers',
|
||||
},
|
||||
{
|
||||
'<leader>fu',
|
||||
function()
|
||||
Snacks.picker.undo()
|
||||
end,
|
||||
desc = 'Pick undotree',
|
||||
},
|
||||
{
|
||||
'<leader>fj',
|
||||
function()
|
||||
Snacks.picker.jumps()
|
||||
end,
|
||||
desc = 'Pick jumps',
|
||||
},
|
||||
{
|
||||
'<leader>f.',
|
||||
function()
|
||||
Snacks.picker.resume()
|
||||
end,
|
||||
desc = 'Fuzzy find resume',
|
||||
},
|
||||
{
|
||||
'<leader>fb',
|
||||
function()
|
||||
Snacks.picker.buffers()
|
||||
end,
|
||||
desc = 'Fuzzy find buffers',
|
||||
},
|
||||
{
|
||||
'<leader>fn',
|
||||
function()
|
||||
Snacks.picker.notifications()
|
||||
end,
|
||||
desc = 'pick notifications',
|
||||
},
|
||||
{
|
||||
'gO',
|
||||
function()
|
||||
Snacks.picker.treesitter()
|
||||
end,
|
||||
desc = 'pick treesitter nodes',
|
||||
},
|
||||
{
|
||||
'<leader>fq',
|
||||
function()
|
||||
Snacks.picker.qflist()
|
||||
end,
|
||||
desc = 'pick quickfix list',
|
||||
},
|
||||
{
|
||||
'<leader>jf',
|
||||
function()
|
||||
require('plugins.lib.snacks_jj').status()
|
||||
end,
|
||||
desc = 'pick notifications',
|
||||
},
|
||||
{
|
||||
'<leader>jj',
|
||||
function()
|
||||
require('plugins.lib.snacks_jj').revs()
|
||||
end,
|
||||
desc = 'pick notifications',
|
||||
},
|
||||
{
|
||||
'<leader>gd',
|
||||
function()
|
||||
Snacks.git.blame_line()
|
||||
end,
|
||||
desc = 'Snacks git blame',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue