or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-system.mdindex.mdplugin-development.mdserver-management.mdutilities-helpers.mdworkspace-management.md

utilities-helpers.mddocs/

0

# Utilities and Helpers

1

2

Comprehensive utility functions for LSP operations, text manipulation, URI handling, Python-specific operations, and code formatting. Provides essential helper functions for plugin development and server operations.

3

4

## Capabilities

5

6

### Decorators and Function Control

7

8

Utility decorators for controlling function execution timing and frequency.

9

10

```python { .api }

11

def debounce(interval_s, keyed_by=None):

12

"""

13

Debounce function calls until interval_s seconds have passed.

14

15

Parameters:

16

- interval_s: float, debounce interval in seconds

17

- keyed_by: str, parameter name to key debouncing by

18

19

Returns:

20

decorator: Function decorator

21

"""

22

23

def throttle(seconds=1):

24

"""

25

Throttle function calls to at most once per interval.

26

27

Parameters:

28

- seconds: float, minimum interval between calls

29

30

Returns:

31

decorator: Function decorator

32

"""

33

```

34

35

### File and Path Utilities

36

37

Functions for finding and manipulating file paths.

38

39

```python { .api }

40

def find_parents(root, path, names):

41

"""

42

Find files matching names in parent directories.

43

44

Parameters:

45

- root: str, root directory to stop searching at

46

- path: str, starting path for search

47

- names: list, file/directory names to find

48

49

Returns:

50

list: Found file paths

51

"""

52

53

def path_to_dot_name(path):

54

"""

55

Convert filesystem path to Python dot notation.

56

57

Parameters:

58

- path: str, filesystem path to Python file

59

60

Returns:

61

str: Python module path in dot notation

62

"""

63

64

def match_uri_to_workspace(uri, workspaces):

65

"""

66

Match URI to appropriate workspace.

67

68

Parameters:

69

- uri: str, document URI

70

- workspaces: list, available Workspace instances

71

72

Returns:

73

Workspace: Best matching workspace

74

"""

75

```

76

77

### Data Manipulation Utilities

78

79

Functions for working with data structures and strings.

80

81

```python { .api }

82

def list_to_string(value):

83

"""

84

Convert list to comma-separated string.

85

86

Parameters:

87

- value: list or str, value to convert

88

89

Returns:

90

str: Comma-separated string

91

"""

92

93

def merge_dicts(dict_a, dict_b):

94

"""

95

Recursively merge dictionaries.

96

97

Parameters:

98

- dict_a: dict, base dictionary

99

- dict_b: dict, dictionary to merge in

100

101

Returns:

102

dict: Merged dictionary

103

"""

104

```

105

106

### Text and Content Formatting

107

108

Functions for formatting text content for LSP clients.

109

110

```python { .api }

111

def escape_plain_text(contents):

112

"""

113

Escape text for plain text display.

114

115

Parameters:

116

- contents: str, text to escape

117

118

Returns:

119

str: Escaped text

120

"""

121

122

def escape_markdown(contents):

123

"""

124

Escape text for Markdown display.

125

126

Parameters:

127

- contents: str, text to escape

128

129

Returns:

130

str: Escaped Markdown text

131

"""

132

133

def wrap_signature(signature):

134

"""

135

Wrap function signature in code block.

136

137

Parameters:

138

- signature: str, function signature

139

140

Returns:

141

str: Wrapped signature

142

"""

143

144

def choose_markup_kind(client_supported_markup_kinds):

145

"""

146

Choose best supported markup kind for client.

147

148

Parameters:

149

- client_supported_markup_kinds: list, client-supported markup kinds

150

151

Returns:

152

str: Best markup kind to use

153

"""

154

155

def format_docstring(contents, markup_kind, signatures=None, signature_config=None):

156

"""

157

Format docstring as LSP MarkupContent.

158

159

Parameters:

160

- contents: str, docstring content

161

- markup_kind: str, markup kind ("plaintext" or "markdown")

162

- signatures: list, optional function signatures

163

- signature_config: dict, signature formatting options

164

165

Returns:

166

dict: LSP MarkupContent with 'kind' and 'value'

167

"""

168

```

169

170

### Position and Text Manipulation

171

172

Functions for working with LSP positions and text coordinates.

173

174

