├── ftdetect ├── plaintex.lua ├── zig.lua └── json.lua ├── .stylua.toml ├── lua └── lvim │ ├── lsp │ ├── providers │ │ ├── tailwindcss.lua │ │ ├── jsonls.lua │ │ ├── vuels.lua │ │ ├── yamlls.lua │ │ └── sumneko_lua.lua │ ├── null-ls │ │ ├── init.lua │ │ ├── code_actions.lua │ │ ├── formatters.lua │ │ ├── linters.lua │ │ └── services.lua │ ├── handlers.lua │ ├── templates.lua │ ├── init.lua │ └── config.lua │ ├── core │ ├── lualine │ │ ├── utils.lua │ │ ├── colors.lua │ │ ├── conditions.lua │ │ ├── init.lua │ │ └── styles.lua │ ├── builtins │ │ └── init.lua │ ├── indentlines.lua │ ├── alpha │ │ └── startify.lua │ ├── project.lua │ ├── illuminate.lua │ ├── comment.lua │ ├── gitsigns.lua │ ├── commands.lua │ ├── alpha.lua │ ├── mason.lua │ ├── telescope │ │ └── custom-finders.lua │ ├── lir.lua │ ├── theme.lua │ └── autopairs.lua │ ├── utils │ ├── functions.lua │ ├── table.lua │ ├── modules.lua │ ├── hooks.lua │ └── git.lua │ ├── config │ ├── defaults.lua │ ├── _deprecated.lua │ ├── init.lua │ └── settings.lua │ ├── interface │ ├── popup.lua │ └── text.lua │ ├── utils.lua │ ├── icons.lua │ └── bootstrap.lua ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature-form.yaml │ ├── general-issue-form.yaml │ └── lsp-issue-form.yaml ├── workflows │ ├── changelog.yml │ ├── close-inactive-bot.yml │ ├── lint.yaml │ ├── commitlint.yml │ ├── format.yaml │ ├── commitlint.config.js │ ├── plugins.yml │ ├── install.yaml │ └── cliff.toml └── pull_request_template.md ├── .luarc.json ├── utils ├── ci │ ├── verify_plugins.sh │ ├── run_commitlint.sh │ ├── update_changelog.sh │ ├── generate_new_lockfile.sh │ ├── run_test.sh │ ├── generate_new_lockfile.lua │ └── verify_plugins.lua ├── bin │ ├── lvim.template │ ├── lvim.ps1 │ └── jdtls ├── desktop │ ├── lvim.desktop │ ├── 16x16 │ │ └── lvim.svg │ ├── 48x48 │ │ └── lvim.svg │ ├── 22x22 │ │ └── lvim.svg │ ├── 64x64 │ │ └── lvim.svg │ ├── 24x24 │ │ └── lvim.svg │ └── 32x32 │ │ └── lvim.svg ├── docker │ ├── Dockerfile.local │ └── Dockerfile.remote └── installer │ ├── install_bin.sh │ ├── install_stylua.sh │ ├── uninstall.ps1 │ ├── uninstall.sh │ └── install-neovim-from-release ├── tests ├── minimal_init.lua ├── lvim │ └── helpers.lua ├── specs │ ├── bootstrap_spec.lua │ ├── config_loader_spec.lua │ ├── plugins_load_spec.lua │ └── lsp_spec.lua └── minimal_lsp.lua ├── .gitignore ├── init.lua ├── .pre-commit-config.yaml ├── .luacheckrc ├── Makefile ├── snapshots └── default.json ├── ftplugin └── lua.lua ├── README.md └── CONTRIBUTING.md /ftdetect/plaintex.lua: -------------------------------------------------------------------------------- 1 | vim.cmd [[ au BufRead,BufNewFile *.tex set filetype=tex ]] 2 | -------------------------------------------------------------------------------- /ftdetect/zig.lua: -------------------------------------------------------------------------------- 1 | vim.cmd [[ 2 | au BufRead,BufNewFile *.zir set filetype=zir 3 | ]] 4 | -------------------------------------------------------------------------------- /ftdetect/json.lua: -------------------------------------------------------------------------------- 1 | vim.cmd [[ 2 | au BufRead,BufNewFile tsconfig.json set filetype=jsonc 3 | ]] 4 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 120 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferDouble" 6 | no_call_parentheses = true 7 | -------------------------------------------------------------------------------- /lua/lvim/lsp/providers/tailwindcss.lua: -------------------------------------------------------------------------------- 1 | local opts = { 2 | root_dir = function(fname) 3 | local util = require "lspconfig/util" 4 | return util.root_pattern("tailwind.config.js", "tailwind.config.cjs", "tailwind.js", "tailwind.cjs")(fname) 5 | end, 6 | } 7 | 8 | return opts 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: christianchiarulli 4 | patreon: chrisatmachine 5 | ko_fi: chrisatmachine 6 | custom: ["https://www.buymeacoffee.com/chrisatmachine", "https://www.paypal.com/paypalme/chrisatmachine", "https://strike.me/chrisatmachine"] 7 | -------------------------------------------------------------------------------- /.luarc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", 3 | "Lua.diagnostics.disable": [ 4 | "redundant-parameter", 5 | "param-type-mismatch", 6 | "missing-parameter" 7 | ], 8 | "diagnostics.libraryFiles": "Disable" 9 | } 10 | -------------------------------------------------------------------------------- /lua/lvim/core/lualine/utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.env_cleanup(venv) 4 | if string.find(venv, "/") then 5 | local final_venv = venv 6 | for w in venv:gmatch "([^/]+)" do 7 | final_venv = w 8 | end 9 | venv = final_venv 10 | end 11 | return venv 12 | end 13 | 14 | return M 15 | -------------------------------------------------------------------------------- /utils/ci/verify_plugins.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | BASEDIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" 5 | BASEDIR="$(dirname -- "$(dirname -- "$BASEDIR")")" 6 | 7 | LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-"$BASEDIR"}" 8 | 9 | lvim --headless \ 10 | -c "luafile ${LUNARVIM_BASE_DIR}/utils/ci/verify_plugins.lua" 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | 3 | contact_links: 4 | - name: Matrix community 5 | url: https://matrix.to/#/#atmachine-neovim:matrix.org 6 | about: Ask and discuss about LunarVim on Matrix. 7 | - name: Discord community 8 | url: https://discord.com/invite/sbDcEmJHww 9 | about: Ask and discuss about LunarVim on Discord. 10 | -------------------------------------------------------------------------------- /lua/lvim/core/lualine/colors.lua: -------------------------------------------------------------------------------- 1 | local colors = { 2 | bg = "#202328", 3 | fg = "#bbc2cf", 4 | yellow = "#ECBE7B", 5 | cyan = "#008080", 6 | darkblue = "#081633", 7 | green = "#98be65", 8 | orange = "#FF8800", 9 | violet = "#a9a1e1", 10 | magenta = "#c678dd", 11 | purple = "#c678dd", 12 | blue = "#51afef", 13 | red = "#ec5f67", 14 | } 15 | 16 | return colors 17 | -------------------------------------------------------------------------------- /utils/ci/run_commitlint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | REPO_DIR="$(git rev-parse --show-toplevel)" 5 | HELP_URL="https://github.com/LunarVim/LunarVim/blob/rolling/CONTRIBUTING.md#commit-messages" 6 | CONFIG="$REPO_DIR/.github/workflows/commitlint.config.js" 7 | 8 | if ! npx commitlint --edit --verbose --help-url "$HELP_URL" --config "$CONFIG"; then 9 | exit 1 10 | fi 11 | -------------------------------------------------------------------------------- /utils/bin/lvim.template: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-RUNTIME_DIR_VAR}" 4 | export LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-CONFIG_DIR_VAR}" 5 | export LUNARVIM_CACHE_DIR="${LUNARVIM_CACHE_DIR:-CACHE_DIR_VAR}" 6 | 7 | export LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-BASE_DIR_VAR}" 8 | 9 | exec -a lvim nvim -u "$LUNARVIM_BASE_DIR/init.lua" "$@" 10 | -------------------------------------------------------------------------------- /lua/lvim/lsp/providers/jsonls.lua: -------------------------------------------------------------------------------- 1 | local opts = { 2 | settings = { 3 | json = { 4 | schemas = require("schemastore").json.schemas(), 5 | }, 6 | }, 7 | setup = { 8 | commands = { 9 | Format = { 10 | function() 11 | vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 }) 12 | end, 13 | }, 14 | }, 15 | }, 16 | } 17 | 18 | return opts 19 | -------------------------------------------------------------------------------- /lua/lvim/lsp/null-ls/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | 5 | function M.setup() 6 | local status_ok, null_ls = pcall(require, "null-ls") 7 | if not status_ok then 8 | Log:error "Missing null-ls dependency" 9 | return 10 | end 11 | 12 | local default_opts = require("lvim.lsp").get_common_opts() 13 | null_ls.setup(vim.tbl_deep_extend("force", default_opts, lvim.lsp.null_ls.setup)) 14 | end 15 | 16 | return M 17 | -------------------------------------------------------------------------------- /tests/minimal_init.lua: -------------------------------------------------------------------------------- 1 | local path_sep = vim.loop.os_uname().version:match "Windows" and "\\" or "/" 2 | local base_dir = vim.env.LUNARVIM_BASE_DIR 3 | local tests_dir = base_dir .. path_sep .. "tests" 4 | 5 | vim.opt.rtp:append(tests_dir) 6 | vim.opt.rtp:append(base_dir) 7 | 8 | require("lvim.bootstrap"):init(base_dir) 9 | 10 | -- NOTE: careful about name collisions 11 | -- see https://github.com/nvim-lualine/lualine.nvim/pull/621 12 | require "tests.lvim.helpers" 13 | -------------------------------------------------------------------------------- /utils/ci/update_changelog.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | BRANCH="$(git rev-parse --abbrev-ref HEAD)" 5 | 6 | if [ "$BRANCH" != "master" ]; then 7 | exit 0 8 | fi 9 | 10 | REPO_DIR="$(git rev-parse --show-toplevel)" 11 | LATEST_TAG="$(git describe --tags --abbrev=0)" 12 | CONFIG_FILE="$REPO_DIR/.github/workflows/cliff.toml" 13 | CHANGELOG="$REPO_DIR/CHANGELOG.md" 14 | 15 | git -C "$REPO_DIR" cliff "$LATEST_TAG"..HEAD -u -c "$CONFIG_FILE" -p "$CHANGELOG" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dein 2 | tags* 3 | .netrwhist 4 | pythonpath.vim 5 | nodepath.vim 6 | autoload/plugged/* 7 | vimspector-config/gadgets/* 8 | paths.vim 9 | session 10 | wiki/ 11 | pack/ 12 | utils/java/* 13 | lv-config.lua 14 | lua-language-server/ 15 | eclipse.jdt.ls/ 16 | .language-servers/ 17 | .debuggers/ 18 | spell/ 19 | nv-settings.lua 20 | lv-settings.lua 21 | lua/lv-user/ 22 | lua/lv-user-config/ 23 | 24 | *.tmp 25 | *.temp 26 | *.bak 27 | *.backup 28 | *.old 29 | 30 | .luarc.json 31 | .luacheckcache 32 | -------------------------------------------------------------------------------- /utils/ci/generate_new_lockfile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | REPO_DIR=$(git rev-parse --show-toplevel) 5 | 6 | export SNAPSHOT_NAME="default.json" 7 | export SNAPSHOT_DIR="${REPO_DIR}/snapshots" 8 | 9 | mkdir -p "${SNAPSHOT_DIR}" 10 | 11 | export SNAPSHOT_PATH="${REPO_DIR}/snapshots/${SNAPSHOT_NAME}" 12 | 13 | time lvim --headless \ 14 | -c "luafile ./utils/ci/generate_new_lockfile.lua" 15 | 16 | temp=$(mktemp) 17 | 18 | jq --sort-keys . "${SNAPSHOT_PATH}" >"${temp}" 19 | mv "${temp}" "${SNAPSHOT_PATH}" 20 | -------------------------------------------------------------------------------- /utils/desktop/lvim.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=LunarVim 3 | GenericName=Text Editor 4 | Comment=An IDE layer for Neovim with sane defaults. Completely free and community driven. 5 | TryExec=lvim 6 | Exec=lvim %F 7 | Terminal=true 8 | Type=Application 9 | Keywords=Text;editor; 10 | Icon=lvim 11 | Categories=Utility;TextEditor; 12 | StartupNotify=false 13 | MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; 14 | -------------------------------------------------------------------------------- /lua/lvim/core/lualine/conditions.lua: -------------------------------------------------------------------------------- 1 | local window_width_limit = 100 2 | 3 | local conditions = { 4 | buffer_not_empty = function() 5 | return vim.fn.empty(vim.fn.expand "%:t") ~= 1 6 | end, 7 | hide_in_width = function() 8 | return vim.o.columns > window_width_limit 9 | end, 10 | -- check_git_workspace = function() 11 | -- local filepath = vim.fn.expand "%:p:h" 12 | -- local gitdir = vim.fn.finddir(".git", filepath .. ";") 13 | -- return gitdir and #gitdir > 0 and #gitdir < #filepath 14 | -- end, 15 | } 16 | 17 | return conditions 18 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: changelog 2 | on: release 3 | 4 | jobs: 5 | changelog-gen: 6 | name: Generate changelog 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | with: 12 | fetch-depth: 0 13 | 14 | - uses: orhun/git-cliff-action@v1 15 | with: 16 | config: cliff.toml 17 | args: -vv --latest --strip header -c .github/workflows/cliff.toml 18 | env: 19 | OUTPUT: CHANGELOG.md 20 | 21 | - name: Print the changelog 22 | run: cat "${{ steps.git-cliff.outputs.changelog }}" 23 | -------------------------------------------------------------------------------- /utils/bin/lvim.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 7.1 2 | $ErrorActionPreference = "Stop" # exit when command fails 3 | 4 | $env:XDG_DATA_HOME = $env:XDG_DATA_HOME ?? $env:APPDATA 5 | $env:XDG_CONFIG_HOME = $env:XDG_CONFIG_HOME ?? $env:LOCALAPPDATA 6 | $env:XDG_CACHE_HOME = $env:XDG_CACHE_HOME ?? $env:TEMP 7 | 8 | $env:LUNARVIM_RUNTIME_DIR = $env:LUNARVIM_RUNTIME_DIR ?? "$env:XDG_DATA_HOME\lunarvim" 9 | $env:LUNARVIM_CONFIG_DIR = $env:LUNARVIM_CONFIG_DIR ?? "$env:XDG_CONFIG_HOME\lvim" 10 | $env:LUNARVIM_CACHE_DIR = $env:LUNARVIM_CACHE_DIR ?? "$env:XDG_CACHE_HOME\lvim" 11 | $env:LUNARVIM_BASE_DIR = $env:LUNARVIM_BASE_DIR ?? "$env:LUNARVIM_RUNTIME_DIR\lvim" 12 | 13 | nvim -u "$env:LUNARVIM_BASE_DIR\init.lua" @args 14 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | local base_dir = vim.env.LUNARVIM_BASE_DIR 2 | or (function() 3 | local init_path = debug.getinfo(1, "S").source 4 | return init_path:sub(2):match("(.*[/\\])"):sub(1, -2) 5 | end)() 6 | 7 | if not vim.tbl_contains(vim.opt.rtp:get(), base_dir) then 8 | vim.opt.rtp:append(base_dir) 9 | end 10 | 11 | require("lvim.bootstrap"):init(base_dir) 12 | 13 | require("lvim.config"):load() 14 | 15 | local plugins = require "lvim.plugins" 16 | 17 | require("lvim.plugin-loader").load { plugins, lvim.plugins } 18 | 19 | require("lvim.core.theme").setup() 20 | 21 | local Log = require "lvim.core.log" 22 | Log:debug "Starting LunarVim" 23 | 24 | local commands = require "lvim.core.commands" 25 | commands.load(commands.defaults) 26 | 27 | require("lvim.lsp").setup() 28 | -------------------------------------------------------------------------------- /lua/lvim/lsp/providers/vuels.lua: -------------------------------------------------------------------------------- 1 | local opts = { 2 | setup = { 3 | root_dir = function(fname) 4 | local util = require "lvim.lspconfig/util" 5 | return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd() 6 | end, 7 | init_options = { 8 | config = { 9 | vetur = { 10 | completion = { 11 | autoImport = true, 12 | tagCasing = "kebab", 13 | useScaffoldSnippets = true, 14 | }, 15 | useWorkspaceDependencies = true, 16 | validation = { 17 | script = true, 18 | style = true, 19 | template = true, 20 | }, 21 | }, 22 | }, 23 | }, 24 | }, 25 | } 26 | return opts 27 | -------------------------------------------------------------------------------- /lua/lvim/lsp/null-ls/code_actions.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | 5 | local null_ls = require "null-ls" 6 | local services = require "lvim.lsp.null-ls.services" 7 | local method = null_ls.methods.CODE_ACTION 8 | 9 | function M.list_registered(filetype) 10 | local registered_providers = services.list_registered_providers_names(filetype) 11 | return registered_providers[method] or {} 12 | end 13 | 14 | function M.setup(actions_configs) 15 | if vim.tbl_isempty(actions_configs) then 16 | return 17 | end 18 | 19 | local registered = services.register_sources(actions_configs, method) 20 | 21 | if #registered > 0 then 22 | Log:debug("Registered the following action-handlers: " .. unpack(registered)) 23 | end 24 | end 25 | 26 | return M 27 | -------------------------------------------------------------------------------- /lua/lvim/utils/functions.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.smart_quit() 4 | local bufnr = vim.api.nvim_get_current_buf() 5 | local modified = vim.api.nvim_buf_get_option(bufnr, "modified") 6 | if modified then 7 | vim.ui.input({ 8 | prompt = "You have unsaved changes. Quit anyway? (y/n) ", 9 | }, function(input) 10 | if input == "y" then 11 | vim.cmd "q!" 12 | end 13 | end) 14 | else 15 | vim.cmd "q!" 16 | end 17 | end 18 | 19 | function M.isempty(s) 20 | return s == nil or s == "" 21 | end 22 | 23 | function M.get_buf_option(opt) 24 | local status_ok, buf_option = pcall(vim.api.nvim_buf_get_option, 0, opt) 25 | if not status_ok then 26 | return nil 27 | else 28 | return buf_option 29 | end 30 | end 31 | 32 | return M 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-form.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for improving this project 3 | labels: [enhancement] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for helping us improve! 9 | 10 | - type: textarea 11 | id: motivation 12 | attributes: 13 | label: Feature Description 14 | placeholder: What is the expected behavior of this new feature? 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: alternatives 19 | attributes: 20 | label: Describe the alternatives you have considered 21 | - type: textarea 22 | id: additional-context 23 | attributes: 24 | label: Support information 25 | description: If applicable, add screenshots or link related issues 26 | -------------------------------------------------------------------------------- /lua/lvim/lsp/handlers.lua: -------------------------------------------------------------------------------- 1 | -- Set Default Prefix. 2 | -- Note: You can set a prefix per lsp server in the lv-globals.lua file 3 | local M = {} 4 | 5 | function M.setup() 6 | local config = { -- your config 7 | virtual_text = lvim.lsp.diagnostics.virtual_text, 8 | signs = lvim.lsp.diagnostics.signs, 9 | underline = lvim.lsp.diagnostics.underline, 10 | update_in_insert = lvim.lsp.diagnostics.update_in_insert, 11 | severity_sort = lvim.lsp.diagnostics.severity_sort, 12 | float = lvim.lsp.diagnostics.float, 13 | } 14 | vim.diagnostic.config(config) 15 | vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, lvim.lsp.float) 16 | vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, lvim.lsp.float) 17 | end 18 | 19 | return M 20 | -------------------------------------------------------------------------------- /.github/workflows/close-inactive-bot.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v5 14 | with: 15 | days-before-issue-stale: 30 16 | days-before-issue-close: 14 17 | stale-issue-label: 'stale' 18 | stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.' 19 | close-issue-message: 'This issue was closed because it has been inactive for 14 days since being marked as stale.' 20 | days-before-pr-stale: -1 21 | days-before-pr-close: -1 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /lua/lvim/lsp/providers/yamlls.lua: -------------------------------------------------------------------------------- 1 | local opts = { 2 | settings = { 3 | yaml = { 4 | hover = true, 5 | completion = true, 6 | validate = true, 7 | schemaStore = { 8 | enable = true, 9 | url = "https://www.schemastore.org/api/json/catalog.json", 10 | }, 11 | schemas = { 12 | kubernetes = { 13 | "daemon.{yml,yaml}", 14 | "manager.{yml,yaml}", 15 | "restapi.{yml,yaml}", 16 | "role.{yml,yaml}", 17 | "role_binding.{yml,yaml}", 18 | "*onfigma*.{yml,yaml}", 19 | "*ngres*.{yml,yaml}", 20 | "*ecre*.{yml,yaml}", 21 | "*eployment*.{yml,yaml}", 22 | "*ervic*.{yml,yaml}", 23 | "kubectl-edit*.yaml", 24 | }, 25 | }, 26 | }, 27 | }, 28 | } 29 | 30 | return opts 31 | -------------------------------------------------------------------------------- /lua/lvim/utils/table.lua: -------------------------------------------------------------------------------- 1 | local Table = {} 2 | 3 | --- Find the first entry for which the predicate returns true. 4 | -- @param t The table 5 | -- @param predicate The function called for each entry of t 6 | -- @return The entry for which the predicate returned True or nil 7 | function Table.find_first(t, predicate) 8 | for _, entry in pairs(t) do 9 | if predicate(entry) then 10 | return entry 11 | end 12 | end 13 | return nil 14 | end 15 | 16 | --- Check if the predicate returns True for at least one entry of the table. 17 | -- @param t The table 18 | -- @param predicate The function called for each entry of t 19 | -- @return True if predicate returned True at least once, false otherwise 20 | function Table.contains(t, predicate) 21 | return Table.find_first(t, predicate) ~= nil 22 | end 23 | 24 | return Table 25 | -------------------------------------------------------------------------------- /lua/lvim/core/builtins/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local builtins = { 4 | "lvim.core.theme", 5 | "lvim.core.which-key", 6 | "lvim.core.gitsigns", 7 | "lvim.core.cmp", 8 | "lvim.core.dap", 9 | "lvim.core.terminal", 10 | "lvim.core.telescope", 11 | "lvim.core.treesitter", 12 | "lvim.core.nvimtree", 13 | "lvim.core.lir", 14 | "lvim.core.illuminate", 15 | "lvim.core.indentlines", 16 | "lvim.core.breadcrumbs", 17 | "lvim.core.project", 18 | "lvim.core.bufferline", 19 | "lvim.core.autopairs", 20 | "lvim.core.comment", 21 | "lvim.core.lualine", 22 | "lvim.core.alpha", 23 | "lvim.core.mason", 24 | } 25 | 26 | function M.config(config) 27 | for _, builtin_path in ipairs(builtins) do 28 | local builtin = reload(builtin_path) 29 | 30 | builtin.config(config) 31 | end 32 | end 33 | 34 | return M 35 | -------------------------------------------------------------------------------- /utils/ci/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | export LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$HOME/.local/share/lunarvim"}" 5 | export LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-"$LUNARVIM_RUNTIME_DIR/lvim"}" 6 | 7 | export LVIM_TEST_ENV=true 8 | 9 | # we should start with an empty configuration 10 | LUNARVIM_CONFIG_DIR="$(mktemp -d)" 11 | LUNARVIM_CACHE_DIR="$(mktemp -d)" 12 | 13 | export LUNARVIM_CONFIG_DIR LUNARVIM_CACHE_DIR 14 | 15 | printf "cache_dir: %s\nconfig_dir: %s\n" "$LUNARVIM_CACHE_DIR" "$LUNARVIM_CONFIG_DIR" 16 | 17 | lvim() { 18 | nvim -u "$LUNARVIM_BASE_DIR/tests/minimal_init.lua" --cmd "set runtimepath+=$LUNARVIM_BASE_DIR" "$@" 19 | } 20 | 21 | if [ -n "$1" ]; then 22 | lvim --headless -c "lua require('plenary.busted').run('$1')" 23 | else 24 | lvim --headless -c "PlenaryBustedDirectory tests/specs { minimal_init = './tests/minimal_init.lua' }" 25 | fi 26 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "rolling" 7 | paths: 8 | - 'lua/**' 9 | - 'snapshots/**' 10 | - 'tests/**' 11 | - 'utils/**' 12 | 13 | jobs: 14 | lua-linter: 15 | name: "Linting with luacheck" 16 | runs-on: ubuntu-20.04 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: leafo/gh-actions-lua@v8 21 | - uses: leafo/gh-actions-luarocks@v4 22 | 23 | - name: Use luacheck 24 | run: luarocks install luacheck 25 | 26 | - name: Run luacheck 27 | run: make lint-lua 28 | 29 | shellcheck: 30 | name: Shellcheck 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v3 34 | - name: Run ShellCheck 35 | uses: ludeeus/action-shellcheck@master 36 | with: 37 | scandir: "./utils" 38 | ignore: "bin" 39 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: shfmt 5 | name: shfmt 6 | minimum_pre_commit_version: 2.4.0 7 | language: system 8 | types: [shell] 9 | entry: bash 10 | args: [-c, make lint-sh] 11 | - id: shellcheck 12 | name: shellcheck 13 | language: system 14 | types: [shell] 15 | entry: bash 16 | args: [-c, make style-sh] 17 | - id: stylua 18 | name: StyLua 19 | language: rust 20 | entry: stylua 21 | types: [lua] 22 | args: ["-"] 23 | - id: luacheck 24 | name: luacheck 25 | language: system 26 | entry: luacheck 27 | types: [lua] 28 | args: [.] 29 | - id: commitlint 30 | name: commitlint 31 | language: system 32 | entry: bash 33 | args: [./utils/ci/run_commitlint.sh] 34 | stages: [commit-msg] 35 | -------------------------------------------------------------------------------- /utils/docker/Dockerfile.local: -------------------------------------------------------------------------------- 1 | # To run this file execute: 2 | # docker build -f -t Lunarvim:local 3 | 4 | FROM ubuntu:latest 5 | 6 | # Set environment correctly 7 | ENV DEBIAN_FRONTEND=noninteractive 8 | ENV PATH="/root/.local/bin:/root/.cargo/bin:/root/.npm-global/bin${PATH}" 9 | 10 | # Copy in local directory 11 | COPY --chown=root:root . /LunarVim 12 | 13 | # Install dependencies and LunarVim 14 | RUN apt update && \ 15 | apt -y install sudo curl build-essential git fzf python3-dev python3-pip cargo && \ 16 | curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \ 17 | apt update && \ 18 | apt -y install nodejs && \ 19 | apt clean && rm -rf /var/lib/apt/lists/* /tmp/* && \ 20 | /LunarVim/utils/installer/install-neovim-from-release && \ 21 | /LunarVim/utils/installer/install.sh --local --no-install-dependencies 22 | 23 | # Setup LVIM to run on startup 24 | ENTRYPOINT ["/bin/bash"] 25 | CMD ["lvim"] 26 | 27 | # vim: ft=dockerfile: 28 | -------------------------------------------------------------------------------- /lua/lvim/lsp/null-ls/formatters.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | 5 | local null_ls = require "null-ls" 6 | local services = require "lvim.lsp.null-ls.services" 7 | local method = null_ls.methods.FORMATTING 8 | 9 | function M.list_registered(filetype) 10 | local registered_providers = services.list_registered_providers_names(filetype) 11 | return registered_providers[method] or {} 12 | end 13 | 14 | function M.list_supported(filetype) 15 | local s = require "null-ls.sources" 16 | local supported_formatters = s.get_supported(filetype, "formatting") 17 | table.sort(supported_formatters) 18 | return supported_formatters 19 | end 20 | 21 | function M.setup(formatter_configs) 22 | if vim.tbl_isempty(formatter_configs) then 23 | return 24 | end 25 | 26 | local registered = services.register_sources(formatter_configs, method) 27 | 28 | if #registered > 0 then 29 | Log:debug("Registered the following formatters: " .. unpack(registered)) 30 | end 31 | end 32 | 33 | return M 34 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable 2 | -- vim: ft=lua tw=80 3 | 4 | stds.nvim = { 5 | globals = { 6 | "lvim", 7 | "reload", 8 | vim = { fields = { "g" } }, 9 | "TERMINAL", 10 | "USER", 11 | "C", 12 | "Config", 13 | "WORKSPACE_PATH", 14 | "JAVA_LS_EXECUTABLE", 15 | "MUtils", 16 | "USER_CONFIG_PATH", 17 | os = { fields = { "capture" } }, 18 | }, 19 | read_globals = { 20 | "jit", 21 | "os", 22 | "vim", 23 | "join_paths", 24 | "get_runtime_dir", 25 | "get_config_dir", 26 | "get_cache_dir", 27 | "get_lvim_base_dir", 28 | "require_clean", 29 | }, 30 | } 31 | std = "lua51+nvim" 32 | 33 | files["tests/*_spec.lua"].std = "lua51+nvim+busted" 34 | files["lua/lvim/impatient*"].ignore = {"121"} 35 | 36 | -- Don't report unused self arguments of methods. 37 | self = false 38 | 39 | -- Rerun tests only if their modification time changed. 40 | cache = true 41 | 42 | ignore = { 43 | "631", -- max_line_length 44 | "212/_.*", -- unused argument, for vars with "_" prefix 45 | } 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /usr/bin/env bash 2 | 3 | install: 4 | @echo starting LunarVim installer 5 | bash ./utils/installer/install.sh 6 | 7 | install-bin: 8 | @echo starting LunarVim bin-installer 9 | bash ./utils/installer/install_bin.sh 10 | 11 | install-neovim-binary: 12 | @echo installing Neovim from github releases 13 | bash ./utils/installer/install-neovim-from-release 14 | 15 | uninstall: 16 | @echo starting LunarVim uninstaller 17 | bash ./utils/installer/uninstall.sh 18 | 19 | generate_new_lockfile: 20 | @echo generating core-plugins latest lockfile 21 | bash ./utils/ci/generate_new_lockfile.sh 22 | 23 | lint: lint-lua lint-sh 24 | 25 | lint-lua: 26 | luacheck *.lua lua/* tests/* 27 | 28 | lint-sh: 29 | shfmt -f . | grep -v jdtls | xargs shellcheck 30 | 31 | style: style-lua style-sh 32 | 33 | style-lua: 34 | stylua --config-path .stylua.toml --check . 35 | 36 | style-sh: 37 | shfmt -f . | grep -v jdtls | xargs shfmt -i 2 -ci -bn -l -d 38 | 39 | test: 40 | bash ./utils/ci/run_test.sh "$(TEST)" 41 | 42 | .PHONY: install install-neovim-binary uninstall lint style test 43 | -------------------------------------------------------------------------------- /lua/lvim/core/indentlines.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.config = function() 4 | lvim.builtin.indentlines = { 5 | active = true, 6 | on_config_done = nil, 7 | options = { 8 | enabled = true, 9 | buftype_exclude = { "terminal", "nofile" }, 10 | filetype_exclude = { 11 | "help", 12 | "startify", 13 | "dashboard", 14 | "packer", 15 | "neogitstatus", 16 | "NvimTree", 17 | "Trouble", 18 | "text", 19 | }, 20 | char = lvim.icons.ui.LineLeft, 21 | show_trailing_blankline_indent = false, 22 | show_first_indent_level = true, 23 | use_treesitter = false, 24 | show_current_context = false, 25 | }, 26 | } 27 | end 28 | 29 | M.setup = function() 30 | local status_ok, indent_blankline = pcall(reload, "indent_blankline") 31 | if not status_ok then 32 | return 33 | end 34 | 35 | indent_blankline.setup(lvim.builtin.indentlines.options) 36 | 37 | if lvim.builtin.indentlines.on_config_done then 38 | lvim.builtin.indentlines.on_config_done() 39 | end 40 | end 41 | 42 | return M 43 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: "Commit Linter" 2 | on: 3 | pull_request: # By default, a workflow only runs when a pull_request event's activity type is opened, synchronize, or reopened. 4 | types: 5 | - opened 6 | - edited 7 | - synchronize 8 | - reopened 9 | jobs: 10 | lint-pr-title: 11 | runs-on: ubuntu-latest 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | HELP_URL: "https://github.com/LunarVim/LunarVim/blob/rolling/CONTRIBUTING.md#commit-messages" 15 | COMMITLINT_CONFIG: ${{ format('{0}/.github/workflows/commitlint.config.js', github.workspace) }} 16 | GH_REPO: ${{ github.repository }} 17 | PR_NUMBER: ${{ github.event.pull_request.number }} 18 | PR_TITLE: ${{ github.event.pull_request.title }} 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: install commitlint 22 | run: | 23 | npm install --save-dev @commitlint/cli 24 | - name: run commitlint 25 | run: | 26 | echo "$PR_TITLE" | npx commitlint --verbose --help-url "$HELP_URL" --config "$COMMITLINT_CONFIG" 27 | -------------------------------------------------------------------------------- /lua/lvim/core/alpha/startify.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.get_sections() 4 | local header = { 5 | type = "text", 6 | val = { 7 | [[ __ _ ___ ]], 8 | [[ / / __ ______ ____ _____| | / (_)___ ___ ]], 9 | [[ / / / / / / __ \/ __ `/ ___/ | / / / __ `__ \]], 10 | [[ / /___/ /_/ / / / / /_/ / / | |/ / / / / / / /]], 11 | [[/_____/\__,_/_/ /_/\__,_/_/ |___/_/_/ /_/ /_/ ]], 12 | }, 13 | opts = { 14 | hl = "Label", 15 | shrink_margin = false, 16 | -- wrap = "overflow"; 17 | }, 18 | } 19 | 20 | local top_buttons = { 21 | entries = { 22 | { "e", lvim.icons.ui.NewFile .. " New File", "ene!" }, 23 | }, 24 | } 25 | 26 | local bottom_buttons = { 27 | entries = { 28 | { "q", "Quit", "quit" }, 29 | }, 30 | } 31 | 32 | local footer = { 33 | type = "group", 34 | } 35 | 36 | return { 37 | header = header, 38 | top_buttons = top_buttons, 39 | bottom_buttons = bottom_buttons, 40 | -- this is probably broken 41 | footer = footer, 42 | } 43 | end 44 | 45 | return M 46 | -------------------------------------------------------------------------------- /.github/workflows/format.yaml: -------------------------------------------------------------------------------- 1 | name: format 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "rolling" 7 | paths: 8 | - 'lua/**' 9 | - 'snapshots/**' 10 | - 'tests/**' 11 | - 'utils/**' 12 | 13 | jobs: 14 | stylua-check: 15 | name: "Formatting check with Stylua" 16 | runs-on: ubuntu-20.04 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - name: Lint with stylua 21 | uses: JohnnyMorganz/stylua-action@v1 22 | with: 23 | token: ${{ secrets.GITHUB_TOKEN }} 24 | # CLI arguments 25 | version: 0.15.1 26 | args: --check . 27 | 28 | shfmt-check: 29 | name: "Formatting check with shfmt" 30 | runs-on: ubuntu-20.04 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - name: Setup Go 35 | uses: actions/setup-go@v2 36 | with: 37 | go-version: "1.16" 38 | 39 | - name: Use shfmt 40 | run: | 41 | GO111MODULE=on go get mvdan.cc/sh/v3/cmd/shfmt 42 | 43 | # https://google.github.io/styleguide/shellguide.html 44 | - name: Check formatting 45 | run: make style-sh 46 | -------------------------------------------------------------------------------- /utils/docker/Dockerfile.remote: -------------------------------------------------------------------------------- 1 | # To run this file execute: 2 | # docker build -f Dockerfile.remote . -t Lunarvim:remote 3 | 4 | FROM ubuntu:latest 5 | 6 | # Build argument to point to correct branch on GitHub 7 | ARG LV_BRANCH=release-1.2/neovim-0.8 8 | 9 | # Set environment correctly 10 | ENV DEBIAN_FRONTEND=noninteractive 11 | ENV PATH="/root/.local/bin:/root/.cargo/bin:/root/.npm-global/bin${PATH}" 12 | 13 | # Install dependencies and LunarVim 14 | RUN apt update && \ 15 | apt -y install sudo curl build-essential git fzf python3-dev python3-pip cargo && \ 16 | curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \ 17 | apt update && \ 18 | apt -y install nodejs && \ 19 | apt clean && rm -rf /var/lib/apt/lists/* /tmp/* && \ 20 | curl -LSs https://raw.githubusercontent.com/lunarvim/lunarvim/${LV_BRANCH}/utils/installer/install-neovim-from-release | bash && \ 21 | LV_BRANCH=${LV_BRANCH} curl -LSs https://raw.githubusercontent.com/lunarvim/lunarvim/${LV_BRANCH}/utils/installer/install.sh | bash -s -- --no-install-dependencies 22 | 23 | # Setup LVIM to run on startup 24 | ENTRYPOINT ["/bin/bash"] 25 | CMD ["lvim"] 26 | 27 | # vim: ft=dockerfile: 28 | -------------------------------------------------------------------------------- /tests/lvim/helpers.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.search_file(file, args) 4 | local Job = require "plenary.job" 5 | local stderr = {} 6 | local stdout, ret = Job:new({ 7 | command = "grep", 8 | args = { args, file }, 9 | cwd = get_cache_dir(), 10 | on_stderr = function(_, data) 11 | table.insert(stderr, data) 12 | end, 13 | }):sync() 14 | return ret, stdout, stderr 15 | end 16 | 17 | function M.file_contains(file, query) 18 | local ret, stdout, stderr = M.search_file(file, query) 19 | if ret == 0 then 20 | return true 21 | end 22 | if not vim.tbl_isempty(stderr) then 23 | error(vim.inspect(stderr)) 24 | end 25 | if not vim.tbl_isempty(stdout) then 26 | error(vim.inspect(stdout)) 27 | end 28 | return false 29 | end 30 | 31 | function M.log_contains(query) 32 | local logfile = require("lvim.core.log"):get_path() 33 | local ret, stdout, stderr = M.search_file(logfile, query) 34 | if ret == 0 then 35 | return true 36 | end 37 | if not vim.tbl_isempty(stderr) then 38 | error(vim.inspect(stderr)) 39 | end 40 | if not vim.tbl_isempty(stdout) then 41 | error(vim.inspect(stdout)) 42 | end 43 | return false 44 | end 45 | 46 | return M 47 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 18 | # Description 19 | 20 | summary of the change 21 | 22 | 23 | 24 | fixes #(issue) 25 | 26 | ## How Has This Been Tested? 27 | 28 | 29 | 30 | 31 | - Run command `:mycommand` 32 | - Check logs 33 | - ... 34 | 35 | -------------------------------------------------------------------------------- /lua/lvim/lsp/null-ls/linters.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | 5 | local null_ls = require "null-ls" 6 | local services = require "lvim.lsp.null-ls.services" 7 | local method = null_ls.methods.DIAGNOSTICS 8 | 9 | local alternative_methods = { 10 | null_ls.methods.DIAGNOSTICS, 11 | null_ls.methods.DIAGNOSTICS_ON_OPEN, 12 | null_ls.methods.DIAGNOSTICS_ON_SAVE, 13 | } 14 | 15 | function M.list_registered(filetype) 16 | local registered_providers = services.list_registered_providers_names(filetype) 17 | local providers_for_methods = vim.tbl_flatten(vim.tbl_map(function(m) 18 | return registered_providers[m] or {} 19 | end, alternative_methods)) 20 | 21 | return providers_for_methods 22 | end 23 | 24 | function M.list_supported(filetype) 25 | local s = require "null-ls.sources" 26 | local supported_linters = s.get_supported(filetype, "diagnostics") 27 | table.sort(supported_linters) 28 | return supported_linters 29 | end 30 | 31 | function M.setup(linter_configs) 32 | if vim.tbl_isempty(linter_configs) then 33 | return 34 | end 35 | 36 | local registered = services.register_sources(linter_configs, method) 37 | 38 | if #registered > 0 then 39 | Log:debug("Registered the following linters: " .. unpack(registered)) 40 | end 41 | end 42 | 43 | return M 44 | -------------------------------------------------------------------------------- /utils/installer/install_bin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | INSTALL_PREFIX="${INSTALL_PREFIX:-"$HOME/.local"}" 5 | 6 | XDG_DATA_HOME="${XDG_DATA_HOME:-"$HOME/.local/share"}" 7 | XDG_CACHE_HOME="${XDG_CACHE_HOME:-"$HOME/.cache"}" 8 | XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-"$HOME/.config"}" 9 | 10 | LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$XDG_DATA_HOME/lunarvim"}" 11 | LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$XDG_CONFIG_HOME/lvim"}" 12 | LUNARVIM_CACHE_DIR="${LUNARVIM_CACHE_DIR:-"$XDG_CACHE_HOME/lvim"}" 13 | 14 | LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-"$LUNARVIM_RUNTIME_DIR/lvim"}" 15 | 16 | function setup_shim() { 17 | local src="$LUNARVIM_BASE_DIR/utils/bin/lvim.template" 18 | local dst="$INSTALL_PREFIX/bin/lvim" 19 | 20 | [ ! -d "$INSTALL_PREFIX/bin" ] && mkdir -p "$INSTALL_PREFIX/bin" 21 | 22 | # remove outdated installation so that `cp` doesn't complain 23 | rm -f "$dst" 24 | 25 | cp "$src" "$dst" 26 | 27 | sed -e s"#RUNTIME_DIR_VAR#\"${LUNARVIM_RUNTIME_DIR}\"#"g \ 28 | -e s"#CONFIG_DIR_VAR#\"${LUNARVIM_CONFIG_DIR}\"#"g \ 29 | -e s"#CACHE_DIR_VAR#\"${LUNARVIM_CACHE_DIR}\"#"g \ 30 | -e s"#BASE_DIR_VAR#\"${LUNARVIM_BASE_DIR}\"#"g "$src" \ 31 | | tee "$dst" >/dev/null 32 | 33 | chmod u+x "$dst" 34 | } 35 | 36 | setup_shim "$@" 37 | 38 | echo "You can start LunarVim by running: $INSTALL_PREFIX/bin/lvim" 39 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | "body-leading-blank": [1, "always"], 4 | "body-max-line-length": [2, "always", 100], 5 | "footer-leading-blank": [1, "always"], 6 | "footer-max-line-length": [2, "always", 100], 7 | "header-max-length": [2, "always", 72], 8 | "scope-case": [2, "always", "lower-case"], 9 | "subject-case": [ 10 | 2, 11 | "never", 12 | ["upper-case", "pascal-case", "sentence-case", "start-case"], 13 | ], 14 | "subject-empty": [2, "never"], 15 | "subject-full-stop": [2, "never", "."], 16 | "type-case": [2, "always", "lower-case"], 17 | "type-empty": [2, "never"], 18 | "type-enum": [ 19 | 2, 20 | "always", 21 | [ 22 | "build", 23 | "chore", 24 | "ci", 25 | "docs", 26 | "feat", 27 | "fix", 28 | "perf", 29 | "refactor", 30 | "revert", 31 | "test", 32 | ], 33 | ], 34 | }, 35 | /* 36 | add a custom parser to handle exclamation marks in a commit 37 | see: https://github.com/conventional-changelog/commitlint/issues/2226#issuecomment-911749509 38 | */ 39 | parserPreset: { 40 | parserOpts: { 41 | headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/, 42 | referenceActions: null, 43 | issuePrefixes: ['ISS-'], 44 | }, 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /lua/lvim/config/defaults.lua: -------------------------------------------------------------------------------- 1 | return { 2 | leader = "space", 3 | reload_config_on_save = true, 4 | colorscheme = "lunar", 5 | transparent_window = false, 6 | format_on_save = { 7 | ---@usage boolean: format on save (Default: false) 8 | enabled = false, 9 | ---@usage pattern string pattern used for the autocommand (Default: '*') 10 | pattern = "*", 11 | ---@usage timeout number timeout in ms for the format request (Default: 1000) 12 | timeout = 1000, 13 | ---@usage filter func to select client 14 | filter = require("lvim.lsp.utils").format_filter, 15 | }, 16 | keys = {}, 17 | 18 | use_icons = true, 19 | icons = require "lvim.icons", 20 | 21 | builtin = {}, 22 | 23 | plugins = { 24 | -- use config.lua for this not put here 25 | }, 26 | 27 | autocommands = {}, 28 | lang = {}, 29 | log = { 30 | ---@usage can be { "trace", "debug", "info", "warn", "error", "fatal" }, 31 | level = "info", 32 | viewer = { 33 | ---@usage this will fallback on "less +F" if not found 34 | cmd = "lnav", 35 | layout_config = { 36 | ---@usage direction = 'vertical' | 'horizontal' | 'window' | 'float', 37 | direction = "horizontal", 38 | open_mapping = "", 39 | size = 40, 40 | float_opts = {}, 41 | }, 42 | }, 43 | -- currently disabled due to instabilities 44 | override_notify = false, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /lua/lvim/core/lualine/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | M.config = function() 3 | lvim.builtin.lualine = { 4 | active = true, 5 | style = "lvim", 6 | options = { 7 | icons_enabled = nil, 8 | component_separators = nil, 9 | section_separators = nil, 10 | theme = nil, 11 | disabled_filetypes = nil, 12 | globalstatus = true, 13 | }, 14 | sections = { 15 | lualine_a = nil, 16 | lualine_b = nil, 17 | lualine_c = nil, 18 | lualine_x = nil, 19 | lualine_y = nil, 20 | lualine_z = nil, 21 | }, 22 | inactive_sections = { 23 | lualine_a = nil, 24 | lualine_b = nil, 25 | lualine_c = nil, 26 | lualine_x = nil, 27 | lualine_y = nil, 28 | lualine_z = nil, 29 | }, 30 | tabline = nil, 31 | extensions = nil, 32 | on_config_done = nil, 33 | } 34 | end 35 | 36 | M.setup = function() 37 | if #vim.api.nvim_list_uis() == 0 then 38 | local Log = require "lvim.core.log" 39 | Log:debug "headless mode detected, skipping running setup for lualine" 40 | return 41 | end 42 | 43 | local status_ok, lualine = pcall(require, "lualine") 44 | if not status_ok then 45 | return 46 | end 47 | 48 | require("lvim.core.lualine.styles").update() 49 | 50 | lualine.setup(lvim.builtin.lualine) 51 | 52 | if lvim.builtin.lualine.on_config_done then 53 | lvim.builtin.lualine.on_config_done(lualine) 54 | end 55 | end 56 | 57 | return M 58 | -------------------------------------------------------------------------------- /tests/specs/bootstrap_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require "plenary.async_lib.tests" 2 | local uv = vim.loop 3 | local home_dir = uv.os_homedir() 4 | 5 | a.describe("initial start", function() 6 | local lvim_config_path = get_config_dir() 7 | local lvim_runtime_path = get_runtime_dir() 8 | local lvim_cache_path = get_cache_dir() 9 | 10 | a.it("should be able to detect test environment", function() 11 | assert.truthy(os.getenv "LVIM_TEST_ENV") 12 | assert.falsy(package.loaded["lvim.impatient"]) 13 | end) 14 | 15 | a.it("should be able to use lunarvim cache directory using vim.fn", function() 16 | assert.equal(lvim_cache_path, vim.fn.stdpath "cache") 17 | end) 18 | 19 | a.it("should be to retrieve default neovim directories", function() 20 | local xdg_config = os.getenv "XDG_CONFIG_HOME" or join_paths(home_dir, ".config") 21 | assert.equal(join_paths(xdg_config, "nvim"), vim.call("stdpath", "config")) 22 | end) 23 | 24 | a.it("should be able to read lunarvim directories", function() 25 | local rtp_list = vim.opt.rtp:get() 26 | assert.truthy(vim.tbl_contains(rtp_list, lvim_runtime_path .. "/lvim")) 27 | assert.truthy(vim.tbl_contains(rtp_list, lvim_config_path)) 28 | end) 29 | 30 | a.it("should be able to run treesitter without errors", function() 31 | assert.truthy(vim.treesitter.highlighter.active) 32 | end) 33 | 34 | a.it("should be able to pass basic checkhealth without errors", function() 35 | vim.cmd "set cmdheight&" 36 | vim.cmd "checkhealth nvim" 37 | local errmsg = vim.fn.eval "v:errmsg" 38 | local exception = vim.fn.eval "v:exception" 39 | assert.equal("", errmsg) -- v:errmsg was not updated. 40 | assert.equal("", exception) 41 | end) 42 | end) 43 | -------------------------------------------------------------------------------- /utils/installer/install_stylua.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu pipefall 4 | 5 | declare -r INSTALL_DIR="$PWD/utils" 6 | declare -r RELEASE="0.10.0" 7 | declare -r OS="linux" 8 | # declare -r OS="$(uname -s)" 9 | declare -r FILENAME="stylua-$RELEASE-$OS" 10 | 11 | declare -a __deps=("curl" "unzip") 12 | 13 | function check_deps() { 14 | for dep in "${__deps[@]}"; do 15 | if ! command -v "$dep" >/dev/null; then 16 | echo "Missing depdendecy!" 17 | echo "The \"$dep\" command was not found!. Please install and try again." 18 | fi 19 | done 20 | } 21 | 22 | function download_stylua() { 23 | local DOWNLOAD_DIR 24 | local URL="https://github.com/JohnnyMorganz/StyLua/releases/download/v$RELEASE/$FILENAME.zip" 25 | 26 | DOWNLOAD_DIR="$(mktemp -d)" 27 | echo "Initiating download for Stylua v$RELEASE" 28 | if ! curl --progress-bar --fail -L "$URL" -o "$DOWNLOAD_DIR/$FILENAME.zip"; then 29 | echo "Download failed. Check that the release/filename are correct." 30 | exit 1 31 | fi 32 | 33 | echo "Installation in progress.." 34 | unzip -q "$DOWNLOAD_DIR/$FILENAME.zip" -d "$DOWNLOAD_DIR" 35 | 36 | if [ -f "$DOWNLOAD_DIR/stylua" ]; then 37 | mv "$DOWNLOAD_DIR/stylua" "$INSTALL_DIR/stylua" 38 | else 39 | mv "$DOWNLOAD_DIR/$FILENAME/stylua" "$INSTALL_DIR/." 40 | fi 41 | 42 | chmod u+x "$INSTALL_DIR/stylua" 43 | } 44 | 45 | function verify_install() { 46 | echo "Verifying installation.." 47 | local DOWNLOADED_VER 48 | DOWNLOADED_VER="$("$INSTALL_DIR/stylua" -V | awk '{ print $2 }')" 49 | if [ "$DOWNLOADED_VER" != "$RELEASE" ]; then 50 | echo "Mismatched version!" 51 | echo "Expected: v$RELEASE but got v$DOWNLOADED_VER" 52 | exit 1 53 | fi 54 | echo "Verification complete!" 55 | } 56 | 57 | function main() { 58 | check_deps 59 | download_stylua 60 | verify_install 61 | } 62 | 63 | main "$@" 64 | -------------------------------------------------------------------------------- /lua/lvim/lsp/providers/sumneko_lua.lua: -------------------------------------------------------------------------------- 1 | local default_workspace = { 2 | library = { 3 | vim.fn.expand "$VIMRUNTIME", 4 | get_lvim_base_dir(), 5 | require("neodev.config").types(), 6 | "${3rd}/busted/library", 7 | "${3rd}/luassert/library", 8 | }, 9 | 10 | maxPreload = 5000, 11 | preloadFileSize = 10000, 12 | } 13 | 14 | local add_packages_to_workspace = function(packages, config) 15 | -- config.settings.Lua = config.settings.Lua or { workspace = default_workspace } 16 | local runtimedirs = vim.api.nvim__get_runtime({ "lua" }, true, { is_lua = true }) 17 | local workspace = config.settings.Lua.workspace 18 | for _, v in pairs(runtimedirs) do 19 | for _, pack in ipairs(packages) do 20 | if v:match(pack) and not vim.tbl_contains(workspace.library, v) then 21 | table.insert(workspace.library, v) 22 | end 23 | end 24 | end 25 | end 26 | 27 | local lspconfig = require "lspconfig" 28 | 29 | local make_on_new_config = function(on_new_config, _) 30 | return lspconfig.util.add_hook_before(on_new_config, function(new_config, _) 31 | local server_name = new_config.name 32 | 33 | if server_name ~= "sumneko_lua" then 34 | return 35 | end 36 | local plugins = { "plenary.nvim", "telescope.nvim", "nvim-treesitter", "LuaSnip" } 37 | add_packages_to_workspace(plugins, new_config) 38 | end) 39 | end 40 | 41 | lspconfig.util.default_config = vim.tbl_extend("force", lspconfig.util.default_config, { 42 | on_new_config = make_on_new_config(lspconfig.util.default_config.on_new_config), 43 | }) 44 | 45 | local opts = { 46 | settings = { 47 | Lua = { 48 | telemetry = { enable = false }, 49 | runtime = { 50 | version = "LuaJIT", 51 | special = { 52 | reload = "require", 53 | }, 54 | }, 55 | diagnostics = { 56 | globals = { "vim", "lvim", "packer_plugins", "reload" }, 57 | }, 58 | workspace = default_workspace, 59 | }, 60 | }, 61 | } 62 | 63 | return opts 64 | -------------------------------------------------------------------------------- /.github/workflows/plugins.yml: -------------------------------------------------------------------------------- 1 | name: plugins-version-bump 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | logLevel: 7 | description: 'Log level' 8 | required: false 9 | default: 'warning' 10 | type: choice 11 | options: 12 | - info 13 | - warning 14 | - debug 15 | schedule: 16 | # note: this will keep updating the existing branch 17 | - cron: "*/15 10-14 * * 0,6" 18 | - cron: "0 14 * * 1-5" 19 | 20 | jobs: 21 | plugins-version-bump: 22 | runs-on: ubuntu-latest 23 | continue-on-error: false 24 | permissions: 25 | contents: write 26 | pull-requests: write 27 | steps: 28 | - uses: actions/checkout@v3 29 | 30 | - name: Install neovim binary 31 | uses: rhysd/action-setup-vim@v1 32 | with: 33 | neovim: true 34 | version: nightly 35 | 36 | - name: Install LunarVim 37 | timeout-minutes: 4 38 | run: | 39 | ./utils/installer/install.sh --local --no-install-dependencies 40 | 41 | - name: run upgrade script 42 | run: make generate_new_lockfile 43 | 44 | - name: Re-install LunarVim 45 | timeout-minutes: 4 46 | run: | 47 | ./utils/installer/uninstall.sh --remove-backups 48 | ./utils/installer/install.sh --local --no-install-dependencies 49 | 50 | - name: Run unit-tests 51 | # NOTE: make sure to adjust the timeout if you start adding a lot of tests 52 | timeout-minutes: 4 53 | run: make test 54 | 55 | - name: Create Pull Request 56 | uses: peter-evans/create-pull-request@v4 57 | with: 58 | branch: plugins-bump 59 | delete-branch: true # Delete the branch when closing pull requests, and when undeleted after merging. 60 | token: ${{ secrets.GITHUB_TOKEN }} 61 | author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 62 | title: "chore: bump plugins version" 63 | commit-message: "chore: bump plugins version" 64 | -------------------------------------------------------------------------------- /tests/specs/config_loader_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require "plenary.async_lib.tests" 2 | local config = require "lvim.config" 3 | local fmt = string.format 4 | 5 | a.describe("config-loader", function() 6 | local user_config_path = join_paths(get_config_dir(), "config.lua") 7 | local default_config_path = join_paths(get_lvim_base_dir(), "utils", "installer", "config.example.lua") 8 | 9 | before_each(function() 10 | os.execute(fmt("cp -f %s %s", default_config_path, user_config_path)) 11 | vim.cmd [[ 12 | let v:errmsg = "" 13 | let v:errors = [] 14 | ]] 15 | end) 16 | 17 | after_each(function() 18 | local errmsg = vim.fn.eval "v:errmsg" 19 | local exception = vim.fn.eval "v:exception" 20 | local errors = vim.fn.eval "v:errors" 21 | assert.equal("", errmsg) 22 | assert.equal("", exception) 23 | assert.True(vim.tbl_isempty(errors)) 24 | end) 25 | 26 | a.it("should be able to find user-config", function() 27 | assert.equal(user_config_path, get_config_dir() .. "/config.lua") 28 | end) 29 | 30 | a.it("should be able to load user-config without errors", function() 31 | config:load(user_config_path) 32 | end) 33 | 34 | a.it("should be able to reload user-config without errors", function() 35 | config:load(user_config_path) 36 | local test_path = "/tmp/lvim" 37 | os.execute(string.format([[echo "vim.opt.undodir = '%s'" >> %s]], test_path, user_config_path)) 38 | config:reload() 39 | vim.schedule(function() 40 | assert.equal(vim.opt.undodir:get()[1], test_path) 41 | end) 42 | end) 43 | 44 | a.it("should not get interrupted by errors in user-config", function() 45 | local test_path = "/tmp/lunarvim" 46 | os.execute(string.format([[echo "vim.opt.undodir = '%s'" >> %s]], test_path, user_config_path)) 47 | config:load(user_config_path) 48 | assert.equal(vim.opt.undodir:get()[1], test_path) 49 | require("lvim.core.log"):set_level "error" 50 | os.execute(string.format("echo 'invalid_function()' >> %s", user_config_path)) 51 | config:load(user_config_path) 52 | require("lvim.core.log"):set_level "error" 53 | assert.equal(vim.opt.undodir:get()[1], test_path) 54 | end) 55 | end) 56 | -------------------------------------------------------------------------------- /lua/lvim/core/project.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.config() 4 | lvim.builtin.project = { 5 | ---@usage set to false to disable project.nvim. 6 | --- This is on by default since it's currently the expected behavior. 7 | active = true, 8 | 9 | on_config_done = nil, 10 | 11 | ---@usage set to true to disable setting the current-woriking directory 12 | --- Manual mode doesn't automatically change your root directory, so you have 13 | --- the option to manually do so using `:ProjectRoot` command. 14 | manual_mode = false, 15 | 16 | ---@usage Methods of detecting the root directory 17 | --- Allowed values: **"lsp"** uses the native neovim lsp 18 | --- **"pattern"** uses vim-rooter like glob pattern matching. Here 19 | --- order matters: if one is not detected, the other is used as fallback. You 20 | --- can also delete or rearangne the detection methods. 21 | -- detection_methods = { "lsp", "pattern" }, -- NOTE: lsp detection will get annoying with multiple langs in one project 22 | detection_methods = { "pattern" }, 23 | 24 | ---@usage patterns used to detect root dir, when **"pattern"** is in detection_methods 25 | patterns = { ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json", "pom.xml" }, 26 | 27 | ---@ Show hidden files in telescope when searching for files in a project 28 | show_hidden = false, 29 | 30 | ---@usage When set to false, you will get a message when project.nvim changes your directory. 31 | -- When set to false, you will get a message when project.nvim changes your directory. 32 | silent_chdir = true, 33 | 34 | ---@usage list of lsp client names to ignore when using **lsp** detection. eg: { "efm", ... } 35 | ignore_lsp = {}, 36 | 37 | ---@type string 38 | ---@usage path to store the project history for use in telescope 39 | datapath = get_cache_dir(), 40 | } 41 | end 42 | 43 | function M.setup() 44 | local status_ok, project = pcall(require, "project_nvim") 45 | if not status_ok then 46 | return 47 | end 48 | 49 | project.setup(lvim.builtin.project) 50 | if lvim.builtin.project.on_config_done then 51 | lvim.builtin.project.on_config_done(project) 52 | end 53 | end 54 | 55 | return M 56 | -------------------------------------------------------------------------------- /utils/installer/uninstall.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 7.1 2 | $ErrorActionPreference = "Stop" # exit when command fails 3 | 4 | # set script variables 5 | $LV_BRANCH = $LV_BRANCH ?? "master" 6 | $LV_REMOTE = $LV_REMOTE ?? "lunarvim/lunarvim.git" 7 | $INSTALL_PREFIX = $INSTALL_PREFIX ?? "$HOME\.local" 8 | 9 | $env:XDG_DATA_HOME = $env:XDG_DATA_HOME ?? $env:APPDATA 10 | $env:XDG_CONFIG_HOME = $env:XDG_CONFIG_HOME ?? $env:LOCALAPPDATA 11 | $env:XDG_CACHE_HOME = $env:XDG_CACHE_HOME ?? $env:TEMP 12 | 13 | $env:LUNARVIM_RUNTIME_DIR = $env:LUNARVIM_RUNTIME_DIR ?? "$env:XDG_DATA_HOME\lunarvim" 14 | $env:LUNARVIM_CONFIG_DIR = $env:LUNARVIM_CONFIG_DIR ?? "$env:XDG_CONFIG_HOME\lvim" 15 | $env:LUNARVIM_CACHE_DIR = $env:LUNARVIM_CACHE_DIR ?? "$env:XDG_CACHE_HOME\lvim" 16 | $env:LUNARVIM_BASE_DIR = $env:LUNARVIM_BASE_DIR ?? "$env:LUNARVIM_RUNTIME_DIR\lvim" 17 | 18 | $__lvim_dirs = ( 19 | $env:LUNARVIM_BASE_DIR, 20 | $env:LUNARVIM_RUNTIME_DIR, 21 | $env:LUNARVIM_CONFIG_DIR, 22 | $env:LUNARVIM_CACHE_DIR 23 | ) 24 | 25 | function main($cliargs) { 26 | Write-Output "Removing LunarVim binary..." 27 | remove_lvim_bin 28 | Write-Output "Removing LunarVim directories..." 29 | $force = $false 30 | if ($cliargs.Contains("--remove-backups")) { 31 | $force = $true 32 | } 33 | remove_lvim_dirs $force 34 | Write-Output "Uninstalled LunarVim!" 35 | } 36 | 37 | function remove_lvim_bin(){ 38 | $lvim_bin="$INSTALL_PREFIX\bin\lvim" 39 | if (Test-Path $lvim_bin) { 40 | Remove-Item -Force $lvim_bin 41 | } 42 | if (Test-Path alias:lvim) { 43 | Write-Warning "Please make sure to remove the 'lvim' alias from your `$PROFILE`: $PROFILE" 44 | } 45 | } 46 | 47 | function remove_lvim_dirs($force) { 48 | foreach ($dir in $__lvim_dirs) { 49 | if (Test-Path $dir) { 50 | Remove-Item -Force -Recurse $dir 51 | } 52 | if ($force -eq $true) { 53 | if (Test-Path "$dir.bak") { 54 | Remove-Item -Force -Recurse "$dir.bak" 55 | } 56 | if (Test-Path "$dir.old") { 57 | Remove-Item -Force -Recurse "$dir.old" 58 | } 59 | } 60 | } 61 | } 62 | 63 | main($args) 64 | -------------------------------------------------------------------------------- /lua/lvim/interface/popup.lua: -------------------------------------------------------------------------------- 1 | local Popup = {} 2 | 3 | --- Create a new floating window 4 | -- @param config The configuration passed to vim.api.nvim_open_win 5 | -- @param win_opts The options registered with vim.api.nvim_win_set_option 6 | -- @param buf_opts The options registered with vim.api.nvim_buf_set_option 7 | -- @return A new popup 8 | function Popup:new(opts) 9 | opts = opts or {} 10 | opts.layout = opts.layout or {} 11 | opts.win_opts = opts.win_opts or {} 12 | opts.buf_opts = opts.buf_opts or {} 13 | 14 | Popup.__index = Popup 15 | 16 | local editor_layout = { 17 | height = vim.o.lines - vim.o.cmdheight - 2, -- Add margin for status and buffer line 18 | width = vim.o.columns, 19 | } 20 | local popup_layout = { 21 | relative = "editor", 22 | height = math.floor(editor_layout.height * 0.9), 23 | width = math.floor(editor_layout.width * 0.8), 24 | style = "minimal", 25 | border = "rounded", 26 | } 27 | popup_layout.row = math.floor((editor_layout.height - popup_layout.height) / 2) 28 | popup_layout.col = math.floor((editor_layout.width - popup_layout.width) / 2) 29 | 30 | local obj = { 31 | buffer = vim.api.nvim_create_buf(false, true), 32 | layout = vim.tbl_deep_extend("force", popup_layout, opts.layout), 33 | win_opts = opts.win_opts, 34 | buf_opts = opts.buf_opts, 35 | } 36 | 37 | setmetatable(obj, Popup) 38 | 39 | return obj 40 | end 41 | 42 | --- Display the popup with the provided content 43 | -- @param content_provider A function accepting the popup's layout and returning the content to display 44 | function Popup:display(content_provider) 45 | self.win_id = vim.api.nvim_open_win(self.buffer, true, self.layout) 46 | vim.api.nvim_command( 47 | string.format("autocmd BufHidden,BufLeave ++once lua pcall(vim.api.nvim_win_close, %d, true)", self.win_id) 48 | ) 49 | 50 | local lines = content_provider(self.layout) 51 | vim.api.nvim_buf_set_lines(self.bufnr or 0, 0, -1, false, lines) 52 | 53 | -- window options 54 | for key, value in pairs(self.win_opts) do 55 | vim.api.nvim_win_set_option(self.win_id or 0, key, value) 56 | end 57 | 58 | -- buffer options 59 | for key, value in pairs(self.buf_opts) do 60 | vim.api.nvim_buf_set_option(self.buffer, key, value) 61 | end 62 | end 63 | 64 | return Popup 65 | -------------------------------------------------------------------------------- /utils/bin/jdtls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # NOTE: 4 | # This doesn't work as is on Windows. You'll need to create an equivalent `.bat` file instead 5 | # 6 | # NOTE: 7 | # If you're not using Linux you'll need to adjust the `-configuration` option 8 | # to point to the `config_mac' or `config_win` folders depending on your system. 9 | 10 | case Darwin in 11 | Linux) 12 | CONFIG="$HOME/.local/share/nvim/lsp_servers/jdtls/config_linux" 13 | ;; 14 | Darwin) 15 | CONFIG="$HOME/.local/share/nvim/lsp_servers/jdtls/config_mac" 16 | ;; 17 | esac 18 | 19 | # Determine the Java command to use to start the JVM. 20 | if [ -n "$JAVA_HOME" ]; then 21 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 22 | # IBM's JDK on AIX uses strange locations for the executables 23 | JAVACMD="$JAVA_HOME/jre/sh/java" 24 | else 25 | JAVACMD="$JAVA_HOME/bin/java" 26 | fi 27 | if [ ! -x "$JAVACMD" ]; then 28 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 29 | 30 | Please set the JAVA_HOME variable in your environment to match the 31 | location of your Java installation." 32 | fi 33 | else 34 | JAVACMD="java" 35 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 36 | 37 | Please set the JAVA_HOME variable in your environment to match the 38 | location of your Java installation." 39 | fi 40 | 41 | # JAR="$HOME/.config/nvim/.language-servers/eclipse.jdt.ls/org.eclipse.jdt.ls.product/target/repository/plugins/org.eclipse.equinox.launcher_*.jar" 42 | JAR="$HOME/.local/share/nvim/lsp_servers/jdtls/plugins/org.eclipse.equinox.launcher_*.jar" 43 | GRADLE_HOME=$HOME/gradle "$JAVACMD" \ 44 | -Declipse.application=org.eclipse.jdt.ls.core.id1 \ 45 | -Dosgi.bundles.defaultStartLevel=4 \ 46 | -Declipse.product=org.eclipse.jdt.ls.core.product \ 47 | -Dlog.protocol=true \ 48 | -Dlog.level=ALL \ 49 | -javaagent:$HOME/.local/share/nvim/lsp_servers/jdtls/lombok.jar \ 50 | -Xms1g \ 51 | -Xmx2G \ 52 | -jar $(echo "$JAR") \ 53 | -configuration "$CONFIG" \ 54 | -data "${1:-$HOME/workspace}" \ 55 | --add-modules=ALL-SYSTEM \ 56 | --add-opens java.base/java.util=ALL-UNNAMED \ 57 | --add-opens java.base/java.lang=ALL-UNNAMED 58 | 59 | # for older java versions if you wanna use lombok 60 | # -Xbootclasspath/a:/usr/local/share/lombok/lombok.jar \ 61 | 62 | # -javaagent:/usr/local/share/lombok/lombok.jar \ 63 | -------------------------------------------------------------------------------- /utils/desktop/16x16/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-issue-form.yaml: -------------------------------------------------------------------------------- 1 | name: General Issue 2 | description: File a bug report 3 | labels: [bug] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | _Before reporting:_ search [existing issues](https://github.com/lunarvim/lunarvim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [Troubleshooting guide](https://www.lunarvim.org/troubleshooting). 10 | If you need real-time help, join us on Discord. Thank you for helping us improve! 11 | 12 | - type: textarea 13 | id: problem-description 14 | attributes: 15 | label: Problem description 16 | description: Also tell us, what did you expect to happen? 17 | placeholder: | 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | validations: 24 | required: true 25 | - type: input 26 | id: version 27 | attributes: 28 | label: LunarVim version 29 | placeholder: | 30 | output of :LvimVersion 31 | validations: 32 | required: true 33 | - type: input 34 | id: nvim-version 35 | attributes: 36 | label: Neovim version (>= 0.8.0) 37 | description: "Output of `nvim --version`" 38 | placeholder: | 39 | NVIM v0.8.0-dev+199-g2875d45e7 40 | validations: 41 | required: true 42 | - type: input 43 | id: system-version 44 | attributes: 45 | label: "Operating system/version" 46 | placeholder: "macOS 11.5" 47 | validations: 48 | required: true 49 | - type: textarea 50 | id: steps 51 | attributes: 52 | label: "Steps to reproduce" 53 | description: "Steps to reproduce using the minimal config." 54 | placeholder: | 55 | 1. `nvim -u ~/.local/share/lunarvim/lvim/tests/minimal_lsp.lua` 56 | 2. ... 57 | - type: textarea 58 | id: support-info 59 | attributes: 60 | label: support info 61 | description: Information from LspInfo and LvimInfo 62 | placeholder: | 63 | ```console 64 | # :LspInfo 65 | ``` 66 | ```console 67 | # :LvimInfo 68 | ``` 69 | validations: 70 | required: true 71 | - type: textarea 72 | id: screenshots 73 | attributes: 74 | label: Screenshots 75 | description: If applicable, add screenshots to help explain your problem 76 | -------------------------------------------------------------------------------- /lua/lvim/core/illuminate.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.config = function() 4 | lvim.builtin.illuminate = { 5 | active = true, 6 | on_config_done = nil, 7 | options = { 8 | -- providers: provider used to get references in the buffer, ordered by priority 9 | providers = { 10 | "lsp", 11 | "treesitter", 12 | "regex", 13 | }, 14 | -- delay: delay in milliseconds 15 | delay = 120, 16 | -- filetypes_denylist: filetypes to not illuminate, this overrides filetypes_allowlist 17 | filetypes_denylist = { 18 | "dirvish", 19 | "fugitive", 20 | "alpha", 21 | "NvimTree", 22 | "packer", 23 | "neogitstatus", 24 | "Trouble", 25 | "lir", 26 | "Outline", 27 | "spectre_panel", 28 | "toggleterm", 29 | "DressingSelect", 30 | "TelescopePrompt", 31 | }, 32 | -- filetypes_allowlist: filetypes to illuminate, this is overridden by filetypes_denylist 33 | filetypes_allowlist = {}, 34 | -- modes_denylist: modes to not illuminate, this overrides modes_allowlist 35 | modes_denylist = {}, 36 | -- modes_allowlist: modes to illuminate, this is overridden by modes_denylist 37 | modes_allowlist = {}, 38 | -- providers_regex_syntax_denylist: syntax to not illuminate, this overrides providers_regex_syntax_allowlist 39 | -- Only applies to the 'regex' provider 40 | -- Use :echom synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name') 41 | providers_regex_syntax_denylist = {}, 42 | -- providers_regex_syntax_allowlist: syntax to illuminate, this is overridden by providers_regex_syntax_denylist 43 | -- Only applies to the 'regex' provider 44 | -- Use :echom synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name') 45 | providers_regex_syntax_allowlist = {}, 46 | -- under_cursor: whether or not to illuminate under the cursor 47 | under_cursor = true, 48 | }, 49 | } 50 | end 51 | 52 | M.setup = function() 53 | local status_ok, illuminate = pcall(reload, "illuminate") 54 | if not status_ok then 55 | return 56 | end 57 | 58 | local config_ok, _ = pcall(illuminate.configure, lvim.builtin.illuminate.options) 59 | if not config_ok then 60 | return 61 | end 62 | 63 | if lvim.builtin.illuminate.on_config_done then 64 | lvim.builtin.illuminate.on_config_done() 65 | end 66 | end 67 | 68 | return M 69 | -------------------------------------------------------------------------------- /tests/specs/plugins_load_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require "plenary.async_lib.tests" 2 | 3 | a.describe("plugin-loader", function() 4 | local plugins = require "lvim.plugins" 5 | local loader = require "lvim.plugin-loader" 6 | 7 | pcall(function() 8 | lvim.log.level = "debug" 9 | package.loaded["packer.log"] = nil 10 | package.loaded["lvim.core.log"] = nil 11 | end) 12 | 13 | a.it("should be able to load default packages without errors", function() 14 | loader.load { plugins, lvim.plugins } 15 | 16 | -- TODO: maybe there's a way to avoid hard-coding the names of the modules? 17 | local startup_plugins = { 18 | "packer", 19 | } 20 | 21 | for _, plugin in ipairs(startup_plugins) do 22 | assert.truthy(package.loaded[plugin]) 23 | end 24 | end) 25 | 26 | a.it("should be able to load lsp packages without errors", function() 27 | loader.load { plugins, lvim.plugins } 28 | 29 | require("lvim.lsp").setup() 30 | 31 | local lsp_packages = { 32 | "lspconfig", 33 | "nlspsettings", 34 | "null-ls", 35 | } 36 | 37 | for _, plugin in ipairs(lsp_packages) do 38 | assert.truthy(package.loaded[plugin]) 39 | end 40 | end) 41 | 42 | pending("should be able to rollback plugins without errors", function() 43 | local plugin = { name = "onedarker.nvim" } 44 | plugin.path = vim.tbl_filter(function(package) 45 | return package:match(plugin.name) 46 | end, vim.api.nvim_list_runtime_paths())[1] 47 | 48 | local get_current_sha = function(repo) 49 | local res = vim.fn.system(string.format("git -C %s log -1 --pretty=%%h", repo)):gsub("\n", "") 50 | return res 51 | end 52 | plugin.test_sha = "316b1c9" 53 | _G.locked_sha = get_current_sha(plugin.path) 54 | loader.load { plugins, lvim.plugins } 55 | 56 | os.execute(string.format("git -C %s fetch --deepen 999 --quiet", plugin.path)) 57 | os.execute(string.format("git -C %s checkout %s --quiet", plugin.path, plugin.test_sha)) 58 | assert.equal(plugin.test_sha, get_current_sha(plugin.path)) 59 | _G.completed = false 60 | _G.verify_sha = function() 61 | if _G.locked_sha ~= get_current_sha(plugin.path) then 62 | error "unmatched results!" 63 | else 64 | _G.completed = true 65 | end 66 | end 67 | vim.cmd [[autocmd User PackerComplete ++once lua _G.verify_sha()]] 68 | loader.load_snapshot() 69 | local ret = vim.wait(30 * 10 * 1000, function() 70 | return _G.completed == true 71 | end, 200) 72 | assert.True(ret) 73 | end) 74 | end) 75 | -------------------------------------------------------------------------------- /lua/lvim/core/comment.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.config() 4 | local pre_hook 5 | local loaded, ts_comment = pcall(require, "ts_context_commentstring.integrations.comment_nvim") 6 | if loaded and ts_comment then 7 | pre_hook = ts_comment.create_pre_hook() 8 | end 9 | lvim.builtin.comment = { 10 | active = true, 11 | on_config_done = nil, 12 | ---Add a space b/w comment and the line 13 | ---@type boolean 14 | padding = true, 15 | 16 | ---Whether cursor should stay at the 17 | ---same position. Only works in NORMAL 18 | ---mode mappings 19 | sticky = true, 20 | 21 | ---Lines to be ignored while comment/uncomment. 22 | ---Could be a regex string or a function that returns a regex string. 23 | ---Example: Use '^$' to ignore empty lines 24 | ---@type string|function 25 | ignore = "^$", 26 | 27 | ---Whether to create basic (operator-pending) and extra mappings for NORMAL/VISUAL mode 28 | ---@type table 29 | mappings = { 30 | ---operator-pending mapping 31 | ---Includes `gcc`, `gcb`, `gc[count]{motion}` and `gb[count]{motion}` 32 | basic = true, 33 | ---Extra mapping 34 | ---Includes `gco`, `gcO`, `gcA` 35 | extra = true, 36 | }, 37 | 38 | ---LHS of line and block comment toggle mapping in NORMAL/VISUAL mode 39 | ---@type table 40 | toggler = { 41 | ---line-comment toggle 42 | line = "gcc", 43 | ---block-comment toggle 44 | block = "gbc", 45 | }, 46 | 47 | ---LHS of line and block comment operator-mode mapping in NORMAL/VISUAL mode 48 | ---@type table 49 | opleader = { 50 | ---line-comment opfunc mapping 51 | line = "gc", 52 | ---block-comment opfunc mapping 53 | block = "gb", 54 | }, 55 | 56 | ---LHS of extra mappings 57 | ---@type table 58 | extra = { 59 | ---Add comment on the line above 60 | above = "gcO", 61 | ---Add comment on the line below 62 | below = "gco", 63 | ---Add comment at the end of line 64 | eol = "gcA", 65 | }, 66 | 67 | ---Pre-hook, called before commenting the line 68 | ---@type function|nil 69 | pre_hook = pre_hook, 70 | 71 | ---Post-hook, called after commenting is done 72 | ---@type function|nil 73 | post_hook = nil, 74 | } 75 | end 76 | 77 | function M.setup() 78 | local nvim_comment = require "Comment" 79 | 80 | nvim_comment.setup(lvim.builtin.comment) 81 | if lvim.builtin.comment.on_config_done then 82 | lvim.builtin.comment.on_config_done(nvim_comment) 83 | end 84 | end 85 | 86 | return M 87 | -------------------------------------------------------------------------------- /lua/lvim/core/gitsigns.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.config = function() 4 | lvim.builtin.gitsigns = { 5 | active = true, 6 | on_config_done = nil, 7 | opts = { 8 | signs = { 9 | add = { 10 | hl = "GitSignsAdd", 11 | text = lvim.icons.ui.BoldLineLeft, 12 | numhl = "GitSignsAddNr", 13 | linehl = "GitSignsAddLn", 14 | }, 15 | change = { 16 | hl = "GitSignsChange", 17 | text = lvim.icons.ui.BoldLineLeft, 18 | numhl = "GitSignsChangeNr", 19 | linehl = "GitSignsChangeLn", 20 | }, 21 | delete = { 22 | hl = "GitSignsDelete", 23 | text = lvim.icons.ui.Triangle, 24 | numhl = "GitSignsDeleteNr", 25 | linehl = "GitSignsDeleteLn", 26 | }, 27 | topdelete = { 28 | hl = "GitSignsDelete", 29 | text = lvim.icons.ui.Triangle, 30 | numhl = "GitSignsDeleteNr", 31 | linehl = "GitSignsDeleteLn", 32 | }, 33 | changedelete = { 34 | hl = "GitSignsChange", 35 | text = lvim.icons.ui.BoldLineLeft, 36 | numhl = "GitSignsChangeNr", 37 | linehl = "GitSignsChangeLn", 38 | }, 39 | }, 40 | numhl = false, 41 | linehl = false, 42 | keymaps = { 43 | -- Default keymap options 44 | noremap = true, 45 | buffer = true, 46 | }, 47 | signcolumn = true, 48 | word_diff = false, 49 | attach_to_untracked = true, 50 | current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame` 51 | current_line_blame_opts = { 52 | virt_text = true, 53 | virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align' 54 | delay = 1000, 55 | ignore_whitespace = false, 56 | }, 57 | current_line_blame_formatter_opts = { 58 | relative_time = false, 59 | }, 60 | max_file_length = 40000, 61 | preview_config = { 62 | -- Options passed to nvim_open_win 63 | border = "rounded", 64 | style = "minimal", 65 | relative = "cursor", 66 | row = 0, 67 | col = 1, 68 | }, 69 | watch_gitdir = { 70 | interval = 1000, 71 | follow_files = true, 72 | }, 73 | sign_priority = 6, 74 | update_debounce = 200, 75 | status_formatter = nil, -- Use default 76 | yadm = { enable = false }, 77 | }, 78 | } 79 | end 80 | 81 | M.setup = function() 82 | local gitsigns = reload "gitsigns" 83 | 84 | gitsigns.setup(lvim.builtin.gitsigns.opts) 85 | if lvim.builtin.gitsigns.on_config_done then 86 | lvim.builtin.gitsigns.on_config_done(gitsigns) 87 | end 88 | end 89 | 90 | return M 91 | -------------------------------------------------------------------------------- /lua/lvim/utils/modules.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | -- revisit this 5 | -- function prequire(package) 6 | -- local status, lib = pcall(require, package) 7 | -- if status then 8 | -- return lib 9 | -- else 10 | -- vim.notify("Failed to require '" .. package .. "' from " .. debug.getinfo(2).source) 11 | -- return nil 12 | -- end 13 | -- end 14 | 15 | local function _assign(old, new, k) 16 | local otype = type(old[k]) 17 | local ntype = type(new[k]) 18 | -- print("hi") 19 | if (otype == "thread" or otype == "userdata") or (ntype == "thread" or ntype == "userdata") then 20 | vim.notify(string.format("warning: old or new attr %s type be thread or userdata", k)) 21 | end 22 | old[k] = new[k] 23 | end 24 | 25 | local function _replace(old, new, repeat_tbl) 26 | if repeat_tbl[old] then 27 | return 28 | end 29 | repeat_tbl[old] = true 30 | 31 | local dellist = {} 32 | for k, _ in pairs(old) do 33 | if not new[k] then 34 | table.insert(dellist, k) 35 | end 36 | end 37 | for _, v in ipairs(dellist) do 38 | old[v] = nil 39 | end 40 | 41 | for k, _ in pairs(new) do 42 | if not old[k] then 43 | old[k] = new[k] 44 | else 45 | if type(old[k]) ~= type(new[k]) then 46 | Log:debug( 47 | string.format("Reloader: mismatch between old [%s] and new [%s] type for [%s]", type(old[k]), type(new[k]), k) 48 | ) 49 | _assign(old, new, k) 50 | else 51 | if type(old[k]) == "table" then 52 | _replace(old[k], new[k], repeat_tbl) 53 | else 54 | _assign(old, new, k) 55 | end 56 | end 57 | end 58 | end 59 | end 60 | 61 | M.require_clean = function(m) 62 | package.loaded[m] = nil 63 | _G[m] = nil 64 | local _, module = pcall(require, m) 65 | return module 66 | end 67 | 68 | M.require_safe = function(mod) 69 | local status_ok, module = pcall(require, mod) 70 | if not status_ok then 71 | local trace = debug.getinfo(2, "SL") 72 | local shorter_src = trace.short_src 73 | local lineinfo = shorter_src .. ":" .. (trace.currentline or trace.linedefined) 74 | local msg = string.format("%s : skipped loading [%s]", lineinfo, mod) 75 | Log:debug(msg) 76 | end 77 | return module 78 | end 79 | 80 | M.reload = function(mod) 81 | if not package.loaded[mod] then 82 | return M.require_safe(mod) 83 | end 84 | 85 | local old = package.loaded[mod] 86 | package.loaded[mod] = nil 87 | local new = M.require_safe(mod) 88 | 89 | if type(old) == "table" and type(new) == "table" then 90 | local repeat_tbl = {} 91 | _replace(old, new, repeat_tbl) 92 | end 93 | 94 | package.loaded[mod] = old 95 | return old 96 | end 97 | 98 | return M 99 | -------------------------------------------------------------------------------- /utils/installer/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | ARGS_REMOVE_BACKUPS=0 5 | ARGS_REMOVE_CONFIG=0 6 | 7 | declare -r XDG_DATA_HOME="${XDG_DATA_HOME:-"$HOME/.local/share"}" 8 | declare -r XDG_CACHE_HOME="${XDG_CACHE_HOME:-"$HOME/.cache"}" 9 | declare -r XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-"$HOME/.config"}" 10 | 11 | declare -r LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$XDG_DATA_HOME/lunarvim"}" 12 | declare -r LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$XDG_CONFIG_HOME/lvim"}" 13 | declare -r LUNARVIM_CACHE_DIR="${LUNARVIM_CACHE_DIR:-"$XDG_CACHE_HOME/lvim"}" 14 | 15 | declare -a __lvim_dirs=( 16 | "$LUNARVIM_RUNTIME_DIR" 17 | "$LUNARVIM_CACHE_DIR" 18 | ) 19 | 20 | __lvim_config_dir="$LUNARVIM_CONFIG_DIR" 21 | 22 | function usage() { 23 | echo "Usage: uninstall.sh []" 24 | echo "" 25 | echo "Options:" 26 | echo " -h, --help Print this help message" 27 | echo " --remove-config Remove user config files as well" 28 | echo " --remove-backups Remove old backup folders as well" 29 | } 30 | 31 | function parse_arguments() { 32 | while [ "$#" -gt 0 ]; do 33 | case "$1" in 34 | --remove-backups) 35 | ARGS_REMOVE_BACKUPS=1 36 | ;; 37 | --remove-config) 38 | ARGS_REMOVE_CONFIG=1 39 | ;; 40 | -h | --help) 41 | usage 42 | exit 0 43 | ;; 44 | esac 45 | shift 46 | done 47 | } 48 | 49 | function remove_lvim_dirs() { 50 | if [ "$ARGS_REMOVE_CONFIG" -eq 1 ]; then 51 | __lvim_dirs+=($__lvim_config_dir) 52 | fi 53 | for dir in "${__lvim_dirs[@]}"; do 54 | rm -rf "$dir" 55 | if [ "$ARGS_REMOVE_BACKUPS" -eq 1 ]; then 56 | rm -rf "$dir.{bak,old}" 57 | fi 58 | done 59 | } 60 | 61 | function remove_lvim_bin() { 62 | local legacy_bin="/usr/local/bin/lvim " 63 | if [ -x "$legacy_bin" ]; then 64 | echo "Error! Unable to remove $legacy_bin without elevation. Please remove manually." 65 | exit 1 66 | fi 67 | 68 | lvim_bin="$(command -v lvim 2>/dev/null)" 69 | rm -f "$lvim_bin" 70 | } 71 | 72 | function remove_desktop_file() { 73 | OS="$(uname -s)" 74 | # TODO: Any other OSes that use desktop files? 75 | ([ "$OS" != "Linux" ] || ! command -v xdg-desktop-menu &>/dev/null) && return 76 | echo "Removing desktop file..." 77 | 78 | find "$XDG_DATA_HOME/icons/hicolor" -name "lvim.svg" -type f -delete 79 | xdg-desktop-menu uninstall lvim.desktop 80 | } 81 | 82 | function main() { 83 | parse_arguments "$@" 84 | echo "Removing LunarVim binary..." 85 | remove_lvim_bin 86 | echo "Removing LunarVim directories..." 87 | remove_lvim_dirs 88 | remove_desktop_file 89 | echo "Uninstalled LunarVim!" 90 | } 91 | 92 | main "$@" 93 | -------------------------------------------------------------------------------- /lua/lvim/utils/hooks.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | local in_headless = #vim.api.nvim_list_uis() == 0 5 | local plugin_loader = require "lvim.plugin-loader" 6 | 7 | function M.run_pre_update() 8 | Log:debug "Starting pre-update hook" 9 | end 10 | 11 | function M.run_pre_reload() 12 | Log:debug "Starting pre-reload hook" 13 | end 14 | 15 | function M.run_on_packer_complete() 16 | Log:debug "Packer operation complete" 17 | vim.api.nvim_exec_autocmds("User", { pattern = "PackerComplete" }) 18 | 19 | -- -- FIXME(kylo252): nvim-tree.lua/lua/nvim-tree/view.lua:442: Invalid window id 20 | -- vim.g.colors_name = lvim.colorscheme 21 | -- pcall(vim.cmd.colorscheme, lvim.colorscheme) 22 | 23 | if M._reload_triggered then 24 | Log:debug "Reloaded configuration" 25 | M._reload_triggered = nil 26 | end 27 | end 28 | 29 | function M.run_post_reload() 30 | Log:debug "Starting post-reload hook" 31 | M._reload_triggered = true 32 | end 33 | 34 | ---Reset any startup cache files used by Packer and Impatient 35 | ---It also forces regenerating any template ftplugin files 36 | ---Tip: Useful for clearing any outdated settings 37 | function M.reset_cache() 38 | vim.cmd [[LuaCacheClear]] 39 | plugin_loader.recompile() 40 | local lvim_modules = {} 41 | for module, _ in pairs(package.loaded) do 42 | if module:match "lvim.core" or module:match "lvim.lsp" then 43 | package.loaded[module] = nil 44 | table.insert(lvim_modules, module) 45 | end 46 | end 47 | Log:trace(string.format("Cache invalidated for core modules: { %s }", table.concat(lvim_modules, ", "))) 48 | require("lvim.lsp.templates").generate_templates() 49 | end 50 | 51 | function M.run_post_update() 52 | Log:debug "Starting post-update hook" 53 | 54 | if vim.fn.has "nvim-0.8" ~= 1 then 55 | local compat_tag = "1.1.4" 56 | vim.notify( 57 | "Please upgrade your Neovim base installation. Newer version of Lunarvim requires v0.7+", 58 | vim.log.levels.WARN 59 | ) 60 | vim.wait(1000, function() 61 | return false 62 | end) 63 | local ret = reload("lvim.utils.git").switch_lvim_branch(compat_tag) 64 | if ret then 65 | vim.notify("Reverted to the last known compatible version: " .. compat_tag, vim.log.levels.WARN) 66 | end 67 | return 68 | end 69 | 70 | M.reset_cache() 71 | 72 | Log:debug "Syncing core plugins" 73 | plugin_loader.sync_core_plugins() 74 | 75 | if not in_headless then 76 | vim.schedule(function() 77 | if package.loaded["nvim-treesitter"] then 78 | vim.cmd [[ TSUpdateSync ]] 79 | end 80 | -- TODO: add a changelog 81 | vim.notify("Update complete", vim.log.levels.INFO) 82 | end) 83 | end 84 | end 85 | 86 | return M 87 | -------------------------------------------------------------------------------- /lua/lvim/config/_deprecated.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable: deprecated 2 | local M = {} 3 | 4 | local function deprecate(name, alternative) 5 | local in_headless = #vim.api.nvim_list_uis() == 0 6 | if in_headless then 7 | return 8 | end 9 | 10 | alternative = alternative or "See https://github.com/LunarVim/LunarVim#breaking-changes" 11 | 12 | local trace = debug.getinfo(3, "Sl") 13 | local shorter_src = trace.short_src 14 | local t = shorter_src .. ":" .. (trace.currentline or trace.lastlinedefined) 15 | vim.schedule(function() 16 | vim.notify_once(string.format("%s: `%s` is deprecated.\n %s.", t, name, alternative), vim.log.levels.WARN) 17 | end) 18 | end 19 | 20 | function M.handle() 21 | local mt = { 22 | __newindex = function(_, k, _) 23 | deprecate(k) 24 | end, 25 | } 26 | 27 | ---@deprecated 28 | lvim.builtin.theme.options = {} 29 | setmetatable(lvim.builtin.theme.options, { 30 | __newindex = function(_, k, v) 31 | deprecate("lvim.builtin.theme.options." .. k, "Use `lvim.builtin.theme..options` instead") 32 | lvim.builtin.theme.tokyonight.options[k] = v 33 | end, 34 | }) 35 | 36 | ---@deprecated 37 | lvim.builtin.notify = {} 38 | setmetatable(lvim.builtin.notify, { 39 | __newindex = function(_, k, _) 40 | deprecate("lvim.builtin.notify." .. k, "See LunarVim#3294") 41 | end, 42 | }) 43 | 44 | if lvim.lsp.override and not vim.tbl_isempty(lvim.lsp.override) then 45 | deprecate("lvim.lsp.override", "Use `lvim.lsp.automatic_configuration.skipped_servers` instead") 46 | vim.tbl_map(function(c) 47 | if not vim.tbl_contains(lvim.lsp.automatic_configuration.skipped_servers, c) then 48 | table.insert(lvim.lsp.automatic_configuration.skipped_servers, c) 49 | end 50 | end, lvim.lsp.override) 51 | end 52 | 53 | if lvim.autocommands.custom_groups then 54 | deprecate( 55 | "lvim.autocommands.custom_groups", 56 | "Use vim.api.nvim_create_autocmd instead or check LunarVim#2592 to learn about the new syntax" 57 | ) 58 | end 59 | 60 | if lvim.lsp.automatic_servers_installation then 61 | deprecate( 62 | "lvim.lsp.automatic_servers_installation", 63 | "Use `lvim.lsp.installer.setup.automatic_installation` instead" 64 | ) 65 | end 66 | 67 | ---@deprecated 68 | lvim.builtin.dashboard = {} 69 | setmetatable(lvim.builtin.dashboard, { 70 | __newindex = function(_, k, _) 71 | deprecate("lvim.builtin.dashboard." .. k, "Use `lvim.builtin.alpha` instead. See LunarVim#1906") 72 | end, 73 | }) 74 | 75 | ---@deprecated 76 | lvim.lsp.popup_border = {} 77 | setmetatable(lvim.lsp.popup_border, mt) 78 | 79 | ---@deprecated 80 | lvim.lang = {} 81 | setmetatable(lvim.lang, mt) 82 | end 83 | 84 | return M 85 | -------------------------------------------------------------------------------- /lua/lvim/core/commands.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | vim.cmd [[ 4 | function! QuickFixToggle() 5 | if empty(filter(getwininfo(), 'v:val.quickfix')) 6 | copen 7 | else 8 | cclose 9 | endif 10 | endfunction 11 | ]] 12 | 13 | M.defaults = { 14 | { 15 | name = "BufferKill", 16 | fn = function() 17 | require("lvim.core.bufferline").buf_kill "bd" 18 | end, 19 | }, 20 | { 21 | name = "LvimToggleFormatOnSave", 22 | fn = function() 23 | require("lvim.core.autocmds").toggle_format_on_save() 24 | end, 25 | }, 26 | { 27 | name = "LvimInfo", 28 | fn = function() 29 | require("lvim.core.info").toggle_popup(vim.bo.filetype) 30 | end, 31 | }, 32 | { 33 | name = "LvimDocs", 34 | fn = function() 35 | local documentation_url = "https://www.lunarvim.org/docs/quick-start" 36 | if vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1 then 37 | vim.fn.execute("!open " .. documentation_url) 38 | elseif vim.fn.has "win32" == 1 or vim.fn.has "win64" == 1 then 39 | vim.fn.execute("!start " .. documentation_url) 40 | elseif vim.fn.has "unix" == 1 then 41 | vim.fn.execute("!xdg-open " .. documentation_url) 42 | else 43 | vim.notify "Opening docs in a browser is not supported on your OS" 44 | end 45 | end, 46 | }, 47 | { 48 | name = "LvimCacheReset", 49 | fn = function() 50 | require("lvim.utils.hooks").reset_cache() 51 | end, 52 | }, 53 | { 54 | name = "LvimReload", 55 | fn = function() 56 | require("lvim.config"):reload() 57 | end, 58 | }, 59 | { 60 | name = "LvimUpdate", 61 | fn = function() 62 | require("lvim.bootstrap"):update() 63 | end, 64 | }, 65 | { 66 | name = "LvimSyncCorePlugins", 67 | fn = function() 68 | require("lvim.plugin-loader").sync_core_plugins() 69 | end, 70 | }, 71 | { 72 | name = "LvimChangelog", 73 | fn = function() 74 | require("lvim.core.telescope.custom-finders").view_lunarvim_changelog() 75 | end, 76 | }, 77 | { 78 | name = "LvimVersion", 79 | fn = function() 80 | print(require("lvim.utils.git").get_lvim_version()) 81 | end, 82 | }, 83 | { 84 | name = "LvimOpenlog", 85 | fn = function() 86 | vim.fn.execute("edit " .. require("lvim.core.log").get_path()) 87 | end, 88 | }, 89 | } 90 | 91 | function M.load(collection) 92 | local common_opts = { force = true } 93 | for _, cmd in pairs(collection) do 94 | local opts = vim.tbl_deep_extend("force", common_opts, cmd.opts or {}) 95 | vim.api.nvim_create_user_command(cmd.name, cmd.fn, opts) 96 | end 97 | end 98 | 99 | return M 100 | -------------------------------------------------------------------------------- /snapshots/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment.nvim": { 3 | "commit": "5f01c1a" 4 | }, 5 | "LuaSnip": { 6 | "commit": "09ce9a7" 7 | }, 8 | "alpha-nvim": { 9 | "commit": "a858e4e" 10 | }, 11 | "bufferline.nvim": { 12 | "commit": "4ecfa81" 13 | }, 14 | "cmp-buffer": { 15 | "commit": "3022dbc" 16 | }, 17 | "cmp-nvim-lsp": { 18 | "commit": "5922477" 19 | }, 20 | "cmp-path": { 21 | "commit": "91ff86c" 22 | }, 23 | "cmp_luasnip": { 24 | "commit": "1809552" 25 | }, 26 | "friendly-snippets": { 27 | "commit": "ef8caa5" 28 | }, 29 | "gitsigns.nvim": { 30 | "commit": "9ff7dfb" 31 | }, 32 | "indent-blankline.nvim": { 33 | "commit": "db7cbcb" 34 | }, 35 | "lir.nvim": { 36 | "commit": "7d8c6c4" 37 | }, 38 | "lualine.nvim": { 39 | "commit": "3325d5d" 40 | }, 41 | "lunar.nvim": { 42 | "commit": "29eedf7" 43 | }, 44 | "mason-lspconfig.nvim": { 45 | "commit": "a1e2219" 46 | }, 47 | "mason.nvim": { 48 | "commit": "9f84d49" 49 | }, 50 | "neodev.nvim": { 51 | "commit": "fdcbdaf" 52 | }, 53 | "nlsp-settings.nvim": { 54 | "commit": "9ea9a13" 55 | }, 56 | "null-ls.nvim": { 57 | "commit": "07d4ed4" 58 | }, 59 | "nvim-autopairs": { 60 | "commit": "6b6e35f" 61 | }, 62 | "nvim-cmp": { 63 | "commit": "8a9e8a8" 64 | }, 65 | "nvim-dap": { 66 | "commit": "6164368" 67 | }, 68 | "nvim-dap-ui": { 69 | "commit": "69a3982" 70 | }, 71 | "nvim-lspconfig": { 72 | "commit": "ea5744f" 73 | }, 74 | "nvim-navic": { 75 | "commit": "40c0ab2" 76 | }, 77 | "nvim-tree.lua": { 78 | "commit": "68a2a09" 79 | }, 80 | "nvim-treesitter": { 81 | "commit": "b880011" 82 | }, 83 | "nvim-ts-context-commentstring": { 84 | "commit": "32d9627" 85 | }, 86 | "nvim-web-devicons": { 87 | "commit": "3b1b794" 88 | }, 89 | "onedarker.nvim": { 90 | "commit": "b00dd21" 91 | }, 92 | "packer.nvim": { 93 | "commit": "6afb674" 94 | }, 95 | "plenary.nvim": { 96 | "commit": "4b7e520" 97 | }, 98 | "popup.nvim": { 99 | "commit": "b7404d3" 100 | }, 101 | "project.nvim": { 102 | "commit": "685bc8e" 103 | }, 104 | "schemastore.nvim": { 105 | "commit": "7741353" 106 | }, 107 | "structlog.nvim": { 108 | "commit": "232a8e2" 109 | }, 110 | "telescope-fzf-native.nvim": { 111 | "commit": "65c0ee3" 112 | }, 113 | "telescope.nvim": { 114 | "commit": "0b1c41a" 115 | }, 116 | "toggleterm.nvim": { 117 | "commit": "3ba6838" 118 | }, 119 | "tokyonight.nvim": { 120 | "commit": "62b4e89" 121 | }, 122 | "vim-illuminate": { 123 | "commit": "a6d0b28" 124 | }, 125 | "which-key.nvim": { 126 | "commit": "61553ae" 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /.github/workflows/install.yaml: -------------------------------------------------------------------------------- 1 | name: install 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "master" 7 | - "rolling" 8 | paths: 9 | - '.github/workflows/**' 10 | - 'lua/**' 11 | - 'snapshots/**' 12 | - 'tests/**' 13 | - 'utils/**' 14 | 15 | jobs: 16 | unixish: 17 | name: ${{ matrix.os }} ${{ matrix.runner }} (${{ matrix.neovim }}) 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - runner: ubuntu-latest 23 | os: linux 24 | neovim: v0.8.0 25 | - runner: macos-latest 26 | os: osx 27 | neovim: v0.8.0 28 | - runner: ubuntu-22.04 29 | os: linux 30 | neovim: nightly 31 | - runner: macos-12 32 | os: osx 33 | neovim: nightly 34 | runs-on: ${{ matrix.runner }} 35 | steps: 36 | - uses: actions/checkout@v3 37 | 38 | - name: Install neovim binary from release 39 | env: 40 | RELEASE_VER: ${{ matrix.neovim }} 41 | run: | 42 | echo "$HOME/.local/bin" >> "$GITHUB_PATH" 43 | bash ./utils/installer/install-neovim-from-release 44 | 45 | - name: Install LunarVim 46 | timeout-minutes: 4 47 | env: 48 | LV_BRANCH: ${{ github.head_ref || github.ref_name }} 49 | LV_REMOTE: ${{ github.event.pull_request.head.repo.full_name || github.repository }} 50 | LUNARVIM_LOG_LEVEL: "debug" 51 | run: | 52 | export PATH="$HOME/.local/bin:$PATH" 53 | 54 | installer_url="https://raw.githubusercontent.com/${LV_REMOTE}/${LV_BRANCH}/utils/installer/install.sh" 55 | curl -LSsO "$installer_url" 56 | bash ./install.sh --no-install-dependencies 57 | 58 | - name: Run unit-tests 59 | # NOTE: make sure to adjust the timeout if you start adding a lot of tests 60 | timeout-minutes: 4 61 | run: | 62 | nvim --version 63 | make test 64 | 65 | windows: 66 | name: "windows-latest" 67 | runs-on: windows-latest 68 | if: github.event.pull_request.draft == false 69 | continue-on-error: true # windows support is still experimental 70 | defaults: 71 | run: 72 | shell: pwsh 73 | steps: 74 | # it's not currently possbile to run tests on windows, see nvim-lua/plenary.nvim#255 75 | - uses: actions/checkout@v3 76 | 77 | - name: Install neovim binary 78 | uses: rhysd/action-setup-vim@v1 79 | with: 80 | neovim: true 81 | version: v0.8.0 82 | 83 | - name: Install LunarVim 84 | timeout-minutes: 4 85 | run: | 86 | echo "$HOME/.local/bin" >> $GITHUB_PATH 87 | pwsh.exe -NoLogo -ExecutionPolicy Bypass -NonInteractive -Command "./utils/installer/install.ps1 --local" 88 | -------------------------------------------------------------------------------- /lua/lvim/interface/text.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function max_len_line(lines) 4 | local max_len = 0 5 | 6 | for _, line in ipairs(lines) do 7 | local line_len = line:len() 8 | if line_len > max_len then 9 | max_len = line_len 10 | end 11 | end 12 | 13 | return max_len 14 | end 15 | 16 | --- Left align lines relatively to the parent container 17 | -- @param container The container where lines will be displayed 18 | -- @param lines The text to align 19 | -- @param alignment The alignment value, range: [0-1] 20 | function M.align_left(container, lines, alignment) 21 | local max_len = max_len_line(lines) 22 | local indent_amount = math.ceil(math.max(container.width - max_len, 0) * alignment) 23 | return M.shift_right(lines, indent_amount) 24 | end 25 | 26 | --- Center align lines relatively to the parent container 27 | -- @param container The container where lines will be displayed 28 | -- @param lines The text to align 29 | -- @param alignment The alignment value, range: [0-1] 30 | function M.align_center(container, lines, alignment) 31 | local output = {} 32 | local max_len = max_len_line(lines) 33 | 34 | for _, line in ipairs(lines) do 35 | local padding = string.rep(" ", (math.max(container.width, max_len) - line:len()) * alignment) 36 | table.insert(output, padding .. line) 37 | end 38 | 39 | return output 40 | end 41 | 42 | --- Shift lines by a given amount 43 | -- @params lines The lines the shift 44 | -- @param amount The amount of spaces to add 45 | function M.shift_right(lines, amount) 46 | local output = {} 47 | local padding = string.rep(" ", amount) 48 | 49 | for _, line in ipairs(lines) do 50 | table.insert(output, padding .. line) 51 | end 52 | 53 | return output 54 | end 55 | 56 | --- Pretty format tables 57 | -- @param entries The table to format 58 | -- @param col_count The number of column to span the table on 59 | -- @param col_sep The separator between each column, default: " " 60 | function M.format_table(entries, col_count, col_sep) 61 | col_sep = col_sep or " " 62 | 63 | local col_rows = math.ceil(vim.tbl_count(entries) / col_count) 64 | local cols = {} 65 | local count = 0 66 | 67 | for i, entry in ipairs(entries) do 68 | if ((i - 1) % col_rows) == 0 then 69 | table.insert(cols, {}) 70 | count = count + 1 71 | end 72 | table.insert(cols[count], entry) 73 | end 74 | 75 | local col_max_len = {} 76 | for _, col in ipairs(cols) do 77 | table.insert(col_max_len, max_len_line(col)) 78 | end 79 | 80 | local output = {} 81 | for i, col in ipairs(cols) do 82 | for j, entry in ipairs(col) do 83 | if not output[j] then 84 | output[j] = entry 85 | else 86 | local padding = string.rep(" ", col_max_len[i - 1] - cols[i - 1][j]:len()) 87 | output[j] = output[j] .. padding .. col_sep .. entry 88 | end 89 | end 90 | end 91 | 92 | return output 93 | end 94 | 95 | return M 96 | -------------------------------------------------------------------------------- /utils/installer/install-neovim-from-release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu pipefall 4 | 5 | declare -r LV_INSTALL_PREFIX="${INSTALL_PREFIX:-"$HOME/.local"}" 6 | declare -r RELEASE_VER="${RELEASE_VER:-latest}" # can be set to nightly 7 | 8 | declare ARCHIVE_NAME 9 | declare RELEASE_NAME 10 | declare OS 11 | 12 | OS="$(uname -s)" 13 | 14 | if [ "$OS" == "Linux" ]; then 15 | ARCHIVE_NAME="nvim-linux64" 16 | RELEASE_NAME="nvim-linux64" 17 | elif [ "$OS" == "Darwin" ]; then 18 | ARCHIVE_NAME="nvim-macos" 19 | # for some reason the archive has a different name 20 | RELEASE_NAME="nvim-osx64" 21 | else 22 | echo "$OS platform is not supported currently" 23 | exit 1 24 | fi 25 | 26 | if [[ "${RELEASE_VER}" == "latest" ]]; then 27 | declare -r RELEASE_URL="https://github.com/neovim/neovim/releases/${RELEASE_VER}/download/${ARCHIVE_NAME}.tar.gz" 28 | else 29 | declare -r RELEASE_URL="https://github.com/neovim/neovim/releases/download/${RELEASE_VER}/${ARCHIVE_NAME}.tar.gz" 30 | fi 31 | declare -r CHECKSUM_URL="$RELEASE_URL.sha256sum" 32 | 33 | DOWNLOAD_DIR="$(mktemp -d)" 34 | readonly DOWNLOAD_DIR 35 | 36 | RELEASE_SHA="$(curl -Ls "$CHECKSUM_URL" | awk '{print $1}')" 37 | readonly RELEASE_SHA 38 | 39 | function main() { 40 | if [ ! -d "$LV_INSTALL_PREFIX" ]; then 41 | mkdir -p "$LV_INSTALL_PREFIX" || __invalid__prefix__handler 42 | fi 43 | download_neovim 44 | verify_neovim 45 | install_neovim 46 | } 47 | 48 | function download_neovim() { 49 | echo "Downloading Neovim's binary from $RELEASE_VER release.." 50 | if ! curl --progress-bar --fail -L "$RELEASE_URL" -o "$DOWNLOAD_DIR/$ARCHIVE_NAME.tar.gz"; then 51 | echo "Download failed. Check that the release/filename are correct." 52 | exit 1 53 | fi 54 | echo "Download complete!" 55 | } 56 | 57 | function verify_neovim() { 58 | echo "Verifying the installation.." 59 | DOWNLOADED_SHA="$(openssl dgst -sha256 "$DOWNLOAD_DIR/$ARCHIVE_NAME.tar.gz" | awk '{print $2}')" 60 | 61 | if [ "$RELEASE_SHA" != "$DOWNLOADED_SHA" ]; then 62 | echo "Error! checksum mismatch." 63 | echo "Expected: $RELEASE_SHA but got: $DOWNLOADED_SHA" 64 | exit 1 65 | fi 66 | echo "Verification complete!" 67 | } 68 | 69 | function install_neovim() { 70 | 71 | echo "Installing Neovim.." 72 | pushd "$DOWNLOAD_DIR" 73 | tar -xzf "$DOWNLOAD_DIR/$ARCHIVE_NAME.tar.gz" 74 | popd 75 | if [ ! -d "$DOWNLOAD_DIR/$RELEASE_NAME" ]; then 76 | # fallback to archive name 77 | RELEASE_NAME="$ARCHIVE_NAME" 78 | fi 79 | # https://dev.to/ackshaey/macos-vs-linux-the-cp-command-will-trip-you-up-2p00 80 | cp -r "$DOWNLOAD_DIR/$RELEASE_NAME/." "$LV_INSTALL_PREFIX" 81 | echo "Installation complete!" 82 | echo "Now you can run $LV_INSTALL_PREFIX/bin/nvim" 83 | } 84 | 85 | function __invalid__prefix__handler() { 86 | echo "Error! Invalid value for LV_INSTALL_PREFIX: [$INSTALL_PREFIX]" 87 | echo "Please verify that the folder exists and re-run the installer!" 88 | exit 1 89 | } 90 | 91 | main "$@" 92 | -------------------------------------------------------------------------------- /ftplugin/lua.lua: -------------------------------------------------------------------------------- 1 | local fmt = string.format 2 | -- luacheck: ignore 3 | -- TODO: fix lint violations 4 | 5 | -- Iterator that splits a string o a given delimiter 6 | local function split(str, delim) 7 | delim = delim or "%s" 8 | return string.gmatch(str, fmt("[^%s]+", delim)) 9 | end 10 | 11 | -- Find the proper directory separator depending 12 | -- on lua installation or OS. 13 | local function dir_separator() 14 | -- Look at package.config for directory separator string (it's the first line) 15 | if package.config then 16 | return string.match(package.config, "^[^\n]") 17 | elseif vim.fn.has "win32" == 1 then 18 | return "\\" 19 | else 20 | return "/" 21 | end 22 | end 23 | 24 | -- Search for lua traditional include paths. 25 | -- This mimics how require internally works. 26 | local function include_paths(fname, ext) 27 | ext = ext or "lua" 28 | local sep = dir_separator() 29 | local paths = string.gsub(package.path, "%?", fname) 30 | for path in split(paths, "%;") do 31 | if vim.fn.filereadable(path) == 1 then 32 | return path 33 | end 34 | end 35 | end 36 | 37 | -- Search for nvim lua include paths 38 | local function include_rtpaths(fname, ext) 39 | ext = ext or "lua" 40 | local sep = dir_separator() 41 | local rtpaths = vim.api.nvim_list_runtime_paths() 42 | local modfile, initfile = fmt("%s.%s", fname, ext), fmt("init.%s", ext) 43 | for _, path in ipairs(rtpaths) do 44 | -- Look on runtime path for 'lua/*.lua' files 45 | local path1 = table.concat({ path, ext, modfile }, sep) 46 | if vim.fn.filereadable(path1) == 1 then 47 | return path1 48 | end 49 | -- Look on runtime path for 'lua/*/init.lua' files 50 | local path2 = table.concat({ path, ext, fname, initfile }, sep) 51 | if vim.fn.filereadable(path2) == 1 then 52 | return path2 53 | end 54 | end 55 | end 56 | 57 | -- Global function that searches the path for the required file 58 | function find_required_path(module) 59 | -- Look at package.config for directory separator string (it's the first line) 60 | local sep = string.match(package.config, "^[^\n]") 61 | -- Properly change '.' to separator (probably '/' on *nix and '\' on Windows) 62 | local fname = vim.fn.substitute(module, "\\.", sep, "g") 63 | local f 64 | ---- First search for lua modules 65 | f = include_paths(fname, "lua") 66 | if f then 67 | return f 68 | end 69 | -- This part is just for nvim modules 70 | f = include_rtpaths(fname, "lua") 71 | if f then 72 | return f 73 | end 74 | ---- Now search for Fennel modules 75 | f = include_paths(fname, "fnl") 76 | if f then 77 | return f 78 | end 79 | -- This part is just for nvim modules 80 | f = include_rtpaths(fname, "fnl") 81 | if f then 82 | return f 83 | end 84 | end 85 | 86 | -- Set options to open require with gf 87 | vim.opt_local.include = [=[\v<((do|load)file|require)\s*\(?['"]\zs[^'"]+\ze['"]]=] 88 | vim.opt_local.includeexpr = "v:lua.find_required_path(v:fname)" 89 | -------------------------------------------------------------------------------- /lua/lvim/core/alpha.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.config() 4 | local lvim_dashboard = require "lvim.core.alpha.dashboard" 5 | local lvim_startify = require "lvim.core.alpha.startify" 6 | lvim.builtin.alpha = { 7 | dashboard = { config = {}, section = lvim_dashboard.get_sections() }, 8 | startify = { config = {}, section = lvim_startify.get_sections() }, 9 | active = true, 10 | mode = "dashboard", 11 | } 12 | end 13 | 14 | local function resolve_buttons(theme_name, entries) 15 | local selected_theme = require("alpha.themes." .. theme_name) 16 | local val = {} 17 | for _, entry in pairs(entries) do 18 | local on_press = function() 19 | local sc_ = entry[1]:gsub("%s", ""):gsub("SPC", "") 20 | local key = vim.api.nvim_replace_termcodes(sc_, true, false, true) 21 | vim.api.nvim_feedkeys(key, "normal", false) 22 | end 23 | local button_element = selected_theme.button(entry[1], entry[2], entry[3]) 24 | -- this became necessary after recent changes in alpha.nvim (06ade3a20ca9e79a7038b98d05a23d7b6c016174) 25 | button_element.on_press = on_press 26 | table.insert(val, button_element) 27 | end 28 | return val 29 | end 30 | 31 | local function resolve_config(theme_name) 32 | local selected_theme = require("alpha.themes." .. theme_name) 33 | local resolved_section = selected_theme.section 34 | local section = lvim.builtin.alpha[theme_name].section 35 | 36 | for name, el in pairs(section) do 37 | for k, v in pairs(el) do 38 | if name:match "buttons" and k == "entries" then 39 | resolved_section[name].val = resolve_buttons(theme_name, v) 40 | elseif v then 41 | resolved_section[name][k] = v 42 | end 43 | end 44 | end 45 | 46 | return selected_theme.config 47 | end 48 | 49 | local function configure_additional_autocmds() 50 | local group = "_dashboard_settings" 51 | vim.api.nvim_create_augroup(group, {}) 52 | vim.api.nvim_create_autocmd("FileType", { 53 | group = group, 54 | pattern = "alpha", 55 | command = "set showtabline=0 | autocmd BufLeave set showtabline=" .. vim.opt.showtabline._value, 56 | }) 57 | if not lvim.builtin.lualine.options.globalstatus then 58 | -- https://github.com/goolord/alpha-nvim/issues/42 59 | vim.api.nvim_create_autocmd("FileType", { 60 | group = group, 61 | pattern = "alpha", 62 | command = "set laststatus=0 | autocmd BufUnload set laststatus=" .. vim.opt.laststatus._value, 63 | }) 64 | end 65 | end 66 | 67 | function M.setup() 68 | local status_ok, alpha = pcall(require, "alpha") 69 | if not status_ok then 70 | return 71 | end 72 | local mode = lvim.builtin.alpha.mode 73 | local config = lvim.builtin.alpha[mode].config 74 | 75 | -- this makes it easier to use a completely custom configuration 76 | if vim.tbl_isempty(config) then 77 | config = resolve_config(mode) 78 | end 79 | 80 | alpha.setup(config) 81 | configure_additional_autocmds() 82 | end 83 | 84 | return M 85 | -------------------------------------------------------------------------------- /lua/lvim/lsp/templates.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | local utils = require "lvim.utils" 5 | local lvim_lsp_utils = require "lvim.lsp.utils" 6 | 7 | local ftplugin_dir = lvim.lsp.templates_dir 8 | 9 | local join_paths = _G.join_paths 10 | 11 | function M.remove_template_files() 12 | -- remove any outdated files 13 | for _, file in ipairs(vim.fn.glob(ftplugin_dir .. "/*.lua", 1, 1)) do 14 | vim.fn.delete(file) 15 | end 16 | end 17 | 18 | local skipped_filetypes = lvim.lsp.automatic_configuration.skipped_filetypes 19 | local skipped_servers = lvim.lsp.automatic_configuration.skipped_servers 20 | local ensure_installed_servers = lvim.lsp.installer.setup.ensure_installed 21 | 22 | ---Check if we should skip generating an ftplugin file based on the server_name 23 | ---@param server_name string name of a valid language server 24 | local function should_skip(server_name) 25 | -- ensure_installed_servers should take priority over skipped_servers 26 | return vim.tbl_contains(skipped_servers, server_name) and not vim.tbl_contains(ensure_installed_servers, server_name) 27 | end 28 | 29 | ---Generates an ftplugin file based on the server_name in the selected directory 30 | ---@param server_name string name of a valid language server, e.g. pyright, gopls, tsserver, etc. 31 | ---@param dir string the full path to the desired directory 32 | function M.generate_ftplugin(server_name, dir) 33 | if should_skip(server_name) then 34 | return 35 | end 36 | 37 | -- get the supported filetypes and remove any ignored ones 38 | local filetypes = vim.tbl_filter(function(ft) 39 | return not vim.tbl_contains(skipped_filetypes, ft) 40 | end, lvim_lsp_utils.get_supported_filetypes(server_name) or {}) 41 | 42 | if not filetypes then 43 | return 44 | end 45 | 46 | for _, filetype in ipairs(filetypes) do 47 | local filename = join_paths(dir, filetype .. ".lua") 48 | local setup_cmd = string.format([[require("lvim.lsp.manager").setup(%q)]], server_name) 49 | -- print("using setup_cmd: " .. setup_cmd) 50 | -- overwrite the file completely 51 | utils.write_file(filename, setup_cmd .. "\n", "a") 52 | end 53 | end 54 | 55 | ---Generates ftplugin files based on a list of server_names 56 | ---The files are generated to a runtimepath: "$LUNARVIM_RUNTIME_DIR/site/after/ftplugin/template.lua" 57 | ---@param servers_names? table list of servers to be enabled. Will add all by default 58 | function M.generate_templates(servers_names) 59 | servers_names = servers_names or lvim_lsp_utils.get_supported_servers() 60 | 61 | Log:debug "Templates installation in progress" 62 | 63 | M.remove_template_files() 64 | 65 | -- create the directory if it didn't exist 66 | if not utils.is_directory(lvim.lsp.templates_dir) then 67 | vim.fn.mkdir(ftplugin_dir, "p") 68 | end 69 | 70 | for _, server in ipairs(servers_names) do 71 | M.generate_ftplugin(server, ftplugin_dir) 72 | end 73 | Log:debug "Templates installation is complete" 74 | end 75 | 76 | return M 77 | -------------------------------------------------------------------------------- /lua/lvim/config/init.lua: -------------------------------------------------------------------------------- 1 | local utils = require "lvim.utils" 2 | local Log = require "lvim.core.log" 3 | 4 | local M = {} 5 | local user_config_dir = get_config_dir() 6 | local user_config_file = utils.join_paths(user_config_dir, "config.lua") 7 | 8 | ---Get the full path to the user configuration file 9 | ---@return string 10 | function M:get_user_config_path() 11 | return user_config_file 12 | end 13 | 14 | --- Initialize lvim default configuration and variables 15 | function M:init() 16 | lvim = vim.deepcopy(require "lvim.config.defaults") 17 | 18 | require("lvim.keymappings").load_defaults() 19 | 20 | local builtins = require "lvim.core.builtins" 21 | builtins.config { user_config_file = user_config_file } 22 | 23 | local settings = require "lvim.config.settings" 24 | settings.load_defaults() 25 | 26 | local autocmds = require "lvim.core.autocmds" 27 | autocmds.load_defaults() 28 | 29 | local lvim_lsp_config = require "lvim.lsp.config" 30 | lvim.lsp = vim.deepcopy(lvim_lsp_config) 31 | 32 | lvim.builtin.luasnip = { 33 | sources = { 34 | friendly_snippets = true, 35 | }, 36 | } 37 | 38 | require("lvim.config._deprecated").handle() 39 | end 40 | 41 | --- Override the configuration with a user provided one 42 | -- @param config_path The path to the configuration overrides 43 | function M:load(config_path) 44 | local autocmds = reload "lvim.core.autocmds" 45 | config_path = config_path or self:get_user_config_path() 46 | local ok, err = pcall(dofile, config_path) 47 | if not ok then 48 | if utils.is_file(user_config_file) then 49 | Log:warn("Invalid configuration: " .. err) 50 | else 51 | vim.notify_once( 52 | string.format("User-configuration not found. Creating an example configuration in %s", config_path) 53 | ) 54 | local example_config = join_paths(get_lvim_base_dir(), "utils", "installer", "config.example.lua") 55 | vim.loop.fs_copyfile(example_config, config_path) 56 | end 57 | end 58 | 59 | Log:set_level(lvim.log.level) 60 | 61 | autocmds.define_autocmds(lvim.autocommands) 62 | 63 | vim.g.mapleader = (lvim.leader == "space" and " ") or lvim.leader 64 | 65 | reload("lvim.keymappings").load(lvim.keys) 66 | 67 | if lvim.transparent_window then 68 | autocmds.enable_transparent_mode() 69 | end 70 | 71 | if lvim.reload_config_on_save then 72 | autocmds.enable_reload_config_on_save() 73 | end 74 | end 75 | 76 | --- Override the configuration with a user provided one 77 | -- @param config_path The path to the configuration overrides 78 | function M:reload() 79 | vim.schedule(function() 80 | reload("lvim.utils.hooks").run_pre_reload() 81 | 82 | M:load() 83 | 84 | reload("lvim.core.autocmds").configure_format_on_save() 85 | 86 | local plugins = reload "lvim.plugins" 87 | local plugin_loader = reload "lvim.plugin-loader" 88 | 89 | plugin_loader.reload { plugins, lvim.plugins } 90 | reload("lvim.core.theme").setup() 91 | reload("lvim.utils.hooks").run_post_reload() 92 | end) 93 | end 94 | 95 | return M 96 | -------------------------------------------------------------------------------- /lua/lvim/core/mason.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local join_paths = require("lvim.utils").join_paths 4 | 5 | function M.config() 6 | lvim.builtin.mason = { 7 | ui = { 8 | border = "rounded", 9 | keymaps = { 10 | toggle_package_expand = "", 11 | install_package = "i", 12 | update_package = "u", 13 | check_package_version = "c", 14 | update_all_packages = "U", 15 | check_outdated_packages = "C", 16 | uninstall_package = "X", 17 | cancel_installation = "", 18 | apply_language_filter = "", 19 | }, 20 | }, 21 | 22 | -- NOTE: should be available in $PATH 23 | install_root_dir = join_paths(vim.fn.stdpath "data", "mason"), 24 | 25 | -- NOTE: already handled in the bootstrap stage 26 | PATH = "skip", 27 | 28 | pip = { 29 | -- These args will be added to `pip install` calls. Note that setting extra args might impact intended behavior 30 | -- and is not recommended. 31 | -- 32 | -- Example: { "--proxy", "https://proxyserver" } 33 | install_args = {}, 34 | }, 35 | 36 | -- Controls to which degree logs are written to the log file. It's useful to set this to vim.log.levels.DEBUG when 37 | -- debugging issues with package installations. 38 | log_level = vim.log.levels.INFO, 39 | 40 | -- Limit for the maximum amount of packages to be installed at the same time. Once this limit is reached, any further 41 | -- packages that are requested to be installed will be put in a queue. 42 | max_concurrent_installers = 4, 43 | 44 | github = { 45 | -- The template URL to use when downloading assets from GitHub. 46 | -- The placeholders are the following (in order): 47 | -- 1. The repository (e.g. "rust-lang/rust-analyzer") 48 | -- 2. The release version (e.g. "v0.3.0") 49 | -- 3. The asset name (e.g. "rust-analyzer-v0.3.0-x86_64-unknown-linux-gnu.tar.gz") 50 | download_url_template = "https://github.com/%s/releases/download/%s/%s", 51 | }, 52 | } 53 | end 54 | 55 | function M.get_prefix() 56 | local default_prefix = join_paths(vim.fn.stdpath "data", "mason") 57 | return vim.tbl_get(lvim.builtin, "mason", "install_root_dir") or default_prefix 58 | end 59 | 60 | ---@param append boolean|nil whether to append to prepend to PATH 61 | local function add_to_path(append) 62 | local p = join_paths(M.get_prefix(), "bin") 63 | if vim.env.PATH:match(p) then 64 | return 65 | end 66 | local string_separator = vim.loop.os_uname().version:match "Windows" and ";" or ":" 67 | if append then 68 | vim.env.PATH = vim.env.PATH .. string_separator .. p 69 | else 70 | vim.env.PATH = p .. string_separator .. vim.env.PATH 71 | end 72 | end 73 | 74 | function M.bootstrap() 75 | add_to_path() 76 | end 77 | 78 | function M.setup() 79 | local status_ok, mason = pcall(reload, "mason") 80 | if not status_ok then 81 | return 82 | end 83 | 84 | add_to_path(lvim.builtin.mason.PATH == "append") 85 | 86 | mason.setup(lvim.builtin.mason) 87 | end 88 | 89 | return M 90 | -------------------------------------------------------------------------------- /tests/specs/lsp_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require "plenary.async_lib.tests" 2 | local utils = require "lvim.utils" 3 | local helpers = require "tests.lvim.helpers" 4 | local spy = require "luassert.spy" 5 | 6 | a.describe("lsp workflow", function() 7 | before_each(function() 8 | vim.cmd [[ 9 | let v:errmsg = "" 10 | let v:errors = [] 11 | ]] 12 | end) 13 | 14 | after_each(function() 15 | local errmsg = vim.fn.eval "v:errmsg" 16 | local exception = vim.fn.eval "v:exception" 17 | local errors = vim.fn.eval "v:errors" 18 | assert.equal("", errmsg) 19 | assert.equal("", exception) 20 | assert.True(vim.tbl_isempty(errors)) 21 | end) 22 | 23 | lvim.lsp.templates_dir = join_paths(get_cache_dir(), "artifacts") 24 | 25 | a.it("should be able to delete ftplugin templates", function() 26 | if utils.is_directory(lvim.lsp.templates_dir) then 27 | assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0) 28 | end 29 | assert.False(utils.is_directory(lvim.lsp.templates_dir)) 30 | end) 31 | 32 | a.it("should be able to generate ftplugin templates", function() 33 | if utils.is_directory(lvim.lsp.templates_dir) then 34 | assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0) 35 | end 36 | 37 | require("lvim.lsp").setup() 38 | 39 | assert.True(utils.is_directory(lvim.lsp.templates_dir)) 40 | end) 41 | 42 | a.it("should not include blacklisted servers in the generated templates", function() 43 | require("lvim.lsp").setup() 44 | 45 | for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do 46 | for _, server_name in ipairs(lvim.lsp.override) do 47 | local setup_cmd = string.format([[require("lvim.lsp.manager").setup(%q)]], server_name) 48 | assert.False(helpers.file_contains(file, setup_cmd)) 49 | end 50 | end 51 | end) 52 | 53 | a.it("should only include one server per generated template", function() 54 | require("lvim.lsp").setup() 55 | 56 | local allowed_dupes = { "tailwindcss" } 57 | for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do 58 | local content = {} 59 | for entry in io.lines(file) do 60 | local server_name = entry:match [[.*setup%("(.*)"%)]] 61 | if not vim.tbl_contains(allowed_dupes, server_name) then 62 | table.insert(content, server_name) 63 | end 64 | end 65 | local err_msg = "" 66 | if #content > 1 then 67 | err_msg = string.format( 68 | "found more than one server for [%q]: \n{\n %q \n}", 69 | file:match "[^/]*.lua$", 70 | table.concat(content, ", ") 71 | ) 72 | end 73 | assert.equal(err_msg, "") 74 | end 75 | end) 76 | 77 | a.it("should not attempt to re-generate ftplugin templates", function() 78 | local s = spy.on(require "lvim.lsp.templates", "generate_templates") 79 | local plugins = require "lvim.plugins" 80 | require("lvim.plugin-loader").load { plugins, lvim.plugins } 81 | 82 | require("lvim.lsp").setup() 83 | assert.spy(s).was_not_called() 84 | s:revert() 85 | end) 86 | end) 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/lsp-issue-form.yaml: -------------------------------------------------------------------------------- 1 | name: LSP Issue 2 | description: File a LSP related bug report 3 | labels: [bug, lsp] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | _Before reporting:_ search [existing issues](https://github.com/lunarvim/lunarvim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [Troubleshooting guide](https://www.lunarvim.org/troubleshooting). 10 | If you need real-time help, join us on Discord. Thank you for helping us improve! 11 | 12 | - type: textarea 13 | id: problem-description 14 | attributes: 15 | label: Problem description 16 | description: "A short description of the problem you are reporting." 17 | validations: 18 | required: true 19 | - type: input 20 | id: version 21 | attributes: 22 | label: LunarVim version 23 | placeholder: | 24 | output of :LvimVersion 25 | validations: 26 | required: true 27 | - type: input 28 | id: nvim-version 29 | attributes: 30 | label: Neovim version (>= 0.8.0) 31 | description: "Output of `nvim --version`" 32 | placeholder: | 33 | NVIM v0.8.0-dev+199-g2875d45e7 34 | validations: 35 | required: true 36 | - type: input 37 | id: system-version 38 | attributes: 39 | label: "Operating system/version" 40 | placeholder: "macOS 11.5" 41 | validations: 42 | required: true 43 | - type: input 44 | id: servers 45 | attributes: 46 | label: "Affected language servers" 47 | description: "If this issue is specific to one or more language servers, list them here. If not, write 'all'." 48 | placeholder: "tsserver" 49 | validations: 50 | required: true 51 | - type: textarea 52 | id: steps 53 | attributes: 54 | label: "Steps to reproduce" 55 | description: "Steps to reproduce using the minimal config." 56 | placeholder: | 57 | 1. `nvim -u ~/.local/share/lunarvim/lvim/tests/minimal_lsp.lua` 58 | 2. ... 59 | - type: textarea 60 | id: behavior 61 | attributes: 62 | label: "Actual behavior" 63 | description: "Observed behavior." 64 | validations: 65 | required: true 66 | - type: textarea 67 | id: expected-behavior 68 | attributes: 69 | label: "Expected behavior" 70 | description: "A description of the behavior you expected." 71 | - type: textarea 72 | id: support-info 73 | attributes: 74 | label: support info 75 | description: Information from LspInfo and LvimInfo 76 | placeholder: | 77 | ```console 78 | # :LspInfo 79 | ``` 80 | ```console 81 | # :LvimInfo 82 | ``` 83 | validations: 84 | required: true 85 | - type: textarea 86 | id: lsp-logs 87 | attributes: 88 | label: logs 89 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 90 | render: console 91 | - type: textarea 92 | id: screenshots 93 | attributes: 94 | label: Screenshots 95 | description: If applicable, add screenshots to help explain your problem 96 | -------------------------------------------------------------------------------- /.github/workflows/cliff.toml: -------------------------------------------------------------------------------- 1 | # configuration file for git-cliff (0.1.0) 2 | 3 | [changelog] 4 | # changelog header 5 | header = """ 6 | # Changelog\n 7 | All notable changes to this project will be documented in this file.\n 8 | """ 9 | # template for the changelog body 10 | # https://tera.netlify.app/docs/#introduction 11 | body = """ 12 | {% if version %}\ 13 | ## [{{ version | trim_start_matches(pat="v") }}] 14 | {% else %}\ 15 | ## [unreleased] 16 | {% endif %}\ 17 | {% for group, commits in commits | group_by(attribute="group") %} 18 | ### {{ group | upper_first }} 19 | {% for commit in commits 20 | | filter(attribute="scope") 21 | | sort(attribute="scope") %} 22 | - {% if commit.breaking %}[**breaking**] {% endif %}_({{commit.scope}})_ {{ commit.message }} 23 | {%- endfor %} 24 | {% for commit in commits %} 25 | {%- if commit.scope -%} 26 | {% else -%} 27 | - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }} 28 | {% endif -%} 29 | {% endfor -%} 30 | {% raw %}{% endraw %}\ 31 | {% endfor %}\n 32 | """ 33 | # remove the leading and trailing whitespaces from the template 34 | trim = true 35 | # changelog footer 36 | footer = """ 37 | 38 | """ 39 | 40 | [git] 41 | # allow only conventional commits 42 | # https://www.conventionalcommits.org 43 | conventional_commits = true 44 | # filter out the commits that are not conventional 45 | filter_unconventional = true 46 | # regex for parsing and grouping commits 47 | commit_preprocessors = [ 48 | { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/lunarvim/lunarvim/pull/${2}))"}, 49 | ] 50 | commit_parsers = [ 51 | { message = "(.*[bB]ump)", group = " Miscellaneous Tasks", skip = true}, 52 | { message = "^[bB]uild", group = " Packaging"}, 53 | { message = "(^[fF]eat|^\\[Feat)", group = " Features"}, 54 | { message = "(^[bB]ug|^[Ff]ix|^\\[Bug)", group = " Bugfix"}, 55 | { message = "(^[rR]efactor|^ref)", group = " Refactor"}, 56 | { message = "^[dD]oc", group = " Documentation"}, 57 | { message = "^[rR]evert", group = " Revert"}, 58 | { message = "^[pP]erf", group = " Performance"}, 59 | { message = "^[cC]hore", group = " Miscellaneous Tasks", skip = true}, 60 | { message = "^ci", group = " Miscellaneous Tasks", skip = true}, 61 | { message = "^test", group = " Miscellaneous Tasks", skip = true}, 62 | { message = "[wW]orkflow", group = " Miscellaneous Tasks", skip = true}, 63 | ] 64 | # filter out the commits that are not matched by commit parsers 65 | filter_commits = false 66 | # glob pattern for matching git tags 67 | tag_pattern = "v[0-9]*" 68 | # regex for skipping tags 69 | skip_tags = "v0.1.0-beta.1" 70 | # regex for ignoring tags 71 | ignore_tags = "" 72 | # sort the tags topologically 73 | topo_order = false 74 | # sort the commits inside sections by oldest/newest order 75 | sort_commits = "oldest" 76 | # protect breaking changes from being skipped due to matching a skipping commit_parser 77 | protect_breaking_commits = false 78 | 79 | [features] 80 | preserve_order = ["serde_json/preserve_order"] 81 | -------------------------------------------------------------------------------- /utils/ci/generate_new_lockfile.lua: -------------------------------------------------------------------------------- 1 | local sp = os.getenv "SNAPSHOT_PATH" 2 | 3 | local function call_proc(process, opts, cb) 4 | local output, error_output = "", "" 5 | local handle_stdout = function(err, chunk) 6 | assert(not err, err) 7 | if chunk then 8 | output = output .. chunk 9 | end 10 | end 11 | 12 | local handle_stderr = function(err, chunk) 13 | assert(not err, err) 14 | if chunk then 15 | error_output = error_output .. chunk 16 | end 17 | end 18 | 19 | local uv = vim.loop 20 | local handle 21 | 22 | local stdout = uv.new_pipe(false) 23 | local stderr = uv.new_pipe(false) 24 | 25 | local stdio = { nil, stdout, stderr } 26 | 27 | handle = uv.spawn( 28 | process, 29 | { args = opts.args, cwd = opts.cwd or uv.cwd(), stdio = stdio }, 30 | vim.schedule_wrap(function(code) 31 | if code ~= 0 then 32 | stdout:read_stop() 33 | stderr:read_stop() 34 | end 35 | 36 | local check = uv.new_check() 37 | check:start(function() 38 | for _, pipe in ipairs(stdio) do 39 | if pipe and not pipe:is_closing() then 40 | return 41 | end 42 | end 43 | check:stop() 44 | handle:close() 45 | cb(code, output, error_output) 46 | end) 47 | end) 48 | ) 49 | 50 | uv.read_start(stdout, handle_stdout) 51 | uv.read_start(stderr, handle_stderr) 52 | 53 | return handle 54 | end 55 | 56 | local plugins_list = {} 57 | 58 | local completed = 0 59 | 60 | local function write_lockfile(verbose) 61 | local default_plugins = {} 62 | local active_jobs = {} 63 | 64 | local core_plugins = require "lvim.plugins" 65 | for _, plugin in pairs(core_plugins) do 66 | local name = plugin[1]:match "/(%S*)" 67 | local url = "https://github.com/" .. plugin[1] 68 | local commit = "" 69 | table.insert(default_plugins, { 70 | name = name, 71 | url = url, 72 | commit = commit, 73 | branch = plugin.branch or "HEAD", 74 | }) 75 | end 76 | 77 | table.sort(default_plugins, function(a, b) 78 | return a.name < b.name 79 | end) 80 | 81 | for _, entry in pairs(default_plugins) do 82 | local on_done = function(success, result, errors) 83 | completed = completed + 1 84 | if not success then 85 | print("error: " .. errors) 86 | return 87 | end 88 | local latest_sha = result:gsub("\tHEAD\n", ""):sub(1, 7) 89 | plugins_list[entry.name] = { 90 | commit = latest_sha, 91 | } 92 | end 93 | 94 | local handle = call_proc("git", { args = { "ls-remote", entry.url, entry.branch } }, on_done) 95 | assert(handle) 96 | table.insert(active_jobs, handle) 97 | end 98 | 99 | print("active: " .. #active_jobs) 100 | print("plugins: " .. #default_plugins) 101 | 102 | vim.wait(#active_jobs * 60 * 1000, function() 103 | return completed == #active_jobs 104 | end) 105 | 106 | if verbose then 107 | print(vim.inspect(plugins_list)) 108 | end 109 | 110 | local fd = assert(io.open(sp, "w")) 111 | fd:write(vim.json.encode(plugins_list), "\n") 112 | fd:flush() 113 | end 114 | 115 | write_lockfile() 116 | vim.cmd "q" 117 | -------------------------------------------------------------------------------- /lua/lvim/core/telescope/custom-finders.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local _, builtin = pcall(require, "telescope.builtin") 4 | local _, finders = pcall(require, "telescope.finders") 5 | local _, pickers = pcall(require, "telescope.pickers") 6 | local _, sorters = pcall(require, "telescope.sorters") 7 | local _, themes = pcall(require, "telescope.themes") 8 | local _, actions = pcall(require, "telescope.actions") 9 | local _, previewers = pcall(require, "telescope.previewers") 10 | local _, make_entry = pcall(require, "telescope.make_entry") 11 | 12 | function M.find_lunarvim_files(opts) 13 | opts = opts or {} 14 | local theme_opts = themes.get_ivy { 15 | sorting_strategy = "ascending", 16 | layout_strategy = "bottom_pane", 17 | prompt_prefix = ">> ", 18 | prompt_title = "~ LunarVim files ~", 19 | cwd = get_runtime_dir(), 20 | search_dirs = { get_lvim_base_dir(), lvim.lsp.templates_dir }, 21 | } 22 | opts = vim.tbl_deep_extend("force", theme_opts, opts) 23 | builtin.find_files(opts) 24 | end 25 | 26 | function M.grep_lunarvim_files(opts) 27 | opts = opts or {} 28 | local theme_opts = themes.get_ivy { 29 | sorting_strategy = "ascending", 30 | layout_strategy = "bottom_pane", 31 | prompt_prefix = ">> ", 32 | prompt_title = "~ search LunarVim ~", 33 | cwd = get_runtime_dir(), 34 | search_dirs = { get_lvim_base_dir(), lvim.lsp.templates_dir }, 35 | } 36 | opts = vim.tbl_deep_extend("force", theme_opts, opts) 37 | builtin.live_grep(opts) 38 | end 39 | 40 | local copy_to_clipboard_action = function(prompt_bufnr) 41 | local _, action_state = pcall(require, "telescope.actions.state") 42 | local entry = action_state.get_selected_entry() 43 | local version = entry.value 44 | vim.fn.setreg("+", version) 45 | vim.fn.setreg('"', version) 46 | vim.notify("Copied " .. version .. " to clipboard", vim.log.levels.INFO) 47 | actions.close(prompt_bufnr) 48 | end 49 | 50 | function M.view_lunarvim_changelog() 51 | local opts = themes.get_ivy { 52 | cwd = get_lvim_base_dir(), 53 | } 54 | opts.entry_maker = make_entry.gen_from_git_commits(opts) 55 | 56 | pickers 57 | .new(opts, { 58 | prompt_title = "~ LunarVim Changelog ~", 59 | 60 | finder = finders.new_oneshot_job( 61 | vim.tbl_flatten { 62 | "git", 63 | "log", 64 | "--pretty=oneline", 65 | "--abbrev-commit", 66 | }, 67 | opts 68 | ), 69 | previewer = { 70 | previewers.git_commit_diff_as_was.new(opts), 71 | }, 72 | 73 | --TODO: consider opening a diff view when pressing enter 74 | attach_mappings = function(_, map) 75 | map("i", "", copy_to_clipboard_action) 76 | map("n", "", copy_to_clipboard_action) 77 | map("i", "", actions._close) 78 | map("n", "", actions._close) 79 | map("n", "q", actions._close) 80 | return true 81 | end, 82 | sorter = sorters.generic_sorter, 83 | }) 84 | :find() 85 | end 86 | 87 | -- Smartly opens either git_files or find_files, depending on whether the working directory is 88 | -- contained in a Git repo. 89 | function M.find_project_files(opts) 90 | opts = opts or {} 91 | local ok = pcall(builtin.git_files, opts) 92 | 93 | if not ok then 94 | builtin.find_files(opts) 95 | end 96 | end 97 | 98 | return M 99 | -------------------------------------------------------------------------------- /lua/lvim/core/lir.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.config = function() 4 | lvim.builtin.lir = { 5 | active = true, 6 | on_config_done = nil, 7 | icon = "", 8 | } 9 | 10 | local status_ok, _ = pcall(require, "lir") 11 | if not status_ok then 12 | return 13 | end 14 | 15 | local actions = require "lir.actions" 16 | local mark_actions = require "lir.mark.actions" 17 | local clipboard_actions = require "lir.clipboard.actions" 18 | 19 | lvim.builtin.lir = vim.tbl_extend("force", lvim.builtin.lir, { 20 | show_hidden_files = false, 21 | devicons_enable = true, 22 | mappings = { 23 | ["l"] = actions.edit, 24 | [""] = actions.edit, 25 | [""] = actions.split, 26 | ["v"] = actions.vsplit, 27 | [""] = actions.tabedit, 28 | 29 | ["h"] = actions.up, 30 | ["q"] = actions.quit, 31 | 32 | ["A"] = actions.mkdir, 33 | ["a"] = actions.newfile, 34 | ["r"] = actions.rename, 35 | ["@"] = actions.cd, 36 | ["Y"] = actions.yank_path, 37 | ["i"] = actions.toggle_show_hidden, 38 | ["d"] = actions.delete, 39 | 40 | ["J"] = function() 41 | mark_actions.toggle_mark() 42 | vim.cmd "normal! j" 43 | end, 44 | ["c"] = clipboard_actions.copy, 45 | ["x"] = clipboard_actions.cut, 46 | ["p"] = clipboard_actions.paste, 47 | }, 48 | float = { 49 | winblend = 0, 50 | curdir_window = { 51 | enable = false, 52 | highlight_dirname = true, 53 | }, 54 | 55 | -- -- You can define a function that returns a table to be passed as the third 56 | -- -- argument of nvim_open_win(). 57 | win_opts = function() 58 | local width = math.floor(vim.o.columns * 0.7) 59 | local height = math.floor(vim.o.lines * 0.7) 60 | return { 61 | border = "rounded", 62 | width = width, 63 | height = height, 64 | -- row = 1, 65 | -- col = math.floor((vim.o.columns - width) / 2), 66 | } 67 | end, 68 | }, 69 | hide_cursor = false, 70 | on_init = function() 71 | -- use visual mode 72 | vim.api.nvim_buf_set_keymap( 73 | 0, 74 | "x", 75 | "J", 76 | ':lua require"lir.mark.actions".toggle_mark("v")', 77 | { noremap = true, silent = true } 78 | ) 79 | 80 | -- echo cwd 81 | -- vim.api.nvim_echo({ { vim.fn.expand "%:p", "Normal" } }, false, {}) 82 | end, 83 | }) 84 | end 85 | 86 | function M.icon_setup() 87 | local function get_hl_by_name(name) 88 | local ret = vim.api.nvim_get_hl_by_name(name.group, true) 89 | return string.format("#%06x", ret[name.property]) 90 | end 91 | 92 | local found, icon_hl = pcall(get_hl_by_name, { group = "NvimTreeFolderIcon", property = "foreground" }) 93 | if not found then 94 | icon_hl = "#42A5F5" 95 | end 96 | 97 | require("nvim-web-devicons").set_icon { 98 | lir_folder_icon = { 99 | icon = lvim.builtin.lir.icon, 100 | color = icon_hl, 101 | name = "LirFolderNode", 102 | }, 103 | } 104 | end 105 | 106 | function M.setup() 107 | local status_ok, lir = pcall(reload, "lir") 108 | if not status_ok then 109 | return 110 | end 111 | lir.setup(lvim.builtin.lir) 112 | 113 | if lvim.builtin.lir.on_config_done then 114 | lvim.builtin.lir.on_config_done(lir) 115 | end 116 | end 117 | 118 | return M 119 | -------------------------------------------------------------------------------- /lua/lvim/core/theme.lua: -------------------------------------------------------------------------------- 1 | local Log = require "lvim.core.log" 2 | 3 | local M = {} 4 | 5 | M.config = function() 6 | lvim.builtin.theme = { 7 | name = "lunar", 8 | lunar = { 9 | options = { -- currently unused 10 | }, 11 | }, 12 | tokyonight = { 13 | options = { 14 | on_highlights = function(hl, c) 15 | hl.IndentBlanklineContextChar = { 16 | fg = c.dark5, 17 | } 18 | hl.TSConstructor = { 19 | fg = c.blue1, 20 | } 21 | hl.TSTagDelimiter = { 22 | fg = c.dark5, 23 | } 24 | end, 25 | style = "night", -- The theme comes in three styles, `storm`, a darker variant `night` and `day` 26 | transparent = lvim.transparent_window, -- Enable this to disable setting the background color 27 | terminal_colors = true, -- Configure the colors used when opening a `:terminal` in Neovim 28 | styles = { 29 | -- Style to be applied to different syntax groups 30 | -- Value is any valid attr-list value for `:help nvim_set_hl` 31 | comments = { italic = true }, 32 | keywords = { italic = true }, 33 | functions = {}, 34 | variables = {}, 35 | -- Background styles. Can be "dark", "transparent" or "normal" 36 | sidebars = "dark", -- style for sidebars, see below 37 | floats = "dark", -- style for floating windows 38 | }, 39 | -- Set a darker background on sidebar-like windows. For example: `["qf", "vista_kind", "terminal", "packer"]` 40 | sidebars = { 41 | "qf", 42 | "vista_kind", 43 | "terminal", 44 | "packer", 45 | "spectre_panel", 46 | "NeogitStatus", 47 | "help", 48 | }, 49 | day_brightness = 0.3, -- Adjusts the brightness of the colors of the **Day** style. Number between 0 and 1, from dull to vibrant colors 50 | hide_inactive_statusline = false, -- Enabling this option, will hide inactive statuslines and replace them with a thin border instead. Should work with the standard **StatusLine** and **LuaLine**. 51 | dim_inactive = false, -- dims inactive windows 52 | lualine_bold = false, -- When `true`, section headers in the lualine theme will be bold 53 | use_background = true, -- can be light/dark/auto. When auto, background will be set to vim.o.background 54 | }, 55 | }, 56 | } 57 | end 58 | 59 | M.setup = function() 60 | -- avoid running in headless mode since it's harder to detect failures 61 | if #vim.api.nvim_list_uis() == 0 then 62 | Log:debug "headless mode detected, skipping running setup for lualine" 63 | return 64 | end 65 | 66 | local selected_theme = lvim.builtin.theme.name 67 | local status_ok, plugin = pcall(require, selected_theme) 68 | if not status_ok then 69 | return 70 | end 71 | pcall(function() 72 | plugin.setup(lvim.builtin.theme[selected_theme].options) 73 | end) 74 | 75 | -- ref: https://github.com/neovim/neovim/issues/18201#issuecomment-1104754564 76 | local colors = vim.api.nvim_get_runtime_file(("colors/%s.*"):format(lvim.colorscheme), false) 77 | if #colors == 0 then 78 | Log:debug(string.format("Could not find '%s' colorscheme", lvim.colorscheme)) 79 | return 80 | end 81 | 82 | vim.g.colors_name = lvim.colorscheme 83 | vim.cmd("colorscheme " .. lvim.colorscheme) 84 | 85 | require("lvim.core.lualine").setup() 86 | require("lvim.core.lir").icon_setup() 87 | end 88 | 89 | return M 90 | -------------------------------------------------------------------------------- /lua/lvim/core/autopairs.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.config() 4 | lvim.builtin.autopairs = { 5 | active = true, 6 | on_config_done = nil, 7 | ---@usage modifies the function or method delimiter by filetypes 8 | map_char = { 9 | all = "(", 10 | tex = "{", 11 | }, 12 | ---@usage check bracket in same line 13 | enable_check_bracket_line = false, 14 | ---@usage check treesitter 15 | check_ts = true, 16 | ts_config = { 17 | lua = { "string", "source" }, 18 | javascript = { "string", "template_string" }, 19 | java = false, 20 | }, 21 | disable_filetype = { "TelescopePrompt", "spectre_panel" }, 22 | ignored_next_char = string.gsub([[ [%w%%%'%[%"%.] ]], "%s+", ""), 23 | enable_moveright = true, 24 | ---@usage disable when recording or executing a macro 25 | disable_in_macro = false, 26 | ---@usage add bracket pairs after quote 27 | enable_afterquote = true, 28 | ---@usage map the key 29 | map_bs = true, 30 | ---@usage map to delete a pair if possible 31 | map_c_w = false, 32 | ---@usage disable when insert after visual block mode 33 | disable_in_visualblock = false, 34 | ---@usage change default fast_wrap 35 | fast_wrap = { 36 | map = "", 37 | chars = { "{", "[", "(", '"', "'" }, 38 | pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""), 39 | offset = 0, -- Offset from pattern match 40 | end_key = "$", 41 | keys = "qwertyuiopzxcvbnmasdfghjkl", 42 | check_comma = true, 43 | highlight = "Search", 44 | highlight_grey = "Comment", 45 | }, 46 | } 47 | end 48 | 49 | local function on_confirm_done(...) 50 | require("nvim-autopairs.completion.cmp").on_confirm_done()(...) 51 | end 52 | 53 | M.setup = function() 54 | local status_ok, autopairs = pcall(require, "nvim-autopairs") 55 | if not status_ok then 56 | return 57 | end 58 | local Rule = require "nvim-autopairs.rule" 59 | 60 | autopairs.setup { 61 | check_ts = lvim.builtin.autopairs.check_ts, 62 | enable_check_bracket_line = lvim.builtin.autopairs.enable_check_bracket_line, 63 | ts_config = lvim.builtin.autopairs.ts_config, 64 | disable_filetype = lvim.builtin.autopairs.disable_filetype, 65 | disable_in_macro = lvim.builtin.autopairs.disable_in_macro, 66 | ignored_next_char = lvim.builtin.autopairs.ignored_next_char, 67 | enable_moveright = lvim.builtin.autopairs.enable_moveright, 68 | enable_afterquote = lvim.builtin.autopairs.enable_afterquote, 69 | map_c_w = lvim.builtin.autopairs.map_c_w, 70 | map_bs = lvim.builtin.autopairs.map_bs, 71 | disable_in_visualblock = lvim.builtin.autopairs.disable_in_visualblock, 72 | fast_wrap = lvim.builtin.autopairs.fast_wrap, 73 | } 74 | 75 | require("nvim-treesitter.configs").setup { autopairs = { enable = true } } 76 | 77 | local ts_conds = require "nvim-autopairs.ts-conds" 78 | 79 | -- TODO: can these rules be safely added from "config.lua" ? 80 | -- press % => %% is only inside comment or string 81 | autopairs.add_rules { 82 | Rule("%", "%", "lua"):with_pair(ts_conds.is_ts_node { "string", "comment" }), 83 | Rule("$", "$", "lua"):with_pair(ts_conds.is_not_ts_node { "function" }), 84 | } 85 | 86 | if lvim.builtin.autopairs.on_config_done then 87 | lvim.builtin.autopairs.on_config_done(autopairs) 88 | end 89 | pcall(function() 90 | require "nvim-autopairs.completion.cmp" 91 | require("cmp").event:off("confirm_done", on_confirm_done) 92 | require("cmp").event:on("confirm_done", on_confirm_done) 93 | end) 94 | end 95 | 96 | return M 97 | -------------------------------------------------------------------------------- /lua/lvim/utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | local uv = vim.loop 3 | 4 | -- recursive Print (structure, limit, separator) 5 | local function r_inspect_settings(structure, limit, separator) 6 | limit = limit or 100 -- default item limit 7 | separator = separator or "." -- indent string 8 | if limit < 1 then 9 | print "ERROR: Item limit reached." 10 | return limit - 1 11 | end 12 | if structure == nil then 13 | io.write("-- O", separator:sub(2), " = nil\n") 14 | return limit - 1 15 | end 16 | local ts = type(structure) 17 | 18 | if ts == "table" then 19 | for k, v in pairs(structure) do 20 | -- replace non alpha keys with ["key"] 21 | if tostring(k):match "[^%a_]" then 22 | k = '["' .. tostring(k) .. '"]' 23 | end 24 | limit = r_inspect_settings(v, limit, separator .. "." .. tostring(k)) 25 | if limit < 0 then 26 | break 27 | end 28 | end 29 | return limit 30 | end 31 | 32 | if ts == "string" then 33 | -- escape sequences 34 | structure = string.format("%q", structure) 35 | end 36 | separator = separator:gsub("%.%[", "%[") 37 | if type(structure) == "function" then 38 | -- don't print functions 39 | io.write("-- lvim", separator:sub(2), " = function ()\n") 40 | else 41 | io.write("lvim", separator:sub(2), " = ", tostring(structure), "\n") 42 | end 43 | return limit - 1 44 | end 45 | 46 | function M.generate_settings() 47 | -- Opens a file in append mode 48 | local file = io.open("lv-settings.lua", "w") 49 | 50 | -- sets the default output file as test.lua 51 | io.output(file) 52 | 53 | -- write all `lvim` related settings to `lv-settings.lua` file 54 | r_inspect_settings(lvim, 10000, ".") 55 | 56 | -- closes the open file 57 | io.close(file) 58 | end 59 | 60 | --- Returns a table with the default values that are missing. 61 | --- either parameter can be empty. 62 | --@param config (table) table containing entries that take priority over defaults 63 | --@param default_config (table) table contatining default values if found 64 | function M.apply_defaults(config, default_config) 65 | config = config or {} 66 | default_config = default_config or {} 67 | local new_config = vim.tbl_deep_extend("keep", vim.empty_dict(), config) 68 | new_config = vim.tbl_deep_extend("keep", new_config, default_config) 69 | return new_config 70 | end 71 | 72 | --- Checks whether a given path exists and is a file. 73 | --@param path (string) path to check 74 | --@returns (bool) 75 | function M.is_file(path) 76 | local stat = uv.fs_stat(path) 77 | return stat and stat.type == "file" or false 78 | end 79 | 80 | --- Checks whether a given path exists and is a directory 81 | --@param path (string) path to check 82 | --@returns (bool) 83 | function M.is_directory(path) 84 | local stat = uv.fs_stat(path) 85 | return stat and stat.type == "directory" or false 86 | end 87 | 88 | M.join_paths = _G.join_paths 89 | 90 | ---Write data to a file 91 | ---@param path string can be full or relative to `cwd` 92 | ---@param txt string|table text to be written, uses `vim.inspect` internally for tables 93 | ---@param flag string used to determine access mode, common flags: "w" for `overwrite` or "a" for `append` 94 | function M.write_file(path, txt, flag) 95 | local data = type(txt) == "string" and txt or vim.inspect(txt) 96 | uv.fs_open(path, flag, 438, function(open_err, fd) 97 | assert(not open_err, open_err) 98 | uv.fs_write(fd, data, -1, function(write_err) 99 | assert(not write_err, write_err) 100 | uv.fs_close(fd, function(close_err) 101 | assert(not close_err, close_err) 102 | end) 103 | end) 104 | end) 105 | end 106 | 107 | return M 108 | -------------------------------------------------------------------------------- /lua/lvim/lsp/null-ls/services.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | 5 | local function find_root_dir() 6 | local util = require "lspconfig/util" 7 | local lsp_utils = require "lvim.lsp.utils" 8 | 9 | local ts_client = lsp_utils.is_client_active "typescript" 10 | if ts_client then 11 | return ts_client.config.root_dir 12 | end 13 | local dirname = vim.fn.expand "%:p:h" 14 | return util.root_pattern "package.json"(dirname) 15 | end 16 | 17 | local function from_node_modules(command) 18 | local root_dir = find_root_dir() 19 | 20 | if not root_dir then 21 | return nil 22 | end 23 | 24 | local join_paths = require("lvim.utils").join_paths 25 | return join_paths(root_dir, "node_modules", ".bin", command) 26 | end 27 | 28 | local local_providers = { 29 | prettier = { find = from_node_modules }, 30 | prettierd = { find = from_node_modules }, 31 | prettier_d_slim = { find = from_node_modules }, 32 | eslint_d = { find = from_node_modules }, 33 | eslint = { find = from_node_modules }, 34 | stylelint = { find = from_node_modules }, 35 | } 36 | 37 | function M.find_command(command) 38 | if local_providers[command] then 39 | local local_command = local_providers[command].find(command) 40 | if local_command and vim.fn.executable(local_command) == 1 then 41 | return local_command 42 | end 43 | end 44 | 45 | if command and vim.fn.executable(command) == 1 then 46 | return command 47 | end 48 | return nil 49 | end 50 | 51 | function M.list_registered_providers_names(filetype) 52 | local s = require "null-ls.sources" 53 | local available_sources = s.get_available(filetype) 54 | local registered = {} 55 | for _, source in ipairs(available_sources) do 56 | for method in pairs(source.methods) do 57 | registered[method] = registered[method] or {} 58 | table.insert(registered[method], source.name) 59 | end 60 | end 61 | return registered 62 | end 63 | 64 | function M.register_sources(configs, method) 65 | local null_ls = require "null-ls" 66 | local is_registered = require("null-ls.sources").is_registered 67 | 68 | local sources, registered_names = {}, {} 69 | 70 | for _, config in ipairs(configs) do 71 | local cmd = config.exe or config.command 72 | local name = config.name or cmd:gsub("-", "_") 73 | local type = method == null_ls.methods.CODE_ACTION and "code_actions" or null_ls.methods[method]:lower() 74 | local source = type and null_ls.builtins[type][name] 75 | Log:debug(string.format("Received request to register [%s] as a %s source", name, type)) 76 | if not source then 77 | Log:error("Not a valid source: " .. name) 78 | elseif is_registered { name = source.name or name, method = method } then 79 | Log:trace(string.format("Skipping registering [%s] more than once", name)) 80 | else 81 | local command = M.find_command(source._opts.command) or source._opts.command 82 | 83 | -- treat `args` as `extra_args` for backwards compatibility. Can otherwise use `generator_opts.args` 84 | local compat_opts = vim.deepcopy(config) 85 | if config.args then 86 | compat_opts.extra_args = config.args or config.extra_args 87 | compat_opts.args = nil 88 | end 89 | 90 | local opts = vim.tbl_deep_extend("keep", { command = command }, compat_opts) 91 | Log:debug("Registering source " .. name) 92 | Log:trace(vim.inspect(opts)) 93 | table.insert(sources, source.with(opts)) 94 | vim.list_extend(registered_names, { source.name }) 95 | end 96 | end 97 | 98 | if #sources > 0 then 99 | null_ls.register { sources = sources } 100 | end 101 | return registered_names 102 | end 103 | 104 | return M 105 | -------------------------------------------------------------------------------- /lua/lvim/icons.lua: -------------------------------------------------------------------------------- 1 | return { 2 | kind = { 3 | Array = "", 4 | Boolean = "蘒", 5 | Class = "", 6 | Color = "", 7 | Constant = "", 8 | Constructor = "", 9 | Enum = "", 10 | EnumMember = "", 11 | Event = "", 12 | Field = "", 13 | File = "", 14 | Folder = "", 15 | Function = "", 16 | Interface = "", 17 | Key = "", 18 | Keyword = "", 19 | Method = "", 20 | Module = "", 21 | Namespace = "", 22 | Null = "ﳠ", 23 | Number = "", 24 | Object = "", 25 | Operator = "", 26 | Package = "", 27 | Property = "", 28 | Reference = "", 29 | Snippet = "", 30 | String = "", 31 | Struct = "", 32 | Text = "", 33 | TypeParameter = "", 34 | Unit = "", 35 | Value = "", 36 | Variable = "", 37 | }, 38 | git = { 39 | LineAdded = "", 40 | LineModified = "", 41 | LineRemoved = "", 42 | FileDeleted = "", 43 | FileIgnored = "◌", 44 | FileRenamed = "➜", 45 | FileStaged = "S", 46 | FileUnmerged = "", 47 | FileUnstaged = "", 48 | FileUntracked = "U", 49 | Diff = "", 50 | Repo = "", 51 | Octoface = "", 52 | Branch = "", 53 | }, 54 | ui = { 55 | ArrowCircleDown = "", 56 | ArrowCircleLeft = "", 57 | ArrowCircleRight = "", 58 | ArrowCircleUp = "", 59 | BoldArrowDown = "", 60 | BoldArrowLeft = "", 61 | BoldArrowRight = "", 62 | BoldArrowUp = "", 63 | BoldClose = "", 64 | BoldDividerLeft = "", 65 | BoldDividerRight = "", 66 | BoldLineLeft = "▎", 67 | BookMark = "", 68 | BoxChecked = "", 69 | Bug = "", 70 | Stacks = " ", 71 | Scopes = "", 72 | Watches = "", 73 | DebugConsole = " ", 74 | Calendar = "", 75 | Check = "", 76 | ChevronRight = ">", 77 | ChevronShortDown = "", 78 | ChevronShortLeft = "", 79 | ChevronShortRight = "", 80 | ChevronShortUp = "", 81 | Circle = "", 82 | Close = "", 83 | CloudDownload = "", 84 | Code = "", 85 | Comment = "", 86 | Dashboard = "", 87 | DividerLeft = "", 88 | DividerRight = "", 89 | DoubleChevronRight = "»", 90 | Ellipsis = "…", 91 | EmptyFolder = "", 92 | EmptyFolderOpen = "", 93 | File = "", 94 | FileSymlink = "", 95 | Files = "", 96 | FindFile = "", 97 | FindText = "", 98 | Fire = "", 99 | Folder = "", 100 | FolderOpen = "", 101 | FolderSymlink = "", 102 | Forward = "", 103 | Gear = "", 104 | History = "", 105 | Lightbulb = "", 106 | LineLeft = "▏", 107 | LineMiddle = "│", 108 | List = "", 109 | Lock = "", 110 | NewFile = "", 111 | Note = "", 112 | Package = "", 113 | Pencil = "", 114 | Plus = "", 115 | Project = "", 116 | Search = "", 117 | SignIn = "", 118 | SignOut = "", 119 | Tab = "", 120 | Table = "", 121 | Target = "", 122 | Telescope = "", 123 | Text = "", 124 | Tree = "", 125 | Triangle = "契", 126 | TriangleShortArrowDown = "", 127 | TriangleShortArrowLeft = "", 128 | TriangleShortArrowRight = "", 129 | TriangleShortArrowUp = "", 130 | }, 131 | diagnostics = { 132 | BoldError = "", 133 | Error = "", 134 | BoldWarning = "", 135 | Warning = "", 136 | BoldInformation = "", 137 | Information = "", 138 | BoldQuestion = "", 139 | Question = "", 140 | BoldHint = "", 141 | Hint = "", 142 | Debug = "", 143 | Trace = "✎", 144 | }, 145 | misc = { 146 | Robot = "ﮧ", 147 | Squirrel = "", 148 | Tag = "", 149 | Watch = "", 150 | Smiley = "ﲃ", 151 | Package = "", 152 | CircuitBoard = "", 153 | }, 154 | } 155 | -------------------------------------------------------------------------------- /lua/lvim/lsp/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | local Log = require "lvim.core.log" 3 | local utils = require "lvim.utils" 4 | local autocmds = require "lvim.core.autocmds" 5 | 6 | local function add_lsp_buffer_options(bufnr) 7 | for k, v in pairs(lvim.lsp.buffer_options) do 8 | vim.api.nvim_buf_set_option(bufnr, k, v) 9 | end 10 | end 11 | 12 | local function add_lsp_buffer_keybindings(bufnr) 13 | local mappings = { 14 | normal_mode = "n", 15 | insert_mode = "i", 16 | visual_mode = "v", 17 | } 18 | 19 | for mode_name, mode_char in pairs(mappings) do 20 | for key, remap in pairs(lvim.lsp.buffer_mappings[mode_name]) do 21 | local opts = { buffer = bufnr, desc = remap[2], noremap = true, silent = true } 22 | vim.keymap.set(mode_char, key, remap[1], opts) 23 | end 24 | end 25 | end 26 | 27 | function M.common_capabilities() 28 | local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") 29 | if status_ok then 30 | return cmp_nvim_lsp.default_capabilities() 31 | end 32 | 33 | local capabilities = vim.lsp.protocol.make_client_capabilities() 34 | capabilities.textDocument.completion.completionItem.snippetSupport = true 35 | capabilities.textDocument.completion.completionItem.resolveSupport = { 36 | properties = { 37 | "documentation", 38 | "detail", 39 | "additionalTextEdits", 40 | }, 41 | } 42 | 43 | return capabilities 44 | end 45 | 46 | function M.common_on_exit(_, _) 47 | if lvim.lsp.document_highlight then 48 | autocmds.clear_augroup "lsp_document_highlight" 49 | end 50 | if lvim.lsp.code_lens_refresh then 51 | autocmds.clear_augroup "lsp_code_lens_refresh" 52 | end 53 | end 54 | 55 | function M.common_on_init(client, bufnr) 56 | if lvim.lsp.on_init_callback then 57 | lvim.lsp.on_init_callback(client, bufnr) 58 | Log:debug "Called lsp.on_init_callback" 59 | return 60 | end 61 | end 62 | 63 | function M.common_on_attach(client, bufnr) 64 | if lvim.lsp.on_attach_callback then 65 | lvim.lsp.on_attach_callback(client, bufnr) 66 | Log:debug "Called lsp.on_attach_callback" 67 | end 68 | local lu = require "lvim.lsp.utils" 69 | if lvim.lsp.document_highlight then 70 | lu.setup_document_highlight(client, bufnr) 71 | end 72 | if lvim.lsp.code_lens_refresh then 73 | lu.setup_codelens_refresh(client, bufnr) 74 | end 75 | add_lsp_buffer_keybindings(bufnr) 76 | add_lsp_buffer_options(bufnr) 77 | lu.setup_document_symbols(client, bufnr) 78 | end 79 | 80 | function M.get_common_opts() 81 | return { 82 | on_attach = M.common_on_attach, 83 | on_init = M.common_on_init, 84 | on_exit = M.common_on_exit, 85 | capabilities = M.common_capabilities(), 86 | } 87 | end 88 | 89 | function M.setup() 90 | Log:debug "Setting up LSP support" 91 | 92 | local lsp_status_ok, _ = pcall(require, "lspconfig") 93 | if not lsp_status_ok then 94 | return 95 | end 96 | 97 | if lvim.use_icons then 98 | for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do 99 | vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name }) 100 | end 101 | end 102 | 103 | require("lvim.lsp.handlers").setup() 104 | 105 | if not utils.is_directory(lvim.lsp.templates_dir) then 106 | require("lvim.lsp.templates").generate_templates() 107 | end 108 | 109 | pcall(function() 110 | require("nlspsettings").setup(lvim.lsp.nlsp_settings.setup) 111 | end) 112 | 113 | pcall(function() 114 | require("mason-lspconfig").setup(lvim.lsp.installer.setup) 115 | local util = require "lspconfig.util" 116 | -- automatic_installation is handled by lsp-manager 117 | util.on_setup = nil 118 | end) 119 | 120 | require("lvim.lsp.null-ls").setup() 121 | 122 | autocmds.configure_format_on_save() 123 | end 124 | 125 | return M 126 | -------------------------------------------------------------------------------- /lua/lvim/config/settings.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.load_default_options = function() 4 | local utils = require "lvim.utils" 5 | local join_paths = utils.join_paths 6 | 7 | local undodir = join_paths(get_cache_dir(), "undo") 8 | 9 | if not utils.is_directory(undodir) then 10 | vim.fn.mkdir(undodir, "p") 11 | end 12 | 13 | local default_options = { 14 | backup = false, -- creates a backup file 15 | clipboard = "unnamedplus", -- allows neovim to access the system clipboard 16 | cmdheight = 1, -- more space in the neovim command line for displaying messages 17 | completeopt = { "menuone", "noselect" }, 18 | conceallevel = 0, -- so that `` is visible in markdown files 19 | fileencoding = "utf-8", -- the encoding written to a file 20 | foldmethod = "manual", -- folding, set to "expr" for treesitter based folding 21 | foldexpr = "", -- set to "nvim_treesitter#foldexpr()" for treesitter based folding 22 | guifont = "monospace:h17", -- the font used in graphical neovim applications 23 | hidden = true, -- required to keep multiple buffers and open multiple buffers 24 | hlsearch = true, -- highlight all matches on previous search pattern 25 | ignorecase = true, -- ignore case in search patterns 26 | mouse = "a", -- allow the mouse to be used in neovim 27 | pumheight = 10, -- pop up menu height 28 | showmode = false, -- we don't need to see things like -- INSERT -- anymore 29 | showtabline = 2, -- always show tabs 30 | smartcase = true, -- smart case 31 | splitbelow = true, -- force all horizontal splits to go below current window 32 | splitright = true, -- force all vertical splits to go to the right of current window 33 | swapfile = false, -- creates a swapfile 34 | termguicolors = true, -- set term gui colors (most terminals support this) 35 | timeoutlen = 1000, -- time to wait for a mapped sequence to complete (in milliseconds) 36 | title = true, -- set the title of window to the value of the titlestring 37 | -- opt.titlestring = "%<%F%=%l/%L - nvim" -- what the title of the window will be set to 38 | undodir = undodir, -- set an undo directory 39 | undofile = true, -- enable persistent undo 40 | updatetime = 100, -- faster completion 41 | writebackup = false, -- if a file is being edited by another program (or was written to file while editing with another program), it is not allowed to be edited 42 | expandtab = true, -- convert tabs to spaces 43 | shiftwidth = 2, -- the number of spaces inserted for each indentation 44 | tabstop = 2, -- insert 2 spaces for a tab 45 | cursorline = true, -- highlight the current line 46 | number = true, -- set numbered lines 47 | numberwidth = 4, -- set number column width to 2 {default 4} 48 | signcolumn = "yes", -- always show the sign column, otherwise it would shift the text each time 49 | wrap = false, -- display lines as one long line 50 | shadafile = join_paths(get_cache_dir(), "lvim.shada"), 51 | scrolloff = 8, -- minimal number of screen lines to keep above and below the cursor. 52 | sidescrolloff = 8, -- minimal number of screen lines to keep left and right of the cursor. 53 | showcmd = false, 54 | ruler = false, 55 | laststatus = 3, 56 | } 57 | 58 | --- SETTINGS --- 59 | vim.opt.spelllang:append "cjk" -- disable spellchecking for asian characters (VIM algorithm does not support it) 60 | vim.opt.shortmess:append "c" -- don't show redundant messages from ins-completion-menu 61 | vim.opt.shortmess:append "I" -- don't show the default intro message 62 | vim.opt.whichwrap:append "<,>,[,],h,l" 63 | 64 | for k, v in pairs(default_options) do 65 | vim.opt[k] = v 66 | end 67 | end 68 | 69 | M.load_headless_options = function() 70 | vim.opt.shortmess = "" -- try to prevent echom from cutting messages off or prompting 71 | vim.opt.more = false -- don't pause listing when screen is filled 72 | vim.opt.cmdheight = 9999 -- helps avoiding |hit-enter| prompts. 73 | vim.opt.columns = 9999 -- set the widest screen possible 74 | vim.opt.swapfile = false -- don't use a swap file 75 | end 76 | 77 | M.load_defaults = function() 78 | if #vim.api.nvim_list_uis() == 0 then 79 | M.load_headless_options() 80 | return 81 | end 82 | M.load_default_options() 83 | end 84 | 85 | return M 86 | -------------------------------------------------------------------------------- /utils/desktop/48x48/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/minimal_lsp.lua: -------------------------------------------------------------------------------- 1 | local on_windows = vim.loop.os_uname().version:match "Windows" 2 | 3 | local function join_paths(...) 4 | local path_sep = on_windows and "\\" or "/" 5 | local result = table.concat({ ... }, path_sep) 6 | return result 7 | end 8 | 9 | vim.cmd [[set runtimepath=$VIMRUNTIME]] 10 | 11 | local temp_dir = vim.loop.os_getenv "TEMP" or "/tmp" 12 | 13 | vim.cmd("set packpath=" .. join_paths(temp_dir, "nvim", "site")) 14 | 15 | local package_root = join_paths(temp_dir, "nvim", "site", "pack") 16 | local install_path = join_paths(package_root, "packer", "start", "packer.nvim") 17 | local compile_path = join_paths(install_path, "plugin", "packer_compiled.lua") 18 | 19 | -- Choose whether to use the executable that's managed by mason 20 | local use_lsp_installer = true 21 | 22 | local function load_plugins() 23 | require("packer").startup { 24 | { 25 | "wbthomason/packer.nvim", 26 | "neovim/nvim-lspconfig", 27 | "williamboman/mason-lspconfig.nvim", 28 | "williamboman/mason.nvim", 29 | }, 30 | config = { 31 | package_root = package_root, 32 | compile_path = compile_path, 33 | }, 34 | } 35 | end 36 | 37 | function _G.dump(...) 38 | local objects = vim.tbl_map(vim.inspect, { ... }) 39 | print(unpack(objects)) 40 | return ... 41 | end 42 | 43 | _G.load_config = function() 44 | vim.lsp.set_log_level "trace" 45 | require("vim.lsp.log").set_format_func(vim.inspect) 46 | local nvim_lsp = require "lspconfig" 47 | local on_attach = function(_, bufnr) 48 | local function buf_set_option(...) 49 | vim.api.nvim_buf_set_option(bufnr, ...) 50 | end 51 | 52 | buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc") 53 | 54 | -- Mappings. 55 | local opts = { buffer = bufnr, noremap = true, silent = true } 56 | vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts) 57 | vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts) 58 | vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) 59 | vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts) 60 | vim.keymap.set("n", "", vim.lsp.buf.signature_help, opts) 61 | vim.keymap.set("n", "wa", vim.lsp.buf.add_workspace_folder, opts) 62 | vim.keymap.set("n", "wr", vim.lsp.buf.remove_workspace_folder, opts) 63 | vim.keymap.set("n", "wl", function() 64 | print(vim.inspect(vim.lsp.buf.list_workspace_folders())) 65 | end, opts) 66 | vim.keymap.set("n", "lD", vim.lsp.buf.type_definition, opts) 67 | vim.keymap.set("n", "lr", vim.lsp.buf.rename, opts) 68 | vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) 69 | vim.keymap.set("n", "gl", vim.diagnostic.open_float, opts) 70 | vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) 71 | vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) 72 | vim.keymap.set("n", "q", vim.diagnostic.setloclist, opts) 73 | vim.keymap.set("n", "li", "LspInfo", opts) 74 | vim.keymap.set("n", "lI", "Mason", opts) 75 | end 76 | 77 | -- Add the server that troubles you here, e.g. "clangd", "pyright", "tsserver" 78 | local name = "sumneko_lua" 79 | 80 | local setup_opts = { 81 | on_attach = on_attach, 82 | } 83 | 84 | if not name then 85 | print "You have not defined a server name, please edit minimal_init.lua" 86 | end 87 | if not nvim_lsp[name].document_config.default_config.cmd and not setup_opts.cmd then 88 | print [[You have not defined a server default cmd for a server 89 | that requires it please edit minimal_init.lua]] 90 | end 91 | 92 | nvim_lsp[name].setup(setup_opts) 93 | if use_lsp_installer then 94 | require("mason-lspconfig").setup { automatic_installation = true } 95 | end 96 | 97 | print [[You can find your log at $HOME/.cache/nvim/lsp.log. Please paste in a github issue under a details tag as described in the issue template.]] 98 | end 99 | 100 | if vim.fn.isdirectory(install_path) == 0 then 101 | vim.fn.system { "git", "clone", "https://github.com/wbthomason/packer.nvim", install_path } 102 | load_plugins() 103 | require("packer").sync() 104 | vim.cmd [[autocmd User PackerComplete ++once lua load_config()]] 105 | else 106 | load_plugins() 107 | require("packer").sync() 108 | _G.load_config() 109 | end 110 | -------------------------------------------------------------------------------- /utils/desktop/22x22/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /utils/desktop/64x64/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /lua/lvim/core/lualine/styles.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | local components = require "lvim.core.lualine.components" 3 | 4 | local styles = { 5 | lvim = nil, 6 | default = nil, 7 | none = nil, 8 | } 9 | 10 | styles.none = { 11 | style = "none", 12 | options = { 13 | theme = "auto", 14 | globalstatus = true, 15 | icons_enabled = lvim.use_icons, 16 | component_separators = { left = "", right = "" }, 17 | section_separators = { left = "", right = "" }, 18 | disabled_filetypes = {}, 19 | }, 20 | sections = { 21 | lualine_a = {}, 22 | lualine_b = {}, 23 | lualine_c = {}, 24 | lualine_x = {}, 25 | lualine_y = {}, 26 | lualine_z = {}, 27 | }, 28 | inactive_sections = { 29 | lualine_a = {}, 30 | lualine_b = {}, 31 | lualine_c = {}, 32 | lualine_x = {}, 33 | lualine_y = {}, 34 | lualine_z = {}, 35 | }, 36 | tabline = {}, 37 | extensions = {}, 38 | } 39 | 40 | styles.default = { 41 | style = "default", 42 | options = { 43 | theme = "auto", 44 | globalstatus = true, 45 | icons_enabled = lvim.use_icons, 46 | component_separators = { 47 | left = lvim.icons.ui.DividerRight, 48 | right = lvim.icons.ui.DividerLeft, 49 | }, 50 | section_separators = { 51 | left = lvim.icons.ui.BoldDividerRight, 52 | right = lvim.icons.ui.BoldDividerLeft, 53 | }, 54 | disabled_filetypes = {}, 55 | }, 56 | sections = { 57 | lualine_a = { "mode" }, 58 | lualine_b = { "branch" }, 59 | lualine_c = { "filename" }, 60 | lualine_x = { "encoding", "fileformat", "filetype" }, 61 | lualine_y = { "progress" }, 62 | lualine_z = { "location" }, 63 | }, 64 | inactive_sections = { 65 | lualine_a = {}, 66 | lualine_b = {}, 67 | lualine_c = { "filename" }, 68 | lualine_x = { "location" }, 69 | lualine_y = {}, 70 | lualine_z = {}, 71 | }, 72 | tabline = {}, 73 | extensions = {}, 74 | } 75 | 76 | styles.lvim = { 77 | style = "lvim", 78 | options = { 79 | theme = "auto", 80 | globalstatus = true, 81 | icons_enabled = lvim.use_icons, 82 | component_separators = { left = "", right = "" }, 83 | section_separators = { left = "", right = "" }, 84 | disabled_filetypes = { "alpha" }, 85 | }, 86 | sections = { 87 | lualine_a = { 88 | components.mode, 89 | }, 90 | lualine_b = { 91 | components.branch, 92 | }, 93 | lualine_c = { 94 | components.diff, 95 | components.python_env, 96 | }, 97 | lualine_x = { 98 | components.diagnostics, 99 | components.lsp, 100 | components.spaces, 101 | components.filetype, 102 | }, 103 | lualine_y = { components.location }, 104 | lualine_z = { 105 | components.progress, 106 | }, 107 | }, 108 | inactive_sections = { 109 | lualine_a = { 110 | components.mode, 111 | }, 112 | lualine_b = { 113 | components.branch, 114 | }, 115 | lualine_c = { 116 | components.diff, 117 | components.python_env, 118 | }, 119 | lualine_x = { 120 | components.diagnostics, 121 | components.lsp, 122 | components.spaces, 123 | components.filetype, 124 | }, 125 | lualine_y = { components.location }, 126 | lualine_z = { 127 | components.progress, 128 | }, 129 | }, 130 | tabline = {}, 131 | extensions = {}, 132 | } 133 | 134 | function M.get_style(style) 135 | local style_keys = vim.tbl_keys(styles) 136 | if not vim.tbl_contains(style_keys, style) then 137 | local Log = require "lvim.core.log" 138 | Log:error( 139 | "Invalid lualine style" 140 | .. string.format('"%s"', style) 141 | .. "options are: " 142 | .. string.format('"%s"', table.concat(style_keys, '", "')) 143 | ) 144 | Log:debug '"lvim" style is applied.' 145 | style = "lvim" 146 | end 147 | 148 | return vim.deepcopy(styles[style]) 149 | end 150 | 151 | function M.update() 152 | local style = M.get_style(lvim.builtin.lualine.style) 153 | 154 | lvim.builtin.lualine = vim.tbl_deep_extend("keep", lvim.builtin.lualine, style) 155 | 156 | local color_template = vim.g.colors_name or lvim.colorscheme 157 | local theme_supported, template = pcall(function() 158 | require("lualine.utils.loader").load_theme(color_template) 159 | end) 160 | if theme_supported and template then 161 | lvim.builtin.lualine.options.theme = color_template 162 | end 163 | end 164 | 165 | return M 166 | -------------------------------------------------------------------------------- /utils/desktop/24x24/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /lua/lvim/lsp/config.lua: -------------------------------------------------------------------------------- 1 | local skipped_servers = { 2 | "angularls", 3 | "ansiblels", 4 | "ccls", 5 | "csharp_ls", 6 | "cssmodules_ls", 7 | "denols", 8 | "ember", 9 | "emmet_ls", 10 | "eslint", 11 | "eslintls", 12 | "glint", 13 | "golangci_lint_ls", 14 | "gradle_ls", 15 | "graphql", 16 | "jedi_language_server", 17 | "ltex", 18 | "ocamlls", 19 | "phpactor", 20 | "psalm", 21 | "pylsp", 22 | "quick_lint_js", 23 | "reason_ls", 24 | "rome", 25 | "ruby_ls", 26 | "scry", 27 | "solang", 28 | "solc", 29 | "solidity_ls", 30 | "sorbet", 31 | "sourcekit", 32 | "sourcery", 33 | "spectral", 34 | "sqlls", 35 | "sqls", 36 | "stylelint_lsp", 37 | "svlangserver", 38 | "tflint", 39 | "verible", 40 | "vuels", 41 | } 42 | 43 | local skipped_filetypes = { "markdown", "rst", "plaintext", "toml", "proto" } 44 | 45 | local join_paths = require("lvim.utils").join_paths 46 | 47 | return { 48 | templates_dir = join_paths(get_runtime_dir(), "site", "after", "ftplugin"), 49 | diagnostics = { 50 | signs = { 51 | active = true, 52 | values = { 53 | { name = "DiagnosticSignError", text = lvim.icons.diagnostics.Error }, 54 | { name = "DiagnosticSignWarn", text = lvim.icons.diagnostics.Warning }, 55 | { name = "DiagnosticSignHint", text = lvim.icons.diagnostics.Hint }, 56 | { name = "DiagnosticSignInfo", text = lvim.icons.diagnostics.Info }, 57 | }, 58 | }, 59 | virtual_text = true, 60 | update_in_insert = false, 61 | underline = true, 62 | severity_sort = true, 63 | float = { 64 | focusable = false, 65 | style = "minimal", 66 | border = "rounded", 67 | source = "always", 68 | header = "", 69 | prefix = "", 70 | format = function(d) 71 | local code = d.code or (d.user_data and d.user_data.lsp.code) 72 | if code then 73 | return string.format("%s [%s]", d.message, code):gsub("1. ", "") 74 | end 75 | return d.message 76 | end, 77 | }, 78 | }, 79 | document_highlight = false, 80 | code_lens_refresh = true, 81 | float = { 82 | focusable = true, 83 | style = "minimal", 84 | border = "rounded", 85 | }, 86 | on_attach_callback = nil, 87 | on_init_callback = nil, 88 | automatic_configuration = { 89 | ---@usage list of servers that the automatic installer will skip 90 | skipped_servers = skipped_servers, 91 | ---@usage list of filetypes that the automatic installer will skip 92 | skipped_filetypes = skipped_filetypes, 93 | }, 94 | buffer_mappings = { 95 | normal_mode = { 96 | ["K"] = { vim.lsp.buf.hover, "Show hover" }, 97 | ["gd"] = { vim.lsp.buf.definition, "Goto Definition" }, 98 | ["gD"] = { vim.lsp.buf.declaration, "Goto declaration" }, 99 | ["gr"] = { vim.lsp.buf.references, "Goto references" }, 100 | ["gI"] = { vim.lsp.buf.implementation, "Goto Implementation" }, 101 | ["gs"] = { vim.lsp.buf.signature_help, "show signature help" }, 102 | ["gl"] = { 103 | function() 104 | local config = lvim.lsp.diagnostics.float 105 | config.scope = "line" 106 | vim.diagnostic.open_float(0, config) 107 | end, 108 | "Show line diagnostics", 109 | }, 110 | }, 111 | insert_mode = {}, 112 | visual_mode = {}, 113 | }, 114 | buffer_options = { 115 | --- enable completion triggered by 116 | omnifunc = "v:lua.vim.lsp.omnifunc", 117 | --- use gq for formatting 118 | formatexpr = "v:lua.vim.lsp.formatexpr(#{timeout_ms:500})", 119 | }, 120 | ---@usage list of settings of nvim-lsp-installer 121 | installer = { 122 | setup = { 123 | ensure_installed = {}, 124 | automatic_installation = { 125 | exclude = {}, 126 | }, 127 | }, 128 | }, 129 | nlsp_settings = { 130 | setup = { 131 | config_home = join_paths(get_config_dir(), "lsp-settings"), 132 | -- set to false to overwrite schemastore.nvim 133 | append_default_schemas = true, 134 | ignored_servers = {}, 135 | loader = "json", 136 | }, 137 | }, 138 | null_ls = { 139 | setup = { 140 | debug = false, 141 | }, 142 | config = {}, 143 | }, 144 | ---@deprecated use lvim.lsp.automatic_configuration.skipped_servers instead 145 | override = {}, 146 | ---@deprecated use lvim.lsp.installer.setup.automatic_installation instead 147 | automatic_servers_installation = nil, 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![lunarvim_logo_dark](https://user-images.githubusercontent.com/59826753/159940098-54284f26-f1da-4481-8b03-1deb34c57533.png) 2 | 3 |

