From 93ab0f7bf0fc2a1556bdff130fe9745aecbeccf0 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 13 Jan 2024 19:34:56 -0800 Subject: [PATCH] Convert all modern Tree-sitter TODO/hyperlink injections into services --- packages/language-c/lib/main.js | 37 ++++++-------- packages/language-c/package.json | 12 +++++ packages/language-css/lib/main.js | 39 ++++----------- packages/language-css/package.json | 12 +++++ packages/language-go/lib/main.js | 29 +++-------- packages/language-go/package.json | 12 +++++ packages/language-html/lib/main.js | 45 +++++------------ packages/language-html/package.json | 12 +++++ packages/language-html/spec/.eslintrc.js | 9 ++++ packages/language-hyperlink/lib/main.js | 33 ++++++++++++ packages/language-hyperlink/package.json | 10 +++- packages/language-hyperlink/spec/.eslintrc.js | 13 +++++ packages/language-java/lib/main.js | 28 +++-------- packages/language-java/package.json | 12 +++++ packages/language-javascript/lib/main.js | 39 +++------------ packages/language-javascript/package.json | 12 +++++ .../grammars/modern-tree-sitter-php.cson | 2 + packages/language-php/lib/main.js | 50 +++++++------------ packages/language-php/package.json | 14 +++++- packages/language-php/spec/.eslintrc.js | 13 +++++ packages/language-python/lib/main.js | 34 ++++--------- packages/language-python/package.json | 12 +++++ packages/language-ruby/lib/main.js | 35 +++---------- packages/language-ruby/package.json | 12 +++++ packages/language-rust-bundled/lib/main.js | 42 +++++++--------- packages/language-rust-bundled/package.json | 12 +++++ packages/language-shellscript/lib/main.js | 29 +++-------- packages/language-shellscript/package.json | 12 +++++ packages/language-todo/lib/main.js | 41 +++++++++++++++ packages/language-todo/package.json | 10 +++- packages/language-toml/lib/main.js | 28 +++-------- packages/language-toml/package.json | 12 +++++ packages/language-typescript/lib/main.js | 37 ++++++-------- packages/language-typescript/package.json | 12 +++++ packages/language-yaml/lib/main.js | 27 +++------- packages/language-yaml/package.json | 14 +++++- 36 files changed, 447 insertions(+), 355 deletions(-) create mode 100644 packages/language-html/spec/.eslintrc.js create mode 100644 packages/language-hyperlink/lib/main.js create mode 100644 packages/language-hyperlink/spec/.eslintrc.js create mode 100644 packages/language-php/spec/.eslintrc.js create mode 100644 packages/language-todo/lib/main.js diff --git a/packages/language-c/lib/main.js b/packages/language-c/lib/main.js index 6e432cd64..1ae428d1d 100644 --- a/packages/language-c/lib/main.js +++ b/packages/language-c/lib/main.js @@ -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'] }); } }; diff --git a/packages/language-c/package.json b/packages/language-c/package.json index 2b891a171..845d28471 100644 --- a/packages/language-c/package.json +++ b/packages/language-c/package.json @@ -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" + } + } } } diff --git a/packages/language-css/lib/main.js b/packages/language-css/lib/main.js index c12fb4b56..cf2d7837c 100644 --- a/packages/language-css/lib/main.js +++ b/packages/language-css/lib/main.js @@ -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'] }); }; diff --git a/packages/language-css/package.json b/packages/language-css/package.json index 96c2d0d7a..7e2d03d1b 100644 --- a/packages/language-css/package.json +++ b/packages/language-css/package.json @@ -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" + } + } } } diff --git a/packages/language-go/lib/main.js b/packages/language-go/lib/main.js index a74d32bef..50a8e11ff 100644 --- a/packages/language-go/lib/main.js +++ b/packages/language-go/lib/main.js @@ -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 - }); - } - - atom.grammars.addInjectionPoint('source.go', { - type: 'comment', - language(node) { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.go', { + types: ['comment', 'interpreted_string_literal', 'raw_string_literal'] }); - +}; + +exports.consumeTodoInjection = (todo) => { + todo.addInjectionPoint('source.go', { types: ['comment'] }); }; diff --git a/packages/language-go/package.json b/packages/language-go/package.json index 91bb8d0e0..01a1355f6 100644 --- a/packages/language-go/package.json +++ b/packages/language-go/package.json @@ -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" + } + } } } diff --git a/packages/language-html/lib/main.js b/packages/language-html/lib/main.js index 55cce8174..c0c230c9f 100644 --- a/packages/language-html/lib/main.js +++ b/packages/language-html/lib/main.js @@ -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'] }); +}; diff --git a/packages/language-html/package.json b/packages/language-html/package.json index e2fd7b41b..721353260 100644 --- a/packages/language-html/package.json +++ b/packages/language-html/package.json @@ -19,5 +19,17 @@ }, "devDependencies": { "dedent": "^0.7.0" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-html/spec/.eslintrc.js b/packages/language-html/spec/.eslintrc.js new file mode 100644 index 000000000..5226d6921 --- /dev/null +++ b/packages/language-html/spec/.eslintrc.js @@ -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" + } +}; diff --git a/packages/language-hyperlink/lib/main.js b/packages/language-hyperlink/lib/main.js new file mode 100644 index 000000000..54e310fee --- /dev/null +++ b/packages/language-hyperlink/lib/main.js @@ -0,0 +1,33 @@ +const HYPERLINK_PATTERN = /\bhttps?:/ + +module.exports = { + provideHyperlinkInjection() { + return { + test(node) { + return HYPERLINK_PATTERN.test(node.text); + }, + + 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 + }); + } + }, + } + } +}; diff --git a/packages/language-hyperlink/package.json b/packages/language-hyperlink/package.json index 676c2425f..9d1df06b3 100644 --- a/packages/language-hyperlink/package.json +++ b/packages/language-hyperlink/package.json @@ -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" + } + } + } } diff --git a/packages/language-hyperlink/spec/.eslintrc.js b/packages/language-hyperlink/spec/.eslintrc.js new file mode 100644 index 000000000..77888e061 --- /dev/null +++ b/packages/language-hyperlink/spec/.eslintrc.js @@ -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" + } +}; diff --git a/packages/language-java/lib/main.js b/packages/language-java/lib/main.js index a1e953a7a..59f36c832 100644 --- a/packages/language-java/lib/main.js +++ b/packages/language-java/lib/main.js @@ -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'] }); }; diff --git a/packages/language-java/package.json b/packages/language-java/package.json index f330983e5..11667e670 100644 --- a/packages/language-java/package.json +++ b/packages/language-java/package.json @@ -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" + } + } } } diff --git a/packages/language-javascript/lib/main.js b/packages/language-javascript/lib/main.js index ed04e1978..015c289b6 100644 --- a/packages/language-javascript/lib/main.js +++ b/packages/language-javascript/lib/main.js @@ -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; diff --git a/packages/language-javascript/package.json b/packages/language-javascript/package.json index 5f8c71c82..52de09034 100644 --- a/packages/language-javascript/package.json +++ b/packages/language-javascript/package.json @@ -16,5 +16,17 @@ "tree-sitter-javascript": "0.19.0", "tree-sitter-jsdoc": "0.19.0", "tree-sitter-regex": "0.19.0" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-php/grammars/modern-tree-sitter-php.cson b/packages/language-php/grammars/modern-tree-sitter-php.cson index 01b82d73c..7469b6cdc 100644 --- a/packages/language-php/grammars/modern-tree-sitter-php.cson +++ b/packages/language-php/grammars/modern-tree-sitter-php.cson @@ -9,4 +9,6 @@ injectionRegex: '^(internal-php)$' treeSitter: parserSource: 'github:tree-sitter/tree-sitter-php#594b8bad093abe739c3d2a2cae5abae33c5fb23d' grammar: 'tree-sitter/tree-sitter-php.wasm' + # TODO: This shouldn't be necessary. Investigate why a `highlightsQuery` is + # still required. highlightsQuery: 'tree-sitter/queries/empty.scm' diff --git a/packages/language-php/lib/main.js b/packages/language-php/lib/main.js index bc8b18c34..d6e59ed7e 100644 --- a/packages/language-php/lib/main.js +++ b/packages/language-php/lib/main.js @@ -1,3 +1,8 @@ +function isPhpDoc(node) { + let { text } = node; + return text.startsWith('/**') && !text.startsWith('/***') +} + exports.activate = function () { // Here's how we handle the mixing of PHP and HTML: @@ -76,36 +81,6 @@ exports.activate = function () { // 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('/***') - } - - 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 // ==================== @@ -141,7 +116,7 @@ exports.activate = function () { // PHPDoc // ====== - + atom.grammars.addInjectionPoint('text.html.php', { type: 'comment', language(node) { @@ -153,3 +128,16 @@ exports.activate = function () { }); }; + +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'] }); +}; diff --git a/packages/language-php/package.json b/packages/language-php/package.json index 2b3e7aa3c..011bba7ae 100644 --- a/packages/language-php/package.json +++ b/packages/language-php/package.json @@ -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" + } + } + } } diff --git a/packages/language-php/spec/.eslintrc.js b/packages/language-php/spec/.eslintrc.js new file mode 100644 index 000000000..77888e061 --- /dev/null +++ b/packages/language-php/spec/.eslintrc.js @@ -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" + } +}; diff --git a/packages/language-python/lib/main.js b/packages/language-python/lib/main.js index 3d5a1fbed..a1f13423a 100644 --- a/packages/language-python/lib/main.js +++ b/packages/language-python/lib/main.js @@ -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'] }); +}; diff --git a/packages/language-python/package.json b/packages/language-python/package.json index d35fac18d..364d49faf 100644 --- a/packages/language-python/package.json +++ b/packages/language-python/package.json @@ -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" + } + } } } diff --git a/packages/language-ruby/lib/main.js b/packages/language-ruby/lib/main.js index 5f343a42f..de523dfb6 100644 --- a/packages/language-ruby/lib/main.js +++ b/packages/language-ruby/lib/main.js @@ -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'] }); +}; diff --git a/packages/language-ruby/package.json b/packages/language-ruby/package.json index 56e9c2a0d..b24fb4926 100644 --- a/packages/language-ruby/package.json +++ b/packages/language-ruby/package.json @@ -18,5 +18,17 @@ }, "devDependencies": { "dedent": "^0.7.0" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-rust-bundled/lib/main.js b/packages/language-rust-bundled/lib/main.js index e4dc9d244..33f19c5e6 100644 --- a/packages/language-rust-bundled/lib/main.js +++ b/packages/language-rust-bundled/lib/main.js @@ -13,29 +13,21 @@ exports.activate = function () { coverShallowerScopes: true }); } - - 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 ['line_comment', 'block_comment']) { - atom.grammars.addInjectionPoint('source.rust', { - type, - language: (node) => { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null - }); - } - - for (let type of ['string_literal', 'raw_string_literal', 'line_comment', 'block_comment']) { - atom.grammars.addInjectionPoint('source.rust', { - type, - language: (node) => { - return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined; - }, - content: (node) => node, - languageScope: null - }); - } +}; + +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.rust', { + types: [ + 'line_comment', + 'block_comment', + 'string_literal', + 'raw_string_literal' + ] + }); +}; + +exports.consumeTodoInjection = (todo) => { + todo.addInjectionPoint('source.rust', { + types: ['line_comment', 'block_comment'] + }); }; diff --git a/packages/language-rust-bundled/package.json b/packages/language-rust-bundled/package.json index 603b2c602..fae238b76 100644 --- a/packages/language-rust-bundled/package.json +++ b/packages/language-rust-bundled/package.json @@ -16,5 +16,17 @@ "engines": { "atom": ">=1.0.0 <2.0.0", "node": ">=12" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-shellscript/lib/main.js b/packages/language-shellscript/lib/main.js index e2eb7368a..706fc91f0 100644 --- a/packages/language-shellscript/lib/main.js +++ b/packages/language-shellscript/lib/main.js @@ -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?:/ - - atom.grammars.addInjectionPoint('source.shell', { - type: 'comment', - language: (node) => { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.shell', { + types: ['comment'] }); - - atom.grammars.addInjectionPoint('source.shell', { - type: 'comment', - language(node) { - return HYPERLINK_PATTERN.test(node.text) ? - 'hyperlink' : undefined; - }, - content: (node) => node, - languageScope: null - }); - +}; + +exports.consumeTodoInjection = (todo) => { + todo.addInjectionPoint('source.shell', { types: ['comment'] }); }; diff --git a/packages/language-shellscript/package.json b/packages/language-shellscript/package.json index 47fa9bc27..0c352b7ef 100644 --- a/packages/language-shellscript/package.json +++ b/packages/language-shellscript/package.json @@ -14,5 +14,17 @@ "license": "MIT", "dependencies": { "tree-sitter-bash": "0.19.0" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-todo/lib/main.js b/packages/language-todo/lib/main.js new file mode 100644 index 000000000..bcbe56306 --- /dev/null +++ b/packages/language-todo/lib/main.js @@ -0,0 +1,41 @@ +const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/; + +module.exports = { + provideTodoInjection() { + return { + test(node) { + return TODO_PATTERN.test(node.text); + }, + + // 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 nodes 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. + 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 TODO_PATTERN.test(node.text) ? 'todo' : undefined; + }, + content(node) { + return options.content ? options.content(node) : node; + }, + languageScope: null + }); + } + } + }; + } +}; diff --git a/packages/language-todo/package.json b/packages/language-todo/package.json index ef6be0a45..074634e69 100644 --- a/packages/language-todo/package.json +++ b/packages/language-todo/package.json @@ -1,11 +1,19 @@ { "name": "language-todo", "version": "0.29.4", + "main": "lib/main", "description": "TODO/FIXME highlighting support in Atom", "engines": { "atom": "*", "node": ">=14" }, "repository": "https://github.com/pulsar-edit/pulsar", - "license": "MIT" + "license": "MIT", + "providedServices": { + "todo.injection": { + "versions": { + "0.1.0": "provideTodoInjection" + } + } + } } diff --git a/packages/language-toml/lib/main.js b/packages/language-toml/lib/main.js index db2280423..efe8b29c1 100644 --- a/packages/language-toml/lib/main.js +++ b/packages/language-toml/lib/main.js @@ -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.toml', { - type: 'string', - language(node) { - return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined; - }, - content: (node) => node, - languageScope: null +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.toml', { + types: ['comment', 'string'] }); - - atom.grammars.addInjectionPoint('source.toml', { - type: 'comment', - language(node) { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null - }); - +}; + +exports.consumeTodoInjection = (todo) => { + todo.addInjectionPoint('source.toml', { types: ['comment'] }); }; diff --git a/packages/language-toml/package.json b/packages/language-toml/package.json index 0436a7eb8..2752ad583 100644 --- a/packages/language-toml/package.json +++ b/packages/language-toml/package.json @@ -11,5 +11,17 @@ }, "devDependencies": { "tree-sitter-toml": "^0.5.1" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-typescript/lib/main.js b/packages/language-typescript/lib/main.js index dd7f40051..0972cf8be 100644 --- a/packages/language-typescript/lib/main.js +++ b/packages/language-typescript/lib/main.js @@ -65,31 +65,24 @@ exports.activate = function () { }, languageScope: null }); - - atom.grammars.addInjectionPoint(scopeName, { - type: 'comment', - language: (node) => { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null - }); - - for (let type of ['template_string', 'string_fragment', 'comment']) { - atom.grammars.addInjectionPoint(scopeName, { - type, - language: (node) => { - return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined; - }, - content: (node) => node, - languageScope: null - }); - } } }; -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?:/ +exports.consumeHyperlinkInjection = (hyperlink) => { + for (const scopeName of ['source.ts', 'source.tsx', 'source.flow']) { + hyperlink.addInjectionPoint(scopeName, { + types: ['template_string', 'string_fragment', 'comment'] + }); + } +}; + +exports.consumeTodoInjection = (todo) => { + for (const scopeName of ['source.ts', 'source.tsx', 'source.flow']) { + todo.addInjectionPoint(scopeName, { types: ['comment'] }); + } +}; + + const STYLED_REGEX = /\bstyled\b/i; function languageStringForTemplateTag(tag) { diff --git a/packages/language-typescript/package.json b/packages/language-typescript/package.json index bf01bce0f..823dfd0e9 100644 --- a/packages/language-typescript/package.json +++ b/packages/language-typescript/package.json @@ -14,5 +14,17 @@ "license": "MIT", "dependencies": { "tree-sitter-typescript": "0.20.1" + }, + "consumedServices": { + "hyperlink.injection": { + "versions": { + "0.1.0": "consumeHyperlinkInjection" + } + }, + "todo.injection": { + "versions": { + "0.1.0": "consumeTodoInjection" + } + } } } diff --git a/packages/language-yaml/lib/main.js b/packages/language-yaml/lib/main.js index deab0a708..793695407 100644 --- a/packages/language-yaml/lib/main.js +++ b/packages/language-yaml/lib/main.js @@ -1,23 +1,10 @@ -exports.activate = () => { - const HYPERLINK_PATTERN = /\bhttps?:/ - const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/; - atom.grammars.addInjectionPoint('source.yaml', { - type: 'comment', - language: (node) => { - return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined; - }, - content: (node) => node, - languageScope: null +exports.consumeHyperlinkInjection = (hyperlink) => { + hyperlink.addInjectionPoint('source.yaml', { + types: ['comment'] }); - - atom.grammars.addInjectionPoint('source.yaml', { - type: 'comment', - language: (node) => { - return TODO_PATTERN.test(node.text) ? 'todo' : undefined; - }, - content: (node) => node, - languageScope: null - }); - +}; + +exports.consumeTodoInjection = (todo) => { + todo.addInjectionPoint('source.yaml', { types: ['comment'] }); }; diff --git a/packages/language-yaml/package.json b/packages/language-yaml/package.json index 47957ef42..52fc83dfb 100644 --- a/packages/language-yaml/package.json +++ b/packages/language-yaml/package.json @@ -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" + } + } + } }