or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcompletion.mdindex.mdkey-bindings.mdlayout.mdprompts.mdstyling.md

completion.mddocs/

0

# Completion and Validation

1

2

Auto-completion system with built-in completers for files, words, and custom data, plus validation framework for input checking. These systems work together to provide intelligent input assistance and error prevention.

3

4

## Capabilities

5

6

### Base Completion Classes

7

8

Core classes for implementing and managing auto-completion functionality.

9

10

```python { .api }

11

class Completion:

12

def __init__(

13

self,

14

text,

15

start_position=0,

16

display=None,

17

display_meta=None,

18

style="",

19

selected_style=""

20

):

21

"""

22

Single completion result.

23

24

Parameters:

25

- text: str, completion text to insert

26

- start_position: int, position where completion starts (negative offset)

27

- display: str, text to display in completion menu (default: text)

28

- display_meta: str, additional metadata to show

29

- style: str, CSS-like style for completion

30

- selected_style: str, style when completion is selected

31

"""

32

33

class Completer:

34

"""Abstract base class for completers."""

35

36

def get_completions(self, document, complete_event):

37

"""

38

Generate completions for document.

39

40

Parameters:

41

- document: Document instance with current text and cursor

42

- complete_event: CompleteEvent with completion context

43

44

Yields:

45

Completion instances

46

"""

47

48

class CompleteEvent:

49

def __init__(self, text_inserted=False, completion_requested=False):

50

"""

51

Completion event context.

52

53

Parameters:

54

- text_inserted: bool, True if triggered by text insertion

55

- completion_requested: bool, True if explicitly requested (Tab)

56

"""

57

58

class ThreadedCompleter(Completer):

59

def __init__(self, completer):

60

"""

61

Wrapper for running completer in background thread.

62

63

Parameters:

64

- completer: Completer instance to wrap

65

"""

66

67

class DummyCompleter(Completer):

68

"""Dummy completer that returns no completions."""

69

70

def __init__(self):

71

"""Create dummy completer for testing."""

72

73

class DynamicCompleter(Completer):

74

def __init__(self, get_completer):

75

"""

76

Dynamic completer that changes based on function.

77

78

Parameters:

79

- get_completer: Function returning Completer instance

80

"""

81

82

class ConditionalCompleter(Completer):

83

def __init__(self, completer, filter):

84

"""

85

Completer active only when filter is true.

86

87

Parameters:

88

- completer: Completer instance to wrap

89

- filter: Filter determining when completer is active

90

"""

91

92

def merge_completers(completers):

93

"""

94

Merge multiple completers into one.

95

96

Parameters:

97

- completers: List of Completer instances

98

99

Returns:

100

Combined Completer instance

101

"""

102

103

def get_common_complete_suffix(completions):

104

"""

105

Get common suffix of all completions.

106

107

Parameters:

108

- completions: List of Completion instances

109

110

Returns:

111

str: Common suffix or empty string

112

"""

113

```

114

115

### Built-in Completers

116

117

Pre-built completers for common completion scenarios.

118

119

