@oh-my-pi/pi-natives 9.4.0 → 9.6.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/README.md +10 -13
- package/native/pi_natives.darwin-arm64.node +0 -0
- package/native/pi_natives.darwin-x64.node +0 -0
- package/native/pi_natives.linux-arm64.node +0 -0
- package/native/pi_natives.linux-x64.node +0 -0
- package/native/pi_natives.win32-x64.node +0 -0
- package/package.json +6 -6
- package/src/find/types.ts +31 -0
- package/src/grep/index.ts +37 -295
- package/src/grep/types.ts +59 -19
- package/src/highlight/index.ts +5 -13
- package/src/html/index.ts +5 -35
- package/src/html/types.ts +1 -16
- package/src/image/index.ts +52 -73
- package/src/index.ts +20 -93
- package/src/native.ts +159 -0
- package/src/request-options.ts +94 -0
- package/src/text/index.ts +16 -24
- package/src/grep/file-reader.ts +0 -51
- package/src/grep/filters.ts +0 -77
- package/src/grep/worker.ts +0 -212
- package/src/html/worker.ts +0 -40
- package/src/image/types.ts +0 -52
- package/src/image/worker.ts +0 -152
- package/src/pool.ts +0 -362
- package/src/wasix.ts +0 -1745
- package/src/worker-resolver.ts +0 -9
- package/wasm/pi_natives.d.ts +0 -148
- package/wasm/pi_natives.js +0 -891
- package/wasm/pi_natives_bg.wasm +0 -0
- package/wasm/pi_natives_bg.wasm.d.ts +0 -32
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @oh-my-pi/pi-natives
|
|
2
2
|
|
|
3
|
-
Native Rust functionality
|
|
3
|
+
Native Rust functionality via N-API.
|
|
4
4
|
|
|
5
5
|
## What's Inside
|
|
6
6
|
|
|
7
|
-
- **Grep**: Regex-based search powered by ripgrep's engine
|
|
7
|
+
- **Grep**: Regex-based search powered by ripgrep's engine with native file walking and matching
|
|
8
8
|
- **Find**: Glob-based file/directory discovery with gitignore support (pure TypeScript via `globPaths`)
|
|
9
|
-
- **Image**: Image processing via photon-rs (resize, format conversion)
|
|
9
|
+
- **Image**: Image processing via photon-rs (resize, format conversion) exposed through N-API
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
@@ -37,8 +37,8 @@ const pngBytes = await resized.get_bytes();
|
|
|
37
37
|
## Building
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
# Build
|
|
41
|
-
bun run build:
|
|
40
|
+
# Build native addon from workspace root (requires Rust)
|
|
41
|
+
bun run build:native
|
|
42
42
|
|
|
43
43
|
# Type check
|
|
44
44
|
bun run check
|
|
@@ -48,16 +48,13 @@ bun run check
|
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
crates/pi-natives/ # Rust source (workspace member)
|
|
51
|
-
src/lib.rs #
|
|
51
|
+
src/lib.rs # N-API exports
|
|
52
52
|
src/image.rs # Image processing (photon-rs)
|
|
53
53
|
Cargo.toml # Rust dependencies
|
|
54
|
-
|
|
55
|
-
pi_natives
|
|
56
|
-
pi_natives.
|
|
57
|
-
pi_natives.d.ts # TypeScript definitions
|
|
54
|
+
native/ # Native addon binaries
|
|
55
|
+
pi_natives.<platform>-<arch>.node
|
|
56
|
+
pi_natives.node
|
|
58
57
|
src/ # TypeScript wrappers
|
|
58
|
+
native.ts # Native addon loader
|
|
59
59
|
index.ts # Public API
|
|
60
|
-
grep/ # Grep with worker pool
|
|
61
|
-
image/ # Async image processing via worker
|
|
62
|
-
pool.ts # Generic worker pool infrastructure
|
|
63
60
|
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-natives",
|
|
3
|
-
"version": "9.
|
|
4
|
-
"description": "Native Rust functionality
|
|
3
|
+
"version": "9.6.0",
|
|
4
|
+
"description": "Native Rust functionality via N-API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"types": "./src/index.ts",
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"src",
|
|
16
|
-
"
|
|
16
|
+
"native"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build:
|
|
19
|
+
"build:native": "bun scripts/build-native.ts",
|
|
20
20
|
"check": "biome check . && tsgo -p tsconfig.json",
|
|
21
21
|
"fix": "biome check --write --unsafe .",
|
|
22
|
-
"test": "bun test",
|
|
22
|
+
"test": "bun run build:native && bun test",
|
|
23
23
|
"bench": "bun bench/grep.ts"
|
|
24
24
|
},
|
|
25
25
|
"author": "Can Bölük",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"directory": "packages/natives"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@oh-my-pi/pi-utils": "9.
|
|
33
|
+
"@oh-my-pi/pi-utils": "9.6.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^25.0.10"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for native find API.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface FindOptions {
|
|
6
|
+
/** Glob pattern to match (e.g., `*.ts`) */
|
|
7
|
+
pattern: string;
|
|
8
|
+
/** Directory to search */
|
|
9
|
+
path: string;
|
|
10
|
+
/** Filter by file type: "file", "dir", or "symlink" */
|
|
11
|
+
fileType?: "file" | "dir" | "symlink";
|
|
12
|
+
/** Include hidden files (default: false) */
|
|
13
|
+
hidden?: boolean;
|
|
14
|
+
/** Maximum number of results */
|
|
15
|
+
maxResults?: number;
|
|
16
|
+
/** Respect .gitignore files (default: true) */
|
|
17
|
+
gitignore?: boolean;
|
|
18
|
+
/** Sort results by mtime (most recent first) before applying limit */
|
|
19
|
+
sortByMtime?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface FindMatch {
|
|
23
|
+
path: string;
|
|
24
|
+
fileType: "file" | "dir" | "symlink";
|
|
25
|
+
mtime?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FindResult {
|
|
29
|
+
matches: FindMatch[];
|
|
30
|
+
totalMatches: number;
|
|
31
|
+
}
|
package/src/grep/index.ts
CHANGED
|
@@ -1,329 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Native ripgrep wrapper using
|
|
3
|
-
*
|
|
4
|
-
* JS handles filesystem operations (directory walking, file reading).
|
|
5
|
-
* WASM handles pure regex matching using ripgrep's engine.
|
|
2
|
+
* Native ripgrep wrapper using N-API.
|
|
6
3
|
*/
|
|
7
4
|
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { globPaths } from "@oh-my-pi/pi-utils";
|
|
11
|
-
import {
|
|
12
|
-
CompiledPattern as WasmCompiledPattern,
|
|
13
|
-
has_match as wasmHasMatch,
|
|
14
|
-
search as wasmSearch,
|
|
15
|
-
} from "../../wasm/pi_natives";
|
|
16
|
-
import { WorkerPool } from "../pool";
|
|
17
|
-
import { resolveWorkerSpecifier } from "../worker-resolver";
|
|
18
|
-
import { FileReader } from "./file-reader";
|
|
19
|
-
import { buildGlobPattern, matchesTypeFilter, resolveTypeFilter } from "./filters";
|
|
5
|
+
import { native } from "../native";
|
|
6
|
+
import { wrapRequestOptions } from "../request-options";
|
|
20
7
|
import type {
|
|
21
8
|
ContextLine,
|
|
9
|
+
FuzzyFindMatch,
|
|
10
|
+
FuzzyFindOptions,
|
|
11
|
+
FuzzyFindResult,
|
|
22
12
|
GrepMatch,
|
|
23
13
|
GrepOptions,
|
|
24
14
|
GrepResult,
|
|
25
15
|
GrepSummary,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
WorkerResponse,
|
|
16
|
+
SearchOptions,
|
|
17
|
+
SearchResult,
|
|
29
18
|
} from "./types";
|
|
30
19
|
|
|
31
|
-
export type {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// =============================================================================
|
|
48
|
-
// Grep Implementation
|
|
49
|
-
// =============================================================================
|
|
50
|
-
|
|
51
|
-
const GREP_WORKERS = (() => {
|
|
52
|
-
const val = process.env.OMP_GREP_WORKERS;
|
|
53
|
-
if (val === undefined) return true;
|
|
54
|
-
const n = Number.parseInt(val, 10);
|
|
55
|
-
return Number.isNaN(n) || n > 0;
|
|
56
|
-
})();
|
|
20
|
+
export type {
|
|
21
|
+
ContextLine,
|
|
22
|
+
FuzzyFindMatch,
|
|
23
|
+
FuzzyFindOptions,
|
|
24
|
+
FuzzyFindResult,
|
|
25
|
+
GrepMatch,
|
|
26
|
+
GrepOptions,
|
|
27
|
+
GrepResult,
|
|
28
|
+
GrepSummary,
|
|
29
|
+
SearchOptions,
|
|
30
|
+
SearchResult,
|
|
31
|
+
};
|
|
57
32
|
|
|
58
33
|
/**
|
|
59
|
-
* Search files for a regex pattern
|
|
34
|
+
* Search files for a regex pattern with optional streaming callback.
|
|
60
35
|
*/
|
|
61
|
-
async function
|
|
62
|
-
|
|
63
|
-
const outputMode = options.mode ?? "content";
|
|
64
|
-
const wasmMode = outputMode === "content" ? "content" : "count";
|
|
65
|
-
|
|
66
|
-
const stat = await fs.stat(searchPath);
|
|
67
|
-
const isFile = stat.isFile();
|
|
68
|
-
|
|
69
|
-
using compiledPattern = new WasmCompiledPattern(
|
|
70
|
-
filterUndefined({
|
|
71
|
-
pattern: options.pattern,
|
|
72
|
-
ignoreCase: options.ignoreCase,
|
|
73
|
-
multiline: options.multiline,
|
|
74
|
-
context: options.context,
|
|
75
|
-
maxColumns: options.maxColumns,
|
|
76
|
-
mode: wasmMode,
|
|
77
|
-
}),
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const typeFilter = resolveTypeFilter(options.type);
|
|
81
|
-
const globPattern = buildGlobPattern(options.glob);
|
|
82
|
-
|
|
83
|
-
const matches: GrepMatch[] = [];
|
|
84
|
-
let totalMatches = 0;
|
|
85
|
-
let filesWithMatches = 0;
|
|
86
|
-
let filesSearched = 0;
|
|
87
|
-
let limitReached = false;
|
|
88
|
-
const maxCount = options.maxCount;
|
|
89
|
-
const globalOffset = options.offset ?? 0;
|
|
90
|
-
|
|
91
|
-
if (isFile) {
|
|
92
|
-
if (typeFilter && !matchesTypeFilter(searchPath, typeFilter)) {
|
|
93
|
-
return {
|
|
94
|
-
matches,
|
|
95
|
-
totalMatches,
|
|
96
|
-
filesWithMatches,
|
|
97
|
-
filesSearched,
|
|
98
|
-
limitReached: limitReached || undefined,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const fileReader = new FileReader();
|
|
103
|
-
const content = await fileReader.read(searchPath);
|
|
104
|
-
if (!content) {
|
|
105
|
-
return {
|
|
106
|
-
matches,
|
|
107
|
-
totalMatches,
|
|
108
|
-
filesWithMatches,
|
|
109
|
-
filesSearched,
|
|
110
|
-
limitReached: limitReached || undefined,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
filesSearched = 1;
|
|
114
|
-
|
|
115
|
-
const result = compiledPattern.search_bytes(
|
|
116
|
-
content,
|
|
117
|
-
maxCount,
|
|
118
|
-
globalOffset > 0 ? globalOffset : undefined,
|
|
119
|
-
) as WasmSearchResult;
|
|
120
|
-
|
|
121
|
-
if (result.error) {
|
|
122
|
-
throw new Error(result.error);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (result.matchCount > 0) {
|
|
126
|
-
filesWithMatches = 1;
|
|
127
|
-
totalMatches = result.matchCount;
|
|
128
|
-
|
|
129
|
-
if (outputMode === "content") {
|
|
130
|
-
for (const m of result.matches) {
|
|
131
|
-
const match: GrepMatch = {
|
|
132
|
-
path: searchPath,
|
|
133
|
-
lineNumber: m.lineNumber,
|
|
134
|
-
line: m.line,
|
|
135
|
-
contextBefore: m.contextBefore?.length ? m.contextBefore : undefined,
|
|
136
|
-
contextAfter: m.contextAfter?.length ? m.contextAfter : undefined,
|
|
137
|
-
truncated: m.truncated || undefined,
|
|
138
|
-
};
|
|
139
|
-
matches.push(match);
|
|
140
|
-
onMatch?.(match);
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
const match: GrepMatch = {
|
|
144
|
-
path: searchPath,
|
|
145
|
-
lineNumber: 0,
|
|
146
|
-
line: "",
|
|
147
|
-
matchCount: result.matchCount,
|
|
148
|
-
};
|
|
149
|
-
matches.push(match);
|
|
150
|
-
onMatch?.(match);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
limitReached = result.limitReached || (maxCount !== undefined && totalMatches >= maxCount);
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
const paths = await globPaths(globPattern, {
|
|
157
|
-
cwd: searchPath,
|
|
158
|
-
dot: options.hidden ?? true,
|
|
159
|
-
onlyFiles: true,
|
|
160
|
-
gitignore: true,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const fileReader = new FileReader();
|
|
164
|
-
for (const relativePath of paths) {
|
|
165
|
-
if (limitReached) break;
|
|
166
|
-
if (typeFilter && !matchesTypeFilter(relativePath, typeFilter)) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
171
|
-
const fullPath = path.join(searchPath, normalizedPath);
|
|
172
|
-
|
|
173
|
-
const content = await fileReader.read(fullPath);
|
|
174
|
-
if (!content) continue;
|
|
175
|
-
|
|
176
|
-
filesSearched++;
|
|
177
|
-
|
|
178
|
-
if (!compiledPattern.has_match_bytes(content)) {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const fileOffset = globalOffset > 0 ? Math.max(globalOffset - totalMatches, 0) : 0;
|
|
183
|
-
const remaining = maxCount !== undefined ? Math.max(maxCount - totalMatches, 0) : undefined;
|
|
184
|
-
if (remaining === 0) {
|
|
185
|
-
limitReached = true;
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
const result = compiledPattern.search_bytes(
|
|
189
|
-
content,
|
|
190
|
-
remaining,
|
|
191
|
-
fileOffset > 0 ? fileOffset : undefined,
|
|
192
|
-
) as WasmSearchResult;
|
|
193
|
-
|
|
194
|
-
if (result.error) {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (result.matchCount > 0) {
|
|
199
|
-
filesWithMatches++;
|
|
200
|
-
totalMatches += result.matchCount;
|
|
201
|
-
|
|
202
|
-
if (outputMode === "content") {
|
|
203
|
-
for (const m of result.matches) {
|
|
204
|
-
const match: GrepMatch = {
|
|
205
|
-
path: normalizedPath,
|
|
206
|
-
lineNumber: m.lineNumber,
|
|
207
|
-
line: m.line,
|
|
208
|
-
contextBefore: m.contextBefore?.length ? m.contextBefore : undefined,
|
|
209
|
-
contextAfter: m.contextAfter?.length ? m.contextAfter : undefined,
|
|
210
|
-
truncated: m.truncated || undefined,
|
|
211
|
-
};
|
|
212
|
-
matches.push(match);
|
|
213
|
-
onMatch?.(match);
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
const match: GrepMatch = {
|
|
217
|
-
path: normalizedPath,
|
|
218
|
-
lineNumber: 0,
|
|
219
|
-
line: "",
|
|
220
|
-
matchCount: result.matchCount,
|
|
221
|
-
};
|
|
222
|
-
matches.push(match);
|
|
223
|
-
onMatch?.(match);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (result.limitReached || (maxCount !== undefined && totalMatches >= maxCount)) {
|
|
227
|
-
limitReached = true;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
matches,
|
|
235
|
-
totalMatches,
|
|
236
|
-
filesWithMatches,
|
|
237
|
-
filesSearched,
|
|
238
|
-
limitReached: limitReached || undefined,
|
|
239
|
-
};
|
|
36
|
+
export async function grep(options: GrepOptions, onMatch?: (match: GrepMatch) => void): Promise<GrepResult> {
|
|
37
|
+
return wrapRequestOptions(() => native.grep(options, onMatch), options);
|
|
240
38
|
}
|
|
241
39
|
|
|
242
|
-
// =============================================================================
|
|
243
|
-
// Content Search (lower-level API)
|
|
244
|
-
// =============================================================================
|
|
245
|
-
|
|
246
40
|
/**
|
|
247
41
|
* Search a single file's content for a pattern.
|
|
248
42
|
* Lower-level API for when you already have file content.
|
|
43
|
+
*
|
|
44
|
+
* Accepts `Uint8Array`/`Buffer` for zero-copy when content is already UTF-8 encoded.
|
|
249
45
|
*/
|
|
250
|
-
export function searchContent(
|
|
251
|
-
content
|
|
252
|
-
options: {
|
|
253
|
-
pattern: string;
|
|
254
|
-
ignoreCase?: boolean;
|
|
255
|
-
multiline?: boolean;
|
|
256
|
-
maxCount?: number;
|
|
257
|
-
offset?: number;
|
|
258
|
-
context?: number;
|
|
259
|
-
maxColumns?: number;
|
|
260
|
-
mode?: "content" | "count";
|
|
261
|
-
},
|
|
262
|
-
): WasmSearchResult {
|
|
263
|
-
return wasmSearch(content, filterUndefined(options)) as WasmSearchResult;
|
|
46
|
+
export function searchContent(content: string | Uint8Array, options: SearchOptions): SearchResult {
|
|
47
|
+
return native.search(content, options);
|
|
264
48
|
}
|
|
265
49
|
|
|
266
50
|
/**
|
|
267
51
|
* Quick check if content contains a pattern match.
|
|
52
|
+
*
|
|
53
|
+
* Accepts `Uint8Array`/`Buffer` for zero-copy when content/pattern are already UTF-8 encoded.
|
|
268
54
|
*/
|
|
269
55
|
export function hasMatch(
|
|
270
|
-
content: string,
|
|
271
|
-
pattern: string,
|
|
56
|
+
content: string | Uint8Array,
|
|
57
|
+
pattern: string | Uint8Array,
|
|
272
58
|
options?: { ignoreCase?: boolean; multiline?: boolean },
|
|
273
59
|
): boolean {
|
|
274
|
-
return
|
|
60
|
+
return native.hasMatch(content, pattern, options?.ignoreCase ?? false, options?.multiline ?? false);
|
|
275
61
|
}
|
|
276
62
|
|
|
277
|
-
// =============================================================================
|
|
278
|
-
// Public API
|
|
279
|
-
// =============================================================================
|
|
280
|
-
|
|
281
63
|
/**
|
|
282
|
-
*
|
|
64
|
+
* Fuzzy file path search for autocomplete.
|
|
283
65
|
*
|
|
284
|
-
*
|
|
66
|
+
* Searches for files and directories whose paths contain the query substring
|
|
67
|
+
* (case-insensitive). Respects .gitignore by default.
|
|
285
68
|
*/
|
|
286
|
-
export async function
|
|
287
|
-
|
|
288
|
-
return await grepPoolInternal(options);
|
|
289
|
-
}
|
|
290
|
-
return await grepDirect(options, onMatch);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Search files using worker pool (always, ignores OMP_GREP_WORKERS).
|
|
295
|
-
*/
|
|
296
|
-
export async function grepPool(options: GrepOptions): Promise<GrepResult> {
|
|
297
|
-
return await grepPoolInternal(options);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// =============================================================================
|
|
301
|
-
// Worker Pool
|
|
302
|
-
// =============================================================================
|
|
303
|
-
|
|
304
|
-
const pool = new WorkerPool<WorkerRequest, WorkerResponse>({
|
|
305
|
-
createWorker: () =>
|
|
306
|
-
new Worker(
|
|
307
|
-
resolveWorkerSpecifier({
|
|
308
|
-
compiled: "./packages/natives/src/grep/worker.ts",
|
|
309
|
-
dev: new URL("./worker.ts", import.meta.url),
|
|
310
|
-
}),
|
|
311
|
-
),
|
|
312
|
-
maxWorkers: 4,
|
|
313
|
-
idleTimeoutMs: 30_000,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
async function grepPoolInternal(request: GrepOptions): Promise<GrepResult> {
|
|
317
|
-
const response = await pool.request<Extract<WorkerResponse, { type: "result" }>>({
|
|
318
|
-
type: "grep",
|
|
319
|
-
request,
|
|
320
|
-
});
|
|
321
|
-
return response.result;
|
|
69
|
+
export async function fuzzyFind(options: FuzzyFindOptions): Promise<FuzzyFindResult> {
|
|
70
|
+
return wrapRequestOptions(() => native.fuzzyFind(options), options);
|
|
322
71
|
}
|
|
323
|
-
|
|
324
|
-
/** Terminate all grep workers. */
|
|
325
|
-
export function terminate(): void {
|
|
326
|
-
pool.terminate();
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export { grepDirect };
|
package/src/grep/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { RequestOptions } from "../request-options";
|
|
2
|
+
|
|
1
3
|
/** Options for searching files. */
|
|
2
|
-
export interface GrepOptions {
|
|
4
|
+
export interface GrepOptions extends RequestOptions {
|
|
3
5
|
/** Regex pattern to search for */
|
|
4
6
|
pattern: string;
|
|
5
7
|
/** Directory or file to search */
|
|
@@ -52,31 +54,69 @@ export interface GrepResult extends GrepSummary {
|
|
|
52
54
|
matches: GrepMatch[];
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
export interface SearchOptions {
|
|
58
|
+
/** Regex pattern to search for */
|
|
59
|
+
pattern: string;
|
|
60
|
+
/** Case-insensitive search */
|
|
61
|
+
ignoreCase?: boolean;
|
|
62
|
+
/** Enable multiline matching */
|
|
63
|
+
multiline?: boolean;
|
|
64
|
+
/** Maximum number of matches to return */
|
|
65
|
+
maxCount?: number;
|
|
66
|
+
/** Skip first N matches */
|
|
67
|
+
offset?: number;
|
|
68
|
+
/** Lines of context before/after matches */
|
|
69
|
+
context?: number;
|
|
70
|
+
/** Truncate lines longer than this (characters) */
|
|
71
|
+
maxColumns?: number;
|
|
72
|
+
/** Output mode */
|
|
73
|
+
mode?: "content" | "count";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SearchMatch {
|
|
57
77
|
lineNumber: number;
|
|
58
78
|
line: string;
|
|
59
|
-
contextBefore
|
|
60
|
-
contextAfter
|
|
61
|
-
truncated
|
|
79
|
+
contextBefore?: ContextLine[];
|
|
80
|
+
contextAfter?: ContextLine[];
|
|
81
|
+
truncated?: boolean;
|
|
62
82
|
}
|
|
63
83
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
matches: WasmMatch[];
|
|
84
|
+
export interface SearchResult {
|
|
85
|
+
matches: SearchMatch[];
|
|
67
86
|
matchCount: number;
|
|
68
87
|
limitReached: boolean;
|
|
69
88
|
error?: string;
|
|
70
89
|
}
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
export type
|
|
74
|
-
| { type: "init"; id: number }
|
|
75
|
-
| { type: "grep"; id: number; request: GrepOptions }
|
|
76
|
-
| { type: "destroy" };
|
|
91
|
+
export type WasmMatch = SearchMatch;
|
|
92
|
+
export type WasmSearchResult = SearchResult;
|
|
77
93
|
|
|
78
|
-
/**
|
|
79
|
-
export
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
/** Options for fuzzy file path search. */
|
|
95
|
+
export interface FuzzyFindOptions extends RequestOptions {
|
|
96
|
+
/** Substring query to match against file paths (case-insensitive). */
|
|
97
|
+
query: string;
|
|
98
|
+
/** Directory to search. */
|
|
99
|
+
path: string;
|
|
100
|
+
/** Include hidden files (default: false). */
|
|
101
|
+
hidden?: boolean;
|
|
102
|
+
/** Respect .gitignore (default: true). */
|
|
103
|
+
gitignore?: boolean;
|
|
104
|
+
/** Maximum number of matches to return (default: 100). */
|
|
105
|
+
maxResults?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** A single match in fuzzy find results. */
|
|
109
|
+
export interface FuzzyFindMatch {
|
|
110
|
+
/** Relative path from the search root (uses `/` separators). */
|
|
111
|
+
path: string;
|
|
112
|
+
/** Whether this entry is a directory. */
|
|
113
|
+
isDirectory: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Result of fuzzy file path search. */
|
|
117
|
+
export interface FuzzyFindResult {
|
|
118
|
+
/** Matched entries (up to `maxResults`). */
|
|
119
|
+
matches: FuzzyFindMatch[];
|
|
120
|
+
/** Total number of matches found (may exceed `matches.length`). */
|
|
121
|
+
totalMatches: number;
|
|
122
|
+
}
|
package/src/highlight/index.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Syntax highlighting powered by
|
|
2
|
+
* Syntax highlighting powered by native syntect bindings.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
type WasmHighlightExports = typeof wasm & {
|
|
8
|
-
highlight_code: (code: string, lang: string | null | undefined, colors: HighlightColors) => string;
|
|
9
|
-
supports_language: (lang: string) => boolean;
|
|
10
|
-
get_supported_languages: () => string[];
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const wasmHighlight = wasm as WasmHighlightExports;
|
|
5
|
+
import { native } from "../native";
|
|
14
6
|
|
|
15
7
|
/**
|
|
16
8
|
* Theme colors for syntax highlighting.
|
|
@@ -41,19 +33,19 @@ export interface HighlightColors {
|
|
|
41
33
|
* @returns Highlighted code as a single string with ANSI color codes
|
|
42
34
|
*/
|
|
43
35
|
export function highlightCode(code: string, lang: string | undefined, colors: HighlightColors): string {
|
|
44
|
-
return
|
|
36
|
+
return native.highlightCode(code, lang, colors);
|
|
45
37
|
}
|
|
46
38
|
|
|
47
39
|
/**
|
|
48
40
|
* Check if a language is supported for highlighting.
|
|
49
41
|
*/
|
|
50
42
|
export function supportsLanguage(lang: string): boolean {
|
|
51
|
-
return
|
|
43
|
+
return native.supportsLanguage(lang);
|
|
52
44
|
}
|
|
53
45
|
|
|
54
46
|
/**
|
|
55
47
|
* Get list of all supported languages.
|
|
56
48
|
*/
|
|
57
49
|
export function getSupportedLanguages(): string[] {
|
|
58
|
-
return
|
|
50
|
+
return native.getSupportedLanguages();
|
|
59
51
|
}
|
package/src/html/index.ts
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTML to Markdown conversion powered by
|
|
3
|
-
*
|
|
4
|
-
* Conversion happens in a worker thread to avoid blocking the main thread.
|
|
2
|
+
* HTML to Markdown conversion powered by native bindings.
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
5
|
+
import { native } from "../native";
|
|
6
|
+
import { type RequestOptions, wrapRequestOptions } from "../request-options";
|
|
7
|
+
import type { HtmlToMarkdownOptions } from "./types";
|
|
10
8
|
|
|
11
9
|
export type { HtmlToMarkdownOptions } from "./types";
|
|
12
10
|
|
|
13
|
-
const pool = new WorkerPool<HtmlRequest, HtmlResponse>({
|
|
14
|
-
createWorker: () =>
|
|
15
|
-
new Worker(
|
|
16
|
-
resolveWorkerSpecifier({
|
|
17
|
-
compiled: "./packages/natives/src/html/worker.ts",
|
|
18
|
-
dev: new URL("./worker.ts", import.meta.url),
|
|
19
|
-
}),
|
|
20
|
-
),
|
|
21
|
-
maxWorkers: 2,
|
|
22
|
-
idleTimeoutMs: 30_000,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
11
|
/**
|
|
26
12
|
* Convert HTML to Markdown.
|
|
27
13
|
*
|
|
@@ -34,21 +20,5 @@ export async function htmlToMarkdown(
|
|
|
34
20
|
options?: HtmlToMarkdownOptions,
|
|
35
21
|
req?: RequestOptions,
|
|
36
22
|
): Promise<string> {
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
type: "convert",
|
|
40
|
-
html,
|
|
41
|
-
options,
|
|
42
|
-
},
|
|
43
|
-
req,
|
|
44
|
-
);
|
|
45
|
-
return response.markdown;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Terminate the HTML worker pool.
|
|
50
|
-
* Call this when shutting down to clean up resources.
|
|
51
|
-
*/
|
|
52
|
-
export function terminate(): void {
|
|
53
|
-
pool.terminate();
|
|
23
|
+
return wrapRequestOptions(() => native.htmlToMarkdown(html, options), req);
|
|
54
24
|
}
|