mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-01-23 02:35:38 +01:00
initial, for PR
This commit is contained in:
parent
2b7f3442ae
commit
1353791277
3 changed files with 753 additions and 0 deletions
|
|
@ -27,6 +27,7 @@ This is the Oh My Zsh repository - a popular open-source framework for managing
|
||||||
- Library files in `lib/` directory
|
- Library files in `lib/` directory
|
||||||
- Tools and utilities in `tools/` directory
|
- Tools and utilities in `tools/` directory
|
||||||
- Custom plugins/themes go in `custom/` directory
|
- Custom plugins/themes go in `custom/` directory
|
||||||
|
- **New plugin**: `eternalhist` plugin added to `plugins/eternalhist/` for advanced persistent command history with multi-remote sync
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
- No specific test commands found - check individual plugin READMEs
|
- No specific test commands found - check individual plugin READMEs
|
||||||
|
|
|
||||||
324
plugins/eternalhist/README.md
Normal file
324
plugins/eternalhist/README.md
Normal file
|
|
@ -0,0 +1,324 @@
|
||||||
|
# EternalHist Plugin
|
||||||
|
|
||||||
|
A comprehensive command history management plugin for Oh My Zsh that extends beyond session boundaries, with support for cloud storage and remote synchronization.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
EternalHist builds upon the concept of persistent shell history by providing advanced search, storage, and synchronization capabilities. Unlike standard shell history that's limited to recent commands or single sessions, EternalHist maintains a comprehensive, searchable archive of your command history across all sessions and systems.
|
||||||
|
|
||||||
|
## Core Features
|
||||||
|
|
||||||
|
### 🔍 Advanced History Search
|
||||||
|
- **Multi-term search**: Search using multiple keywords with AND/OR logic
|
||||||
|
- **Case-insensitive search**: Find commands regardless of case
|
||||||
|
- **Regex support**: Use regular expressions for complex pattern matching
|
||||||
|
- **Context search**: Find commands with surrounding context
|
||||||
|
- **Date/time filtering**: Search within specific time ranges
|
||||||
|
- **Frequency analysis**: Find most-used commands and patterns
|
||||||
|
|
||||||
|
### 💾 Persistent Storage
|
||||||
|
- **Local eternal history**: Maintains `~/.eternal_history` file
|
||||||
|
- **Session deduplication**: Prevents duplicate entries across sessions
|
||||||
|
- **Metadata tracking**: Stores timestamp, working directory, exit status
|
||||||
|
- **Compression support**: Optional compression for large history files
|
||||||
|
- **Backup management**: Automatic rotation and backup of history files
|
||||||
|
|
||||||
|
### ☁️ Cloud & Remote Storage Support
|
||||||
|
- **Multi-provider support**: Works with various cloud storage services
|
||||||
|
- **Environment variable configuration**: Flexible setup via env vars
|
||||||
|
- **Sync on demand**: Manual or automatic synchronization
|
||||||
|
- **Conflict resolution**: Handles merge conflicts across devices
|
||||||
|
- **Encryption support**: Optional encryption for sensitive command history
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### Storage Location Configuration
|
||||||
|
```bash
|
||||||
|
# Local storage (default: ~/.eternal_history)
|
||||||
|
export ETERNALHIST_LOCAL_FILE="$HOME/.eternal_history"
|
||||||
|
|
||||||
|
# Multi-remote filesystem support
|
||||||
|
export ETERNALHIST_REMOTES="primary,backup,work,personal" # Comma-separated list of remote names
|
||||||
|
export ETERNALHIST_DEFAULT_REMOTE="primary" # Default remote for operations
|
||||||
|
export ETERNALHIST_SYNC_ALL_REMOTES="true" # Sync with all configured remotes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Per-Remote Configuration Pattern
|
||||||
|
Each remote is configured using the pattern `ETERNALHIST_<REMOTE_NAME>_<SETTING>`:
|
||||||
|
|
||||||
|
#### Primary Remote Example (Dropbox)
|
||||||
|
```bash
|
||||||
|
export ETERNALHIST_PRIMARY_PROVIDER="dropbox"
|
||||||
|
export ETERNALHIST_PRIMARY_PATH="/Apps/EternalHist/history"
|
||||||
|
export ETERNALHIST_PRIMARY_AUTH_TOKEN="your_dropbox_token"
|
||||||
|
export ETERNALHIST_PRIMARY_ENABLED="true"
|
||||||
|
export ETERNALHIST_PRIMARY_PRIORITY="1" # Sync order priority
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backup Remote Example (S3)
|
||||||
|
```bash
|
||||||
|
export ETERNALHIST_BACKUP_PROVIDER="s3"
|
||||||
|
export ETERNALHIST_BACKUP_BUCKET="my-eternalhist-bucket"
|
||||||
|
export ETERNALHIST_BACKUP_PATH="history/eternal_history"
|
||||||
|
export ETERNALHIST_BACKUP_REGION="us-west-2"
|
||||||
|
export ETERNALHIST_BACKUP_ACCESS_KEY="your_access_key"
|
||||||
|
export ETERNALHIST_BACKUP_SECRET_KEY="your_secret_key"
|
||||||
|
export ETERNALHIST_BACKUP_ENABLED="true"
|
||||||
|
export ETERNALHIST_BACKUP_PRIORITY="2"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Work Remote Example (SSH Server)
|
||||||
|
```bash
|
||||||
|
export ETERNALHIST_WORK_PROVIDER="ssh"
|
||||||
|
export ETERNALHIST_WORK_HOST="work-server.company.com"
|
||||||
|
export ETERNALHIST_WORK_USER="username"
|
||||||
|
export ETERNALHIST_WORK_PATH="/home/username/.shared_eternal_history"
|
||||||
|
export ETERNALHIST_WORK_SSH_KEY="$HOME/.ssh/work_key"
|
||||||
|
export ETERNALHIST_WORK_PORT="22"
|
||||||
|
export ETERNALHIST_WORK_ENABLED="true"
|
||||||
|
export ETERNALHIST_WORK_PRIORITY="3"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Personal Remote Example (Google Drive)
|
||||||
|
```bash
|
||||||
|
export ETERNALHIST_PERSONAL_PROVIDER="gdrive"
|
||||||
|
export ETERNALHIST_PERSONAL_PATH="/EternalHist/personal_history"
|
||||||
|
export ETERNALHIST_PERSONAL_CLIENT_ID="your_client_id"
|
||||||
|
export ETERNALHIST_PERSONAL_CLIENT_SECRET="your_client_secret"
|
||||||
|
export ETERNALHIST_PERSONAL_REFRESH_TOKEN="your_refresh_token"
|
||||||
|
export ETERNALHIST_PERSONAL_ENABLED="true"
|
||||||
|
export ETERNALHIST_PERSONAL_PRIORITY="4"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Remote Sync Strategies
|
||||||
|
```bash
|
||||||
|
# Sync behavior across remotes
|
||||||
|
export ETERNALHIST_SYNC_STRATEGY="all" # all, priority, selective, round-robin
|
||||||
|
export ETERNALHIST_SYNC_TIMEOUT="30" # Timeout per remote (seconds)
|
||||||
|
export ETERNALHIST_SYNC_RETRY_COUNT="3" # Retry failed syncs
|
||||||
|
export ETERNALHIST_SYNC_PARALLEL="true" # Sync remotes in parallel
|
||||||
|
export ETERNALHIST_SYNC_CONFLICT_RESOLUTION="merge" # merge, latest, manual, skip
|
||||||
|
```
|
||||||
|
|
||||||
|
### Synchronization Settings
|
||||||
|
```bash
|
||||||
|
# Auto-sync behavior
|
||||||
|
export ETERNALHIST_AUTO_SYNC="true" # Enable automatic sync
|
||||||
|
export ETERNALHIST_SYNC_INTERVAL="300" # Sync every 5 minutes
|
||||||
|
export ETERNALHIST_SYNC_ON_EXIT="true" # Sync when shell exits
|
||||||
|
|
||||||
|
# Conflict resolution
|
||||||
|
export ETERNALHIST_MERGE_STRATEGY="timestamp" # timestamp, interactive, local, remote
|
||||||
|
export ETERNALHIST_BACKUP_CONFLICTS="true" # Keep conflicted versions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search and Display Options
|
||||||
|
```bash
|
||||||
|
# Search behavior
|
||||||
|
export ETERNALHIST_SEARCH_LIMIT="100" # Max results to display
|
||||||
|
export ETERNALHIST_SEARCH_CONTEXT="2" # Lines of context around matches
|
||||||
|
export ETERNALHIST_CASE_SENSITIVE="false" # Case sensitivity for searches
|
||||||
|
|
||||||
|
# Display formatting
|
||||||
|
export ETERNALHIST_SHOW_TIMESTAMPS="true" # Show when commands were run
|
||||||
|
export ETERNALHIST_SHOW_DIRECTORIES="true" # Show working directory
|
||||||
|
export ETERNALHIST_SHOW_EXIT_STATUS="false" # Show command exit codes
|
||||||
|
export ETERNALHIST_COLOR_OUTPUT="true" # Colorize search results
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security and Privacy
|
||||||
|
```bash
|
||||||
|
# Encryption
|
||||||
|
export ETERNALHIST_ENCRYPT="true" # Encrypt history files
|
||||||
|
export ETERNALHIST_ENCRYPTION_KEY_FILE="$HOME/.eternalhist.key"
|
||||||
|
|
||||||
|
# Privacy filters
|
||||||
|
export ETERNALHIST_EXCLUDE_PATTERNS="password,secret,token,key,api"
|
||||||
|
export ETERNALHIST_PRIVATE_MODE="false" # Disable history collection
|
||||||
|
export ETERNALHIST_MAX_COMMAND_LENGTH="500" # Truncate very long commands
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Default Search Behavior
|
||||||
|
```bash
|
||||||
|
eternalhist <search_terms...> # Search eternal history (default behavior)
|
||||||
|
eternalhist # Show recent eternal history
|
||||||
|
```
|
||||||
|
|
||||||
|
### Core History Management
|
||||||
|
```bash
|
||||||
|
eternalhist add [command] # Add command to eternal history
|
||||||
|
eternalhist remove <pattern> # Remove matching commands (planned)
|
||||||
|
eternalhist clear # Clear all eternal history
|
||||||
|
eternalhist show [--limit N] # Display eternal history
|
||||||
|
eternalhist stats # Show usage statistics
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search with Escape Mechanism
|
||||||
|
```bash
|
||||||
|
eternalhist \<command_name> [terms...] # Search for command names using backslash escape
|
||||||
|
eternalhist \add file # Search for "add file" (not the add command)
|
||||||
|
eternalhist \sync server # Search for "sync server" (not the sync command)
|
||||||
|
eternalhist \clear cache # Search for "clear cache" (not the clear command)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cloud & Remote Operations
|
||||||
|
```bash
|
||||||
|
# Multi-remote operations
|
||||||
|
eternalhist sync [remote_name] # Sync with specific remote or all remotes
|
||||||
|
eternalhist push [remote_name] # Upload to specific remote or all remotes
|
||||||
|
eternalhist pull [remote_name] # Download from specific remote
|
||||||
|
eternalhist status [remote_name] # Show sync status for remotes
|
||||||
|
|
||||||
|
# Remote management
|
||||||
|
eternalhist remotes list # List all configured remotes
|
||||||
|
eternalhist remotes add <name> # Add new remote configuration
|
||||||
|
eternalhist remotes remove <name> # Remove remote configuration
|
||||||
|
eternalhist remotes test <name> # Test remote connection
|
||||||
|
eternalhist remotes enable <name> # Enable remote for sync
|
||||||
|
eternalhist remotes disable <name> # Disable remote from sync
|
||||||
|
|
||||||
|
# Advanced multi-remote operations
|
||||||
|
eternalhist merge <file> # Merge external history file
|
||||||
|
eternalhist backup [--remotes list] # Create backup on specified remotes
|
||||||
|
eternalhist restore <backup> [remote] # Restore from backup on specific remote
|
||||||
|
eternalhist replicate <from> <to> # Copy history from one remote to another
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Features
|
||||||
|
```bash
|
||||||
|
eternalhist export [--format json|csv] # Export history in various formats
|
||||||
|
eternalhist import <file> # Import history from file
|
||||||
|
eternalhist dedupe # Remove duplicate entries
|
||||||
|
eternalhist analyze # Analyze command patterns and usage
|
||||||
|
eternalhist config # Interactive configuration setup
|
||||||
|
eternalhist encrypt # Encrypt existing history file
|
||||||
|
eternalhist decrypt # Decrypt history file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Add `eternalhist` to your plugins list in `~/.zshrc`:
|
||||||
|
```bash
|
||||||
|
plugins=(... eternalhist)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Configure environment variables in `~/.zshrc` or `~/.zprofile`:
|
||||||
|
```bash
|
||||||
|
# Basic configuration
|
||||||
|
export ETERNALHIST_CLOUD_PROVIDER="dropbox"
|
||||||
|
export ETERNALHIST_AUTO_SYNC="true"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Reload your shell or run:
|
||||||
|
```bash
|
||||||
|
source ~/.zshrc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Basic Search (Default Behavior)
|
||||||
|
```bash
|
||||||
|
# Search for git commands (no "search" keyword needed)
|
||||||
|
eternalhist git
|
||||||
|
|
||||||
|
# Search for multiple terms (AND logic)
|
||||||
|
eternalhist git commit push
|
||||||
|
|
||||||
|
# Search with regex
|
||||||
|
eternalhist "npm (install|update)"
|
||||||
|
|
||||||
|
# Search for command names that conflict with eternalhist commands
|
||||||
|
eternalhist \add file # Search for "add file" commands
|
||||||
|
eternalhist \sync backup # Search for "sync backup" commands
|
||||||
|
eternalhist \show details # Search for "show details" commands
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Remote Synchronization
|
||||||
|
```bash
|
||||||
|
# One-time multi-remote setup
|
||||||
|
eternalhist config
|
||||||
|
|
||||||
|
# Sync with all configured remotes
|
||||||
|
eternalhist sync
|
||||||
|
|
||||||
|
# Sync with specific remote
|
||||||
|
eternalhist sync primary
|
||||||
|
|
||||||
|
# Sync with multiple specific remotes
|
||||||
|
eternalhist sync primary,backup
|
||||||
|
|
||||||
|
# Check status of all remotes
|
||||||
|
eternalhist status
|
||||||
|
|
||||||
|
# Check status of specific remote
|
||||||
|
eternalhist status work
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Usage
|
||||||
|
```bash
|
||||||
|
# Export monthly command report
|
||||||
|
eternalhist export --format csv --from "2024-01-01" --to "2024-01-31"
|
||||||
|
|
||||||
|
# Find most used commands
|
||||||
|
eternalhist analyze --top 10
|
||||||
|
|
||||||
|
# Backup before major changes
|
||||||
|
eternalhist backup --compress
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with Existing `ht` Function
|
||||||
|
|
||||||
|
The plugin maintains full backward compatibility with your existing `ht` function. The `ht` command now uses `eternalhist` search functionality while preserving the same interface:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# These work exactly as before
|
||||||
|
ht git commit # Search for git commit commands
|
||||||
|
ht docker run # Search for docker run commands
|
||||||
|
|
||||||
|
# But now you can also use the more direct syntax
|
||||||
|
eternalhist git commit # Same functionality, no "search" needed
|
||||||
|
eternalhist docker run # Direct search without command prefix
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloud Provider Support
|
||||||
|
|
||||||
|
### Planned Integrations
|
||||||
|
- **Dropbox**: Via Dropbox API or mounted filesystem
|
||||||
|
- **Google Drive**: Via Google Drive API or rclone
|
||||||
|
- **iCloud**: Via iCloud Drive folder
|
||||||
|
- **OneDrive**: Via OneDrive API or mounted filesystem
|
||||||
|
- **Amazon S3**: Via AWS CLI or S3 API
|
||||||
|
- **Custom SSH**: Via SCP/SFTP to any SSH server
|
||||||
|
- **Git repositories**: Version-controlled history storage
|
||||||
|
|
||||||
|
### Security Considerations
|
||||||
|
- All cloud uploads can be encrypted before transmission
|
||||||
|
- Support for client-side encryption keys
|
||||||
|
- Optional anonymization of sensitive commands
|
||||||
|
- Configurable exclude patterns for private data
|
||||||
|
|
||||||
|
## Development Roadmap
|
||||||
|
|
||||||
|
- [ ] Core history management functions
|
||||||
|
- [ ] Local file operations and search
|
||||||
|
- [ ] Cloud storage provider integrations
|
||||||
|
- [ ] Encryption and security features
|
||||||
|
- [ ] Advanced analytics and reporting
|
||||||
|
- [ ] Interactive configuration wizard
|
||||||
|
- [ ] Multi-device conflict resolution
|
||||||
|
- [ ] Integration with popular cloud services
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
This plugin is under active development. Contributions welcome for:
|
||||||
|
- Additional cloud provider integrations
|
||||||
|
- Enhanced search algorithms
|
||||||
|
- Security improvements
|
||||||
|
- Documentation and examples
|
||||||
|
- Testing across different environments
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - See LICENSE file for details.
|
||||||
428
plugins/eternalhist/eternalhist.plugin.zsh
Normal file
428
plugins/eternalhist/eternalhist.plugin.zsh
Normal file
|
|
@ -0,0 +1,428 @@
|
||||||
|
#!/usr/bin/env zsh
|
||||||
|
# EternalHist Plugin for Oh My Zsh
|
||||||
|
# Advanced persistent command history with multi-remote synchronization
|
||||||
|
|
||||||
|
# Default configuration
|
||||||
|
ETERNALHIST_LOCAL_FILE="${ETERNALHIST_LOCAL_FILE:-$HOME/.eternal_history}"
|
||||||
|
ETERNALHIST_DEFAULT_REMOTE="${ETERNALHIST_DEFAULT_REMOTE:-}"
|
||||||
|
ETERNALHIST_SYNC_ALL_REMOTES="${ETERNALHIST_SYNC_ALL_REMOTES:-false}"
|
||||||
|
ETERNALHIST_AUTO_SYNC="${ETERNALHIST_AUTO_SYNC:-false}"
|
||||||
|
ETERNALHIST_SEARCH_LIMIT="${ETERNALHIST_SEARCH_LIMIT:-100}"
|
||||||
|
ETERNALHIST_COLOR_OUTPUT="${ETERNALHIST_COLOR_OUTPUT:-true}"
|
||||||
|
|
||||||
|
# Internal variables
|
||||||
|
_ETERNALHIST_PLUGIN_DIR="${0:A:h}"
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
_eternalhist_log() {
|
||||||
|
local level="$1"
|
||||||
|
shift
|
||||||
|
if [[ "$ETERNALHIST_DEBUG" == "true" ]]; then
|
||||||
|
echo "[eternalhist:$level] $*" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_error() {
|
||||||
|
echo "eternalhist: error: $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_warn() {
|
||||||
|
echo "eternalhist: warning: $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_colorize() {
|
||||||
|
if [[ "$ETERNALHIST_COLOR_OUTPUT" == "true" ]]; then
|
||||||
|
case "$1" in
|
||||||
|
"red") echo -e "\033[31m$2\033[0m" ;;
|
||||||
|
"green") echo -e "\033[32m$2\033[0m" ;;
|
||||||
|
"yellow") echo -e "\033[33m$2\033[0m" ;;
|
||||||
|
"blue") echo -e "\033[34m$2\033[0m" ;;
|
||||||
|
"purple") echo -e "\033[35m$2\033[0m" ;;
|
||||||
|
"cyan") echo -e "\033[36m$2\033[0m" ;;
|
||||||
|
*) echo "$2" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Core eternal history functions
|
||||||
|
_eternalhist_ensure_file() {
|
||||||
|
touch "$ETERNALHIST_LOCAL_FILE"
|
||||||
|
chmod 600 "$ETERNALHIST_LOCAL_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_add_entry() {
|
||||||
|
local cmd="$1"
|
||||||
|
local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
local pwd="$(pwd)"
|
||||||
|
local exit_code="${2:-0}"
|
||||||
|
|
||||||
|
_eternalhist_ensure_file
|
||||||
|
echo "$timestamp|$pwd|$exit_code|$cmd" >> "$ETERNALHIST_LOCAL_FILE"
|
||||||
|
_eternalhist_log "debug" "Added entry: $cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_search_local() {
|
||||||
|
local search_terms=("$@")
|
||||||
|
local search_cmd="cat '$ETERNALHIST_LOCAL_FILE'"
|
||||||
|
|
||||||
|
_eternalhist_ensure_file
|
||||||
|
|
||||||
|
for term in "${search_terms[@]}"; do
|
||||||
|
search_cmd="$search_cmd | grep -i '$term'"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "$ETERNALHIST_SEARCH_LIMIT" ]] && [[ "$ETERNALHIST_SEARCH_LIMIT" -gt 0 ]]; then
|
||||||
|
search_cmd="$search_cmd | tail -n $ETERNALHIST_SEARCH_LIMIT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval "$search_cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remote configuration functions
|
||||||
|
_eternalhist_get_remotes() {
|
||||||
|
if [[ -n "$ETERNALHIST_REMOTES" ]]; then
|
||||||
|
echo "$ETERNALHIST_REMOTES" | tr ',' ' '
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_get_remote_var() {
|
||||||
|
local remote="$1"
|
||||||
|
local var="$2"
|
||||||
|
local remote_upper="$(echo "$remote" | tr '[:lower:]' '[:upper:]')"
|
||||||
|
local var_name="ETERNALHIST_${remote_upper}_${var}"
|
||||||
|
echo "${(P)var_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_is_remote_enabled() {
|
||||||
|
local remote="$1"
|
||||||
|
local enabled="$(_eternalhist_get_remote_var "$remote" "ENABLED")"
|
||||||
|
[[ "$enabled" == "true" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_list_remotes() {
|
||||||
|
local remotes=($(_eternalhist_get_remotes))
|
||||||
|
|
||||||
|
if [[ ${#remotes[@]} -eq 0 ]]; then
|
||||||
|
echo "No remotes configured."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%-15s %-10s %-10s %-20s %s\n" "NAME" "ENABLED" "PRIORITY" "PROVIDER" "PATH"
|
||||||
|
printf "%-15s %-10s %-10s %-20s %s\n" "----" "-------" "--------" "--------" "----"
|
||||||
|
|
||||||
|
for remote in "${remotes[@]}"; do
|
||||||
|
local enabled="$(_eternalhist_get_remote_var "$remote" "ENABLED")"
|
||||||
|
local priority="$(_eternalhist_get_remote_var "$remote" "PRIORITY")"
|
||||||
|
local provider="$(_eternalhist_get_remote_var "$remote" "PROVIDER")"
|
||||||
|
local path="$(_eternalhist_get_remote_var "$remote" "PATH")"
|
||||||
|
|
||||||
|
enabled="${enabled:-false}"
|
||||||
|
priority="${priority:-0}"
|
||||||
|
provider="${provider:-unknown}"
|
||||||
|
path="${path:-unknown}"
|
||||||
|
|
||||||
|
local color="red"
|
||||||
|
[[ "$enabled" == "true" ]] && color="green"
|
||||||
|
|
||||||
|
printf "%-15s %s %-10s %-20s %s\n" \
|
||||||
|
"$remote" \
|
||||||
|
"$(_eternalhist_colorize "$color" "$enabled")" \
|
||||||
|
"$priority" \
|
||||||
|
"$provider" \
|
||||||
|
"$path"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_test_remote() {
|
||||||
|
local remote="$1"
|
||||||
|
local provider="$(_eternalhist_get_remote_var "$remote" "PROVIDER")"
|
||||||
|
|
||||||
|
case "$provider" in
|
||||||
|
"ssh")
|
||||||
|
local host="$(_eternalhist_get_remote_var "$remote" "HOST")"
|
||||||
|
local user="$(_eternalhist_get_remote_var "$remote" "USER")"
|
||||||
|
local ssh_key="$(_eternalhist_get_remote_var "$remote" "SSH_KEY")"
|
||||||
|
local port="${$(_eternalhist_get_remote_var "$remote" "PORT"):-22}"
|
||||||
|
|
||||||
|
local ssh_opts="-o ConnectTimeout=10 -o BatchMode=yes"
|
||||||
|
[[ -n "$ssh_key" ]] && ssh_opts="$ssh_opts -i $ssh_key"
|
||||||
|
[[ -n "$port" ]] && ssh_opts="$ssh_opts -p $port"
|
||||||
|
|
||||||
|
if ssh $ssh_opts "${user}@${host}" "echo 'Connection test successful'" 2>/dev/null; then
|
||||||
|
_eternalhist_colorize "green" "✓ SSH connection to $remote successful"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_eternalhist_colorize "red" "✗ SSH connection to $remote failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"dropbox"|"gdrive"|"s3")
|
||||||
|
_eternalhist_warn "Test not implemented for provider: $provider"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_eternalhist_error "Unknown provider: $provider"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sync functions (placeholder implementations)
|
||||||
|
_eternalhist_sync_remote() {
|
||||||
|
local remote="$1"
|
||||||
|
local provider="$(_eternalhist_get_remote_var "$remote" "PROVIDER")"
|
||||||
|
|
||||||
|
if ! _eternalhist_is_remote_enabled "$remote"; then
|
||||||
|
_eternalhist_log "debug" "Remote $remote is disabled, skipping sync"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_eternalhist_log "info" "Syncing with remote: $remote ($provider)"
|
||||||
|
|
||||||
|
case "$provider" in
|
||||||
|
"ssh")
|
||||||
|
_eternalhist_sync_ssh "$remote"
|
||||||
|
;;
|
||||||
|
"dropbox")
|
||||||
|
_eternalhist_sync_dropbox "$remote"
|
||||||
|
;;
|
||||||
|
"gdrive")
|
||||||
|
_eternalhist_sync_gdrive "$remote"
|
||||||
|
;;
|
||||||
|
"s3")
|
||||||
|
_eternalhist_sync_s3 "$remote"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_eternalhist_error "Unsupported provider: $provider"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_sync_ssh() {
|
||||||
|
local remote="$1"
|
||||||
|
local host="$(_eternalhist_get_remote_var "$remote" "HOST")"
|
||||||
|
local user="$(_eternalhist_get_remote_var "$remote" "USER")"
|
||||||
|
local remote_path="$(_eternalhist_get_remote_var "$remote" "PATH")"
|
||||||
|
local ssh_key="$(_eternalhist_get_remote_var "$remote" "SSH_KEY")"
|
||||||
|
local port="$(_eternalhist_get_remote_var "$remote" "PORT")"
|
||||||
|
|
||||||
|
local ssh_opts="-o ConnectTimeout=30"
|
||||||
|
[[ -n "$ssh_key" ]] && ssh_opts="$ssh_opts -i $ssh_key"
|
||||||
|
[[ -n "$port" ]] && ssh_opts="$ssh_opts -p $port"
|
||||||
|
|
||||||
|
# Simple sync: upload local file to remote
|
||||||
|
if scp $ssh_opts "$ETERNALHIST_LOCAL_FILE" "${user}@${host}:${remote_path}" 2>/dev/null; then
|
||||||
|
_eternalhist_colorize "green" "✓ Successfully synced to $remote"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_eternalhist_colorize "red" "✗ Failed to sync to $remote"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Placeholder sync functions for other providers
|
||||||
|
_eternalhist_sync_dropbox() {
|
||||||
|
local remote="$1"
|
||||||
|
_eternalhist_warn "Dropbox sync not yet implemented for remote: $remote"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_sync_gdrive() {
|
||||||
|
local remote="$1"
|
||||||
|
_eternalhist_warn "Google Drive sync not yet implemented for remote: $remote"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_eternalhist_sync_s3() {
|
||||||
|
local remote="$1"
|
||||||
|
_eternalhist_warn "S3 sync not yet implemented for remote: $remote"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main eternalhist command
|
||||||
|
eternalhist() {
|
||||||
|
# Handle empty command (show recent history)
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
_eternalhist_search_local | tail -n "${ETERNALHIST_SEARCH_LIMIT:-20}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
# Check for escape mechanism: \command means search for "command" literally
|
||||||
|
if [[ "$cmd" = \\* ]]; then
|
||||||
|
# Remove the escape backslash and treat as search term
|
||||||
|
local escaped_term="${cmd#\\}"
|
||||||
|
_eternalhist_search_local "$escaped_term" "${@:2}"
|
||||||
|
|
||||||
|
# Also search current session history
|
||||||
|
echo
|
||||||
|
_eternalhist_colorize "blue" "=== Current Session History ==="
|
||||||
|
local hist_cmd="history | grep -i '$escaped_term'"
|
||||||
|
for term in "${@:2}"; do
|
||||||
|
hist_cmd="$hist_cmd | grep -i '$term'"
|
||||||
|
done
|
||||||
|
eval "$hist_cmd"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if first argument is a known command
|
||||||
|
case "$cmd" in
|
||||||
|
"add")
|
||||||
|
shift
|
||||||
|
local entry="$*"
|
||||||
|
[[ -z "$entry" ]] && entry="$(history | tail -n 1 | sed 's/^[[:space:]]*[0-9]*[[:space:]]*//')"
|
||||||
|
_eternalhist_add_entry "$entry"
|
||||||
|
;;
|
||||||
|
"clear")
|
||||||
|
read -q "?Are you sure you want to clear eternal history? (y/N) "
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
> "$ETERNALHIST_LOCAL_FILE"
|
||||||
|
echo "Eternal history cleared."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"show")
|
||||||
|
shift
|
||||||
|
local limit="${1:-20}"
|
||||||
|
tail -n "$limit" "$ETERNALHIST_LOCAL_FILE"
|
||||||
|
;;
|
||||||
|
"stats")
|
||||||
|
_eternalhist_ensure_file
|
||||||
|
local total_lines="$(wc -l < "$ETERNALHIST_LOCAL_FILE")"
|
||||||
|
local unique_commands="$(cut -d'|' -f4 "$ETERNALHIST_LOCAL_FILE" | sort | uniq | wc -l)"
|
||||||
|
local oldest_entry="$(head -n 1 "$ETERNALHIST_LOCAL_FILE" | cut -d'|' -f1)"
|
||||||
|
local newest_entry="$(tail -n 1 "$ETERNALHIST_LOCAL_FILE" | cut -d'|' -f1)"
|
||||||
|
|
||||||
|
echo "Eternal History Statistics:"
|
||||||
|
echo " Total entries: $total_lines"
|
||||||
|
echo " Unique commands: $unique_commands"
|
||||||
|
echo " Oldest entry: ${oldest_entry:-N/A}"
|
||||||
|
echo " Newest entry: ${newest_entry:-N/A}"
|
||||||
|
echo " File location: $ETERNALHIST_LOCAL_FILE"
|
||||||
|
;;
|
||||||
|
"sync")
|
||||||
|
shift
|
||||||
|
local target_remotes=("$@")
|
||||||
|
if [[ ${#target_remotes[@]} -eq 0 ]]; then
|
||||||
|
if [[ "$ETERNALHIST_SYNC_ALL_REMOTES" == "true" ]]; then
|
||||||
|
target_remotes=($(_eternalhist_get_remotes))
|
||||||
|
elif [[ -n "$ETERNALHIST_DEFAULT_REMOTE" ]]; then
|
||||||
|
target_remotes=("$ETERNALHIST_DEFAULT_REMOTE")
|
||||||
|
else
|
||||||
|
_eternalhist_error "No remotes specified and no default remote configured"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
for remote in "${target_remotes[@]}"; do
|
||||||
|
_eternalhist_sync_remote "$remote"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
"remotes")
|
||||||
|
shift
|
||||||
|
local subcmd="$1"
|
||||||
|
shift
|
||||||
|
case "$subcmd" in
|
||||||
|
"list"|"")
|
||||||
|
_eternalhist_list_remotes
|
||||||
|
;;
|
||||||
|
"test")
|
||||||
|
local remote="$1"
|
||||||
|
if [[ -z "$remote" ]]; then
|
||||||
|
_eternalhist_error "Remote name required for test"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_eternalhist_test_remote "$remote"
|
||||||
|
;;
|
||||||
|
"add"|"remove"|"enable"|"disable")
|
||||||
|
_eternalhist_error "Remote management commands not yet implemented"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_eternalhist_error "Unknown remotes subcommand: $subcmd"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
"config")
|
||||||
|
echo "EternalHist Configuration:"
|
||||||
|
echo " Local file: $ETERNALHIST_LOCAL_FILE"
|
||||||
|
echo " Default remote: ${ETERNALHIST_DEFAULT_REMOTE:-none}"
|
||||||
|
echo " Auto sync: $ETERNALHIST_AUTO_SYNC"
|
||||||
|
echo " Configured remotes: ${ETERNALHIST_REMOTES:-none}"
|
||||||
|
;;
|
||||||
|
"help"|"-h"|"--help")
|
||||||
|
cat << 'EOF'
|
||||||
|
EternalHist - Advanced persistent command history
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
eternalhist [SEARCH_TERMS...] # Search eternal history (default behavior)
|
||||||
|
eternalhist [COMMAND] [OPTIONS] # Execute specific command
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
add [COMMAND] Add command to eternal history
|
||||||
|
clear Clear all eternal history
|
||||||
|
show [LIMIT] Show recent eternal history entries
|
||||||
|
stats Display eternal history statistics
|
||||||
|
sync [REMOTE...] Synchronize with remote storage
|
||||||
|
remotes Manage remote configurations
|
||||||
|
list List all configured remotes
|
||||||
|
test REMOTE Test connection to remote
|
||||||
|
config Show current configuration
|
||||||
|
help Show this help message
|
||||||
|
|
||||||
|
SEARCH BEHAVIOR:
|
||||||
|
eternalhist git commit # Search for "git" AND "commit"
|
||||||
|
eternalhist "git commit" # Search for exact phrase "git commit"
|
||||||
|
eternalhist \add something # Search for "add" (escaped to avoid add command)
|
||||||
|
eternalhist \sync # Search for "sync" (escaped to avoid sync command)
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
eternalhist git # Search for git commands
|
||||||
|
eternalhist docker run # Search for docker run commands
|
||||||
|
eternalhist \add file # Search for "add file" (not add command)
|
||||||
|
eternalhist add "custom cmd" # Add custom command to history
|
||||||
|
eternalhist sync primary # Sync with primary remote
|
||||||
|
eternalhist remotes list # List all remotes
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Default behavior: treat as search terms
|
||||||
|
_eternalhist_search_local "$@"
|
||||||
|
|
||||||
|
# Also search current session history like original ht function
|
||||||
|
echo
|
||||||
|
_eternalhist_colorize "blue" "=== Current Session History ==="
|
||||||
|
local hist_cmd="history"
|
||||||
|
for term in "$@"; do
|
||||||
|
hist_cmd="$hist_cmd | grep -i '$term'"
|
||||||
|
done
|
||||||
|
eval "$hist_cmd"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backward compatibility with existing ht function
|
||||||
|
ht() {
|
||||||
|
eternalhist "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Auto-add commands to eternal history (optional)
|
||||||
|
if [[ "$ETERNALHIST_AUTO_ADD" == "true" ]]; then
|
||||||
|
preexec() {
|
||||||
|
_eternalhist_add_entry "$1" 0
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Auto-sync on shell exit (optional)
|
||||||
|
if [[ "$ETERNALHIST_SYNC_ON_EXIT" == "true" ]]; then
|
||||||
|
zshexit() {
|
||||||
|
eternalhist sync >/dev/null 2>&1 &
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
_eternalhist_log "info" "EternalHist plugin loaded"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue