claude-highlight 1.0.1 → 1.0.2

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.
@@ -818,11 +818,13 @@ class ScreenModel {
818
818
  cols;
819
819
  chars;
820
820
  fg;
821
+ bg;
821
822
  ours;
822
823
  rule;
823
824
  x;
824
825
  y;
825
826
  curFg;
827
+ curBg;
826
828
  curOurs;
827
829
  saved;
828
830
  top;
@@ -844,12 +846,14 @@ class ScreenModel {
844
846
  invalidate() {
845
847
  this.chars = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
846
848
  this.fg = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
849
+ this.bg = Array.from({ length: this.rows }, () => new Array(this.cols).fill(null));
847
850
  this.ours = Array.from({ length: this.rows }, () => new Array(this.cols).fill(false));
848
851
  this.rule = new Array(this.rows).fill(null);
849
852
  this.x = this.y = 0;
850
853
  this.curFg = null;
854
+ this.curBg = null;
851
855
  this.curOurs = false;
852
- this.saved = [0, 0, null];
856
+ this.saved = [0, 0, null, null];
853
857
  this.top = 0;
854
858
  this.bot = this.rows - 1;
855
859
  this.alt = false;
@@ -860,6 +864,7 @@ class ScreenModel {
860
864
  }
861
865
  blankRow() {
862
866
  return [
867
+ new Array(this.cols).fill(null),
863
868
  new Array(this.cols).fill(null),
864
869
  new Array(this.cols).fill(null),
865
870
  new Array(this.cols).fill(false)
@@ -868,6 +873,7 @@ class ScreenModel {
868
873
  set(x, ch) {
869
874
  this.chars[this.y][x] = ch;
870
875
  this.fg[this.y][x] = this.curFg;
876
+ this.bg[this.y][x] = this.curBg;
871
877
  this.ours[this.y][x] = this.curOurs;
872
878
  this.dirty.add(this.y);
873
879
  this.rule[this.y] = null;
@@ -900,12 +906,14 @@ class ScreenModel {
900
906
  }
901
907
  scroll(n, up = true) {
902
908
  for (let k = 0;k < Math.max(n, 1); k++) {
903
- const [c, f, o] = this.blankRow();
909
+ const [c, f, bg, o] = this.blankRow();
904
910
  if (up) {
905
911
  this.chars.splice(this.top, 1);
906
912
  this.chars.splice(this.bot, 0, c);
907
913
  this.fg.splice(this.top, 1);
908
914
  this.fg.splice(this.bot, 0, f);
915
+ this.bg.splice(this.top, 1);
916
+ this.bg.splice(this.bot, 0, bg);
909
917
  this.ours.splice(this.top, 1);
910
918
  this.ours.splice(this.bot, 0, o);
911
919
  } else {
@@ -913,6 +921,8 @@ class ScreenModel {
913
921
  this.chars.splice(this.top, 0, c);
914
922
  this.fg.splice(this.bot, 1);
915
923
  this.fg.splice(this.top, 0, f);
924
+ this.bg.splice(this.bot, 1);
925
+ this.bg.splice(this.top, 0, bg);
916
926
  this.ours.splice(this.bot, 1);
917
927
  this.ours.splice(this.top, 0, o);
918
928
  }
@@ -927,10 +937,17 @@ class ScreenModel {
927
937
  while (i < toks.length) {
928
938
  const t = toks[i] || "0";
929
939
  const n = /^[0-9]+$/.test(t) ? parseInt(t, 10) : -1;
930
- if (n === 0 || n === 39) {
940
+ if (n === 0) {
931
941
  this.curFg = null;
942
+ this.curBg = null;
943
+ } else if (n === 39) {
944
+ this.curFg = null;
945
+ } else if (n === 49) {
946
+ this.curBg = null;
932
947
  } else if (n >= 30 && n <= 37 || n >= 90 && n <= 97) {
933
948
  this.curFg = t;
949
+ } else if (n >= 40 && n <= 47 || n >= 100 && n <= 107) {
950
+ this.curBg = t;
934
951
  } else if (n === 38) {
935
952
  if (toks[i + 1] === "5") {
936
953
  this.curFg = toks.slice(i, i + 3).join(";");
@@ -939,6 +956,14 @@ class ScreenModel {
939
956
  this.curFg = toks.slice(i, i + 5).join(";");
940
957
  i += 4;
941
958
  }
959
+ } else if (n === 48) {
960
+ if (toks[i + 1] === "5") {
961
+ this.curBg = toks.slice(i, i + 3).join(";");
962
+ i += 2;
963
+ } else if (toks[i + 1] === "2") {
964
+ this.curBg = toks.slice(i, i + 5).join(";");
965
+ i += 4;
966
+ }
942
967
  }
943
968
  i += 1;
944
969
  }
@@ -948,6 +973,7 @@ class ScreenModel {
948
973
  for (const x of cells) {
949
974
  this.chars[this.y][x] = " ";
950
975
  this.fg[this.y][x] = null;
976
+ this.bg[this.y][x] = null;
951
977
  this.ours[this.y][x] = false;
952
978
  }
953
979
  this.dirty.add(this.y);
@@ -1025,13 +1051,15 @@ class ScreenModel {
1025
1051
  } else if (fin === "L" || fin === "M") {
1026
1052
  const n = Math.max(a, 1);
1027
1053
  for (let k = 0;k < n; k++) {
1028
- const [c, f, o] = this.blankRow();
1054
+ const [c, f, bg, o] = this.blankRow();
1029
1055
  const at = fin === "L" ? this.y : this.bot;
1030
1056
  const from = fin === "L" ? this.bot : this.y;
1031
1057
  this.chars.splice(from, 1);
1032
1058
  this.chars.splice(at, 0, c);
1033
1059
  this.fg.splice(from, 1);
1034
1060
  this.fg.splice(at, 0, f);
1061
+ this.bg.splice(from, 1);
1062
+ this.bg.splice(at, 0, bg);
1035
1063
  this.ours.splice(from, 1);
1036
1064
  this.ours.splice(at, 0, o);
1037
1065
  }
@@ -1040,7 +1068,7 @@ class ScreenModel {
1040
1068
  this.rule = new Array(this.rows).fill(null);
1041
1069
  } else if (fin === "P" || fin === "@") {
1042
1070
  const n = Math.max(a, 1);
1043
- const chars = this.chars[this.y], fg = this.fg[this.y], ours = this.ours[this.y];
1071
+ const chars = this.chars[this.y], fg = this.fg[this.y], bg = this.bg[this.y], ours = this.ours[this.y];
1044
1072
  if (fin === "P") {
1045
1073
  chars.splice(this.x, n);
1046
1074
  while (chars.length < this.cols)
@@ -1048,6 +1076,9 @@ class ScreenModel {
1048
1076
  fg.splice(this.x, n);
1049
1077
  while (fg.length < this.cols)
1050
1078
  fg.push(null);
1079
+ bg.splice(this.x, n);
1080
+ while (bg.length < this.cols)
1081
+ bg.push(null);
1051
1082
  ours.splice(this.x, n);
1052
1083
  while (ours.length < this.cols)
1053
1084
  ours.push(false);
@@ -1057,6 +1088,8 @@ class ScreenModel {
1057
1088
  chars.pop();
1058
1089
  fg.splice(this.x, 0, null);
1059
1090
  fg.pop();
1091
+ bg.splice(this.x, 0, null);
1092
+ bg.pop();
1060
1093
  ours.splice(this.x, 0, false);
1061
1094
  ours.pop();
1062
1095
  }
@@ -1131,9 +1164,9 @@ class ScreenModel {
1131
1164
  continue;
1132
1165
  }
1133
1166
  if (nxt === 55) {
1134
- this.saved = [this.x, this.y, this.curFg];
1167
+ this.saved = [this.x, this.y, this.curFg, this.curBg];
1135
1168
  } else if (nxt === 56) {
1136
- [this.x, this.y, this.curFg] = this.saved;
1169
+ [this.x, this.y, this.curFg, this.curBg] = this.saved;
1137
1170
  this.curOurs = this.curFg !== null && this.palette.has(this.curFg);
1138
1171
  } else if (nxt === 77) {
1139
1172
  if (this.y === this.top)
@@ -1260,7 +1293,7 @@ class ScreenModel {
1260
1293
  const cells = span(idx[start], idx[end - 1] + 1);
1261
1294
  if (cells.some((c) => want[c] !== null))
1262
1295
  continue;
1263
- if (onlyUnstyled && cells.some((c) => this.fg[y][c] !== null && !this.ours[y][c])) {
1296
+ if (onlyUnstyled && cells.some((c) => this.fg[y][c] !== null && !this.ours[y][c] || this.bg[y][c] !== null)) {
1264
1297
  continue;
1265
1298
  }
1266
1299
  for (const c of cells)
@@ -1270,30 +1303,40 @@ class ScreenModel {
1270
1303
  return want;
1271
1304
  }
1272
1305
  corrections(rules, onlyUnstyled = true) {
1273
- if (!this.alt || this.dirty.size === 0)
1306
+ if (!this.alt)
1274
1307
  return Buffer.alloc(0);
1275
- const rows = [...this.dirty].sort((p, q) => p - q);
1276
- this.dirty = new Set;
1277
1308
  const offLimits = this.composerRows();
1309
+ const todo = new Set(this.dirty);
1310
+ for (const y of offLimits)
1311
+ todo.add(y);
1312
+ if (todo.size === 0)
1313
+ return Buffer.alloc(0);
1314
+ const rows = [...todo].sort((p, q) => p - q);
1315
+ this.dirty = new Set;
1278
1316
  const out = [];
1279
1317
  let len = 0, spent = false;
1318
+ const needsFix = (y, x, want) => {
1319
+ if (this.fg[y][x] === want[x])
1320
+ return false;
1321
+ return this.ours[y][x] || want[x] !== null && this.fg[y][x] === null;
1322
+ };
1280
1323
  for (const y of rows) {
1281
1324
  if (spent) {
1282
1325
  this.dirty.add(y);
1283
1326
  continue;
1284
1327
  }
1285
- if (!this.ours[y].some((v) => v))
1286
- continue;
1287
1328
  const want = this.desired(y, rules, onlyUnstyled, offLimits);
1329
+ if (!this.ours[y].some((v) => v) && !want.some((v) => v !== null))
1330
+ continue;
1288
1331
  let x = 0;
1289
1332
  while (x < this.cols) {
1290
- if (!(this.ours[y][x] && this.fg[y][x] !== want[x])) {
1333
+ if (!needsFix(y, x, want)) {
1291
1334
  x += 1;
1292
1335
  continue;
1293
1336
  }
1294
1337
  let start = x;
1295
1338
  const target = want[x];
1296
- while (x < this.cols && this.ours[y][x] && this.fg[y][x] !== want[x] && want[x] === target)
1339
+ while (x < this.cols && needsFix(y, x, want) && want[x] === target)
1297
1340
  x += 1;
1298
1341
  if (this.chars[y][start] === "" && start)
1299
1342
  start -= 1;
@@ -1,4 +1,4 @@
1
- .TH CLAUDE\-HIGHLIGHT 1 "2026-09-09" "claude-highlight 1.0.1" "User Commands"
1
+ .TH CLAUDE\-HIGHLIGHT 1 "2026-09-10" "claude-highlight 1.0.2" "User Commands"
2
2
  .SH NAME
3
3
  claude\-highlight \- run Claude Code behind a PTY that colors epistemic markers
4
4
  .SH SYNOPSIS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-highlight",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Colors epistemic markers in Claude Code's output, live, in the terminal",
6
6
  "keywords": [