0
# Tab Completion
1
2
Comprehensive tab completion system with customizable completion functions, delimiter configuration, and completion context access. These functions enable sophisticated autocompletion behavior for interactive command-line applications.
3
4
## Capabilities
5
6
### Completion Function Management
7
8
Functions for setting up and managing custom completion behavior, allowing applications to provide context-aware autocompletion.
9
10
```python { .api }
11
def set_completer(function=None):
12
"""
13
Set or remove the completer function.
14
15
Parameters:
16
- function (callable, optional): Completer function called as function(text, state)
17
for state in 0, 1, 2, ... until it returns None.
18
If None, removes current completer.
19
20
Returns:
21
None
22
"""
23
24
def get_completer():
25
"""
26
Return current completer function.
27
28
Returns:
29
callable or None: Current completer function, or None if no completer is set
30
"""
31
```
32
33
**Usage Example:**
34
35
```python
36
import readline
37
import os
38
import glob
39
40
def file_completer(text, state):
41
"""Simple file completion example"""
42
# Get all files/directories that start with text
43
matches = glob.glob(text + '*')
44
45
# Add trailing slash to directories
46
matches = [match + '/' if os.path.isdir(match) else match for match in matches]
47
48
# Return the match for this state, or None when exhausted
49
return matches[state] if state < len(matches) else None
50
51
# Set the completer
52
readline.set_completer(file_completer)
53
54
# Enable tab completion
55
readline.parse_and_bind('tab: complete')
56
57
# Check current completer
58
current_completer = readline.get_completer()
59
print(f"Current completer: {current_completer}")
60
61
# Remove completer
62
readline.set_completer(None)
63
```
64
65
### Advanced Completion Example
66
67
```python
68
import readline
69
import keyword
70
import builtins
71
72
class PythonCompleter:
73
def __init__(self):
74
self.matches = []
75
76
def complete(self, text, state):
77
"""Complete Python keywords, builtins, and local variables"""
78
if state == 0: # First call, generate matches
79
self.matches = []
80
81
# Add Python keywords
82
self.matches.extend([kw for kw in keyword.kwlist if kw.startswith(text)])
83
84
# Add built-in functions
85
self.matches.extend([name for name in dir(builtins) if name.startswith(text)])
86
87
# Add local variables (simplified)
88
import __main__
89
if hasattr(__main__, '__dict__'):
90
local_vars = [name for name in __main__.__dict__.keys()
91
if name.startswith(text) and not name.startswith('_')]
92
self.matches.extend(local_vars)
93
94
return self.matches[state] if state < len(self.matches) else None
95
96
# Set up Python completion
97
python_completer = PythonCompleter()
98
readline.set_completer(python_completer.complete)
99
```
100
101
### Completion Context Access
102
103
Functions for accessing information about the current completion attempt, enabling context-sensitive completion behavior.
104
105
```python { .api }
106
def get_completion_type():
107
"""
108
Get the type of completion being attempted.
109
110
Returns:
111
int: Completion type code indicating the kind of completion
112
"""
113
114
def get_begidx():
115
"""
116
Get the beginning index of the readline tab-completion scope.
117
118
Returns:
119
int: Starting index of text being completed within the line buffer
120
"""
121
122
def get_endidx():
123
"""
124
Get the ending index of the readline tab-completion scope.
125
126
Returns:
127
int: Ending index of text being completed within the line buffer
128
"""
129
```
130
131
**Usage Example:**
132
133
```python
134
import readline
135
136
def context_aware_completer(text, state):
137
"""Completer that uses completion context"""
138
if state == 0: # First call, analyze context
139
# Get completion boundaries
140
begidx = readline.get_begidx()
141
endidx = readline.get_endidx()
142
143
# Get the full line being edited
144
line_buffer = readline.get_line_buffer()
145
146
# Extract the word being completed and its context
147
before_cursor = line_buffer[:begidx]
148
completion_text = line_buffer[begidx:endidx]
149
150
print(f"\nCompletion context:")
151
print(f" Line: '{line_buffer}'")
152
print(f" Before cursor: '{before_cursor}'")
153
print(f" Completing: '{completion_text}'")
154
print(f" Indexes: {begidx}-{endidx}")
155
print(f" Completion type: {readline.get_completion_type()}")
156
157
# Simple completion for demonstration
158
options = ['hello', 'help', 'history', 'home']
159
matches = [opt for opt in options if opt.startswith(text)]
160
return matches[state] if state < len(matches) else None
161
162
readline.set_completer(context_aware_completer)
163
```
164
165
### Completion Delimiter Configuration
166
167
Functions for controlling which characters are treated as word boundaries during tab completion.
168
169
```python { .api }
170
def set_completer_delims(string):
171
"""
172
Set the readline word delimiters for tab-completion.
173
174
Parameters:
175
- string (str): Characters to treat as word delimiters
176
177
Returns:
178
None
179
"""
180
181
def get_completer_delims():
182
"""
183
Get the readline word delimiters for tab-completion.
184
185
Returns:
186
str: Current word delimiter characters
187
"""
188
```
189
190
**Usage Example:**
191
192
```python
193
import readline
194
195
# Check current delimiters
196
current_delims = readline.get_completer_delims()
197
print(f"Current delimiters: '{current_delims}'")
198
199
# Set custom delimiters (default is usually ' \t\n`@$><=;|&{(')
200
readline.set_completer_delims(' \t\n') # Only space, tab, and newline
201
202
# For file path completion, you might want to exclude '/' and '.'
203
readline.set_completer_delims(' \t\n=')
204
205
# For programming language completion, include more programming symbols
206
readline.set_completer_delims(' \t\n`@$><=;|&{()}[].,')
207
```
208
209
## Advanced Completion Patterns
210
211
### Command-Specific Completion
212
213
```python
214
import readline
215
import os
216
import subprocess
217
218
class CommandCompleter:
219
def __init__(self):
220
self.commands = {
221
'cd': self._complete_directories,
222
'ls': self._complete_files,
223
'python': self._complete_python_files,
224
'git': self._complete_git_commands,
225
}
226
227
def complete(self, text, state):
228
line_buffer = readline.get_line_buffer()
229
words = line_buffer.split()
230
231
if not words:
232
return None
233
234
command = words[0]
235
if command in self.commands:
236
return self.commands[command](text, state, words)
237
238
# Default file completion
239
return self._complete_files(text, state, words)
240
241
def _complete_directories(self, text, state, words):
242
"""Complete only directories for cd command"""
243
import glob
244
matches = [d for d in glob.glob(text + '*') if os.path.isdir(d)]
245
matches = [d + '/' for d in matches] # Add trailing slash
246
return matches[state] if state < len(matches) else None
247
248
def _complete_files(self, text, state, words):
249
"""Complete files and directories"""
250
import glob
251
matches = glob.glob(text + '*')
252
matches = [m + '/' if os.path.isdir(m) else m for m in matches]
253
return matches[state] if state < len(matches) else None
254
255
def _complete_python_files(self, text, state, words):
256
"""Complete .py files"""
257
import glob
258
matches = glob.glob(text + '*.py')
259
return matches[state] if state < len(matches) else None
260
261
def _complete_git_commands(self, text, state, words):
262
"""Complete git subcommands"""
263
if len(words) == 1: # Completing git subcommand
264
git_commands = ['add', 'commit', 'push', 'pull', 'status', 'log', 'diff', 'branch']
265
matches = [cmd for cmd in git_commands if cmd.startswith(text)]
266
return matches[state] if state < len(matches) else None
267
return None
268
269
# Set up command-specific completion
270
command_completer = CommandCompleter()
271
readline.set_completer(command_completer.complete)
272
```
273
274
### Multi-Level Completion
275
276
```python
277
import readline
278
279
class HierarchicalCompleter:
280
def __init__(self):
281
self.completions = {
282
'show': {
283
'interface': ['eth0', 'eth1', 'lo', 'wlan0'],
284
'route': ['default', 'table', 'all'],
285
'ip': ['route', 'addr', 'link'],
286
},
287
'set': {
288
'interface': ['eth0', 'eth1', 'wlan0'],
289
'route': ['add', 'del', 'change'],
290
}
291
}
292
293
def complete(self, text, state):
294
line_buffer = readline.get_line_buffer()
295
words = line_buffer.split()
296
297
if not words:
298
return None
299
300
# Navigate through completion hierarchy
301
current_level = self.completions
302
for word in words[:-1]: # All words except the one being completed
303
if word in current_level and isinstance(current_level[word], dict):
304
current_level = current_level[word]
305
else:
306
return None
307
308
# Get matches at current level
309
if isinstance(current_level, dict):
310
matches = [key for key in current_level.keys() if key.startswith(text)]
311
elif isinstance(current_level, list):
312
matches = [item for item in current_level if item.startswith(text)]
313
else:
314
matches = []
315
316
return matches[state] if state < len(matches) else None
317
318
# Set up hierarchical completion
319
hierarchical_completer = HierarchicalCompleter()
320
readline.set_completer(hierarchical_completer.complete)
321
```