```python { .api }

120

class WordCompleter(Completer):

121

def __init__(

122

self,

123

words,

124

ignore_case=False,

125

meta_dict=None,

126

WORD=False,

127

sentence=False,

128

match_middle=False,

129

pattern=None

130

):

131

"""

132

Completer for static word list.

133

134

Parameters:

135

- words: List of words to complete

136

- ignore_case: bool, case-insensitive matching

137

- meta_dict: Dict mapping words to metadata

138

- WORD: bool, match Vi-style WORD boundaries

139

- sentence: bool, complete sentences instead of words

140

- match_middle: bool, match anywhere in word

141

- pattern: compiled regex pattern for word boundaries

142

"""

143

144

class PathCompleter(Completer):

145

def __init__(

146

self,

147

only_directories=False,

148

get_paths=None,

149

file_filter=None,

150

min_input_len=0,

151

expanduser=False

152

):

153

"""

154

Completer for file and directory paths.

155

156

Parameters:

157

- only_directories: bool, complete only directories

158

- get_paths: Function returning list of paths to search

159

- file_filter: Function to filter files/directories

160

- min_input_len: int, minimum input length before completing

161

- expanduser: bool, expand ~ to user home directory

162

"""

163

164

class ExecutableCompleter(PathCompleter):

165

def __init__(self):

166

"""Completer for executable files in PATH."""

167

168

class NestedCompleter(Completer):

169

def __init__(self, options, ignore_case=True):

170

"""

171

Completer for nested command structures.

172

173

Parameters:

174

- options: Dict defining nested completion structure

175

- ignore_case: bool, case-insensitive matching

176

177

Options format:

178

{

179

'command1': {

180

'subcommand1': None,

181

'subcommand2': {'option1': None, 'option2': None}

182

},

183

'command2': WordCompleter(['arg1', 'arg2'])

184

}

185

"""

186

187

class FuzzyCompleter(Completer):

188

def __init__(self, completer, WORD=False, pattern=None):

189

"""

190

Fuzzy matching wrapper for any completer.

191

192

Parameters:

193

- completer: Completer instance to wrap

194

- WORD: bool, use Vi-style WORD boundaries

195

- pattern: compiled regex for word boundaries

196

"""

197

198

class FuzzyWordCompleter(Completer):

199

def __init__(

200

self,

201

words,

202

meta_dict=None,

203

WORD=False,

204

pattern=None

205

):

206

"""

207

Fuzzy word completer with built-in word list.

208

209

Parameters:

210

- words: List of words for completion

211

- meta_dict: Dict mapping words to metadata

212

- WORD: bool, use Vi-style WORD boundaries

213

- pattern: compiled regex for word boundaries

214

"""

215

216

class DeduplicateCompleter(Completer):

217

def __init__(self, completer):

218

"""

219

Remove duplicate completions from wrapped completer.

220

221

Parameters:

222

- completer: Completer instance to wrap

223

"""

224

```

225

226

### Validation System

227

228

Framework for validating user input with custom validation rules.

229

230

```python { .api }

231

class Validator:

232

"""Abstract base class for input validators."""

233

234

def validate(self, document):

235

"""

236

Validate document content.

237

238

Parameters:

239

- document: Document instance to validate

240

241

Raises:

242

ValidationError: If validation fails

243

"""

244

245

class ValidationError(Exception):

246

def __init__(self, cursor_position=0, message=""):

247

"""

248

Validation error with position and message.

249

250

Parameters:

251

- cursor_position: int, position where error occurred

252

- message: str, error message to display

253

"""

254

255

@property

256

def cursor_position(self):

257

"""int: Position where validation failed."""

258

259

@property

260

def message(self):

261

"""str: Error message."""

262

263

class ThreadedValidator(Validator):

264

def __init__(self, validator):

265

"""

266

Wrapper for running validator in background thread.

267

268

Parameters:

269

- validator: Validator instance to wrap

270

"""

271

272

class ConditionalValidator(Validator):

273

def __init__(self, validator, filter):

274

"""

275

Validator active only when filter is true.

276

277

Parameters:

278

- validator: Validator instance to wrap

279

- filter: Filter determining when validator is active

280

"""

281

282

class DummyValidator(Validator):

283

"""Dummy validator that never fails."""

284

285

def __init__(self):

286

"""Create dummy validator for testing."""

287

288

class DynamicValidator(Validator):

289

def __init__(self, get_validator):

290

"""

291

Dynamic validator that changes based on function.

292

293

Parameters:

294

- get_validator: Function returning Validator instance

295

"""

296

```

297

298

### Completion Style

299

300

Enumeration for controlling how completions are displayed.

301

302

```python { .api }

303

class CompleteStyle(Enum):

304

"""Completion display styles."""

305

COLUMN = "column"

306

MULTI_COLUMN = "multi-column"

307

READLINE_LIKE = "readline-like"

308

```

309

310

### Auto-suggestion

311

312

System for providing auto-suggestions based on history or other sources.

313

314

```python { .api }

315

class AutoSuggest:

316

"""Abstract base class for auto-suggestion."""

317

318

def get_suggestion(self, buffer, document):

319

"""

320

Get suggestion for current input.

321

322

Parameters:

323

- buffer: Buffer instance

324

- document: Document with current text

325

326

Returns:

327

Suggestion instance or None

328

"""

329

330

class AutoSuggestFromHistory(AutoSuggest):

331

def __init__(self):

332

"""Auto-suggest based on command history."""

333

334

class Suggestion:

335

def __init__(self, text):

336

"""

337

Auto-suggestion text.

338

339

Parameters:

340

- text: str, suggested text to append

341

"""

342

343

@property

344

def text(self):

345

"""str: Suggestion text."""

346

```

347

348

## Usage Examples

349

350

### Word Completion

351

352

