diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/flake.yml b/.github/workflows/flake.yml new file mode 100644 index 0000000..3106f03 --- /dev/null +++ b/.github/workflows/flake.yml @@ -0,0 +1,31 @@ +name: Test flake + +on: + pull_request: + push: + branches: + - main + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: actions/checkout@v3 + - run: nix flake check + + build: + needs: check + runs-on: ubuntu-latest + strategy: + matrix: + profile: + - default + - neovim + steps: + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: extractions/setup-just@v1 + - uses: actions/checkout@v3 + - run: just build "${{ matrix.profile }}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92b2793 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.direnv diff --git a/README.md b/README.md index af9b927..5588179 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,64 @@ # thealtf4stream.nvim Neovim configuration for TheAltF4Stream as a plugin. + +[![Test flake](https://github.com/ALT-F4-LLC/thealtf4stream.nvim/actions/workflows/flake.yml/badge.svg)](https://github.com/ALT-F4-LLC/thealtf4stream.nvim/actions/workflows/flake.yml) + +![Preview](https://github.com/ALT-F4-LLC/thealtf4stream.nvim/blob/main/lib/preview.webp) + +## Install + +### Neovim + +> [!WARNING] +> By default, this setup was designed for Nix and needs a stable example Lua configuration. + +- WIP + +### Nix + +This flake provides a `neovim` derivation that can be used as a packge on any Nix supported system. This is a "wrapped" variant of Neovim which includes configuration and dependencies (language servers, formatters, etc). + +> [!NOTE] +> The `neovim` derivation provides an identical editor expierence on any `nix` supported host. + +#### Run in shell + +- Run `neovim` directly with: + +```shell +$ nix run github:ALT-F4-LLC/thealtf4stream.nvim#neovim +``` + +- Run `neovim` in new shell with: + +```shell +$ nix shell github:ALT-F4-LLC/thealtf4stream.nvim#neovim +$ neovim +``` + +#### Add to flake + +- Add to `flake.nix` as an input: + +```nix +inputs = { + thealtf4stream-nvim.url = "github:ALT-F4-LLC/thealtf4stream.nvim"; +}; +``` + +- (option a): Add to `environment.systemPackages` configuration: + +```nix +environment.systemPackages = [ + inputs.thealtf4stream-nvim.packages.${pkgs.system}.neovim +]; +``` + +- (option b): Add to `home-manager` configuration: + +```nix +programs.neovim = { + enable = true; + package = inputs.thealtf4stream-nvim.packages.${pkgs.system}.neovim; +}; +``` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..a164e5a --- /dev/null +++ b/flake.lock @@ -0,0 +1,63 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1704982712, + "narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "07f6395285469419cf9d078f59b5b49993198c00", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1704722960, + "narHash": "sha256-mKGJ3sPsT6//s+Knglai5YflJUF2DGj7Ai6Ynopz0kI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "317484b1ead87b9c1b8ac5261a8d2dd748a0492d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1703961334, + "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d28029c --- /dev/null +++ b/flake.nix @@ -0,0 +1,41 @@ +{ + description = "Neovim configuration for TheAltF4Stream as a plugin"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = inputs@{ self, flake-parts, nixpkgs, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + flake = { + lib = import ./lib { inherit inputs; }; + }; + + systems = [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ]; + + perSystem = { config, self', inputs', pkgs, system, ... }: + let + inherit (pkgs) just mkShell writeShellApplication; + neovim = self.lib.mkNvim { inherit system; }; + neovimRuntimeInputs = self.lib.mkNvimRuntimeInputs { inherit system; }; + in + { + devShells = { + default = mkShell { + buildInputs = [ just ]; + }; + }; + + packages = { + default = self.lib.mkNvimConfig { inherit system; }; + + neovim = writeShellApplication + { + runtimeInputs = [ neovim ] ++ neovimRuntimeInputs; + name = "nvim"; + text = '' + ${neovim}/bin/nvim "$@" + ''; + }; + }; + }; + }; +} diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..3aedb1e --- /dev/null +++ b/init.lua @@ -0,0 +1 @@ +require 'TheAltF4Stream'.init() diff --git a/justfile b/justfile new file mode 100644 index 0000000..fa0676e --- /dev/null +++ b/justfile @@ -0,0 +1,2 @@ +build profile="default": + nix build --json --no-link --print-build-logs ".#{{ profile }}" diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..d31c641 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,125 @@ +{ inputs }: + +rec { + mkNvimConfig = { system }: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + in + pkgs.vimUtils.buildVimPlugin { + name = "TheAltF4Stream"; + postInstall = '' + rm -rf $out/.envrc + rm -rf $out/.gitignore + rm -rf $out/LICENSE + rm -rf $out/README.md + rm -rf $out/flake.lock + rm -rf $out/flake.nix + rm -rf $out/justfile + rm -rf $out/lib + ''; + src = ../.; + }; + + mkNvimPlugins = { system }: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + thealtf4stream-nvim = mkNvimConfig { inherit system; }; + in + with pkgs; [ + # languages + vimPlugins.nvim-lspconfig + vimPlugins.nvim-treesitter.withAllGrammars + vimPlugins.rust-tools-nvim + vimPlugins.vim-just + + # telescope + vimPlugins.plenary-nvim + vimPlugins.telescope-nvim + + # theme + vimPlugins.oxocarbon-nvim + + # floaterm + vimPlugins.vim-floaterm + + # extras + vimPlugins.ChatGPT-nvim + vimPlugins.copilot-lua + vimPlugins.gitsigns-nvim + vimPlugins.lualine-nvim + vimPlugins.nerdcommenter + vimPlugins.nui-nvim + vimPlugins.nvim-colorizer-lua + vimPlugins.nvim-notify + vimPlugins.nvim-treesitter-context + vimPlugins.nvim-web-devicons + vimPlugins.omnisharp-extended-lsp-nvim + vimPlugins.rainbow-delimiters-nvim + + # configuration + thealtf4stream-nvim + ]; + + mkNvimRuntimeInputs = { system }: + let + pkgs = (import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + }); + in + with pkgs; [ + # language servers + cuelsp + gopls + haskell-language-server + jsonnet-language-server + lua-language-server + nil + nodePackages."bash-language-server" + nodePackages."diagnostic-languageserver" + nodePackages."dockerfile-language-server-nodejs" + nodePackages."pyright" + nodePackages."typescript" + nodePackages."typescript-language-server" + nodePackages."vscode-langservers-extracted" + nodePackages."yaml-language-server" + ocaml-ng.ocamlPackages_5_1.ocaml-lsp + ocaml-ng.ocamlPackages_5_1.ocamlformat + omnisharp-roslyn + rust-analyzer + terraform-ls + + # formatters + nixpkgs-fmt + gofumpt + golines + python310Packages.black + rustfmt + terraform + ]; + + mkNvim = { system }: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + in + pkgs.neovim.override { + configure = { + customRC = '' + lua << EOF + require 'TheAltF4Stream'.init() + EOF + ''; + packages.main = + let + plugins = mkNvimPlugins { inherit system; }; + in + { + start = plugins; + }; + }; + + withNodeJs = true; + withPython3 = true; + withRuby = true; + }; +} diff --git a/lib/preview.webp b/lib/preview.webp new file mode 100644 index 0000000..b860e37 Binary files /dev/null and b/lib/preview.webp differ diff --git a/lua/.luarc.json b/lua/.luarc.json new file mode 100644 index 0000000..23b9ee2 --- /dev/null +++ b/lua/.luarc.json @@ -0,0 +1,3 @@ +{ + "workspace.checkThirdParty": false +} \ No newline at end of file diff --git a/lua/TheAltF4Stream/chatgpt.lua b/lua/TheAltF4Stream/chatgpt.lua new file mode 100644 index 0000000..5cc1978 --- /dev/null +++ b/lua/TheAltF4Stream/chatgpt.lua @@ -0,0 +1,27 @@ +local chatgpt = require 'chatgpt' + +local function init() + local api_key_cmd = "doppler secrets get OPENAI_API_KEY --plain" + local model = "gpt-3.5-turbo" + local edit_model = "code-davinci-edit-001" + + chatgpt.setup({ + api_key_cmd = api_key_cmd, + openai_params = { model = model }, + openai_edit_params = { model = edit_model } + }) + + local map = vim.api.nvim_set_keymap + local options = { noremap = true } + + map('n', 'ga', 'ChatGPTActAs', options) + map('n', 'gg', 'ChatGPT', options) + map('v', 'ge', 'ChatGPTEditWithInstructions', options) + map('v', 'go', 'ChatGPTRun optimize_code', options) + map('v', 'gs', 'ChatGPTRun summarize', options) + map('v', 'gt', 'ChatGPTRun add_tests', options) +end + +return { + init = init +} diff --git a/lua/TheAltF4Stream/floaterm.lua b/lua/TheAltF4Stream/floaterm.lua new file mode 100644 index 0000000..7dfa6e1 --- /dev/null +++ b/lua/TheAltF4Stream/floaterm.lua @@ -0,0 +1,16 @@ +local function init() + local map = vim.api.nvim_set_keymap + + local options = { noremap = true } + + map('n', 'bb', 'FloatermNew --autoclose=2 --height=0.9 --width=0.9 btm', options) + map('n', 'k9', 'FloatermNew --autoclose=2 --height=0.9 --width=0.9 k9s', options) + map('n', 'ld', 'FloatermNew --autoclose=2 --height=0.9 --width=0.9 lazydocker', options) + map('n', 'lg', 'FloatermNew --autoclose=2 --height=0.9 --width=0.9 lazygit', options) + map('n', 'nn', 'FloatermNew --autoclose=2 --height=0.75 --width=0.75 nnn -Hde', options) + map('n', 'tt', 'FloatermNew --autoclose=2 --height=0.9 --width=0.9 zsh', options) +end + +return { + init = init, +} diff --git a/lua/TheAltF4Stream/init.lua b/lua/TheAltF4Stream/init.lua new file mode 100644 index 0000000..b6348d2 --- /dev/null +++ b/lua/TheAltF4Stream/init.lua @@ -0,0 +1,12 @@ +local function init() + require 'TheAltF4Stream.vim'.init() + require 'TheAltF4Stream.theme'.init() + require 'TheAltF4Stream.languages'.init() + require 'TheAltF4Stream.chatgpt'.init() + require 'TheAltF4Stream.floaterm'.init() + require 'TheAltF4Stream.telescope'.init() +end + +return { + init = init, +} diff --git a/lua/TheAltF4Stream/languages.lua b/lua/TheAltF4Stream/languages.lua new file mode 100644 index 0000000..2640c48 --- /dev/null +++ b/lua/TheAltF4Stream/languages.lua @@ -0,0 +1,205 @@ +local copilot = require 'copilot' +local lspconfig = require 'lspconfig' +local omnisharp_extended = require 'omnisharp_extended' +local rust_tools = require 'rust-tools' +local treesitter = require 'nvim-treesitter.configs' +local treesitter_context = require 'treesitter-context' + +local function autocmd(args) + local event = args[1] + local group = args[2] + local callback = args[3] + + vim.api.nvim_create_autocmd(event, { + group = group, + buffer = args[4], + callback = function() + callback() + end, + once = args.once, + }) +end + +local function on_attach(client, buffer) + local augroup_highlight = vim.api.nvim_create_augroup("custom-lsp-references", { clear = true }) + local autocmd_clear = vim.api.nvim_clear_autocmds + + local opts = { buffer = buffer, remap = false } + + -- Enable completion triggered by + vim.bo[buffer].omnifunc = 'v:lua.vim.lsp.omnifunc' + + vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) + vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts) + vim.keymap.set('n', '', vim.lsp.buf.signature_help, opts) + vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, opts) + vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, opts) + vim.keymap.set('n', 'wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, opts) + vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, opts) + vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) + vim.keymap.set({ 'n', 'v' }, 'ca', vim.lsp.buf.code_action, opts) + vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) + vim.keymap.set('n', 'f', function() vim.lsp.buf.format { async = true } end, opts) + + if client.server_capabilities.documentHighlightProvider then + autocmd_clear { group = augroup_highlight, buffer = buffer } + autocmd { "CursorHold", augroup_highlight, vim.lsp.buf.document_highlight, buffer } + autocmd { "CursorMoved", augroup_highlight, vim.lsp.buf.clear_references, buffer } + end +end + +local function init() + -- Copilot setup + copilot.setup { + suggestion = { + auto_trigger = true, + } + } + + -- Rust specific setup + rust_tools.setup { + server = { + settings = { + ['rust-analyzer'] = { + cargo = { + buildScripts = { + enable = true, + }, + }, + diagnostics = { + enable = false, + }, + files = { + excludeDirs = { ".direnv", ".git" }, + watcherExclude = { ".direnv", ".git" }, + }, + }, + }, + on_attach = on_attach, + }, + } + + local language_servers = { + bashls = {}, + cssls = {}, + dagger = {}, + diagnosticls = { + filetypes = { "python" }, + init_options = { + filetypes = { + python = "black" + }, + formatFiletypes = { + python = { "black" } + }, + formatters = { + black = { + command = "black", + args = { "--quiet", "-" }, + rootPatterns = { "pyproject.toml" }, + }, + }, + } + }, + dockerls = {}, + gopls = { + settings = { + gopls = { + gofumpt = true, + }, + }, + }, + hls = {}, + html = {}, + jsonls = {}, + jsonnet_ls = {}, + lua_ls = { + settings = { + Lua = { + diagnostics = { + globals = { 'vim' } + }, + runtime = { + version = 'LuaJIT', + }, + telemetry = { + enable = false, + }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + }, + }, + } + }, + nil_ls = { + settings = { + ['nil'] = { + formatting = { command = { "nixpkgs-fmt" } }, + }, + } + }, + ocamllsp = {}, + omnisharp = { + cmd = { "omnisharp", "--languageserver", "--hostPID", tostring(vim.fn.getpid()) }, + handlers = { + ["textDocument/definition"] = omnisharp_extended.handler, + }, + }, + pyright = { + settings = { + python = { + analysis = { + autoSearchPaths = true, + diagnosticMode = "workspace", + useLibraryCodeForTypes = true + }, + }, + }, + }, + terraformls = {}, + tsserver = {}, + yamlls = { + settings = { + yaml = { + keyOrdering = false, + }, + }, + }, + } + + -- Initialize servers + for server, server_config in pairs(language_servers) do + local config = { on_attach = on_attach } + + if server_config then + for k, v in pairs(server_config) do + config[k] = v + end + end + + lspconfig[server].setup(config) + end + + -- Global mappings. + -- See `:help vim.diagnostic.*` for documentation on any of the below functions + vim.keymap.set('n', 'e', vim.diagnostic.open_float) + vim.keymap.set('n', '[d', vim.diagnostic.goto_prev) + vim.keymap.set('n', ']d', vim.diagnostic.goto_next) + vim.keymap.set('n', 'q', vim.diagnostic.setloclist) + + treesitter.setup { + highlight = { enable = true }, + indent = { enable = true }, + rainbow = { enable = true }, + } + + treesitter_context.setup() +end + +return { + init = init, +} diff --git a/lua/TheAltF4Stream/telescope.lua b/lua/TheAltF4Stream/telescope.lua new file mode 100644 index 0000000..db1c4db --- /dev/null +++ b/lua/TheAltF4Stream/telescope.lua @@ -0,0 +1,52 @@ +local telescope = require 'telescope' + +local function init() + telescope.setup { + defaults = { + file_ignore_patterns = { + "node_modules/.*", + "secret.d/.*", + "%.pem" + }, + layout_strategy = "flex", + layout_config = { + horizontal = { + prompt_position = "top", + preview_width = 0.55, + }, + vertical = { mirror = false }, + width = 0.87, + height = 0.8, + preview_cutoff = 120, + }, + } + } + + telescope.load_extension('notify') + + local map = vim.api.nvim_set_keymap + + local options = { noremap = true } + + -- Builtin + map('n', 'fg', 'lua require("telescope.builtin").git_files{}', options) + map('n', 'ff', 'lua require("telescope.builtin").find_files{ hidden = true }', options) + map('n', 'fl', 'lua require("telescope.builtin").live_grep()', options) + map('n', 'fb', 'lua require("telescope.builtin").buffers()', options) + map('n', 'fh', 'lua require("telescope.builtin").help_tags()', options) + map('n', 'fd', 'lua require("telescope.builtin").diagnostics()', options) + map('n', 'fr', 'lua require("telescope.builtin").registers()', options) + + -- Language Servers + map('n', 'lsd', 'lua require("telescope.builtin").lsp_definitions{}', options) + map('n', 'lsi', 'lua require("telescope.builtin").lsp_implementations{}', options) + map('n', 'lsl', 'lua require("telescope.builtin").lsp_code_actions{}', options) + map('n', 'lst', 'lua require("telescope.builtin").lsp_type_definitions{}', options) + + -- Extensions + map('n', 'fn', 'lua require("telescope").extensions.notify.notify()', options) +end + +return { + init = init, +} diff --git a/lua/TheAltF4Stream/theme.lua b/lua/TheAltF4Stream/theme.lua new file mode 100644 index 0000000..1150861 --- /dev/null +++ b/lua/TheAltF4Stream/theme.lua @@ -0,0 +1,44 @@ +local colorizer = require 'colorizer' +local gitsigns = require 'gitsigns' +local lualine = require 'lualine' +local oxocarbon = require('oxocarbon').oxocarbon + +local function init() + colorizer.setup {} + + gitsigns.setup {} + + lualine.setup { + options = { + component_separators = { left = '', right = '' }, + extensions = { "fzf", "quickfix" }, + icons_enabled = false, + section_separators = { left = '', right = '' }, + }, + } + + vim.opt.background = "dark" + vim.cmd.colorscheme "oxocarbon" + + --[[ Editor ]] + vim.api.nvim_set_hl(0, "Normal", { bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "NormalFloat", { bg = oxocarbon.none }) + + --[[ Telescope ]] + vim.api.nvim_set_hl(0, "TelescopeBorder", { fg = oxocarbon.base03, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopeMatching", + { fg = oxocarbon.base14, bg = oxocarbon.none, bold = true, italic = true }) + vim.api.nvim_set_hl(0, "TelescopeNormal", { fg = oxocarbon.none, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopePreviewLine", { fg = oxocarbon.none, bg = oxocarbon.base01 }) + vim.api.nvim_set_hl(0, "TelescopePreviewTitle", { fg = oxocarbon.base14, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopePromptBorder", { fg = oxocarbon.base03, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopePromptNormal", { fg = oxocarbon.base04, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopePromptPrefix", { fg = oxocarbon.base08, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopePromptTitle", { fg = oxocarbon.base14, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopeResultsTitle", { fg = oxocarbon.base14, bg = oxocarbon.none }) + vim.api.nvim_set_hl(0, "TelescopeSelection", { fg = oxocarbon.none, bg = oxocarbon.base02 }) +end + +return { + init = init, +} diff --git a/lua/TheAltF4Stream/vim.lua b/lua/TheAltF4Stream/vim.lua new file mode 100644 index 0000000..96ff8d9 --- /dev/null +++ b/lua/TheAltF4Stream/vim.lua @@ -0,0 +1,64 @@ +local function set_vim_g() + vim.g.mapleader = " " +end + +local function set_vim_o() + local settings = { + clipboard = 'unnamedplus', + colorcolumn = 80, + expandtab = true, + scrolloff = 3, + shiftwidth = 4, + shortmess = vim.o.shortmess .. 'c', + splitright = true, + tabstop = 4, + termguicolors = true, + updatetime = 300, + } + + for k, v in pairs(settings) do + vim.o[k] = v + end + + -- Not supported + vim.cmd("set colorcolumn=80") +end + +local function set_vim_wo() + local settings = { + number = true, + relativenumber = true, + wrap = false, + } + + for k, v in pairs(settings) do + vim.wo[k] = v + end +end + +local function set_vim_opt() + vim.opt.list = true + vim.opt.listchars:append "eol:↴" +end + +local function set_vim_keymaps() + local map = vim.api.nvim_set_keymap + local options = { noremap = false } + + map('n', 'h', 'wincmd h', options) + map('n', 'j', 'wincmd j', options) + map('n', 'k', 'wincmd k', options) + map('n', 'l', 'wincmd l', options) +end + +local function init() + set_vim_g() + set_vim_o() + set_vim_wo() + set_vim_opt() + set_vim_keymaps() +end + +return { + init = init, +}