4 | 5 | Latest release 6 | 7 | 8 | Last commit 9 | 10 | 11 | License 12 | 13 | 14 | Stars 15 | 16 | 17 | Issues 18 | 19 | 20 | Repo Size 21 | 22 | 23 | Patreon donate button 24 | 25 | 26 | follow on Twitter 27 | 28 | 29 |

30 | 31 |

32 | 33 | An IDE layer for Neovim with sane defaults. Completely free and community driven. 34 | 35 | --- 36 | 37 | **[
 Install 
][Install]**  38 | **[
 Configure 
][Configure]**  39 | **[
 Troubleshooting 
][Troubleshoot]**  40 | **[
 Contribute 
][Contribute]** 41 | 42 | --- 43 | 44 | ## Showcase 45 | 46 | ![demo3](https://user-images.githubusercontent.com/29136904/191626246-ce0cc0c5-4b41-49e3-9cb7-4b1867ab0dcb.png) 47 | ![info](https://user-images.githubusercontent.com/29136904/191624942-3d75ef87-35cf-434d-850e-3e7cd5ce2ad0.png) 48 | 49 | 50 | 51 | ## Socials 52 | 53 |

54 | Github Logo Discord Logo Twitter Logo Reddit Logo 55 |

56 | 57 | [Contribute]: https://github.com/LunarVim/LunarVim/blob/master/CONTRIBUTING.md 58 | [Install]: https://www.lunarvim.org/docs/installation 59 | [Troubleshoot]: https://www.lunarvim.org/docs/troubleshooting 60 | [Configure]: https://www.lunarvim.org/docs/configuration 61 | 62 | ## Thanks to all contributors 63 | 64 | 65 | 66 | 67 | 68 |
69 | -------------------------------------------------------------------------------- /lua/lvim/bootstrap.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | if vim.fn.has "nvim-0.8" ~= 1 then 4 | vim.notify("Please upgrade your Neovim base installation. Lunarvim requires v0.8+", vim.log.levels.WARN) 5 | vim.wait(5000, function() 6 | return false 7 | end) 8 | vim.cmd "cquit" 9 | end 10 | 11 | local uv = vim.loop 12 | local path_sep = uv.os_uname().version:match "Windows" and "\\" or "/" 13 | 14 | ---Join path segments that were passed as input 15 | ---@return string 16 | function _G.join_paths(...) 17 | local result = table.concat({ ... }, path_sep) 18 | return result 19 | end 20 | 21 | _G.require_clean = require("lvim.utils.modules").require_clean 22 | _G.require_safe = require("lvim.utils.modules").require_safe 23 | _G.reload = require("lvim.utils.modules").reload 24 | 25 | ---Get the full path to `$LUNARVIM_RUNTIME_DIR` 26 | ---@return string 27 | function _G.get_runtime_dir() 28 | local lvim_runtime_dir = os.getenv "LUNARVIM_RUNTIME_DIR" 29 | if not lvim_runtime_dir then 30 | -- when nvim is used directly 31 | return vim.call("stdpath", "data") 32 | end 33 | return lvim_runtime_dir 34 | end 35 | 36 | ---Get the full path to `$LUNARVIM_CONFIG_DIR` 37 | ---@return string 38 | function _G.get_config_dir() 39 | local lvim_config_dir = os.getenv "LUNARVIM_CONFIG_DIR" 40 | if not lvim_config_dir then 41 | return vim.call("stdpath", "config") 42 | end 43 | return lvim_config_dir 44 | end 45 | 46 | ---Get the full path to `$LUNARVIM_CACHE_DIR` 47 | ---@return string 48 | function _G.get_cache_dir() 49 | local lvim_cache_dir = os.getenv "LUNARVIM_CACHE_DIR" 50 | if not lvim_cache_dir then 51 | return vim.call("stdpath", "cache") 52 | end 53 | return lvim_cache_dir 54 | end 55 | 56 | ---Initialize the `&runtimepath` variables and prepare for startup 57 | ---@return table 58 | function M:init(base_dir) 59 | self.runtime_dir = get_runtime_dir() 60 | self.config_dir = get_config_dir() 61 | self.cache_dir = get_cache_dir() 62 | self.pack_dir = join_paths(self.runtime_dir, "site", "pack") 63 | self.packer_install_dir = join_paths(self.runtime_dir, "site", "pack", "packer", "start", "packer.nvim") 64 | self.packer_cache_path = join_paths(self.config_dir, "plugin", "packer_compiled.lua") 65 | 66 | ---@meta overridden to use LUNARVIM_CACHE_DIR instead, since a lot of plugins call this function internally 67 | ---NOTE: changes to "data" are currently unstable, see #2507 68 | vim.fn.stdpath = function(what) 69 | if what == "cache" then 70 | return _G.get_cache_dir() 71 | end 72 | return vim.call("stdpath", what) 73 | end 74 | 75 | ---Get the full path to LunarVim's base directory 76 | ---@return string 77 | function _G.get_lvim_base_dir() 78 | return base_dir 79 | end 80 | 81 | if os.getenv "LUNARVIM_RUNTIME_DIR" then 82 | -- vim.opt.rtp:append(os.getenv "LUNARVIM_RUNTIME_DIR" .. path_sep .. "lvim") 83 | vim.opt.rtp:remove(join_paths(vim.call("stdpath", "data"), "site")) 84 | vim.opt.rtp:remove(join_paths(vim.call("stdpath", "data"), "site", "after")) 85 | vim.opt.rtp:prepend(join_paths(self.runtime_dir, "site")) 86 | vim.opt.rtp:append(join_paths(self.runtime_dir, "lvim", "after")) 87 | vim.opt.rtp:append(join_paths(self.runtime_dir, "site", "after")) 88 | 89 | vim.opt.rtp:remove(vim.call("stdpath", "config")) 90 | vim.opt.rtp:remove(join_paths(vim.call("stdpath", "config"), "after")) 91 | vim.opt.rtp:prepend(self.config_dir) 92 | vim.opt.rtp:append(join_paths(self.config_dir, "after")) 93 | -- TODO: we need something like this: vim.opt.packpath = vim.opt.rtp 94 | 95 | vim.cmd [[let &packpath = &runtimepath]] 96 | end 97 | 98 | if not vim.env.LVIM_TEST_ENV then 99 | require "lvim.impatient" 100 | end 101 | 102 | require("lvim.config"):init() 103 | 104 | require("lvim.plugin-loader").init { 105 | package_root = self.pack_dir, 106 | install_path = self.packer_install_dir, 107 | } 108 | 109 | require("lvim.core.mason").bootstrap() 110 | 111 | return self 112 | end 113 | 114 | ---Update LunarVim 115 | ---pulls the latest changes from github and, resets the startup cache 116 | function M:update() 117 | require("lvim.core.log"):info "Trying to update LunarVim..." 118 | 119 | vim.schedule(function() 120 | reload("lvim.utils.hooks").run_pre_update() 121 | local ret = reload("lvim.utils.git").update_base_lvim() 122 | if ret then 123 | reload("lvim.utils.hooks").run_post_update() 124 | end 125 | end) 126 | end 127 | 128 | return M 129 | -------------------------------------------------------------------------------- /utils/desktop/32x32/lvim.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /lua/lvim/utils/git.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local Log = require "lvim.core.log" 4 | local fmt = string.format 5 | local if_nil = vim.F.if_nil 6 | 7 | local function git_cmd(opts) 8 | local plenary_loaded, Job = pcall(require, "plenary.job") 9 | if not plenary_loaded then 10 | return 1, { "" } 11 | end 12 | 13 | opts = opts or {} 14 | opts.cwd = opts.cwd or get_lvim_base_dir() 15 | 16 | local stderr = {} 17 | local stdout, ret = Job:new({ 18 | command = "git", 19 | args = opts.args, 20 | cwd = opts.cwd, 21 | on_stderr = function(_, data) 22 | table.insert(stderr, data) 23 | end, 24 | }):sync() 25 | 26 | if not vim.tbl_isempty(stderr) then 27 | Log:debug(stderr) 28 | end 29 | 30 | if not vim.tbl_isempty(stdout) then 31 | Log:debug(stdout) 32 | end 33 | 34 | return ret, stdout, stderr 35 | end 36 | 37 | local function safe_deep_fetch() 38 | local ret, result, error = git_cmd { args = { "rev-parse", "--is-shallow-repository" } } 39 | if ret ~= 0 then 40 | Log:error(vim.inspect(error)) 41 | return 42 | end 43 | -- git fetch --unshallow will cause an error on a complete clone 44 | local fetch_mode = result[1] == "true" and "--unshallow" or "--all" 45 | ret = git_cmd { args = { "fetch", fetch_mode } } 46 | if ret ~= 0 then 47 | Log:error(fmt "Git fetch %s failed! Please pull the changes manually in %s", fetch_mode, get_lvim_base_dir()) 48 | return 49 | end 50 | if fetch_mode == "--unshallow" then 51 | ret = git_cmd { args = { "remote", "set-branches", "origin", "*" } } 52 | if ret ~= 0 then 53 | Log:error(fmt "Git fetch %s failed! Please pull the changes manually in %s", fetch_mode, get_lvim_base_dir()) 54 | return 55 | end 56 | end 57 | return true 58 | end 59 | 60 | ---pulls the latest changes from github 61 | function M.update_base_lvim() 62 | Log:info "Checking for updates" 63 | 64 | if not vim.loop.fs_access(get_lvim_base_dir(), "w") then 65 | Log:warn(fmt("Lunarvim update aborted! cannot write to %s", get_lvim_base_dir())) 66 | return 67 | end 68 | 69 | if not safe_deep_fetch() then 70 | return 71 | end 72 | 73 | local ret 74 | 75 | ret = git_cmd { args = { "diff", "--quiet", "@{upstream}" } } 76 | if ret == 0 then 77 | Log:info "LunarVim is already up-to-date" 78 | return 79 | end 80 | 81 | ret = git_cmd { args = { "merge", "--ff-only", "--progress" } } 82 | if ret ~= 0 then 83 | Log:error("Update failed! Please pull the changes manually in " .. get_lvim_base_dir()) 84 | return 85 | end 86 | 87 | return true 88 | end 89 | 90 | ---Switch Lunarvim to the specified development branch 91 | ---@param branch string 92 | function M.switch_lvim_branch(branch) 93 | if not safe_deep_fetch() then 94 | return 95 | end 96 | local args = { "switch", branch } 97 | 98 | if branch:match "^[0-9]" then 99 | -- avoids producing an error for tags 100 | vim.list_extend(args, { "--detach" }) 101 | end 102 | 103 | local ret = git_cmd { args = args } 104 | if ret ~= 0 then 105 | Log:error "Unable to switch branches! Check the log for further information" 106 | return 107 | end 108 | return true 109 | end 110 | 111 | ---Get the current Lunarvim development branch 112 | ---@return string|nil 113 | function M.get_lvim_branch() 114 | local _, results = git_cmd { args = { "rev-parse", "--abbrev-ref", "HEAD" } } 115 | local branch = if_nil(results[1], "") 116 | return branch 117 | end 118 | 119 | ---Get currently checked-out tag of Lunarvim 120 | ---@return string 121 | function M.get_lvim_tag() 122 | local args = { "describe", "--tags", "--abbrev=0" } 123 | 124 | local _, results = git_cmd { args = args } 125 | local tag = if_nil(results[1], "") 126 | return tag 127 | end 128 | 129 | ---Get currently running version of Lunarvim 130 | ---@return string 131 | function M.get_lvim_version() 132 | local current_branch = M.get_lvim_branch() 133 | 134 | local lvim_version 135 | if current_branch ~= "HEAD" or "" then 136 | lvim_version = current_branch .. "-" .. M.get_lvim_current_sha() 137 | else 138 | lvim_version = "v" .. M.get_lvim_tag() 139 | end 140 | return lvim_version 141 | end 142 | 143 | ---Get the commit hash of currently checked-out commit of Lunarvim 144 | ---@return string|nil 145 | function M.get_lvim_current_sha() 146 | local _, log_results = git_cmd { args = { "log", "--pretty=format:%h", "-1" } } 147 | local abbrev_version = if_nil(log_results[1], "") 148 | return abbrev_version 149 | end 150 | 151 | return M 152 | -------------------------------------------------------------------------------- /utils/ci/verify_plugins.lua: -------------------------------------------------------------------------------- 1 | local completed = 0 2 | local collection = {} 3 | local active_jobs = {} 4 | 5 | local fmt = string.format 6 | local core_plugins = require "lvim.plugins" 7 | 8 | local default_snapshot_path = join_paths(get_lvim_base_dir(), "snapshots", "default.json") 9 | local fd = io.open(default_snapshot_path, "rb") 10 | local content 11 | if fd then 12 | content = fd:read "*a" 13 | end 14 | local default_sha1 = vim.json.decode(content) 15 | 16 | local get_short_name = function(spec) 17 | return spec[1]:match "/(%S*)" 18 | end 19 | 20 | local get_default_sha1 = function(spec) 21 | local short_name, _ = get_short_name(spec) 22 | assert(default_sha1[short_name]) 23 | return default_sha1[short_name].commit 24 | end 25 | 26 | local is_directory = require("lvim.utils").is_directory 27 | -- see packer.init() 28 | local packdir = join_paths(get_runtime_dir(), "site", "pack", "packer") 29 | 30 | local verify_packer = function() 31 | if not is_directory(packdir) then 32 | io.write "Packer not installed!" 33 | os.exit(1) 34 | end 35 | local status_ok, packer = pcall(require, "packer") 36 | if status_ok and packer then 37 | return 38 | end 39 | io.write "Packer not installed!" 40 | os.exit(1) 41 | end 42 | 43 | local packer_config = { opt_dir = join_paths(packdir, "opt"), start_dir = join_paths(packdir, "start") } 44 | local is_optional = function(spec) 45 | return spec.opt or spec.event or spec.cmd or spec.module 46 | end 47 | local get_install_path = function(spec) 48 | local prefix = is_optional(spec) and packer_config.opt_dir or packer_config.start_dir 49 | local path = join_paths(prefix, get_short_name(spec)) 50 | return is_directory(path) and path 51 | end 52 | 53 | local function call_proc(process, opts, cb) 54 | local output, error_output = "", "" 55 | local handle_stdout = function(err, chunk) 56 | assert(not err, err) 57 | if chunk then 58 | output = output .. chunk 59 | end 60 | end 61 | 62 | local handle_stderr = function(err, chunk) 63 | assert(not err, err) 64 | if chunk then 65 | error_output = error_output .. chunk 66 | end 67 | end 68 | 69 | local uv = vim.loop 70 | local handle 71 | 72 | local stdout = uv.new_pipe(false) 73 | local stderr = uv.new_pipe(false) 74 | 75 | local stdio = { nil, stdout, stderr } 76 | 77 | handle = uv.spawn( 78 | process, 79 | { args = opts.args, cwd = opts.cwd or uv.cwd(), stdio = stdio }, 80 | vim.schedule_wrap(function(code) 81 | if code ~= 0 then 82 | stdout:read_stop() 83 | stderr:read_stop() 84 | end 85 | 86 | local check = uv.new_check() 87 | check:start(function() 88 | for _, pipe in ipairs(stdio) do 89 | if pipe and not pipe:is_closing() then 90 | return 91 | end 92 | end 93 | check:stop() 94 | handle:close() 95 | cb(code, output, error_output) 96 | end) 97 | end) 98 | ) 99 | 100 | uv.read_start(stdout, handle_stdout) 101 | uv.read_start(stderr, handle_stderr) 102 | 103 | return handle 104 | end 105 | 106 | local function verify_core_plugins(verbose) 107 | for _, spec in pairs(core_plugins) do 108 | local path = get_install_path(spec) 109 | if not spec.disable and path then 110 | table.insert(collection, { 111 | name = get_short_name(spec), 112 | commit = get_default_sha1(spec), 113 | path = path, 114 | }) 115 | end 116 | end 117 | 118 | for _, entry in pairs(collection) do 119 | local on_done = function(code, result, errors) 120 | completed = completed + 1 121 | if code ~= 0 then 122 | io.write(errors .. "\n") 123 | -- os.exit(code) 124 | else 125 | if verbose then 126 | io.write(fmt("verified [%s]\n", entry.name)) 127 | end 128 | end 129 | local current_commit = result:gsub("\n", ""):gsub([[']], [[]]):sub(1, 7) 130 | -- just in case there are some extra qutoes or it's a longer commit hash 131 | if current_commit ~= entry.commit then 132 | io.write(fmt("mismatch at [%s]: expected [%s], got [%s]\n", entry.name, entry.commit, current_commit)) 133 | os.exit(1) 134 | end 135 | end 136 | 137 | local handle = call_proc("git", { args = { "rev-parse", "--short", "HEAD" }, cwd = entry.path }, on_done) 138 | assert(handle) 139 | table.insert(active_jobs, handle) 140 | end 141 | 142 | vim.wait(#active_jobs * 60 * 1000, function() 143 | return completed == #active_jobs 144 | end) 145 | end 146 | 147 | verify_packer() 148 | verify_core_plugins() 149 | vim.cmd "q" 150 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to LunarVim 2 | 3 | Welcome to the LunarVim contributing guide. We are excited about the prospect of you joining our [community](https://github.com/lunarvim/LunarVim/graphs/contributors)! 4 | 5 | There are many opportunities to contributing to the project at any level. Every contribution is highly valued and no contribution is too small. 6 | 7 | You do not need to write code to contribute to this project. Documentation, demos, and feature design advancements are a key part of this project's growth. 8 | 9 | One of the best ways to begin contributing in a meaningful way is by helping find bugs and filing issues for them. 10 | 11 | ## Getting Started 12 | 13 | 1. Follow the [Installation](https://www.lunarvim.org/docs/installation) guide 14 | 2. Link your fork with the repository `git remote add upstream https://github.com/lunarvim/LunarVim.git`, or use `gh fork` 15 | 3. That's it! You can now `git fetch upstream` and `git rebase [-i] upstream/rolling` to update your branches with the latest contributions. 16 | 17 |
18 | 19 | ## Setting up development tools 20 | 21 | ### For editing Lua files 22 | 23 | 1. Formatter: [stylua](https://github.com/johnnymorganz/stylua#installation). 24 | 2. Linter: [luacheck](https://github.com/luarocks/luacheck). 25 | 26 | ### For editing shell scripts 27 | 28 | 1. Formatter: [shfmt](https://github.com/mvdan/sh#shfmt). 29 | 2. Linter: [shellcheck](https://github.com/koalaman/shellcheck). 30 | 31 | ### (Optional) 32 | 33 | Install [pre-commit](https://github.com/pre-commit/pre-commit) which will run all linters and formatters for you as a pre-commit-hook. 34 | 35 |
36 | 37 | ## Code Conventions 38 | 39 | All lua code is formatted with [Stylua](https://github.com/JohnnyMorganz/StyLua). 40 | ```bash 41 | # configurations are already stored in .stylua.toml 42 | stylua -c . 43 | ``` 44 | 45 | All shell code is formatted according to [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html) 46 | * use two spaces instead of tabs 47 | ```bash 48 | shfmt -i 2 -ci -bn -l -d . 49 | ``` 50 | 51 |
52 | 53 | ## Pull Requests (PRs) 54 | 55 | - To avoid duplicate work, create a draft pull request. 56 | - Your PR must pass all the [automated-ci-tests](https://github.com/neovim/neovim/actions). 57 | - Use a [git-feature-branch](https://www.atlassian.com/git/tutorials/comparing-workflows) instead of the master/rolling branch. 58 | - Use a [rebase-workflow](http://git-scm.com/book/en/v2/Git-Branching-Rebasing). 59 | - Title the PR the same way as commit headers 60 | 61 | ### Commit Messages 62 | * Commit header is limited to 72 characters. 63 | * Commit body and footer is limited to 100 characters per line. 64 | 65 | **Commit header format:** 66 | ``` 67 | (?): 68 | │ │ │ 69 | │ │ └─> Present tense. 'add something...'(O) vs 'added something...'(X) 70 | │ │ Imperative mood. 'move cursor to...'(O) vs 'moves cursor to...'(X) 71 | │ │ Not capitalized. 72 | │ │ No period at the end. 73 | │ │ 74 | │ └─> Commit Scope is optional, but strongly recommended. 75 | │ Use lower case. 76 | │ 'plugin', 'file', or 'directory' name is suggested, but not limited. 77 | │ 78 | └─> Commit Type: build|ci|docs|feat|fix|perf|refactor|test 79 | ``` 80 | 81 | ##### Commit Type Guideline 82 | 83 | * **build**: changes that affect the build system or external dependencies (example scopes: npm, pip, rg) 84 | * **ci**: changes to CI configuration files and scripts (example scopes: format, lint, issue_templates) 85 | * **docs**: changes to the documentation only 86 | * **feat**: new feature for the user 87 | * **fix**: bug fix 88 | * **perf**: performance improvement 89 | * **refactor**: code change that neither fixes a bug nor adds a feature 90 | * **test**: adding missing tests or correcting existing tests 91 | * **chore**: all the rest, including version bump for plugins 92 | 93 | **Real world examples:** 94 | ``` 95 | feat(quickfix): add 'q' binding to quit quickfix window when focused 96 | ``` 97 | ``` 98 | fix(installer): add missing "HOME" variable 99 | ``` 100 | 101 | 102 | ### Branch Naming 103 | 104 | Name your branches meaningfully. 105 | 106 | ex) 107 | ```(feature|bugfix|hotfix)/what-my-pr-does``` 108 | 109 |
110 | 111 | ## Communication 112 | 113 | Members of the community have multiple ways to collaborate on the project. 114 | We encourage you to join the community: 115 | - [Discord server](https://discord.gg/Xb9B4Ny) 116 | - [Matrix server](https://matrix.to/#/#atmachine-neovim:matrix.org) 117 | --------------------------------------------------------------------------------