```python

353

from prompt_toolkit import prompt

354

from prompt_toolkit.completion import WordCompleter

355

356

# Simple word completer

357

words = ['apple', 'banana', 'cherry', 'date', 'elderberry']

358

completer = WordCompleter(words)

359

360

result = prompt('Enter fruit: ', completer=completer)

361

print(f'You chose: {result}')

362

363

# Word completer with metadata

364

meta_dict = {

365

'apple': 'Red or green fruit',

366

'banana': 'Yellow tropical fruit',

367

'cherry': 'Small red fruit',

368

'date': 'Sweet brown fruit',

369

'elderberry': 'Dark purple berry'

370

}

371

372

completer_with_meta = WordCompleter(words, meta_dict=meta_dict)

373

result = prompt('Enter fruit (with descriptions): ', completer=completer_with_meta)

374

```

375

376

### Path Completion

377

378

```python

379

from prompt_toolkit import prompt

380

from prompt_toolkit.completion import PathCompleter

381

382

# File and directory completer

383

path_completer = PathCompleter()

384

file_path = prompt('Enter file path: ', completer=path_completer)

385

386

# Directory-only completer

387

dir_completer = PathCompleter(only_directories=True)

388

directory = prompt('Enter directory: ', completer=dir_completer)

389

390

# Executable completer

391

from prompt_toolkit.completion import ExecutableCompleter

392

exec_completer = ExecutableCompleter()

393

command = prompt('Enter command: ', completer=exec_completer)

394

```

395

396

### Nested Command Completion

397

398

```python

399

from prompt_toolkit import prompt

400

from prompt_toolkit.completion import NestedCompleter, WordCompleter

401

402

# Define nested command structure

403

nested_completer = NestedCompleter({

404

'git': {

405

'add': None,

406

'commit': {

407

'-m': None,

408

'--message': None,

409

'--amend': None

410

},

411

'push': {

412

'origin': WordCompleter(['master', 'main', 'develop']),

413

'upstream': None

414

},

415

'pull': {

416

'origin': WordCompleter(['master', 'main', 'develop'])

417

},

418

'checkout': {

419

'-b': None,

420

'master': None,

421

'main': None,

422

'develop': None

423

}

424

},

425

'docker': {

426

'run': None,

427

'build': None,

428

'ps': None,

429

'images': None,

430

'stop': None,

431

'rm': None

432

}

433

})

434

435

command = prompt('Enter command: ', completer=nested_completer)

436

print(f'Command: {command}')

437

```

438

439

### Fuzzy Completion

440

441

```python

442

from prompt_toolkit import prompt

443

from prompt_toolkit.completion import FuzzyWordCompleter

444

445

# Fuzzy word matching

446

words = [

447

'application', 'authentication', 'authorization',

448

'configuration', 'documentation', 'implementation',

449

'infrastructure', 'internationalization', 'optimization'

450

]

451

452

fuzzy_completer = FuzzyWordCompleter(words)

453

454

# Type partial matches like 'auth' to get 'authentication', 'authorization'

455

result = prompt('Enter term (fuzzy matching): ', completer=fuzzy_completer)

456

```

457

458

### Custom Completer

459

460

```python

461

from prompt_toolkit import prompt

462

from prompt_toolkit.completion import Completer, Completion

463

from prompt_toolkit.document import Document

464

465

class DatabaseTableCompleter(Completer):

466

def __init__(self, database_connection):

467

self.db = database_connection

468

469

def get_completions(self, document, complete_event):

470

# Get word before cursor

471

word = document.get_word_before_cursor()

472

473

# Query database for table names

474

try:

475

tables = self.db.get_table_names()

476

for table in tables:

477

if table.startswith(word.lower()):

478

yield Completion(

479

text=table,

480

start_position=-len(word),

481

display=table,

482

display_meta=f'Table: {table}'

483

)

484

except Exception:

485

# Handle database errors gracefully

486

pass

487

488

# Usage (assuming database connection exists)

489

# db_completer = DatabaseTableCompleter(db_connection)

490

# query = prompt('Enter table name: ', completer=db_completer)

491

```

492

493

### Input Validation

494

495

