or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

editor-commands.mdeditor-core.mdeditor-factory.mdextension-system.mdindex.mdlanguage-support.mdmime-type-service.mdsearch-replace.mdspecial-extensions.mdtheme-system.md
tile.json

editor-commands.mddocs/

0

# Editor Commands

1

2

Custom command functions for editor interactions, keyboard shortcuts, and special behaviors in JupyterLab context.

3

4

## Capabilities

5

6

### StateCommands Namespace

7

8

Collection of editor state commands designed for JupyterLab integration and context-aware behavior.

9

10

```typescript { .api }

11

/**

12

* CodeMirror commands namespace

13

* Provides context-aware editor commands for JupyterLab integration

14

*/

15

namespace StateCommands {

16

/**

17

* Indent or insert a tab as appropriate, with completer awareness

18

*/

19

function indentMoreOrInsertTab(target: CommandTarget): boolean;

20

21

/**

22

* Insert new line if completer is not active

23

*/

24

function completerOrInsertNewLine(target: CommandTarget): boolean;

25

26

/**

27

* Prevent insertion of new line when running cell with Ctrl/Command + Enter (deprecated)

28

*/

29

function preventNewLineOnRun(target: { dom: HTMLElement }): boolean;

30

31

/**

32

* Insert a new line or run a cell with Ctrl/Command + Enter

33

*/

34

function insertBlankLineOnRun(target: CommandTarget): boolean;

35

36

/**

37

* Simplify selection but do not prevent default to allow switching to command mode

38

*/

39

function simplifySelectionAndMaybeSwitchToCommandMode(target: CommandTarget): boolean;

40

41

/**

42

* Prevent dedenting when launching inspection request (tooltip)

43

*/

44

function dedentIfNotLaunchingTooltip(target: CommandTarget): boolean;

45

}

46

47

/**

48

* Command target interface for state commands

49

*/

50

interface CommandTarget {

51

dom: HTMLElement;

52

state: EditorState;

53

dispatch: (transaction: Transaction) => void;

54

}

55

```

56

57

**Usage Examples:**

58

59

```typescript

60

import { StateCommands } from "@jupyterlab/codemirror";

61

import { keymap } from "@codemirror/view";

62

63

// Create keymap with JupyterLab-aware commands

64

const jupyterLabKeymap = keymap.of([

65

{

66

key: "Tab",

67

run: StateCommands.indentMoreOrInsertTab

68

},

69

{

70

key: "Enter",

71

run: StateCommands.completerOrInsertNewLine

72

},

73

{

74

key: "Ctrl-Enter",

75

run: StateCommands.insertBlankLineOnRun

76

},

77

{

78

key: "Escape",

79

run: StateCommands.simplifySelectionAndMaybeSwitchToCommandMode

80

},

81

{

82

key: "Shift-Tab",

83

run: StateCommands.dedentIfNotLaunchingTooltip

84

}

85

]);

86

87

// Use in editor configuration

88

const editor = new EditorView({

89

extensions: [

90

jupyterLabKeymap,

91

// ... other extensions

92

]

93

});

94

```

95

96

### Indent and Tab Commands

97

98

Smart indentation and tab handling with context awareness.

99

100

```typescript { .api }

101

/**

102

* Indent or insert a tab as appropriate

103

* Handles completer state and selection context

104

*/

105

function indentMoreOrInsertTab(target: CommandTarget): boolean;

106

```

107

108

**Behavior:**

109

- When completer is enabled but not at line beginning: returns false (allows completer)

110

- When text is selected: performs indentation

111

- When cursor is at beginning of line or in whitespace: performs indentation

112

- Otherwise: inserts tab character

113

114

**Usage Example:**

115

116

```typescript

117

// Manual command execution

118

const result = StateCommands.indentMoreOrInsertTab({

119

dom: editor.dom,

120

state: editor.state,

121

dispatch: editor.dispatch

122

});

123

124

if (result) {

125

console.log("Command handled indentation/tab");

126

} else {

127

console.log("Command deferred to other handlers");

128

}

129

```

130

131

### Newline and Enter Commands

132

133

Context-aware newline insertion with completer and cell runner integration.

134

135

```typescript { .api }

136

/**

137

* Insert new line if completer is not active

138

* Integrates with JupyterLab completer and cell execution

139

*/

140

function completerOrInsertNewLine(target: CommandTarget): boolean;

141

142

/**

143

* Insert a new line or run a cell with Ctrl/Command + Enter

144

*/

145

function insertBlankLineOnRun(target: CommandTarget): boolean;

146

```

147

148

**Behavior:**

