diff --git a/ops.ts b/ops.ts index a52485d..776bfed 100644 --- a/ops.ts +++ b/ops.ts @@ -202,14 +202,18 @@ export function pack( case OP_TEXT: { view.setUint32(o, OP_TEXT, true); o += 4; - view.setUint32(o, op.color ?? 0xFFFFFFFF, true); + // No explicit color: leave the terminal default foreground by writing + // 0 and setting ATTR_DEFAULT (0x80 in the attrs byte). The C path ORs + // it into fg and emit_attr skips the foreground SGR (mirrors unset bg). + let textDefault = op.color === undefined; + view.setUint32(o, op.color ?? 0, true); o += 4; view.setUint32( o, (op.fontSize ?? 1) | ((op.fontId ?? 0) << 8) | ((op.wrap ?? 0) << 16) | - ((op.attrs ?? 0) << 24), + (((op.attrs ?? 0) | (textDefault ? 0x80 : 0)) << 24), true, ); o += 4; diff --git a/test/default-foreground.test.ts b/test/default-foreground.test.ts new file mode 100644 index 0000000..1a51593 --- /dev/null +++ b/test/default-foreground.test.ts @@ -0,0 +1,15 @@ +import { text } from "../ops.ts"; +import { createTerm } from "../term.ts"; +import { describe, expect, it } from "./suite.ts"; + +const decode = (b: Uint8Array) => new TextDecoder().decode(b); + +describe("true default foreground", () => { + it("emits uncolored text with no concrete foreground", async () => { + let term = await createTerm({ width: 12, height: 1 }); + let ansi = decode(term.render([text("hi")]).output); + + expect(ansi).toContain("hi"); + expect(ansi).not.toContain("\x1b[38;2;255;255;255"); + }); +});