or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

history.mddocs/

0

# History Management

1

2

Comprehensive history management with programmatic control over command history storage, retrieval, and persistence. The gnureadline history system maintains compatibility with GNU Readline's indexing conventions.

3

4

## Capabilities

5

6

### History Buffer Operations

7

8

Basic operations for adding, retrieving, and manipulating history entries in memory.

9

10

```python { .api }

11

def add_history(line: str):

12

"""

13

Add a line to the history buffer.

14

15

Parameters:

16

- line: Command line to add to history

17

"""

18

19

def clear_history():

20

"""Clear the entire history list."""

21

22

def get_history_item(index: int) -> str:

23

"""

24

Get history item by index (1-based).

25

26

Parameters:

27

- index: History item index (1-based, 0 returns None)

28

29

Returns:

30

str or None: History item or None if index is 0 or out of range

31

"""

32

33

def get_current_history_length() -> int:

34

"""

35

Get the current number of history entries.

36

37

Returns:

38

int: Number of history entries

39

"""

40

```

41

42

### Usage Examples

43

44

```python

45

import gnureadline

46

47

# Build a command history

48

commands = ["ls -la", "cd /home", "python script.py", "git status"]

49

for cmd in commands:

50

gnureadline.add_history(cmd)

51

52

print(f"History length: {gnureadline.get_current_history_length()}") # 4

53

54

# Retrieve history items (1-based indexing)

55

first_cmd = gnureadline.get_history_item(1) # "ls -la"

56

last_cmd = gnureadline.get_history_item(4) # "git status"

57

invalid = gnureadline.get_history_item(0) # None

58

59

# Clear all history

60

gnureadline.clear_history()

61

print(f"After clear: {gnureadline.get_current_history_length()}") # 0

62

```

63

64

### History Modification

65

66

Advanced operations for modifying existing history entries using 0-based indexing.

67

68

```python { .api }

69

def remove_history_item(index: int) -> str:

70

"""

71

Remove history entry by index (0-based).

72

73

Parameters:

74

- index: History item index (0-based)

75

76

Returns:

77

str: Removed history item

78

"""

79

80

def replace_history_item(index: int, line: str) -> str:

81

"""

82

Replace history entry at index (0-based).

83

84

Parameters:

85

- index: History item index (0-based)

86

- line: New history line

87

88

Returns:

89

str: Previous history item at that index

90

"""

91

```

92

93

### Usage Examples

94

95

```python

96

import gnureadline

97

98

# Set up some history

99

gnureadline.add_history("command1")

100

gnureadline.add_history("command2")

101

gnureadline.add_history("command3")

102

103

# Replace second command (0-based index 1)

104

old_cmd = gnureadline.replace_history_item(1, "modified_command2")

105

print(f"Replaced '{old_cmd}' with 'modified_command2'")

106

107

# Remove first command (0-based index 0)

108

removed = gnureadline.remove_history_item(0)

109

print(f"Removed: '{removed}'")

110

111

# Check final state

112

for i in range(gnureadline.get_current_history_length()):

113

print(f"History[{i}]: {gnureadline.get_history_item(i+1)}") # +1 for 1-based get

114

```

115

116

### History Configuration

117

118

Control automatic history behavior and size limits.

119

120

```python { .api }

121

def set_history_length(length: int):

122

"""

123

Set maximum history length.

124

125

Parameters:

126

- length: Maximum number of history entries (-1 for unlimited)

127

"""

128

129

def get_history_length() -> int:

130

"""

131

Get maximum history length setting.

132

133

Returns:

134

int: Maximum history length (-1 if unlimited)

135

"""

136

137

def set_auto_history(enabled: bool):

138

"""

139

Enable or disable automatic history addition.

140

141

Parameters:

142

- enabled: Whether to automatically add lines to history

143

"""

144

```

145

146

### Usage Examples

147

148

```python

149

import gnureadline

150

151

# Set history limit

152

gnureadline.set_history_length(100)

153

print(f"History limit: {gnureadline.get_history_length()}") # 100

154

155

# Disable automatic history (manual control)

156

gnureadline.set_auto_history(False)

157

158

# Unlimited history

159

gnureadline.set_history_length(-1)

160

print(f"Unlimited history: {gnureadline.get_history_length()}") # -1

161

```

162

163

## File Persistence

164

165

### History File Operations

166

167

Save and load history to/from files for persistence across sessions.

168

169

```python { .api }

170

def read_history_file(filename: str = None):

171

"""

172

Load a readline history file.

173

174

Parameters:

175

- filename: History file path (default: ~/.history)

176

"""

177

178

def write_history_file(filename: str = None):

179

"""

180

Save the history to a file.

181

182

Parameters:

183

- filename: History file path (default: ~/.history)

184

"""

185

186

def append_history_file(nelements: int, filename: str = None):

187

"""

188

Append recent history entries to a file.

189

190

Parameters:

191

- nelements: Number of recent entries to append

192

- filename: History file path (default: ~/.history)

193

194

Note: Only available if HAVE_RL_APPEND_HISTORY is defined

195

"""

196

```

