增加cmark-gfm

This commit is contained in:
JackLee 2025-03-05 18:28:16 +08:00
parent 3a0320e311
commit 9fa33257c0
20 changed files with 3300 additions and 8 deletions

BIN
3rdparty/cmark-gfm/bin/cmark-gfm.exe vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,54 @@
#ifndef CMARK_GFM_CORE_EXTENSIONS_H
#define CMARK_GFM_CORE_EXTENSIONS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "cmark-gfm-extension_api.h"
#include "cmark-gfm_export.h"
#include <stdbool.h>
#include <stdint.h>
CMARK_GFM_EXPORT
void cmark_gfm_core_extensions_ensure_registered(void);
CMARK_GFM_EXPORT
uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node);
/** Sets the number of columns for the table, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT
int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns);
CMARK_GFM_EXPORT
uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node);
/** Sets the alignments for the table, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT
int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments);
CMARK_GFM_EXPORT
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node);
/** Sets whether the node is a table header row, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT
int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header);
CMARK_GFM_EXPORT
bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node);
/* For backwards compatibility */
#define cmark_gfm_extensions_tasklist_is_checked cmark_gfm_extensions_get_tasklist_item_checked
/** Sets whether a tasklist item is "checked" (completed), returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT
int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,737 @@
#ifndef CMARK_GFM_EXTENSION_API_H
#define CMARK_GFM_EXTENSION_API_H
#ifdef __cplusplus
extern "C" {
#endif
#include "cmark-gfm.h"
struct cmark_renderer;
struct cmark_html_renderer;
struct cmark_chunk;
/**
* ## Extension Support
*
* While the "core" of libcmark is strictly compliant with the
* specification, an API is provided for extension writers to
* hook into the parsing process.
*
* It should be noted that the cmark_node API already offers
* room for customization, with methods offered to traverse and
* modify the AST, and even define custom blocks.
* When the desired customization is achievable in an error-proof
* way using that API, it should be the preferred method.
*
* The following API requires a more in-depth understanding
* of libcmark's parsing strategy, which is exposed
* [here](http://spec.commonmark.org/0.24/#appendix-a-parsing-strategy).
*
* It should be used when "a posteriori" modification of the AST
* proves to be too difficult / impossible to implement correctly.
*
* It can also serve as an intermediary step before extending
* the specification, as an extension implemented using this API
* will be trivially integrated in the core if it proves to be
* desirable.
*/
typedef struct cmark_plugin cmark_plugin;
/** A syntax extension that can be attached to a cmark_parser
* with cmark_parser_attach_syntax_extension().
*
* Extension writers should assign functions matching
* the signature of the following 'virtual methods' to
* implement new functionality.
*
* Their calling order and expected behaviour match the procedure outlined
* at <http://spec.commonmark.org/0.24/#phase-1-block-structure>:
*
* During step 1, cmark will call the function provided through
* 'cmark_syntax_extension_set_match_block_func' when it
* iterates over an open block created by this extension,
* to determine whether it could contain the new line.
* If no function was provided, cmark will close the block.
*
* During step 2, if and only if the new line doesn't match any
* of the standard syntax rules, cmark will call the function
* provided through 'cmark_syntax_extension_set_open_block_func'
* to let the extension determine whether that new line matches
* one of its syntax rules.
* It is the responsibility of the parser to create and add the
* new block with cmark_parser_make_block and cmark_parser_add_child.
* If no function was provided is NULL, the extension will have
* no effect at all on the final block structure of the AST.
*
* #### Inline parsing phase hooks
*
* For each character provided by the extension through
* 'cmark_syntax_extension_set_special_inline_chars',
* the function provided by the extension through
* 'cmark_syntax_extension_set_match_inline_func'
* will get called, it is the responsibility of the extension
* to scan the characters located at the current inline parsing offset
* with the cmark_inline_parser API.
*
* Depending on the type of the extension, it can either:
*
* * Scan forward, determine that the syntax matches and return
* a newly-created inline node with the appropriate type.
* This is the technique that would be used if inline code
* (with backticks) was implemented as an extension.
* * Scan only the character(s) that its syntax rules require
* for opening and closing nodes, push a delimiter on the
* delimiter stack, and return a simple text node with its
* contents set to the character(s) consumed.
* This is the technique that would be used if emphasis
* inlines were implemented as an extension.
*
* When an extension has pushed delimiters on the stack,
* the function provided through
* 'cmark_syntax_extension_set_inline_from_delim_func'
* will get called in a latter phase,
* when the inline parser has matched opener and closer delimiters
* created by the extension together.
*
* It is then the responsibility of the extension to modify
* and populate the opener inline text node, and to remove
* the necessary delimiters from the delimiter stack.
*
* Finally, the extension should return NULL if its scan didn't
* match its syntax rules.
*
* The extension can store whatever private data it might need
* with 'cmark_syntax_extension_set_private',
* and optionally define a free function for this data.
*/
typedef struct subject cmark_inline_parser;
/** Exposed raw for now */
typedef struct delimiter {
struct delimiter *previous;
struct delimiter *next;
cmark_node *inl_text;
bufsize_t position;
bufsize_t length;
unsigned char delim_char;
int can_open;
int can_close;
} delimiter;
/**
* ### Plugin API.
*
* Extensions should be distributed as dynamic libraries,
* with a single exported function named after the distributed
* filename.
*
* When discovering extensions (see cmark_init), cmark will
* try to load a symbol named "init_{{filename}}" in all the
* dynamic libraries it encounters.
*
* For example, given a dynamic library named myextension.so
* (or myextension.dll), cmark will try to load the symbol
* named "init_myextension". This means that the filename
* must lend itself to forming a valid C identifier, with
* the notable exception of dashes, which will be translated
* to underscores, which means cmark will look for a function
* named "init_my_extension" if it encounters a dynamic library
* named "my-extension.so".
*
* See the 'cmark_plugin_init_func' typedef for the exact prototype
* this function should follow.
*
* For now the extensibility of cmark is not complete, as
* it only offers API to hook into the block parsing phase
* (<http://spec.commonmark.org/0.24/#phase-1-block-structure>).
*
* See 'cmark_plugin_register_syntax_extension' for more information.
*/
/** The prototype plugins' init function should follow.
*/
typedef int (*cmark_plugin_init_func)(cmark_plugin *plugin);
/** Register a syntax 'extension' with the 'plugin', it will be made
* available as an extension and, if attached to a cmark_parser
* with 'cmark_parser_attach_syntax_extension', it will contribute
* to the block parsing process.
*
* See the documentation for 'cmark_syntax_extension' for information
* on how to implement one.
*
* This function will typically be called from the init function
* of external modules.
*
* This takes ownership of 'extension', one should not call
* 'cmark_syntax_extension_free' on a registered extension.
*/
CMARK_GFM_EXPORT
int cmark_plugin_register_syntax_extension(cmark_plugin *plugin,
cmark_syntax_extension *extension);
/** This will search for the syntax extension named 'name' among the
* registered syntax extensions.
*
* It can then be attached to a cmark_parser
* with the cmark_parser_attach_syntax_extension method.
*/
CMARK_GFM_EXPORT
cmark_syntax_extension *cmark_find_syntax_extension(const char *name);
/** Should create and add a new open block to 'parent_container' if
* 'input' matches a syntax rule for that block type. It is allowed
* to modify the type of 'parent_container'.
*
* Should return the newly created block if there is one, or
* 'parent_container' if its type was modified, or NULL.
*/
typedef cmark_node * (*cmark_open_block_func) (cmark_syntax_extension *extension,
int indented,
cmark_parser *parser,
cmark_node *parent_container,
unsigned char *input,
int len);
typedef cmark_node *(*cmark_match_inline_func)(cmark_syntax_extension *extension,
cmark_parser *parser,
cmark_node *parent,
unsigned char character,
cmark_inline_parser *inline_parser);
typedef delimiter *(*cmark_inline_from_delim_func)(cmark_syntax_extension *extension,
cmark_parser *parser,
cmark_inline_parser *inline_parser,
delimiter *opener,
delimiter *closer);
/** Should return 'true' if 'input' can be contained in 'container',
* 'false' otherwise.
*/
typedef int (*cmark_match_block_func) (cmark_syntax_extension *extension,
cmark_parser *parser,
unsigned char *input,
int len,
cmark_node *container);
typedef const char *(*cmark_get_type_string_func) (cmark_syntax_extension *extension,
cmark_node *node);
typedef int (*cmark_can_contain_func) (cmark_syntax_extension *extension,
cmark_node *node,
cmark_node_type child);
typedef int (*cmark_contains_inlines_func) (cmark_syntax_extension *extension,
cmark_node *node);
typedef void (*cmark_common_render_func) (cmark_syntax_extension *extension,
struct cmark_renderer *renderer,
cmark_node *node,
cmark_event_type ev_type,
int options);
typedef int (*cmark_commonmark_escape_func) (cmark_syntax_extension *extension,
cmark_node *node,
int c);
typedef const char* (*cmark_xml_attr_func) (cmark_syntax_extension *extension,
cmark_node *node);
typedef void (*cmark_html_render_func) (cmark_syntax_extension *extension,
struct cmark_html_renderer *renderer,
cmark_node *node,
cmark_event_type ev_type,
int options);
typedef int (*cmark_html_filter_func) (cmark_syntax_extension *extension,
const unsigned char *tag,
size_t tag_len);
typedef cmark_node *(*cmark_postprocess_func) (cmark_syntax_extension *extension,
cmark_parser *parser,
cmark_node *root);
typedef int (*cmark_ispunct_func) (char c);
typedef void (*cmark_opaque_alloc_func) (cmark_syntax_extension *extension,
cmark_mem *mem,
cmark_node *node);
typedef void (*cmark_opaque_free_func) (cmark_syntax_extension *extension,
cmark_mem *mem,
cmark_node *node);
/** Free a cmark_syntax_extension.
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_free (cmark_mem *mem, cmark_syntax_extension *extension);
/** Return a newly-constructed cmark_syntax_extension, named 'name'.
*/
CMARK_GFM_EXPORT
cmark_syntax_extension *cmark_syntax_extension_new (const char *name);
CMARK_GFM_EXPORT
cmark_node_type cmark_syntax_extension_add_node(int is_inline);
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension, int emphasis);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension,
cmark_open_block_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension *extension,
cmark_match_block_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension *extension,
cmark_match_inline_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_extension *extension,
cmark_inline_from_delim_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension,
cmark_llist *special_chars);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension,
cmark_get_type_string_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension,
cmark_can_contain_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension,
cmark_contains_inlines_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension,
cmark_common_render_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_extension *extension,
cmark_common_render_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension,
cmark_common_render_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *extension,
cmark_xml_attr_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension,
cmark_common_render_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension,
cmark_html_render_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension,
cmark_html_filter_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension,
cmark_commonmark_escape_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
void *priv,
cmark_free_func free_func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void *cmark_syntax_extension_get_private(cmark_syntax_extension *extension);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension,
cmark_postprocess_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension *extension,
cmark_opaque_alloc_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension,
cmark_opaque_free_func func);
/** See the documentation for 'cmark_syntax_extension'
*/
CMARK_GFM_EXPORT
void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser,
cmark_ispunct_func func);
/** Return the index of the line currently being parsed, starting with 1.
*/
CMARK_GFM_EXPORT
int cmark_parser_get_line_number(cmark_parser *parser);
/** Return the offset in bytes in the line being processed.
*
* Example:
*
* ### foo
*
* Here, offset will first be 0, then 5 (the index of the 'f' character).
*/
CMARK_GFM_EXPORT
int cmark_parser_get_offset(cmark_parser *parser);
/**
* Return the offset in 'columns' in the line being processed.
*
* This value may differ from the value returned by
* cmark_parser_get_offset() in that it accounts for tabs,
* and as such should not be used as an index in the current line's
* buffer.
*
* Example:
*
* cmark_parser_advance_offset() can be called to advance the
* offset by a number of columns, instead of a number of bytes.
*
* In that case, if offset falls "in the middle" of a tab
* character, 'column' and offset will differ.
*
* ```
* foo \t bar
* ^ ^^
* offset (0) 20
* ```
*
* If cmark_parser_advance_offset is called here with 'columns'
* set to 'true' and 'offset' set to 22, cmark_parser_get_offset()
* will return 20, whereas cmark_parser_get_column() will return
* 22.
*
* Additionally, as tabs expand to the next multiple of 4 column,
* cmark_parser_has_partially_consumed_tab() will now return
* 'true'.
*/
CMARK_GFM_EXPORT
int cmark_parser_get_column(cmark_parser *parser);
/** Return the absolute index in bytes of the first nonspace
* character coming after the offset as returned by
* cmark_parser_get_offset() in the line currently being processed.
*
* Example:
*
* ```
* foo bar baz \n
* ^ ^ ^
* 0 offset (16) first_nonspace (28)
* ```
*/
CMARK_GFM_EXPORT
int cmark_parser_get_first_nonspace(cmark_parser *parser);
/** Return the absolute index of the first nonspace column coming after 'offset'
* in the line currently being processed, counting tabs as multiple
* columns as appropriate.
*
* See the documentation for cmark_parser_get_first_nonspace() and
* cmark_parser_get_column() for more information.
*/
CMARK_GFM_EXPORT
int cmark_parser_get_first_nonspace_column(cmark_parser *parser);
/** Return the difference between the values returned by
* cmark_parser_get_first_nonspace_column() and
* cmark_parser_get_column().
*
* This is not a byte offset, as it can count one tab as multiple
* characters.
*/
CMARK_GFM_EXPORT
int cmark_parser_get_indent(cmark_parser *parser);
/** Return 'true' if the line currently being processed has been entirely
* consumed, 'false' otherwise.
*
* Example:
*
* ```
* foo bar baz \n
* ^
* offset
* ```
*
* This function will return 'false' here.
*
* ```
* foo bar baz \n
* ^
* offset
* ```
* This function will still return 'false'.
*
* ```
* foo bar baz \n
* ^
* offset
* ```
*
* At this point, this function will now return 'true'.
*/
CMARK_GFM_EXPORT
int cmark_parser_is_blank(cmark_parser *parser);
/** Return 'true' if the value returned by cmark_parser_get_offset()
* is 'inside' an expanded tab.
*
* See the documentation for cmark_parser_get_column() for more
* information.
*/
CMARK_GFM_EXPORT
int cmark_parser_has_partially_consumed_tab(cmark_parser *parser);
/** Return the length in bytes of the previously processed line, excluding potential
* newline (\n) and carriage return (\r) trailing characters.
*/
CMARK_GFM_EXPORT
int cmark_parser_get_last_line_length(cmark_parser *parser);
/** Add a child to 'parent' during the parsing process.
*
* If 'parent' isn't the kind of node that can accept this child,
* this function will back up till it hits a node that can, closing
* blocks as appropriate.
*/
CMARK_GFM_EXPORT
cmark_node*cmark_parser_add_child(cmark_parser *parser,
cmark_node *parent,
cmark_node_type block_type,
int start_column);
/** Advance the 'offset' of the parser in the current line.
*
* See the documentation of cmark_parser_get_offset() and
* cmark_parser_get_column() for more information.
*/
CMARK_GFM_EXPORT
void cmark_parser_advance_offset(cmark_parser *parser,
const char *input,
int count,
int columns);
CMARK_GFM_EXPORT
void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffer, size_t len);
/** Attach the syntax 'extension' to the 'parser', to provide extra syntax
* rules.
* See the documentation for cmark_syntax_extension for more information.
*
* Returns 'true' if the 'extension' was successfully attached,
* 'false' otherwise.
*/
CMARK_GFM_EXPORT
int cmark_parser_attach_syntax_extension(cmark_parser *parser, cmark_syntax_extension *extension);
/** Change the type of 'node'.
*
* Return 0 if the type could be changed, 1 otherwise.
*/
CMARK_GFM_EXPORT int cmark_node_set_type(cmark_node *node, cmark_node_type type);
/** Return the string content for all types of 'node'.
* The pointer stays valid as long as 'node' isn't freed.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_string_content(cmark_node *node);
/** Set the string 'content' for all types of 'node'.
* Copies 'content'.
*/
CMARK_GFM_EXPORT int cmark_node_set_string_content(cmark_node *node, const char *content);
/** Get the syntax extension responsible for the creation of 'node'.
* Return NULL if 'node' was created because it matched standard syntax rules.
*/
CMARK_GFM_EXPORT cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node);
/** Set the syntax extension responsible for creating 'node'.
*/
CMARK_GFM_EXPORT int cmark_node_set_syntax_extension(cmark_node *node,
cmark_syntax_extension *extension);
/**
* ## Inline syntax extension helpers
*
* The inline parsing process is described in detail at
* <http://spec.commonmark.org/0.24/#phase-2-inline-structure>
*/
/** Should return 'true' if the predicate matches 'c', 'false' otherwise
*/
typedef int (*cmark_inline_predicate)(int c);
/** Advance the current inline parsing offset */
CMARK_GFM_EXPORT
void cmark_inline_parser_advance_offset(cmark_inline_parser *parser);
/** Get the current inline parsing offset */
CMARK_GFM_EXPORT
int cmark_inline_parser_get_offset(cmark_inline_parser *parser);
/** Set the offset in bytes in the chunk being processed by the given inline parser.
*/
CMARK_GFM_EXPORT
void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset);
/** Gets the cmark_chunk being operated on by the given inline parser.
* Use cmark_inline_parser_get_offset to get our current position in the chunk.
*/
CMARK_GFM_EXPORT
struct cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser);
/** Returns 1 if the inline parser is currently in a bracket; pass 1 for 'image'
* if you want to know about an image-type bracket, 0 for link-type. */
CMARK_GFM_EXPORT
int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image);
/** Remove the last n characters from the last child of the given node.
* This only works where all n characters are in the single last child, and the last
* child is CMARK_NODE_TEXT.
*/
CMARK_GFM_EXPORT
void cmark_node_unput(cmark_node *node, int n);
/** Get the character located at the current inline parsing offset
*/
CMARK_GFM_EXPORT
unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser);
/** Get the character located 'pos' bytes in the current line.
*/
CMARK_GFM_EXPORT
unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, int pos);
/** Whether the inline parser has reached the end of the current line
*/
CMARK_GFM_EXPORT
int cmark_inline_parser_is_eof(cmark_inline_parser *parser);
/** Get the characters located after the current inline parsing offset
* while 'pred' matches. Free after usage.
*/
CMARK_GFM_EXPORT
char *cmark_inline_parser_take_while(cmark_inline_parser *parser, cmark_inline_predicate pred);
/** Push a delimiter on the delimiter stack.
* See <<http://spec.commonmark.org/0.24/#phase-2-inline-structure> for
* more information on the parameters
*/
CMARK_GFM_EXPORT
void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser,
unsigned char c,
int can_open,
int can_close,
cmark_node *inl_text);
/** Remove 'delim' from the delimiter stack
*/
CMARK_GFM_EXPORT
void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, delimiter *delim);
CMARK_GFM_EXPORT
delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser);
CMARK_GFM_EXPORT
int cmark_inline_parser_get_line(cmark_inline_parser *parser);
CMARK_GFM_EXPORT
int cmark_inline_parser_get_column(cmark_inline_parser *parser);
/** Convenience function to scan a given delimiter.
*
* 'left_flanking' and 'right_flanking' will be set to true if they
* respectively precede and follow a non-space, non-punctuation
* character.
*
* Additionally, 'punct_before' and 'punct_after' will respectively be set
* if the preceding or following character is a punctuation character.
*
* Note that 'left_flanking' and 'right_flanking' can both be 'true'.
*
* Returns the number of delimiters encountered, in the limit
* of 'max_delims', and advances the inline parsing offset.
*/
CMARK_GFM_EXPORT
int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser,
int max_delims,
unsigned char c,
int *left_flanking,
int *right_flanking,
int *punct_before,
int *punct_after);
CMARK_GFM_EXPORT
void cmark_manage_extensions_special_characters(cmark_parser *parser, int add);
CMARK_GFM_EXPORT
cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser);
CMARK_GFM_EXPORT
void cmark_arena_push(void);
CMARK_GFM_EXPORT
int cmark_arena_pop(void);
#ifdef __cplusplus
}
#endif
#endif