149

- `completerOrInsertNewLine`: Defers to completer when active, otherwise inserts newline

150

- `insertBlankLineOnRun`: Defers to cell runner when in code runner context, otherwise inserts blank line

151

152

**Usage Examples:**

153

154

```typescript

155

// Configure Enter key behavior

156

const enterKeyBinding = {

157

key: "Enter",

158

run: StateCommands.completerOrInsertNewLine

159

};

160

161

// Configure Ctrl+Enter for cell execution

162

const ctrlEnterBinding = {

163

key: "Ctrl-Enter",

164

run: StateCommands.insertBlankLineOnRun

165

};

166

167

// Use in keymap

168

const keymap = keymap.of([enterKeyBinding, ctrlEnterBinding]);

169

```

170

171

### Selection and Navigation Commands

172

173

Commands for managing selections and editor navigation in JupyterLab context.

174

175

```typescript { .api }

176

/**

177

* Simplify selection but do not prevent default to allow switching to command mode

178

* Enables JupyterLab notebook cell mode switching

179

*/

180

function simplifySelectionAndMaybeSwitchToCommandMode(target: CommandTarget): boolean;

181

182

/**

183

* Prevent dedenting when launching inspection request (tooltip)

184

* Avoids interference with Shift+Tab tooltip functionality

185

*/

186

function dedentIfNotLaunchingTooltip(target: CommandTarget): boolean;

187

```

188

189

**Behavior:**

190

- `simplifySelectionAndMaybeSwitchToCommandMode`: Simplifies selection, allows notebook command mode switching

191

- `dedentIfNotLaunchingTooltip`: Only dedents if not in tooltip-capable context

192

193

### Context Detection

194

195

The commands use CSS selectors to detect JupyterLab context and adjust behavior accordingly.

196

197

```typescript

198

// Selectors used by commands for context detection

199

const CODE_RUNNER_SELECTOR = '[data-jp-code-runner]';

200

const TERMINAL_CODE_RUNNER_SELECTOR = '[data-jp-interaction-mode="terminal"]';

201

const TOOLTIP_OPENER_SELECTOR = '.jp-CodeMirrorEditor:not(.jp-mod-has-primary-selection):not(.jp-mod-in-leading-whitespace):not(.jp-mod-completer-active)';

202

const ACTIVE_CELL_IN_EDIT_MODE_SELECTOR = '.jp-mod-editMode .jp-Cell.jp-mod-active';

203

204

// Commands check these contexts to determine appropriate behavior

205

function contextAwareCommand(target: CommandTarget): boolean {

206

const element = target.dom;

207

208

// Check if in code runner context

209

if (element.closest(CODE_RUNNER_SELECTOR)) {

210

// Defer to code runner

211

return false;

212

}

213

214

// Check if in terminal mode

215

if (element.closest(TERMINAL_CODE_RUNNER_SELECTOR)) {

216

// Handle terminal-specific behavior

217

return handleTerminalMode(target);

218

}

219

220

// Default editor behavior

221

return handleDefaultMode(target);

222

}

223

```

224

225

### Custom Command Creation

226

227

Creating custom commands that integrate with JupyterLab's command system.

228

229

```typescript

230

import { StateCommands } from "@jupyterlab/codemirror";

231

import { EditorState, Transaction } from "@codemirror/state";

232

233

// Create custom command with JupyterLab awareness

234

function customJupyterLabCommand(target: CommandTarget): boolean {

235

const { dom, state, dispatch } = target;

236

237

// Check JupyterLab context

238

const isInNotebook = dom.closest('.jp-Notebook');

239

const isInConsole = dom.closest('.jp-CodeConsole');

240

const isReadOnly = state.readOnly;

241

242

if (isReadOnly) {

243

return false; // Don't handle read-only editors

244

}

245

246

if (isInNotebook) {

247

// Notebook-specific behavior

248

return handleNotebookCommand(target);

249

} else if (isInConsole) {

250

// Console-specific behavior

251

return handleConsoleCommand(target);

252

} else {

253

// File editor behavior

254

return handleFileEditorCommand(target);

255

}

256

}

257

258

function handleNotebookCommand(target: CommandTarget): boolean {

259

// Custom notebook cell command logic

260

const { state, dispatch } = target;

261

262

// Example: Auto-complete imports in Python cells

263

const selection = state.selection.main;

264

const line = state.doc.lineAt(selection.head);

265

const lineText = line.text;

266

267

if (lineText.startsWith('import ') && selection.head === line.to) {

268

// Auto-complete common imports

269

const completion = '\nfrom typing import List, Dict, Optional';

270

dispatch(state.update({

271

changes: { from: selection.head, insert: completion },

272

selection: { anchor: selection.head + completion.length }

273

}));

274

return true;

275

}

276

277

return false;

278

}

279

280

// Register custom command in keymap

281

const customKeymap = keymap.of([

282

{

283

key: "Ctrl-Alt-i",

284

run: customJupyterLabCommand

285

}

286

]);

287

```

