commit 8eb7f9c5fb74316d6e02757c8615a4d33f4bcc82 Author: maia Date: Sat May 30 11:13:18 2026 -0300 initial commit diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..1535671 --- /dev/null +++ b/configuration.nix @@ -0,0 +1,135 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ config, pkgs, ... }: + +{ + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.kernelPackages = pkgs.linuxPackages_latest; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + networking.hostName = "maia"; # Define your hostname. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Enable networking + networking.networkmanager.enable = true; + + hardware.graphics = { + enable = true; + enable32Bit = true; + }; + + # Set your time zone. + time.timeZone = "America/Sao_Paulo"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + + # Configure keymap in X11 + services.xserver.xkb = { + layout = "us"; + variant = "altgr-intl"; + }; + + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users."user" = { + isNormalUser = true; + description = "user"; + shell = pkgs.fish; + extraGroups = [ + "networkmanager" + "wheel" + ]; + packages = with pkgs; [ ]; + }; + + environment.systemPackages = with pkgs; [ + neovim + waypipe + tmux + coreutils + fd + ffmpeg + fira-code-symbols + fzf + git + imagemagick + jq + lazygit + nixfmt + claude-code + ripgrep + stylua + opencode + podman-compose + ]; + + programs.nano.enable = false; + programs.fish.enable = true; + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + + virtualisation = { + containers.enable = true; + podman = { + enable = true; + defaultNetwork.settings.dns_enabled = true; + }; + }; + + services.tailscale.enable = true; + services.openssh.enable = true; + + # Open ports in the firewall. + networking.firewall.allowedTCPPortRanges = [ + { + from = 30000; + to = 30010; + } + ]; + networking.firewall.allowedUDPPortRanges = [ + { + from = 30000; + to = 30010; + } + ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "26.05"; # Did you read the comment? + +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..a98f95a --- /dev/null +++ b/flake.lock @@ -0,0 +1,47 @@ +{ + "nodes": { + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1780099287, + "narHash": "sha256-efIPwVGtIWIjWcznhaop6XN6HxnOL8800hF6CBNvlqQ=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "7d8127d308c3fb9664f7e643eec944be74ebb37d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1780146226, + "narHash": "sha256-0MaqocQeurYZ/qdagoYnyZQQfgYO6tkvO2sjbIe3VbY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "de534dfef991d02afde7a95c8fff79e5fb6885a7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..de49798 --- /dev/null +++ b/flake.nix @@ -0,0 +1,46 @@ +{ + description = "NixOS flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + inputs@{ + nixpkgs, + home-manager, + ... + }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + in + { + nixosConfigurations.maia = nixpkgs.lib.nixosSystem { + inherit system pkgs; + specialArgs = { + inherit + nixpkgs + home-manager + ; + }; + modules = [ + ./configuration.nix + ./hardware-configuration.nix + ./home.nix + inputs.home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + } + ]; + }; + }; +} diff --git a/hardware-configuration.nix b/hardware-configuration.nix new file mode 100644 index 0000000..45d7915 --- /dev/null +++ b/hardware-configuration.nix @@ -0,0 +1,48 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ohci_pci" + "ehci_pci" + "virtio_pci" + "ahci" + "usbhid" + "sr_mod" + "virtio_blk" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/1cf3c5d1-86d1-4673-8daf-311b72ef9256"; + fsType = "xfs"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/ED98-D623"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/home.nix b/home.nix new file mode 100644 index 0000000..9879b98 --- /dev/null +++ b/home.nix @@ -0,0 +1,493 @@ +{ ... }: +{ + home-manager.users.user = + { + config, + pkgs, + lib, + ... + }: + { + imports = [ ./tmux.nix ]; + custom.tmux.enable = true; + home.username = "user"; + home.stateVersion = "26.05"; + programs = { + starship.enable = true; + fish = { + enable = true; + plugins = [ + { + name = "puffer"; + src = pkgs.fetchFromGitHub { + owner = "nickeb96"; + repo = "puffer-fish"; + rev = "83174b0"; + sha256 = "sha256-Dhx5+XRxJvlhdnFyimNxFyFiASrGU4ZwyefsDwtKnSg="; + }; + } + ]; + + interactiveShellInit = '' + set fish_greeting + bind ctrl-space "" + ''; + }; + + ssh = { + enable = true; + enableDefaultConfig = false; + settings = { + "*" = { + serverAliveInterval = 60; + serverAliveCountMax = 3; + }; + }; + }; + delta = { + enable = true; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + }; + enableGitIntegration = true; + }; + git = { + enable = true; + lfs.enable = true; + settings = { + user = { + email = "maia@imatos.dev"; + name = "maia"; + signingkey = "~/.ssh/id_ed25519.pub"; + }; + safe = { + directory = "/etc/nixos"; + }; + gpg = { + format = "ssh"; + ssh.allowedSignersFile = "~/.config/git/allowed_signers"; + }; + commit.gpgsign = true; + tag.gpgsign = true; + core = { + editor = "nvim"; + whitespace = "fix,only-indent-error,trailing-space,space-before-tab"; + quotepath = false; + }; + diff = { + algorithm = "histogram"; + renames = "copies"; + tool = "nvim"; + }; + difftool = { + prompt = false; + nvim.cmd = "nvim -d $LOCAL $REMOTE"; + }; + merge = { + conflictstyle = "zdiff3"; + tool = "nvim"; + }; + mergetool = { + prompt = false; + keepBackup = false; + nvim.cmd = "nvim -d $LOCAL $REMOTE $MERGED -c 'wincmd w' -c 'wincmd J'"; + }; + init = { + defaultBranch = "master"; + }; + push = { + autoSetupRemote = true; + default = "current"; + }; + pull = { + rebase = true; + }; + fetch = { + prune = true; + }; + help = { + autocorrect = "prompt"; + }; + }; + }; + neovim = { + enable = true; + defaultEditor = true; + viAlias = true; + vimAlias = false; + vimdiffAlias = true; + withPython3 = false; + withRuby = false; + plugins = with pkgs.vimPlugins; [ + { + plugin = auto-session; + type = "lua"; + config = '' + require("auto-session").setup({ + cwd_change_handling = true, + suppressed_dirs = { "$HOME", "/etc/nixos", "$HOME/tmp" }, + }) + ''; + } + { + plugin = blink-cmp; + type = "lua"; + config = '' + require("blink.cmp").setup({ + completion = { + documentation = { + auto_show = true + }, + }, + keymap = { + preset = "default", + [""] = { "snippet_forward", "fallback" }, + [""] = { "select_and_accept", "snippet_forward", "fallback" }, + [""] = { "snippet_backward", "fallback" }, + }, + }) + ''; + } + # { + # plugin = comment-nvim; + # type = "lua"; + # config = '' + # require('Comment').setup() + # ''; + # } + { + plugin = conform-nvim; + type = "lua"; + config = '' + require("conform").setup({ + formatters_by_ft = { + c = { "clang-format" }, + cpp = { "clang-format" }, + lua = { "stylua" }, + javascript = { "prettierd" }, + nix = { "nixfmt" }, + python = { "black" }, + php = { "php_cs_fixer" }, + zig = { "zigfmt" }, + css = { "prettierd" }, + scss = { "prettierd" }, + less = { "prettierd" }, + blade = { "blade-formatter" }, + go = { "gofmt" }, + wgsl = { "wgsl_fmt" }, + odin = { "odinfmt" }, + }, + }) + vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*", + callback = function(args) + require("conform").format({ bufnr = args.buf }) + end, + }) + vim.keymap.set("n", "rf", function() + require("conform").format({ + lsp_fallback = true, + async = true, + timeout_ms = 500, + }) + end, { desc = "conform format" }) + ''; + } + leap-nvim + { + plugin = mini-icons; + type = "lua"; + config = ''require("mini.icons").setup()''; + } + { + plugin = neotest; + type = "lua"; + config = '' + require('neotest').setup({ + output = { + open_on_run = true + }, + adapters = { + require('neotest-pest'), + -- require('neotest-zig'), + -- require('neotest-odin'), + }, + watch = { + filter_path = function(path, root) + return true + end, + }, + }) + vim.keymap.set('n', 'pn', function() require('neotest').run.run() end, { desc = "test nearest" }) + vim.keymap.set('n', 'pe', function() require('neotest').run.run(vim.fn.expand('%')) end, { desc = "test file" }) + ''; + } + { + plugin = neotest-pest; + type = "lua"; + } + # { + # plugin = neotest-zig; + # type = "lua"; + # } + { + plugin = nvim-autopairs; + type = "lua"; + config = '' + require('nvim-autopairs').setup() + ''; + } + { + plugin = nvim-dap; + type = "lua"; + config = '' + local dap = require("dap") + dap.adapters = { + php = { + type = "executable", + command = "${pkgs.nodejs}/bin/node", + args = { "${pkgs.vscode-extensions.xdebug.php-debug}/share/vscode/extensions/xdebug.php-debug/out/phpDebug.js" }, + }, + } + + dap.configurations = { + php = { + { + type = 'php', + request = 'launch', + name = 'listen for xdebug', + port = 9003, + } + }, + } + ''; + } + { + plugin = nvim-dap-ui; + type = "lua"; + config = '' + local dapui = require("dapui") + dapui.setup() + dap.listeners.before.attach.dapui_config = function() + dapui.open() + end + dap.listeners.before.launch.dapui_config = function() + dapui.open() + end + dap.listeners.before.event_terminated.dapui_config = function() + dapui.close() + end + dap.listeners.before.event_exited.dapui_config = function() + dapui.close() + end + ''; + } + { + plugin = nvim-treesitter.withAllGrammars; + type = "lua"; + config = '' + local treesitter = require("nvim-treesitter") + treesitter.setup() + vim.api.nvim_create_autocmd('FileType', { + pattern = { + 'c', 'lua', 'vim', 'vimdoc', 'query', 'elixir', 'heex', 'javascript', 'typescript', + 'html', 'yaml', 'blade', 'php', 'scss', 'comment', 'cmake' , 'dockerfile', 'fish', + 'fsharp', 'git_config', 'git_rebase', 'gitignore', 'glsl', 'go', 'gomod', 'graphql', + 'haskell', 'hlsl', 'http', 'ini', 'javadoc', 'jq', 'jsdoc', 'json', 'json5', 'kitty', + 'latex', 'markdown', 'nginx', 'nix', 'php', 'php_only', 'phpdoc', 'regex', 'rust', 'sql', + 'ssh_config', 'tmux', 'vim', 'wgsl', 'yaml', 'zig', 'odin', + }, + callback = function() + vim.treesitter.start() + end, + }) + ''; + } + { + plugin = nvim-treesitter-context; + type = "lua"; + config = ''require("treesitter-context").setup()''; + } + # { + # plugin = nvim-treesitter-textobjectse + # type = "lua"; + # config = '' + # vim.g.no_plugin_maps = true + # require("treesitter-textobjects").setup() + # ''; + # } + nvim-lspconfig + nvim-nio + { + plugin = nvim-surround; + type = "lua"; + config = ''require("nvim-surround").setup()''; + } + { + plugin = nvim-web-devicons; + type = "lua"; + config = ''require("nvim-web-devicons").setup()''; + } + { + plugin = oil-nvim; + type = "lua"; + config = '' + require("oil").setup() + vim.keymap.set("n", "o", "Oil", { desc = "Oil" }) + ''; + } + { + plugin = opencode-nvim; + type = "lua"; + config = '' + vim.o.autoread = true + -- Recommended/example keymaps. + vim.keymap.set({ "n", "x" }, "h", function() require("opencode").ask("@this: ", { submit = true }) end, { desc = "Ask opencode…" }) + vim.keymap.set({ "n", "x" }, "", function() require("opencode").select() end, { desc = "Execute opencode action…" }) + vim.keymap.set({ "n", "t" }, "", function() require("opencode").toggle() end, { desc = "Toggle opencode" }) + + vim.keymap.set({ "n", "x" }, "go", function() return require("opencode").operator("@this ") end, { desc = "Add range to opencode", expr = true }) + + vim.keymap.set("n", "", function() require("opencode").command("session.half.page.up") end, { desc = "Scroll opencode up" }) + vim.keymap.set("n", "", function() require("opencode").command("session.half.page.down") end, { desc = "Scroll opencode down" }) + + -- You may want these if you stick with the opinionated "" and "" above — otherwise consider "o…". + vim.keymap.set("n", "+", "", { desc = "Increment under cursor", noremap = true }) + vim.keymap.set("n", "-", "", { desc = "Decrement under cursor", noremap = true }) + ''; + } + phpactor + plenary-nvim + { + plugin = render-markdown-nvim; + type = "lua"; + config = ''require("render-markdown").setup()''; + } + { + plugin = snacks-nvim; + type = "lua"; + config = '' + local snacks = require("snacks") + snacks.setup({ + bigfile = {}, + dim = {}, + image = {}, + indent = {}, + lazygit = {}, + picker = { + win = { + input = { + keys = { + [""] = { "close", mode = { "n", "i" } }, + }, + }, + }, + }, + quickfile = {}, + notifier = {}, + }) + vim.keymap.set({ "n" }, "t", snacks.picker.grep, { desc = "grep picker" }) + vim.keymap.set({ "n" }, "r", snacks.picker.buffers, { desc = "buffer picker" }) + vim.keymap.set({ "n" }, "s", snacks.picker.files, { desc = "file picker" }) + vim.keymap.set({ "n" }, "ln", snacks.picker.lsp_references, { desc = "lsp references" }) + vim.keymap.set("n", "le", snacks.picker.lsp_implementations, { desc = "lsp implementations" }) + -- vim.keymap.set("n", "lg", function() snacks.lazygit() end , { desc = "lazygit" }) + ''; + } + { + plugin = tabby-nvim; + type = "lua"; + config = '' + require("tabby").setup({ + preset = "active_wins_at_tail", + options = { + theme = { + fill = "TabLineFill", + head = "TabLine", + current_tab = "TabLineSel", + tab = "TabLine", + win = "TabLine", + tail = "TabLine", + }, + nerdfont = true, + lualine_theme = nil, + tab_name = { + name_fallback = function(tabid) + return tabid + end, + }, + buf_name = { mode = "unique", }, + }, + }) + vim.keymap.set("n", "to", "Tabby jump_to_tab", { desc = "Jump to tab" }) + vim.keymap.set("n", "tf", "Tabby pick_window", { desc = "Search tab" }) + ''; + } + { + plugin = ts-autotag-nvim; + type = "lua"; + config = '' + require("ts-autotag").setup() + ''; + } + { + plugin = trouble-nvim; + type = "lua"; + config = '' + require("trouble").setup({}) + vim.keymap.set("n", "id", "Trouble diagnostics toggle", { desc = "Trouble project" }) + ''; + } + { + plugin = undotree; + type = "lua"; + config = ''vim.keymap.set("n", "u", vim.cmd.UndotreeToggle, { desc = "undotree" })''; + } + vim-repeat + { + plugin = which-key-nvim; + type = "lua"; + config = '' + local wk = require("which-key") + wk.setup({ + preset = "helix", + win = { row = 0, col = 0.5 }, + triggers = { + { "", mode = { "n", "v" } }, + { "", mode = { "n", "v" } }, + } + }) + wk.add({ + { "s", group = "Search..." }, + { "l", group = "Launch..." }, + { "t", group = "Tab..." }, + { "g", group = "Go..." }, + { "r", group = "Run..." }, + { "n", group = "term..." }, + }) + -- vim.keymap.set({"t"}, "", wk.show, { desc = "Show which key in terminal mode" }) + ''; + } + vim-fugitive + ]; + initLua = '' + ${builtins.readFile ./neovim/settings.lua} + ${builtins.readFile ./neovim/plugins.lua} + vim.cmd.colorscheme("desert") + -- require("custom") + ''; + }; + + }; + xdg.configFile."containers/containers.conf".text = '' + [engine] + compose_warning_logs=false + ''; + + xdg.configFile."git/allowed_signers".text = '' + maia@imatos.dev namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEnSlABByEEDWpHcJxUotTTlPA/jcuk8wWiDxS5BfZQs + ''; + }; +} diff --git a/neovim/plugins.lua b/neovim/plugins.lua new file mode 100644 index 0000000..c39d64d --- /dev/null +++ b/neovim/plugins.lua @@ -0,0 +1,156 @@ +local hostname = "maia" + +local servers = { + clangd = {}, + textlab = {}, + lua_ls = { + settings = { + Lua = { + runtime = { + version = "LuaJIT", + }, + diagnostics = { + globals = { "vim" }, + }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + }, + }, + }, + nixd = { + nixpkgs = { + expr = 'import (builtins.getFlake "/etc/nixos").inputs.nixpkgs {}', + }, + formatting = { command = { "nixfmt" } }, + options = { + nixos = { + expr = '(builtins.getFlake "/etc/nixos").nixosConfigurations.' .. hostname .. ".options", + }, + home_manager = { + expr = '(builtins.getFlake "/etc/nixos").homeConfigurations.' .. hostname .. ".options", + }, + }, + }, + phpactor = {}, + zls = { + settings = { + zls = { + enable_build_on_save = true, + semantic_tokens = "partial", + global_cache_path = vim.fn.getcwd(0, 0) .. "/.cache/zls", + }, + }, + }, + css = {}, + scss = {}, + less = {}, + blade = {}, + html = { filetypes = { "html", "blade" } }, + htmx = { filetypes = { "html", "blade" } }, + gopls = {}, + ols = { + enable_semantic_tokens = true, + enable_auto_import = true, + checker_args = "-vet", + }, + wgsl_analyzer = {}, +} +for server, config in pairs(servers) do + vim.lsp.config(server, config) + vim.lsp.enable(server) +end + +-- vim.api.nvim_create_autocmd("LspAttach", { +-- group = vim.api.nvim_create_augroup("UserConfigLsp", {}), +-- callback = function(ev) +vim.keymap.set("n", "gn", vim.lsp.buf.declaration, { desc = "go to declaration" }) +vim.keymap.set("n", "ge", vim.lsp.buf.definition, { desc = "go to definition" }) +-- vim.keymap.set("n", "gi", vim.lsp.buf.implementaion, { desc = "go to implementation" }) +vim.keymap.set("n", "rr", vim.lsp.buf.rename, { desc = "lsp rename" }) +vim.keymap.set("n", "ra", vim.lsp.buf.code_action, { desc = "code action" }) +vim.keymap.set({ "n", "i" }, "", vim.lsp.buf.signature_help, { desc = "signature help" }) +vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "references" }) +-- end, +-- }) + +local leap = require("leap") +leap.opts.preview = function(ch0, ch1, ch2) + return not (ch1:match("%s") or (ch0:match("%a") and ch1:match("%a") and ch2:match("%a"))) +end +-- leap.opts.equivalence_classes = { +-- " \t\r\n", +-- "([{", +-- ")]}", +-- "'\"`", +-- } +vim.api.nvim_set_hl(0, "LeapBackdrop", { link = "Comment" }) + +do + -- Return an argument table for `leap()`, tailored for f/t-motions. + local function as_ft(key_specific_args) + local common_args = { + inputlen = 1, + inclusive = true, + -- To limit search scope to the current line: + -- pattern = function (pat) return '\\%.l'..pat end, + opts = { + labels = "", -- force autojump + safe_labels = vim.fn.mode(1):match("[no]") and "" or nil, -- [1] + }, + } + return vim.tbl_deep_extend("keep", common_args, key_specific_args) + end + + local clever = require("leap.user").with_traversal_keys -- [2] + local clever_f = clever("f", "F") + local clever_t = clever("t", "T") + + for key, key_specific_args in pairs({ + f = { opts = clever_f }, + F = { backward = true, opts = clever_f }, + t = { offset = -1, opts = clever_t }, + T = { backward = true, offset = 1, opts = clever_t }, + }) do + vim.keymap.set({ "n", "x", "o" }, key, function() + require("leap").leap(as_ft(key_specific_args)) + end) + end +end + +vim.api.nvim_create_autocmd("CmdlineLeave", { + group = vim.api.nvim_create_augroup("LeapOnSearch", {}), + callback = function() + local ev = vim.v.event + local is_search_cmd = (ev.cmdtype == "/") or (ev.cmdtype == "?") + local cnt = vim.fn.searchcount().total + if is_search_cmd and not ev.abort and (cnt > 1) then + -- Allow CmdLineLeave-related chores to be completed before + -- invoking Leap. + vim.schedule(function() + -- We want "safe" labels, but no auto-jump (as the search + -- command already does that), so just use `safe_labels` + -- as `labels`, with n/N removed. + local labels = require("leap").opts.safe_labels:gsub("[nN]", "") + -- For `pattern` search, we never need to adjust conceallevel + -- (no user input). We cannot merge `nil` from a table, but + -- using the option's current value has the same effect. + local vim_opts = { ["wo.conceallevel"] = vim.wo.conceallevel } + require("leap").leap({ + pattern = vim.fn.getreg("/"), -- last search pattern + windows = { vim.fn.win_getid() }, + opts = { safe_labels = "", labels = labels, vim_opts = vim_opts }, + }) + end) + end + end, +}) + +vim.keymap.set({ "n", "x", "o" }, "s", "(leap)", { desc = "leap" }) +vim.keymap.set({ "n", "x", "o" }, "S", "(leap-from-window)", { desc = "leap across window" }) + + diff --git a/neovim/settings.lua b/neovim/settings.lua new file mode 100644 index 0000000..d22685f --- /dev/null +++ b/neovim/settings.lua @@ -0,0 +1,145 @@ +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.cursorline = true +vim.opt.wrap = false +vim.opt.scrolloff = 10 +vim.opt.sidescrolloff = 8 + +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.softtabstop = 4 +vim.opt.expandtab = true +vim.opt.smartindent = true +vim.opt.autoindent = true + +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.hlsearch = false +vim.opt.incsearch = true + +vim.opt.termguicolors = true +vim.opt.signcolumn = "yes" +vim.opt.colorcolumn = "120" +vim.opt.showmatch = false +--- vim.opt.matchtime = 2 +vim.opt.conceallevel = 0 +vim.opt.concealcursor = "" +vim.opt.synmaxcol = 1000 +vim.opt.isfname:append("@-@") + +vim.opt.backup = false +vim.opt.writebackup = false +vim.opt.swapfile = false +vim.opt.undofile = true +vim.opt.undodir = vim.fn.expand("~/.cache/vim/undodir") +vim.opt.updatetime = 100 +vim.opt.timeoutlen = 500 +vim.opt.ttimeoutlen = 0 +vim.opt.autoread = true +vim.opt.autowrite = false + +vim.opt.hidden = true +--- vim.opt.errorbells = false +vim.opt.backspace = "indent,eol,start" +vim.opt.autochdir = false +vim.opt.path:append("**") +vim.opt.selection = "exclusive" +vim.opt.mouse = "a" +vim.opt.modifiable = true +vim.opt.encoding = "UTF-8" + +-- Split behavior +vim.opt.splitbelow = true +vim.opt.splitright = true + +vim.g.mapleader = " " +vim.g.maplocalleader = vim.api.nvim_replace_termcodes("", false, false, true) + +vim.o.exrc = true +vim.o.showtabline = 2 + +vim.cmd("set title") +vim.cmd("set ic") + +-- Delete without yanking +vim.keymap.set({ "n", "v" }, "d", '"_d', { desc = "Delete without yanking" }) +vim.keymap.set({ "n", "v" }, "", '"+y', { desc = "Copy to clipboard" }) +vim.keymap.set("x", "p", '"_dP', { desc = "Replace without yanking" }) + +-- Wayland clipboard mappings +vim.keymap.set({ "n", "v" }, "y", '"+y', { desc = "Yank to system clipboard" }) +vim.keymap.set("n", "Y", '"+Y', { desc = "Yank line to system clipboard" }) +vim.keymap.set({ "n", "v" }, "p", '"+p', { desc = "Paste from system clipboard" }) +vim.keymap.set({ "n", "v" }, "P", '"+P', { desc = "Paste from system clipboard before cursor" }) + +-- Better J behavior +vim.keymap.set("n", "J", "mzJ`z", { desc = "Join lines and keep cursor position" }) + +--- center when jumping +vim.keymap.set("n", "n", "nzzzv", { desc = "Next search result (centered)" }) +vim.keymap.set("n", "N", "Nzzzv", { desc = "Previous search result (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page down (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page up (centered)" }) + +--- window navigation +vim.keymap.set("n", "Left", "h", { desc = "Move to left window" }) +vim.keymap.set("n", "Right", "l", { desc = "Move to right window" }) +vim.keymap.set("n", "Top", "k", { desc = "Move to top window" }) +vim.keymap.set("n", "Down", "j", { desc = "Move to bottom window" }) + +vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) + +vim.keymap.set("n", "tn", "$tabnew", { desc = "create tab" }) +vim.keymap.set("n", "n", function() + vim.cmd("tabnext 1") +end, { desc = "Go to tab 1" }) +vim.keymap.set("n", "e", function() + vim.cmd("tabnext 2") +end, { desc = "Go to tab 2" }) +vim.keymap.set("n", "i", function() + vim.cmd("tabnext 3") +end, { desc = "Go to tab 3" }) +vim.keymap.set("n", "a", function() + vim.cmd("tabnext 4") +end, { desc = "Go to tab 4" }) +vim.keymap.set({ "n", "t" }, "", function() + vim.cmd("tabnext #") +end, { desc = "Go to previous tab" }) +vim.keymap.set({ "n", "t" }, "", "p", { desc = "Go to previous pane" }) + +vim.keymap.set("n", "", "w", { desc = "save buffer" }) + +vim.diagnostic.config({ + virtual_text = false, + virtual_lines = true, + signs = true, + underline = true, + update_in_insert = true, + severity_sort = true, +}) + +-- Highlight yanked text +vim.api.nvim_create_autocmd("TextYankPost", { + group = augroup, + callback = function() + vim.highlight.on_yank() + end, +}) + +--- return to last edit position when opening files +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup, + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +--- command line completion +vim.opt.wildmenu = true +vim.opt.wildmode = "longest:full,full" +vim.opt.wildignore:append({ "*.o", "*.obj", "*.pyc", "*.class", "*.jar", "*.lock" }) + diff --git a/tmux.nix b/tmux.nix new file mode 100644 index 0000000..8b8915a --- /dev/null +++ b/tmux.nix @@ -0,0 +1,191 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +let + cfg = config.custom.tmux; + whichKeyConfig = pkgs.writeText "tmux-which-key-config.yaml" ( + lib.generators.toYAML { } { + command_alias_start_index = 200; + keybindings = { + prefix_table = "Space"; + }; + title = { + style = "align=centre,bold"; + prefix = "tmux"; + prefix_style = "fg=green,align=centre,bold"; + }; + custom_variables = { }; + macros = [ ]; + position = { + x = "R"; + y = "P"; + }; + items = [ + { + name = "Window 1"; + key = "n"; + command = "select-window -t 1"; + } + { + name = "Window 2"; + key = "e"; + command = "select-window -t 2"; + } + { + name = "Window 3"; + key = "i"; + command = "select-window -t 3"; + } + { + name = "Window 4"; + key = "a"; + command = "select-window -t 4"; + } + { + name = "Next window"; + key = "Enter"; + command = "next-window"; + transient = true; + } + { + name = "Last window"; + key = "Space"; + command = "last-window"; + } + { + separator = true; + } + { + name = "Copy mode"; + key = "BSpace"; + command = "copy-mode"; + } + { + separator = true; + } + { + name = "New window"; + key = "l"; + command = "new-window"; + } + { + name = "New pane (vertical line)"; + key = ","; + command = "splitw -h -c #{pane_current_path}"; + } + { + name = "Split (horizontal line)"; + key = "h"; + command = "splitw -v -c #{pane_current_path}"; + } + { + separator = true; + } + { + name = "Sessions"; + key = "m"; + menu = [ + { + name = "sessionizer"; + key = "Space"; + command = "run-shell \"tmux neww tmux-sessionizer\""; + } + { + name = "last-session"; + key = "Enter"; + command = "run-shell \"tmux switchc -l\""; + } + ]; + } + { + separator = true; + } + { + name = "Kill"; + key = "k"; + menu = [ + { + name = "Kill window"; + key = "w"; + command = "kill-window"; + } + { + name = "Kill pane"; + key = "p"; + command = "kill-pane"; + } + ]; + } + ]; + } + ); +in +{ + options.custom.tmux = { + enable = mkEnableOption "Custom Tmux"; + }; + config = mkIf cfg.enable { + programs.tmux = { + enable = true; + baseIndex = 1; + keyMode = "vi"; + mouse = true; + + plugins = with pkgs.tmuxPlugins; [ + sensible + yank + pain-control + # tmux-powerline + { + plugin = pkgs.tmuxPlugins.tmux-which-key.overrideAttrs (old: { + postInstall = (old.postInstall or "") + '' + echo "[tmux-which-key] Pre-generating configuration at build time..." + + ${lib.getExe (pkgs.python3.withPackages (ps: with ps; [ pyyaml ]))} \ + $target/plugin/build.py \ + ${whichKeyConfig} \ + $target/init.tmux + + # Append a line to source the pre-generated config + echo 'tmux source-file "$root_dir/init.tmux"' >> $target/plugin.sh.tmux + ''; + }); + extraConfig = '' + set -g @tmux-which-key-xdg-enable 1; + set -g @tmux-which-key-disable-autobuild 1; + ''; + } + { + plugin = resurrect; + extraConfig = "set -g @ressurect-strategy-nvim 'session'"; + } + { + plugin = continuum; + extraConfig = '' + set -g @continuum-restore 'on' + set -g @continuum-save-interval '60' + ''; + } + ]; + extraConfig = '' + set -g status-position top + set -g focus-events on + set -g allow-passthrough on + set -s extended-keys on + set -g default-terminal "xterm-ghostty" + set -as terminal-features ",xterm-ghostty:extkeys" + + bind -n M-, run-shell "tmux neww tmux-sessionizer" + bind -n M-/ run-shell "tmux switch-client -t default" + bind -n M-. run-shell "tmux switchc -l" + + bind-key -n Home send Escape "OH" + bind-key -n End send Escape "OF" + ''; + }; + }; +}