@adecore/editor 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/engine.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { changedSpans, DocumentModel, replacementText } from '@adecore/editor-core';
2
2
  import { MAX_REPLACEMENT_CHARACTERS } from './search-protocol.js';
3
+ import { placeAt, postfixOperands, surroundShape, unwrapTargets } from './text-queries.js';
3
4
  import { GrammarPreparation } from './grammar-preparation.js';
4
5
  import { InputController } from './controller.js';
5
6
  import { resolveSmartKeys } from './smart-keys.js';
@@ -784,6 +785,19 @@ class SmartEditor {
784
785
  isReadOnly() {
785
786
  return this.settings.readOnly;
786
787
  }
788
+ placeAt(position) {
789
+ return placeAt(this.model, this, position, this.settings.language ?? 'plaintext');
790
+ }
791
+ postfixOperands(dot) {
792
+ return postfixOperands(this.model, this, dot, this.settings.language ?? 'plaintext');
793
+ }
794
+ surroundShape(range) {
795
+ return surroundShape(this.model, this, range, this.settings.language ?? 'plaintext');
796
+ }
797
+ unwrapTargets(position) {
798
+ const unit = this.settings.insertSpaces ? ' '.repeat(this.settings.tabSize) : '\t';
799
+ return unwrapTargets(this.model, this, position, this.settings.language ?? 'plaintext', unit);
800
+ }
787
801
  runCommand(command) {
788
802
  return this.controller.command(command);
789
803
  }
package/dist/fake.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorReplacement, EditorLineHighlight, LineToken, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorInputPopup, EditorMarker, EditorMessages, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorApplyEditsOptions, EditorCopy, EditorPasteOptions, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWhitespaceCleanup, EditorWidget } from './types.ts';
1
+ import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorReplacement, EditorLineHighlight, LineToken, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorInputPopup, EditorMarker, EditorMessages, EditorOptions, EditorPosition, EditorPostfixOperand, EditorSurroundShape, EditorTextPlace, EditorUnwrapTarget, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorApplyEditsOptions, EditorCopy, EditorPasteOptions, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWhitespaceCleanup, EditorWidget } from './types.ts';
2
2
  import { type Listener } from './listeners.ts';