833
3rdparty/cmark-gfm/include/cmark-gfm.h vendored Normal file
View File

@ -0,0 +1,833 @@
#ifndef CMARK_GFM_H
#define CMARK_GFM_H
#include <stdio.h>
#include <stdint.h>
#include "cmark-gfm_export.h"
#include "cmark-gfm_version.h"
#ifdef __cplusplus
extern "C" {
#endif
/** # NAME
*
* **cmark-gfm** - CommonMark parsing, manipulating, and rendering
*/
/** # DESCRIPTION
*
* ## Simple Interface
*/
/** Convert 'text' (assumed to be a UTF-8 encoded string with length
* 'len') from CommonMark Markdown to HTML, returning a null-terminated,
* UTF-8-encoded string. It is the caller's responsibility
* to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_markdown_to_html(const char *text, size_t len, int options);
/** ## Node Structure
*/
#define CMARK_NODE_TYPE_PRESENT (0x8000)
#define CMARK_NODE_TYPE_BLOCK (CMARK_NODE_TYPE_PRESENT | 0x0000)
#define CMARK_NODE_TYPE_INLINE (CMARK_NODE_TYPE_PRESENT | 0x4000)
#define CMARK_NODE_TYPE_MASK (0xc000)
#define CMARK_NODE_VALUE_MASK (0x3fff)
typedef enum {
/* Error status */
CMARK_NODE_NONE = 0x0000,
/* Block */
CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001,
CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002,
CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003,
CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004,
CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005,
CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006,
CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007,
CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008,
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b,
/* Inline */
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002,
CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003,
CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004,
CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005,
CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006,
CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007,
CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008,
CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009,
CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a,
CMARK_NODE_FOOTNOTE_REFERENCE = CMARK_NODE_TYPE_INLINE | 0x000b,
} cmark_node_type;
extern cmark_node_type CMARK_NODE_LAST_BLOCK;
extern cmark_node_type CMARK_NODE_LAST_INLINE;
/* For backwards compatibility: */
#define CMARK_NODE_HEADER CMARK_NODE_HEADING
#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK
#define CMARK_NODE_HTML CMARK_NODE_HTML_BLOCK
#define CMARK_NODE_INLINE_HTML CMARK_NODE_HTML_INLINE
typedef enum {
CMARK_NO_LIST,
CMARK_BULLET_LIST,
CMARK_ORDERED_LIST
} cmark_list_type;
typedef enum {
CMARK_NO_DELIM,
CMARK_PERIOD_DELIM,
CMARK_PAREN_DELIM
} cmark_delim_type;
typedef struct cmark_node cmark_node;
typedef struct cmark_parser cmark_parser;
typedef struct cmark_iter cmark_iter;
typedef struct cmark_syntax_extension cmark_syntax_extension;
/**
* ## Custom memory allocator support
*/
/** Defines the memory allocation functions to be used by CMark
* when parsing and allocating a document tree
*/
typedef struct cmark_mem {
void *(*calloc)(size_t, size_t);
void *(*realloc)(void *, size_t);
void (*free)(void *);
} cmark_mem;
/** The default memory allocator; uses the system's calloc,
* realloc and free.
*/
CMARK_GFM_EXPORT
cmark_mem *cmark_get_default_mem_allocator(void);
/** An arena allocator; uses system calloc to allocate large
* slabs of memory. Memory in these slabs is not reused at all.
*/
CMARK_GFM_EXPORT
cmark_mem *cmark_get_arena_mem_allocator(void);
/** Resets the arena allocator, quickly returning all used memory
* to the operating system.
*/
CMARK_GFM_EXPORT
void cmark_arena_reset(void);
/** Callback for freeing user data with a 'cmark_mem' context.
*/
typedef void (*cmark_free_func) (cmark_mem *mem, void *user_data);
/*
* ## Basic data structures
*
* To keep dependencies to the strict minimum, libcmark implements
* its own versions of "classic" data structures.
*/
/**
* ### Linked list
*/
/** A generic singly linked list.
*/
typedef struct _cmark_llist
{
struct _cmark_llist *next;
void *data;
} cmark_llist;
/** Append an element to the linked list, return the possibly modified
* head of the list.
*/
CMARK_GFM_EXPORT
cmark_llist * cmark_llist_append (cmark_mem * mem,
cmark_llist * head,
void * data);
/** Free the list starting with 'head', calling 'free_func' with the
* data pointer of each of its elements
*/
CMARK_GFM_EXPORT
void cmark_llist_free_full (cmark_mem * mem,
cmark_llist * head,
cmark_free_func free_func);
/** Free the list starting with 'head'
*/
CMARK_GFM_EXPORT
void cmark_llist_free (cmark_mem * mem,
cmark_llist * head);
/**
* ## Creating and Destroying Nodes
*/
/** Creates a new node of type 'type'. Note that the node may have
* other required properties, which it is the caller's responsibility
* to assign.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
/** Same as `cmark_node_new`, but explicitly listing the memory
* allocator used to allocate the node. Note: be sure to use the same
* allocator for every node in a tree, or bad things can happen.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_new_with_mem(cmark_node_type type,
cmark_mem *mem);
CMARK_GFM_EXPORT cmark_node *cmark_node_new_with_ext(cmark_node_type type,
cmark_syntax_extension *extension);
CMARK_GFM_EXPORT cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type,
cmark_mem *mem,
cmark_syntax_extension *extension);
/** Frees the memory allocated for a node and any children.
*/
CMARK_GFM_EXPORT void cmark_node_free(cmark_node *node);
/**
* ## Tree Traversal
*/
/** Returns the next node in the sequence after 'node', or NULL if
* there is none.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_next(cmark_node *node);
/** Returns the previous node in the sequence after 'node', or NULL if
* there is none.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_previous(cmark_node *node);
/** Returns the parent of 'node', or NULL if there is none.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_parent(cmark_node *node);
/** Returns the first child of 'node', or NULL if 'node' has no children.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
/** Returns the last child of 'node', or NULL if 'node' has no children.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
/** Returns the footnote reference of 'node', or NULL if 'node' doesn't have a
* footnote reference.
*/
CMARK_GFM_EXPORT cmark_node *cmark_node_parent_footnote_def(cmark_node *node);
/**
* ## Iterator
*
* An iterator will walk through a tree of nodes, starting from a root
* node, returning one node at a time, together with information about
* whether the node is being entered or exited. The iterator will
* first descend to a child node, if there is one. When there is no
* child, the iterator will go to the next sibling. When there is no
* next sibling, the iterator will return to the parent (but with
* a 'cmark_event_type' of `CMARK_EVENT_EXIT`). The iterator will
* return `CMARK_EVENT_DONE` when it reaches the root node again.
* One natural application is an HTML renderer, where an `ENTER` event
* outputs an open tag and an `EXIT` event outputs a close tag.
* An iterator might also be used to transform an AST in some systematic
* way, for example, turning all level-3 headings into regular paragraphs.
*
* void
* usage_example(cmark_node *root) {
* cmark_event_type ev_type;
* cmark_iter *iter = cmark_iter_new(root);
*
* while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
* cmark_node *cur = cmark_iter_get_node(iter);
* // Do something with `cur` and `ev_type`
* }
*
* cmark_iter_free(iter);
* }
*
* Iterators will never return `EXIT` events for leaf nodes, which are nodes
* of type:
*
* * CMARK_NODE_HTML_BLOCK
* * CMARK_NODE_THEMATIC_BREAK
* * CMARK_NODE_CODE_BLOCK
* * CMARK_NODE_TEXT
* * CMARK_NODE_SOFTBREAK
* * CMARK_NODE_LINEBREAK
* * CMARK_NODE_CODE
* * CMARK_NODE_HTML_INLINE
*
* Nodes must only be modified after an `EXIT` event, or an `ENTER` event for
* leaf nodes.
*/
typedef enum {
CMARK_EVENT_NONE,
CMARK_EVENT_DONE,
CMARK_EVENT_ENTER,
CMARK_EVENT_EXIT
} cmark_event_type;
/** Creates a new iterator starting at 'root'. The current node and event
* type are undefined until 'cmark_iter_next' is called for the first time.
* The memory allocated for the iterator should be released using
* 'cmark_iter_free' when it is no longer needed.
*/
CMARK_GFM_EXPORT
cmark_iter *cmark_iter_new(cmark_node *root);
/** Frees the memory allocated for an iterator.
*/
CMARK_GFM_EXPORT
void cmark_iter_free(cmark_iter *iter);
/** Advances to the next node and returns the event type (`CMARK_EVENT_ENTER`,
* `CMARK_EVENT_EXIT` or `CMARK_EVENT_DONE`).
*/
CMARK_GFM_EXPORT
cmark_event_type cmark_iter_next(cmark_iter *iter);
/** Returns the current node.
*/
CMARK_GFM_EXPORT
cmark_node *cmark_iter_get_node(cmark_iter *iter);
/** Returns the current event type.
*/
CMARK_GFM_EXPORT
cmark_event_type cmark_iter_get_event_type(cmark_iter *iter);
/** Returns the root node.
*/
CMARK_GFM_EXPORT
cmark_node *cmark_iter_get_root(cmark_iter *iter);
/** Resets the iterator so that the current node is 'current' and
* the event type is 'event_type'. The new current node must be a
* descendant of the root node or the root node itself.
*/
CMARK_GFM_EXPORT
void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
cmark_event_type event_type);
/**
* ## Accessors
*/
/** Returns the user data of 'node'.
*/
CMARK_GFM_EXPORT void *cmark_node_get_user_data(cmark_node *node);
/** Sets arbitrary user data for 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_user_data(cmark_node *node, void *user_data);
/** Set free function for user data */
CMARK_GFM_EXPORT
int cmark_node_set_user_data_free_func(cmark_node *node,
cmark_free_func free_func);
/** Returns the type of 'node', or `CMARK_NODE_NONE` on error.
*/
CMARK_GFM_EXPORT cmark_node_type cmark_node_get_type(cmark_node *node);
/** Like 'cmark_node_get_type', but returns a string representation
of the type, or `"<unknown>"`.
*/
CMARK_GFM_EXPORT
const char *cmark_node_get_type_string(cmark_node *node);
/** Returns the string contents of 'node', or an empty
string if none is set. Returns NULL if called on a
node that does not have string content.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_literal(cmark_node *node);
/** Sets the string contents of 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_literal(cmark_node *node, const char *content);
/** Returns the heading level of 'node', or 0 if 'node' is not a heading.
*/
CMARK_GFM_EXPORT int cmark_node_get_heading_level(cmark_node *node);
/* For backwards compatibility */
#define cmark_node_get_header_level cmark_node_get_heading_level
#define cmark_node_set_header_level cmark_node_set_heading_level
/** Sets the heading level of 'node', returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT int cmark_node_set_heading_level(cmark_node *node, int level);
/** Returns the list type of 'node', or `CMARK_NO_LIST` if 'node'
* is not a list.
*/
CMARK_GFM_EXPORT cmark_list_type cmark_node_get_list_type(cmark_node *node);
/** Sets the list type of 'node', returning 1 on success and 0 on error.
*/
CMARK_GFM_EXPORT int cmark_node_set_list_type(cmark_node *node,
cmark_list_type type);
/** Returns the list delimiter type of 'node', or `CMARK_NO_DELIM` if 'node'
* is not a list.
*/
CMARK_GFM_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node);
/** Sets the list delimiter type of 'node', returning 1 on success and 0
* on error.
*/
CMARK_GFM_EXPORT int cmark_node_set_list_delim(cmark_node *node,
cmark_delim_type delim);
/** Returns starting number of 'node', if it is an ordered list, otherwise 0.
*/
CMARK_GFM_EXPORT int cmark_node_get_list_start(cmark_node *node);
/** Sets starting number of 'node', if it is an ordered list. Returns 1
* on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_list_start(cmark_node *node, int start);
/** Returns 1 if 'node' is a tight list, 0 otherwise.
*/
CMARK_GFM_EXPORT int cmark_node_get_list_tight(cmark_node *node);
/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
/**
* Returns item index of 'node'. This is only used when rendering output
* formats such as commonmark, which need to output the index. It is not
* required for formats such as html or latex.
*/
CMARK_GFM_EXPORT int cmark_node_get_item_index(cmark_node *node);
/** Sets item index of 'node'. Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_item_index(cmark_node *node, int idx);
/** Returns the info string from a fenced code block.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
/** Sets the info string in a fenced code block, returning 1 on
* success and 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_fence_info(cmark_node *node, const char *info);
/** Sets code blocks fencing details
*/
CMARK_GFM_EXPORT int cmark_node_set_fenced(cmark_node * node, int fenced,
int length, int offset, char character);
/** Returns code blocks fencing details
*/
CMARK_GFM_EXPORT int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, char *character);
/** Returns the URL of a link or image 'node', or an empty string
if no URL is set. Returns NULL if called on a node that is
not a link or image.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_url(cmark_node *node);
/** Sets the URL of a link or image 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_url(cmark_node *node, const char *url);
/** Returns the title of a link or image 'node', or an empty
string if no title is set. Returns NULL if called on a node
that is not a link or image.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_title(cmark_node *node);
/** Sets the title of a link or image 'node'. Returns 1 on success,
* 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_title(cmark_node *node, const char *title);
/** Returns the literal "on enter" text for a custom 'node', or
an empty string if no on_enter is set. Returns NULL if called
on a non-custom node.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_on_enter(cmark_node *node);
/** Sets the literal text to render "on enter" for a custom 'node'.
Any children of the node will be rendered after this text.
Returns 1 on success 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_on_enter(cmark_node *node,
const char *on_enter);
/** Returns the literal "on exit" text for a custom 'node', or
an empty string if no on_exit is set. Returns NULL if
called on a non-custom node.
*/
CMARK_GFM_EXPORT const char *cmark_node_get_on_exit(cmark_node *node);
/** Sets the literal text to render "on exit" for a custom 'node'.
Any children of the node will be rendered before this text.
Returns 1 on success 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_set_on_exit(cmark_node *node, const char *on_exit);
/** Returns the line on which 'node' begins.
*/
CMARK_GFM_EXPORT int cmark_node_get_start_line(cmark_node *node);
/** Returns the column at which 'node' begins.
*/
CMARK_GFM_EXPORT int cmark_node_get_start_column(cmark_node *node);
/** Returns the line on which 'node' ends.
*/
CMARK_GFM_EXPORT int cmark_node_get_end_line(cmark_node *node);
/** Returns the column at which 'node' ends.
*/
CMARK_GFM_EXPORT int cmark_node_get_end_column(cmark_node *node);
/**
* ## Tree Manipulation
*/
/** Unlinks a 'node', removing it from the tree, but not freeing its
* memory. (Use 'cmark_node_free' for that.)
*/
CMARK_GFM_EXPORT void cmark_node_unlink(cmark_node *node);
/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_insert_before(cmark_node *node,
cmark_node *sibling);
/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_insert_after(cmark_node *node, cmark_node *sibling);
/** Replaces 'oldnode' with 'newnode' and unlinks 'oldnode' (but does
* not free its memory).
* Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode);
/** Adds 'child' to the beginning of the children of 'node'.
* Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_prepend_child(cmark_node *node, cmark_node *child);
/** Adds 'child' to the end of the children of 'node'.
* Returns 1 on success, 0 on failure.
*/
CMARK_GFM_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child);
/** Consolidates adjacent text nodes.
*/
CMARK_GFM_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
/** Ensures a node and all its children own their own chunk memory.
*/
CMARK_GFM_EXPORT void cmark_node_own(cmark_node *root);
/**
* ## Parsing
*
* Simple interface:
*
* cmark_node *document = cmark_parse_document("Hello *world*", 13,
* CMARK_OPT_DEFAULT);
*
* Streaming interface:
*
* cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
* FILE *fp = fopen("myfile.md", "rb");
* while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
* cmark_parser_feed(parser, buffer, bytes);
* if (bytes < sizeof(buffer)) {
* break;
* }
* }
* document = cmark_parser_finish(parser);
* cmark_parser_free(parser);
*/
/** Creates a new parser object.
*/
CMARK_GFM_EXPORT
cmark_parser *cmark_parser_new(int options);
/** Creates a new parser object with the given memory allocator
*/
CMARK_GFM_EXPORT
cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem);
/** Frees memory allocated for a parser object.
*/
CMARK_GFM_EXPORT
void cmark_parser_free(cmark_parser *parser);
/** Feeds a string of length 'len' to 'parser'.
*/
CMARK_GFM_EXPORT
void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len);
/** Finish parsing and return a pointer to a tree of nodes.
*/
CMARK_GFM_EXPORT
cmark_node *cmark_parser_finish(cmark_parser *parser);
/** Parse a CommonMark document in 'buffer' of length 'len'.
* Returns a pointer to a tree of nodes. The memory allocated for
* the node tree should be released using 'cmark_node_free'
* when it is no longer needed.
*/
CMARK_GFM_EXPORT
cmark_node *cmark_parse_document(const char *buffer, size_t len, int options);
/** Parse a CommonMark document in file 'f', returning a pointer to
* a tree of nodes. The memory allocated for the node tree should be
* released using 'cmark_node_free' when it is no longer needed.
*/
CMARK_GFM_EXPORT
cmark_node *cmark_parse_file(FILE *f, int options);
/**
* ## Rendering
*/
/** Render a 'node' tree as XML. It is the caller's responsibility
* to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_xml(cmark_node *root, int options);
/** As for 'cmark_render_xml', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem);
/** Render a 'node' tree as an HTML fragment. It is up to the user
* to add an appropriate header and footer. It is the caller's
* responsibility to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions);
/** As for 'cmark_render_html', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem);
/** Render a 'node' tree as a groff man page, without the header.
* It is the caller's responsibility to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_man(cmark_node *root, int options, int width);
/** As for 'cmark_render_man', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_man_with_mem(cmark_node *root, int options, int width, cmark_mem *mem);
/** Render a 'node' tree as a commonmark document.
* It is the caller's responsibility to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_commonmark(cmark_node *root, int options, int width);
/** As for 'cmark_render_commonmark', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_commonmark_with_mem(cmark_node *root, int options, int width, cmark_mem *mem);
/** Render a 'node' tree as a plain text document.
* It is the caller's responsibility to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_plaintext(cmark_node *root, int options, int width);
/** As for 'cmark_render_plaintext', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_plaintext_with_mem(cmark_node *root, int options, int width, cmark_mem *mem);
/** Render a 'node' tree as a LaTeX document.
* It is the caller's responsibility to free the returned buffer.
*/
CMARK_GFM_EXPORT
char *cmark_render_latex(cmark_node *root, int options, int width);
/** As for 'cmark_render_latex', but specifying the allocator to use for
* the resulting string.
*/
CMARK_GFM_EXPORT
char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmark_mem *mem);
/**
* ## Options
*/
/** Default options.
*/
#define CMARK_OPT_DEFAULT 0
/**
* ### Options affecting rendering
*/
/** Include a `data-sourcepos` attribute on all block elements.
*/
#define CMARK_OPT_SOURCEPOS (1 << 1)
/** Render `softbreak` elements as hard line breaks.
*/
#define CMARK_OPT_HARDBREAKS (1 << 2)
/** `CMARK_OPT_SAFE` is defined here for API compatibility,
but it no longer has any effect. "Safe" mode is now the default:
set `CMARK_OPT_UNSAFE` to disable it.
*/
#define CMARK_OPT_SAFE (1 << 3)
/** Render raw HTML and unsafe links (`javascript:`, `vbscript:`,
* `file:`, and `data:`, except for `image/png`, `image/gif`,
* `image/jpeg`, or `image/webp` mime types). By default,
* raw HTML is replaced by a placeholder HTML comment. Unsafe
* links are replaced by empty strings.
*/
#define CMARK_OPT_UNSAFE (1 << 17)
/** Render `softbreak` elements as spaces.
*/
#define CMARK_OPT_NOBREAKS (1 << 4)
/**
* ### Options affecting parsing
*/
/** Legacy option (no effect).
*/
#define CMARK_OPT_NORMALIZE (1 << 8)
/** Validate UTF-8 in the input before parsing, replacing illegal
* sequences with the replacement character U+FFFD.
*/
#define CMARK_OPT_VALIDATE_UTF8 (1 << 9)
/** Convert straight quotes to curly, --- to em dashes, -- to en dashes.
*/
#define CMARK_OPT_SMART (1 << 10)
/** Use GitHub-style <pre lang="x"> tags for code blocks instead of <pre><code
* class="language-x">.
*/
#define CMARK_OPT_GITHUB_PRE_LANG (1 << 11)
/** Be liberal in interpreting inline HTML tags.
*/
#define CMARK_OPT_LIBERAL_HTML_TAG (1 << 12)
/** Parse footnotes.
*/
#define CMARK_OPT_FOOTNOTES (1 << 13)
/** Only parse strikethroughs if surrounded by exactly 2 tildes.
* Gives some compatibility with redcarpet.
*/
#define CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE (1 << 14)
/** Use style attributes to align table cells instead of align attributes.
*/
#define CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES (1 << 15)
/** Include the remainder of the info string in code blocks in
* a separate attribute.
*/
#define CMARK_OPT_FULL_INFO_STRING (1 << 16)
/**
* ## Version information
*/
/** The library version as integer for runtime checks. Also available as
* macro CMARK_VERSION for compile time checks.
*
* * Bits 16-23 contain the major version.
* * Bits 8-15 contain the minor version.
* * Bits 0-7 contain the patchlevel.
*
* In hexadecimal format, the number 0x010203 represents version 1.2.3.
*/
CMARK_GFM_EXPORT
int cmark_version(void);
/** The library version string for runtime checks. Also available as
* macro CMARK_VERSION_STRING for compile time checks.
*/
CMARK_GFM_EXPORT
const char *cmark_version_string(void);
/** # AUTHORS
*
* John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
*/
#ifndef CMARK_NO_SHORT_NAMES
#define NODE_DOCUMENT CMARK_NODE_DOCUMENT
#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE
#define NODE_LIST CMARK_NODE_LIST
#define NODE_ITEM CMARK_NODE_ITEM
#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK
#define NODE_HTML_BLOCK CMARK_NODE_HTML_BLOCK
#define NODE_CUSTOM_BLOCK CMARK_NODE_CUSTOM_BLOCK
#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH
#define NODE_HEADING CMARK_NODE_HEADING
#define NODE_HEADER CMARK_NODE_HEADER
#define NODE_THEMATIC_BREAK CMARK_NODE_THEMATIC_BREAK
#define NODE_HRULE CMARK_NODE_HRULE
#define NODE_TEXT CMARK_NODE_TEXT
#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK
#define NODE_LINEBREAK CMARK_NODE_LINEBREAK
#define NODE_CODE CMARK_NODE_CODE
#define NODE_HTML_INLINE CMARK_NODE_HTML_INLINE
#define NODE_CUSTOM_INLINE CMARK_NODE_CUSTOM_INLINE
#define NODE_EMPH CMARK_NODE_EMPH
#define NODE_STRONG CMARK_NODE_STRONG
#define NODE_LINK CMARK_NODE_LINK
#define NODE_IMAGE CMARK_NODE_IMAGE
#define BULLET_LIST CMARK_BULLET_LIST
#define ORDERED_LIST CMARK_ORDERED_LIST
#define PERIOD_DELIM CMARK_PERIOD_DELIM
#define PAREN_DELIM CMARK_PAREN_DELIM
#endif
typedef int32_t bufsize_t;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,43 @@
#ifndef CMARK_GFM_EXPORT_H
#define CMARK_GFM_EXPORT_H
#ifdef CMARK_GFM_STATIC_DEFINE
# define CMARK_GFM_EXPORT
# define CMARK_GFM_NO_EXPORT
#else
# ifndef CMARK_GFM_EXPORT
# ifdef libcmark_gfm_static_EXPORTS
/* We are building this library */
# define CMARK_GFM_EXPORT
# else
/* We are using this library */
# define CMARK_GFM_EXPORT
# endif
# endif
# ifndef CMARK_GFM_NO_EXPORT
# define CMARK_GFM_NO_EXPORT
# endif
#endif
#ifndef CMARK_GFM_DEPRECATED
# define CMARK_GFM_DEPRECATED __declspec(deprecated)
#endif
#ifndef CMARK_GFM_DEPRECATED_EXPORT
# define CMARK_GFM_DEPRECATED_EXPORT CMARK_GFM_EXPORT CMARK_GFM_DEPRECATED
#endif
#ifndef CMARK_GFM_DEPRECATED_NO_EXPORT
# define CMARK_GFM_DEPRECATED_NO_EXPORT CMARK_GFM_NO_EXPORT CMARK_GFM_DEPRECATED
#endif
/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */
#if 0 /* DEFINE_NO_DEPRECATED */
# ifndef CMARK_GFM_NO_DEPRECATED
# define CMARK_GFM_NO_DEPRECATED
# endif
#endif
#endif /* CMARK_GFM_EXPORT_H */

