@heyhuynhgiabuu/pi-pretty 0.1.2 → 0.1.4
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/package.json +1 -1
- package/src/index.ts +128 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyhuynhgiabuu/pi-pretty",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Pretty terminal output for pi — syntax-highlighted file reads, colored bash output, tree-view directory listings, and more.",
|
|
5
5
|
"author": "huynhgiabuu",
|
|
6
6
|
"license": "MIT",
|
package/src/index.ts
CHANGED
|
@@ -156,39 +156,118 @@ function lang(fp: string): BundledLanguage | undefined {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// ---------------------------------------------------------------------------
|
|
159
|
-
// File-type icons
|
|
159
|
+
// File-type icons — Nerd Font glyphs (Seti-UI + Devicons, stable in NF v3+)
|
|
160
|
+
//
|
|
161
|
+
// Requires a Nerd Font installed (e.g., JetBrainsMono Nerd Font, FiraCode NF).
|
|
162
|
+
// Fallback: set PRETTY_ICONS=none to disable icons.
|
|
160
163
|
// ---------------------------------------------------------------------------
|
|
161
164
|
|
|
162
|
-
const
|
|
163
|
-
const
|
|
165
|
+
const ICONS_MODE = (process.env.PRETTY_ICONS ?? "nerd").toLowerCase();
|
|
166
|
+
const USE_ICONS = ICONS_MODE !== "none" && ICONS_MODE !== "off";
|
|
167
|
+
|
|
168
|
+
// Nerd Font codepoints + ANSI color per file type
|
|
169
|
+
const NF_DIR = `${FG_BLUE}\ue5ff${RST}`; // folder
|
|
170
|
+
const NF_DIR_OPEN = `${FG_BLUE}\ue5fe${RST}`; // folder open
|
|
171
|
+
const NF_DEFAULT = `${FG_DIM}\uf15b${RST}`; // generic file
|
|
164
172
|
|
|
165
173
|
const EXT_ICON: Record<string, string> = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
// TypeScript / JavaScript
|
|
175
|
+
ts: `\x1b[38;2;49;120;198m\ue628${RST}`, // blue
|
|
176
|
+
tsx: `\x1b[38;2;49;120;198m\ue7ba${RST}`, // react blue
|
|
177
|
+
js: `\x1b[38;2;241;224;90m\ue74e${RST}`, // yellow
|
|
178
|
+
jsx: `\x1b[38;2;97;218;251m\ue7ba${RST}`, // react cyan
|
|
179
|
+
mjs: `\x1b[38;2;241;224;90m\ue74e${RST}`,
|
|
180
|
+
cjs: `\x1b[38;2;241;224;90m\ue74e${RST}`,
|
|
181
|
+
|
|
182
|
+
// Systems / Backend
|
|
183
|
+
py: `\x1b[38;2;55;118;171m\ue73c${RST}`, // python blue
|
|
184
|
+
rs: `\x1b[38;2;222;165;132m\ue7a8${RST}`, // rust orange
|
|
185
|
+
go: `\x1b[38;2;0;173;216m\ue724${RST}`, // go cyan
|
|
186
|
+
java: `\x1b[38;2;204;62;68m\ue738${RST}`, // java red
|
|
187
|
+
swift: `\x1b[38;2;255;172;77m\ue755${RST}`, // swift orange
|
|
188
|
+
rb: `\x1b[38;2;204;52;45m\ue739${RST}`, // ruby red
|
|
189
|
+
kt: `\x1b[38;2;126;103;200m\ue634${RST}`, // kotlin purple
|
|
190
|
+
c: `\x1b[38;2;85;154;211m\ue61e${RST}`, // c blue
|
|
191
|
+
cpp: `\x1b[38;2;85;154;211m\ue61d${RST}`, // cpp blue
|
|
192
|
+
h: `\x1b[38;2;140;160;185m\ue61e${RST}`, // header muted
|
|
193
|
+
hpp: `\x1b[38;2;140;160;185m\ue61d${RST}`,
|
|
194
|
+
cs: `\x1b[38;2;104;33;122m\ue648${RST}`, // c# purple
|
|
195
|
+
|
|
196
|
+
// Web
|
|
197
|
+
html: `\x1b[38;2;228;77;38m\ue736${RST}`, // html orange
|
|
198
|
+
css: `\x1b[38;2;66;165;245m\ue749${RST}`, // css blue
|
|
199
|
+
scss: `\x1b[38;2;207;100;154m\ue749${RST}`, // scss pink
|
|
200
|
+
less: `\x1b[38;2;66;165;245m\ue749${RST}`,
|
|
201
|
+
vue: `\x1b[38;2;65;184;131m\ue6a0${RST}`, // vue green
|
|
202
|
+
svelte: `\x1b[38;2;255;62;0m\ue697${RST}`, // svelte red-orange
|
|
203
|
+
|
|
204
|
+
// Config / Data
|
|
205
|
+
json: `\x1b[38;2;241;224;90m\ue60b${RST}`, // json yellow
|
|
206
|
+
jsonc: `\x1b[38;2;241;224;90m\ue60b${RST}`,
|
|
207
|
+
yaml: `\x1b[38;2;160;116;196m\ue6a8${RST}`, // yaml purple
|
|
208
|
+
yml: `\x1b[38;2;160;116;196m\ue6a8${RST}`,
|
|
209
|
+
toml: `\x1b[38;2;160;116;196m\ue6b2${RST}`, // toml purple
|
|
210
|
+
xml: `\x1b[38;2;228;77;38m\ue619${RST}`, // xml orange
|
|
211
|
+
sql: `\x1b[38;2;218;218;218m\ue706${RST}`, // sql gray
|
|
212
|
+
|
|
213
|
+
// Markdown / Docs
|
|
214
|
+
md: `\x1b[38;2;66;165;245m\ue73e${RST}`, // markdown blue
|
|
215
|
+
mdx: `\x1b[38;2;66;165;245m\ue73e${RST}`,
|
|
216
|
+
|
|
217
|
+
// Shell / Scripts
|
|
218
|
+
sh: `\x1b[38;2;137;180;130m\ue795${RST}`, // shell green
|
|
219
|
+
bash: `\x1b[38;2;137;180;130m\ue795${RST}`,
|
|
220
|
+
zsh: `\x1b[38;2;137;180;130m\ue795${RST}`,
|
|
221
|
+
fish: `\x1b[38;2;137;180;130m\ue795${RST}`,
|
|
222
|
+
lua: `\x1b[38;2;81;160;207m\ue620${RST}`, // lua blue
|
|
223
|
+
php: `\x1b[38;2;137;147;186m\ue73d${RST}`, // php purple
|
|
224
|
+
dart: `\x1b[38;2;87;182;240m\ue798${RST}`, // dart blue
|
|
225
|
+
|
|
226
|
+
// Images
|
|
227
|
+
png: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
228
|
+
jpg: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
229
|
+
jpeg: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
230
|
+
gif: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
231
|
+
svg: `\x1b[38;2;255;180;50m\uf1c5${RST}`,
|
|
232
|
+
webp: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
233
|
+
ico: `\x1b[38;2;160;116;196m\uf1c5${RST}`,
|
|
234
|
+
|
|
235
|
+
// Misc
|
|
236
|
+
lock: `\x1b[38;2;130;130;130m\uf023${RST}`, // lock gray
|
|
237
|
+
env: `\x1b[38;2;241;224;90m\ue615${RST}`, // env yellow
|
|
238
|
+
graphql: `\x1b[38;2;224;51;144m\ue662${RST}`, // graphql pink
|
|
239
|
+
dockerfile: `\x1b[38;2;56;152;236m\ue7b0${RST}`,
|
|
176
240
|
};
|
|
177
241
|
|
|
178
242
|
const NAME_ICON: Record<string, string> = {
|
|
179
|
-
"package.json":
|
|
180
|
-
"
|
|
181
|
-
".
|
|
182
|
-
|
|
183
|
-
"
|
|
184
|
-
"
|
|
243
|
+
"package.json": `\x1b[38;2;137;180;130m\ue71e${RST}`, // npm green
|
|
244
|
+
"package-lock.json": `\x1b[38;2;130;130;130m\ue71e${RST}`, // npm gray
|
|
245
|
+
"tsconfig.json": `\x1b[38;2;49;120;198m\ue628${RST}`, // ts blue
|
|
246
|
+
"biome.json": `\x1b[38;2;96;165;250m\ue615${RST}`, // config blue
|
|
247
|
+
".gitignore": `\x1b[38;2;222;165;132m\ue702${RST}`, // git orange
|
|
248
|
+
".git": `\x1b[38;2;222;165;132m\ue702${RST}`,
|
|
249
|
+
".env": `\x1b[38;2;241;224;90m\ue615${RST}`, // env yellow
|
|
250
|
+
".envrc": `\x1b[38;2;241;224;90m\ue615${RST}`,
|
|
251
|
+
"dockerfile": `\x1b[38;2;56;152;236m\ue7b0${RST}`, // docker blue
|
|
252
|
+
"makefile": `\x1b[38;2;130;130;130m\ue615${RST}`, // make gray
|
|
253
|
+
"gnumakefile": `\x1b[38;2;130;130;130m\ue615${RST}`,
|
|
254
|
+
"readme.md": `\x1b[38;2;66;165;245m\ue73e${RST}`, // readme blue
|
|
255
|
+
"license": `\x1b[38;2;218;218;218m\ue60a${RST}`, // license white
|
|
256
|
+
"cargo.toml": `\x1b[38;2;222;165;132m\ue7a8${RST}`, // rust
|
|
257
|
+
"go.mod": `\x1b[38;2;0;173;216m\ue724${RST}`, // go
|
|
258
|
+
"pyproject.toml": `\x1b[38;2;55;118;171m\ue73c${RST}`, // python
|
|
185
259
|
};
|
|
186
260
|
|
|
187
261
|
function fileIcon(fp: string): string {
|
|
262
|
+
if (!USE_ICONS) return "";
|
|
188
263
|
const base = basename(fp).toLowerCase();
|
|
189
|
-
if (NAME_ICON[base]) return NAME_ICON[base]
|
|
264
|
+
if (NAME_ICON[base]) return `${NAME_ICON[base]} `;
|
|
190
265
|
const ext = extname(fp).slice(1).toLowerCase();
|
|
191
|
-
return EXT_ICON[ext]
|
|
266
|
+
return EXT_ICON[ext] ? `${EXT_ICON[ext]} ` : `${NF_DEFAULT} `;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function dirIcon(): string {
|
|
270
|
+
return USE_ICONS ? `${NF_DIR} ` : "";
|
|
192
271
|
}
|
|
193
272
|
|
|
194
273
|
// ---------------------------------------------------------------------------
|
|
@@ -336,11 +415,11 @@ function renderTree(text: string, basePath: string): string {
|
|
|
336
415
|
// Detect directories (entries ending with /)
|
|
337
416
|
const isDir = entry.endsWith("/");
|
|
338
417
|
const name = isDir ? entry.slice(0, -1) : entry;
|
|
339
|
-
const icon = isDir ?
|
|
418
|
+
const icon = isDir ? dirIcon() : fileIcon(name);
|
|
340
419
|
const fg = isDir ? FG_BLUE + BOLD : "";
|
|
341
420
|
const reset = isDir ? RST : "";
|
|
342
421
|
|
|
343
|
-
out.push(`${connector}${icon}
|
|
422
|
+
out.push(`${connector}${icon}${fg}${name}${reset}`);
|
|
344
423
|
}
|
|
345
424
|
|
|
346
425
|
if (total > MAX_PREVIEW_LINES) {
|
|
@@ -372,7 +451,7 @@ function renderFindResults(text: string): string {
|
|
|
372
451
|
|
|
373
452
|
for (const [dir, files] of groups) {
|
|
374
453
|
if (count > 0) out.push(""); // blank line between groups
|
|
375
|
-
out.push(`${
|
|
454
|
+
out.push(`${dirIcon()}${FG_BLUE}${BOLD}${dir}/${RST}`);
|
|
376
455
|
for (let i = 0; i < files.length; i++) {
|
|
377
456
|
if (count >= MAX_PREVIEW_LINES) {
|
|
378
457
|
out.push(
|
|
@@ -383,7 +462,7 @@ function renderFindResults(text: string): string {
|
|
|
383
462
|
const isLast = i === files.length - 1;
|
|
384
463
|
const prefix = isLast ? "└── " : "├── ";
|
|
385
464
|
const icon = fileIcon(files[i]);
|
|
386
|
-
out.push(` ${FG_RULE}${prefix}${RST}${icon}
|
|
465
|
+
out.push(` ${FG_RULE}${prefix}${RST}${icon}${files[i]}`);
|
|
387
466
|
count++;
|
|
388
467
|
}
|
|
389
468
|
}
|
|
@@ -426,7 +505,7 @@ async function renderGrepResults(
|
|
|
426
505
|
if (file !== currentFile) {
|
|
427
506
|
if (currentFile) out.push(""); // blank line between files
|
|
428
507
|
const icon = fileIcon(file);
|
|
429
|
-
out.push(`${icon}
|
|
508
|
+
out.push(`${icon}${FG_BLUE}${BOLD}${file}${RST}`);
|
|
430
509
|
currentFile = file;
|
|
431
510
|
}
|
|
432
511
|
|
|
@@ -639,10 +718,29 @@ export default function piPrettyExtension(pi: any): void {
|
|
|
639
718
|
|
|
640
719
|
const d = result.details;
|
|
641
720
|
if (d?._type === "bashResult") {
|
|
642
|
-
const { summary } = renderBashOutput(d.text, d.exitCode);
|
|
643
|
-
const lines = d.text.split("\n")
|
|
644
|
-
const
|
|
645
|
-
|
|
721
|
+
const { summary, body } = renderBashOutput(d.text, d.exitCode);
|
|
722
|
+
const lines = d.text.split("\n");
|
|
723
|
+
const lineCount = lines.length;
|
|
724
|
+
const lineInfo = lineCount > 1 ? ` ${FG_DIM}(${lineCount} lines)${RST}` : "";
|
|
725
|
+
const header = ` ${summary}${lineInfo}`;
|
|
726
|
+
|
|
727
|
+
// Show output content
|
|
728
|
+
if (d.text.trim()) {
|
|
729
|
+
const maxShow = ctx.expanded ? lineCount : MAX_PREVIEW_LINES;
|
|
730
|
+
const show = lines.slice(0, maxShow);
|
|
731
|
+
const tw = termW();
|
|
732
|
+
const out: string[] = [header, rule(tw)];
|
|
733
|
+
for (const line of show) {
|
|
734
|
+
out.push(` ${line}`);
|
|
735
|
+
}
|
|
736
|
+
out.push(rule(tw));
|
|
737
|
+
if (lineCount > maxShow) {
|
|
738
|
+
out.push(`${FG_DIM} … ${lineCount - maxShow} more lines${RST}`);
|
|
739
|
+
}
|
|
740
|
+
text.setText(out.join("\n"));
|
|
741
|
+
} else {
|
|
742
|
+
text.setText(header);
|
|
743
|
+
}
|
|
646
744
|
return text;
|
|
647
745
|
}
|
|
648
746
|
|