Skip to content

Instantly share code, notes, and snippets.

@alexcabrera
Created October 19, 2012 04:31
Show Gist options
  • Save alexcabrera/3916247 to your computer and use it in GitHub Desktop.
Save alexcabrera/3916247 to your computer and use it in GitHub Desktop.
How TM2 handles language grammars
{ patterns = ( { include = '#block'; } );
repository = {
block = {
patterns = (
{ include = '#separator'; },
{ include = '#heading'; },
{ include = '#blockquote'; },
{ include = '#lists'; },
{ include = '#raw_block'; },
{ include = '#link-def'; },
{ include = '#html'; },
{ include = '#paragraph'; },
);
repository = {
blockquote = {
name = 'markup.quote.markdown';
begin = '(^|\G)(>) ?';
while = '(^|\G)(>) ?';
captures = { 2 = { name = 'punctuation.definition.quote.markdown'; }; };
patterns = ( { include = '#block'; } );
};
heading = {
name = 'markup.heading.${1/(#)(#)?(#)?(#)?(#)?(#)?/${6:?6:${5:?5:${4:?4:${3:?3:${2:?2:1}}}}}/}.markdown';
begin = '(?:^|\G)(#{1,6})\s*(?=[\S[^#]])';
end = '\s*(#{1,6})?$\n?';
captures = { 1 = { name = 'punctuation.definition.heading.markdown'; }; };
contentName = 'entity.name.section.markdown';
patterns = ( { include = '#inline'; } );
};
heading-setext = {
patterns = (
{ name = 'markup.heading.setext.1.markdown';
match = '^(={3,})(?=[ \t]*$\n?)';
},
{ name = 'markup.heading.setext.2.markdown';
match = '^(-{3,})(?=[ \t]*$\n?)';
},
);
};
html = {
patterns = (
{ begin = '(?i)(^|\G)(?=<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del).*</\2\s*>\s*$)';
end = '$';
patterns = ( { include = 'text.html.basic'; } );
},
{ begin = '(?i)(^|\G)(?=<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del))';
while = '\G(?!</\2\s*>)';
patterns = ( { include = 'text.html.basic'; } );
},
);
};
link-def = {
name = 'meta.link.reference.def.markdown';
match = '^(?x:
\s* # Leading whitespace
(\[)(.+?)(\])(:) # Reference name
[ \t]* # Optional whitespace
(<?)(\S+?)(>?) # The url
[ \t]* # Optional whitespace
(?:
((\().+?(\))) # Match title in quotes…
| ((").+?(")) # or in parens.
)? # Title is optional
\s* # Optional whitespace
$
)';
captures = {
1 = { name = 'punctuation.definition.constant.markdown'; };
10 = { name = 'punctuation.definition.string.end.markdown'; };
11 = { name = 'string.other.link.description.title.markdown'; };
12 = { name = 'punctuation.definition.string.begin.markdown'; };
13 = { name = 'punctuation.definition.string.end.markdown'; };
2 = { name = 'constant.other.reference.link.markdown'; };
3 = { name = 'punctuation.definition.constant.markdown'; };
4 = { name = 'punctuation.separator.key-value.markdown'; };
5 = { name = 'punctuation.definition.link.markdown'; };
6 = { name = 'markup.underline.link.markdown'; };
7 = { name = 'punctuation.definition.link.markdown'; };
8 = { name = 'string.other.link.description.title.markdown'; };
9 = { name = 'punctuation.definition.string.begin.markdown'; };
};
};
list_paragraph = {
name = 'meta.paragraph.markdown';
begin = '(^|\G)(?=\S)(?![*+-]\s|[0-9]+\.\s)';
while = '(^|\G)(?!\s*$|#|[ ]{,3}([-*_][ ]{2,}){3,}[ \t]*$\n?|>|[ ]{0,3}[*+-]|[ ]{0,3}[0-9]+\.)';
patterns = (
{ include = '#inline'; },
{ include = 'text.html.basic'; },
{ include = '#heading-setext'; },
);
};
lists = {
patterns = (
{ name = 'markup.list.unnumbered.markdown';
comment = 'Currently does not support un-indented second lines.';
begin = '(^|\G)([ ]{0,3})([*+-])([ ]{1,3}|\t)';
while = '\G([ ]{4}|\t|$)';
beginCaptures = { 3 = { name = 'punctuation.definition.list.markdown'; }; };
patterns = (
{ include = '#list_paragraph'; },
{ include = '#block'; },
);
},
{ name = 'markup.list.numbered.markdown';
begin = '(^|\G)([ ]{0,3})([0-9]+\.)([ ]{1,3}|\t)';
while = '\G([ ]{4}|\t|$)';
beginCaptures = { 3 = { name = 'punctuation.definition.list.markdown'; }; };
patterns = (
{ include = '#list_paragraph'; },
{ include = '#block'; },
);
},
);
};
paragraph = {
name = 'meta.paragraph.markdown';
begin = '(^|\G)(?=\S)';
while = '(^|\G)(?!\s*$|#|[ ]{,3}([-*_][ ]{2,}){3,}[ \t]*$\n?|\s*\[.+?\]:|>)';
patterns = (
{ include = '#inline'; },
{ include = 'text.html.basic'; },
{ include = '#heading-setext'; },
);
};
raw_block = {
name = 'markup.raw.block.markdown';
begin = '(^|\G)([ ]{4}|\t)';
while = '(^|\G)([ ]{4}|\t)';
};
separator = {
name = 'meta.separator.markdown';
match = '(^|\G)[ ]{,3}([-*_])([ ]{,2}\2){2,}[ \t]*$\n?';
};
};
};
inline = {
patterns = (
{ include = '#ampersand'; },
{ include = '#bracket'; },
{ include = '#bold'; },
{ include = '#italic'; },
{ include = '#raw'; },
{ include = '#escape'; },
{ include = '#image-inline'; },
{ include = '#image-ref'; },
{ include = '#link-email'; },
{ include = '#link-inet'; },
{ include = '#link-inline'; },
{ include = '#link-ref'; },
{ include = '#link-ref-literal'; },
);
repository = {
bold = {
name = 'markup.bold.markdown';
begin = '(?x)
(\*\*|__)(?=\S) # Open
(?=
(
<[^>]*+> # HTML tags
| (?<raw>`+)([^`]|(?!(?<!`)\k<raw>(?!`))`)*+\k<raw>
# Raw
| \\[\\`*_{}\[\]()#.!+\->]?+ # Escapes
| \[
(
(?<square> # Named group
[^\[\]\\] # Match most chars
| \\. # Escaped chars
| \[ \g<square>*+ \] # Nested brackets
)*+
\]
(
( # Reference Link
[ ]? # Optional space
\[[^\]]*+\] # Ref name
)
| ( # Inline Link
\( # Opening paren
[ \t]*+ # Optional whtiespace
<?(.*?)>? # URL
[ \t]*+ # Optional whtiespace
( # Optional Title
(?<title>[''"])
(.*?)
\k<title>
)?
\)
)
)
)
| (?!(?<=\S)\1). # Everything besides
# style closer
)++
(?<=\S)\1 # Close
)
';
end = '(?<=\S)(\1)';
captures = { 1 = { name = 'punctuation.definition.bold.markdown'; }; };
patterns = (
{ begin = '(?=<[^>]*?>)';
end = '(?<=>)';
applyEndPatternLast = 1;
patterns = ( { include = 'text.html.basic'; } );
},
{ include = '#escape'; },
{ include = '#ampersand'; },
{ include = '#bracket'; },
{ include = '#raw'; },
{ include = '#italic'; },
{ include = '#image-inline'; },
{ include = '#link-inline'; },
{ include = '#link-inet'; },
{ include = '#link-email'; },
{ include = '#image-ref'; },
{ include = '#link-ref-literal'; },
{ include = '#link-ref'; },
);
};
italic = {
name = 'markup.italic.markdown';
begin = '(?x)
(\*|_)(?=\S) # Open
(?=
(
<[^>]*+> # HTML tags
| (?<raw>`+)([^`]|(?!(?<!`)\k<raw>(?!`))`)*+\k<raw>
# Raw
| \\[\\`*_{}\[\]()#.!+\->]?+ # Escapes
| \[
(
(?<square> # Named group
[^\[\]\\] # Match most chars
| \\. # Escaped chars
| \[ \g<square>*+ \] # Nested brackets
)*+
\]
(
( # Reference Link
[ ]? # Optional space
\[[^\]]*+\] # Ref name
)
| ( # Inline Link
\( # Opening paren
[ \t]*+ # Optional whtiespace
<?(.*?)>? # URL
[ \t]*+ # Optional whtiespace
( # Optional Title
(?<title>[''"])
(.*?)
\k<title>
)?
\)
)
)
)
| \1\1 # Must be bold closer
| (?!(?<=\S)\1). # Everything besides
# style closer
)++
(?<=\S)\1 # Close
)
';
end = '(?<=\S)(\1)((?!\1)|(?=\1\1))';
captures = { 1 = { name = 'punctuation.definition.italic.markdown'; }; };
patterns = (
{ begin = '(?=<[^>]*?>)';
end = '(?<=>)';
applyEndPatternLast = 1;
patterns = ( { include = 'text.html.basic'; } );
},
{ include = '#escape'; },
{ include = '#ampersand'; },
{ include = '#bracket'; },
{ include = '#raw'; },
{ include = '#bold'; },
{ include = '#image-inline'; },
{ include = '#link-inline'; },
{ include = '#link-inet'; },
{ include = '#link-email'; },
{ include = '#image-ref'; },
{ include = '#link-ref-literal'; },
{ include = '#link-ref'; },
);
};
ampersand = {
name = 'meta.other.valid-ampersand.markdown';
comment = '
Markdown will convert this for us. We match it so that the
HTML grammar will not mark it up as invalid.
';
match = '&(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)';
};
bracket = {
name = 'meta.other.valid-bracket.markdown';
comment = '
Markdown will convert this for us. We match it so that the
HTML grammar will not mark it up as invalid.
';
match = '<(?![a-z/?\$!])';
};
escape = {
name = 'constant.character.escape.markdown';
match = '\\[-`*_#+.!(){}\[\]\\>]';
};
image-inline = {
name = 'meta.image.inline.markdown';
match = '(?x:
\! # Images start with !
(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
# Match the link text.
([ ])? # Space not allowed
(\() # Opening paren for url
(<?)(\S+?)(>?) # The url
[ \t]* # Optional whitespace
(?:
((\().+?(\))) # Match title in parens…
| ((").+?(")) # or in quotes.
)? # Title is optional
\s* # Optional whitespace
(\))
)';
captures = {
1 = { name = 'punctuation.definition.string.begin.markdown'; };
10 = { name = 'string.other.link.description.title.markdown'; };
11 = { name = 'punctuation.definition.string.markdown'; };
12 = { name = 'punctuation.definition.string.markdown'; };
13 = { name = 'string.other.link.description.title.markdown'; };
14 = { name = 'punctuation.definition.string.markdown'; };
15 = { name = 'punctuation.definition.string.markdown'; };
16 = { name = 'punctuation.definition.metadata.markdown'; };
2 = { name = 'string.other.link.description.markdown'; };
3 = { name = 'punctuation.definition.string.end.markdown'; };
5 = { name = 'invalid.illegal.whitespace.markdown'; };
6 = { name = 'punctuation.definition.metadata.markdown'; };
7 = { name = 'punctuation.definition.link.markdown'; };
8 = { name = 'markup.underline.link.image.markdown'; };
9 = { name = 'punctuation.definition.link.markdown'; };
};
};
image-ref = {
name = 'meta.image.reference.markdown';
match = '\!(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)(.*?)(\])';
captures = {
1 = { name = 'punctuation.definition.string.begin.markdown'; };
2 = { name = 'string.other.link.description.markdown'; };
4 = { name = 'punctuation.definition.string.begin.markdown'; };
5 = { name = 'punctuation.definition.constant.markdown'; };
6 = { name = 'constant.other.reference.link.markdown'; };
7 = { name = 'punctuation.definition.constant.markdown'; };
};
};
link-email = {
name = 'meta.link.email.lt-gt.markdown';
match = '(<)((?:mailto:)?[-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(>)';
captures = {
1 = { name = 'punctuation.definition.link.markdown'; };
2 = { name = 'markup.underline.link.markdown'; };
4 = { name = 'punctuation.definition.link.markdown'; };
};
};
link-inet = {
name = 'meta.link.inet.markdown';
match = '(<)((?:https?|ftp)://.*?)(>)';
captures = {
1 = { name = 'punctuation.definition.link.markdown'; };
2 = { name = 'markup.underline.link.markdown'; };
3 = { name = 'punctuation.definition.link.markdown'; };
};
};
link-inline = {
name = 'meta.link.inline.markdown';
match = '(?x:
(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
# Match the link text.
([ ])? # Space not allowed
(\() # Opening paren for url
(<?)(.*?)(>?) # The url
[ \t]* # Optional whitespace
(?:
((\().+?(\))) # Match title in parens…
| ((").+?(")) # or in quotes.
)? # Title is optional
\s* # Optional whitespace
(\))
)';
captures = {
1 = { name = 'punctuation.definition.string.begin.markdown'; };
10 = { name = 'string.other.link.description.title.markdown'; };
11 = { name = 'punctuation.definition.string.begin.markdown'; };
12 = { name = 'punctuation.definition.string.end.markdown'; };
13 = { name = 'string.other.link.description.title.markdown'; };
14 = { name = 'punctuation.definition.string.begin.markdown'; };
15 = { name = 'punctuation.definition.string.end.markdown'; };
16 = { name = 'punctuation.definition.metadata.markdown'; };
2 = { name = 'string.other.link.title.markdown'; };
4 = { name = 'punctuation.definition.string.end.markdown'; };
5 = { name = 'invalid.illegal.whitespace.markdown'; };
6 = { name = 'punctuation.definition.metadata.markdown'; };
7 = { name = 'punctuation.definition.link.markdown'; };
8 = { name = 'markup.underline.link.markdown'; };
9 = { name = 'punctuation.definition.link.markdown'; };
};
};
link-ref = {
name = 'meta.link.reference.markdown';
match = '(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)([^\]]*+)(\])';
captures = {
1 = { name = 'punctuation.definition.string.begin.markdown'; };
2 = { name = 'string.other.link.title.markdown'; };
4 = { name = 'punctuation.definition.string.end.markdown'; };
5 = { name = 'punctuation.definition.constant.begin.markdown'; };
6 = { name = 'constant.other.reference.link.markdown'; };
7 = { name = 'punctuation.definition.constant.end.markdown'; };
};
};
link-ref-literal = {
name = 'meta.link.reference.literal.markdown';
match = '(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)(\])';
captures = {
1 = { name = 'punctuation.definition.string.begin.markdown'; };
2 = { name = 'string.other.link.title.markdown'; };
4 = { name = 'punctuation.definition.string.end.markdown'; };
5 = { name = 'punctuation.definition.constant.begin.markdown'; };
6 = { name = 'punctuation.definition.constant.end.markdown'; };
};
};
raw = {
name = 'markup.raw.inline.markdown';
match = '(`+)([^`]|(?!(?<!`)\1(?!`))`)*+(\1)';
captures = {
1 = { name = 'punctuation.definition.raw.markdown'; };
2 = { };
3 = { name = 'punctuation.definition.raw.markdown'; };
};
};
};
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment