mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-21 16:41:26 +00:00
lib-vt: C API for SGR parser (#9352)
This exposes the SGR parser to the C and Wasm APIs. An example is shown
in c-vt-sgr.
Compressed example:
```c
#include <assert.h>
#include <stdio.h>
#include <ghostty/vt.h>
int main() {
// Create parser
GhosttySgrParser parser;
assert(ghostty_sgr_new(NULL, &parser) == GHOSTTY_SUCCESS);
// Parse: ESC[1;31m (bold + red foreground)
uint16_t params[] = {1, 31};
assert(ghostty_sgr_set_params(parser, params, NULL, 2) == GHOSTTY_SUCCESS);
printf("Parsing: ESC[1;31m\n\n");
// Iterate through attributes
GhosttySgrAttribute attr;
while (ghostty_sgr_next(parser, &attr)) {
switch (attr.tag) {
case GHOSTTY_SGR_ATTR_BOLD:
printf("✓ Bold enabled\n");
break;
case GHOSTTY_SGR_ATTR_FG_8:
printf("✓ Foreground color: %d (red)\n", attr.value.fg_8);
break;
default:
break;
}
}
ghostty_sgr_free(parser);
return 0;
}
```
**AI disclosure:** Amp wrote most of the C headers, but I verified it
all. https://ampcode.com/threads/T-d9f145cb-e6ef-48a8-ad63-e5fc85c0d43e
This commit is contained in:
committed by
GitHub
parent
27b0978cd5
commit
a82ad89ef3
@@ -30,6 +30,7 @@
|
||||
* The API is organized into the following groups:
|
||||
* - @ref key "Key Encoding" - Encode key events into terminal sequences
|
||||
* - @ref osc "OSC Parser" - Parse OSC (Operating System Command) sequences
|
||||
* - @ref sgr "SGR Parser" - Parse SGR (Select Graphic Rendition) sequences
|
||||
* - @ref paste "Paste Utilities" - Validate paste data safety
|
||||
* - @ref allocator "Memory Management" - Memory management and custom allocators
|
||||
* - @ref wasm "WebAssembly Utilities" - WebAssembly convenience functions
|
||||
@@ -40,6 +41,7 @@
|
||||
* - @ref c-vt/src/main.c - OSC parser example
|
||||
* - @ref c-vt-key-encode/src/main.c - Key encoding example
|
||||
* - @ref c-vt-paste/src/main.c - Paste safety check example
|
||||
* - @ref c-vt-sgr/src/main.c - SGR parser example
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -58,6 +60,11 @@
|
||||
* paste data is safe before sending it to the terminal.
|
||||
*/
|
||||
|
||||
/** @example c-vt-sgr/src/main.c
|
||||
* This example demonstrates how to use the SGR parser to parse terminal
|
||||
* styling sequences and extract text attributes like colors and underline styles.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_H
|
||||
#define GHOSTTY_VT_H
|
||||
|
||||
@@ -68,6 +75,7 @@ extern "C" {
|
||||
#include <ghostty/vt/result.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/osc.h>
|
||||
#include <ghostty/vt/sgr.h>
|
||||
#include <ghostty/vt/key.h>
|
||||
#include <ghostty/vt/paste.h>
|
||||
#include <ghostty/vt/wasm.h>
|
||||
|
||||
77
include/ghostty/vt/color.h
Normal file
77
include/ghostty/vt/color.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file color.h
|
||||
*
|
||||
* Color types and utilities.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_COLOR_H
|
||||
#define GHOSTTY_VT_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* RGB color value.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t r; /**< Red component (0-255) */
|
||||
uint8_t g; /**< Green component (0-255) */
|
||||
uint8_t b; /**< Blue component (0-255) */
|
||||
} GhosttyColorRgb;
|
||||
|
||||
/**
|
||||
* Palette color index (0-255).
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef uint8_t GhosttyColorPaletteIndex;
|
||||
|
||||
/** @addtogroup sgr
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Black color (0) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BLACK 0
|
||||
/** Red color (1) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_RED 1
|
||||
/** Green color (2) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_GREEN 2
|
||||
/** Yellow color (3) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_YELLOW 3
|
||||
/** Blue color (4) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BLUE 4
|
||||
/** Magenta color (5) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_MAGENTA 5
|
||||
/** Cyan color (6) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_CYAN 6
|
||||
/** White color (7) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_WHITE 7
|
||||
/** Bright black color (8) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_BLACK 8
|
||||
/** Bright red color (9) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_RED 9
|
||||
/** Bright green color (10) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_GREEN 10
|
||||
/** Bright yellow color (11) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_YELLOW 11
|
||||
/** Bright blue color (12) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_BLUE 12
|
||||
/** Bright magenta color (13) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_MAGENTA 13
|
||||
/** Bright cyan color (14) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_CYAN 14
|
||||
/** Bright white color (15) @ingroup sgr */
|
||||
#define GHOSTTY_COLOR_NAMED_BRIGHT_WHITE 15
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GHOSTTY_VT_COLOR_H */
|
||||
@@ -15,6 +15,8 @@ typedef enum {
|
||||
GHOSTTY_SUCCESS = 0,
|
||||
/** Operation failed due to failed allocation */
|
||||
GHOSTTY_OUT_OF_MEMORY = -1,
|
||||
/** Operation failed due to invalid value */
|
||||
GHOSTTY_INVALID_VALUE = -2,
|
||||
} GhosttyResult;
|
||||
|
||||
#endif /* GHOSTTY_VT_RESULT_H */
|
||||
|
||||
306
include/ghostty/vt/sgr.h
Normal file
306
include/ghostty/vt/sgr.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* @file sgr.h
|
||||
*
|
||||
* SGR (Select Graphic Rendition) attribute parsing and handling.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_SGR_H
|
||||
#define GHOSTTY_VT_SGR_H
|
||||
|
||||
/** @defgroup sgr SGR Parser
|
||||
*
|
||||
* SGR (Select Graphic Rendition) attribute parser.
|
||||
*
|
||||
* SGR sequences are the syntax used to set styling attributes such as
|
||||
* bold, italic, underline, and colors for text in terminal emulators.
|
||||
* For example, you may be familiar with sequences like `ESC[1;31m`. The
|
||||
* `1;31` is the SGR attribute list.
|
||||
*
|
||||
* The parser processes SGR parameters from CSI sequences (e.g., `ESC[1;31m`)
|
||||
* and returns individual text attributes like bold, italic, colors, etc.
|
||||
* It supports both semicolon (`;`) and colon (`:`) separators, possibly mixed,
|
||||
* and handles various color formats including 8-color, 16-color, 256-color,
|
||||
* X11 named colors, and RGB in multiple formats.
|
||||
*
|
||||
* ## Basic Usage
|
||||
*
|
||||
* 1. Create a parser instance with ghostty_sgr_new()
|
||||
* 2. Set SGR parameters with ghostty_sgr_set_params()
|
||||
* 3. Iterate through attributes using ghostty_sgr_next()
|
||||
* 4. Free the parser with ghostty_sgr_free() when done
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* @code{.c}
|
||||
* #include <assert.h>
|
||||
* #include <stdio.h>
|
||||
* #include <ghostty/vt.h>
|
||||
*
|
||||
* int main() {
|
||||
* // Create parser
|
||||
* GhosttySgrParser parser;
|
||||
* GhosttyResult result = ghostty_sgr_new(NULL, &parser);
|
||||
* assert(result == GHOSTTY_SUCCESS);
|
||||
*
|
||||
* // Parse "bold, red foreground" sequence: ESC[1;31m
|
||||
* uint16_t params[] = {1, 31};
|
||||
* result = ghostty_sgr_set_params(parser, params, NULL, 2);
|
||||
* assert(result == GHOSTTY_SUCCESS);
|
||||
*
|
||||
* // Iterate through attributes
|
||||
* GhosttySgrAttribute attr;
|
||||
* while (ghostty_sgr_next(parser, &attr)) {
|
||||
* switch (attr.tag) {
|
||||
* case GHOSTTY_SGR_ATTR_BOLD:
|
||||
* printf("Bold enabled\n");
|
||||
* break;
|
||||
* case GHOSTTY_SGR_ATTR_FG_8:
|
||||
* printf("Foreground color: %d\n", attr.value.fg_8);
|
||||
* break;
|
||||
* default:
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Cleanup
|
||||
* ghostty_sgr_free(parser);
|
||||
* return 0;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/result.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/color.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opaque handle to an SGR parser instance.
|
||||
*
|
||||
* This handle represents an SGR (Select Graphic Rendition) parser that can
|
||||
* be used to parse SGR sequences and extract individual text attributes.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct GhosttySgrParser *GhosttySgrParser;
|
||||
|
||||
/**
|
||||
* SGR attribute tags.
|
||||
*
|
||||
* These values identify the type of an SGR attribute in a tagged union.
|
||||
* Use the tag to determine which field in the attribute value union to access.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef enum {
|
||||
GHOSTTY_SGR_ATTR_UNSET = 0,
|
||||
GHOSTTY_SGR_ATTR_UNKNOWN = 1,
|
||||
GHOSTTY_SGR_ATTR_BOLD = 2,
|
||||
GHOSTTY_SGR_ATTR_RESET_BOLD = 3,
|
||||
GHOSTTY_SGR_ATTR_ITALIC = 4,
|
||||
GHOSTTY_SGR_ATTR_RESET_ITALIC = 5,
|
||||
GHOSTTY_SGR_ATTR_FAINT = 6,
|
||||
GHOSTTY_SGR_ATTR_UNDERLINE = 7,
|
||||
GHOSTTY_SGR_ATTR_RESET_UNDERLINE = 8,
|
||||
GHOSTTY_SGR_ATTR_UNDERLINE_COLOR = 9,
|
||||
GHOSTTY_SGR_ATTR_UNDERLINE_COLOR_256 = 10,
|
||||
GHOSTTY_SGR_ATTR_RESET_UNDERLINE_COLOR = 11,
|
||||
GHOSTTY_SGR_ATTR_OVERLINE = 12,
|
||||
GHOSTTY_SGR_ATTR_RESET_OVERLINE = 13,
|
||||
GHOSTTY_SGR_ATTR_BLINK = 14,
|
||||
GHOSTTY_SGR_ATTR_RESET_BLINK = 15,
|
||||
GHOSTTY_SGR_ATTR_INVERSE = 16,
|
||||
GHOSTTY_SGR_ATTR_RESET_INVERSE = 17,
|
||||
GHOSTTY_SGR_ATTR_INVISIBLE = 18,
|
||||
GHOSTTY_SGR_ATTR_RESET_INVISIBLE = 19,
|
||||
GHOSTTY_SGR_ATTR_STRIKETHROUGH = 20,
|
||||
GHOSTTY_SGR_ATTR_RESET_STRIKETHROUGH = 21,
|
||||
GHOSTTY_SGR_ATTR_DIRECT_COLOR_FG = 22,
|
||||
GHOSTTY_SGR_ATTR_DIRECT_COLOR_BG = 23,
|
||||
GHOSTTY_SGR_ATTR_BG_8 = 24,
|
||||
GHOSTTY_SGR_ATTR_FG_8 = 25,
|
||||
GHOSTTY_SGR_ATTR_RESET_FG = 26,
|
||||
GHOSTTY_SGR_ATTR_RESET_BG = 27,
|
||||
GHOSTTY_SGR_ATTR_BRIGHT_BG_8 = 28,
|
||||
GHOSTTY_SGR_ATTR_BRIGHT_FG_8 = 29,
|
||||
GHOSTTY_SGR_ATTR_BG_256 = 30,
|
||||
GHOSTTY_SGR_ATTR_FG_256 = 31,
|
||||
} GhosttySgrAttributeTag;
|
||||
|
||||
/**
|
||||
* Underline style types.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef enum {
|
||||
GHOSTTY_SGR_UNDERLINE_NONE = 0,
|
||||
GHOSTTY_SGR_UNDERLINE_SINGLE = 1,
|
||||
GHOSTTY_SGR_UNDERLINE_DOUBLE = 2,
|
||||
GHOSTTY_SGR_UNDERLINE_CURLY = 3,
|
||||
GHOSTTY_SGR_UNDERLINE_DOTTED = 4,
|
||||
GHOSTTY_SGR_UNDERLINE_DASHED = 5,
|
||||
} GhosttySgrUnderline;
|
||||
|
||||
/**
|
||||
* Unknown SGR attribute data.
|
||||
*
|
||||
* Contains the full parameter list and the partial list where parsing
|
||||
* encountered an unknown or invalid sequence.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct {
|
||||
const uint16_t *full_ptr;
|
||||
size_t full_len;
|
||||
const uint16_t *partial_ptr;
|
||||
size_t partial_len;
|
||||
} GhosttySgrUnknown;
|
||||
|
||||
/**
|
||||
* SGR attribute value union.
|
||||
*
|
||||
* This union contains all possible attribute values. Use the tag field
|
||||
* to determine which union member is active. Attributes without associated
|
||||
* data (like bold, italic) don't use the union value.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef union {
|
||||
GhosttySgrUnknown unknown;
|
||||
GhosttySgrUnderline underline;
|
||||
GhosttyColorRgb underline_color;
|
||||
GhosttyColorPaletteIndex underline_color_256;
|
||||
GhosttyColorRgb direct_color_fg;
|
||||
GhosttyColorRgb direct_color_bg;
|
||||
GhosttyColorPaletteIndex bg_8;
|
||||
GhosttyColorPaletteIndex fg_8;
|
||||
GhosttyColorPaletteIndex bright_bg_8;
|
||||
GhosttyColorPaletteIndex bright_fg_8;
|
||||
GhosttyColorPaletteIndex bg_256;
|
||||
GhosttyColorPaletteIndex fg_256;
|
||||
uint64_t _padding[8];
|
||||
} GhosttySgrAttributeValue;
|
||||
|
||||
/**
|
||||
* SGR attribute (tagged union).
|
||||
*
|
||||
* A complete SGR attribute with both its type tag and associated value.
|
||||
* Always check the tag field to determine which value union member is valid.
|
||||
*
|
||||
* Attributes without associated data (e.g., GHOSTTY_SGR_ATTR_BOLD) can be
|
||||
* identified by tag alone; the value union is not used for these and
|
||||
* the memory in the value field is undefined.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct {
|
||||
GhosttySgrAttributeTag tag;
|
||||
GhosttySgrAttributeValue value;
|
||||
} GhosttySgrAttribute;
|
||||
|
||||
/**
|
||||
* Create a new SGR parser instance.
|
||||
*
|
||||
* Creates a new SGR (Select Graphic Rendition) parser using the provided
|
||||
* allocator. The parser must be freed using ghostty_sgr_free() when
|
||||
* no longer needed.
|
||||
*
|
||||
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
|
||||
* @param parser Pointer to store the created parser handle
|
||||
* @return GHOSTTY_SUCCESS on success, or an error code on failure
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
GhosttyResult ghostty_sgr_new(const GhosttyAllocator *allocator, GhosttySgrParser *parser);
|
||||
|
||||
/**
|
||||
* Free an SGR parser instance.
|
||||
*
|
||||
* Releases all resources associated with the SGR parser. After this call,
|
||||
* the parser handle becomes invalid and must not be used. This includes
|
||||
* any attributes previously returned by ghostty_sgr_next().
|
||||
*
|
||||
* @param parser The parser handle to free (may be NULL)
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
void ghostty_sgr_free(GhosttySgrParser parser);
|
||||
|
||||
/**
|
||||
* Reset an SGR parser instance to the beginning of the parameter list.
|
||||
*
|
||||
* Resets the parser's iteration state without clearing the parameters.
|
||||
* After calling this, ghostty_sgr_next() will start from the beginning
|
||||
* of the parameter list again.
|
||||
*
|
||||
* @param parser The parser handle to reset, must not be NULL
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
void ghostty_sgr_reset(GhosttySgrParser parser);
|
||||
|
||||
/**
|
||||
* Set SGR parameters for parsing.
|
||||
*
|
||||
* Sets the SGR parameter list to parse. Parameters are the numeric values
|
||||
* from a CSI SGR sequence (e.g., for `ESC[1;31m`, params would be {1, 31}).
|
||||
*
|
||||
* The separators array optionally specifies the separator type for each
|
||||
* parameter position. Each byte should be either ';' for semicolon or ':'
|
||||
* for colon. This is needed for certain color formats that use colon
|
||||
* separators (e.g., `ESC[4:3m` for curly underline). Any invalid separator
|
||||
* values are treated as semicolons. The separators array must have the same
|
||||
* length as the params array, if it is not NULL.
|
||||
*
|
||||
* If separators is NULL, all parameters are assumed to be semicolon-separated.
|
||||
*
|
||||
* This function makes an internal copy of the parameter and separator data,
|
||||
* so the caller can safely free or modify the input arrays after this call.
|
||||
*
|
||||
* After calling this function, the parser is automatically reset and ready
|
||||
* to iterate from the beginning.
|
||||
*
|
||||
* @param parser The parser handle, must not be NULL
|
||||
* @param params Array of SGR parameter values
|
||||
* @param separators Optional array of separator characters (';' or ':'), or NULL
|
||||
* @param len Number of parameters (and separators if provided)
|
||||
* @return GHOSTTY_SUCCESS on success, or an error code on failure
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
GhosttyResult ghostty_sgr_set_params(
|
||||
GhosttySgrParser parser,
|
||||
const uint16_t *params,
|
||||
const char *separators,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Get the next SGR attribute.
|
||||
*
|
||||
* Parses and returns the next attribute from the parameter list.
|
||||
* Call this function repeatedly until it returns false to process
|
||||
* all attributes in the sequence.
|
||||
*
|
||||
* @param parser The parser handle, must not be NULL
|
||||
* @param attr Pointer to store the next attribute
|
||||
* @return true if an attribute was returned, false if no more attributes
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
bool ghostty_sgr_next(GhosttySgrParser parser, GhosttySgrAttribute *attr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* GHOSTTY_VT_SGR_H */
|
||||
Reference in New Issue
Block a user