Table of Contents
eth.nvim
A Neovim plugin for navigating Ethereum addresses and transaction hashes to various block explorers.
Features
- π Smart Detection: Automatically detects Ethereum addresses and transaction hashes in visual selections
- π Multiple Explorers: Support for Etherscan, Arbiscan, Polygonscan, BSCScan, and custom explorers
- π§ Frecency Ordering: Smart ordering of explorer options based on frequency and recency of use
- βοΈ Configurable: Easy to configure with custom block explorers and URL templates
- π Fast: Lightweight Lua implementation with minimal overhead
- π§ͺ Well Tested: Comprehensive test suite with high coverage
- π Trace Folding: Optional fold expression to collapse foundry trace output
Installation
Using lazy.nvim
{
"0xferrous/eth.nvim",
config = function()
require("eth-nvim").setup({
-- your configuration here
})
end,
}
Using packer.nvim
use {
"0xferrous/eth.nvim",
config = function()
require("eth-nvim").setup()
end
}
Usage
- Visual Selection: Select an Ethereum address or transaction hash in visual mode
- Navigate: Press
<leader>ee(default) or run:lua require('eth-nvim').explore_selection() - Choose Explorer: Select from the configured block explorers (ordered by frecency)
- Open: The URL opens in your default browser
Examples
Select any of these in visual mode and use <leader>ee:
- Address:
0x742d35cc6635c0532925a3b8d3ac25e0b7e4576c - Transaction:
0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Configuration
Default Configuration
require("eth-nvim").setup({
explorers = {
{
name = "Etherscan",
address_url = "https://etherscan.io/address/{address}",
tx_url = "https://etherscan.io/tx/{tx}",
},
{
name = "Arbiscan",
address_url = "https://arbiscan.io/address/{address}",
tx_url = "https://arbiscan.io/tx/{tx}",
},
{
name = "Polygonscan",
address_url = "https://polygonscan.com/address/{address}",
tx_url = "https://polygonscan.com/tx/{tx}",
},
{
name = "BSCScan",
address_url = "https://bscscan.com/address/{address}",
tx_url = "https://bscscan.com/tx/{tx}",
},
},
default_browser_cmd = nil, -- Auto-detect system browser
keymaps = {
explore = "<leader>ee",
},
})
Adding Custom Explorers
require("eth-nvim").setup({
explorers = {
{
name = "Optimism",
address_url = "https://optimistic.etherscan.io/address/{address}",
tx_url = "https://optimistic.etherscan.io/tx/{tx}",
},
{
name = "Gnosis",
address_url = "https://gnosisscan.io/address/{address}",
tx_url = "https://gnosisscan.io/tx/{tx}",
},
-- Add your custom explorers here
},
})
Custom Browser Command
require("eth-nvim").setup({
default_browser_cmd = "firefox", -- or "google-chrome", "brave", etc.
})
Custom Keymaps
require("eth-nvim").setup({
keymaps = {
explore = "<leader>eb", -- Change default keymap
},
})
Commands
:lua require('eth-nvim').explore_selection()- Explore selected Ethereum address/tx:lua require('eth-nvim').show_config()- Show current configuration:EthTraceFoldEnable- Enable folding for foundry traces in the current buffer:EthTraceFoldDisable- Disable trace folding in the current buffer:EthTraceFoldToggle- Toggle trace folding in the current buffer
Trace Folding
Enable folding for foundry traces (with Unicode box-drawing prefixes):
:EthTraceFoldEnable
" Use zM/zR to close/open all folds; za to toggle
Disable or toggle:
:EthTraceFoldDisable
:EthTraceFoldToggle
How it works
- The fold level is derived from each lineβs left prefix:
- Leading whitespace is ignored.
- Count leading
βcharacters (nesting level) after whitespace. - If the line begins with
βorβ(after any spaces/β), add +1. - No prefix β depth 0 (top level).
- The plugin sets
foldmethod=exprand usesrequire('eth-nvim.trace').foldexprto compute levels. foldtextsummarizes folded blocks: first line β¦ [N lines] Β· last line.- ANSI escape codes are stripped during parsing, so colored traces work. Virttext/highlight plugins are compatible.
Example
β ββ call A -> depth 2
β β ββ return -> depth 3
ββ final -> depth 1
Limitations
- Requires Unicode box-drawing (
β,β,β). Plain ASCII (|,+-) is not parsed. - Mixed/malformed prefixes may yield inconsistent folds.
API
Functions
require('eth-nvim').setup(opts)- Setup plugin with optionsrequire('eth-nvim').explore_selection()- Explore current visual selectionrequire('eth-nvim').show_config()- Display current configurationrequire('eth-nvim').enable_trace_folds()- Enable trace folding in current bufferrequire('eth-nvim').disable_trace_folds()- Disable trace folding in current bufferrequire('eth-nvim').toggle_trace_folds()- Toggle trace folding in current buffer
Utility Functions
require('eth-nvim.utils').is_valid_ethereum_address(text)- Validate Ethereum addressrequire('eth-nvim.utils').is_valid_transaction_hash(text)- Validate transaction hashrequire('eth-nvim.utils').detect_ethereum_type(text)- Detect if text is address or txrequire('eth-nvim.explorers').add_explorer(name, address_url, tx_url)- Add explorer programmatically
Development
This project uses Nix for development environment setup.
Prerequisites
- Nix with flakes enabled
Development Shell
nix develop
Running Tests
nix develop --command busted
Linting
nix develop --command luacheck lua/
Formatting
nix develop --command stylua .
Building
nix build
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run tests and linting:
nix flake check - Submit a pull request
License
MIT License - see LICENSE file for details.
Supported Networks
The default configuration includes explorers for:
- Ethereum (Etherscan)
- Arbitrum (Arbiscan)
- Polygon (Polygonscan)
- BSC (BSCScan)
You can easily add support for other networks by configuring custom explorers.
Frecency Implementation
The frecency system combines frequency and recency to intelligently order explorer options:
Algorithm Details
Frecency Score = (Usage Count Γ Recency Factor) + Recent Usage Bonus
Where:
- Usage Count: Total number of times an explorer has been selected
- Recency Factor: Time-based multiplier applied based on last usage:
- Used < 1 day ago: 4x multiplier
- Used < 1 week ago: 2x multiplier
- Used < 1 month ago: 1x multiplier
- Used > 1 month ago: 0.5x multiplier
- Recent Usage Bonus: +0.1 for each usage within the past week
Data Storage
Usage data is stored in ~/.local/share/nvim/eth-nvim/frecency.json with per-directory tracking:
{
"global": {
"Etherscan": {
"count": 15,
"last_used": 1703123456,
"timestamps": [1703123456, 1703109876, ...]
},
"Arbiscan": {
"count": 8,
"last_used": 1703000000,
"timestamps": [1703000000, 1702999876, ...]
}
},
"directories": {
"/home/user/defi-project": {
"Etherscan": {
"count": 10,
"last_used": 1703123456,
"timestamps": [1703123456, ...]
},
"Polygonscan": {
"count": 5,
"last_used": 1703100000,
"timestamps": [1703100000, ...]
}
},
"/home/user/layer2-project": {
"Arbiscan": {
"count": 12,
"last_used": 1703120000,
"timestamps": [1703120000, ...]
}
}
}
}
Privacy & Performance
- Only the last 20 timestamps are stored per explorer to limit data growth
- No sensitive information (addresses, transactions) is stored
- Data persists across Neovim sessions
- Per-directory tracking adapts to project-specific network usage
- Automatic fallback to global data when no directory-specific data exists
- Automatic fallback to original order for new/unused explorers
- Legacy data format automatically migrated to new per-directory structureYou can easily add support for other networks by configuring custom explorers.