3
3
  export declare class FakeEditor implements Editor {
4
4
  readonly element: HTMLElement;
@@ -257,6 +257,10 @@ export declare class FakeEditor implements Editor {
257
257
  zoomTo(size: number | null): void;
258
258
  setReadOnly(readOnly: boolean, reason?: string): void;
259
259
  isReadOnly(): boolean;
260
+ placeAt(position: EditorPosition): EditorTextPlace;
261
+ postfixOperands(dot: EditorPosition): readonly EditorPostfixOperand[];
262
+ surroundShape(range: EditorRange): EditorSurroundShape | null;
263
+ unwrapTargets(position: EditorPosition): readonly EditorUnwrapTarget[];
260
264
  readonly commands: EditorRunCommand[];
261
265
  runCommand(command: EditorRunCommand): boolean;
262
266
  focus(): void;
package/dist/fake.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { emit, subscribe } from './listeners.js';
2
- import { changedSpan, changedSpans } from '@adecore/editor-core';
2
+ import { changedSpan, changedSpans, DocumentModel } from '@adecore/editor-core';
3
+ import { placeAt, postfixOperands, surroundShape, unwrapTargets } from './text-queries.js';
3
4
  import { mapTrackedRange } from './tracked-range.js';
4
5
  const LINE_BREAK = /\r\n|\r|\n/g;
5
6
  /* Where each line starts and where its text ends, before its line break: `\r\n`, a lone `\r` or `\n`, as the real document counts them. */
@@ -918,6 +919,19 @@ export class FakeEditor {
918
919
  isReadOnly() {
919
920
  return this.readOnly;
920
921
  }
922
+ placeAt(position) {
923
+ return placeAt(new DocumentModel(this.text), this, position, this.language ?? 'plaintext');
924
+ }
925
+ postfixOperands(dot) {
926
+ return postfixOperands(new DocumentModel(this.text), this, dot, this.language ?? 'plaintext');
927
+ }
928
+ surroundShape(range) {
929
+ return surroundShape(new DocumentModel(this.text), this, range, this.language ?? 'plaintext');
930
+ }
931
+ unwrapTargets(position) {
932
+ const unit = this.indentation.insertSpaces ? ' '.repeat(this.indentation.tabSize) : '\t';
933
+ return unwrapTargets(new DocumentModel(this.text), this, position, this.language ?? 'plaintext', unit);
934
+ }
921
935
  /* The commands run, in order; of its own the fake carries out only undo and redo. */
922
936
  commands = [];
923
937
  runCommand(command) {
package/dist/index.d.ts CHANGED
@@ -3,8 +3,9 @@ export { AGENT_COLORS } from './attribution.ts';
3
3
  export { findDocComments, MAX_DOC_COMMENTS, type DocComment } from '@adecore/editor-core';
4
4
  export { DEFAULT_TODO_WORDS, findTodos, type TodoMatch, type TodoOptions } from '@adecore/editor-core';
5
5
  export { detectIndentation, type DetectedIndentation } from '@adecore/editor-core';
6
+ export { commentSyntax, type CommentSyntax } from '@adecore/editor-core';
6
7
  export { createSmartEditorEngine } from './engine.ts';
7
8
  export { rememberCopy } from './controller.ts';
8
9
  export { DEFAULT_SMART_KEYS } from './smart-keys.ts';
9
10
  export { shikiScopeColors, shikiTokenizers } from './shiki.ts';
10
- export type { Editor, EditorAttributionHover, EditorAttributionMark, EditorMarkColor, EditorBlock, EditorChangeKind, EditorChangeMark, EditorCodeVision, EditorCodeVisionEntry, EditorClick, EditorCodeBlockOptions, EditorClickHandler, EditorCommand, EditorContextMenu, EditorEngine, EditorFindQuery, EditorFoldHints, EditorFoldRangeHint, EditorFoldOutline, EditorFoldRange, EditorFoldSymbol, EditorFolds, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterIcon, EditorGutterMarker, EditorReplacement, EditorIndentation, EditorContentChange, EditorHighlight, EditorHighlightKind, EditorHover, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorLineAction, EditorLineHighlight, EditorMarker, EditorInputPopup, EditorMessages, EditorMarkerSeverity, EditorReveal, EditorRect, EditorSmartKeys, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorApplyEditsOptions, EditorCopy, EditorPasteOptions, EditorTextChange, EditorTrackedRange, EditorRunCommand, EditorSelectionRanges, EditorTheme, EditorViewCommand, EditorWhitespaceCleanup, EditorWidget, EditorZoom, FoldRole, KeyChord, LineToken, LineTokenKind, ScopeColorSource, ScopeColors, ScopeStyle, EditorSemanticToken, LineTokenizer, SmartEditorEngineOptions, TokenizedLine, TokenizerSource } from './types.ts';
11
+ export type { Editor, EditorAttributionHover, EditorAttributionMark, EditorMarkColor, EditorBlock, EditorChangeKind, EditorChangeMark, EditorCodeVision, EditorCodeVisionEntry, EditorClick, EditorCodeBlockOptions, EditorClickHandler, EditorCommand, EditorContextMenu, EditorEngine, EditorFindQuery, EditorFoldHints, EditorFoldRangeHint, EditorFoldOutline, EditorFoldRange, EditorFoldSymbol, EditorFolds, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterIcon, EditorGutterMarker, EditorReplacement, EditorIndentation, EditorContentChange, EditorHighlight, EditorHighlightKind, EditorHover, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorLineAction, EditorLineHighlight, EditorMarker, EditorInputPopup, EditorMessages, EditorMarkerSeverity, EditorReveal, EditorRect, EditorSmartKeys, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorApplyEditsOptions, EditorCopy, EditorPasteOptions, EditorPostfixOperand, EditorSurroundShape, EditorTextPlace, EditorUnwrapTarget, EditorTextChange, EditorTrackedRange, EditorRunCommand, EditorSelectionRanges, EditorTheme, EditorViewCommand, EditorWhitespaceCleanup, EditorWidget, EditorZoom, FoldRole, KeyChord, LineToken, LineTokenKind, ScopeColorSource, ScopeColors, ScopeStyle, EditorSemanticToken, LineTokenizer, SmartEditorEngineOptions, TokenizedLine, TokenizerSource } from './types.ts';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export { AGENT_COLORS } from './attribution.js';
3
3
  export { findDocComments, MAX_DOC_COMMENTS } from '@adecore/editor-core';
4
4
  export { DEFAULT_TODO_WORDS, findTodos } from '@adecore/editor-core';
5
5
  export { detectIndentation } from '@adecore/editor-core';
6
+ export { commentSyntax } from '@adecore/editor-core';
6
7
  export { createSmartEditorEngine } from './engine.js';
7
8
  export { rememberCopy } from './controller.js';
8
9
  export { DEFAULT_SMART_KEYS } from './smart-keys.js';
@@ -97,6 +97,11 @@ export declare const KEYMAP: {
97
97
  readonly renameSymbol: KeyBinding;
98
98
  readonly organizeImports: KeyBinding;
99
99
  readonly formatDocument: KeyBinding;
100
+ readonly insertLiveTemplate: KeyBinding;
101
+ readonly surroundWith: KeyBinding;
102
+ readonly surroundWithLiveTemplate: KeyBinding;
103
+ readonly unwrap: KeyBinding;
104
+ readonly saveAsLiveTemplate: KeyBinding;
100
105
  readonly wrapWithAbbreviation: KeyBinding;
101
106
  readonly selectionToChat: KeyBinding;
102
107
  readonly inlineEdit: KeyBinding;
@@ -123,7 +128,7 @@ export declare const KEYMAP: {
123
128
  readonly replace: KeyBinding;
124
129
  };
125
130
  export type KeymapId = keyof typeof KEYMAP;
126
- export type OptionalKeymapId = 'toggleRenderedDocs' | 'increaseFontSize' | 'decreaseFontSize' | 'resetFontSize' | 'sortLines' | 'reverseLines' | 'uniqueLines' | 'convertIndentsToSpaces' | 'convertIndentsToTabs' | 'completeCurrentStatement' | 'hippieCompletion' | 'hippieBackwardCompletion' | 'moveStatementUp' | 'moveStatementDown' | 'lastEditLocation' | 'nextEditLocation' | 'methodUp' | 'methodDown' | 'pasteFromHistory' | 'pasteAsPlainText' | 'nextChange' | 'previousChange' | 'codeBlockStart' | 'codeBlockEnd' | 'codeBlockStartWithSelection' | 'codeBlockEndWithSelection' | 'wrapWithAbbreviation' | 'typeHierarchy';
131
+ export type OptionalKeymapId = 'toggleRenderedDocs' | 'increaseFontSize' | 'decreaseFontSize' | 'resetFontSize' | 'sortLines' | 'reverseLines' | 'uniqueLines' | 'convertIndentsToSpaces' | 'convertIndentsToTabs' | 'completeCurrentStatement' | 'hippieCompletion' | 'hippieBackwardCompletion' | 'moveStatementUp' | 'moveStatementDown' | 'lastEditLocation' | 'nextEditLocation' | 'methodUp' | 'methodDown' | 'pasteFromHistory' | 'pasteAsPlainText' | 'nextChange' | 'previousChange' | 'codeBlockStart' | 'codeBlockEnd' | 'codeBlockStartWithSelection' | 'codeBlockEndWithSelection' | 'wrapWithAbbreviation' | 'insertLiveTemplate' | 'surroundWith' | 'surroundWithLiveTemplate' | 'unwrap' | 'saveAsLiveTemplate' | 'typeHierarchy';
127
132
  export type Keymap = Readonly<Record<Exclude<KeymapId, OptionalKeymapId>, KeyBinding> & Partial<Record<OptionalKeymapId, KeyBinding>>>;
128
133
  export type KeymapOverrides = Partial<Record<KeymapId, Partial<KeyBinding>>>;
129
134
  export declare const KEYMAP_IDS: KeymapId[];
@@ -100,7 +100,13 @@ export const KEYMAP = {
100
100
  renameSymbol: bind('Shift+F6'),
101
101
  organizeImports: bind('Ctrl+Alt+O'),
102
102
  formatDocument: bind('Mod+Alt+L'),
103
- wrapWithAbbreviation: bind('Mod+Alt+J'),
103
+ insertLiveTemplate: bind('Mod+J'),
104
+ surroundWith: bind('Mod+Alt+T'),
105
+ surroundWithLiveTemplate: bind('Mod+Alt+J'),
106
+ unwrap: bind('Mod+Shift+Delete'),
107
+ saveAsLiveTemplate: bind(null),
108
+ // Surround with Emmet has no chord of its own: it is a row of Surround with Live Template, which has this one.
109
+ wrapWithAbbreviation: bind(null),
104
110
  selectionToChat: bind(null),
105
111
  inlineEdit: bind(null),
106
112
  suggestInline: bind(null),
@@ -0,0 +1,10 @@
1
+ import type { DocumentModel } from '@adecore/editor-core';
2
+ import type { EditorPosition, EditorPostfixOperand, EditorRange, EditorSurroundShape, EditorTextPlace, EditorUnwrapTarget } from './types.ts';
3
+ export interface Coordinates {
4
+ positionAt(offset: number): EditorPosition;
5
+ offsetAt(position: EditorPosition): number;
6
+ }
7
+ export declare function placeAt(model: DocumentModel, coordinates: Coordinates, position: EditorPosition, language: string): EditorTextPlace;
8
+ export declare function postfixOperands(model: DocumentModel, coordinates: Coordinates, dot: EditorPosition, language: string): EditorPostfixOperand[];
9
+ export declare function surroundShape(model: DocumentModel, coordinates: Coordinates, range: EditorRange, language: string): EditorSurroundShape | null;
10
+ export declare function unwrapTargets(model: DocumentModel, coordinates: Coordinates, position: EditorPosition, language: string, indentUnit: string): EditorUnwrapTarget[];
@@ -0,0 +1,24 @@
1
+ function rangeOf(coordinates, from, to) {
2
+ return { start: coordinates.positionAt(from), end: coordinates.positionAt(to) };
3
+ }
4
+ export function placeAt(model, coordinates, position, language) {
5
+ return model.placeAt(coordinates.offsetAt(position), language);
6
+ }
7
+ export function postfixOperands(model, coordinates, dot, language) {
8
+ const at = coordinates.offsetAt(dot);
9
+ return model.postfixOperands(at, language).map((operand) => ({
10
+ range: rangeOf(coordinates, operand.from, operand.from + model.slice(operand.from, at).trimEnd().length),
11
+ statement: operand.statement
12
+ }));
13
+ }
14
+ export function surroundShape(model, coordinates, range, language) {
15
+ const shape = model.surroundShape(coordinates.offsetAt(range.start), coordinates.offsetAt(range.end), language);
16
+ return shape === null ? null : { range: rangeOf(coordinates, shape.from, shape.to), statements: shape.statements, expression: shape.expression };
17
+ }
18
+ export function unwrapTargets(model, coordinates, position, language, indentUnit) {
19
+ return model.unwrapTargets(coordinates.offsetAt(position), language, indentUnit).map((target) => ({
20
+ kind: target.kind,
21
+ range: rangeOf(coordinates, target.range.from, target.range.to),
22
+ edits: target.edits.map((edit) => ({ range: rangeOf(coordinates, edit.from, edit.to), text: edit.text }))
23
+ }));
24
+ }
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { EditorSearchClientOptions } from './search-client.ts';
2
2
  import type { Keymap } from './keymap-table.ts';
3
- import type { EditorCommand, FoldRole, WhitespaceCleanupOptions } from '@adecore/editor-core';
3
+ import type { EditorCommand, FoldRole, TextPlaceKind, UnwrapKind, WhitespaceCleanupOptions } from '@adecore/editor-core';
4
4
  export type { EditorCommand, FoldRole };
5
5
  export type EditorWhitespaceCleanup = WhitespaceCleanupOptions;
6
6
  export type EditorFoldOutline = 'off' | 'hover' | 'always';
@@ -139,6 +139,24 @@ export interface EditorContentChange {
139
139
  readonly range: EditorRange;
140
140
  readonly text: string;
141
141
  }
142
+ export interface EditorTextPlace {
143
+ readonly language: string;
144
+ readonly kind: TextPlaceKind;
145
+ }
146
+ export interface EditorPostfixOperand {
147
+ readonly range: EditorRange;
148
+ readonly statement: boolean;
149
+ }
150
+ export interface EditorSurroundShape {
151
+ readonly range: EditorRange;
152
+ readonly statements: boolean;
153
+ readonly expression: boolean;
154
+ }
155
+ export interface EditorUnwrapTarget {
156
+ readonly kind: UnwrapKind;
157
+ readonly range: EditorRange;
158
+ readonly edits: readonly EditorContentChange[];
159
+ }
142
160
  export interface EditorCopy {
143
161
  readonly text: string;
144
162
  readonly wholeLines: boolean;
@@ -420,6 +438,10 @@ export interface Editor {
420
438
  onFontSizeChange?(listener: (size: number | null) => void): () => void;
421
439
  setReadOnly(readOnly: boolean, reason?: string): void;
422
440
  isReadOnly?(): boolean;
441
+ placeAt?(position: EditorPosition): EditorTextPlace;
442
+ postfixOperands?(dot: EditorPosition): readonly EditorPostfixOperand[];
443
+ surroundShape?(range: EditorRange): EditorSurroundShape | null;
444
+ unwrapTargets?(position: EditorPosition): readonly EditorUnwrapTarget[];
423
445
  runCommand(command: EditorRunCommand): boolean;
424
446
  focus(): void;
425
447
  dispose(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/editor",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -54,7 +54,7 @@
54
54
  "test": "bun test --conditions=source"
55
55
  },
56
56
  "dependencies": {
57
- "@adecore/editor-core": "0.43.0",
57
+ "@adecore/editor-core": "0.44.0",
58
58
  "linkedom": "^0.18.14",
59
59
  "shiki": "^4.5.0"
60
60
  },
package/src/engine.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { changedSpans, DocumentModel, type EditorSnapshot, type FoldHints, replacementText } from '@adecore/editor-core';
2
2
  import { MAX_REPLACEMENT_CHARACTERS } from './search-protocol.ts';
3
+ import { placeAt, postfixOperands, surroundShape, unwrapTargets } from './text-queries.ts';
3
4
  import { GrammarPreparation } from './grammar-preparation.ts';
4
5
  import { InputController } from './controller.ts';
5
6
  import { resolveSmartKeys } from './smart-keys.ts';
@@ -43,6 +44,10 @@ import type {
43
44
  EditorMessages,
44
45
  EditorOptions,
45
46
  EditorPosition,
47
+ EditorPostfixOperand,
48
+ EditorSurroundShape,
49
+ EditorTextPlace,
50
+ EditorUnwrapTarget,
46
51
  EditorRemoteCursor,
47
52
  EditorRange,
48
53
  EditorReveal,
@@ -1067,6 +1072,24 @@ class SmartEditor implements Editor {
1067
1072
  return this.settings.readOnly;
1068
1073
  }
1069
1074
 
1075
+ placeAt(position: EditorPosition): EditorTextPlace {
1076
+ return placeAt(this.model, this, position, this.settings.language ?? 'plaintext');
1077
+ }
1078
+
1079
+ postfixOperands(dot: EditorPosition): readonly EditorPostfixOperand[] {
1080
+ return postfixOperands(this.model, this, dot, this.settings.language ?? 'plaintext');
1081
+ }
1082
+
1083
+ surroundShape(range: EditorRange): EditorSurroundShape | null {
1084
+ return surroundShape(this.model, this, range, this.settings.language ?? 'plaintext');
1085
+ }
1086
+
1087
+ unwrapTargets(position: EditorPosition): readonly EditorUnwrapTarget[] {
1088
+ const unit = this.settings.insertSpaces ? ' '.repeat(this.settings.tabSize) : '\t';
1089
+
1090
+ return unwrapTargets(this.model, this, position, this.settings.language ?? 'plaintext', unit);
1091
+ }
1092
+
1070
1093
  runCommand(command: EditorRunCommand): boolean {
1071
1094
  return this.controller.command(command);
1072
1095
  }
package/src/fake.ts CHANGED
@@ -34,6 +34,10 @@ import type {
34
34
  EditorMessages,
35
35
  EditorOptions,
36
36
  EditorPosition,
37
+ EditorPostfixOperand,
38
+ EditorSurroundShape,
39
+ EditorTextPlace,
40
+ EditorUnwrapTarget,
37
41
  EditorRemoteCursor,
38
42
  EditorRange,
39
43
  EditorReveal,
@@ -55,7 +59,8 @@ import type {
55
59
  EditorWidget
56
60
  } from './types.ts';
57
61
  import { emit, type Listener, subscribe } from './listeners.ts';
58
- import { changedSpan, changedSpans } from '@adecore/editor-core';
62
+ import { changedSpan, changedSpans, DocumentModel } from '@adecore/editor-core';
63
+ import { placeAt, postfixOperands, surroundShape, unwrapTargets } from './text-queries.ts';
59
64
  import { mapTrackedRange } from './tracked-range.ts';
60
65
 
61
66
  interface OffsetSelection {
@@ -1270,6 +1275,24 @@ export class FakeEditor implements Editor {
1270
1275
  return this.readOnly;
1271
1276
  }
1272
1277
 
1278
+ placeAt(position: EditorPosition): EditorTextPlace {
1279
+ return placeAt(new DocumentModel(this.text), this, position, this.language ?? 'plaintext');
1280
+ }
1281
+
1282
+ postfixOperands(dot: EditorPosition): readonly EditorPostfixOperand[] {
1283
+ return postfixOperands(new DocumentModel(this.text), this, dot, this.language ?? 'plaintext');
1284
+ }
1285
+
1286
+ surroundShape(range: EditorRange): EditorSurroundShape | null {
1287
+ return surroundShape(new DocumentModel(this.text), this, range, this.language ?? 'plaintext');
1288
+ }
1289
+
1290
+ unwrapTargets(position: EditorPosition): readonly EditorUnwrapTarget[] {
1291
+ const unit = this.indentation.insertSpaces ? ' '.repeat(this.indentation.tabSize) : '\t';
1292
+
1293
+ return unwrapTargets(new DocumentModel(this.text), this, position, this.language ?? 'plaintext', unit);
1294
+ }
1295
+
1273
1296
  /* The commands run, in order; of its own the fake carries out only undo and redo. */
1274
1297
  readonly commands: EditorRunCommand[] = [];
1275
1298
 
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export { AGENT_COLORS } from './attribution.ts';
3
3
  export { findDocComments, MAX_DOC_COMMENTS, type DocComment } from '@adecore/editor-core';
4
4
  export { DEFAULT_TODO_WORDS, findTodos, type TodoMatch, type TodoOptions } from '@adecore/editor-core';
5
5
  export { detectIndentation, type DetectedIndentation } from '@adecore/editor-core';
6
+ export { commentSyntax, type CommentSyntax } from '@adecore/editor-core';
6
7
  export { createSmartEditorEngine } from './engine.ts';
7
8
  export { rememberCopy } from './controller.ts';
8
9
  export { DEFAULT_SMART_KEYS } from './smart-keys.ts';
@@ -64,6 +65,10 @@ export type {
64
65
  EditorApplyEditsOptions,
65
66
  EditorCopy,
66
67
  EditorPasteOptions,
68
+ EditorPostfixOperand,
69
+ EditorSurroundShape,
70
+ EditorTextPlace,
71
+ EditorUnwrapTarget,
67
72
  EditorTextChange,
68
73
  EditorTrackedRange,
69
74
  EditorRunCommand,
@@ -123,7 +123,13 @@ export const KEYMAP = {
123
123
  renameSymbol: bind('Shift+F6'),
124
124
  organizeImports: bind('Ctrl+Alt+O'),
125
125
  formatDocument: bind('Mod+Alt+L'),
126
- wrapWithAbbreviation: bind('Mod+Alt+J'),
126
+ insertLiveTemplate: bind('Mod+J'),
127
+ surroundWith: bind('Mod+Alt+T'),
128
+ surroundWithLiveTemplate: bind('Mod+Alt+J'),
129
+ unwrap: bind('Mod+Shift+Delete'),
130
+ saveAsLiveTemplate: bind(null),
131
+ // Surround with Emmet has no chord of its own: it is a row of Surround with Live Template, which has this one.
132
+ wrapWithAbbreviation: bind(null),
127
133
  selectionToChat: bind(null),
128
134
  inlineEdit: bind(null),
129
135
  suggestInline: bind(null),
@@ -182,6 +188,11 @@ export type OptionalKeymapId =
182
188
  | 'codeBlockStartWithSelection'
183
189
  | 'codeBlockEndWithSelection'
184
190
  | 'wrapWithAbbreviation'
191
+ | 'insertLiveTemplate'
192
+ | 'surroundWith'
193
+ | 'surroundWithLiveTemplate'
194
+ | 'unwrap'
195
+ | 'saveAsLiveTemplate'
185
196
  | 'typeHierarchy';
186
197
 
187
198
  export type Keymap = Readonly<Record<Exclude<KeymapId, OptionalKeymapId>, KeyBinding> & Partial<Record<OptionalKeymapId, KeyBinding>>>;
@@ -0,0 +1,45 @@
1
+ import type { DocumentModel } from '@adecore/editor-core';
2
+ import type { EditorPosition, EditorPostfixOperand, EditorRange, EditorSurroundShape, EditorTextPlace, EditorUnwrapTarget } from './types.ts';
3
+
4
+ /* How an editor turns the offsets of the text model into positions and back. */
5
+ export interface Coordinates {
6
+ positionAt(offset: number): EditorPosition;
7
+ offsetAt(position: EditorPosition): number;
8
+ }
9
+
10
+ function rangeOf(coordinates: Coordinates, from: number, to: number): EditorRange {
11
+ return { start: coordinates.positionAt(from), end: coordinates.positionAt(to) };
12
+ }
13
+
14
+ export function placeAt(model: DocumentModel, coordinates: Coordinates, position: EditorPosition, language: string): EditorTextPlace {
15
+ return model.placeAt(coordinates.offsetAt(position), language);
16
+ }
17
+
18
+ export function postfixOperands(model: DocumentModel, coordinates: Coordinates, dot: EditorPosition, language: string): EditorPostfixOperand[] {
19
+ const at = coordinates.offsetAt(dot);
20
+
21
+ return model.postfixOperands(at, language).map((operand) => ({
22
+ range: rangeOf(coordinates, operand.from, operand.from + model.slice(operand.from, at).trimEnd().length),
23
+ statement: operand.statement
24
+ }));
25
+ }
26
+
27
+ export function surroundShape(model: DocumentModel, coordinates: Coordinates, range: EditorRange, language: string): EditorSurroundShape | null {
28
+ const shape = model.surroundShape(coordinates.offsetAt(range.start), coordinates.offsetAt(range.end), language);
29
+
30
+ return shape === null ? null : { range: rangeOf(coordinates, shape.from, shape.to), statements: shape.statements, expression: shape.expression };
31
+ }
32
+
33
+ export function unwrapTargets(
34
+ model: DocumentModel,
35
+ coordinates: Coordinates,
36
+ position: EditorPosition,
37
+ language: string,
38
+ indentUnit: string
39
+ ): EditorUnwrapTarget[] {
40
+ return model.unwrapTargets(coordinates.offsetAt(position), language, indentUnit).map((target) => ({
41
+ kind: target.kind,
42
+ range: rangeOf(coordinates, target.range.from, target.range.to),
43
+ edits: target.edits.map((edit) => ({ range: rangeOf(coordinates, edit.from, edit.to), text: edit.text }))
44
+ }));
45
+ }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { EditorSearchClientOptions } from './search-client.ts';
2
2
  import type { Keymap } from './keymap-table.ts';
3
- import type { EditorCommand, FoldRole, WhitespaceCleanupOptions } from '@adecore/editor-core';
3
+ import type { EditorCommand, FoldRole, TextPlaceKind, UnwrapKind, WhitespaceCleanupOptions } from '@adecore/editor-core';
4
4
 
5
5
  export type { EditorCommand, FoldRole };
6
6
 
@@ -288,6 +288,37 @@ export interface EditorContentChange {
288
288
  readonly text: string;
289
289
  }
290
290
 
291
+ /* What the text at a position is written in, with embedded regions resolved, and whether it is code, a comment or a string. */
292
+ export interface EditorTextPlace {
293
+ readonly language: string;
294
+ readonly kind: TextPlaceKind;
295
+ }
296
+
297
+ /* An expression that ends right before a dot. */
298
+ export interface EditorPostfixOperand {
299
+ /* The expression, without the whitespace before the dot. */
300
+ readonly range: EditorRange;
301
+ /* Whether it starts a statement; only the widest operand can. */
302
+ readonly statement: boolean;
303
+ }
304
+
305
+ /* What a range can be surrounded with: whole statements, one expression, both or neither. */
306
+ export interface EditorSurroundShape {
307
+ /* The range after trimming whitespace, widened past a trailing line comment for statements. */
308
+ readonly range: EditorRange;
309
+ readonly statements: boolean;
310
+ readonly expression: boolean;
311
+ }
312
+
313
+ /* A construct around a position that can be unwrapped or removed. */
314
+ export interface EditorUnwrapTarget {
315
+ readonly kind: UnwrapKind;
316
+ /* The whole construct, for a preview. */
317
+ readonly range: EditorRange;
318
+ /* Small edits in the coordinates of the text before them, which `applyEdits` takes as they are. */
319
+ readonly edits: readonly EditorContentChange[];
320
+ }
321
+
291
322
  /* What a copy or cut put on the clipboard. */
292
323
  export interface EditorCopy {
293
324
  readonly text: string;
@@ -843,6 +874,14 @@ export interface Editor {
843
874
  setReadOnly(readOnly: boolean, reason?: string): void;
844
875
  /* Whether the editor refuses edits. Optional so an editor from before it still fits. */
845
876
  isReadOnly?(): boolean;
877
+ /* What the text at a position is written in and whether it is code, a comment or a string. Optional so an editor from before it still fits. */
878
+ placeAt?(position: EditorPosition): EditorTextPlace;
879
+ /* Every expression that ends right before the `.` at `dot`, innermost first. Optional so an editor from before it still fits. */
880
+ postfixOperands?(dot: EditorPosition): readonly EditorPostfixOperand[];
881
+ /* What a range can be surrounded with; null for a blank range. Optional so an editor from before it still fits. */
882
+ surroundShape?(range: EditorRange): EditorSurroundShape | null;
883
+ /* What can be unwrapped or removed around a position, innermost first. Optional so an editor from before it still fits. */
884
+ unwrapTargets?(position: EditorPosition): readonly EditorUnwrapTarget[];
846
885
  /* Runs an editing command on every caret, as its key would. False when it changed nothing. */
847
886
  runCommand(command: EditorRunCommand): boolean;
848
887
  focus(): void;