mirror of
https://github.com/kristoferssolo/solorice.git
synced 2025-10-21 20:10:34 +00:00
290 lines
13 KiB
JavaScript
290 lines
13 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.Parser = void 0;
|
|
const vscode = require("vscode");
|
|
class Parser {
|
|
/**
|
|
* Creates a new instance of the Parser class
|
|
* @param configuration
|
|
*/
|
|
constructor(config) {
|
|
this.tags = [];
|
|
this.expression = "";
|
|
this.delimiter = "";
|
|
this.blockCommentStart = "";
|
|
this.blockCommentEnd = "";
|
|
this.highlightSingleLineComments = true;
|
|
this.highlightMultilineComments = false;
|
|
this.highlightJSDoc = false;
|
|
// * this will allow plaintext files to show comment highlighting if switched on
|
|
this.isPlainText = false;
|
|
// * this is used to prevent the first line of the file (specifically python) from coloring like other comments
|
|
this.ignoreFirstLine = false;
|
|
// * this is used to trigger the events when a supported language code is found
|
|
this.supportedLanguage = true;
|
|
// Read from the package.json
|
|
this.contributions = vscode.workspace.getConfiguration('better-comments');
|
|
this.configuration = config;
|
|
this.setTags();
|
|
}
|
|
/**
|
|
* Sets the regex to be used by the matcher based on the config specified in the package.json
|
|
* @param languageCode The short code of the current language
|
|
* https://code.visualstudio.com/docs/languages/identifiers
|
|
*/
|
|
SetRegex(languageCode) {
|
|
this.setDelimiter(languageCode);
|
|
// if the language isn't supported, we don't need to go any further
|
|
if (!this.supportedLanguage) {
|
|
return;
|
|
}
|
|
let characters = [];
|
|
for (let commentTag of this.tags) {
|
|
characters.push(commentTag.escapedTag);
|
|
}
|
|
if (this.isPlainText && this.contributions.highlightPlainText) {
|
|
// start by tying the regex to the first character in a line
|
|
this.expression = "(^)+([ \\t]*[ \\t]*)";
|
|
}
|
|
else {
|
|
// start by finding the delimiter (//, --, #, ') with optional spaces or tabs
|
|
this.expression = "(" + this.delimiter + ")+( |\t)*";
|
|
}
|
|
// Apply all configurable comment start tags
|
|
this.expression += "(";
|
|
this.expression += characters.join("|");
|
|
this.expression += ")+(.*)";
|
|
}
|
|
/**
|
|
* Finds all single line comments delimited by a given delimiter and matching tags specified in package.json
|
|
* @param activeEditor The active text editor containing the code document
|
|
*/
|
|
FindSingleLineComments(activeEditor) {
|
|
// If highlight single line comments is off, single line comments are not supported for this language
|
|
if (!this.highlightSingleLineComments)
|
|
return;
|
|
let text = activeEditor.document.getText();
|
|
// if it's plain text, we have to do mutliline regex to catch the start of the line with ^
|
|
let regexFlags = (this.isPlainText) ? "igm" : "ig";
|
|
let regEx = new RegExp(this.expression, regexFlags);
|
|
let match;
|
|
while (match = regEx.exec(text)) {
|
|
let startPos = activeEditor.document.positionAt(match.index);
|
|
let endPos = activeEditor.document.positionAt(match.index + match[0].length);
|
|
let range = { range: new vscode.Range(startPos, endPos) };
|
|
// Required to ignore the first line of .py files (#61)
|
|
if (this.ignoreFirstLine && startPos.line === 0 && startPos.character === 0) {
|
|
continue;
|
|
}
|
|
// Find which custom delimiter was used in order to add it to the collection
|
|
let matchTag = this.tags.find(item => item.tag.toLowerCase() === match[3].toLowerCase());
|
|
if (matchTag) {
|
|
matchTag.ranges.push(range);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Finds block comments as indicated by start and end delimiter
|
|
* @param activeEditor The active text editor containing the code document
|
|
*/
|
|
FindBlockComments(activeEditor) {
|
|
// If highlight multiline is off in package.json or doesn't apply to his language, return
|
|
if (!this.highlightMultilineComments)
|
|
return;
|
|
let text = activeEditor.document.getText();
|
|
// Build up regex matcher for custom delimiter tags
|
|
let characters = [];
|
|
for (let commentTag of this.tags) {
|
|
characters.push(commentTag.escapedTag);
|
|
}
|
|
// Combine custom delimiters and the rest of the comment block matcher
|
|
let commentMatchString = "(^)+([ \\t]*[ \\t]*)(";
|
|
commentMatchString += characters.join("|");
|
|
commentMatchString += ")([ ]*|[:])+([^*/][^\\r\\n]*)";
|
|
// Use start and end delimiters to find block comments
|
|
let regexString = "(^|[ \\t])(";
|
|
regexString += this.blockCommentStart;
|
|
regexString += "[\\s])+([\\s\\S]*?)(";
|
|
regexString += this.blockCommentEnd;
|
|
regexString += ")";
|
|
let regEx = new RegExp(regexString, "gm");
|
|
let commentRegEx = new RegExp(commentMatchString, "igm");
|
|
// Find the multiline comment block
|
|
let match;
|
|
while (match = regEx.exec(text)) {
|
|
let commentBlock = match[0];
|
|
// Find the line
|
|
let line;
|
|
while (line = commentRegEx.exec(commentBlock)) {
|
|
let startPos = activeEditor.document.positionAt(match.index + line.index + line[2].length);
|
|
let endPos = activeEditor.document.positionAt(match.index + line.index + line[0].length);
|
|
let range = { range: new vscode.Range(startPos, endPos) };
|
|
// Find which custom delimiter was used in order to add it to the collection
|
|
let matchString = line[3];
|
|
let matchTag = this.tags.find(item => item.tag.toLowerCase() === matchString.toLowerCase());
|
|
if (matchTag) {
|
|
matchTag.ranges.push(range);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Finds all multiline comments starting with "*"
|
|
* @param activeEditor The active text editor containing the code document
|
|
*/
|
|
FindJSDocComments(activeEditor) {
|
|
// If highlight multiline is off in package.json or doesn't apply to his language, return
|
|
if (!this.highlightMultilineComments && !this.highlightJSDoc)
|
|
return;
|
|
let text = activeEditor.document.getText();
|
|
// Build up regex matcher for custom delimiter tags
|
|
let characters = [];
|
|
for (let commentTag of this.tags) {
|
|
characters.push(commentTag.escapedTag);
|
|
}
|
|
// Combine custom delimiters and the rest of the comment block matcher
|
|
let commentMatchString = "(^)+([ \\t]*\\*[ \\t]*)("; // Highlight after leading *
|
|
let regEx = /(^|[ \t])(\/\*\*)+([\s\S]*?)(\*\/)/gm; // Find rows of comments matching pattern /** */
|
|
commentMatchString += characters.join("|");
|
|
commentMatchString += ")([ ]*|[:])+([^*/][^\\r\\n]*)";
|
|
let commentRegEx = new RegExp(commentMatchString, "igm");
|
|
// Find the multiline comment block
|
|
let match;
|
|
while (match = regEx.exec(text)) {
|
|
let commentBlock = match[0];
|
|
// Find the line
|
|
let line;
|
|
while (line = commentRegEx.exec(commentBlock)) {
|
|
let startPos = activeEditor.document.positionAt(match.index + line.index + line[2].length);
|
|
let endPos = activeEditor.document.positionAt(match.index + line.index + line[0].length);
|
|
let range = { range: new vscode.Range(startPos, endPos) };
|
|
// Find which custom delimiter was used in order to add it to the collection
|
|
let matchString = line[3];
|
|
let matchTag = this.tags.find(item => item.tag.toLowerCase() === matchString.toLowerCase());
|
|
if (matchTag) {
|
|
matchTag.ranges.push(range);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Apply decorations after finding all relevant comments
|
|
* @param activeEditor The active text editor containing the code document
|
|
*/
|
|
ApplyDecorations(activeEditor) {
|
|
for (let tag of this.tags) {
|
|
activeEditor.setDecorations(tag.decoration, tag.ranges);
|
|
// clear the ranges for the next pass
|
|
tag.ranges.length = 0;
|
|
}
|
|
}
|
|
//#region Private Methods
|
|
/**
|
|
* Sets the comment delimiter [//, #, --, '] of a given language
|
|
* @param languageCode The short code of the current language
|
|
* https://code.visualstudio.com/docs/languages/identifiers
|
|
*/
|
|
setDelimiter(languageCode) {
|
|
this.supportedLanguage = false;
|
|
this.ignoreFirstLine = false;
|
|
this.isPlainText = false;
|
|
const config = this.configuration.GetCommentConfiguration(languageCode);
|
|
if (config) {
|
|
let blockCommentStart = config.blockComment ? config.blockComment[0] : null;
|
|
let blockCommentEnd = config.blockComment ? config.blockComment[1] : null;
|
|
this.setCommentFormat(config.lineComment || blockCommentStart, blockCommentStart, blockCommentEnd);
|
|
this.supportedLanguage = true;
|
|
}
|
|
switch (languageCode) {
|
|
case "apex":
|
|
case "javascript":
|
|
case "javascriptreact":
|
|
case "typescript":
|
|
case "typescriptreact":
|
|
this.highlightJSDoc = true;
|
|
break;
|
|
case "elixir":
|
|
case "python":
|
|
case "tcl":
|
|
this.ignoreFirstLine = true;
|
|
break;
|
|
case "plaintext":
|
|
this.isPlainText = true;
|
|
// If highlight plaintext is enabled, this is a supported language
|
|
this.supportedLanguage = this.contributions.highlightPlainText;
|
|
break;
|
|
}
|
|
}
|
|
/**
|
|
* Sets the highlighting tags up for use by the parser
|
|
*/
|
|
setTags() {
|
|
let items = this.contributions.tags;
|
|
for (let item of items) {
|
|
let options = { color: item.color, backgroundColor: item.backgroundColor };
|
|
// ? the textDecoration is initialised to empty so we can concat a preceeding space on it
|
|
options.textDecoration = "";
|
|
if (item.strikethrough) {
|
|
options.textDecoration += "line-through";
|
|
}
|
|
if (item.underline) {
|
|
options.textDecoration += " underline";
|
|
}
|
|
if (item.bold) {
|
|
options.fontWeight = "bold";
|
|
}
|
|
if (item.italic) {
|
|
options.fontStyle = "italic";
|
|
}
|
|
let escapedSequence = item.tag.replace(/([()[{*+.$^\\|?])/g, '\\$1');
|
|
this.tags.push({
|
|
tag: item.tag,
|
|
escapedTag: escapedSequence.replace(/\//gi, "\\/"),
|
|
ranges: [],
|
|
decoration: vscode.window.createTextEditorDecorationType(options)
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Escapes a given string for use in a regular expression
|
|
* @param input The input string to be escaped
|
|
* @returns {string} The escaped string
|
|
*/
|
|
escapeRegExp(input) {
|
|
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
}
|
|
/**
|
|
* Set up the comment format for single and multiline highlighting
|
|
* @param singleLine The single line comment delimiter. If NULL, single line is not supported
|
|
* @param start The start delimiter for block comments
|
|
* @param end The end delimiter for block comments
|
|
*/
|
|
setCommentFormat(singleLine, start = null, end = null) {
|
|
this.delimiter = "";
|
|
this.blockCommentStart = "";
|
|
this.blockCommentEnd = "";
|
|
// If no single line comment delimiter is passed, single line comments are not supported
|
|
if (singleLine) {
|
|
if (typeof singleLine === 'string') {
|
|
this.delimiter = this.escapeRegExp(singleLine).replace(/\//ig, "\\/");
|
|
}
|
|
else if (singleLine.length > 0) {
|
|
// * if multiple delimiters are passed, the language has more than one single line comment format
|
|
var delimiters = singleLine
|
|
.map(s => this.escapeRegExp(s))
|
|
.join("|");
|
|
this.delimiter = delimiters;
|
|
}
|
|
}
|
|
else {
|
|
this.highlightSingleLineComments = false;
|
|
}
|
|
if (start && end) {
|
|
this.blockCommentStart = this.escapeRegExp(start);
|
|
this.blockCommentEnd = this.escapeRegExp(end);
|
|
this.highlightMultilineComments = this.contributions.multilineComments;
|
|
}
|
|
}
|
|
}
|
|
exports.Parser = Parser;
|
|
//# sourceMappingURL=parser.js.map
|