@xynogen/pix-pretty 1.7.12 → 1.7.14
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 +18 -1
- package/package.json +2 -1
- package/src/config.ts +39 -4
- package/src/diff-render.ts +53 -12
- package/src/icon-persist.ts +10 -1
package/README.md
CHANGED
|
@@ -61,7 +61,24 @@ pi install npm:@xynogen/pix-pretty
|
|
|
61
61
|
|
|
62
62
|
## Configuration
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Configuration is read from **`~/.pi/agent/pix.json`** (the unified config file hosted by `@xynogen/pix-data/pix-config`). The `pretty` section of that file sets the defaults for theme, icon mode, and preview lines. Environment variables still override `pix.json` values.
|
|
65
|
+
|
|
66
|
+
> **Note:** `pix-config.ts` and `collapse.ts` previously shipped with `pix-pretty` — they have moved to `pix-data` (`@xynogen/pix-data/pix-config` and `@xynogen/pix-data/collapse`). Update any direct imports.
|
|
67
|
+
|
|
68
|
+
### `pix.json` — `pretty` section
|
|
69
|
+
|
|
70
|
+
```jsonc
|
|
71
|
+
{
|
|
72
|
+
"pretty": {
|
|
73
|
+
"theme": "monokai", // syntax-highlight theme
|
|
74
|
+
"icons": "nerd", // nerd | unicode | ascii
|
|
75
|
+
"maxPreviewLines": 50,
|
|
76
|
+
"diffColors": true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Environment Variables (override `pix.json`)
|
|
65
82
|
|
|
66
83
|
- `PRETTY_THEME` — color theme for syntax highlighting
|
|
67
84
|
- `PRETTY_MAX_HL_CHARS` — max characters to highlight (default: 80000)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xynogen/pix-pretty",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.14",
|
|
4
4
|
"description": "Enhanced tool output rendering with syntax highlighting, file icons, tree views, diff rendering, and FFF search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
+
"@xynogen/pix-data": "^0.3.0",
|
|
61
62
|
"cli-highlight": "^2.1.11",
|
|
62
63
|
"@ff-labs/fff-node": "^0.5.2",
|
|
63
64
|
"diff": "^7.0.0"
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { pixConfig } from "@xynogen/pix-data/pix-config";
|
|
4
5
|
import type { BundledTheme } from "./types.js";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_THEME: BundledTheme = "github-dark";
|
|
@@ -29,8 +30,10 @@ function readThemeFromSettings(agentDir?: string): BundledTheme | undefined {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
function resolvePrettyTheme(agentDir?: string): BundledTheme {
|
|
33
|
+
// Precedence: env → pix.json → settings.json → default
|
|
32
34
|
return (
|
|
33
35
|
(process.env.PRETTY_THEME as BundledTheme | undefined) ??
|
|
36
|
+
(pixConfig().pretty.theme as BundledTheme) ??
|
|
34
37
|
readThemeFromSettings(agentDir) ??
|
|
35
38
|
DEFAULT_THEME
|
|
36
39
|
);
|
|
@@ -49,14 +52,46 @@ export function envInt(name: string, fallback: number): number {
|
|
|
49
52
|
return Number.isFinite(v) && v > 0 ? v : fallback;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
// Precedence for numeric config: env var → pix.json → hardcoded default
|
|
56
|
+
function pixOrEnvInt(
|
|
57
|
+
envName: string,
|
|
58
|
+
pixValue: number,
|
|
59
|
+
fallback: number,
|
|
60
|
+
): number {
|
|
61
|
+
const env = process.env[envName];
|
|
62
|
+
if (env) {
|
|
63
|
+
const v = Number.parseInt(env, 10);
|
|
64
|
+
if (Number.isFinite(v) && v > 0) return v;
|
|
65
|
+
}
|
|
66
|
+
return pixValue !== fallback ? pixValue : fallback;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const pc = pixConfig().pretty;
|
|
70
|
+
|
|
71
|
+
export const MAX_HL_CHARS = pixOrEnvInt(
|
|
72
|
+
"PRETTY_MAX_HL_CHARS",
|
|
73
|
+
pc.maxHighlightChars,
|
|
74
|
+
80_000,
|
|
75
|
+
);
|
|
53
76
|
|
|
54
|
-
export const MAX_PREVIEW_LINES =
|
|
77
|
+
export const MAX_PREVIEW_LINES = pixOrEnvInt(
|
|
78
|
+
"PRETTY_MAX_PREVIEW_LINES",
|
|
79
|
+
pc.maxPreviewLines,
|
|
80
|
+
80,
|
|
81
|
+
);
|
|
55
82
|
|
|
56
|
-
export const CACHE_LIMIT =
|
|
83
|
+
export const CACHE_LIMIT = pixOrEnvInt(
|
|
84
|
+
"PRETTY_CACHE_LIMIT",
|
|
85
|
+
pc.cacheLimit,
|
|
86
|
+
128,
|
|
87
|
+
);
|
|
57
88
|
|
|
58
89
|
// --- Diff rendering limits (edit/write tools) ---
|
|
59
|
-
export const MAX_RENDER_LINES =
|
|
90
|
+
export const MAX_RENDER_LINES = pixOrEnvInt(
|
|
91
|
+
"PRETTY_MAX_RENDER_LINES",
|
|
92
|
+
pc.maxRenderLines,
|
|
93
|
+
150,
|
|
94
|
+
);
|
|
60
95
|
|
|
61
96
|
// Word-level emphasis only when paired del/add lines are at least this similar.
|
|
62
97
|
export const WORD_DIFF_MIN_SIM = 0.15;
|
package/src/diff-render.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// technique below works unchanged — diff backgrounds layer underneath and
|
|
9
9
|
// persist through fg switches.
|
|
10
10
|
|
|
11
|
+
import { pixConfig } from "@xynogen/pix-data/pix-config";
|
|
11
12
|
import * as Diff from "diff";
|
|
12
13
|
import { BG_BASE, BOLD, FG_DIM, FG_LNUM, FG_RULE, RST } from "./ansi.js";
|
|
13
14
|
import { MAX_HL_CHARS, MAX_RENDER_LINES, WORD_DIFF_MIN_SIM } from "./config.js";
|
|
@@ -44,21 +45,58 @@ function envBg(name: string, fallback: string): string {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
// ---------------------------------------------------------------------------
|
|
47
|
-
// Diff-specific ANSI (override via env
|
|
48
|
+
// Diff-specific ANSI (override via env → pix.json → hardcoded)
|
|
48
49
|
// ---------------------------------------------------------------------------
|
|
49
50
|
|
|
50
51
|
const DIM = "\x1b[2m";
|
|
51
52
|
|
|
53
|
+
function hexToBg(hex: string): string {
|
|
54
|
+
if (!/^#[0-9a-fA-F]{6}$/.test(hex)) return "";
|
|
55
|
+
const r = Number.parseInt(hex.slice(1, 3), 16);
|
|
56
|
+
const g = Number.parseInt(hex.slice(3, 5), 16);
|
|
57
|
+
const b = Number.parseInt(hex.slice(5, 7), 16);
|
|
58
|
+
return `\x1b[48;2;${r};${g};${b}m`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function hexToFg(hex: string): string {
|
|
62
|
+
if (!/^#[0-9a-fA-F]{6}$/.test(hex)) return "";
|
|
63
|
+
const r = Number.parseInt(hex.slice(1, 3), 16);
|
|
64
|
+
const g = Number.parseInt(hex.slice(3, 5), 16);
|
|
65
|
+
const b = Number.parseInt(hex.slice(5, 7), 16);
|
|
66
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const dc = pixConfig().pretty.diff;
|
|
70
|
+
|
|
52
71
|
// Subtle diff backgrounds — muted tones to let syntax fg shine through.
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
72
|
+
// Precedence: env → pix.json → hardcoded default
|
|
73
|
+
const BG_ADD = envBg("DIFF_BG_ADD", hexToBg(dc.bgAdd) || "\x1b[48;2;22;38;32m");
|
|
74
|
+
const BG_DEL = envBg("DIFF_BG_DEL", hexToBg(dc.bgDel) || "\x1b[48;2;45;25;25m");
|
|
75
|
+
const BG_ADD_W = envBg(
|
|
76
|
+
"DIFF_BG_ADD_HL",
|
|
77
|
+
hexToBg(dc.bgAddHighlight) || "\x1b[48;2;35;75;50m",
|
|
78
|
+
);
|
|
79
|
+
const BG_DEL_W = envBg(
|
|
80
|
+
"DIFF_BG_DEL_HL",
|
|
81
|
+
hexToBg(dc.bgDelHighlight) || "\x1b[48;2;80;35;35m",
|
|
82
|
+
);
|
|
83
|
+
const BG_GUTTER_ADD = envBg(
|
|
84
|
+
"DIFF_BG_GUTTER_ADD",
|
|
85
|
+
hexToBg(dc.bgGutterAdd) || "\x1b[48;2;18;32;26m",
|
|
86
|
+
);
|
|
87
|
+
const BG_GUTTER_DEL = envBg(
|
|
88
|
+
"DIFF_BG_GUTTER_DEL",
|
|
89
|
+
hexToBg(dc.bgGutterDel) || "\x1b[48;2;38;22;22m",
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const FG_ADD = envFg(
|
|
93
|
+
"DIFF_FG_ADD",
|
|
94
|
+
hexToFg(dc.fgAdd) || "\x1b[38;2;100;180;120m",
|
|
95
|
+
);
|
|
96
|
+
const FG_DEL = envFg(
|
|
97
|
+
"DIFF_FG_DEL",
|
|
98
|
+
hexToFg(dc.fgDel) || "\x1b[38;2;200;100;100m",
|
|
99
|
+
);
|
|
62
100
|
const FG_STRIPE = "\x1b[38;2;40;40;40m"; // diagonal stripes on filler cells
|
|
63
101
|
|
|
64
102
|
const BORDER_BAR = "▌";
|
|
@@ -76,8 +114,11 @@ const MAX_TERM_WIDTH = 210;
|
|
|
76
114
|
|
|
77
115
|
const MAX_PREVIEW_LINES = envInt("PRETTY_MAX_PREVIEW_LINES", 80);
|
|
78
116
|
|
|
79
|
-
const SPLIT_MIN_WIDTH = envInt("DIFF_SPLIT_MIN_WIDTH", 150);
|
|
80
|
-
const SPLIT_MIN_CODE_WIDTH = envInt(
|
|
117
|
+
const SPLIT_MIN_WIDTH = envInt("DIFF_SPLIT_MIN_WIDTH", dc.splitMinWidth || 150);
|
|
118
|
+
const SPLIT_MIN_CODE_WIDTH = envInt(
|
|
119
|
+
"DIFF_SPLIT_MIN_CODE_WIDTH",
|
|
120
|
+
dc.splitMinCodeWidth || 60,
|
|
121
|
+
);
|
|
81
122
|
const SPLIT_MAX_WRAP_RATIO = 0.2;
|
|
82
123
|
const SPLIT_MAX_WRAP_LINES = 8;
|
|
83
124
|
|
package/src/icon-persist.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
15
|
import { dirname, join } from "node:path";
|
|
16
16
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
17
|
+
import { pixConfig } from "@xynogen/pix-data/pix-config";
|
|
17
18
|
import { ICON_MODES, type IconMode, setIconMode } from "./icon-catalog.js";
|
|
18
19
|
|
|
19
20
|
function isIconMode(m: string): m is IconMode {
|
|
@@ -63,8 +64,16 @@ export function saveIconMode(mode: IconMode): void {
|
|
|
63
64
|
/**
|
|
64
65
|
* Apply the persisted mode (if any) to the catalog. Called once at extension
|
|
65
66
|
* load so the env-seeded default is overridden by the user's saved choice.
|
|
67
|
+
*
|
|
68
|
+
* Precedence: env PRETTY_ICONS → pretty.json → pix.json pretty.icons → default ("nerd")
|
|
66
69
|
*/
|
|
67
70
|
export function initIconMode(): void {
|
|
68
71
|
const saved = loadIconMode();
|
|
69
|
-
if (saved)
|
|
72
|
+
if (saved) {
|
|
73
|
+
setIconMode(saved);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// No persisted choice — try pix.json
|
|
77
|
+
const pixIcons = pixConfig().pretty.icons;
|
|
78
|
+
if (pixIcons && isIconMode(pixIcons)) setIconMode(pixIcons);
|
|
70
79
|
}
|