1

I'm working on a vscode extension that lets me generate a section to organize my code

example :
Python :

# ┌─MY─SECTION─┐ 
def test():
    pass
# └────────────┘

CSS :

/* ┌─MY─SECTION─┐ */
.class {
    opacity: 0;
}
/* └────────────┘ */

Here is the code I use :

const template = `$LINE_COMMENT ┌─MY─SECTION─┐\n$TM_SELECTED_TEXT\n$LINE_COMMENT └────────────┘`
let snippet = vscode.SnippetString(template)

textEditor.insertSnippet(snippet)

To do that I use the vscode snippet syntax which has a variable for either single-line comment languages like python ($LINE_COMMENT) or multi-line comment languages like CSS ($BLOCK_COMMENT_START and $BLOCK_COMMENT_END)

The problem is, I can't know when I need to use one or the other.

Is there a way to detect if the language used in the current document uses single or multi-line comments?

  • for a comment remover extension I have hand coded the possibilities for every language – rioV8 Jul 14 '22 at 22:00
  • I've seen that solution on some already existing extensions but I wondered if it was possible to use a more "automatic" method. Thx tho :) – Jumscrafteur Jul 16 '22 at 13:31

1 Answers1

0

You can get the language configuration for the current language and check that for lineComment or blockComment. I do this in my extension Find and Transform so you could look in that repository to see how it is done.

But here is my code simplified (I have to parse some keybinding args, etc. along the way you don't have to):

With const jsonc = require('jsonc-parser'); at the top of the file and that package installed in your extension. Why? Because some of the language configuration files have comments in them, so JSON.parse() will not work for them.

// call the language configuration getter (in an async function)
const documentLanguageId = vscode.window.activeTextEditor.document.languageId;
const config = await languageConfigs.getLanguageConfigFile(documentLanguageId);

config will be an object like config.comments.lineComment and/or config.comments.blockComment. A language like javascript will have values for both but css will have only a config.comments.blockComment and config.comments.lineComment will be undefined.

Here is more code

/**
 * Get an array of "languages", like plaintext, that don't have comment syntax
 * @returns {string[]} 
 */
function _getLanguagesToSkip  () {
  return ['log', 'Log', 'search-result', 'plaintext', 'scminput', 'properties', 'csv', 'tsv', 'excel'];
}

This function above is called because some "languages" like .txt files don't have any comments so skip those in the next function:

/**
 * @param {string} langID - 
 */
exports.getLanguageConfigFile = async function (langID) {

  let thisConfig = {};
  let langConfigFilePath = null;

  // loop through all installed extensions, including built-in extensions
  for (let i = 0; i < vscode.extensions.all.length; i++) {

    let _ext = vscode.extensions.all[i];

    // if an extension contributes languages we want them
    // they have links to their language configuration file
    if (_ext.packageJSON.contributes && _ext.packageJSON.contributes.languages) {

      const contributedLanguages = _ext.packageJSON.contributes.languages;  // may be an array!

      for (let j = 0; j < contributedLanguages.length; j++) {

        let packageLang = contributedLanguages[j];

        // match the current editor language ID that we passed in
        if (packageLang.id === langID) {

          // "languages" to skip, like plaintext, etc. = no configuration properties that we are interested in
          let skipLangs = _getLanguagesToSkip();

          if (!skipLangs?.includes(packageLang.id) && _ext.packageJSON.contributes.languages[j].configuration) {

            langConfigFilePath = path.join(
              _ext.extensionPath,
              _ext.packageJSON.contributes.languages[j].configuration
            );

            if (!!langConfigFilePath && fs.existsSync(langConfigFilePath)) {
              thisConfig = jsonc.parse(fs.readFileSync(langConfigFilePath).toString());
              return thisConfig;
            }
          }
        }
      }
    }
  }
  return thisConfig;   // would be an empty object if we end up here
  // which would mean there is no extension with a language configuration file thay matches the active editor language
};

It works fast enough to not be noticeable, although I do have a version somewhere which gets all the currently installed language configs and saves to storage which can be run once and then again if no match for the current langID is found. That version is much cleaner and shorter because it goes through all extensions, instead of stopping at the current editor language like the above - but does unnecessary work unless you are going to save them all.

Mark
  • 143,421
  • 24
  • 428
  • 436