295 lines
7.5 KiB
Markdown
295 lines
7.5 KiB
Markdown
# Snip - Local-First Code Snippet Manager
|
|
|
|

|
|
|
|
A powerful CLI tool for managing code snippets with local-first architecture. Store snippets in SQLite with FTS5 full-text search, optional AES encryption, and peer-to-peer sync capabilities.
|
|
|
|
## Features
|
|
|
|
- **CRUD Operations**: Create, read, update, delete code snippets with ease
|
|
- **Full-Text Search**: FTS5-powered search across title, description, code, and tags with ranking
|
|
- **Tag Organization**: Flexible tag-based organization with autocomplete
|
|
- **Collections**: Group snippets into named collections for better organization
|
|
- **Syntax Highlighting**: Beautiful terminal syntax highlighting using Pygments
|
|
- **Import/Export**: JSON import/export for backup, sharing, and portability
|
|
- **Encryption**: Optional AES encryption for sensitive snippets using PBKDF2 key derivation
|
|
- **P2P Sync**: Discover and sync snippets with peers on your local network via mDNS
|
|
|
|
## Installation
|
|
|
|
### From Source
|
|
|
|
```bash
|
|
git clone https://7000pct.gitea.bloupla.net/7000pctAUTO/snippet-manager.git
|
|
cd snippet-manager
|
|
pip install -e .
|
|
```
|
|
|
|
### Dependencies
|
|
|
|
```
|
|
click>=8.3.0
|
|
cryptography>=46.0.0
|
|
pygments>=2.19.0
|
|
rich>=13.0.0
|
|
zeroconf>=0.148.0
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Initialize the database
|
|
snip init
|
|
|
|
# Add a snippet
|
|
snip add --title "Hello World" --code 'print("Hello, World!")' --language python
|
|
|
|
# List all snippets
|
|
snip list
|
|
|
|
# Get a snippet with syntax highlighting
|
|
snip get 1
|
|
|
|
# Search snippets
|
|
snip search hello
|
|
|
|
# Add tags to organize
|
|
snip tag add 1 python basics
|
|
|
|
# Create a collection
|
|
snip collection create "Python Snippets"
|
|
|
|
# Export snippets for backup
|
|
snip export all --file backup.json
|
|
|
|
# Import snippets from backup
|
|
snip import --file backup.json --strategy skip
|
|
```
|
|
|
|
## Commands Reference
|
|
|
|
### Snippet Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `snip init` | Initialize the snippet database |
|
|
| `snip add` | Add a new snippet |
|
|
| `snip get <id>` | Get a snippet by ID with syntax highlighting |
|
|
| `snip list` | List all snippets with pagination |
|
|
| `snip edit <id>` | Edit a snippet in your default editor |
|
|
| `snip delete <id>` | Delete a snippet (with confirmation) |
|
|
| `snip search <query>` | Full-text search with FTS5 |
|
|
|
|
### Tag Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `snip tag add <snippet_id> <tag>` | Add a tag to a snippet |
|
|
| `snip tag remove <snippet_id> <tag>` | Remove a tag from a snippet |
|
|
| `snip tag list` | List all tags in use |
|
|
|
|
### Collection Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `snip collection create <name>` | Create a new collection |
|
|
| `snip collection list` | List all collections |
|
|
| `snip collection delete <id>` | Delete a collection |
|
|
| `snip collection add <collection_id> <snippet_id>` | Add snippet to collection |
|
|
| `snip collection remove <collection_id> <snippet_id>` | Remove snippet from collection |
|
|
|
|
### Import/Export Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `snip export all --file <path>` | Export all snippets to JSON |
|
|
| `snip export collection <name> --file <path>` | Export a specific collection |
|
|
| `snip export snippet <id> --file <path>` | Export a single snippet |
|
|
| `snip import --file <path> --strategy <strategy>` | Import snippets (strategies: skip, replace, duplicate) |
|
|
|
|
### P2P Sync Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `snip discover list` | Discover peers on the local network |
|
|
| `snip sync --peer-id <id>` | Sync snippets with a discovered peer |
|
|
| `snip peers` | List known sync peers |
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `SNIP_DB_PATH` | `~/.snip/snippets.db` | Path to SQLite database |
|
|
| `SNIP_KEY_FILE` | `~/.snip/.key` | Path to encryption key file |
|
|
| `SNIP_SYNC_PORT` | `8765` | Port for P2P sync |
|
|
| `SNIP_PEER_CACHE` | `~/.snip/peers.json` | Path to peer cache |
|
|
|
|
### Configuration File
|
|
|
|
Optional configuration can be placed at `~/.snip/config.toml`:
|
|
|
|
```toml
|
|
[database]
|
|
path = "~/.snip/snippets.db"
|
|
|
|
[sync]
|
|
port = 8765
|
|
auto_discover = true
|
|
|
|
[display]
|
|
style = "monokai"
|
|
line_numbers = true
|
|
```
|
|
|
|
## Encryption
|
|
|
|
Snippets can be encrypted using AES encryption with PBKDF2 key derivation (480k iterations, SHA256).
|
|
|
|
```bash
|
|
# Add an encrypted snippet
|
|
snip add --title "API Secret" --code "API_KEY=abc123" --language python --encrypt
|
|
|
|
# View encrypted snippet (will prompt for password)
|
|
snip get 1
|
|
|
|
# Encrypted snippets are stored with is_encrypted flag
|
|
# Decryption happens on-demand with password verification
|
|
```
|
|
|
|
### How Encryption Works
|
|
|
|
1. User provides a password when creating an encrypted snippet
|
|
2. PBKDF2 derives a 32-byte key using SHA256 (480,000 iterations)
|
|
3. Fernet (AES-128-CBC with HMAC) encrypts the snippet content
|
|
4. Encrypted data stored in database with `is_encrypted=True`
|
|
5. On retrieval, password decrypts the content in memory
|
|
|
|
## P2P Sync
|
|
|
|
Snip can discover and sync snippets with other peers on your local network using mDNS/Bonjour service discovery.
|
|
|
|
### Discovery
|
|
|
|
```bash
|
|
# Discover available peers on the network
|
|
snip discover list
|
|
|
|
# Output example:
|
|
# Peer: macbook-pro.local (192.168.1.100:8765)
|
|
# Last seen: 2 minutes ago
|
|
```
|
|
|
|
### Sync Protocol
|
|
|
|
1. Peer discovery via `_snippets._tcp.local.` mDNS service
|
|
2. HTTP/JSON communication over TCP
|
|
3. Sync exchanges snippets updated since last sync
|
|
4. Conflict resolution: newest-wins strategy (with option to keep both)
|
|
|
|
```bash
|
|
# Sync with a specific peer
|
|
snip sync --peer-id <peer_id>
|
|
|
|
# View known peers
|
|
snip peers
|
|
```
|
|
|
|
## Import/Export Format
|
|
|
|
Exported JSON follows this structure:
|
|
|
|
```json
|
|
{
|
|
"version": "1.0",
|
|
"exported_at": "2024-01-15T10:30:00Z",
|
|
"snippets": [
|
|
{
|
|
"title": "Hello World",
|
|
"description": "A simple Hello World example",
|
|
"code": "print('Hello, World!')",
|
|
"language": "python",
|
|
"tags": ["basics", "example"],
|
|
"created_at": "2024-01-10T08:00:00Z",
|
|
"updated_at": "2024-01-10T08:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Import Strategies
|
|
|
|
- **skip**: Skip snippets that already exist (by title match)
|
|
- **replace**: Replace existing snippets with same title
|
|
- **duplicate**: Import all as new snippets (generate new IDs)
|
|
|
|
## Shell Completion
|
|
|
|
Snip supports shell completion for bash and zsh.
|
|
|
|
### Bash
|
|
|
|
```bash
|
|
# Add to ~/.bashrc
|
|
eval "$(_SNIP_COMPLETE=bash snip)"
|
|
```
|
|
|
|
### Zsh
|
|
|
|
```bash
|
|
# Add to ~/.zshrc
|
|
eval "$(_SNIP_COMPLETE=zsh snip)"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Database Locked
|
|
|
|
If you see "Database locked" errors:
|
|
- Ensure no other snip processes are running
|
|
- Check file permissions on `~/.snip/`
|
|
|
|
### FTS Query Syntax Error
|
|
|
|
FTS5 uses special syntax for boolean queries:
|
|
- Use quotes for phrases: `"hello world"`
|
|
- Use AND/OR for boolean: `hello AND world`
|
|
- Escape special characters with `\`
|
|
|
|
### Decryption Failed
|
|
|
|
- Verify you're using the correct password
|
|
- Passwords cannot be recovered if forgotten
|
|
- Encrypted snippets without the password cannot be decrypted
|
|
|
|
### Peer Unreachable
|
|
|
|
- Ensure both peers are on the same network
|
|
- Check firewall settings for port 8765
|
|
- Verify mDNS/Bonjour is enabled on your system
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://7000pct.gitea.bloupla.net/7000pctAUTO/snippet-manager.git
|
|
cd snippet-manager
|
|
|
|
# Install in development mode
|
|
pip install -e ".[dev]"
|
|
|
|
# Run tests
|
|
pytest tests/ -v
|
|
|
|
# Run with verbose output
|
|
pytest tests/ -v --capture=no
|
|
```
|
|
|
|
## License
|
|
|
|
MIT License - see [LICENSE](LICENSE) for details.
|
|
|
|
## Contributing
|
|
|
|
Contributions welcome! Please open an issue or submit a pull request. |