# GFM Markdown Parser

```c
#define FIO_GFM
#include "fio-stl.h"
```

A flat-state, non-recursive parser for GitHub Flavored Markdown. It emits block and inline events through three callbacks — push, write, pop — without allocating heap memory itself. `fio_gfm_parse` is the only public entry point.

The parser depends on `FIO_ENTITY` for HTML entity decoding.

---

## Configuration Macros

#### `FIO_GFM_MAX_DEPTH`

```c
#define FIO_GFM_MAX_DEPTH 255
```

Maximum container nesting depth. Must fit in a byte (≤ 255).

#### `FIO_GFM_MAX_TABLE_COLUMNS`

```c
#define FIO_GFM_MAX_TABLE_COLUMNS 64
```

Maximum table columns. Alignment is bit-packed, so four columns fit in one byte.

#### `FIO_GFM_REF_CACHE_SIZE`

```c
#define FIO_GFM_REF_CACHE_SIZE 128
```

Maximum reference definitions held in the fast inline cache.

---

## Error Codes

#### `FIO_GFM_ERR_GENERIC`, `FIO_GFM_ERR_DEPTH`, `FIO_GFM_ERR_INPUT`

```c
#define FIO_GFM_ERR_GENERIC -1
#define FIO_GFM_ERR_DEPTH   -2
#define FIO_GFM_ERR_INPUT   -3
```

Negative error codes used internally and returned through `fio_gfm_parse`.

---

## Flags

#### `FIO_GFM_F_TIGHT`

```c
#define FIO_GFM_F_TIGHT ((uint8_t)1U << 0)
```

The list is tight (no blank lines between items).

#### `FIO_GFM_F_LOOSE_SEEN`

```c
#define FIO_GFM_F_LOOSE_SEEN ((uint8_t)1U << 1)
```

A blank line was seen between list items.

#### `FIO_GFM_F_TASK`

```c
#define FIO_GFM_F_TASK ((uint8_t)1U << 2)
```

The list item is a task-list item.

#### `FIO_GFM_F_TASK_CHECKED`

```c
#define FIO_GFM_F_TASK_CHECKED ((uint8_t)1U << 3)
```

The task-list marker is checked (`[x]`).

---

## Types

#### `fio_gfm_type_e`

```c
typedef enum {
  FIO_GFM_PARAGRAPH = 1,
  FIO_GFM_HEADING,
  FIO_GFM_THEMATIC_BREAK,
  FIO_GFM_BLOCKQUOTE,
  FIO_GFM_LIST_UNORDERED,
  FIO_GFM_LIST_ORDERED,
  FIO_GFM_LIST_ITEM,
  FIO_GFM_CODE_BLOCK,
  FIO_GFM_HTML_BLOCK,
  FIO_GFM_TABLE,
  FIO_GFM_TABLE_ROW,
  FIO_GFM_TABLE_CELL,
  FIO_GFM_EMPHASIS,
  FIO_GFM_STRONG,
  FIO_GFM_STRIKETHROUGH,
  FIO_GFM_LINK,
  FIO_GFM_TEXT,
  FIO_GFM_SOFT_BREAK,
  FIO_GFM_HARD_BREAK,
  FIO_GFM_CODE_SPAN,
  FIO_GFM_IMAGE,
  FIO_GFM_AUTOLINK,
  FIO_GFM_INLINE_HTML,
  FIO_GFM_FOOTNOTE_REF,
} fio_gfm_type_e;
```

Event type. Values `1`–`12` are block sections; `13`–`16` are inline sections; `17`–`23` are text and leaf content emitted with `write`.

#### `fio_gfm_align_e`

```c
typedef enum {
  FIO_GFM_ALIGN_NONE = 0,
  FIO_GFM_ALIGN_LEFT,
  FIO_GFM_ALIGN_RIGHT,
  FIO_GFM_ALIGN_CENTER,
} fio_gfm_align_e;
```

Table cell alignment.

#### `fio_gfm_event_s`

```c
typedef struct {
  void *udata;
  fio_buf_info_s source;
  fio_buf_info_s text;
  fio_buf_info_s marker;
  fio_buf_info_s info;
  fio_buf_info_s destination;
  fio_buf_info_s title;
  fio_buf_info_s reference;
  uint32_t list_start;
  uint16_t columns;
  uint16_t column;
  uint8_t type;
  uint8_t heading_level;
  uint8_t flags;
  uint8_t align;
  uint8_t padding;
} fio_gfm_event_s;
```

Event passed to every callback.

**Fields:**
- `udata` — live user pointer; the parser copies it back after each callback.
- `source` — full source slice for this event.
- `text` — literal text / label / code content.
- `marker` — marker slice (`#`, fence, list bullet, etc.).
- `info` — fenced code info string (language tag).
- `destination` — link/image/autolink URL.
- `title` — link/image title.
- `reference` — reference label for ref-style links/images.
- `list_start` — ordered list start number.
- `columns` / `column` — table column count and cell index.
- `type` — `fio_gfm_type_e` value.
- `heading_level` — `1`–`6` for headings.
- `flags` — `FIO_GFM_F_*`.
- `align` — `fio_gfm_align_e` for table cells.
- `padding` — virtual leading spaces from tab expansion.

#### `fio_gfm_callbacks_s`

```c
typedef struct {
  int (*push)(fio_gfm_event_s *e);
  int (*write)(fio_gfm_event_s *e);
  int (*pop)(fio_gfm_event_s *e);
} fio_gfm_callbacks_s;
```

Parser callbacks. All are optional. Return `0` to continue, non-zero to abort. Positive values are user errors; negative values are reserved for parser errors.

---

## Parsing

#### `fio_gfm_parse`

```c
SFUNC size_t fio_gfm_parse(const fio_gfm_callbacks_s *callbacks,
                           void *udata,
                           fio_buf_info_s source);
```

Parses a complete Markdown document and emits events. The document must be fully available in `source`; streaming is not supported.

**Parameters:**
- `callbacks` — pointer to callback struct.
- `udata` — user pointer copied into every event; callbacks may update it.
- `source` — full document bytes.

**Returns:** the number of bytes consumed. If this equals `source.len`, parsing completed. A smaller value means a callback aborted or a parser error occurred.

---

## Example

```c
#define FIO_GFM
#include "fio-stl.h"

static int on_push(fio_gfm_event_s *e) {
  fprintf(stderr, "open type=%u\n", e->type);
  return 0;
}

static int on_write(fio_gfm_event_s *e) {
  fprintf(stderr, "text: %.*s\n", (int)e->text.len, e->text.buf);
  return 0;
}

static int on_pop(fio_gfm_event_s *e) {
  fprintf(stderr, "close type=%u\n", e->type);
  return 0;
}

int main(void) {
  fio_gfm_callbacks_s cb = {
      .push = on_push,
      .write = on_write,
      .pop = on_pop,
  };
  fio_buf_info_s src = FIO_BUF_INFO2("# Hello\n\nworld.\n", 16);
  size_t n = fio_gfm_parse(&cb, NULL, src);
  fprintf(stderr, "consumed %zu of %zu bytes\n", n, src.len);
  return 0;
}
```

------------------------------------------------------------
