or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

completion.mdconfiguration.mdhistory.mdhooks.mdindex.mdline-editing.md

hooks.mddocs/

0

# Event Hooks

1

2

Advanced customization through event hooks that execute at specific points in the readline process, enabling custom display and input handling. These hooks provide fine-grained control over readline's behavior at key moments in the input cycle.

3

4

## Capabilities

5

6

### Startup Hook

7

8

Function executed just before readline prints the first prompt, allowing for initialization and setup before user interaction begins.

9

10

```python { .api }

11

def set_startup_hook(function=None):

12

"""

13

Set or remove the startup_hook function.

14

15

Parameters:

16

- function (callable, optional): Function called with no arguments just before

17

readline prints the first prompt. If None, removes hook.

18

19

Returns:

20

None

21

"""

22

```

23

24

**Usage Example:**

25

26

```python

27

import readline

28

import os

29

import time

30

31

def startup_initialization():

32

"""Initialize readline environment at startup"""

33

# Load custom history file

34

history_file = os.path.expanduser('~/.myapp_history')

35

try:

36

readline.read_history_file(history_file)

37

except FileNotFoundError:

38

pass

39

40

# Set up custom completion

41

readline.parse_and_bind('tab: complete')

42

43

# Display welcome message

44

print(f"Welcome! Loaded {readline.get_current_history_length()} history entries.")

45

print("Type 'help' for available commands.")

46

47

# Set startup hook

48

readline.set_startup_hook(startup_initialization)

49

50

# The hook will be called before the first input() call

51

user_input = input("Command: ")

52

```

53

54

### Pre-Input Hook

55

56

Function executed after the first prompt has been printed but before readline starts reading input characters, useful for pre-populating the command line or performing just-in-time setup.

57

58

```python { .api }

59

def set_pre_input_hook(function=None):

60

"""

61

Set or remove the pre_input_hook function.

62

63

Parameters:

64

- function (callable, optional): Function called with no arguments after the first

65

prompt has been printed and just before readline starts

66

reading input characters. If None, removes hook.

67

68

Returns:

69

None

70

71

Note: Only available when compiled with HAVE_RL_PRE_INPUT_HOOK

72

"""

73

```

74

75

**Usage Example:**

76

77

```python

78

import readline

79

import datetime

80

81

def pre_input_setup():

82

"""Set up command line before input begins"""

83

# Insert timestamp prefix

84

timestamp = datetime.datetime.now().strftime("%H:%M ")

85

readline.insert_text(f"[{timestamp}] ")

86

87

# Or insert last command for editing

88

history_length = readline.get_current_history_length()

89

if history_length > 0:

90

last_command = readline.get_history_item(history_length)

91

if last_command and last_command.startswith("repeat:"):

92

# Remove "repeat:" prefix and insert the command

93

command = last_command[7:] # Remove "repeat:" prefix

94

readline.insert_text(command)

95

96

# Set pre-input hook

97

readline.set_pre_input_hook(pre_input_setup)

98

99

# Hook executes after prompt is shown but before input starts

100

command = input("CMD> ")

101

```

102

103

### Advanced Pre-Input Patterns

104

105

```python

106

import readline

107

import os

108

109

class SmartPreInput:

110

def __init__(self):

111

self.context_aware = True

112

self.auto_suggest = True

113

114

def setup_input(self):

115

"""Intelligent pre-input setup based on context"""

116

if not self.context_aware:

117

return

118

119

# Check current directory for context clues

120

current_dir = os.getcwd()

121

files = os.listdir(current_dir)

122

123

# Auto-suggest based on directory contents

124

if 'Makefile' in files:

125

readline.insert_text("make ")

126

elif 'package.json' in files:

127

readline.insert_text("npm ")

128

elif 'requirements.txt' in files:

129

readline.insert_text("pip install -r requirements.txt")

130

elif 'setup.py' in files:

131

readline.insert_text("python setup.py ")

132

elif any(f.endswith('.py') for f in files):

133

py_files = [f for f in files if f.endswith('.py')]

134

if 'main.py' in py_files:

135

readline.insert_text("python main.py ")

136

else:

137

readline.insert_text("python ")

138

139

smart_input = SmartPreInput()

140

readline.set_pre_input_hook(smart_input.setup_input)

141

```

142

143

### Completion Display Hook

144

145

Function for customizing how completion matches are displayed to the user, allowing for enhanced completion interfaces and custom formatting.

146

147

```python { .api }

148

def set_completion_display_matches_hook(function=None):

149

"""

150

Set or remove the completion display function.

151

152

Parameters:

153

- function (callable, optional): Function called as function(substitution, matches,

154

longest_match_length) when displaying completion matches.

155

If None, removes hook.

156

157

Returns:

158

None

159

"""

160

```

161

162

**Usage Example:**

163

164

