diff --git a/packages/language-gfm/grammars/modern-tree-sitter-gfm-inline.cson b/packages/language-gfm/grammars/modern-tree-sitter-gfm-inline.cson new file mode 100644 index 0000000000..7f44177667 --- /dev/null +++ b/packages/language-gfm/grammars/modern-tree-sitter-gfm-inline.cson @@ -0,0 +1,10 @@ +scopeName: 'source.gfm.inline' +type: 'modern-tree-sitter' +parser: 'tree-sitter-markdown_inline' + +injectionRegex: '^(markdown-inline-internal)$' + +treeSitter: + parserSource: 'github:MDeiml/tree-sitter-markdown/tree-sitter-markdown-inline#28aa3baef73bd458d053b613b8bd10fd102b4405' + grammar: 'tree-sitter-markdown-inline/tree-sitter-markdown-inline.wasm' + highlightsQuery: 'tree-sitter-markdown-inline/highlights.scm' diff --git a/packages/language-gfm/grammars/modern-tree-sitter-gfm-with-frontmatter.cson b/packages/language-gfm/grammars/modern-tree-sitter-gfm-with-frontmatter.cson deleted file mode 100644 index 7cdb0977b3..0000000000 --- a/packages/language-gfm/grammars/modern-tree-sitter-gfm-with-frontmatter.cson +++ /dev/null @@ -1,30 +0,0 @@ -name: 'GitHub Markdown' -scopeName: 'source.gfm' -type: 'modern-tree-sitter' -# Generated from `savetheclocktower/tree-sitter-frontmatter`. -parser: 'tree-sitter-frontmatter' - -treeSitter: - grammar: 'tree-sitter/tree-sitter-frontmatter.wasm' - highlightsQuery: 'tree-sitter/tree-sitter-frontmatter/highlights.scm' - -fileTypes: [ - 'markdown' - 'md' - 'mdown' - 'mdwn' - 'mkd' - 'mkdn' - 'mkdown' - 'rmd' - 'ron' - 'workbook' -] - -firstLineRegex: '^---$' - -comments: - start: '' - blockStart: '' diff --git a/packages/language-gfm/grammars/modern-tree-sitter-gfm.cson b/packages/language-gfm/grammars/modern-tree-sitter-gfm.cson index 863370d1d9..b2cf67c6b5 100644 --- a/packages/language-gfm/grammars/modern-tree-sitter-gfm.cson +++ b/packages/language-gfm/grammars/modern-tree-sitter-gfm.cson @@ -1,15 +1,16 @@ -# This grammar doesn't have its own name because it's only meant to be injected. -scopeName: 'source.gfm.embedded' +scopeName: 'source.gfm' type: 'modern-tree-sitter' +name: 'GitHub Markdown' parser: 'tree-sitter-markdown' -injectionRegex: '(MARKDOWN|markdown|GFM|gfm)$' +injectionRegex: '^(markdown|MARKDOWN|gfm|GFM)$' treeSitter: - grammar: 'tree-sitter/tree-sitter-markdown.wasm' - highlightsQuery: 'tree-sitter/tree-sitter-markdown/highlights.scm' - foldsQuery: 'tree-sitter/tree-sitter-markdown/folds.scm' - tagsQuery: 'tree-sitter/tree-sitter-markdown/tags.scm' + parserSource: 'github:MDeiml/tree-sitter-markdown/tree-sitter-markdown#28aa3baef73bd458d053b613b8bd10fd102b4405' + grammar: 'tree-sitter-markdown/tree-sitter-markdown.wasm' + highlightsQuery: 'tree-sitter-markdown/highlights.scm' + foldsQuery: 'tree-sitter-markdown/folds.scm' + tagsQuery: 'tree-sitter-markdown/tags.scm' fileTypes: [ 'markdown' diff --git a/packages/language-gfm/grammars/tree-sitter-markdown-inline/highlights.scm b/packages/language-gfm/grammars/tree-sitter-markdown-inline/highlights.scm new file mode 100644 index 0000000000..0ec5313294 --- /dev/null +++ b/packages/language-gfm/grammars/tree-sitter-markdown-inline/highlights.scm @@ -0,0 +1,77 @@ +; BOLD/ITALIC/OTHER +; =============== + +(emphasis) @markup.italic.gfm + +(emphasis + . (emphasis_delimiter) @punctuation.definition.emphasis.begin.gfm) + +(emphasis + (emphasis_delimiter) @punctuation.definition.emphasis.end.gfm .) + +(strong_emphasis) @markup.bold.gfm +((strong_emphasis) @punctuation.definition.emphasis.begin.gfm + (#set! adjust.endAfterFirstMatchOf "^\\*\\*")) +((strong_emphasis) @punctuation.definition.emphasis.end.gfm + (#set! adjust.startBeforeFirstMatchOf "\\*\\*$")) + +(strikethrough) @markup.strike.gfm + +((strikethrough) @punctuation.definition.strike.begin.gfm + (#set! adjust.endAfterFirstMatchOf "^~~")) +((strikethrough) @punctuation.definition.strike.end.gfm + (#set! adjust.startBeforeFirstMatchOf "~~$")) + + +; INLINE/REPLACED +; =============== + +((uri_autolink) @markup.underline.link + (#set! adjust.startAfterFirstMatchOf "^<") + (#set! adjust.endBeforeFirstMatchOf ">$")) + +((uri_autolink) @punctuation.definition.begin.uri-autolink.gfm + (#set! adjust.endAfterFirstMatchOf "^<")) + +((uri_autolink) @punctuation.definition.end.uri-autolink.gfm + (#set! adjust.startBeforeFirstMatchOf ">$")) + +((link_text (image (image_description))) @_IGNORE_ + (#set! capture.final)) + +[(link_text) (image_description)] @string.unquoted.gfm @meta.link.text + +; The text inside []s in anchors/image syntax. +(full_reference_link + (link_label) @markup.underline.link.gfm + (#set! adjust.startAfterFirstMatchOf "^\\[") + (#set! adjust.endBeforeFirstMatchOf "]$")) + +(image + (link_destination) @markup.underline.link.gfm) + +(inline_link + (link_destination) @markup.underline.link.gfm) + +(link_title) @string.quoted.link-title.gfm + + +; CODE SPANS +; ========== + +(code_span) @meta.embedded.line.inline-code.gfm @markup.raw.inline.gfm + +(code_span + . (code_span_delimiter) @punctuation.definition.begin.string.inline-code.gfm) + +(code_span + (code_span_delimiter) @punctuation.definition.end.string.inline-code.gfm + .) + + +; MISC +; ==== + +(backslash_escape) @constant.character.escape.gfm + +(numeric_character_reference) @constant.character.entity.gfm diff --git a/packages/language-gfm/grammars/tree-sitter-markdown-inline/tree-sitter-markdown-inline.wasm b/packages/language-gfm/grammars/tree-sitter-markdown-inline/tree-sitter-markdown-inline.wasm new file mode 100755 index 0000000000..04618d113f Binary files /dev/null and b/packages/language-gfm/grammars/tree-sitter-markdown-inline/tree-sitter-markdown-inline.wasm differ diff --git a/packages/language-gfm/grammars/tree-sitter-markdown/folds.scm b/packages/language-gfm/grammars/tree-sitter-markdown/folds.scm new file mode 100644 index 0000000000..817b916852 --- /dev/null +++ b/packages/language-gfm/grammars/tree-sitter-markdown/folds.scm @@ -0,0 +1,11 @@ + +; Each individual list item can be folded if it's hard-wrapped. +((list_item) @fold + (#set! fold.endAt endPosition) + (#set! fold.adjustToEndOfPreviousRow true)) + +; Each section represents a heading and all the content underneath it until the +; next heading of equivalent or higher importance. +((section) @fold + (#set! fold.endAt endPosition) + (#set! fold.adjustToEndOfPreviousRow true)) diff --git a/packages/language-gfm/grammars/tree-sitter-markdown/highlights.scm b/packages/language-gfm/grammars/tree-sitter-markdown/highlights.scm new file mode 100644 index 0000000000..b17ba163ed --- /dev/null +++ b/packages/language-gfm/grammars/tree-sitter-markdown/highlights.scm @@ -0,0 +1,94 @@ +; HEADINGS +; ======== + +(setext_heading + heading_content: (_) @markup.heading.heading-1.gfm + (setext_h1_underline) @punctuation.definition.heading-underline.gfm) + +(setext_heading + heading_content: (_) @markup.heading.heading-2.gfm + (setext_h2_underline) @punctuation.definition.heading-underline.gfm) + +(atx_heading + (atx_h1_marker)) @markup.heading.heading-1.gfm + +(atx_heading + (atx_h2_marker)) @markup.heading.heading-2.gfm + +(atx_heading + (atx_h3_marker)) @markup.heading.heading-3.gfm + +(atx_heading + (atx_h4_marker)) @markup.heading.heading-4.gfm + +(atx_heading + (atx_h5_marker)) @markup.heading.heading-5.gfm + +(atx_heading + (atx_h6_marker)) @markup.heading.heading-6.gfm + + +; SECTIONS +; ======== + +(paragraph) @markup.paragraph.gfm +(thematic_break) @markup.horizontal-rule.gfm + +(block_quote) @markup.quote.blockquote.gfm +((block_quote_marker) @punctuation.definition.blockquote.gfm + (#set! adjust.startAndEndAroundFirstMatchOf "\\S")) + + +; LISTS +; ===== + +(list) @meta.list.gfm + +(list_item + (list_marker_dot) @punctuation.definition.list-item.gfm +) @markup.list.numbered + +(list_item + [ + (list_marker_star) + (list_marker_minus) + (list_marker_plus) + ] @punctuation.definition.list-item.gfm +) @markup.list.unnumbered + +(task_list_marker_unchecked) @punctuation.definition.task-marker.unchecked.gfm +(task_list_marker_checked) @punctuation.definition.task-marker.unchecked.gfm + +; CODE BLOCKS +; =========== + +(info_string) @storage.modifier.language._TEXT_.gfm + +(fenced_code_block + (code_fence_content) @markup.raw.block.fenced.gfm) @meta.embedded.block.fenced-code.gfm +(indented_code_block) @markup.raw.block.indented.gfm @meta.embedded.block.indented-code.gfm + + +; MISC +; ==== + +(pipe_table) @markup.other.table.gfm +(pipe_table_header + (pipe_table_cell) @markup.other.table-cell.header.gfm) +(pipe_table_row + (pipe_table_cell) @markup.other.table-cell.data.gfm) +(pipe_table_delimiter_row + (pipe_table_delimiter_cell + (_) @punctuation.separator.table-row.gfm) +) + + +; Link definitions + +(link_reference_definition + (link_label) + (link_destination) @markup.underline.link.gfm) + +((link_label) @meta.link.text + (#set! adjust.offsetStart 1) + (#set! adjust.offsetEnd -1)) diff --git a/packages/language-gfm/grammars/tree-sitter-markdown/tags.scm b/packages/language-gfm/grammars/tree-sitter-markdown/tags.scm new file mode 100644 index 0000000000..afe13abefa --- /dev/null +++ b/packages/language-gfm/grammars/tree-sitter-markdown/tags.scm @@ -0,0 +1,52 @@ + +; Each heading counts as a tag for symbol navigation purposes. We'll indicate a +; symbol's heading level with a certain number of dots prepended to the symbol +; name. + +((atx_heading + (atx_h1_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "· ")) + +((atx_heading + (atx_h2_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "·· ")) + +((atx_heading + (atx_h3_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "··· ")) + +((atx_heading + (atx_h4_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "···· ")) + +((atx_heading + (atx_h5_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "····· ")) + +((atx_heading + (atx_h6_marker) + heading_content: (_) @name) @definition.heading + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "······ ")) + +((setext_heading + heading_content: (_) @name) @definition.heading + (setext_h1_underline) + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "· ")) + +((setext_heading + heading_content: (_) @name) @definition.heading + (setext_h2_underline) + (#set! symbol.strip "(^\\s*|\\s*$)") + (#set! symbol.prepend "·· ")) diff --git a/packages/language-gfm/grammars/tree-sitter-markdown/tree-sitter-markdown.wasm b/packages/language-gfm/grammars/tree-sitter-markdown/tree-sitter-markdown.wasm new file mode 100755 index 0000000000..e248b73355 Binary files /dev/null and b/packages/language-gfm/grammars/tree-sitter-markdown/tree-sitter-markdown.wasm differ diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter.wasm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter.wasm deleted file mode 100755 index c8d0a8e37d..0000000000 Binary files a/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter.wasm and /dev/null differ diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter/highlights.scm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter/highlights.scm deleted file mode 100644 index a3f37189c2..0000000000 --- a/packages/language-gfm/grammars/tree-sitter/tree-sitter-frontmatter/highlights.scm +++ /dev/null @@ -1 +0,0 @@ -(front_matter) @meta.embedded.block.front-matter.gfm diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown.wasm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown.wasm deleted file mode 100755 index 872e944ed5..0000000000 Binary files a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown.wasm and /dev/null differ diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/folds.scm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/folds.scm deleted file mode 100644 index e52dd7fc1f..0000000000 --- a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/folds.scm +++ /dev/null @@ -1,22 +0,0 @@ -; TODO: Folds in Markdown files will have to wait until we can add "tags" to -; divided folds. We want an H1 section to be able to fold up everything until -; the next H1 in the file, an H2 to fold up everything until the next H2 _or_ -; H1, an H3 to fold up everything until the next H3 _or_ H2 _or_ H1… but this -; is not currently possible. - -; (atx_heading (atx_h1_marker)) @fold.start.h1 @fold.end.h1 @fold.end.h2 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6 -; -; (atx_heading (atx_h2_marker)) @fold.start.h2 @fold.end.h2 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6 -; -; (atx_heading (atx_h3_marker)) @fold.start.h3 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6 -; -; (atx_heading (atx_h4_marker)) @fold.start.h4 @fold.end.h4 @fold.end.h5 @fold.end.h6 -; -; (atx_heading (atx_h5_marker)) @fold.start.h5 @fold.end.h5 @fold.end.h6 -; -; (atx_heading (atx_h6_marker)) @fold.start.h6 @fold.end.h6 -; -; ; [(atx_heading) (setext_heading)] @fold.end @fold.start - -((list_item) @fold - (#set! fold.endAt endPosition)) diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/highlights.scm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/highlights.scm deleted file mode 100644 index 42e12ebe69..0000000000 --- a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/highlights.scm +++ /dev/null @@ -1,188 +0,0 @@ -; HEADINGS -; ======== - -(setext_heading - (heading_content) @markup.heading.heading-1.gfm - (setext_h1_underline) @punctuation.definition.heading-underline.gfm) - -(setext_heading - (heading_content) @markup.heading.heading-2.gfm - (setext_h2_underline) @punctuation.definition.heading-underline.gfm) - -(atx_heading - (atx_h1_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-1.gfm - -(atx_heading - (atx_h2_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-2.gfm - -(atx_heading - (atx_h3_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-3.gfm - -(atx_heading - (atx_h4_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-4.gfm - -(atx_heading - (atx_h5_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-5.gfm - -(atx_heading - (atx_h6_marker) @punctuation.definition.heading.gfm - ) @markup.heading.heading-6.gfm - - -; SECTIONS -; ======== - -(paragraph) @markup.paragraph.gfm - -(thematic_break) @markup.horizontal-rule.gfm - -(block_quote) @markup.quote.blockquote.gfm -((block_quote) @punctuation.definition.blockquote.gfm - (#set! adjust.endAfterFirstMatchOf ">")) - - -; LISTS -; ===== - -; `markup.list` gets applied to individual list items, unintuitively. So let's -; scope the entire list. “Tight” vs “Loose” has to do with whether each `
  • ` -; has one or more implicit `

    ` tags around it. - -[(tight_list) (loose_list)] @meta.list.gfm - -((list_item - (list_marker) @punctuation.definition.list-item.gfm) @markup.list.unnumbered - ; Instead of matching bullet or minus or plus, any not-digit here is - ; guaranteed to be an unordered list. - (#not-match? @punctuation.definition.list-item.gfm "^\\d")) - -((list_item - (list_marker) @punctuation.definition.list-item.gfm) @markup.list.numbered - (#match? @punctuation.definition.list-item.gfm "^\\d")) - -((task_list_item - (list_marker) @punctuation.definition.list-item.gfm) @markup.list.unnumbered - ; Instead of matching bullet or minus or plus, any not-digit here is - ; guaranteed to be an unordered list. - (#not-match? @punctuation.definition.list-item.gfm "^\\d")) - -((task_list_item - (list_marker) @punctuation.definition.list-item.gfm) @markup.list.numbered - (#match? @punctuation.definition.list-item.gfm "^\\d")) - - -; INLINE/REPLACED -; =============== - -; The text inside []s in anchors/image syntax. -[(link_text) (image_description)] @string.unquoted.gfm @meta.link.text - -(link_label (text) @meta.link.text) - -; A URL between ()s in anchor syntax. -(link_destination) @markup.underline.link.gfm -((link) @punctuation.definition.begin.link.bracket.round.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "(?<=\\])\\(")) -((link) @punctuation.definition.end.link.bracket.round.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "\\)$")) - -((link) @punctuation.definition.begin.link.bracket.square.gfm - (#set! adjust.endAfterFirstMatchOf "^\\[")) -((link) @punctuation.definition.end.link.bracket.square.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "\\](?=\\(|\\[)")) -((link_reference_definition) @punctuation.definition.begin.link.bracket.square.gfm - (#set! adjust.endAfterFirstMatchOf "^\\[")) -((link_reference_definition) @punctuation.definition.end.link.bracket.square.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "\\](?=\\(|\\[)")) -((link_reference_definition) @punctuation.separator.link.colon.gfm - (#set! adjust.startAndEndAroundFirstMatchOf ":")) - -; A URL between <>s in autolink syntax. -(uri_autolink (text) @markup.underline.link.gfm) -((uri_autolink) @punctuation.definition.link.begin.bracket.angle.gfm - (#set! adjust.endAfterFirstMatchOf "^<")) -((uri_autolink) @punctuation.definition.link.end.bracket.angle.gfm - (#set! adjust.startBeforeFirstMatchOf ">$")) - -; A link title: `[foo](http://example.com "Example web site")` -((link_title) @string.quoted.double.link-title.gfm - (#match? @string.quoted.double.link-title.gfm "^\"") - (#set! capture.final true)) - -((link_title) @punctuation.definition.string.begin.gfm - (#match? @punctuation.definition.string.begin.gfm "^\"") - (#set! adjust.endAfterFirstMatchOf "^\"")) - -((link_title) @punctuation.definition.string.end.gfm - (#match? @punctuation.definition.string.end.gfm "\"$") - (#set! adjust.startBeforeFirstMatchOf "\"$")) - -; Out of laziness, let's throw all other kinds of link title into the generic -; bin — they are all delimited _somehow_, right? -(link_title) @string.quoted.link-title.gfm - -; Link labels in `[foo][bar]` syntax, where `bar` is associated with a URL via -; a subsequent footnote, actually work correctly when one runs "Link: Open" in -; Pulsar, so these should be treated like links. -(link_label) @markup.underline.link.link-label.gfm - -(image) @meta.image.gfm - - -; CODE BLOCKS -; =========== - -(code_span) @meta.embedded.line.inline-code.gfm @markup.raw.inline.gfm -(info_string) @storage.modifier.language._TEXT_.gfm - -(fenced_code_block - (code_fence_content) @markup.raw.block.fenced.gfm) @meta.embedded.block.fenced-code.gfm -(indented_code_block) @markup.raw.block.indented.gfm @meta.embedded.block.indented-code.gfm - - -; BOLD/ITALIC/OTHER -; ================= - -(emphasis) @markup.italic.gfm -(strong_emphasis) @markup.bold.gfm -(strikethrough) @markup.strike.gfm - -((emphasis) @punctuation.delimiter.emphasis.begin.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "^(\\*|_)")) - -((emphasis) @punctuation.delimiter.emphasis.end.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "(\\*|_)$")) - -((strong_emphasis) @punctuation.delimiter.emphasis.begin.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "^(\\*{2}|_{2})")) - -((strong_emphasis) @punctuation.delimiter.emphasis.end.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "(\\*{2}|_{2})$")) - -((strikethrough) @punctuation.delimiter.strike.begin.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "^~~")) - -((strikethrough) @punctuation.delimiter.strike.begin.gfm - (#set! adjust.startAndEndAroundFirstMatchOf "~~$")) - -; HTML -; ==== - -(html_comment) @comment.block.html - -; MISC -; ==== - -(table) @markup.other.table.gfm -(table_header_row (table_cell) @markup.other.table-cell.header.gfm) -(table_data_row (table_cell) @markup.other.table-cell.data.gfm) - -(table_delimiter_row (table_column_alignment) @punctuation.separator.table-row.gfm) - - -(backslash_escape) @constant.character.escape.gfm diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/indents.scm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/indents.scm deleted file mode 100644 index 8aece2f967..0000000000 --- a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/indents.scm +++ /dev/null @@ -1,3 +0,0 @@ -; Intentionally empty indents.scm. By and large, indentation level should be -; manually controlled by the user in Markdown; the best thing we can do is stay -; out of the user's way. diff --git a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/tags.scm b/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/tags.scm deleted file mode 100644 index b776687599..0000000000 --- a/packages/language-gfm/grammars/tree-sitter/tree-sitter-markdown/tags.scm +++ /dev/null @@ -1,56 +0,0 @@ - -((atx_heading - (atx_h1_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "· ") - (#set! symbol.icon "chevron-right")) - -((atx_heading - (atx_h2_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "·· ") - (#set! symbol.icon "chevron-right")) - -((atx_heading - (atx_h3_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "··· ") - (#set! symbol.icon "chevron-right")) - -((atx_heading - (atx_h4_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "···· ") - (#set! symbol.icon "chevron-right")) - -((atx_heading - (atx_h5_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "····· ") - (#set! symbol.icon "chevron-right")) - -((atx_heading - (atx_h6_marker) - (heading_content) @name) @definition.heading - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "······ ") - (#set! symbol.icon "chevron-right")) - -((setext_heading - (heading_content) @name) @definition.heading - (setext_h1_underline) - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "· ") - (#set! symbol.icon "chevron-right")) - -((setext_heading - (heading_content) @name) @definition.heading - (setext_h2_underline) - (#set! symbol.strip "(^\\s*|\\s*$)") - (#set! symbol.prepend "·· ") - (#set! symbol.icon "chevron-right")) diff --git a/packages/language-gfm/lib/main.js b/packages/language-gfm/lib/main.js index d4c62e1b43..f85b2f4cd5 100644 --- a/packages/language-gfm/lib/main.js +++ b/packages/language-gfm/lib/main.js @@ -1,127 +1,74 @@ exports.activate = () => { - - // The top-level tree-sitter parser for `source.gfm` simply divides the text - // into front matter (if it exists) and the remainder, which is directly - // parsed as Markdown. + // Injection for YAML front matter. // - // We do this because the `ikatyang/tree-sitter-markdown` parser does not - // recognize YAML front matter, but is otherwise a very strong Markdown - // parser. If the `MDeiml/tree-sitter-markdown` parser became more stable, - // we could consider switching, and then we wouldn't need this extra parser. - - // Hand off the front matter to the YAML injection. + // TODO: If people want fancy front matter support, like the ability to + // control the front matter description language, then we might try to employ + // the technique we used for the last Markdown parser and use + // `tree-sitter-frontmatter` as the outermost grammar. atom.grammars.addInjectionPoint('source.gfm', { - type: 'front_matter', + type: 'minus_metadata', language: () => 'yaml', - content(node) { - return node.descendantsOfType('text'); - } + content: (node) => node }); - // Hand off everything else to the Markdown injection. + // This is a two-phase parser. The outer parser handles block-level content; + // the inner parser handles inline content. atom.grammars.addInjectionPoint('source.gfm', { - type: 'remainder', - language: () => 'markdown', + type: 'inline', + language: () => { + return 'markdown-inline-internal'; + }, content: (node) => node, + includeChildren: true, languageScope: null }); - // The markdown injection has a scope name of `source.gfm.embedded` so we can - // target it for the rest of these injections, but you can see above that we - // suppress that scope name when we inject it into a document. - - // Highlight HTML blocks. - atom.grammars.addInjectionPoint('source.gfm.embedded', { - type: 'html_block', + // Create one HTML injection layer for all block-level HTML nodes. + atom.grammars.addInjectionPoint('source.gfm', { + type: 'document', language: () => 'html', - content: (node) => node, + content(node) { + return node.descendantsOfType('html_block'); + }, includeChildren: true }); - for (let nodeType of ['paragraph', 'table_cell']) { - atom.grammars.addInjectionPoint('source.gfm.embedded', { - type: nodeType, - language(node) { - let html = node.descendantsOfType([ - 'html_open_tag', - 'html_close_tag', - 'html_self_closing_tag' - ]); - if (html.length === 0) { return null; } - return 'html'; - }, - - content(node) { - let html = node.descendantsOfType([ - 'html_open_tag', - 'html_close_tag', - 'html_self_closing_tag' - ]); - return html; - }, - - includeChildren: true - }); - } - - // All code blocks of the form - // - // ```foo - // (code goes here) - // ``` - // - // get injections on the theory that some grammar's `injectionRegex` will - // match `foo`. - atom.grammars.addInjectionPoint('source.gfm.embedded', { + // Injections for code blocks. + atom.grammars.addInjectionPoint('source.gfm', { type: 'fenced_code_block', language(node) { - let language = node?.firstNamedChild; - if (language?.type === 'info_string') - return language.text; - - return null; + let infoString = node.descendantsOfType('language'); + if (infoString.length === 0) return undefined; + return infoString[0]?.text; }, content(node) { - return node.descendantsOfType('code_fence_content'); + let codeFenceContent = node.descendantsOfType('code_fence_content'); + if (codeFenceContent.length === 0) return undefined; + return codeFenceContent[0]; }, - languageScope: (grammar) => `${grammar.scopeName}.embedded`, includeChildren: true }); -}; - - -// Since this parser isn't guaranteed to detect all URLs in paragraphs (see -// https://github.com/pulsar-edit/pulsar/issues/885), we'll inject the -// `hyperlink` parser into `text` nodes in paragraphs when there appear to be -// URLs in them. -exports.consumeHyperlinkInjection = (hyperlink) => { - - function textChildren(node) { - let results = []; - for (let i = 0; i < node.namedChildCount; i++) { - let child = node.child(i); - if (child.type === 'text') { - results.push(child); - } - } - return results; - } - hyperlink.addInjectionPoint('source.gfm.embedded', { - types: ['paragraph'], - // Override the language callback so that it doesn't test URLs that are - // already handled in `uri_autolink` nodes. + // Another HTML injection for each inline node that covers inline HTML. + atom.grammars.addInjectionPoint('source.gfm.inline', { + type: 'inline', language(node) { - for (let child of textChildren(node)) { - if (hyperlink.test(child)) { - return 'hyperlink'; - } - } - return null; + // Attempt to cut down on the number of injection layers by returning + // `html` here only when there are HTML nodes in the inline tree. + let html = node.descendantsOfType('html_tag'); + return html.length > 0 ? 'html' : undefined; }, content(node) { - return textChildren(node); - } + return node.descendantsOfType('html_tag'); + }, + includeChildren: true }); +}; +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.gfm.inline', { + types: ['inline'], + content: (node) => node, + includeChildren: true + }); }; diff --git a/packages/language-hyperlink/lib/main.js b/packages/language-hyperlink/lib/main.js index 16223af3a5..32cb002abd 100644 --- a/packages/language-hyperlink/lib/main.js +++ b/packages/language-hyperlink/lib/main.js @@ -49,7 +49,8 @@ module.exports = { content(node) { return options.content ? options.content(node) : node; }, - languageScope: null + languageScope: options.languageScope ?? null, + includeChildren: options.includeChildren ?? false }); } }, diff --git a/packages/language-javascript/grammars/tree-sitter/highlights.scm b/packages/language-javascript/grammars/tree-sitter/highlights.scm index 22e14f96cd..3fa44df58c 100644 --- a/packages/language-javascript/grammars/tree-sitter/highlights.scm +++ b/packages/language-javascript/grammars/tree-sitter/highlights.scm @@ -573,15 +573,27 @@ (export_statement (identifier) @variable.other.assignment.export.js) -; The "*" in `import * as Foo` +; The "*" in `import * as Foo from 'bar'` (import_clause (namespace_import "*" @variable.other.assignment.import.all.js)) -; The "Foo" in `import * as Foo` +; The "Foo" in `import * as Foo from 'bar'` (import_clause (namespace_import (identifier) @variable.other.assignment.import.alias.js)) +; The "*" in `export * from 'bar'` +(export_statement "*" @variable.other.assignment.export.all.js) + +; The "*" in `export * as Foo from 'bar'` +(export_statement + (namespace_export "*" @variable.other.assignment.export.all.js)) + +; The "*" in `export * as Foo from 'bar'` +(export_statement + (namespace_export + (identifier) @variable.other.assignment.export.alias.js)) + ; COMMENTS ; ======== diff --git a/packages/language-python/grammars/ts/highlights.scm b/packages/language-python/grammars/ts/highlights.scm index 03e8db4840..0e1c7a5ec1 100644 --- a/packages/language-python/grammars/ts/highlights.scm +++ b/packages/language-python/grammars/ts/highlights.scm @@ -37,13 +37,13 @@ (call function: (identifier) @support.type.constructor.python - (#match? @support.type.constructor.python "^[A-Z][a-z_]+") + (#match? @support.type.constructor.python "^[A-Z][A-Za-z_]+") (#set! capture.final true)) (call function: (attribute attribute: (identifier) @support.type.constructor.python) - (#match? @support.type.constructor.python "^[A-Z][a-z_]+") + (#match? @support.type.constructor.python "^[A-Z][A-Za-z_]+") (#set! capture.final true)) (call diff --git a/packages/language-python/grammars/ts/indents.scm b/packages/language-python/grammars/ts/indents.scm index 670948ed16..9753893079 100644 --- a/packages/language-python/grammars/ts/indents.scm +++ b/packages/language-python/grammars/ts/indents.scm @@ -1,10 +1,16 @@ +; Excluding dictionary key/value separators… (dictionary (pair ":" @_IGNORE_ - (#set! capture.final true))) + (#set! capture.final))) +; …lambda functions… ((lambda ":" @_IGNORE_) - (#set! capture.final true)) + (#set! capture.final)) +; …and type annotations on function parameters/class members… +(":" @_IGNORE_ . (type) (#set! capture.final)) + +; …all other colons we encounter hint at upcoming indents. ":" @indent ; When typing out "else" after an "if" statement, tree-sitter-python won't diff --git a/packages/language-shellscript/grammars/modern-tree-sitter-bash.cson b/packages/language-shellscript/grammars/modern-tree-sitter-bash.cson index d82927921a..bec61a5fe4 100644 --- a/packages/language-shellscript/grammars/modern-tree-sitter-bash.cson +++ b/packages/language-shellscript/grammars/modern-tree-sitter-bash.cson @@ -38,7 +38,7 @@ firstLineRegex: [ # Try to match `bash` exactly, or failing that, anything that ends in `sh` # (for zsh/fish/etc.). -injectionRegex: '(^(bash|BASH)$|sh^|SH^)' +injectionRegex: '(^(bash|BASH)$|sh$|SH$)' treeSitter: parserSource: 'github:tree-sitter/tree-sitter-bash#8df9ea875d557a150d025d3a15b6e6a58624379a' diff --git a/packages/language-typescript/grammars/common/highlights.scm b/packages/language-typescript/grammars/common/highlights.scm index f34c12e50e..5b9d7cf535 100644 --- a/packages/language-typescript/grammars/common/highlights.scm +++ b/packages/language-typescript/grammars/common/highlights.scm @@ -17,6 +17,18 @@ (namespace_import (identifier) @variable.other.assignment.import.namespace._LANG_) +; The "*" in `export * from 'bar'` +(export_statement "*" @variable.other.assignment.export.all.js) + +; The "*" in `export * as Foo from 'bar'` +(export_statement + (namespace_export "*" @variable.other.assignment.export.all.js)) + +; The "*" in `export * as Foo from 'bar'` +(export_statement + (namespace_export + (identifier) @variable.other.assignment.export.alias.js)) + ; The "Foo" in `export { Foo }` (export_specifier name: (identifier) @variable.other.assignment.export._LANG_) @@ -395,9 +407,17 @@ ; TODO: We could add a special scope name to the entire suite of DOM types, but ; I don't have the strength for that right now. -; -((type_identifier) @support.storage.other.type._LANG_ - ) +; The "bar" in `const foo: bar.Baz`. +(nested_type_identifier + module: (identifier) @support.storage.other.property._LANG_) + +; The "bar" and "thud" in `const foo: bar.thud.Baz`. +(nested_identifier + (identifier) @support.storage.other.property._LANG_ + (#is? test.descendantOfType "type_annotation")) + +; Any other type identifiers; the "Bar" in `const foo: Bar`. +(type_identifier) @support.storage.other.type._LANG_ ; SUPPORT ; ======= @@ -739,8 +759,8 @@ ; Interpolations inside of template strings. (template_substitution - "${" @punctuation.definition.template-expression.begin._LANG_ - "}" @punctuation.definition.template-expression.end._LANG_ + "${" @punctuation.section.embedded.begin._LANG_ + "}" @punctuation.section.embedded.end._LANG_ ) @meta.embedded.line.interpolation._LANG_ (string @@ -793,6 +813,22 @@ "debugger" ] @keyword.control._TYPE_._LANG_ + +; REGEX +; ===== + +(regex) @string.regexp.js +(regex + "/" @punctuation.definition.string.begin.js + (#is? test.first)) + +(regex + "/" @punctuation.definition.string.end.js + (#is? test.last)) + +(regex_flags) @keyword.other.js + + ; OPERATORS ; ========= @@ -925,6 +961,10 @@ ; All other sorts of blocks. (statement_block) @meta.block._LANG_ +; The entirety of a type annotation, no matter how simple or complex (e.g., +; `Event`, `foo.Event`, `foo.bar.Event, foo.Event`). +(type_annotation (_) @meta.type.annotation._LANG_) + ; The inside of a parameter definition list. ((formal_parameters) @meta.parameters._LANG_ (#set! adjust.startAt firstChild.endPosition) diff --git a/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm b/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm index c3a11ab01c..b973578d0d 100644 --- a/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm +++ b/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm @@ -28,18 +28,25 @@ (property_identifier) @entity.other.attribute-name.ts.tsx) ; The empty tag used as a shorthand for a fragment: `<>`. -(jsx_fragment) @meta.tag.ts.tsx +((jsx_fragment) @meta.tag.fragment.ts.tsx + (#set! adjust.endAfterFirstMatchOf "^<>")) + +; The closing fragment tag: ``. +((jsx_fragment) @meta.tag.fragment.ts.tsx + (#set! adjust.startBeforeFirstMatchOf "$")) + +; (jsx_fragment) ; The slashes in closing tags should not be interpreted as math operators. (jsx_self_closing_element "/" @punctuation.definition.tag.end.ts.tsx - (#set! capture.final true)) + (#set! capture.final)) (jsx_closing_element "/" @punctuation.definition.tag.end.ts.tsx - (#set! capture.final true)) + (#set! capture.final)) ; All JSX expressions/interpolations within braces. ((jsx_expression) @meta.embedded.block.ts.tsx (#match? @meta.embedded.block.ts.tsx "\\n") - (#set! capture.final true)) + (#set! capture.final)) (jsx_expression) @meta.embedded.line.ts.tsx @@ -55,9 +62,13 @@ "<" @punctuation.definition.tag.begin.ts.tsx ">" @punctuation.definition.tag.end.ts.tsx) +(jsx_fragment + "/" @punctuation.definition.tag.end.ts.tsx + (#set! capture.final)) + (jsx_self_closing_element "<" @punctuation.definition.tag.begin.ts.tsx - (#set! capture.final true)) + (#set! capture.final)) ((jsx_self_closing_element ; The "/>" in ``, extended to cover both anonymous nodes at once. diff --git a/src/wasm-tree-sitter-grammar.js b/src/wasm-tree-sitter-grammar.js index bed2fe8a6e..076be66612 100644 --- a/src/wasm-tree-sitter-grammar.js +++ b/src/wasm-tree-sitter-grammar.js @@ -367,12 +367,10 @@ module.exports = class WASMTreeSitterGrammar { return this.emitter.on('did-change-query-file', callback); } - // TODO: Why is this here? activate() { this.registration = this.registry.addGrammar(this); } - // TODO: Why is this here? deactivate() { this.registration?.dispose(); this.subscriptions?.dispose();