Hi all,
I've created a basic Scintilla lexer for the Markdown formatting syntax
along with Geany syntax and tag support. It doesn't do everything;
indented code blocks and embedded HTML aren't highlighted, but it's
already very useful. Some extra highlighting features are added for
the Pandoc implementation: strikeout, using '#.' as a default ordered
list item marker, and delimited code blocks.
Patch against build 4026 with -p5 from Geany's top build directory.
This was built and tested on Linux.
Cheers,
Jon
*** /home/jstrait/build/geany-4026/scintilla/KeyWords.cxx 2009-07-25 10:50:38.000000000 -0700
--- /home/jstrait/build/geany-my-changes/scintilla/KeyWords.cxx 2009-07-25 14:13:26.000000000 -0700
***************
*** 158,163 ****
--- 158,164 ----
LINK_LEXER(lmLatex);
LINK_LEXER(lmLua);
LINK_LEXER(lmMake);
+ LINK_LEXER(lmMarkdown);
LINK_LEXER(lmMatlab);
LINK_LEXER(lmNsis);
LINK_LEXER(lmNull);
*** /home/jstrait/build/geany-4026/scintilla/Makefile.am 2009-07-25 10:50:38.000000000 -0700
--- /home/jstrait/build/geany-my-changes/scintilla/Makefile.am 2009-07-25 12:44:06.000000000 -0700
***************
*** 21,26 ****
--- 21,27 ----
LexHTML.cxx \
LexYAML.cxx \
LexLua.cxx \
+ LexMarkdown.cxx \
LexNsis.cxx \
LexMatlab.cxx \
LexOthers.cxx \
*** /home/jstrait/build/geany-4026/scintilla/include/SciLexer.h 2009-07-25 10:50:33.000000000 -0700
--- /home/jstrait/build/geany-my-changes/scintilla/include/SciLexer.h 2009-07-25 12:01:38.000000000 -0700
***************
*** 110,115 ****
--- 110,116 ----
#define SCLEX_POWERPRO 95
#define SCLEX_NIMROD 96
#define SCLEX_SML 97
+ #define SCLEX_MARKDOWN 98
#define SCLEX_AUTOMATIC 1000
#define SCE_P_DEFAULT 0
#define SCE_P_COMMENTLINE 1
***************
*** 1277,1282 ****
--- 1278,1305 ----
#define SCE_MYSQL_USER2 19
#define SCE_MYSQL_USER3 20
#define SCE_MYSQL_HIDDENCOMMAND 21
+ #define SCE_MARKDOWN_DEFAULT 0
+ #define SCE_MARKDOWN_LINE_BEGIN 1
+ #define SCE_MARKDOWN_STRONG1 2
+ #define SCE_MARKDOWN_STRONG2 3
+ #define SCE_MARKDOWN_EM1 4
+ #define SCE_MARKDOWN_EM2 5
+ #define SCE_MARKDOWN_HEADER1 6
+ #define SCE_MARKDOWN_HEADER2 7
+ #define SCE_MARKDOWN_HEADER3 8
+ #define SCE_MARKDOWN_HEADER4 9
+ #define SCE_MARKDOWN_HEADER5 10
+ #define SCE_MARKDOWN_HEADER6 11
+ #define SCE_MARKDOWN_PRECHAR 12
+ #define SCE_MARKDOWN_ULIST_ITEM 13
+ #define SCE_MARKDOWN_OLIST_ITEM 14
+ #define SCE_MARKDOWN_BLOCKQUOTE 15
+ #define SCE_MARKDOWN_STRIKEOUT 16
+ #define SCE_MARKDOWN_HRULE 17
+ #define SCE_MARKDOWN_LINK 18
+ #define SCE_MARKDOWN_CODE 19
+ #define SCE_MARKDOWN_CODE2 20
+ #define SCE_MARKDOWN_CODEBK 21
#define SCE_PO_DEFAULT 0
#define SCE_PO_COMMENT 1
#define SCE_PO_MSGID 2
*** /home/jstrait/build/geany-4026/scintilla/include/Scintilla.iface 2009-07-25 10:50:33.000000000 -0700
--- /home/jstrait/build/geany-my-changes/scintilla/include/Scintilla.iface 2009-07-25 12:06:52.000000000 -0700
***************
*** 2135,2140 ****
--- 2135,2141 ----
val SCLEX_POWERPRO=95
val SCLEX_NIMROD=96
val SCLEX_SML=97
+ val SCLEX_MARKDOWN=98
# When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
# value assigned in sequence from SCLEX_AUTOMATIC+1.
***************
*** 3545,3550 ****
--- 3546,3575 ----
val SCE_SML_COMMENT1=13
val SCE_SML_COMMENT2=14
val SCE_SML_COMMENT3=15
+ # Lexical state for SCLEX_MARKDOWN
+ lex Markdown=SCLEX_MARKDOWN SCE_MARKDOWN_
+ val SCE_MARKDOWN_DEFAULT=0
+ val SCE_MARKDOWN_LINE_BEGIN=1
+ val SCE_MARKDOWN_STRONG1=2
+ val SCE_MARKDOWN_STRONG2=3
+ val SCE_MARKDOWN_EM1=4
+ val SCE_MARKDOWN_EM2=5
+ val SCE_MARKDOWN_HEADER1=6
+ val SCE_MARKDOWN_HEADER2=7
+ val SCE_MARKDOWN_HEADER3=8
+ val SCE_MARKDOWN_HEADER4=9
+ val SCE_MARKDOWN_HEADER5=10
+ val SCE_MARKDOWN_HEADER6=11
+ val SCE_MARKDOWN_PRECHAR=12
+ val SCE_MARKDOWN_ULIST_ITEM=13
+ val SCE_MARKDOWN_OLIST_ITEM=14
+ val SCE_MARKDOWN_BLOCKQUOTE=15
+ val SCE_MARKDOWN_STRIKEOUT=16
+ val SCE_MARKDOWN_HRULE=17
+ val SCE_MARKDOWN_LINK=18
+ val SCE_MARKDOWN_CODE=19
+ val SCE_MARKDOWN_CODE2=20
+ val SCE_MARKDOWN_CODEBK=21
# Events
*** /home/jstrait/build/geany-4026/scintilla/LexMarkdown.cxx 2009-07-25 22:36:18.000000000 -0700
--- /home/jstrait/build/geany-my-changes/scintilla/LexMarkdown.cxx 2009-05-21 15:36:47.000000000 -0700
***************
*** 0 ****
--- 1,433 ----
+ /******************************************************************
+ * LexMarkdown.cxx
+ *
+ * A simple Markdown lexer for scintilla.
+ *
+ * Includes highlighting for some extra features from the
+ * Pandoc implementation; strikeout, using '#.' as a default
+ * ordered list item marker, and delimited code blocks.
+ *
+ * Limitations:
+ *
+ * Standard indented code blocks are not highlighted at all,
+ * as it would conflict with other indentation schemes. Use
+ * delimited code blocks for blanket highlighting of an
+ * entire code block. Embedded HTML is not highlighted either.
+ * Blanket HTML highlighting has issues, because some Markdown
+ * implementations allow Markdown markup inside of the HTML. Also,
+ * there is a following blank line issue that can't be ignored,
+ * explained in the next paragraph. Embedded HTML and code
+ * blocks would be better supported with language specific
+ * highlighting; something Scintilla isn't really architected
+ * to support yet.
+ *
+ * The highlighting aims to accurately reflect correct syntax,
+ * but a few restrictions are relaxed. Delimited code blocks are
+ * highlighted, even if the line following the code block is not blank.
+ * Requiring a blank line after a block, breaks the highlighting
+ * in certain cases, because of the way Scintilla ends up calling
+ * the lexer.
+ *
+ * Written by Jon Strait - [email protected]
+ *
+ * This source code is released for free distribution under the
+ * terms of the GNU General Public License.
+ *
+ *****************************************************************/
+
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <stdarg.h>
+
+ #include "Platform.h"
+
+ #include "PropSet.h"
+ #include "Accessor.h"
+ #include "StyleContext.h"
+ #include "KeyWords.h"
+ #include "Scintilla.h"
+ #include "SciLexer.h"
+
+ #ifdef SCI_NAMESPACE
+ using namespace Scintilla;
+ #endif
+
+ static inline bool IsNewline(const int ch) {
+ return (ch == '\n' || ch == '\r');
+ }
+
+ // True if can follow ch down to the end with possibly trailing whitespace
+ static bool FollowToLineEnd(const int ch, const int state, const int endPos, StyleContext &sc) {
+ int i = 0;
+ while (sc.GetRelative(++i) == ch)
+ ;
+ // Skip over whitespace
+ while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos)
+ ++i;
+ if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) {
+ sc.Forward(i);
+ sc.ChangeState(state);
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ return true;
+ }
+ else return false;
+ }
+
+ // Set the state on text section from current to length characters,
+ // then set the rest until the newline to default, except for any characters matching token
+ static void SetStateAndZoom(const int state, const int length, const int token, StyleContext &sc) {
+ int i = 0;
+ sc.SetState(state);
+ sc.Forward(length);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ sc.Forward();
+ while (sc.More() && !IsNewline(sc.ch)) {
+ bool started = false;
+ if (sc.ch == token && !started) {
+ sc.SetState(state);
+ started = true;
+ }
+ else if (sc.ch != token) {
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ started = false;
+ }
+ sc.Forward();
+ }
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+
+ // Does the previous line have more than spaces and tabs?
+ static bool HasPrevLineContent(StyleContext &sc) {
+ int i = 0;
+ // Go back to the previous newline
+ while ((--i + sc.currentPos) && !IsNewline(sc.GetRelative(i)))
+ ;
+ while (--i + sc.currentPos) {
+ if (IsNewline(sc.GetRelative(i)))
+ break;
+ if (!IsASpaceOrTab(sc.GetRelative(i)))
+ return true;
+ }
+ return false;
+ }
+
+ static bool IsValidHrule(const int endPos, StyleContext &sc) {
+ int c, i = 0, count = 1;
+ while (++i) {
+ c = sc.GetRelative(i);
+ if (c == sc.ch)
+ ++count;
+ // hit a terminating character
+ else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) {
+ // Are we a valid HRULE
+ if ((IsNewline(c) || sc.currentPos + i == endPos) &&
+ count >= 3 && !HasPrevLineContent(sc)) {
+ sc.SetState(SCE_MARKDOWN_HRULE);
+ sc.Forward(i);
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ return true;
+ }
+ else {
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ return false;
+ }
+ }
+ }
+ }
+
+ // Only consume if already valid. Doesn't work for delimiting multiple lines.
+ static void ConsumeEnd(const int state, const int origPos, const int endPos,
+ const char *token, StyleContext &sc) {
+ int targetPos;
+ while (sc.currentPos + 1 < endPos) {
+ sc.Forward();
+ if (sc.Match(token) && sc.chPrev != '\\' && sc.chPrev != ' ') {
+ targetPos = sc.currentPos + strlen(token);
+ sc.currentPos = origPos;
+ sc.SetState(state);
+ sc.Forward(targetPos - origPos);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ break;
+ }
+ }
+ }
+
+ static void ColorizeMarkdownDoc(unsigned int startPos, int length, int initStyle,
+ WordList *keywordlists[], Accessor &styler) {
+
+ int digitCount = 0;
+ int endPos = startPos + length;
+ int precharCount;
+ // Don't advance on a new loop iteration and retry at the same position.
+ // Useful in the corner case of having to start at the beginning file position
+ // in the default state.
+ bool freezeCursor = false;
+
+ StyleContext sc(startPos, length, initStyle, styler);
+
+ while (sc.More()) {
+ // Skip past escaped characters
+ if (sc.ch == '\\') {
+ sc.Forward();
+ continue;
+ }
+
+ // A blockquotes resets the line semantics
+ if (sc.state == SCE_MARKDOWN_BLOCKQUOTE)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+
+ // Conditional state-based actions
+ if (sc.state == SCE_MARKDOWN_CODE2) {
+ if (sc.Match("``") && sc.GetRelative(-2) != ' ') {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_CODE) {
+ if (sc.ch == '`' && sc.chPrev != ' ')
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ /* De-activated because it gets in the way of other valid indentation
+ * schemes, for example multiple paragraphs inside a list item.
+ // Code block
+ else if (sc.state == SCE_MARKDOWN_CODEBK) {
+ bool d = true;
+ if (IsNewline(sc.ch)) {
+ if (sc.chNext != '\t') {
+ for (int c = 1; c < 5; ++c) {
+ if (sc.GetRelative(c) != ' ')
+ d = false;
+ }
+ }
+ }
+ else if (sc.atLineStart) {
+ if (sc.ch != '\t' ) {
+ for (int i = 0; i < 4; ++i) {
+ if (sc.GetRelative(i) != ' ')
+ d = false;
+ }
+ }
+ }
+ if (!d)
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ */
+ // Strong
+ else if (sc.state == SCE_MARKDOWN_STRONG1) {
+ if (sc.Match("**") && sc.chPrev != ' ') {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_STRONG2) {
+ if (sc.Match("__") && sc.chPrev != ' ') {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ // Emphasis
+ else if (sc.state == SCE_MARKDOWN_EM1) {
+ if (sc.ch == '*' && sc.chPrev != ' ')
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.state == SCE_MARKDOWN_EM2) {
+ if (sc.ch == '_' && sc.chPrev != ' ')
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.state == SCE_MARKDOWN_CODEBK) {
+ if (sc.atLineStart && sc.Match("~~~")) {
+ int i = 1;
+ while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos)
+ i++;
+ sc.Forward(i);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_STRIKEOUT) {
+ if (sc.Match("~~") && sc.chPrev != ' ') {
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) {
+ // Header
+ if (sc.Match("######"))
+ SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc);
+ else if (sc.Match("#####"))
+ SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc);
+ else if (sc.Match("####"))
+ SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc);
+ else if (sc.Match("###"))
+ SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc);
+ else if (sc.Match("##"))
+ SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc);
+ else if (sc.Match("#")) {
+ // Catch the special case of an unordered list
+ if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ else
+ SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc);
+ }
+ // Code block
+ else if (sc.Match("~~~")) {
+ if (!HasPrevLineContent(sc))
+ sc.SetState(SCE_MARKDOWN_CODEBK);
+ else
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch == '=') {
+ if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc))
+ ;
+ else
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch == '-') {
+ if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc))
+ ;
+ else {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ }
+ else if (IsNewline(sc.ch))
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ else {
+ precharCount = 0;
+ sc.SetState(SCE_MARKDOWN_PRECHAR);
+ }
+ }
+
+ // The header lasts until the newline
+ else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 ||
+ sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 ||
+ sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) {
+ if (IsNewline(sc.ch))
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+
+ // New state only within the initial whitespace
+ if (sc.state == SCE_MARKDOWN_PRECHAR) {
+ // Blockquote
+ if (sc.ch == '>' && precharCount < 5)
+ sc.SetState(SCE_MARKDOWN_BLOCKQUOTE);
+ /*
+ // Begin of code block
+ else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4))
+ sc.SetState(SCE_MARKDOWN_CODEBK);
+ */
+ // HRule - Total of three or more hyphens, asterisks, or underscores
+ // on a line by themselves
+ else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '_') && IsValidHrule(endPos, sc))
+ ;
+ // Unordered list
+ else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '+') && IsASpaceOrTab(sc.chNext)) {
+ sc.SetState(SCE_MARKDOWN_ULIST_ITEM);
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ // Ordered list
+ else if (IsADigit(sc.ch)) {
+ digitCount = 0;
+ while (IsADigit(sc.GetRelative(++digitCount)))
+ ;
+ if (sc.GetRelative(digitCount) == '.' &&
+ IsASpaceOrTab(sc.GetRelative(digitCount + 1))) {
+ sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
+ sc.Forward(digitCount + 1);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ // Alternate Ordered list
+ else if (sc.ch == '#' && sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) {
+ sc.SetState(SCE_MARKDOWN_OLIST_ITEM);
+ sc.Forward(2);
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ }
+ else if (sc.ch != ' ' || precharCount > 2)
+ sc.SetState(SCE_MARKDOWN_DEFAULT);
+ else
+ ++precharCount;
+ }
+
+ // New state anywhere in doc
+ if (sc.state == SCE_MARKDOWN_DEFAULT) {
+ int origPos = sc.currentPos;
+ if (sc.atLineStart && sc.ch == '#') {
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ freezeCursor = true;
+ }
+ // Links and Images
+ if (sc.Match("![") || sc.ch == '[') {
+ int i = 0, j = 0, k = 0;
+ int len = endPos - sc.currentPos;
+ while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\'))
+ ;
+ if (sc.GetRelative(i) == ']') {
+ j = i;
+ if (sc.GetRelative(++i) == '(') {
+ while (i < len && (sc.GetRelative(++i) != ')' || sc.GetRelative(i - 1) == '\\'))
+ ;
+ if (sc.GetRelative(i) == ')')
+ k = i;
+ }
+ else if (sc.GetRelative(i) == '[' || sc.GetRelative(++i) == '[') {
+ while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\'))
+ ;
+ if (sc.GetRelative(i) == ']')
+ k = i;
+ }
+ }
+ // At least a link text
+ if (j) {
+ sc.SetState(SCE_MARKDOWN_LINK);
+ sc.Forward(j);
+ // Also has a URL or reference portion
+ if (k)
+ sc.Forward(k - j);
+ sc.ForwardSetState(SCE_MARKDOWN_DEFAULT);
+ }
+ }
+ // Code - also a special case for alternate inside spacing
+ if (sc.Match("``") && sc.GetRelative(3) != ' ') {
+ sc.SetState(SCE_MARKDOWN_CODE2);
+ sc.Forward();
+ }
+ else if (sc.ch == '`' && sc.chNext != ' ') {
+ sc.SetState(SCE_MARKDOWN_CODE);
+ }
+ // Strong
+ else if (sc.Match("**") && sc.GetRelative(2) != ' ') {
+ sc.SetState(SCE_MARKDOWN_STRONG1);
+ sc.Forward();
+ }
+ else if (sc.Match("__") && sc.GetRelative(2) != ' ') {
+ sc.SetState(SCE_MARKDOWN_STRONG2);
+ sc.Forward();
+ }
+ // Emphasis
+ else if (sc.ch == '*' && sc.chNext != ' ')
+ sc.SetState(SCE_MARKDOWN_EM1);
+ else if (sc.ch == '_' && sc.chNext != ' ')
+ sc.SetState(SCE_MARKDOWN_EM2);
+ // Strikeout
+ else if (sc.Match("~~") && sc.GetRelative(2) != ' ') {
+ sc.SetState(SCE_MARKDOWN_STRIKEOUT);
+ sc.Forward();
+ }
+ // Beginning of line
+ else if (IsNewline(sc.ch))
+ sc.SetState(SCE_MARKDOWN_LINE_BEGIN);
+ }
+ // Advance if not holding back the cursor for this iteration.
+ if (!freezeCursor)
+ sc.Forward();
+ freezeCursor = false;
+ }
+ sc.Complete();
+ }
+
+ LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown");
+
*** /home/jstrait/build/geany-4026/src/filetypes.c 2009-07-25 10:50:51.000000000 -0700
--- /home/jstrait/build/geany-my-changes/src/filetypes.c 2009-07-25 12:15:00.000000000 -0700
***************
*** 341,346 ****
--- 341,357 ----
ft->comment_close = NULL;
ft->group = GEANY_FILETYPE_GROUP_COMPILED;
+ #define MARKDOWN
+ ft = filetypes[GEANY_FILETYPES_MARKDOWN];
+ ft->lang = 36;
+ ft->name = g_strdup("Markdown");
+ ft->title = g_strdup(_("Markdown source file"));
+ ft->extension = g_strdup("md");
+ ft->pattern = utils_strv_new("*.mdml", "*.mdwn", "*.markdown", "*.md", NULL);
+ ft->comment_open = NULL;
+ ft->comment_close = NULL;
+ ft->group = GEANY_FILETYPE_GROUP_MISC;
+
#define SH
ft = filetypes[GEANY_FILETYPES_SH];
ft->lang = 16;
*** /home/jstrait/build/geany-4026/src/filetypes.h 2009-07-25 10:50:51.000000000 -0700
--- /home/jstrait/build/geany-my-changes/src/filetypes.h 2009-07-25 13:27:01.000000000 -0700
***************
*** 76,82 ****
GEANY_FILETYPES_VHDL,
GEANY_FILETYPES_ADA,
GEANY_FILETYPES_CMAKE,
!
/* ^ append items here */
GEANY_MAX_BUILT_IN_FILETYPES /* Don't use this, use filetypes_array->len instead */
}
--- 76,82 ----
GEANY_FILETYPES_VHDL,
GEANY_FILETYPES_ADA,
GEANY_FILETYPES_CMAKE,
! GEANY_FILETYPES_MARKDOWN,
/* ^ append items here */
GEANY_MAX_BUILT_IN_FILETYPES /* Don't use this, use filetypes_array->len instead */
}
*** /home/jstrait/build/geany-4026/src/highlighting.c 2009-07-25 10:50:51.000000000 -0700
--- /home/jstrait/build/geany-my-changes/src/highlighting.c 2009-07-25 12:37:32.000000000 -0700
***************
*** 2725,2730 ****
--- 2725,2789 ----
}
+ static void styleset_markdown_init(gint ft_id, GKeyFile *config, GKeyFile *config_home)
+ {
+ new_style_array(GEANY_FILETYPES_MARKDOWN, 17);
+
+ get_keyfile_hex(config, config_home, "default", 0x000000, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[0]);
+ get_keyfile_hex(config, config_home, "strong", 0xff0000, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[1]);
+ get_keyfile_hex(config, config_home, "emphasis", 0xff0000, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[2]);
+ get_keyfile_hex(config, config_home, "header1", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[3]);
+ get_keyfile_hex(config, config_home, "header2", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[4]);
+ get_keyfile_hex(config, config_home, "header3", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[5]);
+ get_keyfile_hex(config, config_home, "header4", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[6]);
+ get_keyfile_hex(config, config_home, "header5", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[7]);
+ get_keyfile_hex(config, config_home, "header6", 0x0000bb, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[8]);
+ get_keyfile_hex(config, config_home, "ulist_item", 0x007f00, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[9]);
+ get_keyfile_hex(config, config_home, "olist_item", 0x007f00, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[10]);
+ get_keyfile_hex(config, config_home, "blockquote", 0xff0000, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[11]);
+ get_keyfile_hex(config, config_home, "strikeout", 0xaa00ff, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[12]);
+ get_keyfile_hex(config, config_home, "hrule", 0xff901e, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[13]);
+ get_keyfile_hex(config, config_home, "link", 0x0000ff, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[14]);
+ get_keyfile_hex(config, config_home, "code", 0x009f00, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[15]);
+ get_keyfile_hex(config, config_home, "codebk", 0x005f00, 0xffffff, FALSE, &style_sets[GEANY_FILETYPES_MARKDOWN].styling[16]);
+
+ style_sets[GEANY_FILETYPES_MARKDOWN].keywords = g_new(gchar*, 1);
+ style_sets[GEANY_FILETYPES_MARKDOWN].keywords[0] = NULL;
+
+ get_keyfile_wordchars(config, config_home, &style_sets[GEANY_FILETYPES_MARKDOWN].wordchars);
+ }
+
+ static void styleset_markdown(ScintillaObject *sci)
+ {
+ const filetype_id ft_id = GEANY_FILETYPES_MARKDOWN;
+
+ apply_filetype_properties(sci, SCLEX_MARKDOWN, ft_id);
+
+ set_sci_style(sci, STYLE_DEFAULT, GEANY_FILETYPES_MARKDOWN, 0);
+ set_sci_style(sci, SCE_MARKDOWN_DEFAULT, GEANY_FILETYPES_MARKDOWN, 0);
+ set_sci_style(sci, SCE_MARKDOWN_LINE_BEGIN, GEANY_FILETYPES_MARKDOWN, 0);
+ set_sci_style(sci, SCE_MARKDOWN_PRECHAR, GEANY_FILETYPES_MARKDOWN, 0);
+ set_sci_style(sci, SCE_MARKDOWN_STRONG1, GEANY_FILETYPES_MARKDOWN, 1);
+ set_sci_style(sci, SCE_MARKDOWN_STRONG2, GEANY_FILETYPES_MARKDOWN, 1);
+ set_sci_style(sci, SCE_MARKDOWN_EM1, GEANY_FILETYPES_MARKDOWN, 2);
+ set_sci_style(sci, SCE_MARKDOWN_EM2, GEANY_FILETYPES_MARKDOWN, 2);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER1, GEANY_FILETYPES_MARKDOWN, 3);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER2, GEANY_FILETYPES_MARKDOWN, 4);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER3, GEANY_FILETYPES_MARKDOWN, 5);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER4, GEANY_FILETYPES_MARKDOWN, 6);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER5, GEANY_FILETYPES_MARKDOWN, 7);
+ set_sci_style(sci, SCE_MARKDOWN_HEADER6, GEANY_FILETYPES_MARKDOWN, 8);
+ set_sci_style(sci, SCE_MARKDOWN_ULIST_ITEM, GEANY_FILETYPES_MARKDOWN, 9);
+ set_sci_style(sci, SCE_MARKDOWN_OLIST_ITEM, GEANY_FILETYPES_MARKDOWN, 10);
+ set_sci_style(sci, SCE_MARKDOWN_BLOCKQUOTE, GEANY_FILETYPES_MARKDOWN, 11);
+ set_sci_style(sci, SCE_MARKDOWN_STRIKEOUT, GEANY_FILETYPES_MARKDOWN, 12);
+ set_sci_style(sci, SCE_MARKDOWN_HRULE, GEANY_FILETYPES_MARKDOWN, 13);
+ set_sci_style(sci, SCE_MARKDOWN_LINK, GEANY_FILETYPES_MARKDOWN, 14);
+ set_sci_style(sci, SCE_MARKDOWN_CODE, GEANY_FILETYPES_MARKDOWN, 15);
+ set_sci_style(sci, SCE_MARKDOWN_CODE2, GEANY_FILETYPES_MARKDOWN, 15);
+ set_sci_style(sci, SCE_MARKDOWN_CODEBK, GEANY_FILETYPES_MARKDOWN, 16);
+ }
+
static void styleset_haskell_init(gint ft_id, GKeyFile *config, GKeyFile *config_home)
{
new_style_array(GEANY_FILETYPES_HASKELL, 17);
***************
*** 3599,3604 ****
--- 3658,3664 ----
init_styleset_case(GEANY_FILETYPES_LUA, styleset_lua_init);
init_styleset_case(GEANY_FILETYPES_MAKE, styleset_makefile_init);
init_styleset_case(GEANY_FILETYPES_MATLAB, styleset_matlab_init);
+ init_styleset_case(GEANY_FILETYPES_MARKDOWN, styleset_markdown_init);
init_styleset_case(GEANY_FILETYPES_NSIS, styleset_nsis_init);
init_styleset_case(GEANY_FILETYPES_PASCAL, styleset_pascal_init);
init_styleset_case(GEANY_FILETYPES_PERL, styleset_perl_init);
***************
*** 3660,3665 ****
--- 3720,3726 ----
styleset_case(GEANY_FILETYPES_LATEX, styleset_latex);
styleset_case(GEANY_FILETYPES_LUA, styleset_lua);
styleset_case(GEANY_FILETYPES_MAKE, styleset_makefile);
+ styleset_case(GEANY_FILETYPES_MARKDOWN, styleset_markdown);
styleset_case(GEANY_FILETYPES_MATLAB, styleset_matlab);
styleset_case(GEANY_FILETYPES_NSIS, styleset_nsis);
styleset_case(GEANY_FILETYPES_PASCAL, styleset_pascal);
*** /home/jstrait/build/geany-4026/tagmanager/Makefile.am 2009-07-25 10:51:05.000000000 -0700
--- /home/jstrait/build/geany-my-changes/tagmanager/Makefile.am 2009-07-25 13:34:55.000000000 -0700
***************
*** 51,56 ****
--- 51,57 ----
latex.c\
lregex.c\
matlab.c\
+ markdown.c\
pascal.c\
perl.c\
rest.c\
*** /home/jstrait/build/geany-4026/tagmanager/parsers.h 2009-07-25 10:51:05.000000000 -0700
--- /home/jstrait/build/geany-my-changes/tagmanager/parsers.h 2009-07-25 12:40:26.000000000 -0700
***************
*** 50,57 ****
MatlabParser, \
ValaParser, \
ActionScriptParser, \
! NsisParser
!
/*
langType of each parser
0 CParser
--- 50,57 ----
MatlabParser, \
ValaParser, \
ActionScriptParser, \
! NsisParser, \
! MarkdownParser
/*
langType of each parser
0 CParser
***************
*** 90,95 ****
--- 90,96 ----
33 ValaParser
34 ActionScriptParser
35 NsisParser
+ 36 MarkdownParser
*/
#endif /* _PARSERS_H */
*** /home/jstrait/build/geany-4026/tagmanager/markdown.c 2009-07-25 22:42:11.000000000 -0700
--- /home/jstrait/build/geany-my-changes/tagmanager/markdown.c 2009-02-26 00:18:08.000000000 -0800
***************
*** 0 ****
--- 1,106 ----
+ /*
+ *
+ * Copyright (c) 2009, Jon Strait
+ *
+ * This source code is released for free distribution under the terms of the
+ * GNU General Public License.
+ *
+ * This module contains functions for generating tags for Markdown files.
+ */
+
+ /*
+ * INCLUDE FILES
+ */
+ #include "general.h" /* must always come first */
+
+ #include <ctype.h>
+ #include <string.h>
+
+ #include "parse.h"
+ #include "read.h"
+ #include "vstring.h"
+
+ /*
+ * DATA DEFINITIONS
+ */
+
+ static kindOption MarkdownKinds[] = {
+ { TRUE, 'v', "variable", "sections"}
+ };
+
+ /*
+ * FUNCTION DEFINITIONS
+ */
+
+ /* checks if str is all the same character */
+ static boolean issame(const char *str)
+ {
+ char first = *str;
+
+ while (*(++str))
+ {
+ if (*str && *str != first)
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ static void makeMarkdownTag (const vString* const name, boolean name_before)
+ {
+ tagEntryInfo e;
+ initTagEntry (&e, vStringValue(name));
+
+ if (name_before)
+ e.lineNumber--; /* we want the line before the underline chars */
+ e.kindName = "variable";
+ e.kind = 'v';
+
+ makeTagEntry(&e);
+ }
+
+
+ static void findMarkdownTags (void)
+ {
+ vString *name = vStringNew();
+ const unsigned char *line;
+
+ while ((line = fileReadLine()) != NULL)
+ {
+ int line_len = strlen((const char*) line);
+ int name_len = vStringLength(name);
+
+ /* underlines must be the same length or more */
+ if (name_len > 0 && (line[0] == '=' || line[0] == '-') && issame((const char*) line))
+ {
+ makeMarkdownTag(name, TRUE);
+ }
+ else if (line[0] == '#') {
+ vStringClear(name);
+ vStringCatS(name, (const char *) line);
+ vStringTerminate(name);
+ makeMarkdownTag(name, FALSE);
+ }
+ else {
+ vStringClear (name);
+ if (! isspace(*line))
+ vStringCatS(name, (const char*) line);
+ vStringTerminate(name);
+ }
+ }
+ vStringDelete (name);
+ }
+
+ extern parserDefinition* MarkdownParser (void)
+ {
+ static const char *const patterns [] = { "*.md", NULL };
+ static const char *const extensions [] = { "md", NULL };
+ parserDefinition* const def = parserNew ("Markdown");
+
+ def->kinds = MarkdownKinds;
+ def->kindCount = KIND_COUNT (MarkdownKinds);
+ def->patterns = patterns;
+ def->extensions = extensions;
+ def->parser = findMarkdownTags;
+ return def;
+ }
+
_______________________________________________
Geany-devel mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel