@heyhuynhgiabuu/pi-pretty 0.1.3 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +105 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyhuynhgiabuu/pi-pretty",
3
- "version": "0.1.3",
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 ICON_DIR = "📁";
163
- const ICON_DEFAULT = " ";
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
- ts: "🟦", tsx: "🟦", js: "🟨", jsx: "🟨", mjs: "🟨", cjs: "🟨",
167
- py: "🐍", rb: "💎", rs: "🦀", go: "🔵", java: "☕",
168
- c: "🔧", cpp: "🔧", h: "🔧", hpp: "🔧", cs: "🟪",
169
- swift: "🍊", kt: "🟣",
170
- html: "🌐", css: "🎨", scss: "🎨", less: "🎨",
171
- json: "📋", yaml: "📋", yml: "📋", toml: "📋",
172
- md: "📝", mdx: "📝",
173
- sql: "🗃️", sh: "🐚", bash: "🐚", zsh: "🐚",
174
- png: "🖼️", jpg: "🖼️", jpeg: "🖼️", gif: "🖼️", svg: "🖼️", webp: "🖼️",
175
- lock: "🔒", env: "🔐",
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": "📦", "package-lock.json": "📦",
180
- "tsconfig.json": "🟦", "biome.json": "🧹",
181
- ".gitignore": "🙈", ".env": "🔐", ".envrc": "🔐",
182
- dockerfile: "🐳", makefile: "🔧", gnumakefile: "🔧",
183
- "readme.md": "📖", "license": "⚖️",
184
- "cargo.toml": "🦀", "go.mod": "🔵", "pyproject.toml": "🐍",
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] ?? ICON_DEFAULT;
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 ? ICON_DIR : fileIcon(name);
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} ${fg}${name}${reset}`);
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(`${ICON_DIR} ${FG_BLUE}${BOLD}${dir}/${RST}`);
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} ${files[i]}`);
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} ${FG_BLUE}${BOLD}${file}${RST}`);
508
+ out.push(`${icon}${FG_BLUE}${BOLD}${file}${RST}`);
430
509
  currentFile = file;
431
510
  }
432
511