Magnificent app which corrects your previous console command
Rule loading, command matching, and correction generation. This system processes failed commands through available rules to generate appropriate corrections using a sophisticated pattern-matching and correction-generation pipeline.
Functions for discovering, loading, and managing correction rules from both built-in and user-defined sources.
def load_rule(rule, settings):
"""
Imports rule module and returns Rule object.
Parameters:
- rule (pathlib.Path): Path to rule Python file
- settings (Settings): Application settings
Returns:
Rule: Loaded rule object with all metadata
Loads rule module and extracts:
- match function
- get_new_command function
- enabled_by_default (default: True)
- side_effect (default: None)
- priority (default: DEFAULT_PRIORITY or custom from settings)
- requires_output (default: True)
"""
def get_loaded_rules(rules, settings):
"""
Yields all available rules that are enabled in settings.
Parameters:
- rules (iterable): Collection of rule file paths
- settings (Settings): Application settings containing enabled rules
Yields:
Rule: Each enabled and loaded rule
"""
def get_rules(user_dir, settings):
"""
Returns all enabled rules from built-in and user directories.
Parameters:
- user_dir (pathlib.Path): User configuration directory
- settings (Settings): Application settings
Returns:
list[Rule]: Sorted list of enabled rules by priority
Searches for rules in:
- Built-in rules directory (thefuck/rules/*.py)
- User rules directory (~/.thefuck/rules/*.py)
"""Functions for testing rule applicability and generating corrections from matched rules.
def is_rule_match(command, rule, settings):
"""
Returns True if rule matches the given command.
Parameters:
- command (Command): Command to test against rule
- rule (Rule): Rule to test for match
- settings (Settings): Application settings
Returns:
bool: True if rule applies to the command
Handles:
- Script-only commands when rule requires output
- Exception handling for rule match functions
- Debug logging of rule matching attempts
"""
def make_corrected_commands(command, rule, settings):
"""
Generates corrected commands from a matched rule.
Parameters:
- command (Command): Original failed command
- rule (Rule): Matched rule to apply
- settings (Settings): Application settings
Yields:
CorrectedCommand: Each generated correction with proper priority
Handles:
- Single correction return values
- Multiple correction return values (lists)
- Priority calculation for multiple corrections
"""
def get_corrected_commands(command, user_dir, settings):
"""
Returns sorted sequence of corrected commands for a given command.
Parameters:
- command (Command): Original failed command
- user_dir (pathlib.Path): User configuration directory
- settings (Settings): Application settings
Returns:
SortedCorrectedCommandsSequence: Lazy-evaluated, sorted corrections
Process:
1. Load all enabled rules
2. Test each rule for matches
3. Generate corrections from matched rules
4. Return sorted, deduplicated sequence
"""Every correction rule is a Python module that must implement specific functions and can define optional attributes:
def match(command, settings):
"""
Determines if this rule applies to the given command.
Parameters:
- command (Command): The failed command to analyze
- settings (Settings): Application settings
Returns:
bool: True if this rule can correct the command
This function should analyze command.script, command.stdout,
and command.stderr to determine applicability.
"""
def get_new_command(command, settings):
"""
Generates corrected command(s) for the matched command.
Parameters:
- command (Command): The failed command to correct
- settings (Settings): Application settings
Returns:
str or list[str]: Single correction or list of possible corrections
This function should return the corrected command string(s)
that should be executed instead of the original.
"""enabled_by_default = True
"""
bool: Whether this rule is enabled by default.
Default: True if not specified.
"""
priority = 1000
"""
int: Rule priority for ordering corrections.
Lower numbers = higher priority.
Default: conf.DEFAULT_PRIORITY (1000) if not specified.
"""
requires_output = True
"""
bool: Whether this rule needs command output (stdout/stderr) to function.
Default: True if not specified.
Set to False for rules that only analyze command.script.
"""
def side_effect(old_cmd, new_cmd, settings):
"""
Optional function executed when the corrected command runs.
Parameters:
- old_cmd (Command): Original failed command
- new_cmd (str): Corrected command being executed
- settings (Settings): Application settings
Returns:
None
Used for additional actions like updating configuration,
cleaning up state, or logging corrections.
"""The thefuck package includes 70+ built-in rules covering common command-line tools. Here are some examples:
# Example: thefuck/rules/git_push.py
import re
from thefuck.utils import for_app
@for_app('git')
def match(command, settings):
return (command.script.startswith('git push') and
'set-upstream' in command.stderr)
def get_new_command(command, settings):
branch = re.search(r'git push (\w+)', command.script)
if branch:
return f'git push --set-upstream origin {branch.group(1)}'
return 'git push --set-upstream origin main'
enabled_by_default = True
priority = 1000# Example: thefuck/rules/sudo.py
def match(command, settings):
return ('permission denied' in command.stderr.lower() or
'operation not permitted' in command.stderr.lower())
def get_new_command(command, settings):
return f'sudo {command.script}'
enabled_by_default = True
priority = 100 # High priorityfrom thefuck.corrector import get_corrected_commands
from thefuck.types import Command
from thefuck.main import setup_user_dir
from thefuck.conf import get_settings
# Setup
user_dir = setup_user_dir()
settings = get_settings(user_dir)
# Create a failed command
command = Command(
script="git push origin main",
stdout="",
stderr="fatal: The current branch main has no upstream branch."
)
# Get corrections
corrections = get_corrected_commands(command, user_dir, settings)
# Access corrections
if corrections:
print(f"First correction: {corrections[0].script}")
print(f"Total corrections: {len(corrections)}")
for correction in corrections:
print(f" {correction.script} (priority: {correction.priority})")from thefuck.corrector import load_rule, is_rule_match
from pathlib import Path
# Load a specific rule
rule_path = Path("thefuck/rules/git_push.py")
rule = load_rule(rule_path, settings)
# Test rule matching
command = Command("git push origin main", "", "set-upstream error...")
if is_rule_match(command, rule, settings):
print(f"Rule {rule.name} matches the command")
# Generate corrections
corrections = list(make_corrected_commands(command, rule, settings))
for correction in corrections:
print(f"Correction: {correction.script}")from thefuck.corrector import get_rules
# Get all enabled rules
user_dir = setup_user_dir()
settings = get_settings(user_dir)
rules = get_rules(user_dir, settings)
print(f"Loaded {len(rules)} rules:")
for rule in rules[:5]: # Show first 5
print(f" {rule.name} (priority: {rule.priority})")# Pattern: Check command name
def match(command, settings):
return command.script.startswith('docker')
# Pattern: Check error output
def match(command, settings):
return 'command not found' in command.stderr
# Pattern: Complex regex matching
import re
def match(command, settings):
return re.search(r'git \w+', command.script) and 'not a git command' in command.stderr# Pattern: Simple replacement
def get_new_command(command, settings):
return command.script.replace('pussh', 'push')
# Pattern: Multiple corrections
def get_new_command(command, settings):
return [
f'sudo {command.script}',
command.script.replace('apt-get', 'apt')
]
# Pattern: Context-aware correction
def get_new_command(command, settings):
if 'permission denied' in command.stderr:
return f'sudo {command.script}'
elif 'not found' in command.stderr:
return command.script.replace('ll', 'ls -la')The rule system handles various error conditions:
Install with Tessl CLI
npx tessl i tessl/pypi-thefuck