mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-11 11:15:24 +03:00
Merge pull request #859 from savetheclocktower/tree-sitter-january
Tree-sitter rolling fixes (January edition)
This commit is contained in:
commit
2dbd99582e
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
*.ts
|
@ -19,6 +19,12 @@ module.exports = {
|
||||
asyncArrow: "always",
|
||||
named: "never"
|
||||
}],
|
||||
"node/no-missing-require": [
|
||||
"error",
|
||||
{
|
||||
allowModules: ["atom"]
|
||||
}
|
||||
],
|
||||
"node/no-unpublished-require": [
|
||||
"error",
|
||||
{
|
||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -208,7 +208,8 @@ jobs:
|
||||
node ./rolling-release-binary-upload.js
|
||||
|
||||
- name: Upload Video Artifacts
|
||||
if: runner.os != 'Linux'
|
||||
# Run whether this job passed or failed, unless explicitly cancelled.
|
||||
if: ${{ !cancelled() && runner.os != 'Linux' }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }} Videos
|
||||
@ -267,7 +268,8 @@ jobs:
|
||||
node ./rolling-release-binary-upload.js
|
||||
|
||||
- name: Upload Video Artifacts - Linux
|
||||
if: runner.os == 'Linux'
|
||||
# Run whether this job passed or failed, unless explicitly cancelled.
|
||||
if: ${{ !cancelled() && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }} Videos
|
||||
|
@ -23,7 +23,7 @@ const languages = [
|
||||
// {language: "mustache", code: '10', checks: {numeric: '10'}},
|
||||
{language: "Objective C", code: '10', checks: {numeric: '10'}},
|
||||
{language: "Perl", code: '10', checks: {numeric: '10'}},
|
||||
{language: "PHP", code: '<? 10 %>', checks: {numeric: '10'}},
|
||||
{language: "PHP", code: '<? $foo ?>', checks: {variable: '$foo'}},
|
||||
// {language: "property-list", code: '10', checks: {numeric: '10'}},
|
||||
{language: "Python", code: '10', checks: {numeric: '10'}},
|
||||
{language: "Ruby on Rails", code: '10', checks: {numeric: '10'}},
|
||||
|
@ -9,3 +9,4 @@
|
||||
@import "styles/syntax/base.less";
|
||||
@import "styles/syntax/css.less";
|
||||
@import "styles/syntax/html.less";
|
||||
@import "styles/syntax/json.less";
|
||||
|
@ -229,6 +229,12 @@
|
||||
&.syntax--italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// Horizontal rules in GFM used to be scoped as `comment.hr`. For continuity,
|
||||
// we assign the color of a comment to this new scope.
|
||||
&.syntax--horizontal-rule {
|
||||
color: #8A8A8A;
|
||||
}
|
||||
}
|
||||
|
||||
// /* comment */
|
||||
|
11
packages/atom-dark-syntax/styles/syntax/json.less
Normal file
11
packages/atom-dark-syntax/styles/syntax/json.less
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
.syntax--source.syntax--json {
|
||||
|
||||
// Color JSON keys differently from other strings.
|
||||
.syntax--meta.syntax--structure.syntax--key {
|
||||
.syntax--string.syntax--quoted.syntax--double {
|
||||
color: #96CBFE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,3 +8,4 @@
|
||||
|
||||
@import "styles/syntax/base.less";
|
||||
@import "styles/syntax/css.less";
|
||||
@import "styles/syntax/json.less";
|
||||
|
@ -198,6 +198,12 @@
|
||||
&.syntax--italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// Horizontal rules in GFM used to be scoped as `comment.hr`. For continuity,
|
||||
// we assign the color of a comment to this new scope.
|
||||
&.syntax--horizontal-rule {
|
||||
color: #999988;
|
||||
}
|
||||
}
|
||||
|
||||
// /* comment */
|
||||
|
11
packages/atom-light-syntax/styles/syntax/json.less
Normal file
11
packages/atom-light-syntax/styles/syntax/json.less
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
.syntax--source.syntax--json {
|
||||
|
||||
// Color JSON keys differently from other strings.
|
||||
.syntax--meta.syntax--structure.syntax--key {
|
||||
.syntax--string.syntax--quoted.syntax--double {
|
||||
color: #008080;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -267,6 +267,12 @@
|
||||
&.syntax--raw {
|
||||
color: @green;
|
||||
}
|
||||
|
||||
// Horizontal rules in GFM used to be scoped as `comment.hr`. For continuity,
|
||||
// we assign the color of a comment to this new scope.
|
||||
&.syntax--horizontal-rule {
|
||||
color: @gray;
|
||||
}
|
||||
}
|
||||
|
||||
.syntax--source.syntax--gfm {
|
||||
|
@ -8,6 +8,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Color JSON keys differently from other strings.
|
||||
.syntax--meta.syntax--structure.syntax--key {
|
||||
.syntax--string.syntax--quoted.syntax--double {
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
.syntax--meta.syntax--structure.syntax--dictionary.syntax--json, .syntax--meta.syntax--structure.syntax--array.syntax--json {
|
||||
& > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json,
|
||||
& > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json > .syntax--punctuation {
|
||||
|
@ -267,6 +267,12 @@
|
||||
&.syntax--raw {
|
||||
color: @green;
|
||||
}
|
||||
|
||||
// Horizontal rules in GFM used to be scoped as `comment.hr`. For continuity,
|
||||
// we assign the color of a comment to this new scope.
|
||||
&.syntax--horizontal-rule {
|
||||
color: @gray;
|
||||
}
|
||||
}
|
||||
|
||||
.syntax--source.syntax--gfm {
|
||||
|
@ -8,6 +8,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Color JSON keys differently from other strings.
|
||||
.syntax--meta.syntax--structure.syntax--key {
|
||||
.syntax--string.syntax--quoted.syntax--double {
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
.syntax--meta.syntax--structure.syntax--dictionary.syntax--json, .syntax--meta.syntax--structure.syntax--array.syntax--json {
|
||||
& > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json,
|
||||
& > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json > .syntax--punctuation {
|
||||
|
12
packages/bracket-matcher/spec/.eslintrc.js
Normal file
12
packages/bracket-matcher/spec/.eslintrc.js
Normal file
@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
env: { jasmine: true },
|
||||
globals: {
|
||||
waitsForPromise: true,
|
||||
},
|
||||
rules: {
|
||||
"node/no-unpublished-require": "off",
|
||||
"node/no-extraneous-require": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-empty": "off"
|
||||
}
|
||||
};
|
@ -7,6 +7,7 @@ firstLineRegex: '-\\*-[^*]*(Mode:\\s*)?C(\\s*;.*?)?\\s*-\\*-'
|
||||
injectionRegex: '^(c|C)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-c#212a80f86452bb1316324fa0db730cf52f29e05a'
|
||||
grammar: 'tree-sitter-c/tree-sitter-c.wasm'
|
||||
highlightsQuery: 'tree-sitter-c/highlights.scm'
|
||||
tagsQuery: 'tree-sitter-c/tags.scm'
|
||||
|
@ -6,7 +6,7 @@ parser: 'tree-sitter-cpp'
|
||||
injectionRegex: '^(c|C)(\\+\\+|pp|PP)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-cpp#a90f170f92d5d70e7c2d4183c146e61ba5f3a457'
|
||||
parserSource: 'github:tree-sitter/tree-sitter-cpp#a71474021410973b29bfe99440d57bcd750246b1'
|
||||
grammar: 'tree-sitter-cpp/tree-sitter-cpp.wasm'
|
||||
highlightsQuery: 'tree-sitter-cpp/highlights.scm'
|
||||
tagsQuery: 'tree-sitter-cpp/tags.scm'
|
||||
|
@ -13,6 +13,10 @@
|
||||
"#define" @keyword.control.directive.define.c
|
||||
"#include" @keyword.control.directive.include.c
|
||||
|
||||
(["#if" "#ifdef" "#ifndef" "#endif" "#elif" "#else" "#define" "#include"] @punctuation.definition.directive.c
|
||||
(#set! adjust.endAfterFirstMatchOf "^#"))
|
||||
|
||||
|
||||
; This will match if the more specific rules above haven't matched. The
|
||||
; anonymous nodes will match under ideal conditions, but might not be present
|
||||
; if the parser is flummoxed.
|
||||
@ -43,30 +47,41 @@
|
||||
(type_identifier) @_IGNORE_
|
||||
(#set! capture.final true))
|
||||
|
||||
(primitive_type) @support.type.builtin.c
|
||||
(type_identifier) @support.type.other.c
|
||||
(primitive_type) @support.storage.type.builtin.c
|
||||
(type_identifier) @support.other.storage.type.c
|
||||
|
||||
; These types are all reserved words; if we see an identifier with this name,
|
||||
; it must be a type.
|
||||
((identifier) @support.type.builtin.c
|
||||
(#match? @support.type.builtin.c "^(char|int|float|double|long)$"))
|
||||
((identifier) @support.storage.type.builtin.c
|
||||
(#match? @support.storage.type.builtin.c "^(char|int|float|double|long)$"))
|
||||
|
||||
; Assume any identifier that ends in `_t` is a type. This convention is not
|
||||
; always followed, but it's a very strong indicator when it's present.
|
||||
((identifier) @support.type.other.c
|
||||
(#match? @support.type.other.c "_t$"))
|
||||
((identifier) @support.other.storage.type.c
|
||||
(#match? @support.other.storage.type.c "_t$"))
|
||||
|
||||
; These refer to language constructs and remain in the `storage` namespace.
|
||||
[
|
||||
"enum"
|
||||
"long"
|
||||
"short"
|
||||
"signed"
|
||||
"struct"
|
||||
"typedef"
|
||||
"union"
|
||||
"unsigned"
|
||||
] @storage.type.c
|
||||
|
||||
; These refer to value types and go under `support`.
|
||||
[
|
||||
"long"
|
||||
"short"
|
||||
] @support.storage.type.builtin.c
|
||||
|
||||
; These act as modifiers to value types and also go under `support`.
|
||||
[
|
||||
"signed"
|
||||
"unsigned"
|
||||
] @support.storage.modifier.builtin.c
|
||||
|
||||
; These act as general language modifiers and remain in the `storage`
|
||||
; namespace.
|
||||
[
|
||||
"const"
|
||||
"extern"
|
||||
@ -75,10 +90,10 @@
|
||||
"restrict"
|
||||
"static"
|
||||
"volatile"
|
||||
] @storage.modifier.c
|
||||
] @storage.modifier._TYPE_.c
|
||||
|
||||
((primitive_type) @support.type.stdint.c
|
||||
(#match? @support.type.stdint.c "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$"))
|
||||
((primitive_type) @support.storage.type.stdint.c
|
||||
(#match? @support.storage.type.stdint.c "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$"))
|
||||
|
||||
(enum_specifier
|
||||
name: (type_identifier) @variable.other.declaration.type.c)
|
||||
@ -116,32 +131,57 @@
|
||||
; Declarations and assignments
|
||||
; ----------------------------
|
||||
|
||||
; The "x" in `int x`;
|
||||
; The "x" in `int x;`
|
||||
(declaration
|
||||
declarator: (identifier) @variable.declaration.c)
|
||||
|
||||
; The "x" in `int x = y`;
|
||||
; The "x" in `int x = y;`
|
||||
(init_declarator
|
||||
declarator: (identifier) @variable.declaration.c)
|
||||
|
||||
; The "x" in `SomeType *x;`
|
||||
; (Should work no matter how many pointers deep we are.)
|
||||
(pointer_declarator
|
||||
declarator: [(identifier) (field_identifier)] @variable.declaration.pointer.c
|
||||
(#is? test.descendantOfType "declaration field_declaration"))
|
||||
|
||||
; A member of a struct.
|
||||
(field_declaration
|
||||
(field_identifier) @entity.other.attribute-name.c)
|
||||
(field_identifier) @variable.declaration.member.c)
|
||||
|
||||
; An attribute in a C99 struct designated initializer:
|
||||
; the "foo" in `MY_TYPE a = { .foo = true };
|
||||
(initializer_pair
|
||||
(field_designator
|
||||
(field_identifier) @variable.declaration.member.c))
|
||||
|
||||
; (and the associated ".")
|
||||
(initializer_pair
|
||||
(field_designator
|
||||
"." @keyword.operator.accessor.c))
|
||||
|
||||
(field_declaration
|
||||
(pointer_declarator
|
||||
(field_identifier) @entity.other.attribute-name.c))
|
||||
(field_identifier) @variable.declaration.member.c))
|
||||
|
||||
(field_declaration
|
||||
(array_declarator
|
||||
(field_identifier) @entity.other.attribute-name.c))
|
||||
(field_identifier) @variable.declaration.member.c))
|
||||
|
||||
(init_declarator
|
||||
(pointer_declarator
|
||||
(identifier) @entity.other.attribute-name.c))
|
||||
(identifier) @variable.declaration.member.c))
|
||||
|
||||
; The "x" in `x = y;`
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.c)
|
||||
|
||||
; The "foo" in `something->foo = "bar";`
|
||||
(assignment_expression
|
||||
left: (field_expression
|
||||
field: (field_identifier) @variable.other.member.assignment.c)
|
||||
(#set! capture.final))
|
||||
|
||||
|
||||
; Function parameters
|
||||
; -------------------
|
||||
@ -154,9 +194,10 @@
|
||||
declarator: (identifier) @variable.parameter.c)
|
||||
|
||||
; The "foo" in `const char *foo` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (identifier) @variable.parameter.c))
|
||||
; (Should work no matter how many pointers deep we are.)
|
||||
(pointer_declarator
|
||||
declarator: [(identifier) (field_identifier)] @variable.parameter.pointer.c
|
||||
(#is? test.descendantOfType "parameter_declaration"))
|
||||
|
||||
; The "foo" in `const char foo[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
@ -172,7 +213,7 @@
|
||||
; The "size" in `finfo->size`.
|
||||
(field_expression
|
||||
"->"
|
||||
field: (field_identifier) @support.other.property.c)
|
||||
field: (field_identifier) @variable.other.member.c)
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
@ -309,8 +350,10 @@
|
||||
|
||||
";" @punctuation.terminator.statement.c
|
||||
|
||||
"," @punctuation.separator.comma.c
|
||||
"->" @punctuation.separator.pointer-access.c
|
||||
("," @punctuation.separator.comma.c
|
||||
(#set! capture.shy))
|
||||
("->" @keyword.operator.accessor.pointer-access.c
|
||||
(#set! capture.shy))
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.c
|
||||
@ -335,6 +378,22 @@
|
||||
"[" @punctuation.definition.array.begin.bracket.square.c
|
||||
"]" @punctuation.definition.array.end.bracket.square.c
|
||||
|
||||
|
||||
; META
|
||||
; ====
|
||||
|
||||
((compound_statement) @meta.block.c
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
((enumerator_list) @meta.block.enum.c
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
((field_declaration_list) @meta.block.field.c
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
; TODO:
|
||||
;
|
||||
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
|
||||
|
Binary file not shown.
@ -13,6 +13,10 @@
|
||||
"#define" @keyword.control.directive.define.cpp
|
||||
"#include" @keyword.control.directive.include.cpp
|
||||
|
||||
(["#if" "#ifdef" "#ifndef" "#endif" "#elif" "#else" "#define" "#include"] @punctuation.definition.directive.c
|
||||
(#set! adjust.endAfterFirstMatchOf "^#"))
|
||||
|
||||
|
||||
; This will match if the more specific rules above haven't matched. The
|
||||
; anonymous nodes will match under ideal conditions, but might not be present
|
||||
; if the parser is flummoxed.
|
||||
@ -69,28 +73,38 @@
|
||||
|
||||
; These types are all reserved words; if we see an identifier with this name,
|
||||
; it must be a type.
|
||||
((identifier) @support.type.builtin.cpp
|
||||
(#match? @support.type.builtin.cpp "^(char|int|float|double|long)$"))
|
||||
((identifier) @support.storage.type.builtin.cpp
|
||||
(#match? @support.storage.type.builtin.cpp "^(char|int|float|double|long)$"))
|
||||
|
||||
; Assume any identifier that ends in `_t` is a type. This convention is not
|
||||
; always followed, but it's a very strong indicator when it's present.
|
||||
((identifier) @support.type.other.cpp
|
||||
(#match? @support.type.other.cpp "_t$"))
|
||||
((identifier) @support.other.storage.type.cpp
|
||||
(#match? @support.other.storage.type.cpp "_t$"))
|
||||
|
||||
|
||||
; These refer to language constructs and remain in the `storage` namespace.
|
||||
[
|
||||
"enum"
|
||||
"long"
|
||||
"short"
|
||||
"signed"
|
||||
"struct"
|
||||
"typedef"
|
||||
"union"
|
||||
"unsigned"
|
||||
|
||||
"template"
|
||||
] @storage.type.cpp
|
||||
|
||||
; These refer to value types and go under `support`.
|
||||
[
|
||||
"long"
|
||||
"short"
|
||||
] @support.storage.type.builtin.cpp
|
||||
|
||||
; These act as modifiers to value types and also go under `support`.
|
||||
[
|
||||
"signed"
|
||||
"unsigned"
|
||||
] @support.storage.modifier.builtin.cpp
|
||||
|
||||
; These act as general language modifiers and remain in the `storage`
|
||||
; namespace.
|
||||
[
|
||||
"const"
|
||||
"extern"
|
||||
@ -110,15 +124,15 @@
|
||||
"override"
|
||||
"final"
|
||||
"noexcept"
|
||||
] @storage.modifier.cpp
|
||||
|
||||
"typename"
|
||||
] @storage.modifier._TYPE_.cpp
|
||||
|
||||
(
|
||||
(primitive_type) @support.type.stdint.cpp
|
||||
(#match? @support.type.stdint.cpp "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$")
|
||||
(primitive_type) @support.storage.type.stdint.cpp
|
||||
(#match? @support.storage.type.stdint.cpp "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$")
|
||||
)
|
||||
|
||||
"typename" @storage.modifier.typename.cpp
|
||||
|
||||
|
||||
; FUNCTIONS
|
||||
; =========
|
||||
@ -207,36 +221,56 @@
|
||||
; Declarations and assignments
|
||||
; ----------------------------
|
||||
|
||||
; The "x" in `int x`;
|
||||
; The "x" in `int x;`
|
||||
(declaration
|
||||
declarator: (identifier) @variable.declaration.cpp)
|
||||
|
||||
; The "x" in `int x = y`;
|
||||
; The "x" in `int x = y;`
|
||||
(init_declarator
|
||||
declarator: (identifier) @variable.declaration.cpp)
|
||||
|
||||
; The "x" in `SomeType *x;`
|
||||
; (Should work no matter how many pointers deep we are.)
|
||||
(pointer_declarator
|
||||
declarator: [(identifier) (field_identifier)] @variable.declaration.pointer.c
|
||||
(#is? test.descendantOfType "declaration field_declaration"))
|
||||
|
||||
; A member of a struct.
|
||||
(field_declaration
|
||||
(field_identifier) @variable.declaration.cpp)
|
||||
(field_identifier) @variable.declaration.member.cpp)
|
||||
|
||||
; An attribute in a C99 struct designated initializer:
|
||||
; the "foo" in `MY_TYPE a = { .foo = true };
|
||||
(initializer_pair
|
||||
(field_designator
|
||||
(field_identifier) @variable.declaration.member.cpp))
|
||||
|
||||
; (and the associated ".")
|
||||
(initializer_pair
|
||||
(field_designator
|
||||
"." @keyword.operator.accessor.cpp))
|
||||
|
||||
(field_declaration
|
||||
(pointer_declarator
|
||||
(field_identifier) @variable.declaration.cpp))
|
||||
(field_identifier) @variable.declaration.member.cpp))
|
||||
|
||||
(field_declaration
|
||||
(array_declarator
|
||||
(field_identifier) @variable.declaration.cpp))
|
||||
(field_identifier) @variable.declaration.member.cpp))
|
||||
|
||||
(init_declarator
|
||||
(pointer_declarator
|
||||
(identifier) @variable.declaration.cpp))
|
||||
(identifier) @variable.declaration.member.cpp))
|
||||
|
||||
; The "x" in `x = y;`
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.cpp)
|
||||
|
||||
; The "foo" in `bar.foo = "baz"`.
|
||||
; The "foo" in `something->foo = "bar";`
|
||||
(assignment_expression
|
||||
left: (field_expression
|
||||
field: (field_identifier) @variable.other.member.assignment.cpp))
|
||||
field: (field_identifier) @variable.other.member.assignment.cpp)
|
||||
(#set! capture.final))
|
||||
|
||||
((reference_declarator
|
||||
(identifier) @variable.declaration.cpp)
|
||||
@ -248,18 +282,20 @@
|
||||
(preproc_params
|
||||
(identifier) @variable.parameter.preprocessor.cpp)
|
||||
|
||||
; The "foo" in `const char foo` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (identifier) @variable.parameter.cpp)
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (pointer_declarator
|
||||
declarator: (identifier) @variable.parameter.cpp))
|
||||
; The "foo" in `const char *foo` within a parameter list.
|
||||
; (Should work no matter how many pointers deep we are.)
|
||||
(pointer_declarator
|
||||
declarator: [(identifier) (field_identifier)] @variable.parameter.pointer.c
|
||||
(#is? test.descendantOfType "parameter_declaration"))
|
||||
|
||||
(parameter_declaration
|
||||
declarator: (reference_declarator
|
||||
(identifier) @variable.parameter.cpp))
|
||||
|
||||
|
||||
; The "foo" in `const char foo[]` within a parameter list.
|
||||
(parameter_declaration
|
||||
declarator: (array_declarator
|
||||
@ -420,8 +456,10 @@
|
||||
|
||||
";" @punctuation.terminator.statement.cpp
|
||||
|
||||
"," @punctuation.separator.comma.cpp
|
||||
"->" @keyword.operator.accessor.cpp
|
||||
("," @punctuation.separator.comma.cpp
|
||||
(#set! capture.shy))
|
||||
("->" @keyword.operator.accessor.pointer-access.cpp
|
||||
(#set! capture.shy))
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.cpp
|
||||
@ -446,6 +484,22 @@
|
||||
"[" @punctuation.definition.array.begin.bracket.square.cpp
|
||||
"]" @punctuation.definition.array.end.bracket.square.cpp
|
||||
|
||||
; META
|
||||
; ====
|
||||
|
||||
((compound_statement) @meta.block.cpp
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
((enumerator_list) @meta.block.enum.cpp
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
((field_declaration_list) @meta.block.field.cpp
|
||||
(#set! adjust.startAt firstChild.endPosition)
|
||||
(#set! adjust.endAt lastChild.startPosition))
|
||||
|
||||
|
||||
; TODO:
|
||||
;
|
||||
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
|
||||
|
Binary file not shown.
@ -12,28 +12,19 @@ exports.activate = function () {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint(`source.${language}`, {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
for (let type of ['string_literal', 'comment']) {
|
||||
atom.grammars.addInjectionPoint(`source.${language}`, {
|
||||
type,
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
for (const language of ['c', 'cpp']) {
|
||||
hyperlink.addInjectionPoint(`source.${language}`, {
|
||||
types: ['comment', 'string_literal']
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
for (const language of ['c', 'cpp']) {
|
||||
todo.addInjectionPoint(`source.${language}`, { types: ['comment'] });
|
||||
}
|
||||
};
|
||||
|
@ -15,5 +15,17 @@
|
||||
"dependencies": {
|
||||
"tree-sitter-c": "0.20.2",
|
||||
"tree-sitter-cpp": "0.20.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ fileTypes: [
|
||||
]
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-css#98c7b3dceb24f1ee17f1322f3947e55638251c37'
|
||||
grammar: 'tree-sitter/tree-sitter-css.wasm'
|
||||
highlightsQuery: 'tree-sitter/queries/highlights.scm'
|
||||
foldsQuery: 'tree-sitter/queries/folds.scm'
|
||||
|
@ -1,36 +1,36 @@
|
||||
|
||||
; WORKAROUND:
|
||||
|
||||
; NOTE: `tree-sitter-css` recovers poorly from invalidity inside a block when
|
||||
; you're adding a new property-value pair above others in a list. When the user
|
||||
; is typing and the file is temporarily invalid, it will make incorrect guesses
|
||||
; about tokens that occur between the cursor and the end of the block.
|
||||
;
|
||||
; When you're typing a new property name inside of a list, tree-sitter-css will
|
||||
; assume the thing you're typing is a descendant selector tag name until you
|
||||
; get to the colon. This prevents it from highlighting the incomplete line like
|
||||
; a selector tag name.
|
||||
; The fix here is for `tree-sitter-css` to get better at recovering from its
|
||||
; parsing error, but parser authors don't currently have much control over
|
||||
; that. In the meantime, this query is a decent mitigation: it colors the
|
||||
; affected tokens like plain text instead of assuming (nearly always
|
||||
; incorrectly) them to be tag names.
|
||||
;
|
||||
; Ideally, this is temporary, and we can remove it soon. Until then, it makes
|
||||
; syntax highlighting less obnoxious.
|
||||
|
||||
(descendant_selector
|
||||
(tag_name) @_IGNORE_
|
||||
(#set! capture.final true))
|
||||
((tag_name) @_IGNORE_
|
||||
(#is? test.descendantOfType "ERROR")
|
||||
(#set! capture.final))
|
||||
|
||||
(ERROR
|
||||
(attribute_name) @_IGNORE_
|
||||
(#set! capture.final true))
|
||||
(#set! capture.final))
|
||||
|
||||
((ERROR
|
||||
(attribute_name) @invalid.illegal)
|
||||
(#set! capture.final true))
|
||||
(#set! capture.final))
|
||||
|
||||
; WORKAROUND:
|
||||
;
|
||||
; `:hover` and other pseudo-classes don't highlight correctly inside a media
|
||||
; query (https://github.com/tree-sitter/tree-sitter-css/issues/28)
|
||||
(
|
||||
(ERROR) @entity.other.attribute-name.pseudo-class.css
|
||||
(#match? @entity.other.attribute-name.pseudo-class.css "^:[\\w-]+$")
|
||||
)
|
||||
|
||||
; WORKAROUND:
|
||||
;
|
||||
; In `::after`, the "after" has a node type of `tag_name`. We want to catch it
|
||||
; here so that it doesn't get scoped like an HTML tag name in a selector.
|
||||
; In `::after`, the "after" has a node type of `tag_name`. Unclear whether this
|
||||
; is a bug or intended behavior. We want to catch it here so that it doesn't
|
||||
; get scoped like an HTML tag name in a selector.
|
||||
|
||||
; Scope the entire `::after` range as one unit.
|
||||
((pseudo_element_selector)
|
||||
@ -61,9 +61,6 @@
|
||||
|
||||
; (selectors "," @punctuation.separator.list.comma.css)
|
||||
|
||||
; The "div" in `div.foo {`.
|
||||
(tag_name) @entity.name.tag.css
|
||||
|
||||
; The "foo" in `div[attr=foo] {`.
|
||||
(attribute_selector (plain_value) @string.unquoted.css)
|
||||
|
||||
@ -77,10 +74,30 @@
|
||||
(id_selector
|
||||
"#" @punctuation.definition.entity.id.css) @entity.other.attribute-name.id.css
|
||||
|
||||
; KNOWN ISSUE: Namespace selectors like `svg|link` are not supported. See:
|
||||
; https://github.com/tree-sitter/tree-sitter-css/issues/33
|
||||
; Declaration of a namespace:
|
||||
; The "svg" in `@namespace svg url(http://www.w3.org/2000/svg);`
|
||||
(namespace_name) @entity.other.namespace-prefix.css
|
||||
|
||||
;(namespace_name) @entity.other.namespace-prefix.css
|
||||
; A namespaced tag name:
|
||||
; The "svg" in `svg|a {}`.
|
||||
(namespace_selector
|
||||
. (tag_name) @entity.other.namespace-prefix.css
|
||||
"|" @punctuation.separator.namespace.css
|
||||
(#set! capture.final))
|
||||
|
||||
; Not sure if this is intended, but a namespaced attribute in an attribute
|
||||
; selector is construed as two tag-name children of the `attribute_name`.
|
||||
; The "xl" in `[xl|href] {}`.
|
||||
(attribute_name
|
||||
. (tag_name) @entity.other.namespace-prefix.css
|
||||
"|" @punctuation.separator.namespace.css
|
||||
(tag_name) @entity.other.attribute_name.css
|
||||
(#set! capture.final)) @_IGNORE_
|
||||
|
||||
; The "div" in `div.foo {`.
|
||||
(tag_name) @entity.name.tag.css
|
||||
; The "*" in `*[foo="bar"]`.
|
||||
(universal_selector) @entity.name.tag.universal.css
|
||||
|
||||
; The '.' in `.foo`.
|
||||
(class_selector
|
||||
@ -101,29 +118,41 @@
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.endPosition))
|
||||
|
||||
; Punctuation around the arguments of a pseudo-class or a function.
|
||||
(arguments
|
||||
"(" @punctuation.definition.arguments.begin.bracket.round.css
|
||||
")" @punctuation.definition.arguments.end.bracket.round.css)
|
||||
|
||||
; Punctuation around an attribute selector.
|
||||
(attribute_selector
|
||||
"[" @punctuation.definition.entity.begin.bracket.square.css
|
||||
(attribute_name) @entity.other.attribute-name.css
|
||||
"]" @punctuation.definition.entity.end.bracket.square.css)
|
||||
|
||||
; Operators inside attribute selectors.
|
||||
(attribute_selector
|
||||
["=" "^=" "$=" "~=" "|="] @keyword.operator.pattern.css)
|
||||
|
||||
; The `foo` in `@keyframes foo {`.
|
||||
; The "foo" in `@keyframes foo {`.
|
||||
(keyframes_name) @entity.name.keyframes.css
|
||||
|
||||
; VARIABLES
|
||||
; =========
|
||||
|
||||
; Variable declaration:
|
||||
; The "--link-visited" in `--link-visited: #039;`.
|
||||
(declaration
|
||||
(property_name) @variable.other.assignment.css
|
||||
(#match? @variable.other.assignment.css "^--" )
|
||||
(#set! capture.final true))
|
||||
|
||||
; Variable usage:
|
||||
; The ""--link--visited" in `color: var(--link-visited);`.
|
||||
((function_name) @support.function.var.css
|
||||
(arguments (plain_value) @variable.css)
|
||||
(#eq? @support.function.var.css "var"))
|
||||
|
||||
|
||||
; PROPERTIES
|
||||
; ==========
|
||||
|
||||
@ -147,9 +176,9 @@
|
||||
(#match? @string.quoted.single.css "^'")
|
||||
(#match? @string.quoted.single.css "'$"))
|
||||
|
||||
; The punctuation around quoted strings.
|
||||
((string_value) @punctuation.definition.string.begin.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^[\"']"))
|
||||
|
||||
((string_value) @punctuation.definition.string.end.css
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "[\"']$"))
|
||||
|
||||
@ -208,10 +237,6 @@
|
||||
; (#eq? @support.function.var.css "var")
|
||||
; )
|
||||
|
||||
((function_name) @support.function.var.css
|
||||
(arguments (plain_value) @variable.css)
|
||||
(#eq? @support.function.var.css "var"))
|
||||
|
||||
((function_name) @support.function._TEXT_.css
|
||||
; Because we just handled it above.
|
||||
(#not-eq? @support.function._TEXT_.css "var"))
|
||||
|
Binary file not shown.
@ -1,43 +1,26 @@
|
||||
exports.activate = () => {
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'comment',
|
||||
language(node) {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.css', {
|
||||
types: ['comment', 'string_value']
|
||||
});
|
||||
|
||||
for (let type of ['comment', 'string_value']) {
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type,
|
||||
language(node) {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
|
||||
// Catch things like
|
||||
//
|
||||
// @import url(https://www.example.com/style.css);
|
||||
//
|
||||
// where the URL is unquoted.
|
||||
atom.grammars.addInjectionPoint('source.css', {
|
||||
type: 'call_expression',
|
||||
hyperlink.addInjectionPoint('source.css', {
|
||||
types: ['call_expression'],
|
||||
language: () => 'hyperlink',
|
||||
content: (node) => {
|
||||
content(node) {
|
||||
let functionName = node.descendantsOfType('function_value')[0]?.text;
|
||||
if (!functionName === 'url') { return null; }
|
||||
|
||||
return node.descendantsOfType('plain_value');
|
||||
},
|
||||
languageScope: null
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.css', { types: ['comment'] });
|
||||
};
|
||||
|
@ -14,5 +14,17 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tree-sitter-css": "^0.19.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
(paragraph) @markup.paragraph.gfm
|
||||
|
||||
(thematic_break) @punctuation.definition.horizontal-rule.gfm
|
||||
(thematic_break) @markup.horizontal-rule.gfm
|
||||
|
||||
(block_quote) @markup.quote.blockquote.gfm
|
||||
((block_quote) @punctuation.definition.blockquote.gfm
|
||||
@ -140,8 +140,9 @@
|
||||
(code_span) @meta.embedded.line.inline-code.gfm @markup.raw.inline.gfm
|
||||
(info_string) @storage.modifier.language._TEXT_.gfm
|
||||
|
||||
(fenced_code_block) @markup.code.fenced.gfm @meta.embedded.block.fenced-code.gfm
|
||||
(indented_code_block) @markup.code.indented.gfm @meta.embedded.block.indented-code.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
|
||||
|
@ -88,3 +88,40 @@ exports.activate = () => {
|
||||
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.
|
||||
language(node) {
|
||||
for (let child of textChildren(node)) {
|
||||
if (hyperlink.test(child)) {
|
||||
return 'hyperlink';
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
content(node) {
|
||||
return textChildren(node);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -10,5 +10,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"coffeescript": "^1.7.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ comments:
|
||||
start: '// '
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-go#ff86c7f1734873c8c4874ca4dd95603695686d7a'
|
||||
grammar: 'tree-sitter-go/tree-sitter-go.wasm'
|
||||
highlightsQuery: 'tree-sitter-go/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-go/folds.scm'
|
||||
|
@ -47,6 +47,8 @@
|
||||
|
||||
[
|
||||
"struct"
|
||||
"interface"
|
||||
"map"
|
||||
] @storage.type._TYPE_.go
|
||||
|
||||
(struct_type
|
||||
@ -55,13 +57,14 @@
|
||||
(field_identifier) @entity.other.attribute-name.go)))
|
||||
|
||||
(keyed_element
|
||||
(field_identifier) @entity.other.attribute-name.go
|
||||
.
|
||||
":" @punctuation.separator.key-value.go)
|
||||
. (literal_element) @entity.other.attribute-name.go)
|
||||
|
||||
(keyed_element ":" @punctuation.separator.key-value.go)
|
||||
|
||||
[
|
||||
"break"
|
||||
"case"
|
||||
"chan"
|
||||
"continue"
|
||||
"default"
|
||||
"defer"
|
||||
@ -78,7 +81,10 @@
|
||||
] @keyword.control._TYPE_.go
|
||||
|
||||
|
||||
; Function names: the "foo" in `func foo() {`
|
||||
(function_declaration (identifier) @entity.name.function.go)
|
||||
; Method names: the "Foo" in `func (x Bar) Foo {`
|
||||
(method_declaration (field_identifier) @entity.name.function.method.go)
|
||||
|
||||
(call_expression
|
||||
(identifier) @support.function.builtin.go
|
||||
@ -252,7 +258,8 @@
|
||||
|
||||
";" @punctuation.terminator.go
|
||||
"," @punctuation.separator.comma.go
|
||||
":" @punctuation.separator.colon.go
|
||||
(":" @punctuation.separator.colon.go
|
||||
(#set! capture.shy))
|
||||
|
||||
(parameter_list
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.go
|
||||
|
Binary file not shown.
@ -1,25 +1,10 @@
|
||||
exports.activate = () => {
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
for (let type of ['comment', 'interpreted_string_literal', 'raw_string_literal']) {
|
||||
atom.grammars.addInjectionPoint('source.go', {
|
||||
type,
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.go', {
|
||||
types: ['comment', 'interpreted_string_literal', 'raw_string_literal']
|
||||
});
|
||||
}
|
||||
|
||||
atom.grammars.addInjectionPoint('source.go', {
|
||||
type: 'comment',
|
||||
language(node) {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.go', { types: ['comment'] });
|
||||
};
|
||||
|
@ -14,5 +14,17 @@
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"dependencies": {
|
||||
"tree-sitter-go": "0.19.1"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ fileTypes: [
|
||||
injectionRegex: '^(ejs|EJS)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-embedded-template#203f7bd3c1bbfbd98fc19add4b8fcb213c059205'
|
||||
grammar: 'tree-sitter-embedded-template/tree-sitter-embedded-template.wasm'
|
||||
highlightsQuery: 'tree-sitter-embedded-template/ejs/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-embedded-template/ejs/folds.scm'
|
||||
|
@ -11,6 +11,7 @@ fileTypes: [
|
||||
injectionRegex: '^(erb|ERB)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-embedded-template#203f7bd3c1bbfbd98fc19add4b8fcb213c059205'
|
||||
grammar: 'tree-sitter-embedded-template/tree-sitter-embedded-template.wasm'
|
||||
highlightsQuery: 'tree-sitter-embedded-template/erb/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-embedded-template/erb/folds.scm'
|
||||
|
@ -6,6 +6,7 @@ parser: 'tree-sitter-html'
|
||||
injectionRegex: '(HTML|html|Html)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-html#d742025fa2d8e6100f134a6ea990443aa1f074b3'
|
||||
grammar: 'tree-sitter-html/tree-sitter-html.wasm'
|
||||
highlightsQuery: 'tree-sitter-html/highlights.scm'
|
||||
foldsQuery: 'tree-sitter-html/folds.scm'
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
exports.activate = function() {
|
||||
exports.activate = function () {
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'script_element',
|
||||
language() {
|
||||
@ -19,38 +19,6 @@ exports.activate = function() {
|
||||
}
|
||||
});
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.basic', {
|
||||
type: 'attribute_value',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
// TODO: Inject hyperlink grammar into plain text?
|
||||
|
||||
// EMBEDDED
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.ejs', {
|
||||
@ -95,3 +63,14 @@ exports.activate = function() {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
// TODO: Inject hyperlink grammar into plain text?
|
||||
hyperlink.addInjectionPoint('text.html.basic', {
|
||||
types: ['comment', 'attribute_value']
|
||||
});
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('text.html.basic', { types: ['comment'] });
|
||||
};
|
||||
|
@ -19,5 +19,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"dedent": "^0.7.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
packages/language-html/spec/.eslintrc.js
Normal file
9
packages/language-html/spec/.eslintrc.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
env: { jasmine: true },
|
||||
rules: {
|
||||
"node/no-unpublished-require": "off",
|
||||
"node/no-extraneous-require": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-empty": "off"
|
||||
}
|
||||
};
|
58
packages/language-hyperlink/lib/main.js
Normal file
58
packages/language-hyperlink/lib/main.js
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
module.exports = {
|
||||
provideHyperlinkInjection() {
|
||||
return {
|
||||
// Private: Test whether a Tree-sitter node's text contains any tokens
|
||||
// that would benefit from a hyperlink injection.
|
||||
//
|
||||
// Useful if you want to call {GrammarRegistry::addInjectionPoint}
|
||||
// yourself and want to use this logic in a `language` callback.
|
||||
//
|
||||
// * `node` A Tree-sitter tree node.
|
||||
test(node) {
|
||||
return HYPERLINK_PATTERN.test(node.text);
|
||||
},
|
||||
|
||||
// Private: specify one or more types of syntax nodes for a given grammar
|
||||
// that may embed the hyperlink grammar.
|
||||
//
|
||||
// * `scopeName` The {String} ID of the parent language.
|
||||
// * `options` An {Object} with the following keys:
|
||||
// * `types` An {Array} or {String} indicating the type or types of
|
||||
// Tree-sitter tree nodes that may receive injections.
|
||||
// * `language` (optional) A {Function} that may be called to add extra
|
||||
// logic for determining which language should be used in an
|
||||
// injection. If present, will be called before the default logic.
|
||||
// If it returns `undefined`, the default logic will apply. If it
|
||||
// returns a {String} or `null`, the default logic will be preempted.
|
||||
// * `content` (optional) A {Function} that will be used to determine
|
||||
// which of the injection node's children, if any, will be injected
|
||||
// into. The default `content` callback is one that returns the
|
||||
// original node.
|
||||
addInjectionPoint(scopeName, options) {
|
||||
let types = options.types;
|
||||
if (!Array.isArray(types)) types = [types];
|
||||
|
||||
for (let type of types) {
|
||||
atom.grammars.addInjectionPoint(scopeName, {
|
||||
type,
|
||||
language(node) {
|
||||
if (options.language) {
|
||||
let result = options.language(node);
|
||||
if (result !== undefined) return result;
|
||||
}
|
||||
return HYPERLINK_PATTERN.test(node.text) ?
|
||||
'hyperlink' : undefined;
|
||||
},
|
||||
content(node) {
|
||||
return options.content ? options.content(node) : node;
|
||||
},
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
@ -1,11 +1,19 @@
|
||||
{
|
||||
"name": "language-hyperlink",
|
||||
"version": "0.17.1",
|
||||
"main": "lib/main",
|
||||
"description": "Hyperlink colorization in Atom",
|
||||
"engines": {
|
||||
"atom": "*",
|
||||
"node": ">=14"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"providedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "provideHyperlinkInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
packages/language-hyperlink/spec/.eslintrc.js
Normal file
13
packages/language-hyperlink/spec/.eslintrc.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
env: { jasmine: true },
|
||||
globals: {
|
||||
waitsForPromise: true,
|
||||
advanceClock: true
|
||||
},
|
||||
rules: {
|
||||
"node/no-unpublished-require": "off",
|
||||
"node/no-extraneous-require": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-empty": "off"
|
||||
}
|
||||
};
|
@ -217,9 +217,13 @@
|
||||
(identifier) @variable.parameter.lambda.java))
|
||||
|
||||
(variable_declarator
|
||||
name: (identifier) @variable.other.assignment.java)
|
||||
name: (identifier) @variable.other.declaration.java)
|
||||
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.java)
|
||||
|
||||
(update_expression
|
||||
(identifier) @variable.other.assignment.java)
|
||||
|
||||
; PACKAGES
|
||||
; ========
|
||||
@ -359,6 +363,8 @@
|
||||
(binary_expression
|
||||
["&" "|" "^" "~" "<<" ">>" ">>>"] @keyword.operator.bitwise.java)
|
||||
|
||||
["++" "--"] @keyword.operator.increment.java
|
||||
|
||||
"." @keyword.operator.accessor.dot.java
|
||||
"::" @keyword.operator.accessor.method-reference.java
|
||||
|
||||
|
@ -1,24 +1,10 @@
|
||||
exports.activate = () => {
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('source.java', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.java', {
|
||||
types: ['comment', 'string_literal']
|
||||
});
|
||||
|
||||
for (let type of ['string_literal', 'comment']) {
|
||||
atom.grammars.addInjectionPoint('source.java', {
|
||||
type,
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.java', { types: ['comment'] });
|
||||
};
|
||||
|
@ -11,5 +11,17 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tree-sitter-java": "0.19.1"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@ type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-javascript'
|
||||
|
||||
injectionRegex: '^(js|javascript|JS|JAVASCRIPT)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'ts/grammar.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
||||
localsQuery: 'ts/locals.scm'
|
||||
foldsQuery: 'ts/folds.scm'
|
||||
indentsQuery: 'ts/indents.scm'
|
||||
tagsQuery: 'ts/tags.scm'
|
||||
parserSource: 'github:tree-sitter/tree-sitter-javascript#f1e5a09b8d02f8209a68249c93f0ad647b228e6e'
|
||||
grammar: 'tree-sitter/tree-sitter-javascript.wasm'
|
||||
highlightsQuery: 'tree-sitter/highlights.scm'
|
||||
localsQuery: 'tree-sitter/locals.scm'
|
||||
foldsQuery: 'tree-sitter/folds.scm'
|
||||
indentsQuery: 'tree-sitter/indents.scm'
|
||||
tagsQuery: 'tree-sitter/tags.scm'
|
||||
|
||||
firstLineRegex: [
|
||||
# shebang line
|
@ -0,0 +1,13 @@
|
||||
name: 'JSDoc'
|
||||
scopeName: 'source.jsdoc'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-jsdoc'
|
||||
|
||||
injectionRegex: '^jsdoc$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-jsdoc#a5e363a98676136d9f5884cb558086e5f1fc32b6'
|
||||
grammar: 'tree-sitter/jsdoc/tree-sitter-jsdoc.wasm'
|
||||
highlightsQuery: 'tree-sitter/jsdoc/highlights.scm'
|
||||
foldsQuery: 'tree-sitter/jsdoc/folds.scm'
|
||||
indentsQuery: 'tree-sitter/jsdoc/indents.scm'
|
@ -0,0 +1,11 @@
|
||||
name: 'JavaScript RegExp'
|
||||
scopeName: 'source.js.regexp'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-regex'
|
||||
|
||||
injectionRegex: '^(js-regex)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-regex#2354482d7e2e8f8ff33c1ef6c8aa5690410fbc96'
|
||||
grammar: 'tree-sitter/regex/tree-sitter-regex.wasm'
|
||||
highlightsQuery: 'tree-sitter/regex/highlights.scm'
|
@ -1,12 +0,0 @@
|
||||
name: 'JSDoc'
|
||||
scopeName: 'source.jsdoc'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-jsdoc'
|
||||
|
||||
injectionRegex: '^jsdoc$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'ts/jsdoc/tree-sitter-jsdoc.wasm'
|
||||
highlightsQuery: 'ts/jsdoc/highlights.scm'
|
||||
foldsQuery: 'ts/jsdoc/folds.scm'
|
||||
indentsQuery: 'ts/jsdoc/indents.scm'
|
@ -1,9 +0,0 @@
|
||||
name: 'JavaScript RegExp'
|
||||
scopeName: 'source.js.regexp'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-regex'
|
||||
|
||||
injectionRegex: '^(js-regex)$'
|
||||
treeSitter:
|
||||
grammar: 'ts/regex/tree-sitter-regex.wasm'
|
||||
highlightsQuery: 'ts/regex/highlights.scm'
|
@ -80,4 +80,4 @@
|
||||
|
||||
((jsx_self_closing_element) @fold
|
||||
; Exclude both the slash and angle bracket `/>` from the fold.
|
||||
(#set! fold.endAt lastChild.previousSibling.startPosition))
|
||||
(#set! fold.endAt lastChild.startPosition))
|
@ -71,17 +71,26 @@
|
||||
(assignment_expression
|
||||
left: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; The "bar" in `foo.bar = true`
|
||||
; Mark all the properties whose right-hand sides are functions so that we can
|
||||
; exclude them from the next query.
|
||||
(assignment_expression
|
||||
left: (member_expression
|
||||
property: (property_identifier) @variable.other.assignment.property.js))
|
||||
property: (property_identifier) @variable.other.assignment.property.js)
|
||||
right: [(arrow_function) (function)] @_IGNORE_
|
||||
(#set! isFunctionProperty true))
|
||||
|
||||
; The "bar" in `foo.#bar = true`
|
||||
; The "bar" in `foo.bar = true`.
|
||||
(assignment_expression
|
||||
left: (member_expression
|
||||
property: (property_identifier) @variable.other.assignment.property.js)
|
||||
(#is-not? test.rangeWithData isFunctionProperty)
|
||||
(#set! capture.final))
|
||||
|
||||
; The "bar" in `foo.#bar = true`.
|
||||
(assignment_expression
|
||||
left: (member_expression
|
||||
property: (private_property_identifier) @variable.other.assignment.property.private.js))
|
||||
|
||||
|
||||
; The "foo" in `foo += 1`.
|
||||
(augmented_assignment_expression
|
||||
left: (identifier) @variable.other.assignment.js)
|
||||
@ -90,6 +99,13 @@
|
||||
(update_expression
|
||||
argument: (identifier) @variable.other.assignment.js)
|
||||
|
||||
; Public field definition in a class body:
|
||||
; The "foo" in `foo = "bar";`
|
||||
(field_definition
|
||||
property: (property_identifier) @variable.other.assignment.property.public.js)
|
||||
|
||||
; Private field definition in a class body:
|
||||
; The "#foo" in `#foo = "bar";`
|
||||
(field_definition
|
||||
property: (private_property_identifier) @variable.other.assignment.property.private.js)
|
||||
|
||||
@ -139,18 +155,17 @@
|
||||
(rest_pattern
|
||||
(identifier) @variable.other.assignment.destructuring.rest.js))
|
||||
|
||||
; A variable array destructuring:
|
||||
; The "foo" and "bar" in `let [foo, bar] = something`
|
||||
(variable_declarator
|
||||
(array_pattern
|
||||
; An array-destructured assignment or reassignment, regardless of depth:
|
||||
; The "foo" in `[foo] = bar;` and `[[foo]] = bar;`.
|
||||
(array_pattern
|
||||
(identifier) @variable.other.assignment.destructuring.js)
|
||||
|
||||
; An array-destructured assignment or reassignment with a default, regardless of depth:
|
||||
; The "baz" in `let [foo, bar, baz = false] = something;` and `let [[baz = 5]] = something`;
|
||||
(array_pattern
|
||||
(assignment_pattern
|
||||
(identifier) @variable.other.assignment.destructuring.js))
|
||||
|
||||
; A variable array destructuring with a default:
|
||||
; The "baz" in `let [foo, bar, baz = false] = something`
|
||||
(variable_declarator
|
||||
(array_pattern
|
||||
(assignment_pattern
|
||||
(identifier) @variable.other.assignment.destructuring.js)))
|
||||
|
||||
; A variable declaration in a for…(in|of) loop:
|
||||
; The "foo" in `for (let foo of bar) {`
|
||||
@ -250,6 +265,11 @@
|
||||
(method_definition
|
||||
name: (property_identifier) @entity.name.function.method.definition.js)
|
||||
|
||||
; Private method definitions:
|
||||
; the "#foo" in `#foo () {` (inside a class body)
|
||||
(method_definition
|
||||
name: (private_property_identifier) @entity.name.function.method.private.definition.js)
|
||||
|
||||
; Function property assignment:
|
||||
; The "foo" in `thing.foo = (arg) => {}`
|
||||
(assignment_expression
|
||||
@ -744,7 +764,7 @@
|
||||
; The "Foo" in `<Foo />`.
|
||||
(jsx_self_closing_element
|
||||
name: (identifier) @entity.name.tag.js
|
||||
) @meta.tag.js
|
||||
) @meta.tag.jsx.js
|
||||
|
||||
; The "Foo" in `<Foo>`.
|
||||
(jsx_opening_element
|
||||
@ -752,8 +772,6 @@
|
||||
|
||||
; The "Foo" in `</Foo>`.
|
||||
(jsx_closing_element
|
||||
"/" @punctuation.definition.tag.end.js
|
||||
(#set! capture.final true)
|
||||
name: (identifier) @entity.name.tag.js)
|
||||
|
||||
; The "bar" in `<Foo bar={true} />`.
|
||||
@ -769,23 +787,18 @@
|
||||
|
||||
(jsx_opening_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
">" @punctuation.definition.tag.end.js)
|
||||
">" @punctuation.definition.tag.end.js) @meta.tag.jsx.js
|
||||
|
||||
(jsx_closing_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
">" @punctuation.definition.tag.end.js)
|
||||
"</" @punctuation.definition.tag.begin.js
|
||||
">" @punctuation.definition.tag.end.js) @meta.tag.jsx.js
|
||||
|
||||
(jsx_self_closing_element
|
||||
"<" @punctuation.definition.tag.begin.js
|
||||
(#set! capture.final true))
|
||||
|
||||
((jsx_self_closing_element
|
||||
; The "/>" in `<Foo />`, extended to cover both anonymous nodes at once.
|
||||
"/") @punctuation.definition.tag.end.js
|
||||
(#set! adjust.startAt lastChild.previousSibling.startPosition)
|
||||
(#set! adjust.endAt lastChild.endPosition)
|
||||
(#set! capture.final true))
|
||||
|
||||
(jsx_self_closing_element
|
||||
"/>" @punctuation.definition.tag.end.js)
|
||||
|
||||
; OPERATORS
|
||||
; ==========
|
||||
@ -812,7 +825,13 @@
|
||||
|
||||
(unary_expression ["+" "-"] @keyword.operator.unary.js)
|
||||
|
||||
(ternary_expression ["?" ":"] @keyword.operator.ternary.js)
|
||||
(ternary_expression ["?" ":"] @keyword.operator.ternary.js
|
||||
(#set! capture.final))
|
||||
|
||||
; Try to highlight `?` like an operator while the user is typing without
|
||||
; waiting for its paired `:`.
|
||||
("?" @keyword.operator.ternary.js
|
||||
(#is? test.descendantOfType "ERROR"))
|
||||
|
||||
[
|
||||
"&&="
|
@ -1,7 +1,3 @@
|
||||
|
||||
; ((template_string) @ignore
|
||||
; (#is-not? test.OnStartingOrEndingRow true))
|
||||
|
||||
; STATEMENT BLOCKS
|
||||
; ================
|
||||
|
||||
@ -20,11 +16,19 @@
|
||||
(#is? test.last true))
|
||||
(#set! indent.matchIndentOf parent.startPosition))
|
||||
|
||||
; 'case' and 'default' need to be indented one level more than their containing
|
||||
; `switch`. TODO: Might need to make this configurable.
|
||||
; By default, `case` and `default` need to be indented one level more than their containing
|
||||
; `switch`.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
(#set! indent.offsetIndent 1)
|
||||
(#is-not? test.config "language-javascript.indentation.alignCaseWithSwitch"))
|
||||
|
||||
; When this config setting is enabled, `case` and `default` need to be indented
|
||||
; to match their containing `switch`.
|
||||
(["case" "default"] @match
|
||||
(#set! indent.matchIndentOf parent.parent.startPosition)
|
||||
(#set! indent.offsetIndent 0)
|
||||
(#is? test.config "language-javascript.indentation.alignCaseWithSwitch"))
|
||||
|
||||
|
||||
; ONE-LINE CONDITIONALS
|
||||
@ -33,10 +37,12 @@
|
||||
; An `if` statement without an opening brace should indent the next line…
|
||||
(if_statement
|
||||
condition: (parenthesized_expression ")" @indent
|
||||
(#is? test.lastTextOnRow true)))
|
||||
(#is? test.lastTextOnRow true)
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf")))
|
||||
; (as should a braceless `else`…)
|
||||
("else" @indent
|
||||
(#is? test.lastTextOnRow true))
|
||||
(#is? test.lastTextOnRow true)
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf"))
|
||||
|
||||
; …and keep that indent level if the user types a comment before the
|
||||
; consequence…
|
||||
@ -44,7 +50,8 @@
|
||||
consequence: (empty_statement) @match
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition)
|
||||
(#set! indent.matchIndentOf parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
(#set! indent.offsetIndent 1)
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf"))
|
||||
|
||||
; …and keep that indent level after the user starts typing…
|
||||
(if_statement
|
||||
@ -61,7 +68,8 @@
|
||||
; of an `expression_statement`, for some reason.
|
||||
(#not-match? @match "^\\s*{")
|
||||
(#set! indent.matchIndentOf parent.startPosition)
|
||||
(#set! indent.offsetIndent 1))
|
||||
(#set! indent.offsetIndent 1)
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf"))
|
||||
|
||||
; …but dedent after exactly one statement.
|
||||
(if_statement
|
||||
@ -76,7 +84,8 @@
|
||||
] @dedent.next
|
||||
; When an opening curly brace is unpaired, it might get interpreted as part
|
||||
; of an `expression_statement`, for some reason.
|
||||
(#not-match? @dedent.next "^\\s*{"))
|
||||
(#not-match? @dedent.next "^\\s*{")
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf"))
|
||||
|
||||
(else_clause
|
||||
[
|
||||
@ -87,7 +96,8 @@
|
||||
(throw_statement)
|
||||
(debugger_statement)
|
||||
] @dedent.next
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition))
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition)
|
||||
(#is? test.config "language-javascript.indentation.indentAfterBracelessIf"))
|
||||
|
||||
|
||||
; HANGING INDENT ON SPLIT LINES
|
||||
@ -97,14 +107,22 @@
|
||||
; `config` scope test.
|
||||
|
||||
; Any of these at the end of a line indicate the next line should be indented…
|
||||
(["||" "&&" "?"] @indent
|
||||
(["||" "&&"] @indent
|
||||
(#is? test.config "language-javascript.indentation.addHangingIndentAfterLogicalOperators")
|
||||
(#is? test.lastTextOnRow true))
|
||||
|
||||
("?" @indent
|
||||
(#is? test.config "language-javascript.indentation.addHangingIndentAfterTernaryOperators")
|
||||
(#is? test.lastTextOnRow true))
|
||||
|
||||
; …and the line after that should be dedented…
|
||||
(binary_expression
|
||||
["||" "&&"]
|
||||
right: (_) @dedent.next
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition))
|
||||
(#is? test.config "language-javascript.indentation.addHangingIndentAfterLogicalOperators")
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition)
|
||||
; …unless the right side of the expression spans multiple lines.
|
||||
(#is? test.endsOnSameRowAs startPosition))
|
||||
|
||||
; …unless it's a ternary, in which case the dedent should wait until the
|
||||
; alternative clause.
|
||||
@ -115,20 +133,11 @@
|
||||
;
|
||||
(ternary_expression
|
||||
alternative: (_) @dedent.next
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition))
|
||||
|
||||
|
||||
; DEDENT-NEXT IN LIMITED SCENARIOS
|
||||
; ================================
|
||||
|
||||
; Catches unusual hanging-indent scenarios when calling a method, such as:
|
||||
;
|
||||
; return this.veryLongMethodNameWithSeveralArgumentsThat(are, too,
|
||||
; short, forEach, toHave, itsOwn, line);
|
||||
;
|
||||
; (arguments ")" @dedent.next
|
||||
; (#is-not? test.startsOnSameRowAs parent.firstChild.startPosition)
|
||||
; (#is-not? test.firstTextOnRow true))
|
||||
(#is? test.config "language-javascript.indentation.addHangingIndentAfterTernaryOperators")
|
||||
(#is-not? test.startsOnSameRowAs parent.startPosition)
|
||||
; Only dedent the next line if the alternative doesn't itself span multiple
|
||||
; lines.
|
||||
(#is? test.endsOnSameRowAs startPosition))
|
||||
|
||||
|
||||
; GENERAL
|
||||
@ -137,21 +146,27 @@
|
||||
; Weed out `}`s that should not signal dedents.
|
||||
(template_substitution "}" @_IGNORE_ (#set! capture.final true))
|
||||
|
||||
[
|
||||
"{"
|
||||
"("
|
||||
"["
|
||||
] @indent
|
||||
; As strange as it may seem to make all of these basic indentation hints
|
||||
; configurable, some brace styles are incompatible with some of these choices;
|
||||
; see https://github.com/orgs/pulsar-edit/discussions/249.
|
||||
("{" @indent
|
||||
(#is? test.config "language-javascript.indentation.indentBraces"))
|
||||
("}" @dedent
|
||||
(#is? test.config "language-javascript.indentation.indentBraces"))
|
||||
|
||||
("[" @indent
|
||||
(#is? test.config "language-javascript.indentation.indentBrackets"))
|
||||
("]" @dedent
|
||||
(#is? test.config "language-javascript.indentation.indentBrackets"))
|
||||
|
||||
("(" @indent
|
||||
(#is? test.config "language-javascript.indentation.indentParentheses"))
|
||||
(")" @dedent
|
||||
(#is? test.config "language-javascript.indentation.indentParentheses"))
|
||||
|
||||
[
|
||||
"}"
|
||||
")"
|
||||
"]"
|
||||
] @dedent
|
||||
|
||||
["case" "default"] @indent
|
||||
|
||||
|
||||
; JSX
|
||||
; ===
|
||||
|
||||
@ -186,7 +201,7 @@
|
||||
; point, so the usual heuristic won't work. Instead we set `indent.force` and
|
||||
; use `test.lastTextOnRow` to ensure that the dedent fires exactly once while
|
||||
; typing.
|
||||
((jsx_self_closing_element ">" @dedent)
|
||||
((jsx_self_closing_element "/>" @dedent)
|
||||
(#is-not? test.startsOnSameRowAs parent.firstChild.startPosition)
|
||||
(#is? test.lastTextOnRow)
|
||||
(#set! indent.force true))
|
@ -21,7 +21,7 @@
|
||||
|
||||
((inline_tag) @meta.inline-tag.jsdoc.js)
|
||||
|
||||
(tag_name) @entity.name.tag.jsdoc.js
|
||||
(tag_name) @keyword.other.tag.jsdoc.js
|
||||
|
||||
((tag (type)) @storage.type.instance.jsdoc.js
|
||||
; Join the type with its surrounding braces.
|
BIN
packages/language-javascript/grammars/tree-sitter/jsdoc/tree-sitter-jsdoc.wasm
Executable file
BIN
packages/language-javascript/grammars/tree-sitter/jsdoc/tree-sitter-jsdoc.wasm
Executable file
Binary file not shown.
@ -1,8 +1,3 @@
|
||||
; CAVEATS:
|
||||
;
|
||||
; * No support for lookbehind as of March 2023 (waiting on
|
||||
; https://github.com/tree-sitter/tree-sitter-regex/pull/15)
|
||||
|
||||
(non_capturing_group) @meta.group.non-capturing.regexp
|
||||
|
||||
[
|
||||
@ -17,6 +12,8 @@
|
||||
|
||||
[
|
||||
(boundary_assertion)
|
||||
(start_assertion)
|
||||
(end_assertion)
|
||||
] @keyword.control.anchor.regexp
|
||||
|
||||
[
|
||||
@ -24,10 +21,10 @@
|
||||
(lazy)
|
||||
] @keyword.operator.quantifier.regexp
|
||||
|
||||
((lookahead_assertion) @keyword.operator.lookahead.regexp
|
||||
((lookaround_assertion) @keyword.operator.lookaround.regexp
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\?="))
|
||||
|
||||
((lookahead_assertion) @keyword.operator.lookahead.negated.regexp
|
||||
((lookaround_assertion) @keyword.operator.lookaround.negated.regexp
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\?!"))
|
||||
|
||||
((non_capturing_group) @keyword.operator.group.non-capturing.regexp
|
BIN
packages/language-javascript/grammars/tree-sitter/regex/tree-sitter-regex.wasm
Executable file
BIN
packages/language-javascript/grammars/tree-sitter/regex/tree-sitter-regex.wasm
Executable file
Binary file not shown.
BIN
packages/language-javascript/grammars/tree-sitter/tree-sitter-javascript.wasm
Executable file
BIN
packages/language-javascript/grammars/tree-sitter/tree-sitter-javascript.wasm
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -57,19 +57,6 @@ exports.activate = function () {
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
// TODO: Ideal would be to have one `language-todo` injection for the whole
|
||||
// document responsible for highlighting TODOs in all comments, but
|
||||
// performance needs to be better than it is now for that to be possible.
|
||||
// Injecting into individual line comments results in less time parsing
|
||||
// during buffer modification, but _lots_ of language layers.
|
||||
//
|
||||
// Compromise is to test the content first and then only inject a layer for
|
||||
// `language-todo` when we know it'll be needed. All this also applies for
|
||||
// `language-hyperlink`.
|
||||
//
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('source.js', {
|
||||
type: 'comment',
|
||||
language(comment) {
|
||||
@ -81,28 +68,16 @@ exports.activate = function () {
|
||||
languageScope: null,
|
||||
coverShallowerScopes: true
|
||||
});
|
||||
};
|
||||
|
||||
// Experiment: better to have one layer with lots of nodes, or lots of
|
||||
// layers each managing one node?
|
||||
atom.grammars.addInjectionPoint('source.js', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.js', {
|
||||
types: ['comment', 'template_string', 'string_fragment']
|
||||
});
|
||||
};
|
||||
|
||||
for (let type of ['template_string', 'string_fragment', 'comment']) {
|
||||
atom.grammars.addInjectionPoint('source.js', {
|
||||
type,
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.js', { types: ['comment'] });
|
||||
};
|
||||
|
||||
const CSS_REGEX = /\bstyled\b|\bcss\b/i;
|
||||
|
@ -16,5 +16,74 @@
|
||||
"tree-sitter-javascript": "0.19.0",
|
||||
"tree-sitter-jsdoc": "0.19.0",
|
||||
"tree-sitter-regex": "0.19.0"
|
||||
},
|
||||
"configSchema": {
|
||||
"indentation": {
|
||||
"title": "Indentation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"indentBraces": {
|
||||
"title": "Indent Curly Braces",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 1,
|
||||
"description": "Indent after `{`."
|
||||
},
|
||||
"indentBrackets": {
|
||||
"title": "Indent Brackets",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 2,
|
||||
"description": "Indent after `[`."
|
||||
},
|
||||
"indentParentheses": {
|
||||
"title": "Indent Parentheses",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 3,
|
||||
"description": "Indent after `(`."
|
||||
},
|
||||
"alignCaseWithSwitch": {
|
||||
"title": "Align “case” With ”switch”",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"order": 4,
|
||||
"description": "When enabled, `case` and `default` statements in `switch` blocks will match the indent level of the enclosing `switch` instead of indenting themselves one level."
|
||||
},
|
||||
"indentAfterBracelessIf": {
|
||||
"title": "Indent After Braceless “if” And “else”",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 5,
|
||||
"description": "When enabled, `if` and `else` statements without a brace on the initial line will trigger an indent, then a dedent after a single statement. Disable if your brace style is incompatible with this pattern."
|
||||
},
|
||||
"addHangingIndentAfterLogicalOperators": {
|
||||
"title": "Add Hanging Indent After Logical Operators",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 6,
|
||||
"description": "When enabled, will add a hanging indent when a line ends with `&&` or `||`, continuing the indent until the end of the statement."
|
||||
},
|
||||
"addHangingIndentAfterTernaryOperators": {
|
||||
"title": "Add Hanging Indent After Ternary Operators",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"order": 7,
|
||||
"description": "When enabled, will add a hanging indent when a line ends with `?`, continuing the indent through the ensuing `:` until the end of the statement."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,8 @@ parser: 'tree-sitter-php'
|
||||
injectionRegex: 'php|PHP'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-php#d5e7cacb6c27e0e131c7f76c0dbfee56dfcc61e3'
|
||||
parserSource: 'github:tree-sitter/tree-sitter-php#b569a5f2c0d592e67430520d1a0e1f765d83ceb0'
|
||||
grammar: 'tree-sitter/tree-sitter-php.wasm'
|
||||
highlightsQuery: 'tree-sitter/queries/highlights.scm'
|
||||
tagsQuery: 'tree-sitter/queries/tags.scm'
|
||||
foldsQuery: 'tree-sitter/queries/folds.scm'
|
||||
indentsQuery: 'tree-sitter/queries/indents.scm'
|
||||
|
||||
fileTypes: [
|
||||
'aw'
|
||||
@ -28,7 +24,3 @@ fileTypes: [
|
||||
'phtml'
|
||||
'profile'
|
||||
]
|
||||
|
||||
firstLineRegex: "^\\#!.*(?:\\s|\\/)php\\d?(?:$|\\s)|^\\s*<\\?(php|=|\\s|$)"
|
||||
|
||||
contentRegex: "<\\?(php|=|\\s|$)"
|
||||
|
@ -3,10 +3,13 @@ type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-php'
|
||||
|
||||
# Give it a precise injectionRegex that won't get accidentally matched with
|
||||
# anything. This grammar only exists as a way to apply the `source.php` scope.
|
||||
# anything.
|
||||
injectionRegex: '^(internal-php)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-php#594b8bad093abe739c3d2a2cae5abae33c5fb23d'
|
||||
parserSource: 'github:tree-sitter/tree-sitter-php#b569a5f2c0d592e67430520d1a0e1f765d83ceb0'
|
||||
grammar: 'tree-sitter/tree-sitter-php.wasm'
|
||||
highlightsQuery: 'tree-sitter/queries/empty.scm'
|
||||
highlightsQuery: 'tree-sitter/queries/highlights.scm'
|
||||
tagsQuery: 'tree-sitter/queries/tags.scm'
|
||||
foldsQuery: 'tree-sitter/queries/folds.scm'
|
||||
indentsQuery: 'tree-sitter/queries/indents.scm'
|
||||
|
@ -7,14 +7,35 @@
|
||||
; SUPPORT
|
||||
; =======
|
||||
|
||||
; There are lots of constructs that look like ordinary function calls but are
|
||||
; actually special language statements.
|
||||
(array_creation_expression
|
||||
"array" @support.function.builtin.array.php)
|
||||
"array" @support.function.builtin.array.php
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.php
|
||||
")" @punctuation.definition.parameters.end.bracket.round.php)
|
||||
|
||||
(list_literal "list" @support.function.builtin.list.php)
|
||||
(list_literal "list" @support.function.builtin.list.php
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.php
|
||||
")" @punctuation.definition.parameters.end.bracket.round.php)
|
||||
|
||||
(unset_statement
|
||||
"unset" @support.function.unset.php
|
||||
"(" @punctuation.definition.parameters.begin.bracket.round.php
|
||||
")" @punctuation.definition.parameters.end.bracket.round.php)
|
||||
|
||||
(print_intrinsic
|
||||
; Don't delimit the parentheses like parameter punctuation; they're optional
|
||||
; for `print`.
|
||||
"print" @support.function.print.php)
|
||||
|
||||
; The list of standard library methods in `php.cson` is… a lot. This is my
|
||||
; biased attempt to pare it down to the most important functions.
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function._TEXT_.php
|
||||
(#match? @support.function._TEXT_.php "^(isset|eval|empty)$")
|
||||
(#set! capture.final))
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function.array.php
|
||||
(#match? @support.function.array.php "^(shuffle|sizeof|sort|next|nat(case)?sort|count|compact|current|in_array|usort|uksort|uasort|pos|prev|end|each|extract|ksort|key(_exists)?|krsort|list|asort|arsort|rsort|reset|range|array(_(shift|sum|splice|search|slice|chunk|change_key_case|count_values|column|combine|(diff|intersect)(_(u)?(key|assoc))?|u(diff|intersect)(_(u)?assoc)?|unshift|unique|pop|push|pad|product|values|keys|key_exists|filter|fill(_keys)?|flip|walk(_recursive)?|reduce|replace(_recursive)?|reverse|rand|multisort|merge(_recursive)?|map)?))$"))
|
||||
@ -31,10 +52,6 @@
|
||||
function: (name) @support.function.class-obj.php
|
||||
(#match? @support.function.class-obj.php "^(class_alias|all_user_method(_array)?|is_(a|subclass_of)|__autoload|(class|interface|method|property|trait)_exists|get_(class(_(vars|methods))?|(called|parent)_class|object_vars|declared_(classes|interfaces|traits)))$"))
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function.construct.php
|
||||
(#match? @support.function.construct.php "^(isset|unset|eval|empty)$"))
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function.construct.output.php
|
||||
(#match? @support.function.construct.output.php "^(print|echo)$"))
|
||||
@ -101,7 +118,7 @@
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function.math.php
|
||||
(#match? @support.function.math.php "^((a)?(cos|sin|tan)(h)?|sqrt|srand|hypot|hexdec|ceil|is_(nan|(in)?finite)|octdec|dec(hex|oct|bin)|deg2rad|pi|pow|exp(m1)?|floor|fmod|lcg_value|log(1(p|0))?|atan2|abs|round|rand|rad2deg|getrandmax|mt_(srand|rand|getrandmax)|max|min|bindec|base_convert)$"))
|
||||
(#match? @support.function.math.php "^((a)?(cos|sin|tan)(h)?|sqrt|srand|hypot|hexdec|ceil|is_(nan|(in)?finite)|octdec|dec(hex|oct|bin)|deg2rad|pi|pow|exp(m1)?|floor|f(mod|div)|lcg_value|log(1(p|0))?|atan2|abs|round|rand|rad2deg|getrandmax|mt_(srand|rand|getrandmax)|max|min|bindec|base_convert|intdiv)$"))
|
||||
|
||||
(function_call_expression
|
||||
function: (name) @support.function.mbstring.php
|
||||
@ -263,14 +280,15 @@
|
||||
(class_constant_access_expression . (name) @support.class.php)
|
||||
(class_constant_access_expression (name) @support.other.property.php .)
|
||||
|
||||
; The "Foo" and "bar" in "Foo::bar()".
|
||||
(scoped_call_expression
|
||||
scope: (name) @support.class.php
|
||||
name: (name) @support.other.function.method.static.php)
|
||||
|
||||
; The "Foo" and "$bar" in "Foo::$bar()".
|
||||
; The "Foo" in `Foo::bar()` and `Foo::$bar()`.
|
||||
(scoped_call_expression
|
||||
scope: (name) @support.class.php)
|
||||
|
||||
; The "bar" in `Foo::bar()`.
|
||||
(scoped_call_expression
|
||||
name: (name) @support.other.function.method.static.php)
|
||||
|
||||
; The "$bar" in `Foo::$bar()`.
|
||||
(scoped_call_expression
|
||||
name: (variable_name) @variable.other.method.static.php)
|
||||
|
||||
@ -300,6 +318,10 @@
|
||||
name: (variable_name) @variable.other.property.php
|
||||
(#set! capture.final true))
|
||||
|
||||
; The "Foo" in `new Foo();`.
|
||||
(object_creation_expression
|
||||
(name) @support.class.php)
|
||||
|
||||
|
||||
; TRAITS
|
||||
; ======
|
||||
@ -316,13 +338,17 @@
|
||||
; TYPES
|
||||
; =====
|
||||
|
||||
(primitive_type) @storage.type.builtin.php
|
||||
(cast_type) @storage.type.builtin.php
|
||||
(named_type (name) @storage.type.php)
|
||||
(named_type (qualified_name) @storage.type.php)
|
||||
; Primitive types are value types, hence are placed in `support.storage.type`.
|
||||
(primitive_type) @support.storage.type.builtin.php
|
||||
(cast_type) @support.storage.type.builtin.php
|
||||
|
||||
(named_type (name) @support.storage.type.php)
|
||||
(named_type (qualified_name) @support.storage.type.php)
|
||||
|
||||
; Acts as a modifier on all variables, regardless of value type, hence `storage.modifier`.
|
||||
"global" @storage.modifier.global.php
|
||||
|
||||
; Core language constructs go in `storage.type`.
|
||||
["enum" "interface" "trait" "class"] @storage.type._TYPE_.php
|
||||
(enum_case "case" @storage.type.case.php)
|
||||
"function" @storage.type.function.php
|
||||
@ -376,8 +402,10 @@
|
||||
((dynamic_variable_name) @punctuation.definition.variable.begin.php
|
||||
(#set! adjust.startBeforeFirstMatchOf "^\\}$"))
|
||||
|
||||
((name) @constant.other.php
|
||||
(#match? @constant.other.php "^_?[A-Z][A-Z\\d_]+$"))
|
||||
; ((name) @constant.other.php
|
||||
; (#match? @constant.other.php "^_?[A-Z][A-Z\\d_]+$"))
|
||||
|
||||
(const_declaration (const_element) @variable.other.constant.php)
|
||||
|
||||
((name) @constant.language.php
|
||||
(#match? @constant.language.php "^__[A-Z][A-Z\d_]+__$"))
|
||||
@ -483,11 +511,16 @@
|
||||
(#match? @punctuation.definition.comment.php "^#")
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "^#"))
|
||||
|
||||
; Don't highlight PHPDoc comments because the injection will handle them.
|
||||
; Capture these because the PHPDoc injection won't process them…
|
||||
((comment) @comment.block.documentation.php
|
||||
(#match? @comment.block.documentation.php "^/\\*\\*\\*"))
|
||||
|
||||
; …but otherwise leave this style of comment to be handled by PHPDoc.
|
||||
((comment) @_IGNORE_
|
||||
(#match? @_IGNORE_ "^/\\*\\*")
|
||||
(#set! capture.final true))
|
||||
|
||||
|
||||
((comment) @comment.block.php
|
||||
(#match? @comment.block.php "^/\\*(?!\\*)"))
|
||||
|
||||
@ -588,8 +621,10 @@
|
||||
|
||||
"{" @punctuation.definition.block.begin.bracket.curly.php
|
||||
"}" @punctuation.definition.block.end.bracket.curly.php
|
||||
"(" @punctuation.definition.begin.bracket.round.php
|
||||
")" @punctuation.definition.end.bracket.round.php
|
||||
("(" @punctuation.definition.begin.bracket.round.php
|
||||
(#set! capture.shy true))
|
||||
(")" @punctuation.definition.end.bracket.round.php
|
||||
(#set! capture.shy true))
|
||||
"[" @punctuation.definition.begin.bracket.square.php
|
||||
"]" @punctuation.definition.end.bracket.square.php
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
;
|
||||
|
||||
|
||||
["{" "(" "["] @indent
|
||||
["}" ")" "]"] @dedent
|
||||
|
||||
":" @indent
|
||||
; if ($foo):
|
||||
(colon_block ":" @indent)
|
||||
|
||||
["endif" "endfor" "endforeach" "enddeclare" "endswitch"] @dedent
|
||||
|
@ -5,7 +5,8 @@
|
||||
((document) @punctuation.definition.end.comment.phpdoc.php
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "(?:\\*)?\\*/$"))
|
||||
|
||||
(tag_name) @entity.name.tag.phpdoc.php
|
||||
(tag_name) @keyword.other.tag.phpdoc.php
|
||||
(primitive_type) @storage.type.primitive.phpdoc.php
|
||||
(named_type) @storage.type.instance.phpdoc.php
|
||||
(variable_name) @variable.other.phpdoc.php
|
||||
(uri) @markup.underline.link.phpdoc.php
|
||||
|
Binary file not shown.
@ -1,3 +1,83 @@
|
||||
const { Point, Range } = require('atom');
|
||||
|
||||
function isPhpDoc(node) {
|
||||
let { text } = node;
|
||||
return text.startsWith('/**') && !text.startsWith('/***')
|
||||
}
|
||||
|
||||
function comparePoints(a, b) {
|
||||
const rows = a.row - b.row;
|
||||
if (rows === 0) {
|
||||
return a.column - b.column;
|
||||
} else {
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
// Given a series of opening and closing PHP tags, pairs and groups them as a
|
||||
// series of node specs suitable for defining the bounds of an injection.
|
||||
function interpret(nodes) {
|
||||
let sorted = [...nodes].sort((a, b) => {
|
||||
return comparePoints(a.startPosition, b.startPosition);
|
||||
});
|
||||
|
||||
let ranges = [];
|
||||
let currentStart = null;
|
||||
let lastIndex = nodes.length - 1;
|
||||
|
||||
for (let [index, node] of sorted.entries()) {
|
||||
let isStart = node.type === 'php_tag';
|
||||
let isEnd = node.type === '?>';
|
||||
let isLast = index === lastIndex;
|
||||
|
||||
if (isStart) {
|
||||
if (currentStart) {
|
||||
throw new Error('Unbalanced content!');
|
||||
}
|
||||
currentStart = node;
|
||||
|
||||
if (isLast) {
|
||||
// There's no ending tag to match this starting tag. This is valid and
|
||||
// simply signifies that the rest of the file is PHP. We can return a
|
||||
// range from here to `Infinity` and let the language mode clip it to
|
||||
// the edge of the buffer.
|
||||
let spec = {
|
||||
startIndex: currentStart.startIndex,
|
||||
startPosition: currentStart.startPosition,
|
||||
endIndex: Infinity,
|
||||
endPosition: Point.INFINITY,
|
||||
range: new Range(
|
||||
currentStart.range.start,
|
||||
Point.INFINITY
|
||||
)
|
||||
};
|
||||
ranges.push(spec);
|
||||
currentStart = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnd) {
|
||||
if (!currentStart) {
|
||||
throw new Error('Unbalanced content!');
|
||||
}
|
||||
let spec = {
|
||||
startIndex: currentStart.startIndex,
|
||||
startPosition: currentStart.startPosition,
|
||||
endIndex: node.endIndex,
|
||||
endPosition: node.endPosition,
|
||||
range: new Range(
|
||||
currentStart.range.start,
|
||||
node.range.end
|
||||
)
|
||||
};
|
||||
ranges.push(spec);
|
||||
currentStart = null;
|
||||
}
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
exports.activate = function () {
|
||||
|
||||
// Here's how we handle the mixing of PHP and HTML:
|
||||
@ -45,67 +125,49 @@ exports.activate = function () {
|
||||
return 'internal-php';
|
||||
},
|
||||
content(node) {
|
||||
let results = [];
|
||||
// At the top level we should ignore `text` nodes, since they're just
|
||||
// HTML. We should also ignore the middle children of
|
||||
// `text_interpolation` nodes (also `text`), but we need to include their
|
||||
// first and last children, which correspond to `?>` and `<?php`.
|
||||
// The actual structure of the tree is utter chaos for us. The best way
|
||||
// to make sense of it is to grab all the delimiters of the ranges we're
|
||||
// interested in, sort them, pair them off, and turn them into fake
|
||||
// ranges. As long as we return objects with the range properties that
|
||||
// actual nodes have, _and_ we opt into `includeChildren` (so that it
|
||||
// doesn't try to read the `children` property to subtract child nodes'
|
||||
// ranges), this works just fine.
|
||||
//
|
||||
// In practice, it seems that `text` is always a child of the root except
|
||||
// inside of `text_interpolation`, and `text_interpolation` is always a
|
||||
// child of the root. The only exceptions I've noticed are when the tree
|
||||
// is in an error state, so they may not be worth worrying about.
|
||||
for (let child of node.children) {
|
||||
if (child.type === 'text') { continue; }
|
||||
if (child.type === 'text_interpolation') {
|
||||
for (let grandchild of child.children) {
|
||||
if (grandchild.type === 'text') { continue; }
|
||||
results.push(grandchild);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
results.push(child);
|
||||
}
|
||||
return results;
|
||||
// If you're ever skeptical about whether this is really the easiest way
|
||||
// to do this, fire up `tree-sitter-tools` and take a look at the
|
||||
// structure of a PHP file in `tree-sitter-php`. If you know of something
|
||||
// simpler, I'm all ears.
|
||||
//
|
||||
// TODO: This method should be allowed to return actual ordinary `Range`
|
||||
// instances, in which case we'd understand that no futher processing
|
||||
// need take place by the language mode.
|
||||
let boundaries = node.descendantsOfType(['php_tag', '?>']);
|
||||
return interpret(boundaries);
|
||||
},
|
||||
includeChildren: true,
|
||||
newlinesBetween: true,
|
||||
includeAdjacentWhitespace: true
|
||||
});
|
||||
newlinesBetween: false,
|
||||
// includeAdjacentWhitespace: true,
|
||||
|
||||
// TODOs and URLs
|
||||
// ==============
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
function isPhpDoc(node) {
|
||||
let { text } = node;
|
||||
return text.startsWith('/**') && !text.startsWith('/***')
|
||||
// For parity with the TextMate PHP grammar, we need to be able to scope
|
||||
// this region with not just `source.php` but also `meta.embedded.X.php`,
|
||||
// where X is one of `line` or `block` depending on whether the range spans
|
||||
// multiple lines.
|
||||
//
|
||||
// There is no way to do this via queries because there is no discrete node
|
||||
// against which we could conditionally add `meta.embedded.block` or
|
||||
// `meta.embedded.line`… because of the aforementioned lunacy of the tree
|
||||
// structure.
|
||||
//
|
||||
// So we had to invent a feature for it. When `languageScope` is a function,
|
||||
// it allows the injection to decide on a range-by-range basis what the
|
||||
// scope name is… _and_ it can return more than one scope name.
|
||||
languageScope(grammar, _buffer, range) {
|
||||
let extraScope = range.start.row !== range.end.row ?
|
||||
'meta.embedded.block.php' : 'meta.embedded.line.php';
|
||||
return [grammar.scopeName, extraScope];
|
||||
}
|
||||
|
||||
atom.grammars.addInjectionPoint('text.html.php', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
for (let type of ['comment', 'string_value']) {
|
||||
atom.grammars.addInjectionPoint('text.html.php', {
|
||||
type,
|
||||
language(node) {
|
||||
// PHPDoc can parse URLs better than we can.
|
||||
if (isPhpDoc(node)) return undefined;
|
||||
return HYPERLINK_PATTERN.test(node.text) ?
|
||||
'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
|
||||
// HEREDOCS and NOWDOCS
|
||||
// ====================
|
||||
@ -153,3 +215,19 @@ exports.activate = function () {
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// TODOs and URLs
|
||||
// ==============
|
||||
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('text.html.php', {
|
||||
types: ['comment', 'string_value'],
|
||||
language(node) {
|
||||
if (isPhpDoc(node)) return null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('text.html.php', { types: ['comment'] });
|
||||
};
|
||||
|
@ -8,5 +8,17 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
packages/language-php/spec/.eslintrc.js
Normal file
13
packages/language-php/spec/.eslintrc.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
env: { jasmine: true },
|
||||
globals: {
|
||||
waitsForPromise: true,
|
||||
advanceClock: true
|
||||
},
|
||||
rules: {
|
||||
"node/no-unpublished-require": "off",
|
||||
"node/no-extraneous-require": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-empty": "off"
|
||||
}
|
||||
};
|
@ -27,8 +27,7 @@ fileTypes: [
|
||||
]
|
||||
|
||||
treeSitter:
|
||||
# Built from tree-sitter-python 62827156d01c74dc1538266344e788da74536b8a
|
||||
# to add support for `match` statements.
|
||||
parserSource: 'github:tree-sitter/tree-sitter-python#4bfdd9033a2225cc95032ce77066b7aeca9e2efc'
|
||||
grammar: 'ts/tree-sitter-python.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
||||
tagsQuery: 'ts/tags.scm'
|
||||
|
@ -187,24 +187,27 @@
|
||||
; similarly here. No need to account for the rawness of a string in the scope
|
||||
; name unless someone requests that feature.
|
||||
|
||||
((string) @string.quoted.triple.block.format.python
|
||||
(#match? @string.quoted.triple.block.format.python "^[fFrR]+\"\"\"")
|
||||
(#set! capture.final))
|
||||
|
||||
((string) @string.quoted.triple.block.python
|
||||
(#match? @string.quoted.triple.block.python "^[bBrRuU]*\"\"\""))
|
||||
|
||||
((string) @string.quoted.triple.block.format.python
|
||||
(#match? @string.quoted.triple.block.format.python "^[fFrR]*\"\"\""))
|
||||
((string) @string.quoted.double.single-line.format.python
|
||||
(#match? @string.quoted.double.single-line.format.python "^[fFrR]+\"")
|
||||
(#set! capture.final))
|
||||
|
||||
((string) @string.quoted.double.single-line.python
|
||||
(#match? @string.quoted.double.single-line.python "^[bBrRuU]*\"(?!\")"))
|
||||
|
||||
((string) @string.quoted.double.single-line.format.python
|
||||
(#match? @string.quoted.double.single-line.format.python "^[fFrR]*\""))
|
||||
((string) @string.quoted.single.single-line.format.python
|
||||
(#match? @string.quoted.single.single-line.format.python "^[fFrR]+?\'")
|
||||
(#set! capture.final))
|
||||
|
||||
((string) @string.quoted.single.single-line.python
|
||||
(#match? @string.quoted.single.single-line.python "^[bBrRuU]*\'"))
|
||||
|
||||
((string) @string.quoted.single.single-line.format.python
|
||||
(#match? @string.quoted.single.single-line.format.python "^[fFrR]*?\'"))
|
||||
|
||||
(string_content (escape_sequence) @constant.character.escape.python)
|
||||
|
||||
(interpolation
|
||||
@ -219,7 +222,7 @@
|
||||
_ @punctuation.definition.string.end.python
|
||||
(#is? test.last true))
|
||||
|
||||
(string prefix: _ @storage.type.string.python
|
||||
(string (string_start) @storage.type.string.python
|
||||
(#match? @storage.type.string.python "^[bBfFrRuU]+")
|
||||
(#set! adjust.endAfterFirstMatchOf "^[bBfFrRuU]+"))
|
||||
|
||||
@ -255,6 +258,7 @@
|
||||
] @keyword.control.statement._TYPE_.python
|
||||
|
||||
[
|
||||
"break"
|
||||
"continue"
|
||||
"for"
|
||||
"while"
|
||||
@ -393,6 +397,9 @@
|
||||
"or"
|
||||
] @keyword.operator.logical._TYPE_.python
|
||||
|
||||
; The 'not' and 'in' are each scoped separately, each one being an anonymous
|
||||
; node incorrectly named "not in".
|
||||
"not in" @keyword.operator.logical.not-in.python
|
||||
"is not" @keyword.operator.logical.is-not.python
|
||||
|
||||
(call
|
||||
|
Binary file not shown.
@ -1,30 +1,6 @@
|
||||
exports.activate = function () {
|
||||
if (!atom.grammars.addInjectionPoint) return;
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
|
||||
atom.grammars.addInjectionPoint('source.python', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
for (let type of ['comment', 'string']) {
|
||||
atom.grammars.addInjectionPoint('source.python', {
|
||||
type,
|
||||
language(node) {
|
||||
return HYPERLINK_PATTERN.test(node.text) ?
|
||||
'hyperlink' : undefined;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: There's no regex literal in Python. The TM-style grammar has a
|
||||
// very obscure option that, when enabled, assumes all raw strings are
|
||||
// regexes and highlights them accordingly. This might be worth doing in the
|
||||
@ -42,3 +18,13 @@ exports.activate = function () {
|
||||
// languageScope: null
|
||||
// });
|
||||
}
|
||||
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.python', {
|
||||
types: ['comment', 'string_content']
|
||||
});
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.python', { types: ['comment'] });
|
||||
};
|
||||
|
@ -15,5 +15,17 @@
|
||||
"dependencies": {
|
||||
"atom-grammar-test": "^0.6.4",
|
||||
"tree-sitter-python": "0.19.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"hyperlink.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeHyperlinkInjection"
|
||||
}
|
||||
},
|
||||
"todo.injection": {
|
||||
"versions": {
|
||||
"0.1.0": "consumeTodoInjection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
scopeName: 'source.rb.regexp'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-regex'
|
||||
|
||||
injectionRegex: '^(rb-regex)$'
|
||||
|
||||
treeSitter:
|
||||
parserSource: 'github:tree-sitter/tree-sitter-regex#2354482d7e2e8f8ff33c1ef6c8aa5690410fbc96'
|
||||
grammar: 'tree-sitter-regex/tree-sitter-regex.wasm'
|
||||
highlightsQuery: 'tree-sitter-regex/highlights.scm'
|
@ -6,12 +6,13 @@ parser: 'tree-sitter-ruby'
|
||||
injectionRegex: 'rb|ruby|RB|RUBY'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'ts/grammar.wasm'
|
||||
highlightsQuery: 'ts/highlights.scm'
|
||||
localsQuery: 'ts/locals.scm'
|
||||
foldsQuery: 'ts/folds.scm'
|
||||
indentsQuery: 'ts/indents.scm'
|
||||
tagsQuery: 'ts/tags.scm'
|
||||
parserSource: 'github:tree-sitter/tree-sitter-ruby#4d9ad3f010fdc47a8433adcf9ae30c8eb8475ae7'
|
||||
grammar: 'tree-sitter-ruby/tree-sitter-ruby.wasm'
|
||||
highlightsQuery: 'tree-sitter-ruby/highlights.scm'
|
||||
localsQuery: 'tree-sitter-ruby/locals.scm'
|
||||
foldsQuery: 'tree-sitter-ruby/folds.scm'
|
||||
indentsQuery: 'tree-sitter-ruby/indents.scm'
|
||||
tagsQuery: 'tree-sitter-ruby/tags.scm'
|
||||
|
||||
firstLineRegex: [
|
||||
# shebang line
|
@ -1,13 +0,0 @@
|
||||
scopeName: 'source.regexp'
|
||||
type: 'modern-tree-sitter'
|
||||
parser: 'tree-sitter-regex'
|
||||
|
||||
# TODO: Decide whether to have one regex grammar that's shared among grammars
|
||||
# _or_ one separate instance of a tree-sitter-regex grammar for each language.
|
||||
# In the latter case, they could still share the same `wasm` file and perhaps
|
||||
# differ only in the query files.
|
||||
injectionRegex: '^(rb-regex)$'
|
||||
|
||||
treeSitter:
|
||||
grammar: 'ts/regex/tree-sitter-regex.wasm'
|
||||
highlightsQuery: 'ts/regex/highlights.scm'
|
@ -0,0 +1,50 @@
|
||||
(non_capturing_group) @meta.group.non-capturing.regexp
|
||||
|
||||
[
|
||||
(anonymous_capturing_group)
|
||||
] @meta.group.capturing.regexp
|
||||
|
||||
[
|
||||
(identity_escape)
|
||||
(control_escape)
|
||||
(character_class_escape)
|
||||
] @constant.character.escape.backslash.regexp
|
||||
|
||||
[
|
||||
(boundary_assertion)
|
||||
(start_assertion)
|
||||
(end_assertion)
|
||||
] @keyword.control.anchor.regexp
|
||||
|
||||
[
|
||||
(optional)
|
||||
(lazy)
|
||||
] @keyword.operator.quantifier.regexp
|
||||
|
||||
((lookaround_assertion) @keyword.operator.lookaround.regexp
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\?="))
|
||||
|
||||
((lookaround_assertion) @keyword.operator.lookaround.negated.regexp
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\?!"))
|
||||
|
||||
((non_capturing_group) @keyword.operator.group.non-capturing.regexp
|
||||
(#set! adjust.startAndEndAroundFirstMatchOf "\\?:"))
|
||||
|
||||
(anonymous_capturing_group
|
||||
"(" @punctuation.definition.group.begin.bracket.round.regexp
|
||||
")" @punctuation.definition.group.end.bracket.round.regexp
|
||||
(#set! capture.final true))
|
||||
|
||||
"|" @keyword.operator.or.regexp
|
||||
["*" "+"] @keyword.operator.quantifier.regexp
|
||||
|
||||
(character_class) @constant.other.character-class.set.regexp
|
||||
|
||||
(character_class
|
||||
"[" @punctuation.definition.character-class.begin.regexp)
|
||||
|
||||
(character_class
|
||||
"]" @punctuation.definition.character-class.end.regexp)
|
||||
|
||||
(character_class
|
||||
"^" @keyword.operator.negation.regexp)
|
BIN
packages/language-ruby/grammars/tree-sitter-regex/tree-sitter-regex.wasm
Executable file
BIN
packages/language-ruby/grammars/tree-sitter-regex/tree-sitter-regex.wasm
Executable file
Binary file not shown.
BIN
packages/language-ruby/grammars/tree-sitter-ruby/tree-sitter-ruby.wasm
Executable file
BIN
packages/language-ruby/grammars/tree-sitter-ruby/tree-sitter-ruby.wasm
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -24,33 +24,14 @@ exports.activate = function () {
|
||||
// coverShallowerScopes: false
|
||||
});
|
||||
|
||||
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
|
||||
const HYPERLINK_PATTERN = /\bhttps?:/
|
||||
};
|
||||
|
||||
atom.grammars.addInjectionPoint('source.ruby', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return TODO_PATTERN.test(node.text) ? 'todo' : null;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('source.ruby', {
|
||||
type: 'comment',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : null;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
});
|
||||
|
||||
atom.grammars.addInjectionPoint('source.ruby', {
|
||||
type: 'string_content',
|
||||
language: (node) => {
|
||||
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : null;
|
||||
},
|
||||
content: (node) => node,
|
||||
languageScope: null
|
||||
exports.consumeHyperlinkInjection = (hyperlink) => {
|
||||
hyperlink.addInjectionPoint('source.ruby', {
|
||||
types: ['comment', 'string_content']
|
||||
});
|
||||
};
|
||||
|
||||
exports.consumeTodoInjection = (todo) => {
|
||||
todo.addInjectionPoint('source.ruby', { types: ['comment'] });
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user