[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemacs-commit] qemacs Makefile markdown.c
From: |
Charlie Gordon |
Subject: |
[Qemacs-commit] qemacs Makefile markdown.c |
Date: |
Fri, 07 Mar 2014 02:30:05 +0000 |
CVSROOT: /sources/qemacs
Module name: qemacs
Changes by: Charlie Gordon <chqrlie> 14/03/07 02:30:05
Modified files:
. : Makefile
Added files:
. : markdown.c
Log message:
add markdown-mode for John Gruber's Markdown syntax
* detect markdown files on extension: *.md and *.mkd
* support some pandoc extensions
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/Makefile?cvsroot=qemacs&r1=1.64&r2=1.65
http://cvs.savannah.gnu.org/viewcvs/qemacs/markdown.c?cvsroot=qemacs&rev=1.1
Patches:
Index: Makefile
===================================================================
RCS file: /sources/qemacs/qemacs/Makefile,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -b -r1.64 -r1.65
--- Makefile 3 Mar 2014 23:56:50 -0000 1.64
+++ Makefile 7 Mar 2014 02:30:05 -0000 1.65
@@ -109,8 +109,8 @@
OBJS+= charsetjis.o charsetmore.o
ifdef CONFIG_ALL_MODES
- OBJS+= unihex.o clang.o xml.o bufed.o \
- lisp.o makemode.o orgmode.o perl.o htmlsrc.o script.o extra-modes.o
+ OBJS+= unihex.o bufed.o clang.o xml.o htmlsrc.o \
+ lisp.o makemode.o markdown.o orgmode.o perl.o script.o extra-modes.o
ifndef CONFIG_WIN32
OBJS+= shell.o dired.o latex-mode.o archive.o
endif
Index: markdown.c
===================================================================
RCS file: markdown.c
diff -N markdown.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ markdown.c 7 Mar 2014 02:30:03 -0000 1.1
@@ -0,0 +1,799 @@
+/*
+ * Markdown mode for QEmacs.
+ *
+ * Copyright (c) 2014 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "qe.h"
+
+ModeDef mkd_mode;
+
+enum {
+ QE_STYLE_MKD_HEADING1 = QE_STYLE_FUNCTION,
+ QE_STYLE_MKD_HEADING2 = QE_STYLE_STRING,
+ QE_STYLE_MKD_HEADING3 = QE_STYLE_VARIABLE,
+ QE_STYLE_MKD_HEADING4 = QE_STYLE_TYPE,
+ QE_STYLE_MKD_TILDE = QE_STYLE_PREPROCESS,
+ QE_STYLE_MKD_COMMENT = QE_STYLE_COMMENT,
+ QE_STYLE_MKD_BLOCK_QUOTE = QE_STYLE_FUNCTION,
+ QE_STYLE_MKD_TABLE = QE_STYLE_TYPE,
+ QE_STYLE_MKD_HBAR = QE_STYLE_VARIABLE,
+ QE_STYLE_MKD_STRONG2 = QE_STYLE_FUNCTION,
+ QE_STYLE_MKD_STRONG1 = QE_STYLE_FUNCTION,
+ QE_STYLE_MKD_EMPHASIS2 = QE_STYLE_VARIABLE,
+ QE_STYLE_MKD_EMPHASIS1 = QE_STYLE_VARIABLE,
+ QE_STYLE_MKD_CODE = QE_STYLE_STRING,
+ QE_STYLE_MKD_IMAGE_LINK = QE_STYLE_KEYWORD,
+ QE_STYLE_MKD_REF_LINK = QE_STYLE_KEYWORD,
+ QE_STYLE_MKD_DLIST = QE_STYLE_NUMBER,
+ QE_STYLE_MKD_LIST = QE_STYLE_NUMBER,
+
+#if 0
+QE_STYLE_COMMENT,
+QE_STYLE_PREPROCESS,
+QE_STYLE_STRING,
+QE_STYLE_STRING_Q,
+QE_STYLE_KEYWORD,
+QE_STYLE_NUMBER,
+QE_STYLE_FUNCTION,
+QE_STYLE_VARIABLE,
+QE_STYLE_TYPE,
+QE_STYLE_TAG,
+#endif
+};
+
+#define IN_BLOCK 0x8000
+#define IN_C 0x4000
+#define IN_HTML_BLOCK 0x2000
+#define IN_TABLE 0x1000
+#define IN_LEVEL 0x0F00
+#define LEVEL_SHIFT 8
+
+#define MAX_BUF_SIZE 512
+#define MAX_LEVEL 128
+
+/* TODO: define specific styles */
+#define BULLET_STYLES 4
+static int MkdBulletStyles[BULLET_STYLES] = {
+ QE_STYLE_MKD_HEADING1,
+ QE_STYLE_MKD_HEADING2,
+ QE_STYLE_MKD_HEADING3,
+ QE_STYLE_MKD_HEADING4,
+};
+
+static int mkd_scan_chunk(const unsigned int *str,
+ const char *begin, const char *end, int min_width)
+{
+ int i, j;
+
+ for (i = 0; begin[i]; i++) {
+ if (str[i] != begin[i])
+ return 0;
+ }
+ for (j = 0; j < min_width; j++) {
+ if (str[i + j] == '\0')
+ return 0;
+ }
+ for (i += j; str[i] != '\0'; i++) {
+ for (j = 0; end[j]; j++) {
+ if (str[i + j] != end[j])
+ break;
+ }
+ if (!end[j])
+ return i + j;
+ }
+ return 0;
+}
+
+static void mkd_colorize_line(unsigned int *str, int n, int *statep,
+ __unused__ int state_only)
+{
+ int colstate = *statep;
+ int level, indent, i = 0, j = 0, base_style = 0;
+
+ if (colstate & IN_HTML_BLOCK) {
+ if (str[i] != '<' && str[i] != '\0' && !qe_isblank(str[i]))
+ colstate &= ~IN_HTML_BLOCK;
+ }
+
+ if ((colstate & IN_HTML_BLOCK)
+ || (str[i] == '<' && str[i + 1] != '/')) {
+ /* block level HTML markup */
+ colstate &= ~IN_HTML_BLOCK;
+ htmlsrc_colorize_line(str, n, &colstate, state_only);
+ colstate |= IN_HTML_BLOCK;
+ if ((str[i] & CHAR_MASK) == '<' && (str[i + 1] & CHAR_MASK) == '/')
+ colstate = 0;
+ *statep = colstate;
+ return;
+ }
+
+ if (colstate & IN_BLOCK) {
+ /* Should count number of ~ to detect end of block */
+ if (ustristart(str + i, "~~~", NULL)) {
+ colstate &= ~(IN_BLOCK | IN_C);
+ set_color(str + i, str + n, QE_STYLE_MKD_TILDE);
+ i = n;
+ } else {
+ if (colstate & IN_C) {
+ colstate &= ~(IN_BLOCK | IN_C);
+ c_colorize_line(str, n, &colstate, state_only);
+ colstate |= (IN_BLOCK | IN_C);
+ } else {
+ set_color(str + i, str + n, QE_STYLE_MKD_CODE);
+ }
+ }
+ *statep = colstate;
+ return;
+ }
+
+ if (str[i] == '#') {
+ /* Check for heading: initial string of '#' followed by ' ' */
+ for (j = i + 1; str[j] == '#'; j++)
+ continue;
+
+ if (qe_isblank(str[j])) {
+ base_style = MkdBulletStyles[(j - i - 1) % BULLET_STYLES];
+ set_color(str + i, str + j + 1, base_style);
+ i = j + 1;
+ }
+ } else
+ if (str[i] == '%') {
+ /* pandoc extension: line comment */
+ set_color(str + i, str + n, QE_STYLE_MKD_COMMENT);
+ i = n;
+ } else
+ if (str[i] == '>') {
+ /* block quoting */
+ set_color(str + i, str + n, QE_STYLE_MKD_BLOCK_QUOTE);
+ i = n;
+ } else
+ if (ustrstart(str + i, "~~~", NULL)) {
+ /* verbatim block */
+ colstate |= IN_BLOCK;
+ if (ustristart(str + i + 3, " {.c", NULL)) {
+ colstate |= IN_C;
+ }
+ set_color(str + i, str + n, QE_STYLE_MKD_TILDE);
+ i = n;
+ } else
+ if (str[i] == '-') {
+ /* dashes underline a heading */
+ for (j = i + 1; str[j] == '-'; j++)
+ continue;
+ if (j == n) {
+ set_color(str + i, str + n, QE_STYLE_MKD_HEADING2);
+ i = n;
+ }
+ } else
+ if (str[i] == '=') {
+ /* equal signs indicate a heading */
+ for (j = i + 1; str[j] == '='; j++)
+ continue;
+ if (j == n) {
+ set_color(str + i, str + n, QE_STYLE_MKD_HEADING1);
+ i = n;
+ }
+ } else
+ if (str[i] == '|') {
+ colstate |= IN_TABLE;
+ base_style = QE_STYLE_MKD_TABLE;
+ }
+
+ /* [X] unordered lists: /[-*+] / */
+ /* [X] ordered lists: /[0-9]+[.] / */
+ /* [ ] list continuation lines are indented 1 level */
+ /* [ ] code blocks are indented one extra level */
+ /* [X] horizontal rules: /^ *([-*_][ ]*){3-}$/ */
+ /* [/] inline links: /[[].*[]]([(].*[)])?/ */
+ /* [/] reference links: /[[].*[]][ ]*[[][a-zA-Z0-9 ,.;:?]*[]])/ */
+ /* [/] references: /[ ]{0-3}[[][a-zA-Z0-9 ,.;:?]+[]]:.*)/ */
+ /* [/] images: same as links, preceded by ! */
+ /* [X] automatic links and email addresses: <http://adress> */
+ /* [X] emphasis: _.*_ \*.*\* __.*__ \*\*.*\*\* */
+ /* [X] code span: `code` */
+ /* [X] code span with embedded `: ``code`` or `` code `` */
+ /* [X] litteral chars: isolate them or escape them with \ */
+ /* \ ` * _ { } [ ] ( ) # + - . ! */
+
+ level = (colstate & IN_LEVEL) >> LEVEL_SHIFT;
+ for (indent = 0;; i++) {
+ if (str[i] == ' ')
+ indent++;
+ else
+ if (str[i] == '\t')
+ indent += 4;
+ else
+ break;
+ }
+
+ if (i < n) {
+ /* ignore blank lines for level and code triggers */
+ if (indent < level * 4) {
+ level = indent >> 2;
+ }
+ indent -= level * 4;
+
+ if (indent >= 4) {
+ /* Should detect sequel lines in ordered/unordered lists */
+ set_color(str + i, str + n, QE_STYLE_MKD_CODE);
+ i = n;
+ }
+ }
+
+ if (str[i] == '*' || str[i] == '-' || str[i] == '_') {
+ int count = 1;
+ for (j = i + 1; j < n; j++) {
+ if (qe_isblank(str[j]))
+ continue;
+ if (str[j] == str[i])
+ count++;
+ else
+ break;
+ }
+ if (j == n && count >= 3) {
+ /* Horizontal rule */
+ set_color(str + i, str + n, QE_STYLE_MKD_HBAR);
+ i = n;
+ }
+ }
+
+ if (level) {
+ base_style = QE_STYLE_MKD_LIST;
+ }
+
+ if (qe_isdigit(str[i])) {
+ for (j = i + 1; qe_isdigit(str[j]); j++)
+ continue;
+ if (str[j] == '.' && qe_isblank(str[j + 1])) {
+ base_style = QE_STYLE_MKD_DLIST;
+ level++;
+ }
+ } else
+ if ((str[i] == '-' || str[i] == '*' || str[i] == '+')
+ && qe_isblank(str[i + 1])) {
+ base_style = QE_STYLE_MKD_LIST;
+ level++;
+ }
+
+ for (;;) {
+ int chunk = 0, chunk_style = base_style;
+ int flags;
+ int c = str[i];
+
+ if (c == '\0')
+ break;
+
+ switch (c) {
+ case '#':
+ break;
+ case '*': /* bold */
+ if (str[i + 1] == '*') {
+ chunk_style = QE_STYLE_MKD_STRONG2;
+ chunk = mkd_scan_chunk(str + i, "**", "**", 1);
+ } else {
+ chunk_style = QE_STYLE_MKD_STRONG1;
+ chunk = mkd_scan_chunk(str + i, "*", "*", 1);
+ }
+ break;
+ case '_': /* emphasis */
+ if (str[i + 1] == '_') {
+ chunk_style = QE_STYLE_MKD_EMPHASIS2;
+ chunk = mkd_scan_chunk(str + i, "__", "__", 1);
+ } else {
+ chunk_style = QE_STYLE_MKD_EMPHASIS1;
+ chunk = mkd_scan_chunk(str + i, "_", "_", 1);
+ }
+ break;
+ case '`': /* code */
+ chunk_style = QE_STYLE_MKD_CODE;
+ if (str[i + 1] == '`') {
+ if (str[i + 2] == ' ') {
+ chunk = mkd_scan_chunk(str + i, "`` ", " ``", 1);
+ } else {
+ chunk = mkd_scan_chunk(str + i, "``", "``", 1);
+ }
+ } else {
+ chunk = mkd_scan_chunk(str + i, "`", "`", 1);
+ }
+ break;
+ case '!': /* image link ^[...: <...>] */
+ chunk_style = QE_STYLE_MKD_IMAGE_LINK;
+ chunk = mkd_scan_chunk(str + i, "![", "]", 1);
+ break;
+ case '[': /* link ^[...: <...>] */
+ chunk_style = QE_STYLE_MKD_REF_LINK;
+ chunk = mkd_scan_chunk(str + i, "[", "]", 1);
+ break;
+ case '<': /* automatic link <http://address> */
+ chunk_style = QE_STYLE_MKD_REF_LINK;
+ chunk = mkd_scan_chunk(str + i, "<http", ">", 1);
+ if (chunk)
+ break;
+ for (flags = 0, j = i + 1; j < n; j++) {
+ if (str[j] == '@')
+ flags |= 1;
+ if (str[j] == '>') {
+ flags |= 2;
+ break;
+ }
+ }
+ if (flags == 3) {
+ chunk = j + 1;
+ break;
+ }
+ break;
+ case '\\': /* escape */
+ if (strchr("\\`*_{}[]()#+-.!", str[i + 1])) {
+ set_color(str + i, str + i + 2, base_style);
+ i += 2;
+ continue;
+ }
+ break;
+ }
+ if (chunk) {
+ set_color(str + i, str + i + chunk, chunk_style);
+ i += chunk;
+ } else {
+ set_color1(str + i, base_style);
+ i++;
+ }
+ }
+
+ colstate &= ~IN_TABLE;
+ colstate &= ~IN_LEVEL;
+ colstate |= level << LEVEL_SHIFT;
+ *statep = colstate;
+}
+
+static int mkd_is_header_line(EditState *s, int offset)
+{
+ /* Check if line starts with '#' */
+ /* XXX: should ignore blocks using colorstate */
+ return eb_nextc(s->b, eb_goto_bol(s->b, offset), &offset) == '#';
+}
+
+static int mkd_find_heading(EditState *s, int offset, int *level, int silent)
+{
+ int offset1, nb, c;
+
+ offset = eb_goto_bol(s->b, offset);
+ for (;;) {
+ /* Find line starting with '#' */
+ /* XXX: should ignore blocks using colorstate */
+ if (eb_nextc(s->b, offset, &offset1) == '#') {
+ for (nb = 1; (c = eb_nextc(s->b, offset1, &offset1)) == '#'; nb++)
+ continue;
+ if (qe_isblank(c)) {
+ *level = nb;
+ return offset;
+ }
+ }
+ if (offset == 0)
+ break;
+ offset = eb_prev_line(s->b, offset);
+ }
+ if (!silent)
+ put_status(s, "Before first heading");
+
+ return -1;
+}
+
+static int mkd_next_heading(EditState *s, int offset, int target, int *level)
+{
+ int offset1, nb, c;
+
+ for (;;) {
+ offset = eb_next_line(s->b, offset);
+ if (offset >= s->b->total_size) {
+ nb = 0;
+ break;
+ }
+ /* XXX: should ignore blocks using colorstate */
+ if (eb_nextc(s->b, offset, &offset1) == '#') {
+ for (nb = 1; (c = eb_nextc(s->b, offset1, &offset1)) == '#'; nb++)
+ continue;
+ if (qe_isblank(c) && nb <= target) {
+ break;
+ }
+ }
+ }
+ if (level)
+ *level = nb;
+ return offset;
+}
+
+static int mkd_prev_heading(EditState *s, int offset, int target, int *level)
+{
+ int offset1, nb, c;
+
+ for (;;) {
+ if (offset == 0) {
+ nb = 0;
+ break;
+ }
+ offset = eb_prev_line(s->b, offset);
+ /* XXX: should ignore blocks using colorstate */
+ if (eb_nextc(s->b, offset, &offset1) == '#') {
+ for (nb = 1; (c = eb_nextc(s->b, offset1, &offset1)) == '#'; nb++)
+ continue;
+ if (qe_isblank(c) && nb <= target) {
+ break;
+ }
+ }
+ }
+ if (level)
+ *level = nb;
+ return offset;
+}
+
+static void do_outline_next_vsible_heading(EditState *s)
+{
+ s->offset = mkd_next_heading(s, s->offset, MAX_LEVEL, NULL);
+}
+
+static void do_outline_previous_vsible_heading(EditState *s)
+{
+ s->offset = mkd_prev_heading(s, s->offset, MAX_LEVEL, NULL);
+}
+
+static void do_outline_up_heading(EditState *s)
+{
+ int offset, level;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ if (level <= 1) {
+ put_status(s, "Already at top level of the outline");
+ return;
+ }
+
+ s->offset = mkd_prev_heading(s, offset, level - 1, &level);
+}
+
+static void do_mkd_backward_same_level(EditState *s)
+{
+ int offset, level, level1;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ offset = mkd_prev_heading(s, offset, level, &level1);
+ if (level1 != level) {
+ put_status(s, "No previous same-level heading");
+ return;
+ }
+ s->offset = offset;
+}
+
+static void do_mkd_forward_same_level(EditState *s)
+{
+ int offset, level, level1;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ offset = mkd_next_heading(s, offset, level, &level1);
+ if (level1 != level) {
+ put_status(s, "No following same-level heading");
+ return;
+ }
+ s->offset = offset;
+}
+
+static void do_mkd_goto(EditState *s, const char *dest)
+{
+ int offset, level, level1, nb;
+ const char *p = dest;
+
+ /* XXX: Should pop up a window with numbered outline index
+ * and let the user select the target interactively.
+ */
+
+ /* Jump to numbered destination. */
+ for (offset = 0, level = 0; qe_isdigit(*p); ) {
+ nb = strtol(p, (char **)&p, 10);
+ if (*p == '.')
+ p++;
+ level++;
+ for (; nb > 0; nb--) {
+ offset = mkd_next_heading(s, offset, level, &level1);
+ if (level != level1) {
+ put_status(s, "Heading not found");
+ return;
+ }
+ }
+ }
+ if (level)
+ s->offset = offset;
+}
+
+static void do_mkd_mark_element(EditState *s, int subtree)
+{
+ QEmacsState *qs = s->qe_state;
+ int offset, offset1, level;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ offset1 = mkd_next_heading(s, offset, subtree ? level : MAX_LEVEL, NULL);
+
+ /* XXX: if repeating last command, add subtree to region */
+ if (qs->last_cmd_func != qs->this_cmd_func)
+ s->b->mark = offset;
+
+ s->offset = offset1;
+ /* activate region hilite */
+ if (s->qe_state->hilite_region)
+ s->region_style = QE_STYLE_REGION_HILITE;
+}
+
+static void do_mkd_insert_heading(EditState *s, int flags)
+{
+ int offset, offset0, offset1, level = 1;
+
+ if (check_read_only(s))
+ return;
+
+ offset = mkd_find_heading(s, s->offset, &level, 1);
+ offset0 = eb_goto_bol(s->b, s->offset);
+ offset1 = eb_goto_eol(s->b, s->offset);
+
+ /* if at beginning of heading line, insert sibling heading before,
+ * if in the middle of a heading line, split the heading,
+ * otherwise, make the current line a heading line at current level.
+ */
+ if (flags & 2) {
+ /* respect-content: insert heading at end of subtree */
+ offset = mkd_next_heading(s, offset, level, NULL);
+ eb_insert_uchar(s->b, offset, '\n');
+ eb_insert_uchar(s->b, offset, '\n');
+ } else
+ if (s->offset <= offset + level + 1) {
+ eb_insert_uchar(s->b, offset, '\n');
+ } else
+ if (offset == offset0 || offset == offset1) {
+ offset = s->offset;
+ offset += eb_insert_uchar(s->b, offset, '\n');
+ } else {
+ offset = offset0;
+ }
+ while (eb_nextc(s->b, offset, &offset1) == ' ') {
+ eb_delete_uchar(s->b, offset);
+ }
+ while (level-- > 0) {
+ offset += eb_insert_uchar(s->b, offset, '#');
+ }
+ offset += eb_insert_uchar(s->b, offset, ' ');
+ s->offset = eb_goto_eol(s->b, offset);
+}
+
+static void do_mkd_promote(EditState *s, int dir)
+{
+ int offset, level;
+
+ if (check_read_only(s))
+ return;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ if (dir < 0) {
+ eb_insert_uchar(s->b, offset, '#');
+ } else
+ if (dir > 0) {
+ if (level > 1)
+ eb_delete_uchar(s->b, offset);
+ else
+ put_status(s, "Cannot promote to level 0");
+ }
+}
+
+static void do_mkd_promote_subtree(EditState *s, int dir)
+{
+ int offset, level, level1;
+
+ if (check_read_only(s))
+ return;
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ for (;;) {
+ if (dir < 0) {
+ eb_insert_uchar(s->b, offset, '#');
+ } else
+ if (dir > 0) {
+ if (level > 1) {
+ eb_delete_uchar(s->b, offset);
+ } else {
+ put_status(s, "Cannot promote to level 0");
+ return;
+ }
+ }
+ offset = mkd_next_heading(s, offset, MAX_LEVEL, &level1);
+ if (level1 <= level)
+ break;
+ }
+}
+
+static void do_mkd_move_subtree(EditState *s, int dir)
+{
+ int offset, offset1, offset2, level, level1, level2, size;
+ EditBuffer *b1;
+
+ if (check_read_only(s))
+ return;
+
+ if (!mkd_is_header_line(s, s->offset)) {
+ put_status(s, "Not on header line");
+ return;
+ }
+
+ offset = mkd_find_heading(s, s->offset, &level, 0);
+ if (offset < 0)
+ return;
+
+ offset1 = mkd_next_heading(s, offset, level, &level1);
+ size = offset1 - offset;
+
+ if (dir < 0) {
+ offset2 = mkd_prev_heading(s, offset, level, &level2);
+ if (level2 < level) {
+ put_status(s, "Cannot move substree");
+ return;
+ }
+ } else {
+ if (offset1 == s->b->total_size || level1 < level) {
+ put_status(s, "Cannot move substree");
+ return;
+ }
+ offset2 = mkd_next_heading(s, offset1, level, &level2);
+ }
+ b1 = eb_new("*tmp*", BF_SYSTEM | (s->b->flags & BF_STYLES));
+ eb_set_charset(b1, s->b->charset, s->b->eol_type);
+ eb_insert_buffer_convert(b1, 0, s->b, offset, size);
+ eb_delete(s->b, offset, size);
+ if (offset2 > offset)
+ offset2 -= size;
+ eb_insert_buffer_convert(s->b, offset2, b1, 0, b1->total_size);
+ eb_free(&b1);
+ s->offset = offset2;
+}
+
+static void do_mkd_meta_return(EditState *s)
+{
+ do_mkd_insert_heading(s, 0);
+}
+
+static void do_mkd_metaleft(EditState *s)
+{
+ if (mkd_is_header_line(s, s->offset))
+ do_mkd_promote(s, +1);
+ else
+ do_word_right(s, -1);
+}
+
+static void do_mkd_metaright(EditState *s)
+{
+ if (mkd_is_header_line(s, s->offset))
+ do_mkd_promote(s, -1);
+ else
+ do_word_right(s, +1);
+}
+
+static void do_mkd_metadown(EditState *s)
+{
+ do_mkd_move_subtree(s, +1);
+}
+
+static void do_mkd_metaup(EditState *s)
+{
+ do_mkd_move_subtree(s, -1);
+}
+
+static int mkd_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+ /* just check file extension */
+ if (match_extension(p->filename, mode->extensions))
+ return 80;
+
+ return 1;
+}
+
+/* Mkd mode specific commands */
+static CmdDef mkd_commands[] = {
+ /* Motion */
+ CMD2( KEY_CTRLC(KEY_CTRL('n')), KEY_NONE, /* C-c C-n */
+ "mkd-next-visible-heading",
+ do_outline_next_vsible_heading, ES, "")
+ CMD2( KEY_CTRLC(KEY_CTRL('p')), KEY_NONE, /* C-c C-p */
+ "mkd-previous-visible-heading",
+ do_outline_previous_vsible_heading, ES, "")
+ CMD2( KEY_CTRLC(KEY_CTRL('u')), KEY_NONE, /* C-c C-u */
+ "mkd-up-heading", do_outline_up_heading, ES, "")
+ CMD2( KEY_CTRLC(KEY_CTRL('b')), KEY_NONE, /* C-c C-b */
+ "mkd-backward-same-level", do_mkd_backward_same_level, ES, "")
+ CMD2( KEY_CTRLC(KEY_CTRL('f')), KEY_NONE, /* C-c C-f */
+ "mkd-forward-same-level", do_mkd_forward_same_level, ES, "")
+ CMD2( KEY_CTRLC(KEY_CTRL('j')), KEY_NONE, /* C-c C-j */
+ "mkd-goto", do_mkd_goto, ESs,
+ "s{select location to jump to: }[mkdjump]|mkdjump|")
+ CMD3( KEY_META('h'), KEY_NONE, /* M-h */
+ "mkd-mark-element", do_mkd_mark_element, ESi, 0, "v")
+ CMD3( KEY_CTRLC('@'), KEY_NONE, /* C-c @ */
+ "mkd-mark-subtree", do_mkd_mark_element, ESi, 1, "v")
+ /* Editing */
+ CMD3( KEY_NONE, KEY_NONE, /* indirect through M-RET */
+ "mkd-insert-heading", do_mkd_insert_heading, ESi, 0, "*v")
+ CMD3( KEY_CTRL('j'), KEY_NONE, /* actually C-RET */
+ "mkd-insert-heading-respect-content", do_mkd_insert_heading, ESi, 2,
"*v")
+ CMD3( KEY_NONE, KEY_NONE,
+ "mkd-do-demote", do_mkd_promote, ESi, -1, "*v")
+ CMD3( KEY_NONE, KEY_NONE,
+ "mkd-do-promote", do_mkd_promote, ESi, +1, "*v")
+ CMD3( KEY_CTRLX('>'), KEY_NONE, /* actually M-S-right | C-c C-x R */
+ "mkd-demote-subtree", do_mkd_promote_subtree, ESi, -1, "*v")
+ CMD3( KEY_CTRLX('<'), KEY_NONE, /* actually M-S-left | C-c C-x L */
+ "mkd-promote-subtree", do_mkd_promote_subtree, ESi, +1, "*v")
+ CMD3( KEY_NONE, KEY_NONE,
+ "mkd-move-subtree-down", do_mkd_move_subtree, ESi, +1, "*v")
+ CMD3( KEY_NONE, KEY_NONE,
+ "mkd-move-subtree-up", do_mkd_move_subtree, ESi, -1, "*v")
+ CMD2( KEY_META(KEY_RET), KEY_NONE, /* Actually M-RET | C-c C-x m */
+ "mkd-meta-return", do_mkd_meta_return, ES, "*")
+ CMD2( KEY_ESC, KEY_LEFT, /* actually M-left | C-c C-x l */
+ "mkd-metaleft", do_mkd_metaleft, ES, "")
+ CMD2( KEY_ESC, KEY_RIGHT, /* actually M-right | C-c C-x r */
+ "mkd-metaright", do_mkd_metaright, ES, "")
+ CMD2( KEY_ESC, KEY_DOWN, /* actually M-down | C-c C-x d */
+ "mkd-metadown", do_mkd_metadown, ES, "")
+ CMD2( KEY_ESC, KEY_UP, /* actually M-up | C-c C-x u */
+ "mkd-metaup", do_mkd_metaup, ES, "")
+ CMD_DEF_END,
+};
+
+static int mkd_mode_init(EditState *s, ModeSavedData *saved_data)
+{
+ text_mode_init(s, saved_data);
+ s->b->tab_width = 4;
+ return 0;
+}
+
+static int mkd_init(void)
+{
+ memcpy(&mkd_mode, &text_mode, sizeof(ModeDef));
+ mkd_mode.name = "markdown";
+ mkd_mode.extensions = "mkd|md";
+ mkd_mode.mode_probe = mkd_mode_probe;
+ mkd_mode.mode_init = mkd_mode_init;
+ mkd_mode.colorize_func = mkd_colorize_line;
+
+ qe_register_mode(&mkd_mode);
+ qe_register_cmd_table(mkd_commands, &mkd_mode);
+
+ return 0;
+}
+
+qe_module_init(mkd_init);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemacs-commit] qemacs Makefile markdown.c,
Charlie Gordon <=