IS_UNORDERED_LIST_1,
IS_UNORDERED_LIST_2,
IS_UNORDERED_LIST_3,
+ IS_UNORDERED_LIST_EXT,
IS_CENTER,
IS_EMPTY
};
#define UNORDERED_LIST_MAX_LEVEL 3
deck_t *markdown_load(FILE *input);
-int markdown_analyse(cstring_t *text);
+int markdown_analyse(cstring_t *text, int prev);
void markdown_debug(deck_t *deck, int debug);
void adjust_line_length(line_t *line);
bool is_utf8(char ch);
%author: visit1985
%date: 2014-09-22
-mdp
-===
+-> mdp <-
+=========
-A command-line based markdown presentation tool.
+-> A command-line based markdown presentation tool. <-
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
The input file is split into multiple slides by
horizontal rules (hr). A hr consisting of at
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
First-level headers can be prefixed by single *#*
or underlined by *===*.
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Second-level headers can be prefixed by *##* or
underlined by *---*.
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Inline codes are surrounded with backticks.
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Code blocks are automatically detected by 4
spaces at the beginning of a line.
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Quotes are auto-detected by preceding *>*.
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Inline highlighting is supported as followed:
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Backslashes force special markdown characters
like *\**, *\_*, *#* and *>* to be printed as normal
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Leading *\** or *-* indicate lists.
-TODO list
-\* major 1
-\ \- minor 1.1
-\ \- detail 1.1.1 \*IMPORTANT\*
-\ \- detail 1.1.2
-\ \- minor 1.2
+list
+\* major
+\ - minor
+\ - \*important\*
+\ detail
+\ - minor
becomes
-TODO list
-* major 1
- - minor 1.1
- - detail 1.1.1 *IMPORTANT*
- - detail 1.1.2
- - minor 1.2
+list
+* major
+ - minor
+ - *important*
+ detail
+ - minor
-------------------------------------------------
-# Supported markdown formatting's
+-> # Supported markdown formatting's <-
Leading *->* indicates centering.
-------------------------------------------------
-## More information about markdown
+-> ## More information about markdown <-
can be found on
-------------------------------------------------
-# Support for UTF-8 special characters
+-> # Support for UTF-8 special characters <-
Here are some examples.
-------------------------------------------------
-# Suspend your presentation for hands-on examples
+-> # Suspend your presentation for hands-on examples <-
Use *Ctrl + z* to suspend the presentation.
-------------------------------------------------
-# Convert your presentation to PDF
+-> # Convert your presentation to PDF <-
To publish your presentation later on, you may
want to convert it to PDF.
-------------------------------------------------
-## Last words
+-> ## Last words <-
I hope you like *mdp*. But be aware, that it is
still in alpha status.
int lc = 0; // line count
int sc = 1; // slide count
int bits = 0; // markdown bits
+ int prev = 0; // markdown bits of previous line
deck_t *deck = new_deck();
slide_t *slide = deck->slide;
line_t *tmp = NULL;
cstring_t *text = cstring_init();
+ // initialize bits as empty line
+ SET_BIT(bits, IS_EMPTY);
+
while ((c = fgetc(input)) != EOF) {
if (ferror(input)) {
fprintf(stderr, "markdown_load() failed to read input: %s\n", strerror(errno));
if(c == '\n') {
// markdown analyse
- bits = markdown_analyse(text);
+ prev = bits;
+ bits = markdown_analyse(text, prev);
// if first line in file is markdown hr
if(!line && CHECK_BIT(bits, IS_HR)) {
while(slide) {
line = slide->line;
while(line) {
+ // combine underlined H1/H2 in single line
if((CHECK_BIT(line->bits, IS_H1) ||
CHECK_BIT(line->bits, IS_H2)) &&
CHECK_BIT(line->bits, IS_EMPTY) &&
line->prev &&
!CHECK_BIT(line->prev->bits, IS_EMPTY)) {
- // combine underlined H1/H2 in single line
+
// remove line from linked list
line->prev->next = line->next;
(tmp->text->delete)(tmp->text);
free(tmp);
+ // pass enclosing flag IS_UNORDERED_LIST_3
+ // to nested levels for unordered lists
} else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_3)) {
tmp = line->next;
line_t *list_last_level_3 = line;
SET_BIT(tmp->bits, IS_UNORDERED_LIST_3);
}
+ // pass enclosing flag IS_UNORDERED_LIST_2
+ // to nested levels for unordered lists
} else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)) {
tmp = line->next;
line_t *list_last_level_2 = line;
SET_BIT(tmp->bits, IS_UNORDERED_LIST_2);
}
+ // pass enclosing flag IS_UNORDERED_LIST_1
+ // to nested levels for unordered lists
} else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)) {
tmp = line->next;
line_t *list_last_level_1 = line;
return deck;
}
-int markdown_analyse(cstring_t *text) {
+int markdown_analyse(cstring_t *text, int prev) {
+ // static variables can not be redeclaired, but changed outside of a declaration
+ // the program remembers their value on every function calls
static int unordered_list_level = 0;
static int unordered_list_level_offset[] = {-1, -1, -1, -1};
(text->text[offset] == '*' || text->text[offset] == '-') &&
text->text[offset + 1] == ' ') {
- for(i = offset; i<eol; i++) {
- if(text->text[i] != '*' &&
- text->text[i] != '-' &&
- text->text[i] != ' ') {
- if(offset > unordered_list_offset + CODE_INDENT) {
- SET_BIT(bits, IS_CODE);
- } else if(offset != unordered_list_offset) {
- for(i = unordered_list_level; i >= 0; i--) {
- if(unordered_list_level_offset[i] == offset) {
- unordered_list_level = i;
- break;
- }
- }
- if(i != unordered_list_level) {
- unordered_list_level = MIN(unordered_list_level + 1, UNORDERED_LIST_MAX_LEVEL);
- unordered_list_level_offset[unordered_list_level] = offset;
- }
- }
+ // if different from last lines offset
+ if(offset != unordered_list_offset) {
- if(unordered_list_level == 0) {
- unordered_list_level = 1;
- unordered_list_level_offset[1] = offset;
+ // test if offset matches a lower indent level
+ for(i = unordered_list_level; i >= 0; i--) {
+ if(unordered_list_level_offset[i] == offset) {
+ unordered_list_level = i;
+ break;
}
+ }
+ // if offset doesn't match any previously stored indent level
+ if(i != unordered_list_level) {
+ unordered_list_level = MIN(unordered_list_level + 1, UNORDERED_LIST_MAX_LEVEL);
+ // memorize the offset as next bigger indent level
+ unordered_list_level_offset[unordered_list_level] = offset;
+ }
+ }
- switch(unordered_list_level) {
- case 1: SET_BIT(bits, IS_UNORDERED_LIST_1); break;
- case 2: SET_BIT(bits, IS_UNORDERED_LIST_2); break;
- case 3: SET_BIT(bits, IS_UNORDERED_LIST_3); break;
- default: break;
- }
+ // if no previous indent level matches, this must be the first line of the list
+ if(unordered_list_level == 0) {
+ unordered_list_level = 1;
+ unordered_list_level_offset[1] = offset;
+ }
- break;
- }
+ switch(unordered_list_level) {
+ case 1: SET_BIT(bits, IS_UNORDERED_LIST_1); break;
+ case 2: SET_BIT(bits, IS_UNORDERED_LIST_2); break;
+ case 3: SET_BIT(bits, IS_UNORDERED_LIST_3); break;
+ default: break;
}
}
!CHECK_BIT(bits, IS_UNORDERED_LIST_2) &&
!CHECK_BIT(bits, IS_UNORDERED_LIST_3)) {
- unordered_list_level = 0;
+ // continue list if indent level is still the same as in previous line
+ if ((CHECK_BIT(prev, IS_UNORDERED_LIST_1) ||
+ CHECK_BIT(prev, IS_UNORDERED_LIST_2) ||
+ CHECK_BIT(prev, IS_UNORDERED_LIST_3)) &&
+ offset >= unordered_list_offset) {
+
+ switch(unordered_list_level) {
+ case 1: SET_BIT(bits, IS_UNORDERED_LIST_1); break;
+ case 2: SET_BIT(bits, IS_UNORDERED_LIST_2); break;
+ case 3: SET_BIT(bits, IS_UNORDERED_LIST_3); break;
+ default: break;
+ }
+
+ // this line extends the previous list item
+ SET_BIT(bits, IS_UNORDERED_LIST_EXT);
+
+ // or reset indent level
+ } else {
+ unordered_list_level = 0;
+ }
+ }
+
+ if(!CHECK_BIT(bits, IS_UNORDERED_LIST_1) &&
+ !CHECK_BIT(bits, IS_UNORDERED_LIST_2) &&
+ !CHECK_BIT(bits, IS_UNORDERED_LIST_3)) {
// IS_CODE
- if(offset >= CODE_INDENT) {
+ if(offset >= CODE_INDENT &&
+ (CHECK_BIT(prev, IS_EMPTY) ||
+ CHECK_BIT(prev, IS_CODE))) {
SET_BIT(bits, IS_CODE);
} else {
char prompt[13];
strcpy(&prompt[0], CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? " | " : " ");
strcpy(&prompt[4], CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)? " | " : " ");
- strcpy(&prompt[8], " +- ");
+
+ if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
+ strcpy(&prompt[8], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_3)? " | " : " ");
+ } else {
+ strcpy(&prompt[8], " +- ");
+ offset += 2;
+ }
+
wprintw(window,
"%s", prompt);
- inline_display(window, &line->text->text[offset + 2], colors);
+ if(!CHECK_BIT(line->bits, IS_CODE))
+ inline_display(window, &line->text->text[offset], colors);
// IS_UNORDERED_LIST_2
} else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)) {
offset = next_nonblank(line->text, 0);
char prompt[9];
strcpy(&prompt[0], CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)? " | " : " ");
- strcpy(&prompt[4], " +- ");
+
+ if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
+ strcpy(&prompt[4], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_2)? " | " : " ");
+ } else {
+ strcpy(&prompt[4], " +- ");
+ offset += 2;
+ }
+
wprintw(window,
"%s", prompt);
- inline_display(window, &line->text->text[offset + 2], colors);
+ if(!CHECK_BIT(line->bits, IS_CODE))
+ inline_display(window, &line->text->text[offset], colors);
// IS_UNORDERED_LIST_1
} else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)) {
offset = next_nonblank(line->text, 0);
char prompt[5];
- strcpy(&prompt[0], " +- ");
+
+ if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_EXT)) {
+ strcpy(&prompt[0], line->next && CHECK_BIT(line->next->bits, IS_UNORDERED_LIST_1)? " | " : " ");
+ } else {
+ strcpy(&prompt[0], " +- ");
+ offset += 2;
+ }
+
wprintw(window,
"%s", prompt);
- inline_display(window, &line->text->text[offset + 2], colors);
+ if(!CHECK_BIT(line->bits, IS_CODE))
+ inline_display(window, &line->text->text[offset], colors);
+ }
// IS_CODE
- } else if(CHECK_BIT(line->bits, IS_CODE)) {
+ if(CHECK_BIT(line->bits, IS_CODE)) {
// set static offset for code
offset = CODE_INDENT;
// print whole lines
wprintw(window,
"%s", &line->text->text[offset]);
+ }
- // IS_QUOTE
- } else if(CHECK_BIT(line->bits, IS_QUOTE)) {
- while(line->text->text[offset] == '>') {
- // print a reverse color block
- if(colors) {
- wattron(window, COLOR_PAIR(CP_BLACK));
- wprintw(window, "%s", " ");
- wattron(window, COLOR_PAIR(CP_WHITE));
- wprintw(window, "%s", " ");
- } else {
- wprintw(window, "%s", ">");
- }
-
- // find next quote or break
- offset++;
- if(line->text->text[offset] == ' ')
- offset = next_word(line->text, offset);
- }
+ if(!CHECK_BIT(line->bits, IS_UNORDERED_LIST_1) &&
+ !CHECK_BIT(line->bits, IS_UNORDERED_LIST_2) &&
+ !CHECK_BIT(line->bits, IS_UNORDERED_LIST_3) &&
+ !CHECK_BIT(line->bits, IS_CODE)) {
+
+ // IS_QUOTE
+ if(CHECK_BIT(line->bits, IS_QUOTE)) {
+ while(line->text->text[offset] == '>') {
+ // print a reverse color block
+ if(colors) {
+ wattron(window, COLOR_PAIR(CP_BLACK));
+ wprintw(window, "%s", " ");
+ wattron(window, COLOR_PAIR(CP_WHITE));
+ wprintw(window, "%s", " ");
+ } else {
+ wprintw(window, "%s", ">");
+ }
- inline_display(window, &line->text->text[offset], colors);
+ // find next quote or break
+ offset++;
+ if(line->text->text[offset] == ' ')
+ offset = next_word(line->text, offset);
+ }
- } else {
+ inline_display(window, &line->text->text[offset], colors);
+ } else {
- // IS_CENTER
- if(CHECK_BIT(line->bits, IS_CENTER)) {
- if(line->length < max_cols) {
- wmove(window, y, x + ((max_cols - line->length) / 2));
+ // IS_CENTER
+ if(CHECK_BIT(line->bits, IS_CENTER)) {
+ if(line->length < max_cols) {
+ wmove(window, y, x + ((max_cols - line->length) / 2));
+ }
}
- }
- // IS_H1 || IS_H2
- if(CHECK_BIT(line->bits, IS_H1) || CHECK_BIT(line->bits, IS_H2)) {
+ // IS_H1 || IS_H2
+ if(CHECK_BIT(line->bits, IS_H1) || CHECK_BIT(line->bits, IS_H2)) {
- // set headline color
- if(colors)
- wattron(window, COLOR_PAIR(CP_BLUE));
+ // set headline color
+ if(colors)
+ wattron(window, COLOR_PAIR(CP_BLUE));
- // enable underline for H1
- if(CHECK_BIT(line->bits, IS_H1))
- wattron(window, A_UNDERLINE);
+ // enable underline for H1
+ if(CHECK_BIT(line->bits, IS_H1))
+ wattron(window, A_UNDERLINE);
- // skip hashes
- while(line->text->text[offset] == '#')
- offset = next_word(line->text, offset);
+ // skip hashes
+ while(line->text->text[offset] == '#')
+ offset = next_word(line->text, offset);
- // print whole lines
- wprintw(window,
- "%s", &line->text->text[offset]);
+ // print whole lines
+ wprintw(window,
+ "%s", &line->text->text[offset]);
- wattroff(window, A_UNDERLINE);
+ wattroff(window, A_UNDERLINE);
- // no line-wide markdown
- } else {
+ // no line-wide markdown
+ } else {
- inline_display(window, &line->text->text[offset], colors);
+ inline_display(window, &line->text->text[offset], colors);
+ }
}
}