#1037

Feature Request: Support OSC 10/11 foreground/background color query APIs

OpenDCjanusopened 8mo ago

Background

Codex CLI previously implemented OSC 10/11 color queries at the application layer and later ran into input stream contention issues: the hard part isn’t sending the query sequence, but safely reading the reply. Because OSC color query replies share the same input stream as keyboard/mouse events, an application-layer implementation can easily race with the event loop, leading to timeouts, parse failures, or accidentally consuming/disrupting other input data.

In openai/codex#5935, Codex addressed this by depending on a crossterm fork that includes color query support, pushing this capability down into the library layer and coordinating it with crossterm’s event reading internally. That PR description also notes that it resolves some user-visible input issues (e.g. openai/codex#4945, openai/codex#5603).

Proposal

It would be great if crossterm could natively support color query APIs for OSC 10/11 and handle coordination with crossterm::event reading internally. For terminals that don’t support the feature, return None (or other suggestions):

use std::io;

use crossterm::style::Color;

pub fn query_foreground_color() -> io::Result<Option<Color>>;
pub fn query_background_color() -> io::Result<Option<Color>>;

Notes:

  • The exact behavior for cases like timeouts / unrecognized replies is open to suggestions.

Goals

  1. Reduce ecosystem fragmentation so other users with similar needs can rely on upstream crossterm directly;
  2. Reduce Codex’s long-term cost of tracking crossterm updates, and make it feasible to return to upstream crossterm instead of relying on a fork indefinitely.

References

If this direction makes sense, I’m happy to submit a minimal PR for discussion.

Note: Since I’m not a native English speaker, I used an AI agent to help draft the wording, and I reviewed/edited it before posting.

Activity

3
MartenBE25d ago

This seems very handy, is there any update on this?

joshka21d ago

This has been on my list of things I'd like to see in Crossterm since 2025, when I was working at OpenAI and discussed it directly with Jeremy (@nornagon) as it was being used in Codex. My initial thought was that we could probably bring his changes over fairly directly. Looking into Codex's experience since then, though, there's considerably more involved.

My recollection from discussing this with Jeremy is that some of the difficulty comes from Crossterm's async architecture: the async interface is layered over a thread-driven reader with shared locking, rather than asynchronous operation being built through the input core. That makes coordinating queries, replies, cancellation, and timeouts awkward. Moving color-query handling into Crossterm avoids a competing application-level reader, but does not by itself resolve those coordination problems.

Several parts of Codex's experience are relevant:

There are also smaller implementation issues in the reference patch. Its /dev/tty path opens a read-only handle and then attempts to write through it, causing a fallback to stdout. Its RGB conversion computes 0x8000 / 257 as 127 while the added tests expect 128. Those details need correction, but they are relatively straightforward compared with the input ownership and recovery questions.

On compatibility, the original color-query patch adds a private InternalEvent variant, so it does not itself break exhaustive matches on public Event. Live color-scheme notifications do extend that public enum. Making Event non-exhaustive would also be a breaking change, and is a broader API-policy decision already discussed in the bracketed-paste issue.

So yes, the capability makes sense, but I don't think importing the existing patch gets us close to a complete solution. It opens up substantial engineering work, including existing problems that are only indirectly related to color queries and would need to be resolved along the way. Given that depth and scope, this isn't something I'd want to invest time in myself. Jeremy's implementation, Codex's subsequent changes, and the existing query and color-query proposals provide useful context for anyone taking it on, but I wouldn't characterize it as a straightforward patch import.

Assisted by Codex in digging into the implementation, related Crossterm issues, and the deeper problems and subsequent fixes in Codex's terminal input handling. This is based on source and discussion review, rather than new terminal reproductions.

DCjanus21d ago

@MartenBE Thanks for following up. I did try implementing this after opening the issue, but I found it much harder to make robust on top of Crossterm’s current input architecture than I initially expected. @joshka’s analysis matches the difficulties I ran into.

For a specific application such as Codex, it may be possible to make a usable implementation by controlling when queries run and accepting some application-specific constraints. For a general-purpose library, though, I would want stronger guarantees around interaction with the event reader, timeouts, late or partial replies, and preserving ordinary user input.

My current impression is that a reliable upstream implementation would need substantial changes to the input-reading and parsing architecture, rather than just adding OSC 10/11 support. I don’t currently have a solution that I would be comfortable proposing for general use.

I also opened a similar PR for termwiz, the terminal library in the WezTerm repository: wezterm/wezterm#7690. Its streaming VT parser already understands OSC dynamic-color sequences, which seems like a better foundation for exploring this. That PR is still a draft, however: the current probe can block when a terminal does not reply and can consume unrelated input, so it still needs a bounded no-response path and better input handling.

I still think this capability would be useful, but I underestimated the work needed to make it reliable at the library level.