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

Reply via email to