```python { .api }

175

def clip_column(column, lines, line_number):

176

"""

177

Normalize column position within line bounds.

178

179

Parameters:

180

- column: int, column position

181

- lines: list, document lines

182

- line_number: int, line number (0-based)

183

184

Returns:

185

int: Clipped column position

186

"""

187

188

def position_to_jedi_linecolumn(document, position):

189

"""

190

Convert LSP position to Jedi line/column format.

191

192

Parameters:

193

- document: Document, document instance

194

- position: dict, LSP position with 'line' and 'character'

195

196

Returns:

197

tuple: (line, column) for Jedi (1-based line, 0-based column)

198

"""

199

200

def get_eol_chars(text):

201

"""

202

Get end-of-line characters used in text.

203

204

Parameters:

205

- text: str, text to analyze

206

207

Returns:

208

str: EOL characters ("\r\n", "\r", or "\n") or None if none found

209

"""

210

211

def format_signature(signature, config, signature_formatter):

212

"""

213

Format function signature using ruff or black formatter.

214

215

Parameters:

216

- signature: str, function signature to format

217

- config: dict, formatting configuration with line_length

218

- signature_formatter: str, formatter name ("ruff" or "black")

219

220

Returns:

221

str: Formatted signature

222

"""

223

224

def convert_signatures_to_markdown(signatures, config):

225

"""

226

Convert list of signatures to markdown code block.

227

228

Parameters:

229

- signatures: list, function signatures

230

- config: dict, formatting configuration

231

232

Returns:

233

str: Markdown-formatted signatures

234

"""

235

```

236

237

### Process Utilities

238

239

Functions for process management and monitoring.

240

241

```python { .api }

242

def is_process_alive(pid):

243

"""

244

Check if process is still alive.

245

246

Parameters:

247

- pid: int, process ID

248

249

Returns:

250

bool: True if process is alive

251

"""

252

```

253

254

### URI Utilities

255

256

Functions for working with URIs and filesystem paths.

257

258

```python { .api }

259

def urlparse(uri):

260

"""

261

Parse and decode URI parts.

262

263

Parameters:

264

- uri: str, URI to parse

265

266

Returns:

267

tuple: Parsed URI components (scheme, netloc, path, params, query, fragment)

268

"""

269

270

def urlunparse(parts):

271

"""

272

Unparse and encode URI parts.

273

274

Parameters:

275

- parts: tuple, URI components

276

277

Returns:

278

str: Assembled URI

279

"""

280

281

def to_fs_path(uri):

282

"""

283

Convert URI to filesystem path.

284

285

Parameters:

286

- uri: str, file URI

287

288

Returns:

289

str: Filesystem path

290

"""

291

292

def from_fs_path(path):

293

"""

294

Convert filesystem path to URI.

295

296

Parameters:

297

- path: str, filesystem path

298

299

Returns:

300

str: File URI

301

"""

302

303

def uri_with(uri, **parts):

304

"""

305

Return URI with specified parts replaced.

306

307

Parameters:

308

- uri: str, base URI

309

- **parts: URI components to replace

310

311

Returns:

312

str: Modified URI

313

"""

314

```

315

316

### Text Edit Utilities

317

318

Functions for manipulating and applying text edits.

319

320

```python { .api }

321

def get_well_formatted_range(lsp_range):

322

"""

323

Normalize LSP range format.

324

325

Parameters:

326

- lsp_range: dict, LSP range with 'start' and 'end'

327

328

Returns:

329

dict: Normalized range

330

"""

331

332

def get_well_formatted_edit(text_edit):

333

"""

334

Normalize LSP text edit format.

335

336

Parameters:

337

- text_edit: dict, LSP TextEdit

338

339

Returns:

340

dict: Normalized text edit

341

"""

342

343

def compare_text_edits(a, b):

344

"""

345

Compare text edits for sorting.

346

347

Parameters:

348

- a: dict, first text edit

349

- b: dict, second text edit

350

351

Returns:

352

int: Comparison result (-1, 0, 1)

353

"""

354

355

def merge_sort_text_edits(text_edits):

356

"""

357

Sort text edits by position.

358

359

Parameters:

360

- text_edits: list, text edits to sort

361

362

Returns:

363

list: Sorted text edits

364

"""

365

366

def apply_text_edits(doc, text_edits):

367

"""

368

Apply text edits to document.

369

370

Parameters:

371

- doc: Document, document to edit

372

- text_edits: list, text edits to apply

373

374

Returns:

375

str: Document text after applying edits

376

"""

377

```

378

379

### Code Formatters

380

381

Classes for code formatting with different tools.

382

383

```python { .api }

384

class Formatter:

385

"""Base class for code formatters."""

386

387

@property

388

def is_installed(self):

389

"""

390

Check if formatter is available.

391

392

Returns:

393

bool: True if formatter is installed

394

"""

395

396

def format(self, code, line_length=79):

397

"""

398

Format code.

399

400

Parameters:

401

- code: str, code to format

402

- line_length: int, maximum line length

403

404

Returns:

405

str: Formatted code

406

"""

407

408

class RuffFormatter(Formatter):

409

"""Ruff code formatter."""

410

411

class BlackFormatter(Formatter):

412

"""Black code formatter."""

413

```

414

415

### Constants

416

417

Utility constants used throughout the server.

418

419

