A Neovim plugin for navigating Ethereum addresses and transaction hashes to various block explorers.
- 🔍 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
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
}- 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
Select any of these in visual mode and use <leader>ee:
- Address:
0x742d35cc6635c0532925a3b8d3ac25e0b7e4576c - Transaction:
0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
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",
},
})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
},
})require("eth-nvim").setup({
default_browser_cmd = "firefox", -- or "google-chrome", "brave", etc.
})require("eth-nvim").setup({
keymaps = {
explore = "<leader>eb", -- Change default keymap
},
}):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
Enable folding for foundry traces (with Unicode box-drawing prefixes):
:EthTraceFoldEnable
" Use zM/zR to close/open all folds; za to toggleDisable or toggle:
:EthTraceFoldDisable
:EthTraceFoldToggleHow 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.
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
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
This project uses Nix for development environment setup.
- Nix with flakes enabled
nix developnix develop --command bustednix develop --command luacheck lua/nix develop --command stylua .nix build- 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
MIT License - see LICENSE file for details.
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.
The frecency system combines frequency and recency to intelligently order explorer options:
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
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, ...]
}
}
}
}- 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.