https://github.com/ph1losof/ecolog.nvim
The most sophisticated all-in-one toolkit to work with .env files and environment variables in NeoVim
https://github.com/ph1losof/ecolog.nvim
neovim neovim-lua-plugin neovim-plugin neovim-plugins nvim nvim-cmp nvim-plugin
Last synced: 3 months ago
JSON representation
The most sophisticated all-in-one toolkit to work with .env files and environment variables in NeoVim
- Host: GitHub
- URL: https://github.com/ph1losof/ecolog.nvim
- Owner: ph1losof
- License: mit
- Created: 2024-12-09T20:24:42.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-01-14T16:52:05.000Z (3 months ago)
- Last Synced: 2026-01-14T19:20:51.814Z (3 months ago)
- Topics: neovim, neovim-lua-plugin, neovim-plugin, neovim-plugins, nvim, nvim-cmp, nvim-plugin
- Language: Lua
- Homepage:
- Size: 1.3 MB
- Stars: 169
- Watchers: 1
- Forks: 11
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ๐ฒ ecolog.nvim


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 Neovim plugin for seamless environment variable integration and management. Provides intelligent autocompletion, type checking, and value peeking for environment variables in your projects. All in one place.
> ๐ก **LATEST INFO**: Please set branch to **v1** or consider **beta** if possible, **beta** is a complete rewrite of ecolog.nvim from the ground up.