288

289

### Advanced Command Patterns

290

291

Complex command scenarios and command composition.

292

293

```typescript

294

// Compose multiple commands

295

function compositeCommand(...commands: Array<(target: CommandTarget) => boolean>) {

296

return (target: CommandTarget): boolean => {

297

for (const command of commands) {

298

if (command(target)) {

299

return true; // First successful command wins

300

}

301

}

302

return false; // No command handled the input

303

};

304

}

305

306

// Create fallback command chain

307

const smartIndentCommand = compositeCommand(

308

StateCommands.indentMoreOrInsertTab,

309

(target) => {

310

// Fallback: always insert 2 spaces

311

target.dispatch(target.state.update({

312

changes: { from: target.state.selection.main.head, insert: " " },

313

selection: { anchor: target.state.selection.main.head + 2 }

314

}));

315

return true;

316

}

317

);

318

319

// Conditional command execution

320

function conditionalCommand(

321

condition: (target: CommandTarget) => boolean,

322

trueCommand: (target: CommandTarget) => boolean,

323

falseCommand?: (target: CommandTarget) => boolean

324

) {

325

return (target: CommandTarget): boolean => {

326

if (condition(target)) {

327

return trueCommand(target);

328

} else if (falseCommand) {

329

return falseCommand(target);

330

}

331

return false;

332

};

333

}

334

335

// Use conditional command

336

const contextSensitiveEnter = conditionalCommand(

337

(target) => target.dom.closest('.jp-CodeConsole') !== null,

338

StateCommands.insertBlankLineOnRun, // Console: run command

339

StateCommands.completerOrInsertNewLine // Notebook: handle completer

340

);

341

```

342

343

### Integration with Editor

344

345

Using commands within the editor configuration and extension system.

346

347

```typescript

348

import { StateCommands } from "@jupyterlab/codemirror";

349

import { CodeMirrorEditor } from "@jupyterlab/codemirror";

350

import { keymap } from "@codemirror/view";

351

352

// Create editor with JupyterLab commands

353

const editor = new CodeMirrorEditor({

354

model,

355

host,

356

extensions: [

357

keymap.of([

358

{ key: "Tab", run: StateCommands.indentMoreOrInsertTab },

359

{ key: "Enter", run: StateCommands.completerOrInsertNewLine },

360

{ key: "Ctrl-Enter", run: StateCommands.insertBlankLineOnRun },

361

{ key: "Escape", run: StateCommands.simplifySelectionAndMaybeSwitchToCommandMode },

362

{ key: "Shift-Tab", run: StateCommands.dedentIfNotLaunchingTooltip }

363

])

364

]

365

});

366

367

// Execute commands programmatically

368

editor.execCommand(StateCommands.indentMoreOrInsertTab);

369

370

// Create command-based extension

371

function jupyterLabCommandsExtension() {

372

return keymap.of([

373

{ key: "Tab", run: StateCommands.indentMoreOrInsertTab },

374

{ key: "Enter", run: StateCommands.completerOrInsertNewLine },

375

{ key: "Ctrl-Enter", run: StateCommands.insertBlankLineOnRun },

376

{ key: "Escape", run: StateCommands.simplifySelectionAndMaybeSwitchToCommandMode },

377

{ key: "Shift-Tab", run: StateCommands.dedentIfNotLaunchingTooltip }

378

]);

379

}

380

```

381

382

## Types

383

384

```typescript { .api }

385

interface CommandTarget {

386

dom: HTMLElement;

387

state: EditorState;

388

dispatch: (transaction: Transaction) => void;

389

}

390

391

type StateCommand = (target: CommandTarget) => boolean;

392

393

namespace StateCommands {

394

function indentMoreOrInsertTab(target: CommandTarget): boolean;

395

function completerOrInsertNewLine(target: CommandTarget): boolean;

396

function preventNewLineOnRun(target: { dom: HTMLElement }): boolean;

397

function insertBlankLineOnRun(target: CommandTarget): boolean;

398

function simplifySelectionAndMaybeSwitchToCommandMode(target: CommandTarget): boolean;

399

function dedentIfNotLaunchingTooltip(target: CommandTarget): boolean;

400

}

401

```