Skip to content

ph1losof/ecolog2.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🌲 ecolog2.nvim

Neovim Lua

Ecolog (эколог) - your environment guardian in Neovim. Named after the Russian word for "environmentalist", this plugin protects and manages your environment variables with the same care an ecologist shows for nature.

A modern LSP-powered Neovim plugin for seamless environment variable integration and management. Provides intelligent auto-completion, hover, go-to-definition, references, and diagnostics for environment variables in your projects.

CleanShot 2026-01-14 at 17 41 04

Why Ecolog?

Environment variables are the backbone of modern application configuration, yet they remain one of the least supported aspects of the developer experience:

Your Code Your Env Vars
Auto-completion Manual typing
Go to definition Grep through files
Hover documentation Switch to .env file
Type checking Runtime crashes

Ecolog changes this. By leveraging the Language Server Protocol (LSP) and tree-sitter AST parsing, Ecolog brings first-class IDE intelligence to environment variables:

  • Instant hover - See variable values and sources without leaving your code
  • Smart completion - All available variables, contextually aware
  • Go to definition - Jump directly to the .env file
  • Find references - See every usage across your codebase
  • Rename - Rename variables across your codebase and .env files
  • Diagnostics - Catch undefined variables before runtime
  • Value masking - Protect secrets during screen sharing (via shelter.nvim)
  • vim.env sync - Access env vars directly in Lua with vim_env = true

Works with JavaScript, TypeScript, Python, Rust, and Go. Supports telescope.nvim, fzf-lua, and snacks.nvim pickers.

Table of Contents


Quick Start

{
  "ph1losof/ecolog2.nvim",
  lazy = false,
  build = "cargo install ecolog-lsp",
  keys = {
    { "<leader>el", "<cmd>Ecolog list<cr>", desc = "List env variables" },
    { "<leader>ef", "<cmd>Ecolog files select<cr>", desc = "Select env file" },
    { "<leader>eo", "<cmd>Ecolog files open_active<cr>", desc = "Open active env file" },
    { "<leader>er", "<cmd>Ecolog refresh<cr>", desc = "Refresh env variables" },
  },
  config = function()
    require("ecolog").setup()
  end,
}

That's it! The plugin auto-detects and starts the LSP, attaches to all buffers, and provides completions, hover, and go-to-definition.

Requirements: Neovim 0.10+ (0.11+ recommended), Rust/Cargo for the LSP binary.

Performance: The plugin is a thin Lua wrapper over ecolog-lsp. It adds virtually no overhead to your Neovim startup time - the LSP spawns asynchronously and all heavy lifting happens in a separate process.


Author's Configuration

My personal setup using ecolog2.nvim with shelter.nvim for value masking. Includes custom sorting (file variables before shell), statusline with highlights, and convenient keymaps.

ecolog2.nvim

{
  {
    'ph1losof/ecolog2.nvim',
    build = [[
      cargo install ecolog-lsp && \
      cargo install ecolog-provider-doppler --root ~/.local/share/ecolog/providers
    ]],
    keys = {
      { '<leader>ef', '<cmd>Ecolog files<cr>', desc = 'Ecolog toggle file module' },
      { '<leader>ev', '<cmd>Ecolog copy value<cr>', desc = 'Ecolog copy value' },
      { '<leader>er', '<cmd>Ecolog remote<cr>', desc = 'Ecolog toggle remote source' },
      { '<leader>ers', '<cmd>Ecolog remote setup<cr>', desc = 'Ecolog remote setup' },
      { '<leader>ege', '<cmd>Ecolog generate .env.example<cr>', desc = 'Ecolog generate .env.example' },
      { '<leader>eg', '<cmd>Ecolog generate<cr>', desc = 'Ecolog generate' },
      { '<leader>es', '<cmd>Ecolog files select<cr>', desc = 'Ecolog select active file' },
      { '<leader>ei', '<cmd>Ecolog interpolation<cr>', desc = 'Ecolog toggle interpolation' },
      { '<leader>el', '<cmd>Ecolog list<cr>', desc = 'Ecolog list variables' },
      { '<leader>ge', '<cmd>Ecolog files open_active<cr>', desc = 'Go to active ecolog file' },
      { '<leader>eh', '<cmd>Ecolog shell<cr>', desc = 'Ecolog toggle shell module' },
    },
    config = function()
      require('ecolog').setup {
        vim_env = true,
        statusline = {
          sources = {
            enabled = true,
            show_disabled = true,
          },
          interpolation = {
            show_disabled = false,
          },
          highlights = {
            sources = 'String',
            sources_disabled = 'Comment',
            env_file = 'Directory',
            vars_count = 'Number',
          },
        },
        sort_var_fn = function(a, b)
          local function get_source_priority(var)
            local source = var.source or ''
            if source == 'System Environment' then
              return 3
            elseif source:match '^Remote' then
              return 2
            else
              return 1
            end
          end

          local a_priority = get_source_priority(a)
          local b_priority = get_source_priority(b)

          if a_priority ~= b_priority then
            return a_priority < b_priority
          end

          return a.name < b.name
        end,
        lsp = {
          providers = {
            path = vim.fn.expand '~/.local/share/ecolog/providers',
            doppler = {
              enabled = true,
            },
          },
          sources = {
            defaults = {
              shell = false,
              file = true,
            },
          },
          init_options = {
            interpolation = {
              enabled = false,
            },
          },
        },
      }
    end,
  },
}

