sreenivas
sreenivas

Reputation: 2247

VSCode API Check if the current line is a comment

Is it possible to query if the current line is a comment using the VSCode API ?

Upvotes: 10

Views: 843

Answers (1)

Zoom
Zoom

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

Related Questions