Codebase list mdp-src / 37692c7
Merge tag 'upstream/1.0.7' Upstream version 1.0.7 Lev Lamberov 7 years ago
8 changed file(s) with 288 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
1010 dopsi
1111 alx741
1212 mnalt
13 guobin2312
14 lukebond
1315
2424
2525 #define MDP_VER_MAJOR 1
2626 #define MDP_VER_MINOR 0
27 #define MDP_VER_REVISION 6
27 #define MDP_VER_REVISION 7
2828
2929 #endif // !defined( MAIN_H )
4848 #define CODE_INDENT 4
4949 #define UNORDERED_LIST_MAX_LEVEL 3
5050
51 deck_t *markdown_load(FILE *input);
51 deck_t *markdown_load(FILE *input, int noexpand);
5252 int markdown_analyse(cstring_t *text, int prev);
5353 void markdown_debug(deck_t *deck, int debug);
54 void expand_character_entities(line_t *line);
5455 void adjust_line_length(line_t *line);
5556 int next_nonblank(cstring_t *text, int i);
5657 int prev_blank(cstring_t *text, int i);
6161 void fade_in(WINDOW *window, int trans, int colors, int invert);
6262 int int_length (int val);
6363 int get_slide_number(char init);
64 void setup_list_strings(void);
6465
6566 #endif // !defined( VIEWER_H )
44 .\"
55 .
66 .
7 .TH MDP 1 "2016-02-07" "User Commands"
7 .TH MDP 1 "2016-04-02" "User Commands"
88 .SH NAME
99 mdp \- A command-line based
1010 markdown presentation tool
3232 the presentation is read from standard input.
3333 .SS "Output Control"
3434 .TP
35 .BR \-e ", " \-\^\-expand
36 Enable character entity expansion (e.g. '>' becomes '>').
37 .TP
3538 .BR \-f ", " \-\^\-nofade
3639 Disable color fading in 256 color mode.
3740 .TP
5154 .TP
5255 .BR \-v ", " \-\^\-version
5356 Display version and license information.
57 .
58 .SH ENVIRONMENT VARIABLES
59 .SS "Output Control"
60 .TP
61 .BR MDP_LIST_HEAD[1-3],\ MDP_LIST_OPEN[1-3]
62 Controls the list characters of unordered lists.
63
64 The default is equivalent to:
65 .br
66 MDP_LIST_OPEN1=' | '
67 .br
68 MDP_LIST_OPEN2=' | '
69 .br
70 MDP_LIST_OPEN3=' | '
71 .br
72 MDP_LIST_HEAD1=' +- '
73 .br
74 MDP_LIST_HEAD2=' +- '
75 .br
76 MDP_LIST_HEAD3=' +- '
5477 .
5578 .SH MARKDOWN FORMATTING
5679 For a complete list of supported markups, refer the sample presentation
3030 fprintf(stderr, "%s", "A command-line based markdown presentation tool.\n\n");
3131 fprintf(stderr, "%s", " -d, --debug enable debug messages on STDERR\n");
3232 fprintf(stderr, "%s", " add it multiple times to increases debug level\n");
33 fprintf(stderr, "%s", " -e, --expand enable character entity expansion\n");
3334 fprintf(stderr, "%s", " -f, --nofade disable color fading in 256 color mode\n");
3435 fprintf(stderr, "%s", " -h, --help display this help and exit\n");
3536 fprintf(stderr, "%s", " -i, --invert swap black and white color\n");
5556 int notrans = 0; // disable transparency
5657 int nofade = 0; // disable fading
5758 int invert = 0; // invert color (black on white)
59 int noexpand = 1; // disable character entity expansion
5860 int reload = 0; // reload page N (0 means no reload)
5961 int noreload = 1; // reload disabled until we know input is a file
6062 int slidenum = 2; // 0:don't show; 1:show #; 2:show #/#
6163
6264 // define command-line options
6365 struct option longopts[] = {
64 { "debug", no_argument, 0, 'd' },
65 { "nofade", no_argument, 0, 'f' },
66 { "help", no_argument, 0, 'h' },
67 { "invert", no_argument, 0, 'i' },
68 { "notrans", no_argument, 0, 't' },
69 { "version", no_argument, 0, 'v' },
66 { "debug", no_argument, 0, 'd' },
67 { "expand", no_argument, 0, 'e' },
68 { "nofade", no_argument, 0, 'f' },
69 { "help", no_argument, 0, 'h' },
70 { "invert", no_argument, 0, 'i' },
71 { "notrans", no_argument, 0, 't' },
72 { "version", no_argument, 0, 'v' },
7073 { "noslidenum", no_argument, 0, 's' },
7174 { "noslidemax", no_argument, 0, 'x' },
7275 { 0, 0, 0, 0 }
7477
7578 // parse command-line options
7679 int opt, debug = 0;
77 while ((opt = getopt_long(argc, argv, ":dfhitvsx", longopts, NULL)) != -1) {
80 while ((opt = getopt_long(argc, argv, ":defhitvsx", longopts, NULL)) != -1) {
7881 switch(opt) {
79 case 'd': debug += 1; break;
80 case 'f': nofade = 1; break;
81 case 'h': usage(); break;
82 case 'i': invert = 1; break;
83 case 't': notrans = 1; break;
84 case 'v': version(); break;
82 case 'd': debug += 1; break;
83 case 'e': noexpand = 0; break;
84 case 'f': nofade = 1; break;
85 case 'h': usage(); break;
86 case 'i': invert = 1; break;
87 case 't': notrans = 1; break;
88 case 'v': version(); break;
8589 case 's': slidenum = 0; break;
8690 case 'x': slidenum = 1; break;
8791 case ':': fprintf(stderr, "%s: '%c' requires an argument\n", argv[0], optopt); usage(); break;
9397 // set locale to that of the environment, so that ncurses properly renders
9498 // UTF-8 characters if the system supports it
9599 setlocale(LC_CTYPE, "");
100
101 // setup list string
102 setup_list_strings();
96103
97104 // open file or set input to STDIN
98105 char *file = NULL;
136143
137144 // load deck object from input
138145 deck_t *deck;
139 deck = markdown_load(input);
146 deck = markdown_load(input, noexpand);
140147
141148 // close file
142149 fclose(input);
3030
3131 #include "parser.h"
3232
33 deck_t *markdown_load(FILE *input) {
33 // char entry translation table
34 static struct named_character_entity {
35 wchar_t ucs;
36 const wchar_t *name;
37 } named_character_entities[] = {
38 { L'\x0022', L"quot" },
39 { L'\x0026', L"amp" },
40 { L'\x0027', L"apos" },
41 { L'\x003C', L"lt" },
42 { L'\x003E', L"gt" },
43 { L'\x00A2', L"cent" },
44 { L'\x00A3', L"pound" },
45 { L'\x00A5', L"yen" },
46 { L'\x00A7', L"sect" },
47 { L'\x00A9', L"copy" },
48 { L'\x00AA', L"laquo" },
49 { L'\x00AE', L"reg" },
50 { L'\x00B0', L"deg" },
51 { L'\x00B1', L"plusmn" },
52 { L'\x00B2', L"sup2" },
53 { L'\x00B3', L"sup3" },
54 { L'\x00B6', L"para" },
55 { L'\x00B9', L"sup1" },
56 { L'\x00BB', L"raquo" },
57 { L'\x00BC', L"frac14" },
58 { L'\x00BD', L"frac12" },
59 { L'\x00BE', L"frac34" },
60 { L'\x00D7', L"times" },
61 { L'\x00F7', L"divide" },
62 { L'\x2018', L"lsquo" },
63 { L'\x2019', L"rsquo" },
64 { L'\x201C', L"ldquo" },
65 { L'\x201D', L"rdquo" },
66 { L'\x2020', L"dagger" },
67 { L'\x2021', L"Dagger" },
68 { L'\x2022', L"bull" },
69 { L'\x2026', L"hellip" },
70 { L'\x2030', L"permil" },
71 { L'\x2032', L"prime" },
72 { L'\x2033', L"Prime" },
73 { L'\x2039', L"lsaquo" },
74 { L'\x203A', L"rsaquo" },
75 { L'\x20AC', L"euro" },
76 { L'\x2122', L"trade" },
77 { L'\x2190', L"larr" },
78 { L'\x2191', L"uarr" },
79 { L'\x2192', L"rarr" },
80 { L'\x2193', L"darr" },
81 { L'\x2194', L"harr" },
82 { L'\x21B5', L"crarr" },
83 { L'\x21D0', L"lArr" },
84 { L'\x21D1', L"uArr" },
85 { L'\x21D2', L"rArr" },
86 { L'\x21D3', L"dArr" },
87 { L'\x21D4', L"hArr" },
88 { L'\x221E', L"infin" },
89 { L'\x2261', L"equiv" },
90 { L'\x2308', L"lceil" },
91 { L'\x2309', L"rceil" },
92 { L'\x230A', L"lfloor" },
93 { L'\x230B', L"rfloor" },
94 { L'\x25CA', L"loz" },
95 { L'\x2660', L"spades" },
96 { L'\x2663', L"clubs" },
97 { L'\x2665', L"hearts" },
98 { L'\x2666', L"diams" },
99 { L'\0', NULL },
100 };
101
102 deck_t *markdown_load(FILE *input, int noexpand) {
34103
35104 wchar_t c = L'\0'; // char
36105 int i = 0; // increment
119188
120189 // calc offset
121190 line->offset = next_nonblank(text, 0);
191
192 // expand character entities if enabled
193 if(line->text->value &&
194 !noexpand &&
195 !CHECK_BIT(line->bits, IS_CODE))
196 expand_character_entities(line);
122197
123198 // adjust line length dynamicaly - excluding markup
124199 if(line->text->value)
602677 }
603678 }
604679
680 void expand_character_entities(line_t *line)
681 {
682 wchar_t *ampersand;
683 wchar_t *prev, *curr;
684
685 ampersand = NULL;
686 curr = &line->text->value[0];
687
688 // for each char in line
689 for(prev = NULL; *curr; prev = curr++) {
690 if (*curr == L'&' && (prev == NULL || *prev != L'\\')) {
691 ampersand = curr;
692 continue;
693 }
694 if (ampersand == NULL) {
695 continue;
696 }
697 if (*curr == L'#') {
698 if (prev == ampersand)
699 continue;
700 ampersand = NULL;
701 continue;
702 }
703 if (iswalpha(*curr) || iswxdigit(*curr)) {
704 continue;
705 }
706 if (*curr == L';') {
707 int cnt;
708 wchar_t ucs = L'\0';
709 if (ampersand + 1 >= curr || ampersand + 16 < curr) { // what is a good limit?
710 ampersand = NULL;
711 continue;
712 }
713 if (ampersand[1] == L'#') { // &#nnnn; or &#xhhhh;
714 if (ampersand + 2 >= curr) {
715 ampersand = NULL;
716 continue;
717 }
718 if (ampersand[2] != L'x') { // &#nnnn;
719 cnt = wcsspn(&ampersand[2], L"0123456789");
720 if (ampersand + 2 + cnt != curr) {
721 ampersand = NULL;
722 continue;
723 }
724 ucs = wcstoul(&ampersand[2], NULL, 10);
725 } else { // &#xhhhh;
726 if (ampersand + 3 >= curr) {
727 ampersand = NULL;
728 continue;
729 }
730 cnt = wcsspn(&ampersand[3], L"0123456789abcdefABCDEF");
731 if (ampersand + 3 + cnt != curr) {
732 ampersand = NULL;
733 continue;
734 }
735 ucs = wcstoul(&ampersand[3], NULL, 16);
736 }
737 } else { // &name;
738 for (cnt = 0; cnt < sizeof(named_character_entities)/sizeof(named_character_entities[0]); ++cnt) {
739 if (wcsncmp(named_character_entities[cnt].name, &ampersand[1], curr - ampersand - 1))
740 continue;
741 ucs = named_character_entities[cnt].ucs;
742 break;
743 }
744 if (ucs == L'\0') {
745 ampersand = NULL;
746 continue;
747 }
748 }
749 *ampersand = ucs;
750 cstring_strip(line->text, ampersand + 1 - &line->text->value[0], curr - ampersand);
751 curr = ampersand;
752 ampersand = NULL;
753 }
754 }
755 }
756
605757 void adjust_line_length(line_t *line) {
606758 int l = 0;
607759 const static wchar_t *special = L"\\*_`"; // list of interpreted chars
2525 #include <wctype.h> // iswalnum
2626 #include <string.h> // strcpy
2727 #include <unistd.h> // usleep
28 #include <stdlib.h> // getenv
2829 #include "viewer.h"
2930
3031 // color ramp for fading from black to color
5960 206, 207, 201, 200, 199, 199,
6061 198, 198, 197, 197, 196, 196};
6162
63 // unordered list characters
64 //
65 // override via env vars:
66 // export MDP_LIST_OPEN1=" " MDP_LIST_OPEN2=" " MDP_LIST_OPEN3=" "
67 // export MDP_LIST_HEAD1=" ■ " MDP_LIST_HEAD2=" ● " MDP_LIST_HEAD3=" ▫ "
68 static const char *list_open1 = " | ";
69 static const char *list_open2 = " | ";
70 static const char *list_open3 = " | ";
71 static const char *list_head1 = " +- ";
72 static const char *list_head2 = " +- ";
73 static const char *list_head3 = " +- ";
74
6275 int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reload, int noreload, int slidenum) {
6376
64 int c = 0; // char
65 int i = 0; // iterate
66 int l = 0; // line number
67 int lc = 0; // line count
68 int sc = 1; // slide count
69 int colors = 0; // amount of colors supported
70 int fade = 0; // disable color fading by default
71 int trans = -1; // enable transparency if term supports it
72 int max_lines = 0; // max lines per slide
73 int max_cols = 0; // max columns per line
74 int offset; // text offset
75 int stop = 0; // passed stop bits per slide
77 int c = 0; // char
78 int i = 0; // iterate
79 int l = 0; // line number
80 int lc = 0; // line count
81 int sc = 1; // slide count
82 int colors = 0; // amount of colors supported
83 int fade = 0; // disable color fading by default
84 int trans = -1; // enable transparency if term supports it
85 int max_lines = 0; // max lines per slide
86 int max_lines_slide = -1; // the slide that has the most lines
87 int max_cols = 0; // max columns per line
88 int offset; // text offset
89 int stop = 0; // passed stop bits per slide
7690
7791 // header line 1 is displayed at the top
7892 int bar_top = (deck->headers > 0) ? 1 : 0;
139153 }
140154
141155 max_lines = MAX(lc, max_lines);
156 if (lc == max_lines) {
157 max_lines_slide = sc;
158 }
142159
143160 slide = slide->next;
161 ++sc;
144162 }
145163
146164 // not enough lines
150168 endwin();
151169
152170 // print error
153 fwprintf(stderr, L"Error: Terminal height (%i lines) too small. Need at least %i lines.\n", LINES, max_lines + bar_top + bar_bottom);
171 fwprintf(stderr, L"Error: Terminal height (%i lines) too small. Need at least %i lines for slide #%i.\n", LINES, max_lines + bar_top + bar_bottom, max_lines_slide);
154172 fwprintf(stderr, L"You may need to add additional horizontal rules (---) to split your file in shorter slides.\n");
155173
156174 // no reload
242260 slide = deck->slide;
243261
244262 // find slide to reload
263 sc = 0;
245264 while(reload > 1 && reload <= deck->slides) {
246265 slide = slide->next;
247266 sc++;
332351 }
333352
334353 // print pandoc URL references
335 // only if we already printed all lines of the current slide
336 if(!line) {
354 // only if we already printed all lines of the current slide (or output is stopped)
355 if(!line ||
356 stop > slide->stop) {
337357 int i, ymax;
338358 getmaxyx( content, ymax, i );
339359 for (i = 0; i < url_get_amount(); i++) {
515535 return reload;
516536 }
517537
538 void setup_list_strings(void)
539 {
540 const char *str;
541
542 /* utf8 can require 6 bytes */
543 if ((str = getenv("MDP_LIST_OPEN")) != NULL && strlen(str) <= 4*6) {
544 list_open1 = list_open2 = list_open3 = str;
545 } else {
546 if ((str = getenv("MDP_LIST_OPEN1")) != NULL && strlen(str) <= 4*6)
547 list_open1 = str;
548 if ((str = getenv("MDP_LIST_OPEN2")) != NULL && strlen(str) <= 4*6)
549 list_open2 = str;
550 if ((str = getenv("MDP_LIST_OPEN3")) != NULL && strlen(str) <= 4*6)
551 list_open3 = str;
552 }
553 if ((str = getenv("MDP_LIST_HEAD")) != NULL && strlen(str) <= 4*6) {
554 list_head1 = list_head2 = list_head3 = str;
555 } else {
556 if ((str = getenv("MDP_LIST_HEAD1")) != NULL && strlen(str) <= 4*6)
557 list_head1 = str;
558 if ((str = getenv("MDP_LIST_HEAD2")) != NULL && strlen(str) <= 4*6)
559 list_head2 = str;
560 if ((str = getenv("MDP_LIST_HEAD3")) != NULL && strlen(str) <= 4*6)
561 list_head3 = str;
562 }
563 }
564
518565 void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colors) {
519566
520567 int i; // increment
540587 // IS_UNORDERED_LIST_3
541588 if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_3)) {
542589 offset = next_nonblank(line->text, 0);
543 char prompt[13];
544 strcpy(&prompt[0], CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? " | " : " ");
545 strcpy(&prompt[4], CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)? " | " : " ");
590 char prompt[13 * 6];
591 int pos = 0, len, cnt;
592 len = sizeof(prompt) - pos;
593 cnt = snprintf(&prompt[pos], len, "%s", CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? list_open1 : " ");
594 pos += (cnt > len - 1 ? len - 1 : cnt);
595 len = sizeof(prompt) - pos;
596 cnt = snprintf(&prompt[pos], len, "%s", CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)? list_open2 : " ");
597 pos += (cnt > len - 1 ? len - 1 : cnt);
598 len = sizeof(prompt) - pos;
546599
547600 if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
548 strcpy(&prompt[8], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_3)? " | " : " ");
601 snprintf(&prompt[pos], len, "%s", line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_3)? list_open3 : " ");
549602 } else {
550 strcpy(&prompt[8], " +- ");
603 snprintf(&prompt[pos], len, "%s", list_head3);
551604 offset += 2;
552605 }
553606
560613 // IS_UNORDERED_LIST_2
561614 } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)) {
562615 offset = next_nonblank(line->text, 0);
563 char prompt[9];
564 strcpy(&prompt[0], CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? " | " : " ");
616 char prompt[9 * 6];
617 int pos = 0, len, cnt;
618 len = sizeof(prompt) - pos;
619 cnt = snprintf(&prompt[pos], len, "%s", CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? list_open1 : " ");
620 pos += (cnt > len - 1 ? len - 1 : cnt);
621 len = sizeof(prompt) - pos;
565622
566623 if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
567 strcpy(&prompt[4], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_2)? " | " : " ");
624 snprintf(&prompt[pos], len, "%s", line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_2)? list_open2 : " ");
568625 } else {
569 strcpy(&prompt[4], " +- ");
626 snprintf(&prompt[pos], len, "%s", list_head2);
570627 offset += 2;
571628 }
572629
579636 // IS_UNORDERED_LIST_1
580637 } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)) {
581638 offset = next_nonblank(line->text, 0);
582 char prompt[5];
639 char prompt[5 * 6];
583640
584641 if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
585 strcpy(&prompt[0], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_1)? " | " : " ");
642 strcpy(&prompt[0], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_1)? list_open1 : " ");
586643 } else {
587 strcpy(&prompt[0], " +- ");
644 strcpy(&prompt[0], list_head1);
588645 offset += 2;
589646 }
590647