Fossil SCM
Initial implementation of <span data> wrappers around @name and #tag references. Seems functional on a test-markdown-render basis, but the definitions of what counts as a reference and what to do with them still remains to be handled.
Commit
31a607d33ce903ab5d11343291740fc5af3363893dbe7a0c46ebb8fa2c0053be
Parent
60ed1ff9511306a…
2 files changed
+53
+30
+53
| --- src/markdown.c | ||
| +++ src/markdown.c | ||
| @@ -21,10 +21,11 @@ | ||
| 21 | 21 | |
| 22 | 22 | #include "config.h" |
| 23 | 23 | #include "markdown.h" |
| 24 | 24 | |
| 25 | 25 | #include <assert.h> |
| 26 | +#include <ctype.h> | |
| 26 | 27 | #include <string.h> |
| 27 | 28 | #include <stdlib.h> |
| 28 | 29 | |
| 29 | 30 | #define MKD_LI_END 8 /* internal list flag */ |
| 30 | 31 | |
| @@ -39,10 +40,16 @@ | ||
| 39 | 40 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 40 | 41 | MKDA_NORMAL, /* normal http/http/ftp link */ |
| 41 | 42 | MKDA_EXPLICIT_EMAIL, /* e-mail link with explicit mailto: */ |
| 42 | 43 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 43 | 44 | }; |
| 45 | + | |
| 46 | +/* mkd_tagspan -- type of tagged <span> */ | |
| 47 | +enum mkd_tagspan { | |
| 48 | + MKDT_ATREF, /* @name references, as in /chat attention targeting */ | |
| 49 | + MKDT_HASH, /* #hash tags, message IDs, etc. */ | |
| 50 | +}; | |
| 44 | 51 | |
| 45 | 52 | /* mkd_renderer -- functions for rendering parsed data */ |
| 46 | 53 | struct mkd_renderer { |
| 47 | 54 | /* document level callbacks */ |
| 48 | 55 | void (*prolog)(struct Blob *ob, void *opaque); |
| @@ -77,10 +84,12 @@ | ||
| 77 | 84 | struct Blob *alt, void *opaque); |
| 78 | 85 | int (*linebreak)(struct Blob *ob, void *opaque); |
| 79 | 86 | int (*link)(struct Blob *ob, struct Blob *link, struct Blob *title, |
| 80 | 87 | struct Blob *content, void *opaque); |
| 81 | 88 | int (*raw_html_tag)(struct Blob *ob, struct Blob *tag, void *opaque); |
| 89 | + int (*tagspan)(struct Blob *ob, struct Blob *ref, enum mkd_tagspan type, | |
| 90 | + void *opaque); | |
| 82 | 91 | int (*triple_emphasis)(struct Blob *ob, struct Blob *text, |
| 83 | 92 | char c, void *opaque); |
| 84 | 93 | |
| 85 | 94 | /* low level callbacks - NULL copies input directly into the output */ |
| 86 | 95 | void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque); |
| @@ -869,10 +878,52 @@ | ||
| 869 | 878 | blob_append(ob, data, end); |
| 870 | 879 | } |
| 871 | 880 | return end; |
| 872 | 881 | } |
| 873 | 882 | |
| 883 | + | |
| 884 | +/* char_atref_tag -- '@' followed by "word" characters to tag | |
| 885 | + * at-references */ | |
| 886 | +static size_t char_atref_tag( | |
| 887 | + struct Blob *ob, | |
| 888 | + struct render *rndr, | |
| 889 | + char *data, | |
| 890 | + size_t offset, | |
| 891 | + size_t size | |
| 892 | +){ | |
| 893 | + size_t end; | |
| 894 | + struct Blob work = BLOB_INITIALIZER; | |
| 895 | + | |
| 896 | + if (size < 2 || !isalpha(data[1])) return 0; | |
| 897 | + for (end = 2; (end < size) && isalnum(data[end]); ++end) /* */ ; | |
| 898 | + | |
| 899 | + blob_init(&work, data + 1, end - 1); | |
| 900 | + rndr->make.tagspan(ob, &work, MKDT_ATREF, rndr->make.opaque); | |
| 901 | + return end; | |
| 902 | +} | |
| 903 | + | |
| 904 | + | |
| 905 | +/* char_hashref_tag -- '#' followed by "word" characters to tag | |
| 906 | + * post numbers, hashtags, etc. */ | |
| 907 | +static size_t char_hashref_tag( | |
| 908 | + struct Blob *ob, | |
| 909 | + struct render *rndr, | |
| 910 | + char *data, | |
| 911 | + size_t offset, | |
| 912 | + size_t size | |
| 913 | +){ | |
| 914 | + size_t end; | |
| 915 | + struct Blob work = BLOB_INITIALIZER; | |
| 916 | + | |
| 917 | + if (size < 2 || !isalnum(data[1])) return 0; | |
| 918 | + for (end = 2; (end < size) && (isalnum(data[end] || data[end] == '.')); ++end) /* */ ; | |
| 919 | + | |
| 920 | + blob_init(&work, data + 1, end - 1); | |
| 921 | + rndr->make.tagspan(ob, &work, MKDT_HASH, rndr->make.opaque); | |
| 922 | + return end; | |
| 923 | +} | |
| 924 | + | |
| 874 | 925 | |
| 875 | 926 | /* char_langle_tag -- '<' when tags or autolinks are allowed */ |
| 876 | 927 | static size_t char_langle_tag( |
| 877 | 928 | struct Blob *ob, |
| 878 | 929 | struct render *rndr, |
| @@ -2221,10 +2272,12 @@ | ||
| 2221 | 2272 | } |
| 2222 | 2273 | } |
| 2223 | 2274 | if( rndr.make.codespan ) rndr.active_char['`'] = char_codespan; |
| 2224 | 2275 | if( rndr.make.linebreak ) rndr.active_char['\n'] = char_linebreak; |
| 2225 | 2276 | if( rndr.make.image || rndr.make.link ) rndr.active_char['['] = char_link; |
| 2277 | + rndr.active_char['@'] = char_atref_tag; | |
| 2278 | + rndr.active_char['#'] = char_hashref_tag; | |
| 2226 | 2279 | rndr.active_char['<'] = char_langle_tag; |
| 2227 | 2280 | rndr.active_char['\\'] = char_escape; |
| 2228 | 2281 | rndr.active_char['&'] = char_entity; |
| 2229 | 2282 | |
| 2230 | 2283 | /* first pass: looking for references, copying everything else */ |
| 2231 | 2284 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -21,10 +21,11 @@ | |
| 21 | |
| 22 | #include "config.h" |
| 23 | #include "markdown.h" |
| 24 | |
| 25 | #include <assert.h> |
| 26 | #include <string.h> |
| 27 | #include <stdlib.h> |
| 28 | |
| 29 | #define MKD_LI_END 8 /* internal list flag */ |
| 30 | |
| @@ -39,10 +40,16 @@ | |
| 39 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 40 | MKDA_NORMAL, /* normal http/http/ftp link */ |
| 41 | MKDA_EXPLICIT_EMAIL, /* e-mail link with explicit mailto: */ |
| 42 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 43 | }; |
| 44 | |
| 45 | /* mkd_renderer -- functions for rendering parsed data */ |
| 46 | struct mkd_renderer { |
| 47 | /* document level callbacks */ |
| 48 | void (*prolog)(struct Blob *ob, void *opaque); |
| @@ -77,10 +84,12 @@ | |
| 77 | struct Blob *alt, void *opaque); |
| 78 | int (*linebreak)(struct Blob *ob, void *opaque); |
| 79 | int (*link)(struct Blob *ob, struct Blob *link, struct Blob *title, |
| 80 | struct Blob *content, void *opaque); |
| 81 | int (*raw_html_tag)(struct Blob *ob, struct Blob *tag, void *opaque); |
| 82 | int (*triple_emphasis)(struct Blob *ob, struct Blob *text, |
| 83 | char c, void *opaque); |
| 84 | |
| 85 | /* low level callbacks - NULL copies input directly into the output */ |
| 86 | void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque); |
| @@ -869,10 +878,52 @@ | |
| 869 | blob_append(ob, data, end); |
| 870 | } |
| 871 | return end; |
| 872 | } |
| 873 | |
| 874 | |
| 875 | /* char_langle_tag -- '<' when tags or autolinks are allowed */ |
| 876 | static size_t char_langle_tag( |
| 877 | struct Blob *ob, |
| 878 | struct render *rndr, |
| @@ -2221,10 +2272,12 @@ | |
| 2221 | } |
| 2222 | } |
| 2223 | if( rndr.make.codespan ) rndr.active_char['`'] = char_codespan; |
| 2224 | if( rndr.make.linebreak ) rndr.active_char['\n'] = char_linebreak; |
| 2225 | if( rndr.make.image || rndr.make.link ) rndr.active_char['['] = char_link; |
| 2226 | rndr.active_char['<'] = char_langle_tag; |
| 2227 | rndr.active_char['\\'] = char_escape; |
| 2228 | rndr.active_char['&'] = char_entity; |
| 2229 | |
| 2230 | /* first pass: looking for references, copying everything else */ |
| 2231 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -21,10 +21,11 @@ | |
| 21 | |
| 22 | #include "config.h" |
| 23 | #include "markdown.h" |
| 24 | |
| 25 | #include <assert.h> |
| 26 | #include <ctype.h> |
| 27 | #include <string.h> |
| 28 | #include <stdlib.h> |
| 29 | |
| 30 | #define MKD_LI_END 8 /* internal list flag */ |
| 31 | |
| @@ -39,10 +40,16 @@ | |
| 40 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ |
| 41 | MKDA_NORMAL, /* normal http/http/ftp link */ |
| 42 | MKDA_EXPLICIT_EMAIL, /* e-mail link with explicit mailto: */ |
| 43 | MKDA_IMPLICIT_EMAIL /* e-mail link without mailto: */ |
| 44 | }; |
| 45 | |
| 46 | /* mkd_tagspan -- type of tagged <span> */ |
| 47 | enum mkd_tagspan { |
| 48 | MKDT_ATREF, /* @name references, as in /chat attention targeting */ |
| 49 | MKDT_HASH, /* #hash tags, message IDs, etc. */ |
| 50 | }; |
| 51 | |
| 52 | /* mkd_renderer -- functions for rendering parsed data */ |
| 53 | struct mkd_renderer { |
| 54 | /* document level callbacks */ |
| 55 | void (*prolog)(struct Blob *ob, void *opaque); |
| @@ -77,10 +84,12 @@ | |
| 84 | struct Blob *alt, void *opaque); |
| 85 | int (*linebreak)(struct Blob *ob, void *opaque); |
| 86 | int (*link)(struct Blob *ob, struct Blob *link, struct Blob *title, |
| 87 | struct Blob *content, void *opaque); |
| 88 | int (*raw_html_tag)(struct Blob *ob, struct Blob *tag, void *opaque); |
| 89 | int (*tagspan)(struct Blob *ob, struct Blob *ref, enum mkd_tagspan type, |
| 90 | void *opaque); |
| 91 | int (*triple_emphasis)(struct Blob *ob, struct Blob *text, |
| 92 | char c, void *opaque); |
| 93 | |
| 94 | /* low level callbacks - NULL copies input directly into the output */ |
| 95 | void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque); |
| @@ -869,10 +878,52 @@ | |
| 878 | blob_append(ob, data, end); |
| 879 | } |
| 880 | return end; |
| 881 | } |
| 882 | |
| 883 | |
| 884 | /* char_atref_tag -- '@' followed by "word" characters to tag |
| 885 | * at-references */ |
| 886 | static size_t char_atref_tag( |
| 887 | struct Blob *ob, |
| 888 | struct render *rndr, |
| 889 | char *data, |
| 890 | size_t offset, |
| 891 | size_t size |
| 892 | ){ |
| 893 | size_t end; |
| 894 | struct Blob work = BLOB_INITIALIZER; |
| 895 | |
| 896 | if (size < 2 || !isalpha(data[1])) return 0; |
| 897 | for (end = 2; (end < size) && isalnum(data[end]); ++end) /* */ ; |
| 898 | |
| 899 | blob_init(&work, data + 1, end - 1); |
| 900 | rndr->make.tagspan(ob, &work, MKDT_ATREF, rndr->make.opaque); |
| 901 | return end; |
| 902 | } |
| 903 | |
| 904 | |
| 905 | /* char_hashref_tag -- '#' followed by "word" characters to tag |
| 906 | * post numbers, hashtags, etc. */ |
| 907 | static size_t char_hashref_tag( |
| 908 | struct Blob *ob, |
| 909 | struct render *rndr, |
| 910 | char *data, |
| 911 | size_t offset, |
| 912 | size_t size |
| 913 | ){ |
| 914 | size_t end; |
| 915 | struct Blob work = BLOB_INITIALIZER; |
| 916 | |
| 917 | if (size < 2 || !isalnum(data[1])) return 0; |
| 918 | for (end = 2; (end < size) && (isalnum(data[end] || data[end] == '.')); ++end) /* */ ; |
| 919 | |
| 920 | blob_init(&work, data + 1, end - 1); |
| 921 | rndr->make.tagspan(ob, &work, MKDT_HASH, rndr->make.opaque); |
| 922 | return end; |
| 923 | } |
| 924 | |
| 925 | |
| 926 | /* char_langle_tag -- '<' when tags or autolinks are allowed */ |
| 927 | static size_t char_langle_tag( |
| 928 | struct Blob *ob, |
| 929 | struct render *rndr, |
| @@ -2221,10 +2272,12 @@ | |
| 2272 | } |
| 2273 | } |
| 2274 | if( rndr.make.codespan ) rndr.active_char['`'] = char_codespan; |
| 2275 | if( rndr.make.linebreak ) rndr.active_char['\n'] = char_linebreak; |
| 2276 | if( rndr.make.image || rndr.make.link ) rndr.active_char['['] = char_link; |
| 2277 | rndr.active_char['@'] = char_atref_tag; |
| 2278 | rndr.active_char['#'] = char_hashref_tag; |
| 2279 | rndr.active_char['<'] = char_langle_tag; |
| 2280 | rndr.active_char['\\'] = char_escape; |
| 2281 | rndr.active_char['&'] = char_entity; |
| 2282 | |
| 2283 | /* first pass: looking for references, copying everything else */ |
| 2284 |
+30
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -530,10 +530,39 @@ | ||
| 530 | 530 | BLOB_APPEND_BLOB(ob, content); |
| 531 | 531 | } |
| 532 | 532 | blob_append(ob, zClose, -1); |
| 533 | 533 | return 1; |
| 534 | 534 | } |
| 535 | + | |
| 536 | +/* Invoked for @name and #tag tagged words, marked up in the | |
| 537 | +** output text in a way that JS and CSS can do something | |
| 538 | +** interesting with them. This isn't standard Markdown, so | |
| 539 | +** it's implementation-specific what occurs here. More, each | |
| 540 | +** Fossil feature using Markdown is free to apply markup and | |
| 541 | +** behavior to these in feature-specific ways. | |
| 542 | +*/ | |
| 543 | +static int html_tagspan( | |
| 544 | + struct Blob *ob, /* Write the output here */ | |
| 545 | + struct Blob *text, /* The stuff in between the code span marks */ | |
| 546 | + enum mkd_tagspan type, /* which type of tagspan we're creating */ | |
| 547 | + void *opaque | |
| 548 | +){ | |
| 549 | + if( text==0 ){ | |
| 550 | + /* no-op */ | |
| 551 | + }else{ | |
| 552 | + BLOB_APPEND_LITERAL(ob, "<span data-"); | |
| 553 | + switch (type) { | |
| 554 | + case MKDT_ATREF: BLOB_APPEND_LITERAL(ob, "atref"); break; | |
| 555 | + case MKDT_HASH: BLOB_APPEND_LITERAL(ob, "hash"); break; | |
| 556 | + } | |
| 557 | + BLOB_APPEND_LITERAL(ob, "=\""); | |
| 558 | + html_quote(ob, blob_buffer(text), blob_size(text)); | |
| 559 | + BLOB_APPEND_LITERAL(ob, "\""); | |
| 560 | + blob_appendf(ob, ">%b</span>", text); | |
| 561 | + } | |
| 562 | + return 1; | |
| 563 | +} | |
| 535 | 564 | |
| 536 | 565 | static int html_triple_emphasis( |
| 537 | 566 | struct Blob *ob, |
| 538 | 567 | struct Blob *text, |
| 539 | 568 | char c, |
| @@ -586,10 +615,11 @@ | ||
| 586 | 615 | html_emphasis, |
| 587 | 616 | html_image, |
| 588 | 617 | html_linebreak, |
| 589 | 618 | html_link, |
| 590 | 619 | html_raw_html_tag, |
| 620 | + html_tagspan, | |
| 591 | 621 | html_triple_emphasis, |
| 592 | 622 | |
| 593 | 623 | /* low level elements */ |
| 594 | 624 | 0, /* entity */ |
| 595 | 625 | html_normal_text, |
| 596 | 626 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -530,10 +530,39 @@ | |
| 530 | BLOB_APPEND_BLOB(ob, content); |
| 531 | } |
| 532 | blob_append(ob, zClose, -1); |
| 533 | return 1; |
| 534 | } |
| 535 | |
| 536 | static int html_triple_emphasis( |
| 537 | struct Blob *ob, |
| 538 | struct Blob *text, |
| 539 | char c, |
| @@ -586,10 +615,11 @@ | |
| 586 | html_emphasis, |
| 587 | html_image, |
| 588 | html_linebreak, |
| 589 | html_link, |
| 590 | html_raw_html_tag, |
| 591 | html_triple_emphasis, |
| 592 | |
| 593 | /* low level elements */ |
| 594 | 0, /* entity */ |
| 595 | html_normal_text, |
| 596 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -530,10 +530,39 @@ | |
| 530 | BLOB_APPEND_BLOB(ob, content); |
| 531 | } |
| 532 | blob_append(ob, zClose, -1); |
| 533 | return 1; |
| 534 | } |
| 535 | |
| 536 | /* Invoked for @name and #tag tagged words, marked up in the |
| 537 | ** output text in a way that JS and CSS can do something |
| 538 | ** interesting with them. This isn't standard Markdown, so |
| 539 | ** it's implementation-specific what occurs here. More, each |
| 540 | ** Fossil feature using Markdown is free to apply markup and |
| 541 | ** behavior to these in feature-specific ways. |
| 542 | */ |
| 543 | static int html_tagspan( |
| 544 | struct Blob *ob, /* Write the output here */ |
| 545 | struct Blob *text, /* The stuff in between the code span marks */ |
| 546 | enum mkd_tagspan type, /* which type of tagspan we're creating */ |
| 547 | void *opaque |
| 548 | ){ |
| 549 | if( text==0 ){ |
| 550 | /* no-op */ |
| 551 | }else{ |
| 552 | BLOB_APPEND_LITERAL(ob, "<span data-"); |
| 553 | switch (type) { |
| 554 | case MKDT_ATREF: BLOB_APPEND_LITERAL(ob, "atref"); break; |
| 555 | case MKDT_HASH: BLOB_APPEND_LITERAL(ob, "hash"); break; |
| 556 | } |
| 557 | BLOB_APPEND_LITERAL(ob, "=\""); |
| 558 | html_quote(ob, blob_buffer(text), blob_size(text)); |
| 559 | BLOB_APPEND_LITERAL(ob, "\""); |
| 560 | blob_appendf(ob, ">%b</span>", text); |
| 561 | } |
| 562 | return 1; |
| 563 | } |
| 564 | |
| 565 | static int html_triple_emphasis( |
| 566 | struct Blob *ob, |
| 567 | struct Blob *text, |
| 568 | char c, |
| @@ -586,10 +615,11 @@ | |
| 615 | html_emphasis, |
| 616 | html_image, |
| 617 | html_linebreak, |
| 618 | html_link, |
| 619 | html_raw_html_tag, |
| 620 | html_tagspan, |
| 621 | html_triple_emphasis, |
| 622 | |
| 623 | /* low level elements */ |
| 624 | 0, /* entity */ |
| 625 | html_normal_text, |
| 626 |