197

198

### Usage Examples

199

200

```python

201

import gnureadline

202

import os

203

204

# Set up custom history file location

205

history_file = os.path.expanduser("~/.my_app_history")

206

207

# Load existing history on startup

208

try:

209

gnureadline.read_history_file(history_file)

210

print(f"Loaded {gnureadline.get_current_history_length()} history entries")

211

except OSError as e:

212

print(f"No existing history file: {e}")

213

214

# Add some commands during session

215

gnureadline.add_history("command 1")

216

gnureadline.add_history("command 2")

217

218

# Save complete history on exit

219

try:

220

gnureadline.write_history_file(history_file)

221

print("History saved successfully")

222

except OSError as e:

223

print(f"Failed to save history: {e}")

224

225

# Alternatively, append only recent entries

226

try:

227

gnureadline.append_history_file(10, history_file) # Last 10 entries

228

print("Recent history appended")

229

except OSError as e:

230

print(f"Failed to append history: {e}")

231

```

232

233

## Advanced History Management

234

235

### History Filtering and Processing

236

237

```python

238

import gnureadline

239

import re

240

241

class HistoryManager:

242

def __init__(self, max_length=1000, filter_duplicates=True):

243

self.max_length = max_length

244

self.filter_duplicates = filter_duplicates

245

gnureadline.set_history_length(max_length)

246

gnureadline.set_auto_history(False) # Manual control

247

248

def add_filtered_history(self, line: str):

249

"""Add history with filtering logic."""

250

# Skip empty lines and whitespace-only lines

251

if not line.strip():

252

return

253

254

# Skip commands starting with space (privacy feature)

255

if line.startswith(' '):

256

return

257

258

# Filter out sensitive commands

259

sensitive_patterns = [r'password', r'secret', r'key\s*=']

260

if any(re.search(pattern, line, re.I) for pattern in sensitive_patterns):

261

return

262

263

# Remove duplicates if enabled

264

if self.filter_duplicates:

265

current_length = gnureadline.get_current_history_length()

266

if current_length > 0:

267

last_item = gnureadline.get_history_item(current_length)

268

if last_item == line:

269

return

270

271

gnureadline.add_history(line)

272

273

def search_history(self, pattern: str) -> list:

274

"""Search history for matching entries."""

275

matches = []

276

length = gnureadline.get_current_history_length()

277

278

for i in range(1, length + 1):

279

item = gnureadline.get_history_item(i)

280

if item and re.search(pattern, item, re.I):

281

matches.append((i, item))

282

283

return matches

284

285

def cleanup_history(self):

286

"""Remove old/redundant entries to keep history manageable."""

287

length = gnureadline.get_current_history_length()

288

if length <= self.max_length:

289

return

290

291

# Keep only the most recent entries

292

keep_entries = []

293

start_index = length - self.max_length + 1

294

295

for i in range(start_index, length + 1):

296

item = gnureadline.get_history_item(i)

297

if item:

298

keep_entries.append(item)

299

300

# Clear and rebuild history

301

gnureadline.clear_history()

302

for entry in keep_entries:

303

gnureadline.add_history(entry)

304

305

# Usage example

306

history_mgr = HistoryManager(max_length=500, filter_duplicates=True)

307

308

# Add commands with filtering

309

commands = [

310

"ls -la",

311

"cd /home",

312

"ls -la", # Duplicate - will be filtered

313

" secret_command", # Starts with space - will be filtered

314

"export PASSWORD=secret", # Contains sensitive data - will be filtered

315

"python script.py"

316

]

317

318

for cmd in commands:

319

history_mgr.add_filtered_history(cmd)

320

321

# Search history

322

matches = history_mgr.search_history("python")

323

print(f"Found {len(matches)} matches for 'python'")

324

325

# Periodic cleanup

326

history_mgr.cleanup_history()

327

```

328

329

## Index Compatibility Notes

330

331

**Important**: GNU Readline uses different indexing conventions for different operations:

332

333

- `get_history_item()`: **1-based indexing** (index 0 returns None)

334

- `remove_history_item()` and `replace_history_item()`: **0-based indexing**

335

336

This matches the GNU Readline C library behavior for compatibility with existing applications.

337

338

```python

339

import gnureadline

340

341

# Add some test data

342

gnureadline.add_history("first") # Will be at index 0 for remove/replace

343

gnureadline.add_history("second") # Will be at index 1 for remove/replace

344

345

# Getting items (1-based)

346

first = gnureadline.get_history_item(1) # "first"

347

second = gnureadline.get_history_item(2) # "second"

348

349

# Modifying items (0-based)

350

gnureadline.replace_history_item(0, "FIRST") # Replace "first" with "FIRST"

351

gnureadline.remove_history_item(1) # Remove "second"

352

353

# Verify the change

354

print(gnureadline.get_history_item(1)) # "FIRST"

355

print(gnureadline.get_history_item(2)) # None (removed)

356

```