```python { .api }

420

JEDI_VERSION = "0.19.1" # Jedi library version

421

422

# End-of-line character sequences in preference order

423

EOL_CHARS = ["\r\n", "\r", "\n"]

424

425

# Regex for matching EOL characters

426

EOL_REGEX = re.compile(r"(\r\n|\r|\n)")

427

428

# Markup kinds supported by server

429

SERVER_SUPPORTED_MARKUP_KINDS = {"plaintext", "markdown"}

430

431

# Available formatters

432

formatters = {

433

"ruff": RuffFormatter(),

434

"black": BlackFormatter()

435

}

436

```

437

438

### Exceptions

439

440

Custom exceptions for text editing operations.

441

442

```python { .api }

443

class OverLappingTextEditException(Exception):

444

"""Raised when text edits overlap and cannot be applied."""

445

```

446

447

## Usage Examples

448

449

### Debouncing and Throttling

450

451

```python

452

from pylsp._utils import debounce, throttle

453

454

# Debounce linting to avoid excessive calls

455

@debounce(0.5, keyed_by='document')

456

def run_linting(document):

457

# Linting logic here

458

pass

459

460

# Throttle progress updates

461

@throttle(seconds=1)

462

def update_progress(message):

463

# Progress update logic

464

pass

465

```

466

467

### Path and File Operations

468

469

```python

470

from pylsp._utils import find_parents, path_to_dot_name

471

472

# Find configuration files

473

config_files = find_parents(

474

"/project",

475

"/project/src/module.py",

476

["setup.cfg", "pyproject.toml"]

477

)

478

479

# Convert path to module name

480

module_name = path_to_dot_name("/project/src/utils/helper.py")

481

print(module_name) # "src.utils.helper"

482

```

483

484

### Text Formatting

485

486

```python

487

from pylsp._utils import (

488

format_docstring, escape_markdown, wrap_signature,

489

format_signature, convert_signatures_to_markdown

490

)

491

492

# Format docstring for hover

493

docstring = format_docstring(

494

"Function description\n\nArgs:\n x: parameter",

495

"markdown",

496

signatures=["def func(x: int) -> str"]

497

)

498

499

# Escape markdown content

500

escaped = escape_markdown("Text with *special* chars")

501

502

# Wrap signature

503

wrapped = wrap_signature("def example(param: str) -> int")

504

505

# Format signature with black or ruff

506

config = {"line_length": 88}

507

formatted_sig = format_signature("def func(a,b,c):", config, "black")

508

509

# Convert multiple signatures to markdown

510

sigs = ["def func1(x: int) -> str", "def func2(y: float) -> bool"]

511

markdown_sigs = convert_signatures_to_markdown(sigs, config)

512

```

513

514

### Position Conversion

515

516

```python

517

from pylsp._utils import position_to_jedi_linecolumn, clip_column

518

519

# Convert LSP position to Jedi format

520

lsp_pos = {"line": 5, "character": 10}

521

jedi_line, jedi_col = position_to_jedi_linecolumn(document, lsp_pos)

522

523

# Clip column to line bounds

524

clipped_col = clip_column(100, document.lines, 5) # Won't exceed line length

525

```

526

527

### URI Handling

528

529

```python

530

from pylsp.uris import to_fs_path, from_fs_path, uri_with

531

532

# Convert between URIs and paths

533

path = to_fs_path("file:///project/src/main.py") # "/project/src/main.py"

534

uri = from_fs_path("/project/src/main.py") # "file:///project/src/main.py"

535

536

# Modify URI components

537

new_uri = uri_with("file:///project/old.py", path="/project/new.py")

538

```

539

540

### Text Edits

541

542

```python

543

from pylsp.text_edit import apply_text_edits, merge_sort_text_edits

544

545

# Apply text edits to document

546

edits = [

547

{

548

"range": {

549

"start": {"line": 0, "character": 0},

550

"end": {"line": 0, "character": 5}

551

},

552

"newText": "print"

553

}

554

]

555

556

# Sort edits and apply

557

sorted_edits = merge_sort_text_edits(edits)

558

new_text = apply_text_edits(document, sorted_edits)

559

```

560

561

### Code Formatting

562

563

```python

564

from pylsp._utils import formatters

565

566

# Use available formatters

567

black_formatter = formatters["black"]

568

if black_formatter.is_installed:

569

formatted_code = black_formatter.format("def f():pass", line_length=88)

570

571

ruff_formatter = formatters["ruff"]

572

if ruff_formatter.is_installed:

573

formatted_code = ruff_formatter.format(code, line_length=100)

574

```

575

576

### Data Manipulation

577

578

```python

579

from pylsp._utils import merge_dicts, list_to_string

580

581

# Merge configuration dictionaries

582

base_config = {"plugins": {"pyflakes": {"enabled": True}}}

583

user_config = {"plugins": {"pyflakes": {"ignore": ["E203"]}}}

584

merged = merge_dicts(base_config, user_config)

585

586

# Convert list to string

587

error_codes = ["E203", "W503", "E501"]

588

ignore_string = list_to_string(error_codes) # "E203,W503,E501"

589

```