@involvex/fresh-editor 0.1.76 → 0.1.78
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/bin/CHANGELOG.md +1017 -0
- package/bin/LICENSE +117 -0
- package/bin/README.md +248 -0
- package/bin/fresh.exe +0 -0
- package/bin/plugins/README.md +71 -0
- package/bin/plugins/audit_mode.i18n.json +821 -0
- package/bin/plugins/audit_mode.ts +1810 -0
- package/bin/plugins/buffer_modified.i18n.json +67 -0
- package/bin/plugins/buffer_modified.ts +281 -0
- package/bin/plugins/calculator.i18n.json +93 -0
- package/bin/plugins/calculator.ts +770 -0
- package/bin/plugins/clangd-lsp.ts +168 -0
- package/bin/plugins/clangd_support.i18n.json +223 -0
- package/bin/plugins/clangd_support.md +20 -0
- package/bin/plugins/clangd_support.ts +325 -0
- package/bin/plugins/color_highlighter.i18n.json +145 -0
- package/bin/plugins/color_highlighter.ts +304 -0
- package/bin/plugins/config-schema.json +768 -0
- package/bin/plugins/csharp-lsp.ts +147 -0
- package/bin/plugins/csharp_support.i18n.json +80 -0
- package/bin/plugins/csharp_support.ts +170 -0
- package/bin/plugins/css-lsp.ts +143 -0
- package/bin/plugins/diagnostics_panel.i18n.json +236 -0
- package/bin/plugins/diagnostics_panel.ts +642 -0
- package/bin/plugins/examples/README.md +85 -0
- package/bin/plugins/examples/async_demo.ts +165 -0
- package/bin/plugins/examples/bookmarks.ts +329 -0
- package/bin/plugins/examples/buffer_query_demo.ts +110 -0
- package/bin/plugins/examples/git_grep.ts +262 -0
- package/bin/plugins/examples/hello_world.ts +93 -0
- package/bin/plugins/examples/virtual_buffer_demo.ts +116 -0
- package/bin/plugins/find_references.i18n.json +275 -0
- package/bin/plugins/find_references.ts +359 -0
- package/bin/plugins/git_blame.i18n.json +496 -0
- package/bin/plugins/git_blame.ts +707 -0
- package/bin/plugins/git_find_file.i18n.json +314 -0
- package/bin/plugins/git_find_file.ts +300 -0
- package/bin/plugins/git_grep.i18n.json +171 -0
- package/bin/plugins/git_grep.ts +191 -0
- package/bin/plugins/git_gutter.i18n.json +93 -0
- package/bin/plugins/git_gutter.ts +477 -0
- package/bin/plugins/git_log.i18n.json +481 -0
- package/bin/plugins/git_log.ts +1285 -0
- package/bin/plugins/go-lsp.ts +143 -0
- package/bin/plugins/html-lsp.ts +145 -0
- package/bin/plugins/json-lsp.ts +145 -0
- package/bin/plugins/lib/fresh.d.ts +1321 -0
- package/bin/plugins/lib/index.ts +24 -0
- package/bin/plugins/lib/navigation-controller.ts +214 -0
- package/bin/plugins/lib/panel-manager.ts +220 -0
- package/bin/plugins/lib/types.ts +72 -0
- package/bin/plugins/lib/virtual-buffer-factory.ts +130 -0
- package/bin/plugins/live_grep.i18n.json +171 -0
- package/bin/plugins/live_grep.ts +422 -0
- package/bin/plugins/markdown_compose.i18n.json +223 -0
- package/bin/plugins/markdown_compose.ts +630 -0
- package/bin/plugins/merge_conflict.i18n.json +821 -0
- package/bin/plugins/merge_conflict.ts +1810 -0
- package/bin/plugins/path_complete.i18n.json +80 -0
- package/bin/plugins/path_complete.ts +165 -0
- package/bin/plugins/python-lsp.ts +162 -0
- package/bin/plugins/rust-lsp.ts +166 -0
- package/bin/plugins/search_replace.i18n.json +405 -0
- package/bin/plugins/search_replace.ts +484 -0
- package/bin/plugins/test_i18n.i18n.json +67 -0
- package/bin/plugins/test_i18n.ts +18 -0
- package/bin/plugins/theme_editor.i18n.json +3746 -0
- package/bin/plugins/theme_editor.ts +2063 -0
- package/bin/plugins/todo_highlighter.i18n.json +184 -0
- package/bin/plugins/todo_highlighter.ts +206 -0
- package/bin/plugins/typescript-lsp.ts +167 -0
- package/bin/plugins/vi_mode.i18n.json +1549 -0
- package/bin/plugins/vi_mode.ts +2747 -0
- package/bin/plugins/welcome.i18n.json +236 -0
- package/bin/plugins/welcome.ts +76 -0
- package/bin/themes/dark.json +102 -0
- package/bin/themes/dracula.json +62 -0
- package/bin/themes/high-contrast.json +102 -0
- package/bin/themes/light.json +102 -0
- package/bin/themes/nord.json +62 -0
- package/bin/themes/nostalgia.json +102 -0
- package/bin/themes/solarized-dark.json +62 -0
- package/binary-install.js +1 -1
- package/dist/bin/fresh.js +9 -0
- package/dist/binary-install.js +149 -0
- package/dist/binary.js +30 -0
- package/dist/fresh-6yhknp07.exe +0 -0
- package/dist/install.js +158 -0
- package/dist/run-fresh.js +43 -0
- package/package.json +7 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Example Plugins
|
|
2
|
+
|
|
3
|
+
This directory contains example plugins demonstrating the editor's plugin system. These are educational examples showing specific API features.
|
|
4
|
+
|
|
5
|
+
For the complete API reference, see **[docs/plugin-api.md](../../docs/plugin-api.md)**.
|
|
6
|
+
|
|
7
|
+
## Available Examples
|
|
8
|
+
|
|
9
|
+
### hello_world.ts
|
|
10
|
+
|
|
11
|
+
A simple "Hello World" plugin that demonstrates:
|
|
12
|
+
- Registering a custom command
|
|
13
|
+
- Setting status messages
|
|
14
|
+
- Basic plugin structure
|
|
15
|
+
|
|
16
|
+
### async_demo.ts
|
|
17
|
+
|
|
18
|
+
Demonstrates async process spawning:
|
|
19
|
+
- Running external commands with `spawnProcess`
|
|
20
|
+
- Processing stdout/stderr
|
|
21
|
+
- Handling exit codes
|
|
22
|
+
|
|
23
|
+
### buffer_query_demo.ts
|
|
24
|
+
|
|
25
|
+
Demonstrates buffer queries:
|
|
26
|
+
- Getting buffer metadata with `getBufferInfo`
|
|
27
|
+
- Listing all open buffers
|
|
28
|
+
- Querying cursor and viewport information
|
|
29
|
+
|
|
30
|
+
### virtual_buffer_demo.ts
|
|
31
|
+
|
|
32
|
+
Demonstrates virtual buffer creation:
|
|
33
|
+
- Creating virtual buffers with `createVirtualBufferInSplit`
|
|
34
|
+
- Using text properties for embedded metadata
|
|
35
|
+
- Defining custom modes with keybindings
|
|
36
|
+
- Handling "go to" navigation from results
|
|
37
|
+
|
|
38
|
+
### bookmarks.ts
|
|
39
|
+
|
|
40
|
+
A complete bookmark management example:
|
|
41
|
+
- Managing persistent state across sessions
|
|
42
|
+
- Creating navigation commands
|
|
43
|
+
- Using overlays for visual markers
|
|
44
|
+
|
|
45
|
+
### git_grep.ts
|
|
46
|
+
|
|
47
|
+
Git grep implementation demonstrating:
|
|
48
|
+
- Spawning async git processes
|
|
49
|
+
- Parsing structured output
|
|
50
|
+
- Opening files at specific line:column positions
|
|
51
|
+
- Interactive search with prompt API
|
|
52
|
+
|
|
53
|
+
## Writing Your Own Plugin
|
|
54
|
+
|
|
55
|
+
1. Create a `.ts` file in the plugins directory
|
|
56
|
+
2. Use the `editor` global object to access the API
|
|
57
|
+
3. Register commands with `editor.registerCommand()`
|
|
58
|
+
4. The plugin will be automatically loaded when the editor starts
|
|
59
|
+
|
|
60
|
+
Example template:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
/// <reference path="../types/fresh.d.ts" />
|
|
64
|
+
|
|
65
|
+
// Define the command handler
|
|
66
|
+
globalThis.my_command = function(): void {
|
|
67
|
+
editor.setStatus("My command executed!");
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Register the command
|
|
71
|
+
editor.registerCommand(
|
|
72
|
+
"My Custom Command",
|
|
73
|
+
"Does something cool",
|
|
74
|
+
"my_command",
|
|
75
|
+
"normal"
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Initialization message
|
|
79
|
+
editor.debug("My custom plugin loaded");
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Further Reading
|
|
83
|
+
|
|
84
|
+
- **Getting Started:** [docs/PLUGIN_DEVELOPMENT.md](../../docs/PLUGIN_DEVELOPMENT.md)
|
|
85
|
+
- **API Reference:** [docs/plugin-api.md](../../docs/plugin-api.md)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/// <reference path="../../types/fresh.d.ts" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Async Process Demo Plugin
|
|
5
|
+
* Demonstrates spawning external processes asynchronously with async/await
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Git status
|
|
9
|
+
globalThis.async_git_status = async function(): Promise<void> {
|
|
10
|
+
editor.setStatus("Running git status...");
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const result = await editor.spawnProcess("git", ["status", "--short"]);
|
|
14
|
+
if (result.exit_code === 0) {
|
|
15
|
+
if (result.stdout === "" || result.stdout === "\n") {
|
|
16
|
+
editor.setStatus("Git: Working tree clean");
|
|
17
|
+
} else {
|
|
18
|
+
const count = result.stdout.split("\n").filter(line => line.trim()).length;
|
|
19
|
+
editor.setStatus(`Git: ${count} files changed`);
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
editor.setStatus(`Git status failed: ${result.stderr}`);
|
|
23
|
+
}
|
|
24
|
+
} catch (e) {
|
|
25
|
+
editor.setStatus(`Git status error: ${e}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
editor.registerCommand(
|
|
30
|
+
"Async Demo: Git Status",
|
|
31
|
+
"Run git status and show output",
|
|
32
|
+
"async_git_status",
|
|
33
|
+
"normal"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Current directory
|
|
37
|
+
globalThis.async_pwd = async function(): Promise<void> {
|
|
38
|
+
try {
|
|
39
|
+
const result = await editor.spawnProcess("pwd");
|
|
40
|
+
if (result.exit_code === 0) {
|
|
41
|
+
const dir = result.stdout.trim();
|
|
42
|
+
editor.setStatus(`Current directory: ${dir}`);
|
|
43
|
+
} else {
|
|
44
|
+
editor.setStatus("pwd failed");
|
|
45
|
+
}
|
|
46
|
+
} catch (e) {
|
|
47
|
+
editor.setStatus(`pwd error: ${e}`);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
editor.registerCommand(
|
|
52
|
+
"Async Demo: Current Directory",
|
|
53
|
+
"Show current directory using pwd",
|
|
54
|
+
"async_pwd",
|
|
55
|
+
"normal"
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// List files
|
|
59
|
+
globalThis.async_ls = async function(): Promise<void> {
|
|
60
|
+
editor.setStatus("Listing files...");
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const result = await editor.spawnProcess("ls", ["-1"]);
|
|
64
|
+
if (result.exit_code === 0) {
|
|
65
|
+
const count = result.stdout.split("\n").filter(line => line.trim()).length;
|
|
66
|
+
editor.setStatus(`Found ${count} files/directories`);
|
|
67
|
+
} else {
|
|
68
|
+
editor.setStatus("ls failed");
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
editor.setStatus(`ls error: ${e}`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
editor.registerCommand(
|
|
76
|
+
"Async Demo: List Files",
|
|
77
|
+
"List files in current directory",
|
|
78
|
+
"async_ls",
|
|
79
|
+
"normal"
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Git branch
|
|
83
|
+
globalThis.async_git_branch = async function(): Promise<void> {
|
|
84
|
+
try {
|
|
85
|
+
const result = await editor.spawnProcess("git", ["branch", "--show-current"]);
|
|
86
|
+
if (result.exit_code === 0) {
|
|
87
|
+
const branch = result.stdout.trim();
|
|
88
|
+
if (branch !== "") {
|
|
89
|
+
editor.setStatus(`Git branch: ${branch}`);
|
|
90
|
+
} else {
|
|
91
|
+
editor.setStatus("Not on any branch (detached HEAD)");
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
editor.setStatus("Not a git repository");
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
editor.setStatus(`Git branch error: ${e}`);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
editor.registerCommand(
|
|
102
|
+
"Async Demo: Git Branch",
|
|
103
|
+
"Show current git branch",
|
|
104
|
+
"async_git_branch",
|
|
105
|
+
"normal"
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Echo test
|
|
109
|
+
globalThis.async_echo = async function(): Promise<void> {
|
|
110
|
+
try {
|
|
111
|
+
const result = await editor.spawnProcess("echo", ["Hello from async process!"]);
|
|
112
|
+
editor.setStatus(`Echo output: ${result.stdout.trim()}`);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
editor.setStatus(`Echo error: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
editor.registerCommand(
|
|
119
|
+
"Async Demo: Echo Test",
|
|
120
|
+
"Test with simple echo command",
|
|
121
|
+
"async_echo",
|
|
122
|
+
"normal"
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// With working directory
|
|
126
|
+
globalThis.async_with_cwd = async function(): Promise<void> {
|
|
127
|
+
try {
|
|
128
|
+
const result = await editor.spawnProcess("pwd", [], "/tmp");
|
|
129
|
+
const dir = result.stdout.trim();
|
|
130
|
+
editor.setStatus(`Working dir was: ${dir}`);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
editor.setStatus(`pwd error: ${e}`);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
editor.registerCommand(
|
|
137
|
+
"Async Demo: With Working Dir",
|
|
138
|
+
"Run command in /tmp directory",
|
|
139
|
+
"async_with_cwd",
|
|
140
|
+
"normal"
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Error handling
|
|
144
|
+
globalThis.async_error = async function(): Promise<void> {
|
|
145
|
+
try {
|
|
146
|
+
const result = await editor.spawnProcess("this_command_does_not_exist");
|
|
147
|
+
if (result.exit_code !== 0) {
|
|
148
|
+
editor.setStatus(`Command failed (as expected): exit ${result.exit_code}`);
|
|
149
|
+
} else {
|
|
150
|
+
editor.setStatus("Unexpected success");
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
editor.setStatus(`Command failed with error: ${e}`);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
editor.registerCommand(
|
|
158
|
+
"Async Demo: Error Handling",
|
|
159
|
+
"Demonstrate error handling with non-existent command",
|
|
160
|
+
"async_error",
|
|
161
|
+
"normal"
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
editor.setStatus("Async Demo plugin loaded! Try the 'Async Demo' commands.");
|
|
165
|
+
editor.debug("Async Demo plugin initialized with native async/await support");
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/// <reference path="../../types/fresh.d.ts" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bookmarks Plugin for Fresh Editor (TypeScript)
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates the new TypeScript plugin ops:
|
|
7
|
+
* - editor.registerCommand() - Register plugin commands
|
|
8
|
+
* - editor.openFile() - Open file at specific location
|
|
9
|
+
* - editor.getActiveSplitId() - Get current split ID
|
|
10
|
+
* - editor.openFileInSplit() - Open file in specific split
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Add bookmarks at current cursor position
|
|
14
|
+
* - List all bookmarks
|
|
15
|
+
* - Jump to bookmarks
|
|
16
|
+
* - Remove bookmarks
|
|
17
|
+
* - Split-aware navigation
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Bookmark storage
|
|
21
|
+
interface Bookmark {
|
|
22
|
+
id: number;
|
|
23
|
+
name: string;
|
|
24
|
+
path: string;
|
|
25
|
+
line: number;
|
|
26
|
+
column: number;
|
|
27
|
+
splitId: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const bookmarks: Map<number, Bookmark> = new Map();
|
|
31
|
+
let nextBookmarkId = 1;
|
|
32
|
+
|
|
33
|
+
// Helper: Get current location info
|
|
34
|
+
function getCurrentLocation(): {
|
|
35
|
+
path: string;
|
|
36
|
+
position: number;
|
|
37
|
+
splitId: number;
|
|
38
|
+
} {
|
|
39
|
+
const bufferId = editor.getActiveBufferId();
|
|
40
|
+
const path = editor.getBufferPath(bufferId);
|
|
41
|
+
const position = editor.getCursorPosition();
|
|
42
|
+
const splitId = editor.getActiveSplitId();
|
|
43
|
+
|
|
44
|
+
return { path, position, splitId };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Helper: Get actual line number using the API
|
|
48
|
+
function getCurrentLineCol(): { line: number; column: number } {
|
|
49
|
+
// Use the actual getCursorLine API for accurate line number
|
|
50
|
+
const lineNumber = editor.getCursorLine();
|
|
51
|
+
|
|
52
|
+
// Get cursor position within the line by reading buffer content
|
|
53
|
+
const bufferId = editor.getActiveBufferId();
|
|
54
|
+
const cursorPos = editor.getCursorPosition();
|
|
55
|
+
const bufferInfo = editor.getBufferInfo(bufferId);
|
|
56
|
+
|
|
57
|
+
// Calculate column by finding start of current line
|
|
58
|
+
let column = 1;
|
|
59
|
+
if (bufferInfo && cursorPos > 0) {
|
|
60
|
+
// Read a small chunk before cursor to find line start
|
|
61
|
+
const readStart = Math.max(0, cursorPos - 1000);
|
|
62
|
+
const textBefore = editor.getBufferText(bufferId, readStart, cursorPos);
|
|
63
|
+
const lastNewline = textBefore.lastIndexOf("\n");
|
|
64
|
+
if (lastNewline !== -1) {
|
|
65
|
+
column = cursorPos - (readStart + lastNewline);
|
|
66
|
+
} else {
|
|
67
|
+
// No newline found, column is position from readStart
|
|
68
|
+
column = cursorPos - readStart + 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { line: lineNumber, column };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Action: Add bookmark at current position
|
|
76
|
+
globalThis.bookmark_add = function (): void {
|
|
77
|
+
const { path, position, splitId } = getCurrentLocation();
|
|
78
|
+
const { line, column } = getCurrentLineCol();
|
|
79
|
+
|
|
80
|
+
if (!path) {
|
|
81
|
+
editor.setStatus("Cannot bookmark: buffer has no file path");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const id = nextBookmarkId++;
|
|
86
|
+
const name = `Bookmark ${id}`;
|
|
87
|
+
|
|
88
|
+
const bookmark: Bookmark = {
|
|
89
|
+
id,
|
|
90
|
+
name,
|
|
91
|
+
path,
|
|
92
|
+
line,
|
|
93
|
+
column,
|
|
94
|
+
splitId,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
bookmarks.set(id, bookmark);
|
|
98
|
+
|
|
99
|
+
// Add visual indicator with bookmark namespace
|
|
100
|
+
const bufferId = editor.getActiveBufferId();
|
|
101
|
+
editor.addOverlay(
|
|
102
|
+
bufferId,
|
|
103
|
+
"bookmark", // namespace for all bookmarks
|
|
104
|
+
position,
|
|
105
|
+
position + 1,
|
|
106
|
+
0, // Red
|
|
107
|
+
128, // Green (teal color)
|
|
108
|
+
255, // Blue
|
|
109
|
+
true // Underline
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
editor.setStatus(`Added ${name} at ${path}:${line}:${column}`);
|
|
113
|
+
editor.debug(`Bookmark ${id} created: ${JSON.stringify(bookmark)}`);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Action: List all bookmarks
|
|
117
|
+
globalThis.bookmark_list = function (): void {
|
|
118
|
+
if (bookmarks.size === 0) {
|
|
119
|
+
editor.setStatus("No bookmarks");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const list: string[] = [];
|
|
124
|
+
bookmarks.forEach((bm, id) => {
|
|
125
|
+
list.push(`[${id}] ${bm.path}:${bm.line}:${bm.column}`);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
editor.setStatus(`Bookmarks: ${list.join(" | ")}`);
|
|
129
|
+
editor.debug(`All bookmarks: ${JSON.stringify([...bookmarks.values()])}`);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Action: Jump to bookmark by ID
|
|
133
|
+
globalThis.bookmark_goto = function (): void {
|
|
134
|
+
if (bookmarks.size === 0) {
|
|
135
|
+
editor.setStatus("No bookmarks to jump to");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Jump to the first bookmark (simplified)
|
|
140
|
+
const firstBookmark = bookmarks.values().next().value;
|
|
141
|
+
if (firstBookmark) {
|
|
142
|
+
const success = editor.openFile(
|
|
143
|
+
firstBookmark.path,
|
|
144
|
+
firstBookmark.line,
|
|
145
|
+
firstBookmark.column
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
if (success) {
|
|
149
|
+
editor.setStatus(
|
|
150
|
+
`Jumped to ${firstBookmark.name}: ${firstBookmark.path}:${firstBookmark.line}`
|
|
151
|
+
);
|
|
152
|
+
} else {
|
|
153
|
+
editor.setStatus(`Failed to open ${firstBookmark.path}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Action: Jump to bookmark in same split (split-aware)
|
|
159
|
+
globalThis.bookmark_goto_split = function (): void {
|
|
160
|
+
if (bookmarks.size === 0) {
|
|
161
|
+
editor.setStatus("No bookmarks");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const currentSplit = editor.getActiveSplitId();
|
|
166
|
+
const firstBookmark = bookmarks.values().next().value;
|
|
167
|
+
|
|
168
|
+
if (firstBookmark) {
|
|
169
|
+
// Open in the current split, not the bookmark's original split
|
|
170
|
+
const success = editor.openFileInSplit(
|
|
171
|
+
currentSplit,
|
|
172
|
+
firstBookmark.path,
|
|
173
|
+
firstBookmark.line,
|
|
174
|
+
firstBookmark.column
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (success) {
|
|
178
|
+
editor.setStatus(
|
|
179
|
+
`Opened ${firstBookmark.name} in split ${currentSplit}`
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
editor.setStatus(`Failed to open in split ${currentSplit}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Action: Remove all bookmarks
|
|
188
|
+
globalThis.bookmark_clear = function (): void {
|
|
189
|
+
const bufferId = editor.getActiveBufferId();
|
|
190
|
+
|
|
191
|
+
// Remove all bookmark overlays using namespace
|
|
192
|
+
editor.clearNamespace(bufferId, "bookmark");
|
|
193
|
+
|
|
194
|
+
const count = bookmarks.size;
|
|
195
|
+
bookmarks.clear();
|
|
196
|
+
|
|
197
|
+
editor.setStatus(`Cleared ${count} bookmark(s)`);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Action: Show current split info
|
|
201
|
+
globalThis.show_split_info = function (): void {
|
|
202
|
+
const splitId = editor.getActiveSplitId();
|
|
203
|
+
const bufferId = editor.getActiveBufferId();
|
|
204
|
+
const path = editor.getBufferPath(bufferId);
|
|
205
|
+
|
|
206
|
+
editor.setStatus(`Split ${splitId} | Buffer ${bufferId} | ${path || "[untitled]"}`);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Interactive bookmark selection using prompt API
|
|
210
|
+
let bookmarkSuggestionIds: number[] = [];
|
|
211
|
+
|
|
212
|
+
globalThis.bookmark_select = function (): void {
|
|
213
|
+
if (bookmarks.size === 0) {
|
|
214
|
+
editor.setStatus("No bookmarks to select");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Create suggestions from bookmarks
|
|
219
|
+
const suggestions: PromptSuggestion[] = [];
|
|
220
|
+
bookmarkSuggestionIds = [];
|
|
221
|
+
|
|
222
|
+
bookmarks.forEach((bm) => {
|
|
223
|
+
const filename = bm.path.split("/").pop() || bm.path;
|
|
224
|
+
suggestions.push({
|
|
225
|
+
text: `${bm.name}: ${bm.path}:${bm.line}:${bm.column}`,
|
|
226
|
+
description: `${filename} at line ${bm.line}`,
|
|
227
|
+
value: String(bm.id),
|
|
228
|
+
disabled: false,
|
|
229
|
+
});
|
|
230
|
+
bookmarkSuggestionIds.push(bm.id);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
editor.startPrompt("Select bookmark: ", "bookmark-select");
|
|
234
|
+
editor.setPromptSuggestions(suggestions);
|
|
235
|
+
editor.setStatus(`${bookmarks.size} bookmark(s) available`);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Handle bookmark selection confirmation
|
|
239
|
+
globalThis.onBookmarkSelectConfirmed = function (args: {
|
|
240
|
+
prompt_type: string;
|
|
241
|
+
selected_index: number | null;
|
|
242
|
+
input: string;
|
|
243
|
+
}): boolean {
|
|
244
|
+
if (args.prompt_type !== "bookmark-select") {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (args.selected_index !== null && bookmarkSuggestionIds[args.selected_index] !== undefined) {
|
|
249
|
+
const bookmarkId = bookmarkSuggestionIds[args.selected_index];
|
|
250
|
+
const bookmark = bookmarks.get(bookmarkId);
|
|
251
|
+
|
|
252
|
+
if (bookmark) {
|
|
253
|
+
editor.openFile(bookmark.path, bookmark.line, bookmark.column);
|
|
254
|
+
editor.setStatus(`Jumped to ${bookmark.name}: ${bookmark.path}:${bookmark.line}`);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
editor.setStatus("No bookmark selected");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return true;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Handle bookmark selection cancellation
|
|
264
|
+
globalThis.onBookmarkSelectCancelled = function (args: { prompt_type: string }): boolean {
|
|
265
|
+
if (args.prompt_type !== "bookmark-select") {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
editor.setStatus("Bookmark selection cancelled");
|
|
270
|
+
return true;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// Register bookmark event handlers
|
|
274
|
+
editor.on("prompt_confirmed", "onBookmarkSelectConfirmed");
|
|
275
|
+
editor.on("prompt_cancelled", "onBookmarkSelectCancelled");
|
|
276
|
+
|
|
277
|
+
// Register commands on plugin load
|
|
278
|
+
editor.registerCommand(
|
|
279
|
+
"Add Bookmark",
|
|
280
|
+
"Add a bookmark at the current cursor position",
|
|
281
|
+
"bookmark_add",
|
|
282
|
+
"normal"
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
editor.registerCommand(
|
|
286
|
+
"List Bookmarks",
|
|
287
|
+
"Show all bookmarks",
|
|
288
|
+
"bookmark_list",
|
|
289
|
+
"normal"
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
editor.registerCommand(
|
|
293
|
+
"Go to Bookmark",
|
|
294
|
+
"Jump to the first bookmark",
|
|
295
|
+
"bookmark_goto",
|
|
296
|
+
"normal"
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
editor.registerCommand(
|
|
300
|
+
"Go to Bookmark (Current Split)",
|
|
301
|
+
"Jump to bookmark in current split",
|
|
302
|
+
"bookmark_goto_split",
|
|
303
|
+
"normal"
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
editor.registerCommand(
|
|
307
|
+
"Clear Bookmarks",
|
|
308
|
+
"Remove all bookmarks",
|
|
309
|
+
"bookmark_clear",
|
|
310
|
+
"normal"
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
editor.registerCommand(
|
|
314
|
+
"Show Split Info",
|
|
315
|
+
"Display current split and buffer information",
|
|
316
|
+
"show_split_info",
|
|
317
|
+
"" // Available in all contexts
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
editor.registerCommand(
|
|
321
|
+
"Select Bookmark",
|
|
322
|
+
"Interactively select and jump to a bookmark",
|
|
323
|
+
"bookmark_select",
|
|
324
|
+
"normal"
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
// Plugin initialized
|
|
328
|
+
editor.setStatus("Bookmarks plugin loaded - 7 commands registered");
|
|
329
|
+
editor.debug("Bookmarks plugin initialized with command registration and prompt API support");
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/// <reference path="../../types/fresh.d.ts" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Buffer Query Demo Plugin
|
|
5
|
+
* Demonstrates the buffer query APIs in Phase 2
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Show buffer info
|
|
9
|
+
globalThis.show_buffer_info_demo = function(): void {
|
|
10
|
+
const bufferId = editor.getActiveBufferId();
|
|
11
|
+
const info = editor.getBufferInfo(bufferId);
|
|
12
|
+
|
|
13
|
+
if (info) {
|
|
14
|
+
const msg = `Buffer ${info.id}: ${info.path || "[No Name]"} (${
|
|
15
|
+
info.modified ? "modified" : "saved"
|
|
16
|
+
}, ${info.length} bytes)`;
|
|
17
|
+
editor.setStatus(msg);
|
|
18
|
+
} else {
|
|
19
|
+
editor.setStatus("No buffer info available");
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
editor.registerCommand(
|
|
24
|
+
"Query Demo: Show Buffer Info",
|
|
25
|
+
"Display information about the current buffer",
|
|
26
|
+
"show_buffer_info_demo",
|
|
27
|
+
"normal"
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// Show cursor position with selection info
|
|
31
|
+
globalThis.show_cursor_info_demo = function(): void {
|
|
32
|
+
const cursor = editor.getPrimaryCursor();
|
|
33
|
+
|
|
34
|
+
if (cursor) {
|
|
35
|
+
let msg: string;
|
|
36
|
+
if (cursor.selection) {
|
|
37
|
+
msg = `Cursor at ${cursor.position}, selection: ${cursor.selection.start}-${cursor.selection.end} (${
|
|
38
|
+
cursor.selection.end - cursor.selection.start
|
|
39
|
+
} chars)`;
|
|
40
|
+
} else {
|
|
41
|
+
msg = `Cursor at byte position ${cursor.position} (no selection)`;
|
|
42
|
+
}
|
|
43
|
+
editor.setStatus(msg);
|
|
44
|
+
} else {
|
|
45
|
+
editor.setStatus("No cursor info available");
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
editor.registerCommand(
|
|
50
|
+
"Query Demo: Show Cursor Position",
|
|
51
|
+
"Display cursor position and selection info",
|
|
52
|
+
"show_cursor_info_demo",
|
|
53
|
+
"normal"
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Count all cursors (multi-cursor support)
|
|
57
|
+
globalThis.count_cursors_demo = function(): void {
|
|
58
|
+
const cursors = editor.getAllCursors();
|
|
59
|
+
editor.setStatus(`Active cursors: ${cursors.length}`);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
editor.registerCommand(
|
|
63
|
+
"Query Demo: Count All Cursors",
|
|
64
|
+
"Display the number of active cursors",
|
|
65
|
+
"count_cursors_demo",
|
|
66
|
+
"normal"
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// List all buffers
|
|
70
|
+
globalThis.list_all_buffers_demo = function(): void {
|
|
71
|
+
const buffers = editor.listBuffers();
|
|
72
|
+
let modifiedCount = 0;
|
|
73
|
+
|
|
74
|
+
for (const buf of buffers) {
|
|
75
|
+
if (buf.modified) {
|
|
76
|
+
modifiedCount++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
editor.setStatus(`Open buffers: ${buffers.length} (${modifiedCount} modified)`);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
editor.registerCommand(
|
|
84
|
+
"Query Demo: List All Buffers",
|
|
85
|
+
"Show count of open buffers",
|
|
86
|
+
"list_all_buffers_demo",
|
|
87
|
+
"normal"
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Show viewport info
|
|
91
|
+
globalThis.show_viewport_demo = function(): void {
|
|
92
|
+
const vp = editor.getViewport();
|
|
93
|
+
|
|
94
|
+
if (vp) {
|
|
95
|
+
const msg = `Viewport: ${vp.width}x${vp.height}, top_byte=${vp.top_byte}, left_col=${vp.left_column}`;
|
|
96
|
+
editor.setStatus(msg);
|
|
97
|
+
} else {
|
|
98
|
+
editor.setStatus("No viewport info available");
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
editor.registerCommand(
|
|
103
|
+
"Query Demo: Show Viewport Info",
|
|
104
|
+
"Display viewport dimensions and scroll position",
|
|
105
|
+
"show_viewport_demo",
|
|
106
|
+
"normal"
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
editor.setStatus("Buffer Query Demo plugin loaded! Try the 'Query Demo' commands.");
|
|
110
|
+
editor.debug("Buffer Query Demo plugin initialized (TypeScript version)");
|