shelter.nvim (value masking)

shelter.nvim provides first-class ecolog support for masking sensitive values in completions, hover, picker, and buffers.

{
  'ph1losof/shelter.nvim',
  lazy = false,
  keys = {
    { '<leader>st', '<cmd>Shelter toggle<cr>', desc = 'Toggle masking' },
  },
  opts = {
    modules = {
      ecolog = {
        cmp = true,      -- Mask in completion
        peek = false,    -- Show real value on hover
        picker = false,  -- Show real value in picker
      },
      files = true,
      snacks_previewer = true,
    },
  },
}

Commands

Command Description
:Ecolog list Open variable picker
:Ecolog copy value Copy variable value at cursor
:Ecolog files select Select active env file(s)
:Ecolog files open_active Open active env file in editor
:Ecolog files Toggle File source
:Ecolog shell Toggle Shell source
:Ecolog interpolation Toggle variable interpolation
:Ecolog workspaces List detected workspaces (monorepo)
:Ecolog root [path] Set workspace root
:Ecolog generate [path] Generate .env.example
:Ecolog refresh Restart LSP and reload env files
:Ecolog info Show plugin status

Tab completion is available for all subcommands. Use enable/disable suffixes for explicit control (e.g., :Ecolog shell enable).


Configuration Reference

require("ecolog").setup({
  -- LSP Configuration
  lsp = {
    -- "auto" (default) | "native" (0.11+) | "lspconfig" | false (external)
    backend = "auto",
    cmd = nil,              -- Binary path (auto-detected if nil)
    filetypes = nil,        -- Filetypes to attach (nil = all buffers)
    root_dir = nil,         -- Workspace root (nil = cwd)

    -- Feature toggles (sent to LSP)
    features = {
      hover = true,
      completion = true,
      diagnostics = true,
      definition = true,
    },

    -- Strict mode: only show features in valid contexts
    strict = {
      hover = true,         -- Only hover on valid env var references
      completion = true,    -- Only complete after env object access
    },

    -- LSP initialization options
    init_options = {
      interpolation = {
        enabled = true,     -- Enable ${VAR} expansion
      },
    },
  },

  -- Picker Configuration (Telescope, fzf-lua, or snacks.nvim)
  picker = {
    backend = nil,          -- Auto-detect if nil
    keys = {
      copy_value = "<C-y>",
      copy_name = "<C-u>",
      append_value = "<C-a>",
      append_name = "<CR>",
      goto_source = "<C-g>",
    },
  },

  -- Statusline Configuration
  statusline = {
    hidden_mode = false,    -- Hide when no env file active
    icons = {
      enabled = true,
      env = "",
    },
    format = {              -- Custom formatters
      env_file = function(name) return name end,
      vars_count = function(count) return tostring(count) end,
    },
    highlights = {
      enabled = true,
      env_file = "EcologStatusFile",
      vars_count = "EcologStatusCount",
      icons = "EcologStatusIcons",
      sources = "EcologStatusSources",
      sources_disabled = "EcologStatusSourcesDisabled",
      interpolation = "EcologStatusInterpolation",
      interpolation_disabled = "EcologStatusInterpolationDisabled",
    },
    sources = {
      enabled = true,
      show_disabled = false,
      format = "compact",   -- "compact" (SF) or "badges" ([S] [F])
      icons = { shell = "S", file = "F" },
    },
    interpolation = {
      enabled = true,
      show_disabled = true,
      icon = "I",
    },
  },

  -- Additional Options
  vim_env = false,          -- Sync to vim.env for Lua access
  sort_var_fn = nil,        -- Custom sorting: function(a, b) return a.name < b.name end
})

Lualine integration:

require("lualine").setup({
  sections = {
    lualine_c = { require("ecolog").lualine() },
  },
})

Supported Languages

