or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

completion.mddocs/

0

# Tab Completion

1

2

Programmable tab completion system with customizable word breaking and completion functions. The gnureadline completion system provides context-aware completion with full control over behavior and display.

3

4

## Capabilities

5

6

### Completion Function Management

7

8

Set up and manage the function that provides completion suggestions.

9

10

```python { .api }

11

def set_completer(function):

12

"""

13

Set the completion function.

14

15

Parameters:

16

- function: Completion function(text: str, state: int) -> str or None

17

Should return the state-th completion for text, or None when done

18

"""

19

20

def get_completer():

21

"""

22

Get the current completion function.

23

24

Returns:

25

callable or None: Current completion function

26

"""

27

```

28

29

### Usage Examples

30

31

```python

32

import gnureadline

33

import os

34

35

def file_completer(text: str, state: int) -> str:

36

"""Complete file and directory names."""

37

if state == 0:

38

# First call - generate list of matches

39

if not hasattr(file_completer, 'matches'):

40

file_completer.matches = []

41

42

# Get directory to search in

43

dirname = os.path.dirname(text) or '.'

44

basename = os.path.basename(text)

45

46

try:

47

# Find matching files

48

file_completer.matches = []

49

for filename in os.listdir(dirname):

50

if filename.startswith(basename):

51

full_path = os.path.join(dirname, filename)

52

if os.path.isdir(full_path):

53

file_completer.matches.append(filename + '/')

54

else:

55

file_completer.matches.append(filename)

56

except OSError:

57

file_completer.matches = []

58

59

# Return the state-th match

60

try:

61

return file_completer.matches[state]

62

except IndexError:

63

return None

64

65

# Set up file completion

66

gnureadline.set_completer(file_completer)

67

gnureadline.parse_and_bind("tab: complete")

68

69

# Test the completer

70

current_completer = gnureadline.get_completer()

71

print(f"Current completer: {current_completer.__name__}")

72

```

73

74

### Word Breaking Configuration

75

76

Control how readline splits the input into words for completion.

77

78

```python { .api }

79

def set_completer_delims(string: str):

80

"""

81

Set the word break characters for completion.

82

83

Parameters:

84

- string: Characters that separate words for completion

85

"""

86

87

def get_completer_delims() -> str:

88

"""

89

Get the current word break characters for completion.

90

91

Returns:

92

str: Current word break characters

93

"""

94

```

95

96

### Usage Examples

97

98

```python

99

import gnureadline

100

101

# Default delimiters include space, tab, newline and many punctuation chars

102

default_delims = gnureadline.get_completer_delims()

103

print(f"Default delimiters: '{default_delims}'")

104

105

# Set custom delimiters for specific applications

106

# For shell-like completion, keep most punctuation as delimiters

107

gnureadline.set_completer_delims(' \t\n`!@#$%^&*()=+[{]}\\|;:\'",<>?')

108

109

# For Python identifier completion, use fewer delimiters

110

gnureadline.set_completer_delims(' \t\n`!@#$%^&*()=+[{]}\\|;:\'",<>?/')

111

112

# For path completion, don't break on forward slashes

113

gnureadline.set_completer_delims(' \t\n`!@#$%^&*()=+[{]}\\|;:\'",<>?')

114

115

print(f"Updated delimiters: '{gnureadline.get_completer_delims()}'")

116

```

117

118

### Completion Context Information

119

120

Access information about the current completion context.

121

122

```python { .api }

123

def get_completion_type() -> int:

124

"""

125

Get the type of completion being attempted.

126

127

Returns:

128

int: Completion type constant

129

"""

130

131

def get_begidx() -> int:

132

"""

133

Get the beginning index of the completion.

134

135

Returns:

136

int: Start index of text being completed

137

"""

138

139

def get_endidx() -> int:

140

"""

141

Get the ending index of the completion.

142

143

Returns:

144

int: End index of text being completed

145

"""

146

```

147

148

### Usage Examples

149

150

```python

151

import gnureadline

152

153

def context_aware_completer(text: str, state: int) -> str:

154

"""Completer that uses context information."""

155

if state == 0:

156

# Get completion context

157

begidx = gnureadline.get_begidx()

158

endidx = gnureadline.get_endidx()

159

completion_type = gnureadline.get_completion_type()

160

line_buffer = gnureadline.get_line_buffer()

161

162

print(f"\nCompletion context:")

163

print(f" Text: '{text}'")

164

print(f" Begin: {begidx}, End: {endidx}")

165

print(f" Type: {completion_type}")

166

print(f" Buffer: '{line_buffer}'")

167

print(f" Before: '{line_buffer[:begidx]}'")

168

print(f" After: '{line_buffer[endidx:]}'")

169

170

# Generate completions based on context

171

before_text = line_buffer[:begidx].strip()

172

173

if not before_text:

174

# At beginning of line - complete commands

175

context_aware_completer.matches = [

176

cmd for cmd in ['help', 'list', 'show', 'quit', 'exit']

177

if cmd.startswith(text)

178

]

179

elif before_text.endswith('--'):

180

# Complete long options

181

context_aware_completer.matches = [

182

opt for opt in ['--help', '--version', '--verbose', '--quiet']

183

if opt.startswith(text)

184

]

185

else:

186

# Complete filenames

187

import os

188

try:

189

context_aware_completer.matches = [

190

f for f in os.listdir('.')

191

if f.startswith(text)

192

]

193

except OSError:

194

context_aware_completer.matches = []

195

196

try:

197

return context_aware_completer.matches[state]

198

except (IndexError, AttributeError):

199

return None

200

201

gnureadline.set_completer(context_aware_completer)

202

gnureadline.parse_and_bind("tab: complete")