## Table of Contents
- [Installation](#-installation)
- [Plugin Setup](#plugin-setup)
- [Features](#-features)
- [Usage](#-usage)
- [Available Commands](#available-commands)
- [Environment File Priority](#-environment-file-priority)
- [Shell Variables Integration](#-shell-variables-integration)
- [Basic Usage](#basic-usage)
- [Advanced Configuration](#advanced-configuration)
- [Configuration Options](#configuration-options)
- [Features](#features)
- [Best Practices](#best-practices)
- [Monorepo Support](#-monorepo-support)
- [Configuration](#configuration)
- [Workspace Detection](#workspace-detection)
- [Environment File Resolution](#environment-file-resolution)
- [Workspace Switching](#workspace-switching)
- [Advanced Configuration](#advanced-configuration-1)
- [Variable Interpolation](#-variable-interpolation)
- [Supported Syntax](#supported-syntax)
- [Examples](#examples)
- [Configuration Options](#configuration-options-1)
- [Features](#features-1)
- [Best Practices](#best-practices-1)
- [Supported Languages](#-supported-languages)
- [Currently Supported](#currently-supported)
- [Adding new languages and custom providers](#-custom-providers)
- [Custom Environment File Patterns](#-custom-environment-file-patterns)
- [Basic Usage](#basic-usage-1)
- [Pattern Format](#pattern-format)
- [Examples](#examples)
- [Features](#features-1)
- [Custom Sort Functions](#-custom-sort-functions)
- [File Sorting](#file-sorting)
- [Variable Sorting](#variable-sorting)
- [Integrations](#-integrations)
- [Nvim-cmp Integration](#nvim-cmp-integration)
- [Blink-cmp Integration](#blink-cmp-integration)
- [Omnifunc Integration](#omnifunc-integration)
- [Setup](#setup)
- [Usage](#usage)
- [Shelter Mode Integration](#shelter-mode-integration)
- [Manual Setup](#manual-setup)
- [LSP Integration](#lsp-integration-experimental)
- [LSP Saga Integration](#lsp-saga-integration)
- [Telescope Integration](#telescope-integration)
- [FZF Integration](#fzf-integration)
- [Snacks Integration](#snacks-integration)
- [Custom Actions for Pickers](#custom-actions-for-pickers)
- [Statusline Integration](#statusline-integration)
- [AWS Secrets Manager](#aws-secrets-manager)
- [HashiCorp Vault Secrets](#hashicorp-vault-secrets)
- [Shelter Previewers](#-shelter-previewers)
- [Telescope Previewer](#telescope-previewer)
- [FZF Previewer](#fzf-previewer)
- [Snacks Previewer](#snacks-previewer)
- [Shelter Mode](#๏ธ-shelter-mode)
- [Configuration](#-configuration)
- [Features](#-features-1)
- [Module-specific Masking](#module-specific-masking)
- [Partial Masking](#partial-masking)
- [Commands](#-commands)
- [Example](#-example)
- [Pattern-based Protection](#pattern-based-protection)
- [Customization](#-customization)
- [Best Practices](#-best-practices)
- [Ecolog Types](#-ecolog-types)
- [Type Configuration](#type-configuration)
- [Custom Type Definition](#custom-type-definition)
- [Tips](#-tips)
- [Theme Integration](#-theme-integration)
- [Author Setup](#๏ธ-author-setup)
- [Comparisons](#-comparisons)
- [Environment Variable Completion](#environment-variable-completion-vs-cmp-dotenv)
- [Security Features](#security-features-vs-cloaknvim)
- [Environment Management](#environment-management-vs-telescope-envnvim)
- [File Management](#file-management-vs-dotenvnvim)
- [Key Benefits of ecolog.nvim](#key-benefits-of-ecolognvim)
- [Contributing](#-contributing)
- [License](#-license)
## ๐ฆ Installation
Using [lazy.nvim](https://github.com/folke/lazy.nvim):
### Plugin Setup
> ๐ก **Quick Start**: If you want to quickly start with ecolog.nvim, check out the [author's personal setup](#๏ธ-author-setup) section.
```lua
{
'ph1losof/ecolog.nvim',
branch = "v1",
-- Optional: you can add some keybindings
-- (I personally use lspsaga so check out lspsaga integration or lsp integration for a smoother experience without separate keybindings)
keys = {
{ 'ge', 'EcologGoto', desc = 'Go to env file' },
{ 'ep', 'EcologPeek', desc = 'Ecolog peek variable' },
{ 'es', 'EcologSelect', desc = 'Switch env file' },
},
-- Lazy loading is done internally
lazy = false,
opts = {
integrations = {
-- WARNING: for both cmp integrations see readme section below
nvim_cmp = true, -- If you dont plan to use nvim_cmp set to false, enabled by default
-- If you are planning to use blink cmp uncomment this line
-- blink_cmp = true,
},
-- Enables shelter mode for sensitive values
shelter = {
configuration = {
-- Partial mode configuration:
-- false: completely mask values (default)
-- true: use default partial masking settings
-- table: customize partial masking
-- partial_mode = false,
-- or with custom settings:
partial_mode = {
show_start = 3, -- Show first 3 characters
show_end = 3, -- Show last 3 characters
min_mask = 3, -- Minimum masked characters
},
mask_char = "*", -- Character used for masking
mask_length = nil, -- Optional: fixed length for masked portion (defaults to value length)
skip_comments = false, -- Skip masking comment lines in environment files (default: false)
},
modules = {
cmp = true, -- Enabled to mask values in completion
peek = false, -- Enable to mask values in peek view
files = true, -- Enabled to mask values in file buffers
telescope = false, -- Enable to mask values in telescope integration
telescope_previewer = false, -- Enable to mask values in telescope preview buffers
fzf = false, -- Enable to mask values in fzf picker
fzf_previewer = false, -- Enable to mask values in fzf preview buffers
snacks_previewer = false, -- Enable to mask values in snacks previewer
snacks = false, -- Enable to mask values in snacks picker
}
},
-- true by default, enables built-in types (database_url, url, etc.)
types = true,
path = vim.fn.getcwd(), -- Path to search for .env files
preferred_environment = "development", -- Optional: prioritize specific env files
-- Controls how environment variables are extracted from code and how cmp works
provider_patterns = true, -- true by default, when false will not check provider patterns
},
}
```
To use the latest features and improvements, you can use the beta branch:
```lua
{
'ph1losof/ecolog.nvim',
branch = 'beta',
-- ... rest of your configuration
}
```
> Even though beta branch may contain more experimental changes, new and shiny features will appear faster here.
> Consider using it as a contribution to the development of the main branch. Since you can share your feedback.
Setup auto-completion with `nvim-cmp`:
```lua
require('cmp').setup({
sources = {
{ name = 'ecolog' },
-- your other sources...
},
})
```
If you use `blink.cmp` see [Blink-cmp Integration guide](#blink-cmp-integration)
## โจ Features
๐ **Advanced Environment Variable Management**
- Intelligent variable detection across multiple languages
- Real-time file monitoring and cache updates
- Support for custom environment file patterns
- Priority-based environment file loading
- Shell variables integration
- vim.env synchronization
- Advanced variable interpolation with shell-like syntax
๐ค **Smart Autocompletion**
- Context-aware suggestions with nvim-cmp and blink-cmp
- Type-safe completions with validation
- Intelligent provider detection
- Language-specific completion triggers
- Comment and metadata support in completions
๐ก๏ธ **Enhanced Security Features**
- Configurable shelter mode for sensitive data
- Partial masking with customizable patterns
- Per-feature security controls
- Real-time visual masking
- Temporary value reveal functionality
- Screen sharing protection
๐ **Integrations**
- LSP integration for hover and definition
- Telescope integration with fuzzy finding
- FZF integration with preview support
- LSP Saga integration
- Custom provider API for language support
๐ **Multi-Environment Support**
- Multiple .env file handling
- Custom file pattern matching
- Priority-based loading system
- Environment-specific configurations
- Custom sort functions for file priority
๐ข **Monorepo Support**
- Automatic workspace detection (Turborepo, Nx, Lerna, Rush, etc.)
- Intelligent environment file resolution strategies
- Workspace-aware variable completion and display
- Automatic and manual workspace switching
- Cross-workspace environment file management
๐ก **Type System**
- Built-in type validation
- Custom type definitions
- Pattern-based type detection
- Value transformation support
- Type-aware completion and validation
๐จ **UI/UX Features**
- Theme integration with existing colorschemes
- Customizable highlighting
- Rich preview windows
- Inline documentation
- Status indicators
## ๐ Variable Interpolation
Ecolog supports advanced variable interpolation with shell-like syntax in your environment files.
### Supported Syntax
- **Basic Variables**: `$VAR` or `${VAR}`
- **Default Values**: `${VAR:-default}` (use default if VAR is unset or empty)
- **Alternate Values**: `${VAR-alternate}` (use alternate if VAR is unset)
- **Command Substitution**: `$(command)`
- **Quoted Strings**:
- Single quotes (`'...'`): No interpolation
- Double quotes (`"..."`): With interpolation
### Examples
```sh
# Basic variable interpolation
APP_URL=${HOST}:${PORT}
# Default values
API_TIMEOUT=${TIMEOUT:-5000}
DB_HOST=${DATABASE_HOST:-localhost}
# Alternate values
CACHE_DIR=${CUSTOM_CACHE-/tmp/cache}
# Command substitution
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
TIMESTAMP=$(date +%Y%m%d)
# Nested interpolation
DATABASE_URL="postgres://${DB_USER:-postgres}:${DB_PASS}@${DB_HOST:-localhost}:${DB_PORT:-5432}/${DB_NAME}"
```
### Security
By default, Ecolog sanitizes potentially dangerous characters in command substitutions to prevent command injection attacks. Characters like `;`, `|`, `` ` ``, `$`, `()` are removed from commands before execution.
For example:
```sh
# This dangerous command:
HACK=$(echo hello; rm -rf /)
# Gets sanitized to:
HACK=$(echo hello rm -rf /)
```
#### Disabling Security (Advanced)
In trusted environments where you need complex shell commands, you can disable security sanitization:
```lua
require('ecolog').setup({
interpolation = {
enabled = true,
disable_security = true, -- โ ๏ธ Use with caution!
-- ... other options
}
})
```
**โ ๏ธ Warning**: Only disable security in trusted environments. When `disable_security = true`, all shell command characters are allowed, which can be dangerous if environment files contain malicious commands.
### Configuration Options
You can customize the interpolation behavior through the plugin's configuration:
```lua
require('ecolog').setup({
-- Enable interpolation with default settings
interpolation = true,
-- Or disable interpolation
interpolation = false,
-- Or customize interpolation settings
interpolation = {
enabled = true, -- Enable/disable interpolation
max_iterations = 10, -- Maximum iterations for nested interpolation
warn_on_undefined = true, -- Warn about undefined variables
fail_on_cmd_error = false, -- How to handle command substitution errors
disable_security = false, -- Disable security sanitization for command substitution
features = {
variables = true, -- Enable variable interpolation ($VAR, ${VAR})
defaults = true, -- Enable default value syntax (${VAR:-default})
alternates = true, -- Enable alternate value syntax (${VAR-alternate})
commands = true, -- Enable command substitution ($(command))
escapes = true, -- Enable escape sequences (\n, \t, etc.)
}
}
})
```
The configuration options are:
| Option | Type | Default | Description |
| ------------------- | ------- | ------- | --------------------------------------------------------- |
| enabled | boolean | false | Enable/disable interpolation |
| max_iterations | number | 10 | Maximum iterations for nested variable interpolation |
| warn_on_undefined | boolean | true | Whether to warn when undefined variables are referenced |
| fail_on_cmd_error | boolean | false | Whether to error or warn on command substitution failures |
| disable_security | boolean | false | Disable security sanitization for command substitution |
| features | table | - | Control specific interpolation features |
| features.variables | boolean | true | Enable variable interpolation ($VAR, ${VAR}) |
| features.defaults | boolean | true | Enable default value syntax (${VAR:-default}) |
| features.alternates | boolean | true | Enable alternate value syntax (${VAR-alternate}) |
| features.commands | boolean | true | Enable command substitution ($(command)) |
| features.escapes | boolean | true | Enable escape sequences (\n, \t, etc.) |
### Features
- **Recursive Interpolation**: Variables can reference other variables
- **Shell Integration**: Access shell environment variables
- **Error Handling**: Configurable warnings and error handling
- **Command Substitution**: Execute shell commands and use their output
- **Escape Sequences**: Support for common escape sequences (`\n`, `\t`, etc.)
- **Quote Handling**: Proper handling of single and double quotes
- **Default Values**: Support for default and alternate value syntax
- **Safety Limits**: Prevention of infinite recursion with iteration limits
- **Security Sanitization**: Built-in protection against command injection attacks
### Best Practices
1. Use braces `${}` for clarity and to avoid ambiguity
2. Provide default values for optional variables
3. Use single quotes for literal strings
4. Be cautious with command substitution in production environments
5. Keep nesting levels reasonable for better maintainability
6. Use feature flags to enhance security:
- Disable `commands` in production to prevent command injection
- Disable `alternates` and `defaults` if not needed
- Keep `variables` enabled for basic interpolation
- Consider disabling `escapes` if not using special characters
7. Use security settings appropriately:
- Keep `disable_security = false` (default) in untrusted environments
- Only set `disable_security = true` in trusted environments where you need complex shell commands
- Be aware that disabling security allows potentially dangerous characters like `;`, `|`, `` ` ``, `$`, `()` in command substitutions
## ๐ Supported Languages
### Currently Supported
Ecolog provides intelligent environment variable detection and completion for multiple programming languages:
| Language | File Extensions | Environment Variable Access Patterns |
| ---------- | ---------------- | ---------------------------------------------------------------------------------------------------- |
| TypeScript | .ts, .tsx | `process.env.VAR`, `process.env['VAR']`, `import.meta.env.VAR`, `Bun.env.VAR`, `Deno.env.get('VAR')` |
| JavaScript | .js, .jsx | `process.env.VAR`, `process.env['VAR']`, `Bun.env.VAR` |
| Python | .py | `os.environ.get('VAR')` |
| PHP | .php | `getenv('VAR')`, `$_ENV['VAR']`, `$_SERVER['VAR']` |
| Lua | .lua | `os.getenv('VAR')` |
| Go | .go | `os.Getenv('VAR')` |
| Rust | .rs | `env::var('VAR')`, `std::env::var('VAR')`, `std::env::var_os('VAR')` |
| Java | .java | `System.getenv('VAR')`, `env.get('VAR')` |
| C# | .cs, .csharp | `Environment.GetEnvironmentVariable('VAR')`, `System.Environment.GetEnvironmentVariable('VAR')` |
| Ruby | .rb | `ENV['VAR']`, `ENV.fetch('VAR')` |
| Shell | .sh, .bash, .zsh | `$VAR`, `${VAR}` |
| Kotlin | .kt, .kotlin | `System.getenv('VAR')` |
| Dockerfile | Dockerfile | `${VAR}` |
Each language provider is optimized for its specific environment variable access patterns and supports both completion and detection. The providers are loaded lazily to maintain performance.
### ๐ Custom Providers
You can add support for additional languages by registering custom providers. Each provider defines how environment variables are detected and extracted in specific file types.
### Example: Adding a Custom Provider
```lua
require('ecolog').setup({
providers = {
{
-- Pattern to match environment variable access
pattern = "ENV%[['\"]%w['\"]%]",
-- Filetype(s) this provider supports (string or table)
filetype = "custom_lang",
-- Function to extract variable name from the line
extract_var = function(line, col)
local before_cursor = line:sub(1, col + 1)
return before_cursor:match("ENV%['\"['\"]%]$")
end,
-- Function to return completion trigger pattern
get_completion_trigger = function()
return "ENV['"
end
}
}
})
```
Each provider must specify:
1. `pattern`: A Lua pattern to match environment variable access in the code
2. `filetype`: The filetype(s) this provider supports (string or table)
3. `extract_var`: Function to extract the variable name from the line
4. `get_completion_trigger`: Function to return the completion trigger pattern
The provider will be automatically loaded when editing files of the specified filetype.
## ๐ Usage
### Available Commands
| Command | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------------- |
| `:EcologPeek [variable_name]` | Peek at environment variable value and metadata |
| `:EcologPeek` | Peek at environment variable under cursor |
| `:EcologRefresh` | Refresh environment variable cache |
| `:EcologSelect` | Open a selection window to choose environment file |
| `:EcologSelect [file_path]` | Directly load a specific environment file without selection prompt |
| `:EcologGoto` | Open selected environment file in buffer |
| `:EcologGotoVar` | Go to specific variable definition in env file |
| `:EcologGotoVar [variable_name]` | Go to specific variable definition in env file with variable under cursor |
| `:EcologShelterToggle [command] [feature]` | Control shelter mode for masking sensitive values |
| `:EcologShelterLinePeek` | Temporarily reveal value on current line in env file |
| `:Telescope ecolog env` | Alternative way to open Telescope picker |
| `:EcologTelescope` | Open environment variables picker using telescope (must have telescope installed) |
| `:EcologFzf` | Alternative way to open fzf-lua picker (must have fzf-lua installed) |
| `:EcologSnacks` | Open environment variables picker using snacks.nvim (must have snacks.nvim installed) |
| `:EcologEnvGet` | Get the value of a specific environment variable |
| `:EcologEnvSet` | Sets the value of a specified environment variable |
| `:EcologCopy [variable_name]` | Copy raw value of environment variable to clipboard |
| `:EcologCopy` | Copy raw value of environment variable under cursor to clipboard |
| `:EcologAWSConfig` | Open configuration menu for AWS Secrets Manager (region, profile, secrets) |
| `:EcologVaultConfig` | Open configuration menu for HCP Vault (organization, project, apps) |
| `:EcologInterpolationToggle` | Toggle environment variable interpolation on/off |
| `:EcologShellToggle` | Loads and unloads shell variables |
## ๐ Environment File Priority
Only one environment file is selected and loaded at a time, based on the following priority order:
1. `.env.{preferred_environment}` (if preferred_environment is set)
2. `.env`
3. Other `.env.*` files (alphabetically)
The first available file in this priority order will be selected. Environment variables from shell and secret managers may still be merged with the selected file's variables.
## ๐ Shell Variables Integration
Ecolog can load environment variables directly from your shell environment. This is useful when you want to:
- Access system environment variables
- Work with variables set by your shell profile
- Handle dynamic environment variables
#### Basic Usage
Enable shell variable loading with default settings:
```lua
require('ecolog').setup({
load_shell = true
})
```
#### Advanced Configuration
For more control over shell variable handling:
```lua
require('ecolog').setup({
load_shell = {
enabled = true, -- Enable shell variable loading
override = false, -- When false, .env files take precedence over shell variables
-- Optional: filter specific shell variables
filter = function(key, value)
-- Example: only load specific variables
return key:match("^(PATH|HOME|USER)$") ~= nil
end,
-- Optional: transform shell variables before loading
transform = function(key, value)
-- Example: prefix shell variables for clarity
return "[shell] " .. value
end
}
})
```
#### Configuration Options
| Option | Type | Default | Description |
| ----------- | ------------- | ------- | ---------------------------------------------------------- |
| `enabled` | boolean | `false` | Enable/disable shell variable loading |
| `override` | boolean | `false` | When true, shell variables take precedence over .env files |
| `filter` | function\|nil | `nil` | Optional function to filter which shell variables to load |
| `transform` | function\|nil | `nil` | Optional function to transform shell variable values |
#### Features
- Full integration with all Ecolog features (completion, peek, shelter mode)
- Shell variables are marked with "shell" as their source
- Configurable precedence between shell and .env file variables
- Optional filtering and transformation of shell variables
- Type detection and value transformation support
#### Best Practices
1. Use `filter` to limit which shell variables are loaded to avoid cluttering
2. Consider using `transform` to clearly mark shell-sourced variables
3. Be mindful of the `override` setting when working with both shell and .env variables
4. Apply shelter mode settings to shell variables containing sensitive data
## ๐ข Monorepo Support
Ecolog provides comprehensive monorepo support for managing environment variables across multiple workspaces and projects. This feature automatically detects monorepo structures and provides intelligent workspace-aware environment variable management.
### Basic Configuration
Enable monorepo support with default settings:
```lua
require('ecolog').setup({
monorepo = true, -- Enable with default configuration
-- or
monorepo = {
enabled = true,
auto_switch = true, -- Automatically switch to workspace based on current file
}
})
```
### Advanced Configuration
The new monorepo system supports advanced configuration with provider-based detection and performance optimization:
```lua
require('ecolog').setup({
monorepo = {
enabled = true,
auto_switch = true,
notify_on_switch = false, -- Show notifications when switching workspaces
-- Provider configuration
providers = {
-- Built-in providers (loaded automatically)
builtin = {
"turborepo",
"nx",
"lerna",
"yarn_workspaces",
"cargo_workspaces"
},
-- Custom providers
custom = {
{
module = "my_custom_provider",
config = { custom_option = "value" }
}
}
},
-- Performance settings
performance = {
-- Cache configuration
cache = {
max_entries = 1000,
default_ttl = 300000, -- 5 minutes
cleanup_interval = 60000 -- 1 minute
},
-- Auto-switch throttling
auto_switch_throttle = {
min_interval = 100, -- Minimum ms between checks
debounce_delay = 250, -- Debounce delay for rapid changes
same_file_skip = true, -- Skip if same file
workspace_boundary_only = true, -- Only check when crossing boundaries
max_checks_per_second = 10 -- Rate limiting
}
}
}
})
```
### Plugin System Configuration
The new monorepo system supports a plugin architecture for extensibility:
```lua
require('ecolog').setup({
monorepo = {
enabled = true,
-- Plugin configuration
plugins = {
-- Load plugins from directory
directory = "/path/to/my/monorepo/plugins",
-- Or register plugins directly
list = {
{
name = "my_monorepo_plugin",
providers = {
{
type = "simple",
name = "my_simple_provider",
detection = {
file_markers = { "my-workspace.json" }
},
workspace = {
patterns = { "apps/*", "libs/*" }
}
}
},
hooks = {
before_detection = function(path)
print("Detecting monorepo at:", path)
end,
after_workspace_switch = function(new_workspace, old_workspace)
print("Switched to workspace:", new_workspace and new_workspace.name or "none")
end
}
}
}
}
}
})
```
### Workspace Detection
The new system uses provider-specific detection instead of global constants:
#### Built-in Providers
Each provider has its own detection logic and workspace patterns:
| Provider | Detection Files | Workspace Patterns |
| -------------------- | -------------------------------------- | -------------------------------------- |
| **Turborepo** | `turbo.json` | `apps/*`, `packages/*` |
| **NX** | `nx.json`, `workspace.json` | `apps/*`, `libs/*`, `tools/*`, `e2e/*` |
| **Lerna** | `lerna.json` | `packages/*` |
| **Yarn Workspaces** | `package.json` (with workspaces field) | `packages/*`, `apps/*`, `services/*` |
| **Cargo Workspaces** | `Cargo.toml` (with workspace section) | `crates/*`, `libs/*`, `bins/*` |
#### Custom Provider Example
```lua
-- File: lua/my_custom_provider.lua
local BaseProvider = require("ecolog.monorepo.detection.providers.base")
local MyCustomProvider = {}
setmetatable(MyCustomProvider, { __index = BaseProvider })
function MyCustomProvider.new(config)
local default_config = {
name = "my_custom_provider",
detection = {
strategies = { "file_markers" },
file_markers = { "my-monorepo.json" },
max_depth = 4,
cache_duration = 300000,
},
workspace = {
patterns = { "workspaces/*", "projects/*" },
priority = { "workspaces", "projects" }
},
env_resolution = {
strategy = "workspace_first",
inheritance = true,
override_order = { "workspace", "root" }
},
priority = 50,
}
local merged_config = config and vim.tbl_deep_extend("force", default_config, config) or default_config
local instance = BaseProvider.new(merged_config)
setmetatable(instance, { __index = MyCustomProvider })
return instance
end
return MyCustomProvider
```
### Factory-Based Provider Creation
```lua
-- Using the factory system for quick custom providers
local Factory = require("ecolog.monorepo.detection.providers.factory")
-- Create from template
local my_provider = Factory.create_from_template("js_monorepo", {
name = "my_js_provider",
detection = {
file_markers = { "my-package.json" }
},
workspace = {
patterns = { "my-apps/*", "my-packages/*" }
}
})
-- Register the provider
local monorepo = require("ecolog.monorepo")
monorepo.register_provider(my_provider.new())
```
### Environment File Resolution
Each provider defines its own environment file resolution strategy:
#### Resolution Strategies
1. **`workspace_first`** (default): Workspace files take precedence over root files
2. **`root_first`**: Root files take precedence over workspace files
3. **`workspace_only`**: Only load workspace environment files
#### Provider-Specific Resolution
Each provider can define its own resolution strategy:
```lua
-- Example: Custom provider with specific resolution
local MyProvider = {}
setmetatable(MyProvider, { __index = BaseProvider })
function MyProvider.new(config)
local default_config = {
name = "my_provider",
-- Provider-specific resolution strategy
env_resolution = {
strategy = "workspace_first",
inheritance = true,
override_order = { "workspace", "root" }
},
-- Provider-specific workspace patterns
workspace = {
patterns = { "my-apps/*", "my-packages/*" },
priority = { "my-apps", "my-packages" }
}
}
local merged_config = config and vim.tbl_deep_extend("force", default_config, config) or default_config
local instance = BaseProvider.new(merged_config)
setmetatable(instance, { __index = MyProvider })
return instance
end
return MyProvider
```
#### Available Templates
The factory system provides pre-configured templates:
```lua
local Factory = require("ecolog.monorepo.detection.providers.factory")
-- Available templates: "simple", "js_monorepo", "generic"
local templates = Factory.get_available_templates()
-- Create from template
local provider = Factory.create_from_template("js_monorepo", {
name = "my_js_provider",
detection = {
file_markers = { "my-package.json" }
}
})
```
### Workspace Switching
#### Automatic Workspace Switching
When `auto_switch = true`, Ecolog automatically switches to the appropriate workspace based on your current file location:
```lua
-- Opens file in apps/frontend/src/component.tsx
-- Automatically switches to apps/frontend workspace
-- Loads environment files from apps/frontend/.env, apps/frontend/.env.local, etc.
```
#### Manual Workspace Selection
When `auto_switch = false`, use `:EcologSelect` to manually choose environment files from all workspaces:
```vim
:EcologSelect
```
This will show files with workspace context:
```
1. .env.local (apps/frontend)
2. .env (apps/frontend)
3. .env.local (apps/backend)
4. .env (apps/backend)
5. .env.local (packages/shared)
6. .env (root)
```
#### Workspace Context Display
All ecolog integrations display workspace context for better identification:
- **File Selection**: Shows workspace path in file listings
- **Completion**: Displays workspace context in completion details
- **Pickers**: Shows workspace information in Telescope, FZF, and Snacks
- **Peek Window**: Displays workspace context in source information
- **Statusline**: Shows current workspace and environment file
### Performance
#### Caching System
```lua
require('ecolog').setup({
monorepo = {
performance = {
cache = {
max_entries = 1000, -- Maximum cache entries
default_ttl = 300000, -- 5 minutes default TTL
cleanup_interval = 60000 -- 1 minute cleanup interval
}
}
}
})
```
#### Auto-Switch Throttling
```lua
require('ecolog').setup({
monorepo = {
performance = {
auto_switch_throttle = {
min_interval = 100, -- Minimum ms between checks
debounce_delay = 250, -- Debounce rapid changes
same_file_skip = true, -- Skip if same file
workspace_boundary_only = true, -- Only check at boundaries
max_checks_per_second = 10 -- Rate limiting
}
}
}
})
```
### API Usage Examples
```lua
local monorepo = require("ecolog.monorepo")
-- Setup with custom configuration
monorepo.setup({
enabled = true,
providers = {
builtin = { "turborepo", "nx" }
}
})
-- Detection
local root_path, provider, info = monorepo.detect_monorepo_root()
if root_path then
print("Found monorepo at:", root_path)
print("Provider:", provider.name)
end
-- Get workspaces
local workspaces = monorepo.get_workspaces(root_path, provider)
for _, workspace in ipairs(workspaces) do
print("Workspace:", workspace.name, "at", workspace.path)
end
-- Manual workspace switching
local current_workspace = monorepo.find_current_workspace(nil, workspaces)
if current_workspace then
monorepo.set_current_workspace(current_workspace)
end
-- Register custom provider
local custom_provider = Factory.create_simple_provider({
name = "my_provider",
detection = {
file_markers = { "my-config.json" }
}
})
monorepo.register_provider(custom_provider.new())
-- Statistics and monitoring
local stats = monorepo.get_stats()
print("Monorepo stats:", vim.inspect(stats))
```
## ๐ก vim.env Integration
Ecolog can automatically sync your environment variables with Neovim's built-in `vim.env` table, making them available to any Neovim process or plugin.
### Configuration
Enable vim.env module in your setup:
```lua
{
vim_env = true, -- false by default
}
```
### Features
- Automatically syncs environment variables to `vim.env`
- Updates `vim.env` in real-time when environment files change
- Cleans up variables when they are removed from the environment file
- Provides commands to inspect the current state
### Example
```lua
-- In your config
require('ecolog').setup({
vim_env = true,
-- ... other options
})
-- After setup, variables from your .env file will be available in vim.env:
print(vim.env.DATABASE_URL) -- prints your database URL
print(vim.env.API_KEY) -- prints your API key
```
### Provider Patterns
The `provider_patterns` option controls how environment variables are extracted from your code and how completion works. It can be configured in two ways:
1. As a boolean (for backward compatibility):
```lua
provider_patterns = true -- Enables both extraction and completion with language patterns
-- or
provider_patterns = false -- Disables both, falls back to word under cursor and basic completion
```
2. As a table for fine-grained control:
```lua
provider_patterns = {
extract = true, -- Controls variable extraction from code
cmp = true -- Controls completion behavior
}
```
#### Extract Mode
The `extract` field controls how variables are extracted from code for features like peek, goto definition, etc:
- When `true` (default): Only recognizes environment variables through language-specific patterns
- Example: In JavaScript, only matches `process.env.MY_VAR` or `import.meta.env.MY_VAR`
- Example: In Python, only matches `os.environ.get('MY_VAR')` or `os.environ['MY_VAR']`
- When `false`: Falls back to the word under cursor if no language provider matches
- Useful when you want to peek at any word that might be an environment variable
- Less strict but might give false positives
#### Completion Mode
The `cmp` field controls how completion behaves:
- When `true` (default):
- Uses language-specific triggers (e.g., `process.env.` in JavaScript)
- Only completes in valid environment variable contexts
- Formats completions according to language patterns
- When `false`:
- Uses a basic trigger (any character)
- Completes environment variables anywhere
- Useful for more flexible but less context-aware completion
#### Example Configurations
1. Default behavior (strict mode):
```lua
provider_patterns = {
extract = true, -- Only extract vars from language patterns
cmp = true -- Only complete in valid contexts
}
```
2. Flexible extraction, strict completion:
```lua
provider_patterns = {
extract = false, -- Extract any word as potential var
cmp = true -- Only complete in valid contexts
}
```
3. Strict extraction, flexible completion:
```lua
provider_patterns = {
extract = true, -- Only extract vars from language patterns
cmp = false -- Complete anywhere
}
```
4. Maximum flexibility:
```lua
provider_patterns = {
extract = false, -- Extract any word as potential var
cmp = false -- Complete anywhere
}
```
This affects all features that extract variables from code (peek, goto definition, etc.) and how completion behaves.
## ๐ก Custom Environment File Patterns
Ecolog supports custom patterns for matching environment files. This allows you to define your own naming conventions and directory structures beyond the default `.env*` pattern.
#### Basic Usage
Set a single custom pattern:
```lua
require('ecolog').setup({
env_file_patterns = { "config/env.*" } -- Matches env.any_here file in the config directory
})
```
Use multiple patterns:
```lua
require('ecolog').setup({
env_file_patterns = {
"config/.env", -- Matches .env file in config directory
"config/.env.*", -- Matches any .env.* file in config directory
"environments/*" -- Matches any file in environments directory
}
})
```
#### Pattern Format
- Patterns use glob/wildcard syntax (e.g., `*` matches any characters)
- Patterns are relative to the project root (`path` option)
- Default patterns (`.env`, `.envrc`, `.env.*`) are used if no custom patterns are specified
- When custom patterns are specified, ONLY those patterns are used (defaults are not included)
#### Pattern Matching Rules
1. **Directory Structure**: Patterns can include directories (e.g., `config/.env`, `environments/.env.*`)
2. **File Extensions**: Use `.*` to match any extension (e.g., `.env.*` matches `.env.development`, `.env.test`)
3. **Wildcards**: Use `*` to match any characters (e.g., `config/*` matches any file in the config directory)
#### Examples
```lua
-- Match specific environments in config directory
env_file_patterns = {
"config/.env.development",
"config/.env.production"
}
-- Match all env files in multiple directories
env_file_patterns = {
"config/env/*",
"environments/*",
".env*"
}
-- Match specific naming convention
env_file_patterns = {
"env.*.config",
"env.*.local"
}
```
#### Default Behavior
If no custom patterns are specified, Ecolog uses these default patterns:
- `.env` - Main environment file
- `.envrc` - Shell environment file
- `.env.*` - Environment-specific files (e.g., `.env.development`, `.env.test`)
## ๐ Custom Sort Functions
Ecolog provides two types of sort functions to customize how both environment files and variables are ordered in various interfaces:
1. **File Sorting (`sort_file_fn`)**: Controls how environment files are prioritized and ordered
2. **Variable Sorting (`sort_var_fn`)**: Controls how environment variables are sorted in completion, pickers, and other interfaces
### File Sorting (`sort_file_fn`)
Ecolog allows you to customize how environment files are sorted using the `sort_file_fn` option (previously named `sort_fn`). This is useful when you need specific ordering beyond the default alphabetical sorting.
#### Basic Usage
```lua
require('ecolog').setup({
sort_file_fn = function(a, b)
-- Sort by file size (smaller files first)
local a_size = vim.fn.getfsize(a)
local b_size = vim.fn.getfsize(b)
return a_size < b_size
end
})
```
#### Examples
1. **Priority-based sorting**:
```lua
sort_file_fn = function(a, b)
local priority = {
[".env.production"] = 1,
[".env.staging"] = 2,
[".env.development"] = 3,
[".env"] = 4
}
local a_name = vim.fn.fnamemodify(a, ":t")
local b_name = vim.fn.fnamemodify(b, ":t")
return (priority[a_name] or 99) < (priority[b_name] or 99)
end
```
2. **Sort by modification time**:
```lua
sort_file_fn = function(a, b)
local a_time = vim.fn.getftime(a)
local b_time = vim.fn.getftime(b)
return a_time > b_time -- Most recently modified first
end
```
3. **Sort by environment type**:
```lua
sort_file_fn = function(a, b)
-- Extract environment type from filename
local function get_env_type(file)
local name = vim.fn.fnamemodify(file, ":t")
return name:match("^%.env%.(.+)$") or ""
end
return get_env_type(a) < get_env_type(b)
end
```
### Variable Sorting (`sort_var_fn`)
The `sort_var_fn` option allows you to customize how environment variables are sorted in various interfaces (completion, pickers, etc.).
#### Basic Usage
```lua
require('ecolog').setup({
sort_var_fn = function(a, b)
-- Sort by variable name length (shorter names first)
return #a.name < #b.name
end
})
```
#### Examples
1. **Sort by value type**:
```lua
sort_var_fn = function(a, b)
-- Sort variables with types before those without
if a.type and not b.type then
return true
elseif not a.type and b.type then
return false
end
-- Then sort alphabetically by name
return a.name < b.name
end
```
2. **Sort by source priority**:
```lua
sort_var_fn = function(a, b)
local priority = {
[".env.local"] = 1,
[".env"] = 2,
["shell"] = 3
}
local a_priority = priority[a.source] or 99
local b_priority = priority[b.source] or 99
return a_priority < b_priority
end
```
3. **Sort by custom categories**:
```lua
sort_var_fn = function(a, b)
-- Sort API keys first, then database variables, then others
local function get_category(var)
if var.name:match("_KEY$") then return 1
elseif var.name:match("^DB_") then return 2
else return 3 end
end
local a_cat = get_category(a)
local b_cat = get_category(b)
if a_cat ~= b_cat then
return a_cat < b_cat
end
return a.name < b.name
end
```
#### Features
- Custom sorting logic for both environment files and variables
- Access to full file paths for file sorting
- Access to variable metadata (name, type, source, value) for variable sorting
- Real-time sorting when files or variables change
- Affects all interfaces where variables are displayed (completion, pickers, etc.)
## ๐ Integrations
### Nvim-cmp Integration
Add `ecolog` to your nvim-cmp sources:
```lua
require('cmp').setup({
sources = {
{ name = 'ecolog' },
-- your other sources...
},
})
```
Nvim-cmp integration is enabled by default. To disable it:
```lua
require('ecolog').setup({
integrations = {
nvim_cmp = false,
},
})
```
See [Currently Supported Languages](#currently-supported) for available completion triggers and [Custom Providers](#-custom-providers) for adding support for additional languages.
### Blink-cmp Integration
PS: When blink_cmp is enabled, nvim_cmp is disabled by default.
Ecolog provides an integration with [blink.cmp](https://github.com/saghen/blink.cmp) for environment variable completions. To enable it:
1. Enable the integration in your Ecolog setup:
```lua
require('ecolog').setup({
integrations = {
blink_cmp = true,
},
})
```
2. Configure Blink CMP to use the Ecolog source:
```lua
{
"saghen/blink.cmp",
opts = {
sources = {
default = { 'ecolog', 'lsp', 'path', 'snippets', 'buffer' },
providers = {
ecolog = { name = 'ecolog', module = 'ecolog.integrations.cmp.blink_cmp' },
},
},
},
}
```
See [Currently Supported Languages](#currently-supported) for available completion triggers and [Custom Providers](#-custom-providers) for adding support for additional languages.
### Omnifunc Integration
Ecolog provides a built-in omnifunc integration that enables environment variable completion using Vim's native completion system (``). This is particularly useful if you prefer not to use nvim-cmp or blink-cmp, or want a lightweight completion option.
#### Setup
The omnifunc integration is disabled by default. To enable it:
```lua
require('ecolog').setup({
integrations = {
omnifunc = true, -- Enable omnifunc integration with automatic setup (default)
-- Or with configuration options:
omnifunc = {
auto_setup = false, -- Disable automatic setup, allowing manual configuration
},
},
})
```
When enabled with `auto_setup = true` (the default), Ecolog will automatically set itself as the omnifunc provider for filetypes that don't already have one configured.
#### Usage
1. In insert mode, type a language-specific environment variable trigger (e.g., `process.env.` for JavaScript)
2. Press `` to trigger omni completion
3. Navigate through completions using `` and ``
4. The preview window will automatically appear at the top of your screen showing:
- Variable type
- Current value
- Source file
- Any associated comments
5. To close the preview window after completion:
- It will close automatically when you leave insert mode
- Or press `` to close it manually
6. Press `` to select a completion
The preview window will show information in this format:
```
VARIABLE_NAME [type] = value # comment (if any)
```
#### Shelter Mode Integration
The omnifunc integration respects shelter mode settings. When shelter mode is enabled for cmp:
```lua
require('ecolog').setup({
shelter = {
modules = {
cmp = true, -- Enable shelter mode for all completion interfaces including omnifunc
}
}
})
```
Variable values will be masked in the completion menu according to your shelter mode configuration. Note that this setting affects all completion interfaces (nvim-cmp, blink-cmp, and omnifunc) since they share the same completion infrastructure.
#### Manual Setup
If you prefer to have full control over where and when the omnifunc is set, you can disable automatic setup with `auto_setup = false` and configure it manually:
```lua
-- In your configuration, for specific filetypes:
vim.api.nvim_create_autocmd("FileType", {
pattern = { "javascript", "typescript", "python" }, -- Add your desired filetypes
callback = function()
vim.bo.omnifunc = "v:lua.require'ecolog.integrations.cmp.omnifunc'.complete"
end,
})
-- Or for a specific buffer:
vim.bo.omnifunc = "v:lua.require'ecolog.integrations.cmp.omnifunc'.complete"
```
This gives you full control over when and where Ecolog's environment variable completion is available. The automatic setup only applies to filetypes without existing omnifunc settings, ensuring it doesn't override your existing configurations.
### LSP Integration (Experimental)
> โ ๏ธ **Warning**: The LSP integration is currently experimental and may interfere with your existing LSP setup. Use with caution.
Ecolog provides optional LSP integration that enhances the hover and definition functionality for environment variables. When enabled, it will:
- Show environment variable values when hovering over them
- Jump to environment variable definitions using goto-definition
meaning you dont need any custom keymaps
#### Setup
To enable LSP integration, add this to your Neovim configuration:
```lua
require('ecolog').setup({
integrations = {
lsp = true,
}
})
```
PS: If you're using lspsaga, please see section [LSP Saga Integration](#lsp-saga-integration) don't use lsp integration use one or the other.
#### Features
- **Hover Preview**: When you hover (K) over an environment variable, it will show the value and metadata in a floating window
- **Goto Definition**: Using goto-definition (gd) on an environment variable will jump to its definition in the .env file
#### Known Limitations
1. The integration overrides the default LSP hover and definition handlers
2. May conflict with other plugins that modify LSP hover behavior
3. Performance impact on LSP operations (though optimized and should be unnoticable)
#### Disabling LSP Integration
If you experience any issues, you can disable the LSP integration:
```lua
require('ecolog').setup({
integrations = {
lsp = false,
}
})
```
Please report such issues on our GitHub repository
### LSP Saga Integration
Ecolog provides integration with [lspsaga.nvim](https://github.com/nvimdev/lspsaga.nvim) that enhances hover and goto-definition functionality for environment variables while preserving Saga's features for other code elements.
#### Setup
To enable LSP Saga integration, add this to your configuration:
```lua
require('ecolog').setup({
integrations = {
lspsaga = true,
}
})
```
PS: If you're using lspsaga then don't use lsp integration use one or the other.
#### Features
The integration adds two commands that intelligently handle both environment variables and regular code:
1. **EcologSagaHover**:
- Shows environment variable value when hovering over env vars
- Falls back to Saga's hover for other code elements
- Automatically replaces existing Saga hover keymaps
2. **EcologSagaGD** (Goto Definition):
- Jumps to environment variable definition in .env file
- Uses Saga's goto definition for other code elements
- Automatically replaces existing Saga goto-definition keymaps
> ๐ก **Note**: When enabled, the integration automatically detects and updates your existing Lspsaga keymaps to use Ecolog's enhanced functionality. No manual keymap configuration required!
#### Example Configuration
```lua
{
'ph1losof/ecolog.nvim',
opts = {
integrations = {
lspsaga = true,
}
},
}
```
> ๐ก **Note**: The LSP Saga integration provides a smoother experience than the experimental LSP integration if you're already using Saga in your setup.
### Telescope Integration
First, load the extension:
```lua
require('telescope').load_extension('ecolog')
```
Then configure it in your Telescope setup (optional):
```lua
require('telescope').setup({
extensions = {
ecolog = {
shelter = {
-- Whether to show masked values when copying to clipboard
mask_on_copy = false,
},
-- Default keybindings
mappings = {
-- Key to copy value to clipboard
copy_value = "",
-- Key to copy name to clipboard
copy_name = "",
-- Key to append value to buffer
append_value = "",
-- Key to append name to buffer (defaults to )
append_name = "",
-- Key to edit environment variable
edit_var = "",
},
}
}
})
```
### FZF Integration
Ecolog integrates with [fzf-lua](https://github.com/ibhagwan/fzf-lua) to provide a fuzzy finder interface for environment variables.
#### Setup
```lua
require('ecolog').setup({
integrations = {
fzf = {
shelter = {
mask_on_copy = false, -- Whether to mask values when copying
},
mappings = {
copy_value = "ctrl-y", -- Copy variable value to clipboard
copy_name = "ctrl-n", -- Copy variable name to clipboard
append_value = "ctrl-a", -- Append value at cursor position
append_name = "enter", -- Append name at cursor position
edit_var = "ctrl-e", -- Edit environment variable
},
}
}
})
```
You can trigger the FZF picker using `:EcologFzf` command.
#### Features
- ๐ Fuzzy search through environment variables
- ๐ Copy variable names or values to clipboard
- โจ๏ธ Insert variables into your code
- โ๏ธ Edit environment variables directly from the picker
- ๐ก๏ธ Integrated with shelter mode for sensitive data protection
- ๐ Real-time updates when environment files change
#### Usage
Open the environment variables picker:
```vim
:EcologFzf
```
#### Default Keymaps
| Key | Action |
| --------- | ----------------------- |
| `` | Insert variable name |
| `` | Copy value to clipboard |
| `` | Copy name to clipboard |
| `` | Append value to buffer |
| `` | Edit variable value |
All keymaps are customizable through the configuration.
### Snacks Integration
Ecolog integrates with [snacks.nvim](https://github.com/folke/snacks.nvim) to provide a modern and beautiful picker interface for environment variables.
#### Setup
```lua
require('ecolog').setup({
integrations = {
snacks = {
shelter = {
mask_on_copy = false, -- Whether to mask values when copying
},
keys = {
copy_value = "", -- Copy variable value to clipboard
copy_name = "", -- Copy variable name to clipboard
append_value = "", -- Append value at cursor position
append_name = "", -- Append name at cursor position
edit_var = "", -- Edit environment variable
},
layout = { -- Any Snacks layout configuration
preset = "dropdown",
preview = false,
},
}
}
})
```
You can trigger the Snacks picker using `:EcologSnacks` command.
#### Features
- ๐จ Beautiful VSCode-like interface
- ๐ Real-time fuzzy search
- ๐ Copy variable names or values to clipboard
- โจ๏ธ Insert variables into your code
- โ๏ธ Edit environment variables directly from the picker
- ๐ก๏ธ Integrated with shelter mode for sensitive data protection
- ๐ Live updates when environment files change
- ๐ฏ Syntax highlighting for better readability
#### Usage
Open the environment variables picker:
```vim
:EcologSnacks
```
#### Default Keymaps
| Key | Action |
| ------- | ----------------------- |
| `` | Insert variable name |
| `` | Copy value to clipboard |
| `` | Copy name to clipboard |
| `` | Append value to buffer |
| `` | Edit variable value |
All keymaps are customizable through the configuration.
### Custom Actions for Pickers
All picker integrations (Telescope, FZF, and Snacks) support custom actions. This allows you to define your own key mappings and actions to perform on environment variables.
#### Adding Custom Actions
You can add custom actions in your Neovim configuration when setting up Ecolog:
```lua
require("ecolog").setup({
-- Your other configuration options
integrations = {
telescope = {
custom_actions = {
-- Define a custom action that appends the variable with special formatting
format_var = {
key = "",
callback = function(item, picker)
-- item contains: name, value, masked_value, source, type
return "${" .. item.name .. "}"
end,
opts = {
close_on_action = true, -- Close the picker after action
notify = true, -- Show notification after action
message = "Formatted variable appended" -- Custom notification message
}
}
}
},
fzf = {
custom_actions = {
-- Similar structure for FZF custom actions
}
},
snacks = {
custom_actions = {
-- Similar structure for Snacks custom actions
}
}
}
})
```
#### Adding Actions After Setup
You can also add custom actions after Ecolog has been set up:
```lua
-- For Telescope
require("telescope").extensions.ecolog.add_action(
"format_var", -- Action name
"", -- Key mapping
function(item, picker) -- Callback function
return "${" .. item.name .. "}"
end,
{ -- Options
close_on_action = true,
notify = true,
message = "Formatted variable appended"
}
)
-- For FZF
require("ecolog.integrations.fzf").add_action("format_var", "ctrl-f", function(item, picker)
return "${" .. item.name .. "}"
end, { notify = true })
-- For Snacks
require("ecolog.integrations.snacks").add_action("format_var", "", function(item, picker)
return "${" .. item.name .. "}"
end, { close_on_action = true })
```
#### Custom Action Parameters
- `name`: A unique name for the action
- `key`: A string or table of strings representing the key mappings
- `callback`: A function that receives:
- `item`: The selected environment variable data
- `picker`: The picker instance
- `opts`: Options table with:
- `close_on_action`: Whether to close the picker after action (default: true)
- `notify`: Whether to show a notification after action (default: true)
- `message`: Custom notification message
The `item` parameter contains the following fields:
- `name`: The environment variable name
- `value`: The actual value
- `masked_value`: The masked value (if shelter.mask_on_copy is enabled)
- `source`: The source of the variable
- `type`: The type of the variable
### Statusline Integration
Ecolog provides a built-in statusline component that shows your current environment file, variable count, and shelter mode status. It supports both native statusline and lualine integration.
#### Setup
```lua
require('ecolog').setup({
integrations = {
statusline = {
hidden_mode = false, -- Hide when no env file is loaded
icons = {
enabled = true, -- Enable icons in statusline
env = "๐ฒ", -- Icon for environment file
shelter = "๐ก๏ธ", -- Icon for shelter mode
},
format = {
env_file = function(name)
return name -- Format environment file name
end,
vars_count = function(count)
return string.format("%d vars", count) -- Format variables count
end,
},
highlights = {
enabled = true, -- Enable custom highlights
env_file = "Directory", -- Highlight group for file name
vars_count = "Number", -- Highlight group for vars count
icons = "Special"
},
}
}
})
```
#### Native Statusline
Add to your statusline:
```lua
vim.o.statusline = "%{%v:lua.require'ecolog'.get_status()%}"
```
#### Lualine Integration
Add to your lualine config:
```lua
require('lualine').setup({
sections = {
lualine_x = {
require('ecolog.integrations.statusline').lualine(),
}
}
})
```
#### Features
- Shows current environment file name
- Displays number of loaded variables
- Indicates shelter mode status
- Configurable icons and formatting
- Custom highlighting support
- Automatic updates on file changes
- Optional hiding when no env file is loaded
#### Advanced Highlighting
The statusline integration supports customizable highlighting with both highlight group names and hex color codes:
```lua
require('ecolog').setup({
integrations = {
statusline = {
highlights = {
enabled = true,
-- Using highlight groups
env_file = "Directory", -- Highlight group for file name
vars_count = "Number", -- Highlight group for vars count
icons = "Special", -- Highlight group for icons
-- OR using hex color codes
env_file = "#7FBBB3", -- Hex color for file name
vars_count = "#A7C080", -- Hex color for vars count
icons = "#ED8796", -- Hex color for icons
-- OR different highlights for env and shelter icons
icons = {
env = "String", -- Highlight group for env icon
shelter = "WarningMsg" -- Highlight group for shelter icon
},
-- OR with hex colors
icons = {
env = "#83C092", -- Hex color for env icon
shelter = "#E67E80" -- Hex color for shelter icon
}
},
}
}
})
```
The highlighting system automatically detects the format and applies the appropriate highlighting:
- Highlight group names: Links to existing highlight groups in your colorscheme
- Hex color codes: Creates dynamic highlight groups with the specified colors
- Table with env/shelter keys: Allows different highlights for each mode
Both the native statusline and lualine integration fully support these highlighting options for all elements (file name, variable count, and icons), ensuring a consistent appearance across different statusline implementations.
### AWS Secrets Manager
The AWS Secrets Manager integration allows you to load secrets from AWS Secrets Manager into your environment variables. This integration requires the AWS CLI to be installed and configured with appropriate credentials.
> โ ๏ธ **Note**: This is a WIP feature and may have breaking changes in future releases.
#### Configuration
```lua
require('ecolog').setup({
integrations = {
secret_managers = {
aws = {
enabled = true, -- Enable AWS Secrets Manager integration
override = false, -- When true, AWS secrets take precedence over .env files and shell variables
region = "us-west-2", -- Required: AWS region where your secrets are stored
profile = "default", -- Optional: AWS profile to use
secrets = { -- Optional: List of secret names to fetch on startup
"my-app/dev/database",
"my-app/dev/api"
},
filter = function(key, value) -- Optional: Filter function for secrets
return true -- Return true to include the secret, false to exclude it
end,
transform = function(key, value) -- Optional: Transform function for secret values
return value -- Return the transformed value
end
}
}
}
})
```
#### Features
- Load secrets from AWS Secrets Manager into your environment variables
- Support for both JSON and plain text secrets:
- JSON secrets: Each key-value pair becomes a separate environment variable
- Plain text secrets: The last part of the secret name is used as the variable name
- Interactive secret selection with visual feedback
- Integration with shelter mode for sensitive data protection
- Automatic credential validation and error handling
- Support for AWS profiles and regions
- Direct configuration access through `:EcologAWSConfig` command
- Real-time configuration changes with automatic secret reloading
- Parallel secret loading with retry support
- Proper cleanup on Neovim exit
#### Interactive Configuration
The `:EcologAWSConfig` command provides access to three main configuration options:
1. **Region**: Select or change the AWS region
2. **Profile**: Choose the AWS profile to use
3. **Secrets**: Select which secrets to load
Each option can be accessed directly using:
```vim
:EcologAWSConfig region " Configure AWS region
:EcologAWSConfig profile " Configure AWS profile
:EcologAWSConfig secrets " Configure which secrets to load
```
Default keybindings in the configuration UI:
| Key | Action |
| --------- | ----------------------------------- |
| `j`/`k` | Navigate through options |
| `` | Toggle selection (for multi-select) |
| `` | Select option or confirm selection |
| `q`/`ESC` | Close without changes |
#### Requirements
- AWS CLI v2 installed and configured (`aws --version` should show version 2.x.x)
- AWS CLI must be authenticated with valid credentials using one of:
- `aws configure` to set up credentials
- AWS SSO login (`aws sso login`)
- Environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY)
- IAM role with appropriate permissions
- Appropriate AWS credentials with permissions to access the specified secrets
#### Error Handling
The integration provides clear error messages for common issues:
- Invalid or missing AWS credentials
- Network connectivity problems
- Access denied errors
- Region configuration issues
- Missing or invalid secrets
- Command timeout errors
- AWS CLI installation issues
### HashiCorp Vault Secrets
The HashiCorp Vault Secrets integration allows you to load secrets from HCP Vault Secrets into your environment variables. This integration requires the HCP CLI to be installed and configured with appropriate credentials.
> โ ๏ธ **Note**: This is a WIP feature and may have breaking changes in future releases.
#### Configuration
```lua
require('ecolog').setup({
integrations = {
secret_managers = {
vault = {
enabled = true, -- Enable HCP Vault Secrets integration
override = false, -- When true, Vault secrets take precedence over .env files and shell variables
apps = { -- Optional: List of application names to fetch secrets from by default
"sample-app",
"database"
},
filter = function(key, value) -- Optional: Filter function for secrets
return true -- Return true to include the secret, false to exclude it
end,
transform = function(key, value) -- Optional: Transform function for secret values
return value -- Return the transformed value
end
}
}
}
})
```
#### Features
- Load secrets from HCP Vault Secrets into your environment variables
- Support for both JSON and plain text secrets:
- JSON secrets: Each key-value pair becomes a separate environment variable
- Plain text secrets: The secret name is used as the variable name
- Interactive application and secret selection with visual feedback
- Integration with shelter mode for sensitive data protection
- Automatic credential validation and error handling
- Support for HCP service principal authentication
- Direct configuration access through `:EcologVaultConfig` command
- Real-time configuration changes with automatic secret reloading
- Proper cleanup on Neovim exit
#### Interactive Configuration
The `:EcologVaultConfig` command provides access to three main configuration options:
1. **Organization**: Select or change the HCP organization
2. **Project**: Choose the HCP project to use
3. **Apps**: Select which applications to load secrets from
Each option can be accessed directly using:
```vim
:EcologVaultConfig organization " Configure HCP organization
:EcologVaultConfig project " Configure HCP project
:EcologVaultConfig apps " Configure which apps to load secrets from
```
Default keybindings in the configuration UI:
| Key | Action |
| --------- | ----------------------------------- |
| `j`/`k` | Navigate through options |
| `` | Toggle selection (for multi-select) |
| `` | Select option or confirm selection |
| `q`/`ESC` | Close without changes |
#### Requirements
- HCP CLI installed (`hcp --version` should be available)
- HCP CLI must be authenticated with valid credentials using one of:
- HCP service principal credentials (client ID and client secret)
- `hcp auth login` command
- Appropriate HCP permissions to access the specified applications and secrets
#### Error Handling
The integration provides clear error messages for common issues:
- Invalid or missing HCP credentials
- Network connectivity problems
- Access denied errors
- Missing or invalid applications
- Missing or invalid secrets
- Command timeout errors
- HCP CLI installation issues
### ๐ Shelter Previewers
`ecolog.nvim` integrates with various file pickers to provide a secure way to use file picker without leaking sensitive data, when searching for files.
- Secure environment file previews
- Configurable masking behavior
- Minimal memory footprint
- Efficient buffer management
- Integration with fzf-lua, telescope and snacks.picker
#### Telescope Previewer
Configuration:
```lua
require('ecolog').setup({
shelter = {
modules = {
telescope_previewer = true, -- Mask values in telescope preview buffers
}
}
})
```
#### FZF Previewer
Configuration:
```lua
require('ecolog').setup({
shelter = {
modules = {
fzf_previewer = true, -- Mask values in fzf preview buffers
}
}
})
```
#### Snacks Previewer
Configuration:
```lua
require('ecolog').setup({
shelter = {
modules = {
snacks_previewer = true, -- Mask values in snacks previewer
}
}
})
```
## ๐ก๏ธ Shelter Mode
Shelter mode provides a secure way to work with sensitive environment variables by masking their values in different contexts. This feature helps prevent accidental exposure of sensitive data like API keys, passwords, tokens, and other credentials.
### ๐ง Configuration
```lua
require('ecolog').setup({
shelter = {
configuration = {
-- Partial mode configuration:
-- false: completely mask values (default)
-- true: use default partial masking settings
-- table: customize partial masking
-- partial_mode = false,
-- or with custom settings:
partial_mode = {
show_start = 3, -- Show first 3 characters
show_end = 3, -- Show last 3 characters
min_mask = 3, -- Minimum masked characters
},
mask_char = "*", -- Character used for masking
mask_length = nil, -- Optional: fixed length for masked portion (defaults to value length)
skip_comments = false, -- Skip masking comment lines in environment files (default: false)
},
modules = {
cmp = false, -- Mask values in completion
peek = false, -- Mask values in peek view
files = false, -- Mask values in files
telescope = false, -- Mask values in telescope integration
telescope_previewer = false, -- Mask values in telescope preview buffers
fzf = false, -- Mask values in fzf picker
fzf_previewer = false, -- Mask values in fzf preview buffers
snacks = false, -- Mask values in snacks picker
snacks_previewer = false, -- Mask values in snacks previewer
}
},
path = vim.fn.getcwd(), -- Path to search for .env files
preferred_environment = "development", -- Optional: prioritize specific env files
})
```
### ๐ฏ Features
#### Module-specific Masking
1. **Completion Menu (`cmp = true`)**
- Masks values in nvim-cmp completion menu
- Protects sensitive data during autocompletion
2. **Peek View (`peek = true`)**
- Masks values when using EcologPeek command
- Allows secure variable inspection
3. **File View (`files = true`)**
- Masks values directly in .env files
- Use `:EcologShelterLinePeek` to temporarily reveal values
4. **Telescope Preview (`telescope_previewer = true`)**
- Masks values in telescope preview buffers
- Automatically applies to any `.env` file previewed in telescope with support of custom env file patterns
- Maintains masking state across buffer refreshes
5. **FZF Preview (`fzf_previewer = true`)**
- Masks values in fzf-lua preview buffers
- Automatically applies to any `.env` file previewed in fzf-lua with support of custom env file patterns
- Supports all fzf-lua commands that show previews (files, git_files, live_grep, etc.)
- Maintains masking state across buffer refreshes
- Optimized for performance with buffer content caching
6. **FZF Picker (`fzf = true`)**
- Masks values in fzf-lua picker
7. **Telescope Integration (`telescope = true`)**
- Masks values in telescope picker from integration
8. **Snacks Integration (`snacks = true`, `snacks_previewer = true`)**
- Masks values in snacks picker and previewer
- Provides secure browsing of environment variables
#### Partial Masking
Three modes of operation:
1. **Full Masking (Default)**
```lua
partial_mode = false
-- Example: "my-secret-key" -> "************"
```
2. **Default Partial Masking**
```lua
partial_mode = true
-- Example: "my-secret-key" -> "my-***-key"
```
3. **Custom Partial Masking**
```lua
partial_mode = {
show_start = 4, -- Show more start characters
show_end = 2, -- Show fewer end characters
min_mask = 3, -- Minimum mask length
}
-- Example: "my-secret-key" -> "my-s***ey"
```
#### Masking Length Control
You can control the length of masked portions using the `mask_length` option:
1. **Full Masking Mode**:
```lua
shelter = {
configuration = {
partial_mode = false,
mask_length = 5 -- All masked values will be 5 characters long
}
}
-- Examples:
-- "my-secret-key" -> "*****" -- Long value becomes 5 chars
-- "short" -> "*****" -- Short value padded to 5 chars
-- "very-long-secret" -> "*****" -- Long value truncated to 5 chars
```
2. **Partial Masking Mode**:
```lua
shelter = {
configuration = {
partial_mode = true,
mask_length = 5 -- Masked portion will be 5 characters
}
}
-- Example: "my-secret-key" -> "my-*****-key"
-- Example: "short-key" -> "sho*****key"
```
When `mask_length` is not set (nil), the masked portion will match the length of the original value.
### ๐ฎ Commands
`:EcologShelterToggle` provides flexible control over shelter mode:
1. Basic Usage:
```vim
:EcologShelterToggle " Toggle between all-off and initial settings
```
2. Global Control:
```vim
:EcologShelterToggle enable " Enable all shelter modes
:EcologShelterToggle disable " Disable all shelter modes
```
3. Feature-Specific Control:
```vim
:EcologShelterToggle enable cmp " Enable shelter for completion only
:EcologShelterToggle disable peek " Disable shelter for peek only
:EcologShelterToggle enable files " Enable shelter for file display
```
4. Quick Value Reveal:
```vim
:EcologShelterLinePeek " Temporarily reveal value on current line
```
- Shows the actual value for the current line
- Value is hidden again when cursor moves away
- Only works when shelter mode is enabled for files
### ๐ Example
Original `.env` file:
```env
# Authentication
JWT_SECRET=my-super-secret-key
AUTH_TOKEN="bearer 1234567890"
# Database Configuration
DB_HOST=localhost
DB_USER=admin
DB_PASS=secure_password123
```
With full masking (partial_mode = false):
```env
# Authentication
JWT_SECRET=********************
AUTH_TOKEN=******************
# Database Configuration
DB_HOST=*********
DB_USER=*****
DB_PASS=******************
```
#### Partial Masking Examples
With default settings (show_start=3, show_end=3, min_mask=3):
```
"mysecretkey" -> "mys***key" # Enough space for min_mask (3) characters
"secret" -> "******" # Not enough space for min_mask between shown parts
"api_key" -> "*******" # Would only have 1 char for masking, less than min_mask
"very_long_key" -> "ver*****key" # Plenty of space for masking
```
The min_mask setting ensures that sensitive values are properly protected by requiring
a minimum number of masked characters between the visible parts. If this minimum
cannot be met, the entire value is masked for security.
### Configuration Options
The files module can be configured in two ways:
1. **Simple boolean configuration**:
```lua
shelter = {
modules = {
files = true -- Simply enable/disable files module
}
}
```
2. **Detailed configuration with options**:
```lua
shelter = {
modules = {
files = {
shelter_on_leave = false, -- Control automatic re-enabling of shelter when leaving buffer
disable_cmp = true, -- Disable completion in sheltered buffers (default: true)
skip_comments = false, -- Skip masking comment lines in environment files (default: false)
}
},
configuration = {
skip_comments = false, -- Skip masking comment lines in environment files (default: false)
}
}
```
When `shelter_on_leave` is enabled (default when using boolean configuration), the shelter mode will automatically re-enable itself when you leave an environment file buffer. This provides an extra layer of security by ensuring sensitive data is always masked when not actively being viewed.
The `disable_cmp` option (enabled by default) will automatically disable both nvim-cmp and blink-cmp completions in sheltered buffers. This prevents sensitive values from being exposed through the completion menu while editing environment files. Completion is automatically re-enabled when unsheltering the buffer.
The `skip_comments` option (disabled by default) allows you to keep comments visible while masking the actual environment variable values. This can be useful when you want to maintain readability of documentation in your environment files while still protecting sensitive data.
### Enhanced Comment Masking
Ecolog now intelligently masks key-value pairs found in comments. This provides additional security for comments that might contain sensitive information. For example:
```env
# Configuration for testing - api_key=MY_SECRET_KEY user=admin
DB_URL=postgres://user:password@localhost:5432/db
```
With comment masking enabled (the default), any key-value pairs in comments will also be masked, providing more comprehensive protection. This feature works across:
- CMP completion popups (nvim-cmp, blink-cmp, omnifunc)
- Peek information windows
- File buffers (when shelter is enabled)
### Pattern-based Protection
You can define different masking rules based on variable names or file sources:
```lua
shelter = {
configuration = {
-- Pattern-based rules take precedence
patterns = {
["*_KEY"] = "full", -- Always fully mask API keys
["TEST_*"] = "none", -- Never mask test variables
},
-- Source-based rules as fallback
sources = {
[".env.*"] = "full",
[".env.local"] = "none",
["shell"] = "none",
},
}
}
```
## ๐จ Customization
1. **Custom Mask Character**:
```lua
shelter = {
configuration = {
mask_char = "โข" -- Use dots
}
}
-- or
shelter = {
configuration = {
mask_char = "โ" -- Use blocks
}
}
```
2. **Custom Highlighting**:
```lua
shelter = {
configuration = {
highlight_group = "NonText" -- Use a different highlight group for masked values
}
}
```
### ๐ก Best Practices
1. Enable shelter mode by default for production environments
2. Use file shelter mode during screen sharing or pair programming
3. Enable completion shelter mode to prevent accidental exposure in screenshots
4. Use source-based masking to protect sensitive files
5. Apply stricter masking rules for production and staging environments
6. Keep development and test files less restricted for better workflow
## ๐ก Ecolog Types
Ecolog includes a flexible type system for environment variables with built-in and custom types.
### Type Configuration
Configure types through the `types` option in setup:
```lua
require('ecolog').setup({
custom_types = {
semver = {
pattern = "^v?%d+%.%d+%.%d+%-?[%w]*$",
validate = function(value)
local major, minor, patch = value:match("^v?(%d+)%.(%d+)%.(%d+)")
return major and minor and patch
end,
},
aws_region = {
pattern = "^[a-z]{2}%-[a-z]+%-[0-9]$",
validate = function(value)
local valid_regions = {
["us-east-1"] = true,
["us-west-2"] = true,
-- ... etc
}
return valid_regions[value] == true
end
}
},
types = {
-- Built-in types
url = true, -- URLs (http/https)
localhost = true, -- Localhost URLs
ipv4 = true, -- IPv4 addresses
database_url = true, -- Database connection strings
number = true, -- Integers and decimals
boolean = true, -- true/false/yes/no/1/0
json = true, -- JSON objects and arrays
iso_date = true, -- ISO 8601 dates (YYYY-MM-DD)
iso_time = true, -- ISO 8601 times (HH:MM:SS)
hex_color = true, -- Hex color codes (#RGB or #RRGGBB)
}
})
```
You can also:
- Enable all built-in types: `types = true`
- Disable all built-in types: `types = false`
- Enable specific types and add custom ones:
```lua
require('ecolog').setup({
custom_types = {
jwt = {
pattern = "^[A-Za-z0-9%-_]+%.[A-Za-z0-9%-_]+%.[A-Za-z0-9%-_]+$",
validate = function(value)
local parts = vim.split(value, ".", { plain = true })
return #parts == 3
end
},
}
types = {
url = true,
number = true,
}
})
```
### Custom Type Definition
Each custom type requires:
1. **`pattern`** (required): A Lua pattern string for initial matching
2. **`validate`** (optional): A function for additional validation
3. **`transform`** (optional): A function to transform the value
Example usage in .env files:
```env
VERSION=v1.2.3 # Will be detected as semver type
REGION=us-east-1 # Will be detected as aws_region type
AUTH_TOKEN=eyJhbG.eyJzd.iOiJ # Will be detected as jwt type
```
## ๐ก Tips
1. **Selective Protection**: Enable shelter mode only for sensitive environments:
```lua
-- In your config
if vim.fn.getcwd():match("production") then
require('ecolog').setup({
shelter = {
configuration = {
partial_mode = {
show_start = 3, -- Number of characters to show at start
show_end = 3, -- Number of characters to show at end
min_mask = 3, -- Minimum number of mask characters
},
mask_char = "*", -- Character used for masking
-- Mask all values from production files
sources = {
[".env.prod"] = "full",
[".env.local"] = "partial",
["shell"] = "none",
},
},
modules = {
cmp = true, -- Mask values in completion
peek = true, -- Mask values in peek view
files = true, -- Mask values in files
telescope = false, -- Mask values in telescope
telescope_previewer = false, -- Mask values in telescope preview buffers
}
},
path = vim.fn.getcwd(), -- Path to search for .env files
preferred_environment = "development", -- Optional: prioritize specific env files
})
end
```
2. **Source-based Protection**: Use different masking levels based on file sources:
```lua
shelter = {
configuration = {
-- Mask values based on their source file
sources = {
[".env.prod"] = "full",
[".env.local"] = "partial",
["shell"] = "none",
},
-- Pattern-based rules take precedence
patterns = {
["*_KEY"] = "full", -- Always fully mask API keys
["TEST_*"] = "none", -- Never mask test variables
},
}
}
```
3. **Custom Masking**: Use different characters for masking:
```lua
shelter = {
configuration = {
mask_char = "โข" -- Use dots
}
}
-- or
shelter = {
configuration = {
mask_char = "โ" -- Use blocks
}
}
-- or
shelter = {
configuration = {
highlight_group = "NonText" -- Use a different highlight group for masked values
}
}
```
The `highlight_group` option allows you to customize the highlight group used for masked values. By default, it uses the `Comment` highlight group. You can use any valid Neovim highlight group name.
4. **Temporary Viewing**: Use `:EcologShelterToggle disable` temporarily when you need to view values, then re-enable with `:EcologShelterToggle enable`
5. **Security Best Practices**:
- Enable shelter mode by default for production environments
- Use file shelter mode during screen sharing or pair programming
- Enable completion shelter mode to prevent accidental exposure in screenshots
- Use source-based masking to protect sensitive files
- Apply stricter masking rules for production and staging environments
- Keep development and test files less restricted for better workflow
## ๐จ Theme Integration
The plugin seamlessly integrates with your current colorscheme:
| Element | Color Source |
| -------------- | ------------ |
| Variable names | `Identifier` |
| Types | `Type` |
| Values | `String` |
| Sources | `Directory` |
## ๐ ๏ธ Author Setup
It's author's (`ph1losof`) personal setup for ecolog.nvim, it is opionated. However, it usefull to quickly get started especially if you don't want to think much of a setup and reading docs:
> **Note**: Additional setup is required for [blink-cmp](#blink-cmp-integration) and [statusline](#statusline-integration) integrations.
```lua
{
'ph1losof/ecolog.nvim',
branch = "v1",
keys = {
{ 'e', '', desc = '+ecolog', mode = { 'n', 'v' } },
{ 'el', 'EcologShelterLinePeek', desc = 'Peek line' },
{ 'ey', 'EcologCopy', desc = 'Copy value under cursor' },
{ 'ei', 'EcologInterpolationToggle', desc = 'Toggle interpolation' },
{ 'eh', 'EcologShellToggle', desc = 'Toggle shell variables' },
{ 'ge', 'EcologGoto', desc = 'Go to env file' },
{ 'ec', 'EcologSnacks', desc = 'Open a picker' },
{ 'eS', 'EcologSelect', desc = 'Switch env file' },
{ 'es', 'EcologShelterToggle', desc = 'Shelter toggle' },
},
opts = {
preferred_environment = 'local',
types = true,
monorepo = {
enabled = true,
auto_switch = true,
notify_on_switch = false,
},
providers = {
{
pattern = '{{[%w_]+}}?$',
filetype = 'http',
extract_var = function(line, col)
local utils = require 'ecolog.utils'
return utils.extract_env_var(line, col, '{{([%w_]+)}}?$')
end,
get_completion_trigger = function()
return '{{'
end,
},
},
interpolation = {
enabled = true,
features = {
commands = false,
},
},
sort_var_fn = function(a, b)
if a.source == 'shell' and b.source ~= 'shell' then
return false
end
if a.source ~= 'shell' and b.source == 'shell' then
return true
end
return a.name < b.name
end,
integrations = {
lspsaga = true,
blink_cmp = true,
snacks = true,
statusline = {
hidden_mode = true,
icons = { enabled = true, env = 'E', shelter = 'S' },
highlights = {
env_file = 'Directory',
vars_count = 'Number',
},
},
},
shelter = {
configuration = {
patterns = {
['DATABASE_URL'] = 'full',
},
sources = {
['.env.example'] = 'none',
},
partial_mode = {
min_mask = 5,
show_start = 1,
show_end = 1,
},
mask_char = '*',
},
modules = {
files = true,
peek = false,
snacks_previewer = true,
snacks = false,
cmp = true,
},
},
path = vim.fn.getcwd(),
},
}
```
## ๐ Comparisons
While `ecolog.nvim` has many great and unique features, here are some comparisons with other plugins in neovim ecosystem in **_their specific fields_**:
### Environment Variable Completion (vs [cmp-dotenv](https://github.com/jcha0713/cmp-dotenv))
| Feature | ecolog.nvim | cmp-dotenv |
| -------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| Language-aware Completion | โ
Fully configurable context-aware triggers for multiple languages and filetypes | โ Basic environment variable completion only on every char |
| Type System | โ
Built-in type validation and custom types | โ No type system |
| Nvim-cmp support | โ
Nvim-cmp integration | โ
Nvim-cmp integration |
| Blink-cmp support | โ
Native blink-cmp integration | โ Doesn't support blink-cmp natively |
| Omnifunc support | โ
Native vim's omnifunc | โ Doesn't support omnifunc |
| Multi-line env variables | โ
Full support | โ No support |
| Documentation Support | โ
Rich documentation with type info and source | ๐ก Basic documentation support |
| Shell Variable Integration | โ
Configurable shell variable loading and filtering | ๐ก Basic shell variable support |
| Sorting | โ
Built-in fully customizable sorting for both variables and files, involving all all integrations | โ No sorting supported |
| Multiple Environment Files | โ
Priority-based loading with custom sorting and switching between multiple environment files | ๐ก Basic environment variable loading |
### Security Features (vs [cloak.nvim](https://github.com/laytan/cloak.nvim))
| Feature | ecolog.nvim | cloak.nvim |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Partial Value Masking | โ
Configurable partial masking with patterns | ๐ก Full masking only |
| Pattern-based Security | โ
Custom patterns for different security levels | ๐ก Basic pattern matching |
| Preview Protection | โ
Telescope/FZF/Snacks picker preview protection | ๐ก Only Telescope preview protection |
| Avoid value leaking | โ
Full support, never leak environment variables | โ Doesn't support masking on startup and pasting content from insert mode, flashes values |
| Mask on leave | โ
Supports | โ
Supports |
| Completion disable | โ
Supports both blink-cmp and nvim-cmp, configurable | ๐ก Only nvim-cmp and can't disable |
| Custom mask and highlights | โ
Supports | โ
Supports |
| Multi-line env variables | โ
Full support | โ No support |
| Performance | โ
Significantly better performance and memory usage, especially in previewer buffers due to LRU caching, on benchmarks faster when opening/processing files. ~2.5ms startup | ๐ก Significantly slower on file processing. However, due to minimal implementation startup time is much lower |
| Line of code | ๐ก ~2500+ LOC actively used on average, the rest is lazy loaded | โ
Only ~300 LOC |
| Supports custom integrations | โ
Supports all ecolog.nvim features telescope-lua, snacks, fzf-lua, cmp, peek and etc. | ๐ก Only works in file buffers and telescope previewer |
| Setup and Docs | ๐ก Docs are big due to the amount of features, but it's well documented and the plugin provides a lot of defaults, so it should be relatively easy to setup | โ
Well documented and easy to setup |
| Filetype support | ๐ก Supports only `sh` and `.env` files | โ
Can work in any filetype |
### Environment Management (vs [telescope-env.nvim](https://github.com/LinArcX/telescope-env.nvim))
| Feature | ecolog.nvim | telescope-env.nvim |
| --------------------------- | ------------------------------------------- | ----------------------- |
| Environment Variable Search | โ
Basic search | โ
Basic search |
| Customizable keymaps | โ
Fully customizable | โ
Fully customizable |
| Value Preview | โ
Protected value preview | ๐ก Basic value preview |
| Multiple Picker Support | โ
Telescope, Snacks picker and FZF support | ๐ก Telescope only |
| Security Features | โ
Integrated security in previews | โ No security features |
| Custom Sort/Filter | โ
Advanced sorting and filtering options | ๐ก Basic sorting only |
### File Management (vs [dotenv.nvim](https://github.com/ellisonleao/dotenv.nvim))
| Feature | ecolog.nvim | dotenv.nvim |
| ---------------------------- | ------------------------------------------------------ | ------------------------------------------------ |
| Environment File Detection | โ
Custom patterns and priority-based loading | ๐ก Basic env file loading |
| Multi-line env variables | โ
Full support | โ No support |
| Monorepo support | โ
Support for monorepo environments and custom config | ๐ก No direct support, configuration very limited |
| Multiple Environment Support | โ
Advanced environment file switching | ๐ก Basic environment support |
| Shell Variable Integration | โ
Configurable shell variable loading and filtering | โ No shell integration |
### Key Benefits of ecolog.nvim
1. **All-in-One Solution**: Most importantly it combines features from multiple plugins into a cohesive environment management suite which also opens new possibilties
2. **Language Intelligence**: Provides language-specific completions and integrations
3. **Advanced Security**: Offers the most comprehensive security features for sensitive data
4. **Type System**: Unique type system for validation and documentation
5. **Rich Integrations**: Seamless integration with LSP, Telescope, FZF, EcologPeek and more
6. **Performance**: Optimzed for speed and efficiency in mind
7. **Extensibility**: Custom providers and types for extending functionality
## ๐ค Contributing
Contributions are welcome! Feel free to:
- ๐ Report bugs
- ๐ก Suggest features
- ๐ง Submit pull requests
## ๐ License
MIT License - See [LICENSE](./LICENSE) for details.
---