View File

@ -0,0 +1,7 @@
#ifndef CMARK_GFM_VERSION_H
#define CMARK_GFM_VERSION_H
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 13)
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.13"
#endif

View File

@ -0,0 +1,19 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "libcmark-gfm-extensions_static" for configuration "Release"
set_property(TARGET libcmark-gfm-extensions_static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(libcmark-gfm-extensions_static PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libcmark-gfm-extensions.a"
)
list(APPEND _cmake_import_check_targets libcmark-gfm-extensions_static )
list(APPEND _cmake_import_check_files_for_libcmark-gfm-extensions_static "${_IMPORT_PREFIX}/lib/libcmark-gfm-extensions.a" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View File

@ -0,0 +1,101 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.0 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.3")
message(FATAL_ERROR "CMake >= 2.8.3 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.3...3.28)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS libcmark-gfm-extensions_static)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target libcmark-gfm-extensions_static
add_library(libcmark-gfm-extensions_static STATIC IMPORTED)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/cmark-gfm-extensions-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
if(CMAKE_VERSION VERSION_LESS "3.28"
OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target}
OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}")
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
endif()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

View File

@ -0,0 +1,28 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "cmark-gfm" for configuration "Release"
set_property(TARGET cmark-gfm APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(cmark-gfm PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/cmark-gfm.exe"
)
list(APPEND _cmake_import_check_targets cmark-gfm )
list(APPEND _cmake_import_check_files_for_cmark-gfm "${_IMPORT_PREFIX}/bin/cmark-gfm.exe" )
# Import target "libcmark-gfm_static" for configuration "Release"
set_property(TARGET libcmark-gfm_static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(libcmark-gfm_static PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libcmark-gfm.a"
)
list(APPEND _cmake_import_check_targets libcmark-gfm_static )
list(APPEND _cmake_import_check_files_for_libcmark-gfm_static "${_IMPORT_PREFIX}/lib/libcmark-gfm.a" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View File

@ -0,0 +1,104 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.0 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.3")
message(FATAL_ERROR "CMake >= 2.8.3 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.3...3.28)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS cmark-gfm libcmark-gfm_static)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target cmark-gfm
add_executable(cmark-gfm IMPORTED)
# Create imported target libcmark-gfm_static
add_library(libcmark-gfm_static STATIC IMPORTED)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/cmark-gfm-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
if(CMAKE_VERSION VERSION_LESS "3.28"
OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target}
OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}")
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
endif()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

Binary file not shown.

BIN
3rdparty/cmark-gfm/lib/libcmark-gfm.a vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,10 @@
prefix=F:/SourceCode/ctai/3rdparty/cmark-gfm
exec_prefix=F:/SourceCode/ctai/3rdparty/cmark-gfm
libdir=F:/SourceCode/ctai/3rdparty/cmark-gfm/lib
includedir=F:/SourceCode/ctai/3rdparty/cmark-gfm/include
Name: libcmark-gfm
Description: CommonMark parsing, rendering, and manipulation with GitHub Flavored Markdown extensions
Version: 0.29.0.gfm.13
Libs: -L${libdir} -lcmark-gfm -lcmark-gfm-extensions
Cflags: -I${includedir}

View File

@ -0,0 +1,78 @@
.TH "cmark-gfm" "1" "March 24, 2016" "LOCAL" "General Commands Manual"
.SH "NAME"
\fBcmark\fR
\- convert CommonMark formatted text with GitHub Flavored Markdown extensions to HTML
.SH "SYNOPSIS"
.HP 6n
\fBcmark-gfm\fR
[options]
file*
.SH "DESCRIPTION"
\fBcmark-gfm\fR
converts Markdown formatted plain text to either HTML, groff man,
CommonMark XML, LaTeX, or CommonMark, using the conventions
described in the CommonMark spec. It reads input from \fIstdin\fR
or the specified files (concatenating their contents) and writes
output to \fIstdout\fR.
.SH "OPTIONS"
.TP 12n
.B \-\-to, \-t \f[I]FORMAT\f[]
Specify output format (\f[C]html\f[], \f[C]man\f[], \f[C]xml\f[],
\f[C]latex\f[], \f[C]commonmark\f[]).
.TP 12n
.B \-\-width \f[I]WIDTH\f[]
Specify a column width to which to wrap the output. For no wrapping, use
the value 0 (the default). This option currently only affects the
commonmark, latex, and man renderers.
.TP 12n
.B \-\-hardbreaks
Render soft breaks (newlines inside paragraphs in the CommonMark source)
as hard line breaks in the target format. If this option is specified,
hard wrapping is disabled for CommonMark output, regardless of the value
given with \-\-width.
.TP 12n
.B \-\-nobreaks
Render soft breaks as spaces. If this option is specified,
hard wrapping is disabled for all output formats, regardless of the value
given with \-\-width.
.TP 12n
.B \-\-sourcepos
Include source position attribute.
.TP 12n
.B \-\-normalize
Consolidate adjacent text nodes.
.TP 12n
.B \-\-extension, \-e \f[I]EXTENSION_NAME\f[]
Specify an extension name to use.
.TP 12n
.B \-\-list\-extensions
List available extensions and quit.
.TP 12n
.B \-\-validate-utf8
Validate UTF-8, replacing illegal sequences with U+FFFD.
.TP 12n
.B \-\-smart
Use smart punctuation. Straight double and single quotes will
be rendered as curly quotes, depending on their position.
\f[C]\-\-\f[] will be rendered as an en-dash.
\f[C]\-\-\-\f[] will be rendered as an em-dash.
\f[C]...\f[] will be rendered as ellipses.
.TP 12n
.B \-\-unsafe
Render raw HTML and potentially dangerous URLs.
(Raw HTML is not replaced by a placeholder comment; potentially
dangerous URLs are not replaced by empty strings.) Dangerous
URLs are those that begin with `javascript:`, `vbscript:`,
`file:`, or `data:` (except for `image/png`, `image/gif`,
`image/jpeg`, or `image/webp` mime types).
.TP 12n
.B \-\-help
Print usage information.
.TP 12n
.B \-\-version
Print version.
.SH "AUTHORS"
John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
.SH "SEE ALSO"
.PP
CommonMark spec: \f[C]http://spec.commonmark.org\f[].

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,11 @@ else()
endif()
LIST(APPEND CMAKE_PREFIX_PATH ${QT_DIR} ${MSYS})
#JSON
SET(JSON ${PROJECT_SOURCE_DIR}/3rdparty/json)
include_directories(${JSON}/include)
#CURL
find_package(CURL REQUIRED)
#cmark
@ -67,9 +72,6 @@ MESSAGE(STATUS "QT_DIR_PATH=${QT_DIR}")
MESSAGE(STATUS "JSON_DIR_PATH=${JSON}")
MESSAGE(STATUS "----------基础路径输出 END---------------")
#JSON
SET(JSON ${PROJECT_SOURCE_DIR}/3rdparty/json)
include_directories(${JSON}/include)
#suicpp
@ -135,12 +137,12 @@ configure_file (version.h.in version.h @ONLY)
SET(CMAKE_EXE_LINKER_FLAGS -static)
target_link_libraries(
${PROJECT_NAME} PRIVATE
${PROJECT_NAME} PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
cmark::cmark
CURL::libcurl
cmark::cmark
)

183
src/ctai_cmark-gfm.cpp Normal file
View File

@ -0,0 +1,183 @@
#include "ctai_cmark-gfm.h"
ctai_cmark_gfm::ctai_cmark_gfm(QTextEdit *editor, QObject *parent) : QObject(parent),
m_editor(editor),
m_bufferMax(8192)
{
}
void ctai_cmark_gfm::processInput(const QString &text)
{
// 更新缓冲区
m_buffer += text;
qDebug()<<"处理的块:"<<m_buffer;
handleBufferOverflow();
// 语法状态检测
SyntaxState newState = detectSyntaxState(m_buffer);
updateSyntaxStack(newState);
// 渲染决策
if (shouldRender(newState))
{
renderContent();
}
}
// 处理缓冲区溢出
void ctai_cmark_gfm::handleBufferOverflow()
{
if (m_buffer.length() > m_bufferMax * 1.2)
{
int removeCount = m_buffer.length() - m_bufferMax;
m_buffer.remove(0, removeCount);
adjustSyntaxPositions(removeCount);
}
}
// 调整语法标签位置
void ctai_cmark_gfm::adjustSyntaxPositions(int offset)
{
std::stack<SyntaxTag> adjustedStack;
while (!m_syntaxStack.empty())
{
SyntaxTag tag = m_syntaxStack.top();
m_syntaxStack.pop();
tag.startPos = qMax(0, tag.startPos - offset);
if (tag.startPos >= 0)
{
adjustedStack.push(tag);
}
}
m_syntaxStack = adjustedStack;
}
// 语法状态检测
SyntaxState ctai_cmark_gfm::detectSyntaxState(const QString &buffer)
{
SyntaxState state;
static const QVector<QPair<QRegularExpression, SyntaxType>> syntaxPatterns = {
{QRegularExpression(R"(\*\*(?!\s))"), Bold},
{QRegularExpression(R"(\*(?!\s))"), Italic},
{QRegularExpression(R"(^#{1,6}\s)"), Heading},
{QRegularExpression(R"(^```+[\s\S]*?```)", QRegularExpression::MultilineOption), CodeBlock},
{QRegularExpression(R"(^[\*\+-]\s)"), List},
{QRegularExpression(R"(^>\s)"), Blockquote},
{QRegularExpression(R"($$.*?$$$.*?$)"), Link},
{QRegularExpression(R"(!$$.*?$$$.*?$)"), Image}};
for (const auto &[pattern, type] : syntaxPatterns)
{
QRegularExpressionMatchIterator it = pattern.globalMatch(buffer);
while (it.hasNext())
{
QRegularExpressionMatch match = it.next();
state.activeTags.insert(type, match.captured());
}
}
state.needsClosure = !m_syntaxStack.empty() &&
(buffer.length() - m_syntaxStack.top().startPos) > m_bufferMax / 2;
return state;
}
// 更新语法标签栈
void ctai_cmark_gfm::updateSyntaxStack(const SyntaxState &newState)
{
// 处理标签闭合
auto it = newState.activeTags.begin();
while (it != newState.activeTags.end())
{
if (it.key() == CodeBlock && m_syntaxStack.top().type == CodeBlock)
{
m_syntaxStack.pop();
}
// 其他标签闭合逻辑...
++it;
}
// 处理新标签
for (auto type : newState.activeTags.keys())
{
SyntaxTag newTag;
newTag.type = type;
newTag.startPos = m_buffer.lastIndexOf(newState.activeTags[type]);
newTag.opener = newState.activeTags[type];
newTag.closer = getCloserForType(type);
m_syntaxStack.push(newTag);
}
}
// 获取闭合标签
QString ctai_cmark_gfm::getCloserForType(SyntaxType type)
{
static const QMap<SyntaxType, QString> closers = {
{CodeBlock, "\n```"},
{Bold, "**"},
{Italic, "*"},
{Heading, "\n"},
{List, "\n"},
{Blockquote, "\n"},
{Link, ")"},
{Image, ")"}};
return closers.value(type, "");
}
// 渲染决策
bool ctai_cmark_gfm::shouldRender(const SyntaxState &state)
{
return state.needsClosure ||
(!m_syntaxStack.empty() && m_buffer.length() - m_syntaxStack.top().startPos > 512) ||
m_buffer.length() >= m_bufferMax;
}
void ctai_cmark_gfm::renderContent()
{
QString renderContent = m_buffer;
// 自动闭合未完成的标签
while (!m_syntaxStack.empty())
{
const SyntaxTag &tag = m_syntaxStack.top();
if (!renderContent.contains(tag.closer))
{
renderContent += tag.closer;
}
m_syntaxStack.pop();
}
// 使用cmark解析
cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
cmark_parser_feed(parser, renderContent.toUtf8().constData(), renderContent.size());
cmark_node *doc = cmark_parser_finish(parser);
// 转换为HTML
char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
updateEditor(QString::fromUtf8(html));
// 清理资源
cmark_node_free(doc);
cmark_parser_free(parser);
free(html);
// 重置缓冲区
m_buffer.clear();
}
// 更新编辑器内容(保持滚动位置)
void ctai_cmark_gfm::updateEditor(const QString &html)
{
QTextCursor cursor(m_editor->document());
int oldHeight = m_editor->document()->size().height();
bool atBottom = m_editor->verticalScrollBar()->value() ==
m_editor->verticalScrollBar()->maximum();
cursor.select(QTextCursor::Document);
cursor.insertHtml(html);
// 滚动位置处理
if (atBottom)
{
m_editor->verticalScrollBar()->setValue(m_editor->verticalScrollBar()->maximum());
}
else
{
int newHeight = m_editor->document()->size().height();
m_editor->verticalScrollBar()->setValue(m_editor->verticalScrollBar()->value() + (newHeight - oldHeight));
}
}

52
src/ctai_cmark-gfm.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef CTAI_CMARK_GFM_H
#define CTAI_CMARK_GFM_H
#include <QTextEdit>
#include <cmark.h>
#include <stack>
#include <QRegularExpression>
#include <QScrollBar>
enum SyntaxType {
CodeBlock, // 代码块
Bold, // 粗体
Italic, // 斜体
Heading, // 标题
List, // 列表
Blockquote, // 引用
Link, // 链接
Image, // 图片
CustomBlock // 自定义块
};
struct SyntaxTag {
SyntaxType type;
int startPos;
QString opener;
QString closer;
};
struct SyntaxState {
QMap<SyntaxType, QString> activeTags;
bool needsClosure = false;
};
class ctai_cmark_gfm : public QObject {
Q_OBJECT
public:
ctai_cmark_gfm(QTextEdit *editor, QObject *parent = nullptr);
void processInput(const QString &text);
private:
QTextEdit *m_editor;
const int m_bufferMax;
QString m_buffer;
std::stack<SyntaxTag> m_syntaxStack; // 语法标签栈
void handleBufferOverflow();
void adjustSyntaxPositions(int offset);
SyntaxState detectSyntaxState(const QString &buffer);
void updateSyntaxStack(const SyntaxState &newState);
bool shouldRender(const SyntaxState &state);
QString getCloserForType(SyntaxType type);
void renderContent();
void updateEditor(const QString &html);
};
#endif

View File

@ -148,8 +148,8 @@ void ctai_session_info::ctai_session_curl_state_tips(std::string state_str)
}
void ctai_session_info::ctai_session_set_steam_mode(bool state)
{
m_stream_mode!=state;
qDebug() << "steam mode:" << state;
m_stream_mode = state; // 直接将switch的状态赋值给m_stream_mode
qDebug() << "steam mode:" << m_stream_mode;
}
void ctai_session_info::ctai_session_user_sending()
{

View File

@ -23,7 +23,7 @@ bool ctai_switch_button::SwBtn_isChecked() const
void ctai_switch_button::setSwBtn_Status(bool check)
{
m_SwBtn_Status=check;
m_SwBtn_timer.start(10);
m_SwBtn_timer.start(1);
}
void ctai_switch_button::setSwBtn_BackgroundColor(QColor color)