203

```

204

205

## Advanced Completion Examples

206

207

### Command-Specific Completion

208

209

```python

210

import gnureadline

211

import shlex

212

213

class CommandCompleter:

214

def __init__(self):

215

self.commands = {

216

'ls': self._complete_files,

217

'cd': self._complete_directories,

218

'cat': self._complete_files,

219

'grep': self._complete_grep,

220

'help': self._complete_help_topics,

221

}

222

223

self.help_topics = ['commands', 'completion', 'history', 'configuration']

224

225

def complete(self, text: str, state: int) -> str:

226

"""Main completion entry point."""

227

if state == 0:

228

line_buffer = gnureadline.get_line_buffer()

229

begidx = gnureadline.get_begidx()

230

231

# Parse the command line

232

try:

233

tokens = shlex.split(line_buffer[:begidx])

234

except ValueError:

235

tokens = line_buffer[:begidx].split()

236

237

if not tokens:

238

# Complete command names

239

self.matches = [cmd for cmd in self.commands.keys() if cmd.startswith(text)]

240

else:

241

command = tokens[0]

242

if command in self.commands:

243

# Command-specific completion

244

self.matches = self.commands[command](text, tokens)

245

else:

246

# Default to file completion

247

self.matches = self._complete_files(text, tokens)

248

249

try:

250

return self.matches[state]

251

except (IndexError, AttributeError):

252

return None

253

254

def _complete_files(self, text: str, tokens: list) -> list:

255

"""Complete file names."""

256

import os

257

import glob

258

259

if text:

260

pattern = text + '*'

261

else:

262

pattern = '*'

263

264

matches = glob.glob(pattern)

265

return [match + ('/' if os.path.isdir(match) else '') for match in matches]

266

267

def _complete_directories(self, text: str, tokens: list) -> list:

268

"""Complete directory names only."""

269

import os

270

import glob

271

272

pattern = text + '*' if text else '*'

273

matches = glob.glob(pattern)

274

return [match + '/' for match in matches if os.path.isdir(match)]

275

276

def _complete_grep(self, text: str, tokens: list) -> list:

277

"""Complete grep command with patterns and files."""

278

if len(tokens) < 2:

279

# First argument - could be a pattern or option

280

if text.startswith('-'):

281

return [opt for opt in ['-i', '-v', '-r', '-n', '-l'] if opt.startswith(text)]

282

else:

283

# Return some common patterns

284

patterns = ['error', 'warning', 'TODO', 'FIXME', 'import', 'def ', 'class ']

285

return [p for p in patterns if p.startswith(text)]

286

else:

287

# Additional arguments - complete files

288

return self._complete_files(text, tokens)

289

290

def _complete_help_topics(self, text: str, tokens: list) -> list:

291

"""Complete help topics."""

292

return [topic for topic in self.help_topics if topic.startswith(text)]

293

294

# Set up the command completer

295

completer = CommandCompleter()

296

gnureadline.set_completer(completer.complete)

297

gnureadline.parse_and_bind("tab: complete")

298

299

# Configure word delimiters for shell-like behavior

300

gnureadline.set_completer_delims(' \t\n`!@#$%^&*()=+[{]}\\|;:\'",<>?')

301

```

302

303

### Python Code Completion

304

305

```python

306

import gnureadline

307

import keyword

308

import builtins

309

310

class PythonCompleter:

311

def __init__(self):

312

self.namespace = {

313

**builtins.__dict__,

314

**globals(),

315

**locals()

316

}

317

318

def complete(self, text: str, state: int) -> str:

319

"""Complete Python identifiers and keywords."""

320

if state == 0:

321

self.matches = []

322

323

# Get the current line context

324

line = gnureadline.get_line_buffer()

325

begidx = gnureadline.get_begidx()

326

327

# Simple completion logic

328

if '.' in text:

329

# Attribute completion

330

parts = text.split('.')

331

obj_name = '.'.join(parts[:-1])

332

attr_prefix = parts[-1]

333

334

try:

335

obj = eval(obj_name, self.namespace)

336

attrs = [attr for attr in dir(obj)

337

if not attr.startswith('_') and attr.startswith(attr_prefix)]

338

self.matches = [f"{obj_name}.{attr}" for attr in attrs]

339

except:

340

self.matches = []

341

else:

342

# Name completion

343

candidates = []

344

345

# Python keywords

346

candidates.extend(keyword.kwlist)

347

348

# Built-in functions and types

349

candidates.extend(dir(builtins))

350

351

# Names in current namespace

352

candidates.extend(self.namespace.keys())

353

354

# Filter matches

355

self.matches = [name for name in candidates

356

if name.startswith(text) and not name.startswith('_')]

357

358

# Sort matches

359

self.matches.sort()

360

361

try:

362

return self.matches[state]

363

except (IndexError, AttributeError):

364

return None

365

366

def update_namespace(self, new_namespace: dict):

367

"""Update the completion namespace."""

368

self.namespace.update(new_namespace)

369

370

# Example usage in a Python REPL

371

python_completer = PythonCompleter()

372

gnureadline.set_completer(python_completer.complete)

373

gnureadline.parse_and_bind("tab: complete")

374

375

# For Python code, use different delimiters

376

gnureadline.set_completer_delims(' \t\n`!@#$%^&*()=+[{]}\\|;:\'",<>?/')

377

378

# Update namespace as variables are defined

379

python_completer.update_namespace({'my_variable': 42, 'my_function': lambda x: x})

380

```

381

382

## Completion Display Customization

383

384

For advanced completion display options, see the [Hook Functions](./hooks.md) documentation, specifically the `set_completion_display_matches_hook` function which allows customization of how completion matches are presented to the user.