-
Notifications
You must be signed in to change notification settings - Fork 9
Editor Integration
bkmr integrates directly into your editor through its built-in Language Server Protocol (LSP) server and specialized plugins, providing intelligent snippet completion without leaving your development environment.
Instead of context-switching between editor and terminal to access snippets, bkmr brings your entire snippet library directly into your IDE with:
- Automatic completion - Snippets appear in completion popup while typing
- Language-aware filtering - Only relevant snippets shown based on file type
- Universal snippets - Write once, automatically adapt to any language
- Template interpolation - Dynamic content with Jinja2-style templates
- CRUD operations - Manage snippets directly from your editor
bkmr provides three integration paths:
- Neovim Plugin (Recommended for Neovim) - Visual interface with zero configuration
- Built-in LSP Server - Universal integration for VS Code, Vim, Emacs, Sublime, etc.
- IntelliJ Platform Plugin - JetBrains IDEs with seamless LSP integration
For Neovim users, bkmr-nvim provides the best integration experience with a visual interface and zero configuration.
- Visual snippet browser - Telescope/FZF integration for browsing and searching
- In-editor editing - Create and edit snippets without leaving Neovim
- Automatic LSP setup - Configures bkmr LSP server automatically
-
Custom commands -
:Bkmr,:BkmrEdit,:BkmrSearch - Zero configuration - Works out of the box
With lazy.nvim:
{
"sysid/bkmr-nvim",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
require("bkmr").setup() -- Zero config required!
end,
}With packer.nvim:
use {
'sysid/bkmr-nvim',
requires = { 'nvim-lua/plenary.nvim' },
config = function()
require("bkmr").setup()
end
}With vim-plug:
Plug 'nvim-lua/plenary.nvim'
Plug 'sysid/bkmr-nvim'
" In your init.vim after plug#end():
lua require("bkmr").setup()require("bkmr").setup({
-- LSP configuration
lsp = {
cmd = { "bkmr", "lsp" },
filetypes = { "*" }, -- Enable for all file types
},
-- Picker configuration (Telescope or FZF)
picker = "telescope", -- or "fzf"
-- Optional: Custom keymaps
keymaps = {
search = "<leader>bs",
edit = "<leader>be",
insert = "<leader>bi",
}
})Commands:
-
:Bkmr- Open snippet browser -
:BkmrSearch [query]- Search snippets with optional query -
:BkmrEdit <id>- Edit snippet by ID -
:BkmrCreate- Create new snippet
Default Keymaps (customizable):
-
<leader>bs- Search snippets -
<leader>be- Edit snippet -
<leader>bi- Insert snippet at cursor
The bkmr binary includes a full Language Server Protocol implementation accessible via bkmr lsp, compatible with any LSP client.
# Start LSP server (usually configured in your editor)
bkmr lsp
# Start without template interpolation
bkmr lsp --no-interpolationAll commands are executed via workspace/executeCommand:
| Command | Parameters | Returns | Description |
|---|---|---|---|
bkmr.createSnippet |
url (required)title (required)description (optional)tags (optional) |
Created snippet | Creates new snippet with _snip_ tag |
bkmr.updateSnippet |
id (required)url (optional)title (optional)description (optional)tags (optional) |
Updated snippet | Updates existing snippet |
bkmr.getSnippet |
id (required) |
Snippet data | Retrieves snippet by ID |
bkmr.deleteSnippet |
id (required) |
Success status | Deletes snippet |
bkmr.listSnippets |
language (optional) |
{snippets: []} |
Lists snippets filtered by language |
bkmr.insertFilepathComment |
Direct string URI | WorkspaceEdit | Inserts relative filepath as comment |
Example Command Usage:
{
"command": "bkmr.createSnippet",
"arguments": [{
"url": "console.log('test')",
"title": "JS Log",
"tags": ["javascript", "js"]
}]
}If you prefer manual configuration without the plugin:
-- ~/.config/nvim/lua/lsp/bkmr.lua
local lspconfig = require('lspconfig')
-- Define the bkmr LSP configuration
lspconfig.configs.bkmr_lsp = {
default_config = {
cmd = { "bkmr", "lsp" },
filetypes = {
"rust", "python", "javascript", "typescript", "go",
"java", "c", "cpp", "html", "css", "shell", "yaml",
"json", "markdown", "vim"
},
root_dir = function(fname)
return lspconfig.util.find_git_ancestor(fname)
or vim.fn.getcwd()
end,
settings = {},
},
}
-- Setup with capabilities and custom commands
lspconfig.bkmr_lsp.setup{
capabilities = require('cmp_nvim_lsp').default_capabilities(),
on_attach = function(client, bufnr)
-- Custom command for filepath insertion
vim.api.nvim_buf_create_user_command(bufnr, 'BkmrInsertPath',
function()
vim.lsp.buf.execute_command({
command = "bkmr.insertFilepathComment",
arguments = { vim.uri_from_bufnr(bufnr) }
})
end,
{ desc = "Insert filepath comment" }
)
-- List snippets command
vim.api.nvim_buf_create_user_command(bufnr, 'BkmrListSnippets',
function()
local filetype = vim.bo[bufnr].filetype
vim.lsp.buf.execute_command({
command = "bkmr.listSnippets",
arguments = { { language = filetype } }
})
end,
{ desc = "List snippets for current language" }
)
end
}Add to your settings.json:
{
"languageServerExample.servers": {
"bkmr-lsp": {
"command": "bkmr",
"args": ["lsp"],
"filetypes": ["*"]
}
}
}Note: Requires an LSP extension like "LSP" or "Language Server Client" to connect custom LSP servers.
if executable('bkmr')
augroup LspBkmr
autocmd!
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'bkmr-lsp',
\ 'cmd': {server_info->['bkmr', 'lsp']},
\ 'allowlist': [
\ 'rust', 'javascript', 'typescript', 'python', 'go',
\ 'java', 'c', 'cpp', 'html', 'css', 'scss', 'ruby',
\ 'php', 'swift', 'kotlin', 'shell', 'yaml', 'json',
\ 'markdown', 'xml', 'vim'
\ ],
\ })
augroup END
endif;; Add to your init.el or .emacs
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs
'((rust-mode python-mode js-mode typescript-mode go-mode) . ("bkmr" "lsp"))))Create a configuration in LSP settings:
{
"clients": {
"bkmr-lsp": {
"enabled": true,
"command": ["bkmr", "lsp"],
"selector": "source"
}
}
}bkmr-intellij-plugin brings bkmr integration to all JetBrains IDEs through the JetBrains Marketplace.
- Seamless LSP integration - Automatic snippet completion with no manual triggers
- Tab navigation - Full snippet placeholder support with Tab/Shift+Tab navigation
-
Cross-platform - Works in all JetBrains IDEs:
- IntelliJ IDEA
- PyCharm
- WebStorm
- CLion
- RustRover
- GoLand
- PhpStorm
- Android Studio
- Filepath comments - Insert relative filepaths as comments with smart language detection
- Open your JetBrains IDE
- Go to Settings/Preferences → Plugins
- Search for "bkmr" in Marketplace
- Click Install
- Restart IDE
Or install manually:
- Download from JetBrains Marketplace
- Settings/Preferences → Plugins → ⚙️ → Install Plugin from Disk
The plugin automatically detects the bkmr binary in your PATH. For custom locations:
- Settings/Preferences → Tools → bkmr
- Set bkmr Executable Path to custom location
- Optionally enable/disable template interpolation
The LSP server automatically detects file types and filters snippets accordingly.
| Language | Extensions | LSP ID | Tag Aliases | Comment Style |
|---|---|---|---|---|
| Rust | .rs |
rust |
rust |
//, /* */
|
| Python | .py |
python |
python, py
|
# |
| JavaScript |
.js, .mjs
|
javascript |
javascript, js
|
//, /* */
|
| TypeScript |
.ts, .tsx
|
typescript |
typescript, ts
|
//, /* */
|
| Go | .go |
go |
go, golang
|
//, /* */
|
| Shell |
.sh, .bash
|
shell, sh
|
shell, sh, bash
|
# |
| Java | .java |
java |
java |
//, /* */
|
| C/C++ |
.c, .cpp, .h
|
c, cpp
|
c, cpp
|
//, /* */
|
| HTML | .html |
html |
html |
<!-- --> |
| CSS | .css |
css |
css |
/* */ |
| Ruby | .rb |
ruby |
ruby |
# |
| PHP | .php |
php |
php |
//, /* */
|
| YAML |
.yaml, .yml
|
yaml |
yaml, yml
|
# |
| JSON | .json |
json |
json |
N/A |
| Markdown | .md |
markdown |
markdown, md
|
<!-- --> |
# Language-specific snippets
bkmr add 'println!("{}", ${1:value})' rust,_snip_ --title "Rust Print"
bkmr add 'console.log(${1:message})' javascript,_snip_ --title "JS Log"
bkmr add 'print(f"{${1:var}}")' python,_snip_ --title "Python F-String"
# Multi-language snippets
bkmr add 'if ${1:condition} {\n ${2:body}\n}' rust,go,_snip_ --title "If Statement"
# Universal snippets (work in any language)
bkmr add '// TODO: ${1:description}' universal,_snip_ --title "TODO Comment"Universal snippets are bkmr's most powerful feature - write once in Rust syntax, automatically adapt to any language.
Universal snippets stored in Rust syntax are automatically translated to the target language's conventions:
Original Snippet (Rust syntax):
// Function: ${1:name}
// Description: ${2:description}
fn ${1:name}() {
${3:// Implementation}
}Automatically Becomes in Python:
# Function: ${1:name}
# Description: ${2:description}
def ${1:name}():
${3:# Implementation}Automatically Becomes in JavaScript:
// Function: ${1:name}
// Description: ${2:description}
function ${1:name}() {
${3:// Implementation}
}Single-line comments:
-
Rust/JS/C:
// comment(original) -
Python/Shell/YAML:
# comment -
HTML/XML:
<!-- comment --> -
CSS:
/* comment */
Block comments:
-
Rust/JS/C:
/* block */(original) -
Python:
"""block"""or'''block''' -
HTML:
<!-- block --> -
Ruby:
=begin\nblock\n=end
- Rust/Python/Java: 4 spaces (default)
- JavaScript/TypeScript: 2 spaces
- Go: Tabs
- HTML/CSS/YAML: 2 spaces
- Makefile: Tabs (required)
Function Template:
bkmr add '// ${1:Function name}
// ${2:Description}
fn ${1}() {
${3:// Implementation}
}' universal,_snip_ --title "Function Template"Error Handling:
bkmr add '// Handle ${1:error type}
match ${1} {
Ok(val) => ${2:// Success},
Err(e) => ${3:// Error handling},
}' universal,rust,_snip_ --title "Error Handler"Documentation Block:
bkmr add '// ${1:Component name}
//
// ${2:Description}
//
// Args:
// ${3:arguments}
//
// Returns:
// ${4:return type}' universal,_snip_ --title "Doc Block"The LSP server processes Jinja2-style templates before serving snippets.
# With interpolation (default)
bkmr lsp
# Without interpolation (raw snippets)
bkmr lsp --no-interpolationDate-Stamped Comments:
bkmr add '// Generated on {{ current_date | strftime("%Y-%m-%d") }}
// By: {{ env("USER") }}
// Host: {{ "hostname" | shell }}' _snip_ --title "Header"Dynamic Imports:
bkmr add 'import {{ "git branch --show-current" | shell | replace("-", "_") }}' python,_snip_ --title "Branch Import"Environment-Aware Configuration:
bkmr add 'API_URL={{ env("API_URL", "http://localhost:8000") }}
USER={{ env("USER") }}
TIMESTAMP={{ current_date | strftime("%s") }}' _snip_ --title "Config"See Template Interpolation for complete template documentation.
Tag snippets with plain to prevent LSP placeholder interpretation:
# Plain text - literal insertion, no ${} processing
bkmr add 'DATABASE_URL=${DATABASE_URL}' plain,_snip_ --title "Env Template"
# LSP snippet - with placeholders
bkmr add 'DATABASE_URL=${1:localhost}' _snip_ --title "Env Config"Use Cases for Plain Snippets:
- Shell scripts with literal
${}variable syntax - Configuration templates with environment variables
- Docker Compose files with
${VAR}syntax - Helm templates with Go template syntax
1. Quick Snippet Access:
# In your editor, start typing...
Type: "log"
↓
Completion popup shows:
- JS Log: console.log(${1:message})
- Python Log: print(f"{${1:var}}")
- Rust Log: println!("{}", ${1:value})
2. Insert and Fill Placeholders:
Select "JS Log"
↓
Inserts: console.log(█)
↓
Type your message
↓
Press Tab to move to next placeholder (if any)
3. Create Snippets On-The-Fly:
# In Neovim with bkmr-nvim:
:BkmrCreate
↓
Enter snippet content
↓
Tag with language
↓
Immediately available in completion
# Create review comment snippet
bkmr add '// REVIEW: ${1:issue}
// Suggested fix: ${2:solution}
// Priority: ${3:high|medium|low}' review,_snip_ --title "Review Comment"
# Now available in any code file
# Type "review" → automatic completion → fill placeholders# Create function documentation template
bkmr add '/// ${1:Brief description}
///
/// # Arguments
/// * `${2:arg}` - ${3:arg description}
///
/// # Returns
/// ${4:return description}' rust,doc,_snip_ --title "Rust Doc"
# Use in editor:
# Type "doc" above function → select template → fill in detailsCheck snippet existence:
bkmr search -t _snip_
bkmr search -t _snip_,rust # Language-specificTest LSP server:
# Basic connectivity test
echo '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{}}' | bkmr lsp
# Should return JSON response with capabilitiesVerify bkmr version:
bkmr --version
# Requires 4.31.0 or later for full LSP supportCheck editor LSP client:
- Neovim:
:LspInfo- Verify bkmr_lsp is attached - VS Code: Check "Output" → "Language Server" logs
- Vim:
:LspStatusor check vim-lsp logs
Issue: All snippets appear regardless of file type
Solutions:
- Tag snippets with language names:
# Ensure snippets have language tags
bkmr add 'content' python,_snip_ --title "Python Snippet"- Verify file type detection:
# In Neovim
:set filetype?
# Should match language ID (python, rust, javascript, etc.)- Check LSP language filtering:
# Test language-specific filtering
python3 scripts/lsp/list_snippets.py --language rust --debugTemplates not resolving:
# Start LSP with interpolation explicitly enabled (default)
bkmr lsp
# Or disable if templates conflict with snippet content
bkmr lsp --no-interpolationEnvironment variables not expanding:
# Check variable exists
echo $VARIABLE_NAME
# Use fallback values in templates
{{ env("VARIABLE", "default-value") }}Enable detailed logging:
# Start LSP with debug logging
RUST_LOG=debug bkmr lsp 2>/tmp/bkmr-lsp.log
# In another terminal, watch logs
tail -f /tmp/bkmr-lsp.log
# Trigger completion in editor, check logs for errorsCommon log messages:
-
Received completion request- LSP client requesting completions -
Filtering snippets for language: rust- Language detection working -
Found N snippets for language- Snippets being served -
Template rendering failed- Template syntax errors
Use the provided test scripts in scripts/lsp/:
# List all snippets
python3 scripts/lsp/list_snippets.py
# List by language
python3 scripts/lsp/list_snippets.py --language rust --debug
# Get specific snippet
python3 scripts/lsp/get_snippet.py 123
# Show available commands
python3 scripts/lsp/show_commands.py
# Test LSP client communication
python3 scripts/lsp/test_lsp_client.pyPlugin not connecting:
- Verify
bkmris in PATH:
which bkmr
bkmr --version-
Check plugin settings:
- Settings → Tools → bkmr
- Verify executable path
- Test connection button
-
Check IDE logs:
- Help → Show Log in Finder/Explorer
- Search for "bkmr" or "LSP" errors
Snippets not appearing:
- Ensure snippets have
_snip_system tag:
bkmr search -t _snip_ --json | jq '.[] | {id, title, tags}'- Verify language tags match file type:
# For a .rs file, snippets should have "rust" tag
bkmr search -t _snip_,rustThe LSP server performs all filtering server-side for efficiency:
- Network traffic: Only relevant snippets transmitted to editor
- Client performance: Minimal processing in editor/IDE
- Latency: Fast completions even with thousands of snippets
- Database access: Efficient connection pooling via r2d2
- Stateless operation: Each request independent for reliability
- Concurrent access: Supports multiple editor instances
1. Tag snippets appropriately:
# Good: Specific language tags
bkmr add 'content' rust,async,_snip_ --title "Async Code"
# Avoid: Generic tags that match everything
bkmr add 'content' code,_snip_ --title "Code"2. Use plain tag when appropriate:
# For literals, use plain to skip LSP processing
bkmr add '${VAR}' plain,_snip_ --title "Literal Variable"3. Limit snippet size:
- Keep snippets focused and concise
- Large snippets slow down completion popup
- Break complex templates into smaller pieces
- bkmr-nvim - Neovim plugin with visual interface
- bkmr-intellij-plugin - JetBrains IDEs integration
- LSP Test Scripts - Python scripts for testing LSP functionality
- bkmr CLI - Main bkmr project
- LSP Specification - Official protocol documentation
- tower-lsp - Rust LSP framework used by bkmr
The bkmr LSP server is built into the binary and provides:
- Protocol implementation: tower-lsp for LSP 3.17 specification
- Service integration: Direct integration with bkmr's service layer
- Server-side filtering: Efficient language-aware snippet filtering
- Async operations: tokio runtime for non-blocking I/O
- Stateless design: Reliable operation across editor restarts
- Dependency injection: Clean architecture with explicit dependencies
Key Design Decisions:
- Single binary includes both CLI and LSP functionality
- No separate server process installation required
- Same snippet database used by CLI and LSP
- Templates processed server-side for consistency
- Content Types - Understanding snippet system tags
- Template Interpolation - Dynamic snippet content
- Search and Discovery - Finding and managing snippets
- Configuration - LSP and snippet configuration
- Basic Usage - Creating and managing snippets via CLI