Reputation: 2247
Is it possible to query if the current line is a comment using the VSCode API ?
Upvotes: 10
Views: 843
Reputation: 462
This solution is not optimal, but it works.
Taken from: https://github.com/aaron-bond/better-comments/pull/302/commits/47717e7ddcf110cb7cd2a7902ccc98ab146f97a5
You can generate a configuration file that lists all the language specific keywords/symbols from the currently installed extensions.
Then use this file to get the comment configuration and thus the comment delimiters (for line comment and comment blocks).
I implemented a class for doing this, borrowing from the above commit:
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
interface CommentConfig {
lineComment?: string;
blockComment?: [string, string];
}
export class CommentConfigHandler {
private readonly languageToConfigPath = new Map<string, string>();
private readonly commentConfig = new Map<string, CommentConfig | undefined>();
public constructor() {
this.updateLanguagesDefinitions();
}
/**
* Generate a map of language configuration file by language defined by extensions
* External extensions can override default configurations os VSCode
*/
public updateLanguagesDefinitions() {
this.commentConfig.clear();
for (const extension of vscode.extensions.all) {
const packageJSON = extension.packageJSON as any;
if (packageJSON.contributes && packageJSON.contributes.languages) {
for (const language of packageJSON.contributes.languages) {
if (language.configuration) {
const configPath = path.join(extension.extensionPath, language.configuration);
this.languageToConfigPath.set(language.id, configPath);
}
}
}
}
}
/**
* Return the comment config for `languageCode`
* @param languageCode The short code of the current language
*/
public getCommentConfig(languageCode: string): CommentConfig | undefined {
if (this.commentConfig.has(languageCode)) {
return this.commentConfig.get(languageCode);
}
if (!this.languageToConfigPath.has(languageCode)) {
return undefined;
}
const file = this.languageToConfigPath.get(languageCode) as string;
const content = fs.readFileSync(file, { encoding: 'utf8' });
try {
// Using normal JSON because json5 behaved buggy.
// Might need JSON5 in the future to parse language jsons with comments.
const config = JSON.parse(content);
this.commentConfig.set(languageCode, config.comments);
return config.comments;
} catch (error) {
this.commentConfig.set(languageCode, undefined);
return undefined;
}
}
}
To detect if a line is a comment you could get the comment configuration using the class above, escape the delimiters, and use them in a regex.
Something like this:
activeEditor = vscode.window.activeTextEditor;
const commentConfigHandler = new CommentConfig();
const commentCfg = commentConfigHandler.getCommentConfig(activeEditor.document.languageId);
function escapeRegex(string: string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
const commentLineDelimiter = commentCfg.lineComment;
const regex = new RegExp(`\s*${escapeRegex(commentLineDelimiter )}.*`, "ig");
const isComment = regex.test(lineText)
Note that the above example only tests for single line comments and will need to be extended for block comments with a more extensive regex that includes commentCfg.blockComment[0]
and commentCfg.blockComment[1]
.
Upvotes: 2