-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
gemtext.h
182 lines (150 loc) · 5.28 KB
/
gemtext.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#ifndef GEMTEXT_H
#define GEMTEXT_H
#include <stddef.h>
#include <stdalign.h>
#include <stdio.h>
enum gemtext_error
{
/// The operation was successful.
GEMTEXT_SUCCESS = 0,
/// The same as `GEMTEXT_SUCCESS`, but indicates that the `fragment` variable
/// was initialized.
/// Only valid for `gemtextParserFeed` and `gemtextParserFinalize`.
GEMTEXT_SUCCESS_FRAGMENT = 1,
/// The operation failed due to a lack of memory.
GEMTEXT_ERR_OUT_OF_MEMORY = -1,
/// The operation failed as a given index was out of bounds.
GEMTEXT_ERR_OUT_OF_BOUNDS = -2,
};
enum gemtext_fragment_type
{
GEMTEXT_FRAGMENT_EMPTY = 0,
GEMTEXT_FRAGMENT_PARAGRAPH = 1,
GEMTEXT_FRAGMENT_PREFORMATTED = 2,
GEMTEXT_FRAGMENT_QUOTE = 3,
GEMTEXT_FRAGMENT_LINK = 4,
GEMTEXT_FRAGMENT_LIST = 5,
GEMTEXT_FRAGMENT_HEADING = 6,
};
enum gemtext_renderer
{
/// Renders canonical gemini text
GEMTEXT_RENDER_GEMTEXT = 0,
/// Renders the gemini text as HTML.
GEMTEXT_RENDER_HTML = 1,
/// Renders the gemini text as commonmark markdown.
GEMTEXT_RENDER_MARKDOWN = 2,
/// Renders the gemini text as rich text.
GEMTEXT_RENDER_RTF = 3,
};
enum gemtext_heading_level
{
GEMTEXT_HEADING_H1 = 1,
GEMTEXT_HEADING_H2 = 2,
GEMTEXT_HEADING_H3 = 3,
};
struct gemtext_lines
{
size_t count;
char const *const *lines;
};
struct gemtext_preformatted
{
struct gemtext_lines lines;
char const *alt_text; // can be NULL
};
struct gemtext_link
{
char const *href;
char const *title; // can be NULL
};
struct gemtext_heading
{
char const *text;
enum gemtext_heading_level level;
};
struct gemtext_fragment
{
enum gemtext_fragment_type type;
union
{
char const *paragraph;
struct gemtext_preformatted preformatted;
struct gemtext_lines quote;
struct gemtext_link link;
struct gemtext_lines list;
struct gemtext_heading heading;
};
};
struct gemtext_document
{
size_t fragment_count;
struct gemtext_fragment const *fragments;
};
struct gemtext_parser
{
// KEEP THIS IN SYNC WITH THE ASSERT IN src/gemtext.zig:Parser!
alignas(16) char opaque[128];
};
/// Initializes the `document`.
enum gemtext_error gemtextDocumentCreate(struct gemtext_document *document);
/// Inserts a `fragment` at `index` in `document`.
enum gemtext_error gemtextDocumentInsert(struct gemtext_document *document, size_t index, struct gemtext_fragment const *fragment);
/// Appends a `fragment` at the end to `document`.
enum gemtext_error gemtextDocumentAppend(struct gemtext_document *document, struct gemtext_fragment const *fragment);
/// Removes a fragment from `document` at `index`.
void gemtextDocumentRemove(struct gemtext_document *document, size_t index);
/// Destroys the `document` and all contained resources.
void gemtextDocumentDestroy(struct gemtext_document *document);
/// Initializes `parser`.
enum gemtext_error gemtextParserCreate(struct gemtext_parser *parser);
/// Destroys `parser` and all contained resources.
void gemtextParserDestroy(struct gemtext_parser *parser);
/// Feeds a sequence of `bytes` into the parser and returns
/// the number of `consumed_bytes` to the caller. This sequence is `total_bytes` long.
/// If a `fragment` was parsed, returns `GEMTEXT_SUCCESS_FRAGMENT`
/// and the variable `fragment` was initialized by the parser to a valid value.
/// If `consumed_bytes` is less than `total_bytes`, the parser has not consumed
/// all bytes in the input sequence and the caller should process the returned fragment,
/// then feed the rest of the bytes into the parser.
/// If a `fragment` was returned, it must be freed with `gemtextParserDestroyFragment`.
enum gemtext_error gemtextParserFeed(
struct gemtext_parser *parser,
struct gemtext_fragment *fragment,
size_t *consumed_bytes,
size_t total_bytes,
char const *bytes);
/// Tells the parser that we finished the current file and will flush all internal
/// buffers.
/// If `GEMTEXT_SUCCESS_FRAGMENT` is returned, `fragment` will be valid and must be
/// freed with `gemtextParserDestroyFragment`.
enum gemtext_error gemtextParserFinalize(
struct gemtext_parser *parser,
struct gemtext_fragment *fragment);
/// Destroys a `fragment` returned by `gemtextParserFeed()` or `gemtextParserFinalize()`. `parser` is the
/// associated parser that was passed into `gemtextParserFeed()` or `gemtextParserFinalize()`.
void gemtextParserDestroyFragment(
struct gemtext_parser *parser,
struct gemtext_fragment *fragment);
/// Renders a sequence of `fragments` with the selected `renderer`.
/// Every time text is emitted, `render` is called with
/// both the `context` parameter passed verbatim into the callback
/// as well as a sequence of `bytes` with the given `length`.
enum gemtext_error gemtextRender(
enum gemtext_renderer renderer,
struct gemtext_fragment const *fragments,
size_t fragment_count,
void *context,
void (*render)(void *context, char const *bytes, size_t length));
/// Parses a string into a `gemtext_document` and will return that `document`
/// on success.
enum gemtext_error gemtextDocumentParseString(
struct gemtext_document *document,
char const *text,
size_t length);
/// Parses a file stream into a `gemtext_document` and will return that `document`
/// on success.
enum gemtext_error gemtextDocumentParseFile(
struct gemtext_document *document,
FILE *file);
#endif // GEMTEXT_H