Language Patterns Detected
JavaScript process.env.VAR, process.env["VAR"], import.meta.env.VAR, destructuring
TypeScript Same as JavaScript + type annotations
Python os.environ["VAR"], os.environ.get("VAR"), os.getenv("VAR")
Rust env!("VAR"), std::env::var("VAR")
Go os.Getenv("VAR"), os.LookupEnv("VAR")
// JavaScript/TypeScript
process.env.API_KEY;
const { API_KEY, SECRET } = process.env;
# Python
os.environ.get("API_KEY", "default")
// Rust
env!("API_KEY")
std::env::var("API_KEY")
// Go
os.Getenv("API_KEY")

Advanced Features

Hooks System

The hooks system enables integrations like shelter.nvim for value masking.

Hook Context Return Purpose
on_lsp_attach {client, bufnr} - LSP attached to buffer
on_variables_list EcologVariable[] EcologVariable[] Transform variables before display
on_variable_hover EcologVariable EcologVariable Transform variable for hover
on_variable_peek EcologVariable EcologVariable Transform variable for peek/copy
on_active_file_changed {patterns, result, success} - Active file selection changed
on_picker_entry entry entry Transform picker entry display
local hooks = require("ecolog").hooks()

-- Register a hook
local id = hooks.register("on_variable_hover", function(var)
  var.value = mask(var.value)
  return var
end, { priority = 200 })

-- Unregister
hooks.unregister("on_variable_hover", id)
Lua API
local ecolog = require("ecolog")

-- Core functions
ecolog.setup(opts)
ecolog.peek()                      -- Peek at variable under cursor
ecolog.goto_definition()           -- Go to variable definition
ecolog.copy("value")               -- Copy variable value at cursor
ecolog.list()                      -- Open variable picker
ecolog.select()                    -- Open file picker
ecolog.refresh()                   -- Restart LSP
ecolog.generate_example()          -- Generate .env.example
ecolog.info()                      -- Show plugin status

-- Async variable access
ecolog.get("API_KEY", function(var)
  if var then print(var.name .. " = " .. var.value) end
end)

ecolog.all(function(vars)
  for _, var in ipairs(vars) do print(var.name) end
end)

-- Statusline access
local statusline = ecolog.statusline()
statusline.is_running()            -- LSP running?
statusline.get_active_file()       -- Current file name
statusline.get_var_count()         -- Total variables
LSP Backends
Backend Neovim Version Description
"auto" 0.10+ Uses native (0.11+) or lspconfig fallback
"native" 0.11+ Uses vim.lsp.start() directly
"lspconfig" 0.10+ Requires nvim-lspconfig
false Any External management (hooks into LspAttach)

The binary is auto-detected in this order: Mason install → System PATH → Cargo bin (~/.cargo/bin/).

ecolog.toml Configuration

Create ecolog.toml in your workspace root for LSP-level configuration:

[features]
hover = true
completion = true
diagnostics = true
definition = true

[strict]
hover = true
completion = true

[workspace]
env_files = [".env", ".env.local", ".env.*"]

[resolution]
precedence = ["Shell", "File", "Remote"]

[interpolation]
enabled = true
max_depth = 10

[cache]
enabled = true
hot_cache_size = 100
ttl = 300
Architecture & Performance

This plugin is the LSP client for ecolog-lsp, which provides analysis using tree-sitter.

Aspect ecolog-plugin (LSP) Traditional (regex)
Analysis Tree-sitter AST parsing Regex pattern matching
Completion LSP textDocument/completion Custom completion source
Languages 5 languages via LSP Per-language regex providers
Extensibility Hooks system Direct configuration

Why this is fast:

The Neovim plugin is intentionally minimal - it's a thin Lua wrapper that:

  • Configures and spawns the LSP process
  • Provides commands and pickers for user interaction
  • Manages statusline integration

All the heavy work (tree-sitter parsing, env file watching, variable resolution, cross-file analysis) runs in the ecolog-lsp process, completely separate from your Neovim instance. This means:

  • Near-zero startup impact - The plugin just registers a few autocommands and the LSP spawns asynchronously
  • No editor blocking - File parsing and analysis never freeze your Neovim
  • Memory isolation - The LSP's memory usage doesn't affect Neovim's footprint

Troubleshooting

LSP not starting:

  • Check status: :Ecolog info
  • Verify binary: which ecolog-lsp
  • Check logs: :LspLog

No completions:

  • Verify you're in a supported filetype (JS, TS, Python, Rust, Go)
  • Check File source: :Ecolog files enable
  • Verify .env file exists

Variables not found:

  • Check active file: :Ecolog info
  • Select file: :Ecolog files select
  • Refresh: :Ecolog refresh

Picker not working:

  • Install Telescope, fzf-lua, or snacks.nvim
  • Force backend: picker.backend = "telescope"

Health check: Run :checkhealth ecolog to diagnose issues.


Related Projects

License

MIT

About

A modern LSP-powered Neovim plugin for seamless environment variable integration and management. Provides intelligent auto-completion, hover, go-to-definition, references, and diagnostics for environment variables in your projects.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages