or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-application.mddata-types.mdindex.mdrule-development.mdrule-system.mdshell-integration.mduser-interface.mdutilities.md

rule-system.mddocs/

0

# Rule System and Correction

1

2

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.

3

4

## Capabilities

5

6

### Rule Loading and Management

7

8

Functions for discovering, loading, and managing correction rules from both built-in and user-defined sources.

9

10

```python { .api }

11

def load_rule(rule, settings):

12

"""

13

Imports rule module and returns Rule object.

14

15

Parameters:

16

- rule (pathlib.Path): Path to rule Python file

17

- settings (Settings): Application settings

18

19

Returns:

20

Rule: Loaded rule object with all metadata

21

22

Loads rule module and extracts:

23

- match function

24

- get_new_command function

25

- enabled_by_default (default: True)

26

- side_effect (default: None)

27

- priority (default: DEFAULT_PRIORITY or custom from settings)

28

- requires_output (default: True)

29

"""

30

31

def get_loaded_rules(rules, settings):

32

"""

33

Yields all available rules that are enabled in settings.

34

35

Parameters:

36

- rules (iterable): Collection of rule file paths

37

- settings (Settings): Application settings containing enabled rules

38

39

Yields:

40

Rule: Each enabled and loaded rule

41

"""

42

43

def get_rules(user_dir, settings):

44

"""

45

Returns all enabled rules from built-in and user directories.

46

47

Parameters:

48

- user_dir (pathlib.Path): User configuration directory

49

- settings (Settings): Application settings

50

51

Returns:

52

list[Rule]: Sorted list of enabled rules by priority

53

54

Searches for rules in:

55

- Built-in rules directory (thefuck/rules/*.py)

56

- User rules directory (~/.thefuck/rules/*.py)

57

"""

58

```

59

60

### Command Matching and Processing

61

62

Functions for testing rule applicability and generating corrections from matched rules.

63

64

```python { .api }

65

def is_rule_match(command, rule, settings):

66

"""

67

Returns True if rule matches the given command.

68

69

Parameters:

70

- command (Command): Command to test against rule

71

- rule (Rule): Rule to test for match

72

- settings (Settings): Application settings

73

74

Returns:

75

bool: True if rule applies to the command

76

77

Handles:

78

- Script-only commands when rule requires output

79

- Exception handling for rule match functions

80

- Debug logging of rule matching attempts

81

"""

82

83

def make_corrected_commands(command, rule, settings):

84

"""

85

Generates corrected commands from a matched rule.

86

87

Parameters:

88

- command (Command): Original failed command

89

- rule (Rule): Matched rule to apply

90

- settings (Settings): Application settings

91

92

Yields:

93

CorrectedCommand: Each generated correction with proper priority

94

95

Handles:

96

- Single correction return values

97

- Multiple correction return values (lists)

98

- Priority calculation for multiple corrections

99

"""

100

101

def get_corrected_commands(command, user_dir, settings):

102

"""

103

Returns sorted sequence of corrected commands for a given command.

104

105

Parameters:

106

- command (Command): Original failed command

107

- user_dir (pathlib.Path): User configuration directory

108

- settings (Settings): Application settings

109

110

Returns:

111

SortedCorrectedCommandsSequence: Lazy-evaluated, sorted corrections

112

113

Process:

114

1. Load all enabled rules

115

2. Test each rule for matches

116

3. Generate corrections from matched rules

117

4. Return sorted, deduplicated sequence

118

"""

119

```

120

121

## Rule Structure

122

123

Every correction rule is a Python module that must implement specific functions and can define optional attributes:

124

125

### Required Functions

126

127

```python { .api }

128

def match(command, settings):

129

"""

130

Determines if this rule applies to the given command.

131

132

Parameters:

133

- command (Command): The failed command to analyze

134

- settings (Settings): Application settings

135

136

Returns:

137

bool: True if this rule can correct the command

138

139

This function should analyze command.script, command.stdout,

140

and command.stderr to determine applicability.

141

"""

142

143

def get_new_command(command, settings):

144

"""

145

Generates corrected command(s) for the matched command.

146

147

Parameters:

148

- command (Command): The failed command to correct

149

- settings (Settings): Application settings

150

151

Returns:

152

str or list[str]: Single correction or list of possible corrections

153

154

This function should return the corrected command string(s)

155

that should be executed instead of the original.

156

"""

157

```

158

159

### Optional Attributes

160

161

```python { .api }

162

enabled_by_default = True

163

"""

164

bool: Whether this rule is enabled by default.

165

Default: True if not specified.

166

"""

167

168

priority = 1000

169

"""

170

int: Rule priority for ordering corrections.

171

Lower numbers = higher priority.

172

Default: conf.DEFAULT_PRIORITY (1000) if not specified.

173

"""

174

175

requires_output = True

176

"""

177

bool: Whether this rule needs command output (stdout/stderr) to function.

178

Default: True if not specified.

179

Set to False for rules that only analyze command.script.

180

"""

181

182

def side_effect(old_cmd, new_cmd, settings):

183

"""

184

Optional function executed when the corrected command runs.

185

186

Parameters:

187

- old_cmd (Command): Original failed command

188

- new_cmd (str): Corrected command being executed

189

- settings (Settings): Application settings

190

191

Returns:

192

None

193

194

Used for additional actions like updating configuration,

195

cleaning up state, or logging corrections.

196

"""

197

```

198

199

## Built-in Rules Examples

200

201

The thefuck package includes 70+ built-in rules covering common command-line tools. Here are some examples:

202

203

### Git Push Rule Example

204

205

```python

206

# Example: thefuck/rules/git_push.py

207

import re

208

from thefuck.utils import for_app

209

210

@for_app('git')

211

def match(command, settings):

212

return (command.script.startswith('git push') and

213

'set-upstream' in command.stderr)

214

215

def get_new_command(command, settings):

216

branch = re.search(r'git push (\w+)', command.script)

217

if branch:

218

return f'git push --set-upstream origin {branch.group(1)}'

219

return 'git push --set-upstream origin main'

220

221

enabled_by_default = True

222

priority = 1000

223

```

224

225

### Sudo Rule Example

226

227

```python

228

# Example: thefuck/rules/sudo.py

229

def match(command, settings):

230

return ('permission denied' in command.stderr.lower() or

231

'operation not permitted' in command.stderr.lower())

232

233

def get_new_command(command, settings):

234

return f'sudo {command.script}'

235

236

enabled_by_default = True

237

priority = 100 # High priority

238

```

239

240

## Usage Examples

241

242

### Basic Rule Processing

243

244

```python

245

from thefuck.corrector import get_corrected_commands

246

from thefuck.types import Command

247

from thefuck.main import setup_user_dir

248

from thefuck.conf import get_settings

249

250

# Setup

251

user_dir = setup_user_dir()

252

settings = get_settings(user_dir)

253

254

# Create a failed command

255

command = Command(

256

script="git push origin main",

257

stdout="",

258

stderr="fatal: The current branch main has no upstream branch."

259

)

260

261

# Get corrections

262

corrections = get_corrected_commands(command, user_dir, settings)

263

264

# Access corrections

265

if corrections:

266

print(f"First correction: {corrections[0].script}")

267

print(f"Total corrections: {len(corrections)}")

268

269

for correction in corrections:

270

print(f" {correction.script} (priority: {correction.priority})")

271

```

272

273

### Manual Rule Testing

274

275

```python

276

from thefuck.corrector import load_rule, is_rule_match

277

from pathlib import Path

278

279

# Load a specific rule

280

rule_path = Path("thefuck/rules/git_push.py")

281

rule = load_rule(rule_path, settings)

282

283

# Test rule matching

284

command = Command("git push origin main", "", "set-upstream error...")

285

if is_rule_match(command, rule, settings):

286

print(f"Rule {rule.name} matches the command")

287

288

# Generate corrections

289

corrections = list(make_corrected_commands(command, rule, settings))

290

for correction in corrections:

291

print(f"Correction: {correction.script}")

292

```

293

294

### Custom Rule Loading

295

296

```python

297

from thefuck.corrector import get_rules

298

299

# Get all enabled rules

300

user_dir = setup_user_dir()

301

settings = get_settings(user_dir)

302

rules = get_rules(user_dir, settings)

303

304

print(f"Loaded {len(rules)} rules:")

305

for rule in rules[:5]: # Show first 5

306

print(f" {rule.name} (priority: {rule.priority})")

307

```

308

309

## Rule Development Patterns

310

311

### Command Analysis Patterns

312

313

```python

314

# Pattern: Check command name

315

def match(command, settings):

316

return command.script.startswith('docker')

317

318

# Pattern: Check error output

319

def match(command, settings):

320

return 'command not found' in command.stderr

321

322

# Pattern: Complex regex matching

323

import re

324

def match(command, settings):

325

return re.search(r'git \w+', command.script) and 'not a git command' in command.stderr

326

```

327

328

### Correction Generation Patterns

329

330

```python

331

# Pattern: Simple replacement

332

def get_new_command(command, settings):

333

return command.script.replace('pussh', 'push')

334

335

# Pattern: Multiple corrections

336

def get_new_command(command, settings):

337

return [

338

f'sudo {command.script}',

339

command.script.replace('apt-get', 'apt')

340

]

341

342

# Pattern: Context-aware correction

343

def get_new_command(command, settings):

344

if 'permission denied' in command.stderr:

345

return f'sudo {command.script}'

346

elif 'not found' in command.stderr:

347

return command.script.replace('ll', 'ls -la')

348

```

349

350

## Error Handling

351

352

The rule system handles various error conditions:

353

354

- **Rule loading errors**: Invalid rule modules are logged and skipped

355

- **Match function exceptions**: Caught and logged, rule is skipped for that command

356

- **Correction generation errors**: Caught and logged, rule produces no corrections

357

- **Priority conflicts**: Rules with same priority are ordered consistently

358

- **Circular dependencies**: Prevented through proper rule isolation