```python

496

from prompt_toolkit import prompt

497

from prompt_toolkit.validation import Validator, ValidationError

498

import re

499

500

class EmailValidator(Validator):

501

def validate(self, document):

502

text = document.text

503

if not re.match(r'^[^@]+@[^@]+\.[^@]+$', text):

504

raise ValidationError(

505

message='Invalid email format',

506

cursor_position=len(text)

507

)

508

509

class PasswordValidator(Validator):

510

def validate(self, document):

511

text = document.text

512

if len(text) < 8:

513

raise ValidationError(

514

message='Password must be at least 8 characters',

515

cursor_position=len(text)

516

)

517

if not re.search(r'[A-Z]', text):

518

raise ValidationError(

519

message='Password must contain uppercase letter',

520

cursor_position=len(text)

521

)

522

if not re.search(r'[0-9]', text):

523

raise ValidationError(

524

message='Password must contain a number',

525

cursor_position=len(text)

526

)

527

528

# Use validators

529

email = prompt('Email: ', validator=EmailValidator())

530

password = prompt('Password: ', password=True, validator=PasswordValidator())

531

```

532

533

### Completion with Validation

534

535

```python

536

from prompt_toolkit import prompt

537

from prompt_toolkit.completion import WordCompleter

538

from prompt_toolkit.validation import Validator, ValidationError

539

540

# Valid countries list

541

countries = ['USA', 'Canada', 'Mexico', 'Germany', 'France', 'Japan', 'Australia']

542

543

class CountryValidator(Validator):

544

def validate(self, document):

545

text = document.text

546

if text and text not in countries:

547

raise ValidationError(

548

message=f'"{text}" is not a valid country',

549

cursor_position=len(text)

550

)

551

552

# Combine completion and validation

553

country_completer = WordCompleter(countries, ignore_case=True)

554

country_validator = CountryValidator()

555

556

country = prompt(

557

'Enter country: ',

558

completer=country_completer,

559

validator=country_validator

560

)

561

print(f'Selected country: {country}')

562

```

563

564

### Dynamic Completion

565

566

```python

567

from prompt_toolkit import prompt

568

from prompt_toolkit.completion import DynamicCompleter, WordCompleter

569

570

# Different completion sets

571

programming_languages = ['python', 'javascript', 'java', 'c++', 'go']

572

frameworks = ['django', 'flask', 'react', 'vue', 'angular']

573

574

# Function to select completer based on context

575

def get_completer():

576

# This could be based on application state, user input, etc.

577

if current_mode == 'languages':

578

return WordCompleter(programming_languages)

579

elif current_mode == 'frameworks':

580

return WordCompleter(frameworks)

581

else:

582

return WordCompleter([])

583

584

# Use dynamic completer

585

dynamic_completer = DynamicCompleter(get_completer)

586

587

# Set mode and prompt

588

current_mode = 'languages'

589

language = prompt('Programming language: ', completer=dynamic_completer)

590

591

current_mode = 'frameworks'

592

framework = prompt('Framework: ', completer=dynamic_completer)

593

```

594

595

### Auto-suggestion with History

596

597

```python

598

from prompt_toolkit import PromptSession

599

from prompt_toolkit.history import FileHistory

600

from prompt_toolkit.auto_suggest import AutoSuggestFromHistory

601

from prompt_toolkit.completion import WordCompleter

602

603

# Create session with history and auto-suggestions

604

session = PromptSession(

605

history=FileHistory('.command_history'),

606

auto_suggest=AutoSuggestFromHistory(),

607

completer=WordCompleter(['help', 'exit', 'status', 'config'])

608

)

609

610

print("Type commands. Previous commands will be suggested in gray.")

611

print("Press Ctrl-C to exit.")

612

613

while True:

614

try:

615

command = session.prompt('> ')

616

if command.lower() == 'exit':

617

break

618

print(f'Executing: {command}')

619

except (EOFError, KeyboardInterrupt):

620

break

621

```

622

623

### Threaded Completion for Slow Operations

624

625

```python

626

from prompt_toolkit import prompt

627

from prompt_toolkit.completion import ThreadedCompleter, Completer, Completion

628

import time

629

630

class SlowCompleter(Completer):

631

"""Completer that simulates slow operations like network requests."""

632

633

def get_completions(self, document, complete_event):

634

word = document.get_word_before_cursor()

635

636

# Simulate slow operation (e.g., API call)

637

time.sleep(0.5)

638

639

# Generate completions

640

options = ['slow_option_1', 'slow_option_2', 'slow_option_3']

641

for option in options:

642

if option.startswith(word):

643

yield Completion(

644

text=option,

645

start_position=-len(word),

646

display_meta='From slow API'

647

)

648

649

# Wrap in ThreadedCompleter to avoid blocking UI

650

threaded_completer = ThreadedCompleter(SlowCompleter())

651

652

result = prompt('Enter option (completions load in background): ',

653

completer=threaded_completer)

654

```