```python

165

import readline

166

167

def custom_completion_display(substitution, matches, longest_match_length):

168

"""Custom completion display with enhanced formatting"""

169

print(f"\nπŸ“‹ {len(matches)} completions for '{substitution}':")

170

171

# Group matches by type or category

172

files = []

173

dirs = []

174

commands = []

175

176

for match in matches:

177

if match.endswith('/'):

178

dirs.append(match)

179

elif '.' in match:

180

files.append(match)

181

else:

182

commands.append(match)

183

184

# Display grouped results

185

if dirs:

186

print(" πŸ“ Directories:")

187

for d in dirs[:5]: # Show first 5

188

print(f" {d}")

189

if len(dirs) > 5:

190

print(f" ... and {len(dirs) - 5} more directories")

191

192

if files:

193

print(" πŸ“„ Files:")

194

for f in files[:5]:

195

print(f" {f}")

196

if len(files) > 5:

197

print(f" ... and {len(files) - 5} more files")

198

199

if commands:

200

print(" ⚑ Commands:")

201

for c in commands[:5]:

202

print(f" {c}")

203

if len(commands) > 5:

204

print(f" ... and {len(commands) - 5} more commands")

205

206

print() # Extra line for readability

207

208

# Set custom display hook

209

readline.set_completion_display_matches_hook(custom_completion_display)

210

```

211

212

### Advanced Display Hook Example

213

214

```python

215

import readline

216

import os

217

import stat

218

219

def detailed_completion_display(substitution, matches, longest_match_length):

220

"""Detailed completion display with file information"""

221

print(f"\nπŸ” Completions for '{substitution}' ({len(matches)} matches):")

222

223

# Sort matches: directories first, then files

224

dirs = [m for m in matches if m.endswith('/')]

225

files = [m for m in matches if not m.endswith('/')]

226

sorted_matches = dirs + files

227

228

# Display with details

229

for i, match in enumerate(sorted_matches[:10]): # Show first 10

230

if match.endswith('/'):

231

icon = "πŸ“"

232

details = "directory"

233

else:

234

icon = "πŸ“„"

235

try:

236

# Get file size and modification time

237

stats = os.stat(match)

238

size = stats.st_size

239

mtime = stats.st_mtime

240

241

# Format size

242

if size < 1024:

243

size_str = f"{size}B"

244

elif size < 1024 * 1024:

245

size_str = f"{size // 1024}KB"

246

else:

247

size_str = f"{size // (1024 * 1024)}MB"

248

249

details = f"{size_str}"

250

251

# Check if executable

252

if os.access(match, os.X_OK):

253

icon = "⚑"

254

details += " (executable)"

255

256

except OSError:

257

details = "file"

258

259

print(f" {i+1:2d}. {icon} {match:<{longest_match_length + 2}} {details}")

260

261

if len(matches) > 10:

262

print(f" ... and {len(matches) - 10} more matches")

263

print()

264

265

readline.set_completion_display_matches_hook(detailed_completion_display)

266

```

267

268

## Hook Integration Patterns

269

270

### Complete Interactive Setup

271

272

```python

273

import readline

274

import atexit

275

import os

276

277

class InteractiveShell:

278

def __init__(self):

279

self.history_file = os.path.expanduser('~/.myshell_history')

280

self.setup_readline()

281

282

def setup_readline(self):

283

"""Complete readline setup with all hooks"""

284

# Set all hooks

285

readline.set_startup_hook(self.startup_hook)

286

readline.set_pre_input_hook(self.pre_input_hook)

287

readline.set_completion_display_matches_hook(self.display_hook)

288

289

# Configure completion

290

readline.set_completer(self.completer)

291

readline.parse_and_bind('tab: complete')

292

293

# Set up history

294

try:

295

readline.read_history_file(self.history_file)

296

except FileNotFoundError:

297

pass

298

299

atexit.register(self.cleanup)

300

301

def startup_hook(self):

302

"""Initialization at startup"""

303

print("πŸš€ Interactive shell ready!")

304

readline.set_history_length(1000)

305

306

def pre_input_hook(self):

307

"""Pre-input setup"""

308

# Could insert context-aware prefixes here

309

pass

310

311

def display_hook(self, substitution, matches, longest_match_length):

312

"""Custom completion display"""

313

if len(matches) > 1:

314

print(f"\nπŸ’‘ {len(matches)} options for '{substitution}':")

315

for i, match in enumerate(matches[:5]):

316

print(f" {i+1}. {match}")

317

if len(matches) > 5:

318

print(f" ... and {len(matches) - 5} more")

319

print()

320

321

def completer(self, text, state):

322

"""Simple file completion"""

323

import glob

324

matches = glob.glob(text + '*')

325

return matches[state] if state < len(matches) else None

326

327

def cleanup(self):

328

"""Cleanup when exiting"""

329

readline.write_history_file(self.history_file)

330

331

# Set up interactive shell

332

shell = InteractiveShell()

333

```

334

335

## Platform Availability

336

337

**Note**: The `set_pre_input_hook()` function is only available when compiled with `HAVE_RL_PRE_INPUT_HOOK`. It may not be available on all systems or readline installations.