opencode-db-search 1.0.0 → 1.1.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/opencode-db-search.ts +127 -8
- package/package.json +1 -1
package/opencode-db-search.ts
CHANGED
|
@@ -283,6 +283,112 @@ function kvBlock(pairs: Array<[string, string]>): void {
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Word-wrap text to fit within a given width.
|
|
288
|
+
* Breaks at spaces; falls back to hard-break for words exceeding width.
|
|
289
|
+
*/
|
|
290
|
+
function wordWrap(text: string, width: number): string[] {
|
|
291
|
+
if (width <= 0) return [text];
|
|
292
|
+
const words = text.split(/\s+/);
|
|
293
|
+
const lines: string[] = [];
|
|
294
|
+
let line = "";
|
|
295
|
+
for (const word of words) {
|
|
296
|
+
if (word === "") continue;
|
|
297
|
+
if (line.length === 0) {
|
|
298
|
+
// Hard-break words longer than width
|
|
299
|
+
if (visibleLen(word) > width) {
|
|
300
|
+
let remaining = word;
|
|
301
|
+
while (visibleLen(remaining) > width) {
|
|
302
|
+
lines.push(remaining.slice(0, width));
|
|
303
|
+
remaining = remaining.slice(width);
|
|
304
|
+
}
|
|
305
|
+
line = remaining;
|
|
306
|
+
} else {
|
|
307
|
+
line = word;
|
|
308
|
+
}
|
|
309
|
+
} else if (visibleLen(line) + 1 + visibleLen(word) <= width) {
|
|
310
|
+
line += " " + word;
|
|
311
|
+
} else {
|
|
312
|
+
lines.push(line);
|
|
313
|
+
if (visibleLen(word) > width) {
|
|
314
|
+
let remaining = word;
|
|
315
|
+
while (visibleLen(remaining) > width) {
|
|
316
|
+
lines.push(remaining.slice(0, width));
|
|
317
|
+
remaining = remaining.slice(width);
|
|
318
|
+
}
|
|
319
|
+
line = remaining;
|
|
320
|
+
} else {
|
|
321
|
+
line = word;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (line) lines.push(line);
|
|
326
|
+
return lines.length > 0 ? lines : [""];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Render a search result card with box-drawing borders.
|
|
331
|
+
*/
|
|
332
|
+
function card(opts: {
|
|
333
|
+
id: string;
|
|
334
|
+
badge: string;
|
|
335
|
+
title: string;
|
|
336
|
+
subtitle?: string;
|
|
337
|
+
body: string[];
|
|
338
|
+
width?: number;
|
|
339
|
+
maxBodyLines?: number;
|
|
340
|
+
}): void {
|
|
341
|
+
const w = opts.width || 80;
|
|
342
|
+
const inner = w - 4; // "│ " + content + " │"
|
|
343
|
+
const maxLines = opts.maxBodyLines || 6;
|
|
344
|
+
const dim = (s: string) => ansi("2", s);
|
|
345
|
+
|
|
346
|
+
// Top border: ┌─ id ──...── badge ─┐
|
|
347
|
+
const idStr = ` ${opts.id} `;
|
|
348
|
+
const badgeStr = ` ${opts.badge} `;
|
|
349
|
+
const fill = w - 2 - idStr.length - badgeStr.length; // -2 for ┌ and ┐
|
|
350
|
+
const topLine =
|
|
351
|
+
dim(BOX.tl + BOX.h) +
|
|
352
|
+
ansi("1;36", idStr) +
|
|
353
|
+
dim(BOX.h.repeat(Math.max(1, fill))) +
|
|
354
|
+
dim(badgeStr) +
|
|
355
|
+
dim(BOX.h + BOX.tr);
|
|
356
|
+
console.log(topLine);
|
|
357
|
+
|
|
358
|
+
// Body line renderer
|
|
359
|
+
const printLine = (text: string) => {
|
|
360
|
+
const padded = pad(text, inner);
|
|
361
|
+
// Truncate if pad somehow exceeds inner width
|
|
362
|
+
const display = visibleLen(padded) > inner ? trunc(padded, inner) : padded;
|
|
363
|
+
console.log(`${dim(BOX.v)} ${display} ${dim(BOX.v)}`);
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// Title (bold)
|
|
367
|
+
printLine(ansi("1", trunc(opts.title, inner)));
|
|
368
|
+
|
|
369
|
+
// Subtitle (dimmed)
|
|
370
|
+
if (opts.subtitle) {
|
|
371
|
+
printLine(ansi("2", trunc(opts.subtitle, inner)));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Blank separator before body
|
|
375
|
+
if (opts.body.length > 0) {
|
|
376
|
+
printLine("");
|
|
377
|
+
let printed = 0;
|
|
378
|
+
for (const line of opts.body) {
|
|
379
|
+
if (printed >= maxLines) {
|
|
380
|
+
printLine(ansi("2", "…"));
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
printLine(line);
|
|
384
|
+
printed++;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Bottom border
|
|
389
|
+
console.log(dim(BOX.bl + BOX.h.repeat(w - 2) + BOX.br));
|
|
390
|
+
}
|
|
391
|
+
|
|
286
392
|
function size(bytes: number): string {
|
|
287
393
|
if (bytes < 1024) return `${bytes} B`;
|
|
288
394
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -953,7 +1059,7 @@ function cmdSearch(db: Database) {
|
|
|
953
1059
|
)
|
|
954
1060
|
.all(...w.params, limit) as any[];
|
|
955
1061
|
|
|
956
|
-
const radius =
|
|
1062
|
+
const radius = 250;
|
|
957
1063
|
for (const r of rows) {
|
|
958
1064
|
const pv = partPreview(r.part_data);
|
|
959
1065
|
const idx = pv.toLowerCase().indexOf(query.toLowerCase());
|
|
@@ -968,7 +1074,7 @@ function cmdSearch(db: Database) {
|
|
|
968
1074
|
title: r.title,
|
|
969
1075
|
directory: r.directory,
|
|
970
1076
|
match: "part",
|
|
971
|
-
preview: ctx || pv.slice(0,
|
|
1077
|
+
preview: ctx || pv.slice(0, 500),
|
|
972
1078
|
updated: r.time_updated,
|
|
973
1079
|
created: r.time_created,
|
|
974
1080
|
});
|
|
@@ -986,13 +1092,26 @@ function cmdSearch(db: Database) {
|
|
|
986
1092
|
console.log(`No results for "${query}".`);
|
|
987
1093
|
return;
|
|
988
1094
|
}
|
|
1095
|
+
|
|
1096
|
+
const cardWidth = Math.min(width, termWidth());
|
|
1097
|
+
const cardInner = cardWidth - 4;
|
|
989
1098
|
for (const r of final) {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1099
|
+
// For title matches, the title is already shown — skip redundant preview
|
|
1100
|
+
const body =
|
|
1101
|
+
r.match === "title"
|
|
1102
|
+
? []
|
|
1103
|
+
: wordWrap(r.preview, cardInner).map((line) => highlight(line, query));
|
|
1104
|
+
card({
|
|
1105
|
+
id: r.session,
|
|
1106
|
+
badge: r.match,
|
|
1107
|
+
title:
|
|
1108
|
+
r.match === "title"
|
|
1109
|
+
? highlight(r.title || "(untitled)", query)
|
|
1110
|
+
: r.title || "(untitled)",
|
|
1111
|
+
subtitle: r.directory || undefined,
|
|
1112
|
+
body,
|
|
1113
|
+
width: cardWidth,
|
|
1114
|
+
});
|
|
996
1115
|
console.log();
|
|
997
1116
|
}
|
|
998
1117
|
console.log(`${final.length} result(s)`);
|
package/package.json
CHANGED