cliedit 0.1.2 → 0.1.3
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/README.md +13 -7
- package/dist/editor.editing.d.ts +9 -0
- package/dist/editor.editing.js +31 -0
- package/dist/editor.keys.js +44 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A lightweight, zero-dependency, raw-mode terminal editor component for Node.js.
|
|
|
4
4
|
|
|
5
5
|
`cliedit` is designed to be imported into your own CLI application to provide a full-featured, TTY-based text editing experience. It's perfect for applications that need to ask the user for multi-line input, edit configuration files, or write commit messages.
|
|
6
6
|
|
|
7
|
-
It includes line wrapping, visual navigation, undo/redo, text selection, and clipboard support.
|
|
7
|
+
It includes line wrapping, visual navigation, smart auto-indentation, undo/redo, text selection, Find/Replace, and cross-platform clipboard support.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -13,18 +13,21 @@ It includes line wrapping, visual navigation, undo/redo, text selection, and cli
|
|
|
13
13
|
- **Visual Navigation:** `Up`/`Down` arrows move by visual rows, not logical lines.
|
|
14
14
|
- **Undo/Redo:** `Ctrl+Z` / `Ctrl+Y` for persistent history.
|
|
15
15
|
- **Text Selection:** `Ctrl+Arrow` keys to select text.
|
|
16
|
-
- **Clipboard Support:** `Ctrl+C` (Copy), `Ctrl+X` (Cut), `Ctrl+V` (Paste) for system clipboard (macOS
|
|
16
|
+
- **Clipboard Support:** `Ctrl+C` (Copy), `Ctrl+X` (Cut), `Ctrl+V` (Paste) for system clipboard (macOS, Windows, **and Linux** via `xclip`).
|
|
17
17
|
- **File I/O:** Loads from and saves to the filesystem.
|
|
18
|
-
- **Search:** `Ctrl+W` to find text.
|
|
18
|
+
- **Search & Replace:** `Ctrl+W` to find text, `Ctrl+R` to find and replace interactively.
|
|
19
|
+
- **Go to Line:** `Ctrl+L` to quickly jump to a specific line number.
|
|
20
|
+
- **Smart Auto-Indentation:** Automatically preserves indentation level when pressing Enter.
|
|
19
21
|
|
|
20
22
|
## Installation
|
|
21
23
|
```bash
|
|
22
24
|
npm install cliedit
|
|
23
|
-
|
|
25
|
+
````
|
|
24
26
|
|
|
25
27
|
## Usage
|
|
26
28
|
|
|
27
29
|
The package exports an `async` function `openEditor` that returns a `Promise`. The promise resolves when the user quits the editor.
|
|
30
|
+
|
|
28
31
|
```javascript
|
|
29
32
|
import { openEditor } from 'cliedit';
|
|
30
33
|
import path from 'path';
|
|
@@ -60,13 +63,15 @@ getCommitMessage();
|
|
|
60
63
|
`openEditor(filepath: string)`
|
|
61
64
|
|
|
62
65
|
Opens the editor for the specified file. If the file doesn't exist, it will be created upon saving.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
|
|
67
|
+
- **Returns:** `Promise<{ saved: boolean; content: string }>`
|
|
68
|
+
* `saved`: `true` if the user saved (Ctrl+S), `false` otherwise (Ctrl+Q).
|
|
69
|
+
* `content`: The final content of the file as a string.
|
|
66
70
|
|
|
67
71
|
`CliEditor`
|
|
68
72
|
|
|
69
73
|
The main editor class. You can import this directly if you need to extend or instantiate the editor with custom logic.
|
|
74
|
+
|
|
70
75
|
```javascript
|
|
71
76
|
import { CliEditor } from 'cliedit';
|
|
72
77
|
```
|
|
@@ -74,6 +79,7 @@ import { CliEditor } from 'cliedit';
|
|
|
74
79
|
### Types
|
|
75
80
|
|
|
76
81
|
Key types are also exported for convenience:
|
|
82
|
+
|
|
77
83
|
```javascript
|
|
78
84
|
import type {
|
|
79
85
|
DocumentState,
|
package/dist/editor.editing.d.ts
CHANGED
|
@@ -29,6 +29,14 @@ declare function deleteBackward(this: CliEditor): void;
|
|
|
29
29
|
* Deletes the character after the cursor, or joins the current line with the next one.
|
|
30
30
|
*/
|
|
31
31
|
declare function deleteForward(this: CliEditor): void;
|
|
32
|
+
/**
|
|
33
|
+
* Handles auto-pairing of brackets and quotes.
|
|
34
|
+
* If text is selected, it wraps the selection.
|
|
35
|
+
* Otherwise, it inserts the pair and places the cursor in the middle.
|
|
36
|
+
* @param openChar The opening character that was typed (e.g., '(', '[', '{').
|
|
37
|
+
* @param closeChar The corresponding closing character (e.g., ')', ']', '}').
|
|
38
|
+
*/
|
|
39
|
+
declare function handleAutoPair(this: CliEditor, openChar: string, closeChar: string): void;
|
|
32
40
|
export declare const editingMethods: {
|
|
33
41
|
insertContentAtCursor: typeof insertContentAtCursor;
|
|
34
42
|
insertCharacter: typeof insertCharacter;
|
|
@@ -36,5 +44,6 @@ export declare const editingMethods: {
|
|
|
36
44
|
insertNewLine: typeof insertNewLine;
|
|
37
45
|
deleteBackward: typeof deleteBackward;
|
|
38
46
|
deleteForward: typeof deleteForward;
|
|
47
|
+
handleAutoPair: typeof handleAutoPair;
|
|
39
48
|
};
|
|
40
49
|
export {};
|
package/dist/editor.editing.js
CHANGED
|
@@ -110,6 +110,36 @@ function deleteForward() {
|
|
|
110
110
|
}
|
|
111
111
|
this.setDirty();
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Handles auto-pairing of brackets and quotes.
|
|
115
|
+
* If text is selected, it wraps the selection.
|
|
116
|
+
* Otherwise, it inserts the pair and places the cursor in the middle.
|
|
117
|
+
* @param openChar The opening character that was typed (e.g., '(', '[', '{').
|
|
118
|
+
* @param closeChar The corresponding closing character (e.g., ')', ']', '}').
|
|
119
|
+
*/
|
|
120
|
+
function handleAutoPair(openChar, closeChar) {
|
|
121
|
+
if (this.selectionAnchor) {
|
|
122
|
+
// There is a selection, so we need to wrap it.
|
|
123
|
+
const selection = this.getNormalizedSelection();
|
|
124
|
+
if (!selection)
|
|
125
|
+
return; // Should not happen if anchor exists, but good practice
|
|
126
|
+
const selectedText = this.getSelectedText();
|
|
127
|
+
// The deleteSelectedText() function automatically moves the cursor to the start
|
|
128
|
+
// of the selection, so we don't need to set it manually.
|
|
129
|
+
this.deleteSelectedText();
|
|
130
|
+
// Wrap the original selected text
|
|
131
|
+
const wrappedText = openChar + selectedText + closeChar;
|
|
132
|
+
this.insertContentAtCursor(wrappedText.split('\n'));
|
|
133
|
+
// The selection is already cancelled by deleteSelectedText().
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// No selection, just insert the opening and closing characters
|
|
137
|
+
this.insertCharacter(openChar + closeChar);
|
|
138
|
+
// Move cursor back one position to be in between the pair
|
|
139
|
+
this.cursorX--;
|
|
140
|
+
}
|
|
141
|
+
this.setDirty();
|
|
142
|
+
}
|
|
113
143
|
export const editingMethods = {
|
|
114
144
|
insertContentAtCursor,
|
|
115
145
|
insertCharacter,
|
|
@@ -117,4 +147,5 @@ export const editingMethods = {
|
|
|
117
147
|
insertNewLine,
|
|
118
148
|
deleteBackward,
|
|
119
149
|
deleteForward,
|
|
150
|
+
handleAutoPair,
|
|
120
151
|
};
|
package/dist/editor.keys.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
// src/editor.keys.ts
|
|
2
2
|
import { KEYS } from './constants.js';
|
|
3
|
+
const PAIR_MAP = {
|
|
4
|
+
'(': ')',
|
|
5
|
+
'[': ']',
|
|
6
|
+
'{': '}',
|
|
7
|
+
"'": "'",
|
|
8
|
+
'"': '"',
|
|
9
|
+
};
|
|
3
10
|
/**
|
|
4
11
|
* Main router for standardized keypress events from the 'keypress' library.
|
|
5
12
|
*/
|
|
@@ -175,10 +182,24 @@ function handleEditKeys(key) {
|
|
|
175
182
|
this.insertNewLine();
|
|
176
183
|
return true;
|
|
177
184
|
case KEYS.BACKSPACE:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
// Handle auto-pair deletion
|
|
186
|
+
const line = this.lines[this.cursorY] || '';
|
|
187
|
+
const charBefore = line[this.cursorX - 1];
|
|
188
|
+
const charAfter = line[this.cursorX];
|
|
189
|
+
if (!this.selectionAnchor &&
|
|
190
|
+
charBefore && charAfter &&
|
|
191
|
+
PAIR_MAP[charBefore] === charAfter) {
|
|
192
|
+
// Delete both characters of the pair
|
|
193
|
+
this.lines[this.cursorY] = line.slice(0, this.cursorX - 1) + line.slice(this.cursorX + 1);
|
|
194
|
+
this.cursorX--; // Move cursor back
|
|
195
|
+
this.setDirty();
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
if (this.selectionAnchor)
|
|
199
|
+
this.deleteSelectedText();
|
|
200
|
+
else
|
|
201
|
+
this.deleteBackward();
|
|
202
|
+
}
|
|
182
203
|
return true;
|
|
183
204
|
case KEYS.DELETE:
|
|
184
205
|
if (this.selectionAnchor)
|
|
@@ -238,11 +259,26 @@ function handleEditKeys(key) {
|
|
|
238
259
|
* Handles insertion of a character, deleting selection first if it exists.
|
|
239
260
|
*/
|
|
240
261
|
function handleCharacterKey(ch) {
|
|
241
|
-
|
|
242
|
-
|
|
262
|
+
const line = this.lines[this.cursorY] || '';
|
|
263
|
+
const charAfter = line[this.cursorX];
|
|
264
|
+
// If user types a closing character and it's what we expect, just move the cursor.
|
|
265
|
+
if (!this.selectionAnchor &&
|
|
266
|
+
(ch === ')' || ch === ']' || ch === '}' || ch === "'" || ch === '"') &&
|
|
267
|
+
charAfter === ch) {
|
|
268
|
+
this.cursorX++;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const closeChar = PAIR_MAP[ch];
|
|
272
|
+
if (closeChar) {
|
|
273
|
+
this.handleAutoPair(ch, closeChar);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
if (this.selectionAnchor) {
|
|
277
|
+
this.deleteSelectedText();
|
|
278
|
+
}
|
|
279
|
+
this.insertCharacter(ch);
|
|
280
|
+
this.setDirty();
|
|
243
281
|
}
|
|
244
|
-
this.insertCharacter(ch);
|
|
245
|
-
this.setDirty();
|
|
246
282
|
}
|
|
247
283
|
/**
|
|
248
284
|
* Handles Ctrl+Q (Quit) sequence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cliedit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A lightweight, raw-mode terminal editor utility for Node.js CLI applications, with line wrapping and undo/redo support.",
|
|
5
5
|
"repository": "https://github.com/CodeTease/cliedit",
|
|
6
6
|
"type": "module",
|