[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**Code example**\n\n```Cpp\n// Put your code here\n```\n\n**Expected result**\n\n```Cpp\n/**\n * @brief Put the expected comment here\n */\n```\n\n**Actual result**\n\n```Cpp\n/**\n * @brief Put the actually generated comment here\n */\n```\n\n**Screencaps**\nIf applicable, add screencaps to help explain your problem.\n\n**Your System:**\n - OS: [Windows, macOS, Linux]\n - VS Code Version [e.g. 1.55]\n - Doxdocgen Code Version [e.g. 1.3.1]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "# Description\n\nAnything you'd like to add\n\n## Code example\n\n```Cpp\n// Put your code here\n```\n\n### Expected result\n\n```Cpp\n/**\n * @brief Put the expected comment here\n */\n```\n\n### Actual result\n\n```Cpp\n/**\n * @brief Put the actually generated comment here\n */\n```\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Fix/Feature/Other\n\n## Fix\n\n- [ ] Link to issue. If there is no issue please describe it using at least the issue template\n\n- [ ] Description of the fix\n\n- [ ] Added unit test\n\n## Feature\n\n- [ ] Description of what's added\n\n- [ ] Gif of your feature if appropriate\n\n- [ ] Added gif to README\n\n- [ ] Added unit test\n\n## Other\n\n- [ ] Description\n"
  },
  {
    "path": ".github/workflows/cd.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n  release:\n    types:\n      - created\n\njobs:\n  pipeline:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Use Node.js\n        uses: actions/setup-node@v1\n        with:\n          node-version: '15.11.0'\n      - run: yarn\n\n      - name: Install VSCE\n        run: yarn add vsce ovsx -D\n\n      - name: Update $PATH\n        run: echo \"$PWD/node_modules/.bin/\" >> $GITHUB_PATH\n\n      - name: Build vsix\n        run: vsce package && ls -alh\n\n      - name: Publish to VS Code Marketplace\n        run: vsce publish -p ${VSCE_TOKEN}\n        env:\n          VSCE_TOKEN: ${{ secrets.VSCE_TOKEN }}\n        if: contains(github.ref, 'refs/tags/')\n\n      - name: Publish to Open VSX Registry\n        run: ovsx publish\n        env:\n          OVSX_PAT: ${{ secrets.OPEN_VSX_TOKEN }}\n        if: contains(github.ref, 'refs/tags/')\n\n      - name: Upload vsix to GitHub release\n        uses: svenstaro/upload-release-action@v2\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: doxdocgen-*.vsix\n          tag: ${{ github.ref }}\n          overwrite: true\n          file_glob: true\n        if: contains(github.ref, 'refs/tags/')\n\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Use Node.js\n        uses: actions/setup-node@v1\n        with:\n          node-version: '15.11.0'\n      - run: yarn\n\n      - name: Lint\n        run: yarn lint\n  \n  build:\n    needs: lint\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n      \n      - name: Use Node.js\n        uses: actions/setup-node@v1\n        with:\n          node-version: '15.11.0'\n      - run: yarn\n\n      - name: Compile\n        run: yarn compile\n  \n  test:\n    needs: build\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        # disable ubuntu-latest until https://github.com/microsoft/vscode/issues/106569 is fixed\n        os: [macos-latest, windows-latest]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n      \n      - name: Use Node.js\n        uses: actions/setup-node@v1\n        with:\n          node-version: '15.11.0'\n      - run: yarn\n\n      - name: Test\n        run: yarn test\n        # Run tests only on non-coverage job\n        if: matrix.os != 'macOS-latest'\n      \n      - name: Generate Coverage\n        run: yarn cov\n        if: matrix.os == 'macOS-latest'\n\n      - name: Publish coverage\n        uses: codecov/codecov-action@v1\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n        if: matrix.os == 'macOS-latest'\n \n      - name: Upload coverage\n        uses: actions/upload-artifact@v2\n        with:\n          name: cov\n          path: coverage\n        if: matrix.os == 'macOS-latest'\n\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ master ]\n  schedule:\n    - cron: '32 8 * * 3'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'javascript' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]\n        # Learn more:\n        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".gitignore",
    "content": "out\nnode_modules\n.vscode-test/\n*.vsix\ncoverage/\n.DS_Store\n/npm-debug.log\n/.nyc_output/\npackage-lock.json"
  },
  {
    "path": ".nycrc",
    "content": "{\n    \"extends\": \"@istanbuljs/nyc-config-typescript\",\n    \"cache\": false,\n    \"cwd\": \"./\",\n    \"exclude\": [\n        \"**/**.test.js\"\n    ],\n    \"extension\": [\n        \".ts\",\n        \".tsx\"\n    ],\n    \"hookRequire\": true,\n    \"hookRunInContext\": true,\n    \"hookRunInThisContext\": true,\n    \"instrument\": true,\n    \"reporter\": [\"json\", \"text\"],\n    \"recursive\": true,\n    \"require\": [\n        \"ts-node/register\",\n        \"source-map-support/register\"\n    ],\n    \"sourceMap\": true,\n    \"all\": true,\n    \"include\": [ \"src/Lang\" ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "// A launch configuration that compiles the extension and then opens it inside a new window\n{\n    \"version\": \"0.1.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Launch Extension\",\n            \"type\": \"extensionHost\",\n            \"request\": \"launch\",\n            \"runtimeExecutable\": \"${execPath}\",\n            \"args\": [\"--extensionDevelopmentPath=${workspaceRoot}\" ],\n            \"stopOnEntry\": false,\n            \"sourceMaps\": true,\n            \"outFiles\": [ \"${workspaceRoot}/out/**/*.js\" ],\n            \"preLaunchTask\": \"npm: compile\"\n        },\n        {\n            \"name\": \"Launch Tests\",\n            \"type\": \"extensionHost\",\n            \"request\": \"launch\",\n            \"runtimeExecutable\": \"${execPath}\",\n            \"args\": [\"--extensionDevelopmentPath=${workspaceRoot}\", \"--extensionTestsPath=${workspaceRoot}/out/test\", \"--disable-extensions\" ],\n            \"stopOnEntry\": false,\n            \"sourceMaps\": true,\n            \"outFiles\": [ \"${workspaceRoot}/out/test/**/*.js\" ],\n            \"preLaunchTask\": \"npm: compile\"\n        }\n    ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "// Place your settings in this file to overwrite default and user settings.\n{\n    \"files.exclude\": {\n        \"out\": false // set this to true to hide the \"out\" folder with the compiled JS files\n    },\n    \"search.exclude\": {\n        \"out\": true // set this to false to include \"out\" folder in search results\n    }\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "// See https://go.microsoft.com/fwlink/?LinkId=733558\n// for the documentation about the tasks.json format\n{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"npm\",\n            \"script\": \"watch\",\n            \"problemMatcher\": \"$tsc-watch\",\n            \"isBackground\": true,\n            \"presentation\": {\n                \"reveal\": \"never\"\n            },\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            }\n        }\n    ]\n}"
  },
  {
    "path": ".vscodeignore",
    "content": ".vscode/**\n.vscode-test/**\nout/test/**\nout/**/*.map\nsrc/**\n.gitignore\ntsconfig.json\nvsc-extension-quickstart.md\n.travis.yml\nappveyor.yml\ncoverconfig.json\npublish_coverage.sh\n.github/**"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\n## [1.4.0]\n\n### Feature\n\n- Use `vscode.workspace.workspaceFolders[0]` to construct SimpleGit instance (#268)\n  Thanks to @lukester1975\n\n### Fix\n\n- Add official VS Code Language identifier for CUDA (#273)\n  Thanks to @jobtijhuis\n\n## [1.3.2]\n\n### Fix\n\n- Indent alignment not working in file comments (#206) (#236)\n  Thanks to @HO-COOH\n\n- Several typos (#233)\n  Thanks to @jogo-\n\n## [1.3.1]\n\n### Fix\n\n- Only suggest Doxygen snippet's when the cursor is in a comment section (#224) (#229)\n  Thanks to @HO-COOH\n\n## [1.3.0]\n\n### Feature\n\n- Add `{file}` template, so it can be used in custom tag of both file comments and generic comments (#191) (#221)\n  Thanks to @HO-COOH\n\n## [1.2.2]\n\n### Fix\n\n- Fix tags in generic order not expanded (#204) (#217)\n  Thanks to @HO-COOH\n\n## [1.2.1]\n\n### Fix\n\n- Fix unexpected return tag on non-functions (#210) (#214)\n  Thanks to @HO-COOH\n\n## [1.2.0]\n\n### Feature\n\n- Doxygen command Intellisense support (#211)\n  Thanks to @HO-COOH\n\n### Other\n\n- Nicer setting descriptions (#209)\n  Thanks to @HO-COOH\n\n## [1.1.0]\n\n### Feature\n\n- Substitute author and email by git config (#186) (#182)\n  Thanks to @to-s\n\n### Other\n\n- Update to Typescript 3.8.3\n\n## [1.0.1]\n\n### Fix\n\n- Files without includes don't trigger the autocomplete for file description (#141) (#183)\n  Thanks to @to-s\n\n## [1.0.0]\n\n### Revert\n\n- Revert reverting Replace environment variables in templated strings. If no environment variable can be found the name of the variable will be inserted (#110)\n\n### Other\n\n- vsce packaging is forcing yarn even if no yarn config exists. Override this behavior now to use npm.\n\n## [0.8.2]\n\n### Other\n\n- Package with older version of vsce\n\n## [0.8.1]\n\n### Revert\n\n- Replace environment variables in templated strings. If no environment variable can be found the name of the variable will be inserted (#110)\n\n## [0.8.0]\n\n### Feature\n\n- Support for arbitrary tags (#169)\n\n- Replace environment variables in templated strings. If no environment variable can be found the name of the variable will be inserted (#110)\n\n### Fix\n\n- Incorrect parameter name of template (#170)\n\n## [0.7.2]\n\n### Fix\n\n- Could not generate correct file header annotation (again) #164 (#161)\n\n## [0.7.1]\n\n### Fix\n\n- Could not generate correct file header annotation #162 (#161)\n\n## [0.7.0]\n\n### Feature\n\n- Add option to filter keywords (like custom defines) from input line #159 (#152)\n\n### Fix\n\n- Argument type would be placed as the param instead of the argument name #154\n\n  Thanks to @DaanHuinink\n\n- Bug when commenting macros #158 (#142)\n\n## [0.6.0]\n\n### Feature\n\n- Add support for multiline template #140 (#127)\n  \n  Thanks to @eternalphane\n\n- Enable CUDA language support #148 (#128)\n  \n  Thanks to @trxcllnt\n\n### Other\n\n- Update dev dependencies\n\n## [0.5.2]\n\n### Fix\n\n- Cannot see params & return value, for global functions (#136)\n\n## [0.5.1]\n\n### Fix\n\n- Ignore `restrict` keyword in C function parameter pointer (#121)\n\n- Parameters not generated when using custom trigger (#119)\n\n- Function argument. Pointer to table is not generated. (#123)\n\n### Other\n\n- Update dev dependencies and increase min VS Code version (#131, #132)\n\n## [0.5.0]\n\n### Feature\n\n- Feature suggest: Indent option (#107)\n\n#### Alignment\n\nThis version introduces the possibility to align text elements in config strings at a specified width.\n\nExample:\n\n```json\n\"doxdocgen.generic.paramTemplate\": \"@param{indent:10}{param}{indent:30}My Param doc\"\n```\n\nwill turn into\n\n```cpp\n/**\n * @param    foo                 My Param doc\n * @param    barIsAlsoAnOption   My Param doc\n */\nvoid bar(int foo, int barIsAlsoAnOption);\n```\n\nYou can use the `{indent:<number>}` in any templated config option available. Numbers have to be bigger than 0 to have any effect.\n\nAlignment will be done from the start of the config string, like this:\n\n```json\n\"doxdocgen.generic.paramTemplate\": \"@param {param}{indent:14}test\"\n```\n\n```cpp\n/**\n * @param        test\n */ \n   |<---------->| // 14\n```\n\n## [0.4.3]\n\n### Fix\n\n- Trigger Sequence /** causes extra */ to be generated and the comment block isn't fully generated. (#111)\n\n## [0.4.2]\n\n### Fix\n\n- Invalid argument name for C `enum` types (#102)\n\n## [0.4.1]\n\n### Fix\n\n- Wrong \\param value generation. (#91)\n\n## [0.4.0]\n\n### Feature\n\n- Additional file header fields for version, copyright, and custom text (#89)\n\n## [0.3.3]\n\n### Fix\n\n- Doesn't parse CPP member pointer names correctly (#78)\n\n## [0.3.2]\n\n### Fix\n\n- Cannot read property 'text' of undefined (#79)\n\n## [0.3.1]\n\n### Fix\n\n- Don't create a comment while editing an existing comment. (#67)\n\n## [0.3.0]\n\n### Features\n\n- Custom Doxygen tag order for methods (#55)\n\n- Suggest smart text (#57)\n\n  For more details see [README.md](https://github.com/christophschlosser/doxdocgen/tree/0.3.0#smart-text)\n\n- Config keys are now grouped, see [Config update](#config-update) for changes\n\n### Config update\n\n| Old value                             | New value                              | Change   |\n|---------------------------------------|----------------------------------------|:--------:|\n| doxdocgen.generic.triggerSequence     | doxdocgen.c.triggerSequence            | Category |\n| doxdocgen.generic.firstLine           | doxdocgen.c.firstLine                  | Category |\n| doxdocgen.generic.commentPrefix       | doxdocgen.c.commentPrefix              | Category |\n| doxdocgen.generic.lastLine            | doxdocgen.c.lastLine                   | Category |\n|                                       | doxdocgen.c.setterText                 | Added    |\n|                                       | doxdocgen.c.getterText                 | Added    |\n|                                       | doxdocgen.c.factoryMethodText          | Added    |\n| doxdocgen.generic.newLineAfterTParams |                                        | Removed  |\n| doxdocgen.generic.newLineAfterBrief   |                                        | Removed  |\n| doxdocgen.generic.newLineAfterParams  |                                        | Removed  |\n| doxdocgen.generic.tparamTemplate      | doxdocgen.cpp.tparamTemplate           | Category |\n|                                       | doxdocgen.cpp.ctorText                 | Added    |\n|                                       | doxdocgen.cpp.dtorText                 | Added    |\n| doxdocgen.generic.fileTemplate        | doxdocgen.file.fileTemplate            | Category |\n| doxdocgen.generic.fileOrder           | doxdocgen.file.fileOrder               | Category |\n|                                       | doxdocgen.generic.generateSmartText    | Added    |\n|                                       | doxdocgen.generic.splitCasingSmartText | Added    |\n|                                       | doxdocgen.generic.order                | Added    |\n\n## [0.2.1]\n\n- Hotfix. Include moment.js as runtime dependency\n\n## [0.2.0]\n\n- Fix #51\n\n- Fix #52\n\n## [0.1.0]\n\n- Fix #40\n\n- Fix #38\n\n- Fix #37\n\n- Fix #36\n\n- Fix #28\n\n- Fix #24\n\n- Implemented support for `noexcept` and `throw`\n\n- Implemented support for `constexpr` and `final`\n\n- Implemented support for unnamed parameters, this broke in version 0.0.7\n\n- Add new config variable that allows a user to disable the true and false return on bool types and make it behave like a normal type\n\n## [0.0.7]\n\n- Fix #31\n\n- Fixed bug where using a different trigger sequence than \"*\" causes a newline to be added between the comment and the documented entity.\n\n## [0.0.6]\n\n- Improve and fix comment generation for several C++ features (#23) (thanks to @rowanG077 again)\n\n## [0.0.5]\n\n- Extend customization of generated documentation (#15, #16) (thanks to @rowanG077)\n\n- Fix #10\n\n## [0.0.4]\n\n- Fix #9\n\n- Add option to choose if the return type should be included in generated documentation\n\n## [0.0.3]\n\n- Add possibility to set comment start indicator to Qt style\n\n## [0.0.2]\n\n- Add C parser and generator\n\n## [0.0.1]\n\n- Initial release\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017-2021 Christoph Schlosser\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Generate Doxygen Comments in VS Code\n\nThis VS Code Extensions provides Doxygen Documentation generation on the fly by starting a Doxygen comment block and pressing enter.\n\n[![CI build status](https://img.shields.io/github/workflow/status/cschlosser/doxdocgen/CI/master)](https://github.com/cschlosser/doxdocgen/actions/workflows/ci.yml?query=branch%3Amaster)\n[![Release build status](https://img.shields.io/github/workflow/status/cschlosser/doxdocgen/CD?label=Release)](https://github.com/cschlosser/doxdocgen/actions/workflows/cd.yml?query=event%3Arelease++)\n[![codecov](https://codecov.io/gh/cschlosser/doxdocgen/branch/master/graph/badge.svg)](https://codecov.io/gh/cschlosser/doxdocgen)\n[![IRC chat](https://img.shields.io/badge/irc.oftc.net-%23doxdocgen-brightgreen)](https://webchat.oftc.net/?channels=doxdocgen)\n\n## Table of Contents\n\n- [Generate Doxygen Comments in VS Code](#generate-doxygen-comments-in-vs-code)\n  - [Table of Contents](#table-of-contents)\n  - [Features](#features)\n    - [Alignment](#alignment)\n    - [Attributes](#attributes)\n    - [Con- and Destructors](#con--and-destructors)\n    - [Extensive customization](#extensive-customization)\n    - [File descriptions](#file-descriptions)\n    - [Function pointers](#function-pointers)\n    - [Operators](#operators)\n    - [Parameters](#parameters)\n    - [Return types](#return-types)\n    - [Smart text](#smart-text)\n      - [Trailing](#trailing)\n    - [Templates](#templates)\n    - [Auto-complete doxygen commands](#auto-complete-doxygen-commands)\n  - [Config options](#config-options)\n  - [Contributors](#contributors)\n  - [Known Issues](#known-issues)\n  - [What's to come](#whats-to-come)\n\n## Features\n\n### Alignment\n\n![Alignment](images/alignment.gif)\n\nFor how this works, see the [CHANGELOG.md](https://github.com/cschlosser/doxdocgen/blob/master/CHANGELOG.md#alignment)\n\n### Attributes\n\n![Attribute](images/attributes.gif)\n\n### Con- and Destructors\n\n![Constructor](images/ctor.gif)\n![Destructor](images/dtor.gif)\n\n### Extensive customization\n\n![options](images/options.gif)\n![xml options](images/opts-xml.gif)\n![order of commands](images/opt-order.gif)\n\n### File descriptions\n\n![file description](images/file.gif)\n\n### Function pointers\n\n![func_ptr](images/function_ptr.gif)\n\n### Operators\n\n![Operator](images/operator.gif)\n![Delete Operator](images/op-delete.gif)\n\n### Parameters\n\n![Simple Parameter](images/param_simple.gif)\n![Long Parameter](images/long-param.gif)\n\n### Return types\n\n![Bool return val](images/bool.gif)\n![Declaration](images/declaration.gif)\n\n### Smart text\n\n![Smart text CTor](images/smartTextCtor.gif)\n![Smart text Custom](images/smartTextCustom.gif)\n![Smart text Getter](images/smartTextGet.gif)\n\nSupported smart text snippets:\n\n* Constructors\n\n* Destructors\n\n* Getters\n\n* Setters\n\n* Factory methods\n\nEach of them can be configured with its own custom text and you can decide if the addon should attempt to split the name of the method according to its case.\n\n#### Trailing\n\n![Trailing return](images/trailing.gif)\n\n### Templates\n\n![Template method](images/template.gif)\n![Template class](images/template-class.gif)\n\n### Auto-complete doxygen commands\n\n![Auto complete doxygen](images/doxygen-auto-complete.gif)\n\n\n## Config options\n\n```jsonc\n{\n  // The prefix that is used for each comment line except for first and last.\n  \"doxdocgen.c.commentPrefix\": \" * \",\n\n  // Smart text snippet for factory methods/functions.\n  \"doxdocgen.c.factoryMethodText\": \"Create a {name} object\",\n\n  // The first line of the comment that gets generated. If empty it won't get generated at all.\n  \"doxdocgen.c.firstLine\": \"/**\",\n\n  // Smart text snippet for getters.\n  \"doxdocgen.c.getterText\": \"Get the {name} object\",\n\n  // The last line of the comment that gets generated. If empty it won't get generated at all.\n  \"doxdocgen.c.lastLine\": \" */\",\n\n  // Smart text snippet for setters.\n  \"doxdocgen.c.setterText\": \"Set the {name} object\",\n\n  // Doxygen comment trigger. This character sequence triggers generation of Doxygen comments.\n  \"doxdocgen.c.triggerSequence\": \"/**\",\n\n  // Smart text snippet for constructors.\n  \"doxdocgen.cpp.ctorText\": \"Construct a new {name} object\",\n\n  // Smart text snippet for destructors.\n  \"doxdocgen.cpp.dtorText\": \"Destroy the {name} object\",\n\n  // The template of the template parameter Doxygen line(s) that are generated. If empty it won't get generated at all.\n  \"doxdocgen.cpp.tparamTemplate\": \"@tparam {param} \",\n\n  // File copyright documentation tag.  Array of strings will be converted to one line per element.  Can template {year}.\n  \"doxdocgen.file.copyrightTag\": [\n    \"@copyright Copyright (c) {year}\"\n  ],\n\n  // Additional file documentation. One tag per line will be added. Can template `{year}`, `{date}`, `{author}`, `{email}` and `{file}`. You have to specify the prefix.\n  \"doxdocgen.file.customTag\": [],\n\n  // The order to use for the file comment. Values can be used multiple times. Valid values are shown in default setting.\n  \"doxdocgen.file.fileOrder\": [\n    \"file\",\n    \"author\",\n    \"brief\",\n    \"version\",\n    \"date\",\n    \"empty\",\n    \"copyright\",\n    \"empty\",\n    \"custom\"\n  ],\n\n  // The template for the file parameter in Doxygen.\n  \"doxdocgen.file.fileTemplate\": \"@file {name}\",\n\n  // Version number for the file.\n  \"doxdocgen.file.versionTag\": \"@version 0.1\",\n\n  // Set the e-mail address of the author.  Replaces {email}.\n  \"doxdocgen.generic.authorEmail\": \"you@domain.com\",\n\n  // Set the name of the author.  Replaces {author}.\n  \"doxdocgen.generic.authorName\": \"your name\",\n\n  // Set the style of the author tag and your name.  Can template {author} and {email}.\n  \"doxdocgen.generic.authorTag\": \"@author {author} ({email})\",\n\n  // If this is enabled a bool return value will be split into true and false return param.\n  \"doxdocgen.generic.boolReturnsTrueFalse\": true,\n\n  // The template of the brief Doxygen line that is generated. If empty it won't get generated at all.\n  \"doxdocgen.generic.briefTemplate\": \"@brief {text}\",\n\n  // The format to use for the date.\n  \"doxdocgen.generic.dateFormat\": \"YYYY-MM-DD\",\n\n  // The template for the date parameter in Doxygen.\n  \"doxdocgen.generic.dateTemplate\": \"@date {date}\",\n\n  // Decide if you want to get smart text for certain commands.\n  \"doxdocgen.generic.generateSmartText\": true,\n\n  // Whether include type information at return.\n  \"doxdocgen.generic.includeTypeAtReturn\": true,\n\n  // How many lines the plugin should look for to find the end of the declaration. Please be aware that setting this value too low could improve the speed of comment generation by a very slim margin but the plugin also may not correctly detect all declarations or definitions anymore.\n  \"doxdocgen.generic.linesToGet\": 20,\n\n  // The order to use for the comment generation. Values can be used multiple times. Valid values are shown in default setting.\n  \"doxdocgen.generic.order\": [\n    \"brief\",\n    \"empty\",\n    \"tparam\",\n    \"param\",\n    \"return\",\n    \"custom\",\n    \"version\",\n    \"author\",\n    \"date\",\n    \"copyright\"\n  ],\n\n  // Custom tags to be added to the generic order. One tag per line will be added. Can template `{year}`, `{date}`, `{author}`, `{email}` and `{file}`. You have to specify the prefix.\n  \"doxdocgen.generic.customTags\": [],\n\n  // The template of the param Doxygen line(s) that are generated. If empty it won't get generated at all.\n  \"doxdocgen.generic.paramTemplate\": \"@param {param} \",\n\n  // The template of the return Doxygen line that is generated. If empty it won't get generated at all.\n  \"doxdocgen.generic.returnTemplate\": \"@return {type} \",\n\n  // Decide if the values put into {name} should be split according to their casing.\n  \"doxdocgen.generic.splitCasingSmartText\": true,\n\n  // Array of keywords that should be removed from the input prior to parsing.\n  \"doxdocgen.generic.filteredKeywords\": [],\n\n  // Substitute {author} with git config --get user.name.\n  \"doxdocgen.generic.useGitUserName\": false,\n\n  // Substitute {email} with git config --get user.email.\n  \"doxdocgen.generic.useGitUserEmail\": false,\n\n  // Provide intellisense and snippet for doxygen commands\n  \"doxdocgen.generic.commandSuggestion\": true,\n\n  // Add `\\\\` in doxygen command suggestion for better readability (need to enable commandSuggestion)\n  \"doxdocgen.generic.commandSuggestionAddPrefix\": false,\n}\n```\n\n## Contributors\n\n[Christoph Schlosser](https://github.com/cschlosser)\n\n[Rowan Goemans](https://github.com/rowanG077)\n\n## Known Issues\n\n[See open bugs](https://github.com/cschlosser/doxdocgen/labels/bug)\n\n## What's to come\n\n[See open features](https://github.com/cschlosser/doxdocgen/labels/enhancement)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"doxdocgen\",\n  \"displayName\": \"Doxygen Documentation Generator\",\n  \"description\": \"Let me generate Doxygen documentation from your source code for you.\",\n  \"version\": \"1.4.0\",\n  \"publisher\": \"cschlosser\",\n  \"engines\": {\n    \"vscode\": \"^1.55.0\"\n  },\n  \"categories\": [\n    \"Other\"\n  ],\n  \"badges\": [\n    {\n      \"url\": \"https://img.shields.io/github/workflow/status/cschlosser/doxdocgen/CI/master\",\n      \"href\": \"https://github.com/cschlosser/doxdocgen/actions/workflows/ci.yml?query=branch%3Amaster+\",\n      \"description\": \"Continous integration\"\n    },\n    {\n      \"url\": \"https://img.shields.io/github/workflow/status/cschlosser/doxdocgen/CD?label=Release\",\n      \"href\": \"https://github.com/cschlosser/doxdocgen/actions/workflows/cd.yml?query=event%3Arelease++\",\n      \"description\": \"Release pipeline\"\n    },\n    {\n      \"url\": \"https://codecov.io/gh/cschlosser/doxdocgen/branch/master/graph/badge.svg\",\n      \"href\": \"https://codecov.io/gh/cschlosser/doxdocgen\",\n      \"description\": \"Code coverage\"\n    }\n  ],\n  \"activationEvents\": [\n    \"onLanguage:cuda\",\n    \"onLanguage:cuda-cpp\",\n    \"onLanguage:cpp\",\n    \"onLanguage:c\"\n  ],\n  \"contributes\": {\n    \"configuration\": {\n      \"type\": \"object\",\n      \"title\": \"Doxygen Documentation Generator Settings\",\n      \"properties\": {\n        \"doxdocgen.c.triggerSequence\": {\n          \"description\": \"Doxygen comment trigger. This character sequence triggers generation of Doxygen comments.\",\n          \"type\": \"string\",\n          \"default\": \"/**\"\n        },\n        \"doxdocgen.c.firstLine\": {\n          \"description\": \"The first line of the comment that gets generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \"/**\"\n        },\n        \"doxdocgen.c.commentPrefix\": {\n          \"description\": \"The prefix that is used for each comment line except for first and last.\",\n          \"type\": \"string\",\n          \"default\": \" * \"\n        },\n        \"doxdocgen.c.lastLine\": {\n          \"description\": \"The last line of the comment that gets generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \" */\"\n        },\n        \"doxdocgen.c.setterText\": {\n          \"description\": \"Smart text snippet for setters.\",\n          \"type\": \"string\",\n          \"default\": \"Set the {name} object\"\n        },\n        \"doxdocgen.c.getterText\": {\n          \"description\": \"Smart text snippet for getters.\",\n          \"type\": \"string\",\n          \"default\": \"Get the {name} object\"\n        },\n        \"doxdocgen.c.factoryMethodText\": {\n          \"description\": \"Smart text snippet for factory methods/functions.\",\n          \"type\": \"string\",\n          \"default\": \"Create a {name} object\"\n        },\n        \"doxdocgen.cpp.tparamTemplate\": {\n          \"description\": \"The template of the template parameter Doxygen line(s) that are generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \"@tparam {param} \"\n        },\n        \"doxdocgen.cpp.ctorText\": {\n          \"description\": \"Smart text snippet for constructors.\",\n          \"type\": \"string\",\n          \"default\": \"Construct a new {name} object\"\n        },\n        \"doxdocgen.cpp.dtorText\": {\n          \"description\": \"Smart text snippet for destructors.\",\n          \"type\": \"string\",\n          \"default\": \"Destroy the {name} object\"\n        },\n        \"doxdocgen.file.fileTemplate\": {\n          \"description\": \"The template for the file parameter in Doxygen.\",\n          \"type\": \"string\",\n          \"default\": \"@file {name}\"\n        },\n        \"doxdocgen.file.copyrightTag\": {\n          \"markdownDescription\": \"File copyright documentation tag.  Array of strings will be converted to one line per element. Can template `{year}`.\",\n          \"type\": [\n            \"array\",\n            \"string\"\n          ],\n          \"default\": [\n            \"@copyright Copyright (c) {year}\"\n          ]\n        },\n        \"doxdocgen.file.versionTag\": {\n          \"description\": \"Version number for the file.\",\n          \"type\": \"string\",\n          \"default\": \"@version 0.1\"\n        },\n        \"doxdocgen.file.customTag\": {\n          \"markdownDescription\": \"Additional file documentation.  Array of strings will be converted to one line per element. Can template `{year}`, `{date}`, `{author}`, `{email}` and `{file}`. You have to specify the prefix.\",\n          \"type\": [\n            \"array\",\n            \"string\"\n          ],\n          \"default\": []\n        },\n        \"doxdocgen.file.fileOrder\": {\n          \"markdownDescription\": \"The order to use for the file comment. Values can be used multiple times. Valid values are `file`, `author`, `brief`, `version`, `date`, `empty`, `copyright` and `custom`.\",\n          \"type\": [\n            \"array\",\n            \"string\"\n          ],\n          \"default\": [\n            \"file\",\n            \"author\",\n            \"brief\",\n            \"version\",\n            \"date\",\n            \"empty\",\n            \"copyright\",\n            \"empty\",\n            \"custom\"\n          ]\n        },\n        \"doxdocgen.generic.includeTypeAtReturn\": {\n          \"description\": \"Whether include type information at return.\",\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"doxdocgen.generic.boolReturnsTrueFalse\": {\n          \"markdownDescription\": \"If this is enabled, the documentation for a `bool` return value will be split into `true` and `false` entries.\",\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"doxdocgen.generic.briefTemplate\": {\n          \"description\": \"The template of the brief Doxygen line that is generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \"@brief {text}\"\n        },\n        \"doxdocgen.generic.paramTemplate\": {\n          \"description\": \"The template of the param Doxygen line(s) that are generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \"@param {param} \"\n        },\n        \"doxdocgen.generic.returnTemplate\": {\n          \"description\": \"The template of the return Doxygen line that is generated. If empty it won't get generated at all.\",\n          \"type\": \"string\",\n          \"default\": \"@return {type} \"\n        },\n        \"doxdocgen.generic.linesToGet\": {\n          \"description\": \"How many lines the plugin should look for to find the end of the declaration. Please be aware that setting this value too low could improve the speed of comment generation by a very slim margin but the plugin also may not correctly detect all declarations or definitions anymore.\",\n          \"type\": \"number\",\n          \"default\": 20\n        },\n        \"doxdocgen.generic.authorName\": {\n          \"markdownDescription\": \"Set the name of the author.  Replaces `{author}`.\",\n          \"type\": \"string\",\n          \"default\": \"your name\"\n        },\n        \"doxdocgen.generic.authorEmail\": {\n          \"markdownDescription\": \"Set the e-mail address of the author.  Replaces `{email}`.\",\n          \"type\": \"string\",\n          \"default\": \"you@domain.com\"\n        },\n        \"doxdocgen.generic.authorTag\": {\n          \"markdownDescription\": \"Set the style of the author tag and your name.  Can template `{author}` and `{email}`.\",\n          \"type\": \"string\",\n          \"default\": \"@author {author} ({email})\"\n        },\n        \"doxdocgen.generic.dateTemplate\": {\n          \"description\": \"The template for the date parameter in Doxygen.\",\n          \"type\": \"string\",\n          \"default\": \"@date {date}\"\n        },\n        \"doxdocgen.generic.dateFormat\": {\n          \"description\": \"The format to use for the date.\",\n          \"type\": \"string\",\n          \"default\": \"YYYY-MM-DD\"\n        },\n        \"doxdocgen.generic.generateSmartText\": {\n          \"description\": \"Decide if you want to get smart text for certain commands.\",\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"doxdocgen.generic.splitCasingSmartText\": {\n          \"markdownDescription\": \"Decide if the values put into `{name}` should be split according to their casing.\",\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"doxdocgen.generic.order\": {\n          \"markdownDescription\": \"The order to use for the comment generation. Values can be used multiple times. Valid values are `brief`, `empty`, `tparam`, `param`, `return`, `custom`, `author`, `date`, `version` and `copyright`.\",\n          \"type\": [\n            \"array\",\n            \"string\"\n          ],\n          \"default\": [\n            \"brief\",\n            \"empty\",\n            \"tparam\",\n            \"param\",\n            \"return\",\n            \"custom\"\n          ]\n        },\n        \"doxdocgen.generic.customTags\": {\n          \"markdownDescription\": \"Custom tags to be added to the generic order. One tag per line will be added. Can template `{year}`, `{date}`, `{author}`, `{email}` and `{file}`. You have to specify the prefix.\",\n          \"type\": [\n            \"array\",\n            \"string\"\n          ],\n          \"default\": []\n        },\n        \"doxdocgen.generic.filteredKeywords\": {\n          \"description\": \"Array of keywords that should be removed from the input prior to parsing.\",\n          \"type\": \"array\",\n          \"default\": []\n        },\n        \"doxdocgen.generic.useGitUserName\": {\n          \"markdownDescription\": \"Substitute `{author}` with `git config --get user.name`.\",\n          \"type\": \"boolean\",\n          \"default\": false\n        },\n        \"doxdocgen.generic.useGitUserEmail\": {\n          \"markdownDescription\": \"Substitute `{email}` with `git config --get user.email`.\",\n          \"type\": \"boolean\",\n          \"default\": false\n        },\n        \"doxdocgen.generic.commandSuggestion\": {\n          \"description\": \"Provide intellisense and snippet for doxygen commands\",\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"doxdocgen.generic.commandSuggestionAddPrefix\": {\n          \"markdownDescription\": \"Add `\\\\` in doxygen command suggestion for better readability (need to enable commandSuggestion)\",\n          \"type\": \"boolean\",\n          \"default\": false\n        }\n      }\n    }\n  },\n  \"icon\": \"images/icon.png\",\n  \"keywords\": [\n    \"cpp\",\n    \"c++\",\n    \"c\",\n    \"Doxygen\"\n  ],\n  \"license\": \"SEE LICENSE IN LICENSE\",\n  \"main\": \"./out/extension\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/cschlosser/doxdocgen.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/cschlosser/doxdocgen/labels/bug\"\n  },\n  \"scripts\": {\n    \"vscode:prepublish\": \"yarn compile\",\n    \"compile\": \"tsc -p ./\",\n    \"watch\": \"tsc -watch -p ./\",\n    \"test\": \"yarn compile && node ./out/test/runTests.js\",\n    \"cov\": \"yarn clean && nyc yarn test\",\n    \"lint\": \"tslint -c tslint.json 'src/**/*.ts'\",\n    \"clean\": \"rm -rf coverage .nyc_output out\"\n  },\n  \"dependencies\": {\n    \"env-var\": \"^4.1.0\",\n    \"moment\": \"^2.29.4\",\n    \"opn\": \"^5.2.0\",\n    \"simple-git\": \"^3.5.0\"\n  },\n  \"devDependencies\": {\n    \"@istanbuljs/nyc-config-typescript\": \"0.1.3\",\n    \"@types/mocha\": \"^5.2.7\",\n    \"@types/node\": \"12.7.1\",\n    \"@types/vscode\": \"^1.55.0\",\n    \"decache\": \"^4.5.1\",\n    \"glob\": \"^7.1.6\",\n    \"handlebars\": \"^4.7.3\",\n    \"minimist\": \">=1.2.6\",\n    \"mocha\": \"^9.1.3\",\n    \"nyc\": \"12.0.1\",\n    \"remap-istanbul\": \"^0.13.0\",\n    \"source-map-support\": \"^0.5.19\",\n    \"ts-node\": \"^9.1.1\",\n    \"tslint\": \"^5.20.0\",\n    \"typescript\": \"^4.2.4\",\n    \"vscode-test\": \"^1.5.2\",\n    \"yargs-parser\": \">=13.1.2\"\n  }\n}\n"
  },
  {
    "path": "src/CodeParserController.ts",
    "content": "import {\n    Disposable,\n    Position,\n    Range,\n    TextDocumentContentChangeEvent,\n    TextEditor,\n    TextLine,\n    window,\n    workspace,\n} from \"vscode\";\nimport CodeParser from \"./Common/ICodeParser\";\nimport { Config } from \"./Config\";\nimport GitConfig from \"./GitConfig\";\nimport CppParser from \"./Lang/Cpp/CppParser\";\nimport { inComment } from \"./util\";\n/**\n *\n * Checks if the event matches the specified guidelines and if a parser exists for this language\n *\n * @export\n * @class CodeParserController\n */\nexport default class CodeParserController {\n    private disposable: Disposable;\n    private cfg: Config;\n    private gitConfig: GitConfig;\n\n    /**\n     * Creates an instance of CodeParserController\n     *\n     * @memberOf CodeParserController\n     */\n    public constructor() {\n        const subscriptions: Disposable[] = [];\n        this.gitConfig = new GitConfig();\n\n        // Hand off the event to the parser if a valid parser is found\n        workspace.onDidChangeTextDocument((event) => {\n            const activeEditor: TextEditor = window.activeTextEditor;\n            if (activeEditor && event.document === activeEditor.document) {\n                this.cfg = Config.ImportFromSettings();\n                this.onEvent(activeEditor, event.contentChanges[0]);\n            }\n        }, this, subscriptions);\n\n        this.disposable = Disposable.from(...subscriptions);\n    }\n\n    /**\n     *\n     * Disposes of the subscriptions\n     *\n     * @memberOf CodeParserController\n     */\n    public dispose() {\n        this.disposable.dispose();\n    }\n\n    /***************************************************************************\n                                    Implementation\n     ***************************************************************************/\n\n    private check(activeEditor: TextEditor, event: TextDocumentContentChangeEvent): boolean {\n        if (activeEditor === undefined || activeEditor == null ||\n            event === undefined || event.text == null) {\n            return false;\n        }\n        const activeSelection: Position = activeEditor.selection.active;\n        const activeLine: TextLine = activeEditor.document.lineAt(activeSelection.line);\n        const activeChar: string = activeLine.text.charAt(activeSelection.character);\n        const startsWith: boolean = event.text.startsWith(\"\\n\") || event.text.startsWith(\"\\r\\n\");\n\n        // Check if enter was pressed. Note the !\n        if (!((activeChar === \"\") && startsWith)) {\n            return false;\n        }\n\n        // Check if currently in a comment block\n        if (inComment(activeEditor, activeSelection.line)) {\n            return false;\n        }\n\n        // Do not trigger when there's whitespace after the trigger sequence\n        // tslint:disable-next-line:max-line-length\n        const seq = \"[\\\\s]*(\" + this.cfg.C.triggerSequence.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\") + \")$\";\n        const match: RegExpMatchArray = activeLine.text.match(seq);\n\n        if (match !== null) {\n            const cont: string = match[1];\n            return this.cfg.C.triggerSequence === cont;\n        } else {\n            return false;\n        }\n    }\n\n    private onEvent(activeEditor: TextEditor, event: TextDocumentContentChangeEvent) {\n        if (!this.check(activeEditor, event)) {\n            return null;\n        }\n\n        const lang: string = activeEditor.document.languageId;\n        let parser: CodeParser;\n\n        switch (lang) {\n            case \"c\":\n            case \"cpp\":\n            case \"cuda\":\n            case \"cuda-cpp\":\n                parser = new CppParser(this.cfg);\n                break;\n            default:\n                // tslint:disable-next-line:no-console\n                console.log(\"No comments can be generated for language: \" + lang);\n                return null;\n        }\n\n        const currentPos: Position = window.activeTextEditor.selection.active;\n        const startReplace: Position = new Position(\n            currentPos.line,\n            currentPos.character - this.cfg.C.triggerSequence.length,\n        );\n\n        const nextLineText: string = window.activeTextEditor.document.lineAt(startReplace.line + 1).text;\n        const endReplace = new Position(currentPos.line + 1, nextLineText.length);\n\n        parser.Parse(activeEditor).GenerateDoc(new Range(startReplace, endReplace), this.gitConfig);\n    }\n}\n"
  },
  {
    "path": "src/Common/ICodeParser.ts",
    "content": "import { TextEditor } from \"vscode\";\nimport { IDocGen } from \"./IDocGen\";\n\nexport default interface ICodeParser {\n    /**\n     * @param  {TextEditor} activeEditor The open active Editor where the event came from\n     */\n    Parse(activeEditor: TextEditor): IDocGen;\n}\n"
  },
  {
    "path": "src/Common/IDocGen.ts",
    "content": "import { Range } from \"vscode\";\nimport GitConfig from \"../GitConfig\";\n\nexport interface IDocGen {\n    /**\n     * @brief Generate documentation string and write it to the active editor\n     * @param {Range} rangeToReplace Range to replace with the generated comment.\n     */\n    GenerateDoc(rangeToReplace: Range, gitConfig: GitConfig);\n}\n"
  },
  {
    "path": "src/Config.ts",
    "content": "import { workspace } from \"vscode\";\n// tslint:disable:max-classes-per-file\n// tslint:disable:max-line-length\n\nclass C {\n    public static getConfiguration() {\n        return workspace.getConfiguration(\"doxdocgen.c\");\n    }\n\n    public triggerSequence: string = \"/**\";\n    public firstLine: string = \"/**\";\n    public commentPrefix: string = \" * \";\n    public lastLine: string = \" */\";\n    public getterText: string = \"Get the {name} object\";\n    public setterText: string = \"Set the {name} object\";\n    public factoryMethodText: string = \"Create a {name} object\";\n}\n\nclass Cpp {\n    public static getConfiguration() {\n        return workspace.getConfiguration(\"doxdocgen.cpp\");\n    }\n\n    public tparamTemplate: string = \"@tparam {param} \";\n    public ctorText: string = \"Construct a new {name} object\";\n    public dtorText: string = \"Destroy the {name} object\";\n}\n\nclass File {\n    public static getConfiguration() {\n        return workspace.getConfiguration(\"doxdocgen.file\");\n    }\n\n    public fileTemplate: string = \"@file {name}\";\n    public copyrightTag: string[] = [\"@copyright Copyright (c) {year}\"];\n    public versionTag: string = \"@version 0.1\";\n    public customTag: string[] = [];\n    public fileOrder: string[] = [\"brief\", \"empty\", \"file\", \"author\", \"date\"];\n}\n\nclass Generic {\n    public static getConfiguration() {\n        return workspace.getConfiguration(\"doxdocgen.generic\");\n    }\n\n    public includeTypeAtReturn: boolean = true;\n    public boolReturnsTrueFalse: boolean = true;\n    public briefTemplate: string = \"@brief {text}\";\n    public paramTemplate: string = \"@param {param} \";\n    public returnTemplate: string = \"@return {type} \";\n    public linesToGet: number = 20;\n    public authorName: string = \"your name\";\n    public authorEmail: string = \"you@domain.com\";\n    public authorTag: string = \"@author {author} ({email})\";\n    public dateTemplate: string = \"@date {date}\";\n    public dateFormat: string = \"YYYY-MM-DD\";\n    public generateSmartText: boolean = true;\n    public splitCasingSmartText: boolean = true;\n    public order: string[] = [\"brief\", \"empty\", \"tparam\", \"param\", \"return\"];\n    public customTags: string[] = [];\n    public filteredKeywords: string[] = [];\n    public useGitUserName: boolean = false;\n    public useGitUserEmail: boolean = false;\n}\n\nexport class Config {\n    public static ImportFromSettings(): Config {\n        const values: Config = new Config();\n\n        values.C.triggerSequence = C.getConfiguration().get<string>(\"triggerSequence\", values.C.triggerSequence);\n        values.C.firstLine = C.getConfiguration().get<string>(\"firstLine\", values.C.firstLine);\n        values.C.commentPrefix = C.getConfiguration().get<string>(\"commentPrefix\", values.C.commentPrefix);\n        values.C.lastLine = C.getConfiguration().get<string>(\"lastLine\", values.C.lastLine);\n        values.C.getterText = C.getConfiguration().get<string>(\"getterText\", values.C.getterText);\n        values.C.setterText = C.getConfiguration().get<string>(\"setterText\", values.C.setterText);\n        values.C.factoryMethodText = C.getConfiguration().get<string>(\"factoryMethodText\", values.C.factoryMethodText);\n\n        values.Cpp.tparamTemplate = Cpp.getConfiguration().get<string>(\"tparamTemplate\", values.Cpp.tparamTemplate);\n        values.Cpp.ctorText = Cpp.getConfiguration().get<string>(\"ctorText\", values.Cpp.ctorText);\n        values.Cpp.dtorText = Cpp.getConfiguration().get<string>(\"dtorText\", values.Cpp.dtorText);\n\n        values.File.fileTemplate = File.getConfiguration().get<string>(\"fileTemplate\", values.File.fileTemplate);\n        values.File.versionTag = File.getConfiguration().get<string>(\"versionTag\", values.File.versionTag);\n        values.File.copyrightTag = File.getConfiguration().get<string[]>(\"copyrightTag\", values.File.copyrightTag);\n        values.File.customTag = File.getConfiguration().get<string[]>(\"customTag\", values.File.customTag);\n        values.File.fileOrder = File.getConfiguration().get<string[]>(\"fileOrder\", values.File.fileOrder);\n\n        values.Generic.includeTypeAtReturn = Generic.getConfiguration().get<boolean>(\"includeTypeAtReturn\", values.Generic.includeTypeAtReturn);\n        values.Generic.boolReturnsTrueFalse = Generic.getConfiguration().get<boolean>(\"boolReturnsTrueFalse\", values.Generic.boolReturnsTrueFalse);\n        values.Generic.briefTemplate = Generic.getConfiguration().get<string>(\"briefTemplate\", values.Generic.briefTemplate);\n        values.Generic.paramTemplate = Generic.getConfiguration().get<string>(\"paramTemplate\", values.Generic.paramTemplate);\n        values.Generic.returnTemplate = Generic.getConfiguration().get<string>(\"returnTemplate\", values.Generic.returnTemplate);\n        values.Generic.linesToGet = Generic.getConfiguration().get<number>(\"linesToGet\", values.Generic.linesToGet);\n        values.Generic.authorTag = Generic.getConfiguration().get<string>(\"authorTag\", values.Generic.authorTag);\n        values.Generic.authorName = Generic.getConfiguration().get<string>(\"authorName\", values.Generic.authorName);\n        values.Generic.authorEmail = Generic.getConfiguration().get<string>(\"authorEmail\", values.Generic.authorEmail);\n        values.Generic.dateTemplate = Generic.getConfiguration().get<string>(\"dateTemplate\", values.Generic.dateTemplate);\n        values.Generic.dateFormat = Generic.getConfiguration().get<string>(\"dateFormat\", values.Generic.dateFormat);\n        values.Generic.generateSmartText = Generic.getConfiguration().get<boolean>(\"generateSmartText\", values.Generic.generateSmartText);\n        values.Generic.splitCasingSmartText = Generic.getConfiguration().get<boolean>(\"splitCasingSmartText\", values.Generic.splitCasingSmartText);\n        values.Generic.order = Generic.getConfiguration().get<string[]>(\"order\", values.Generic.order);\n        values.Generic.customTags = Generic.getConfiguration().get<string[]>(\"customTags\", values.Generic.customTags);\n        values.Generic.filteredKeywords = Generic.getConfiguration().get<string[]>(\"filteredKeywords\", values.Generic.filteredKeywords);\n        values.Generic.useGitUserName = Generic.getConfiguration().get<boolean>(\"useGitUserName\", values.Generic.useGitUserName);\n        values.Generic.useGitUserEmail = Generic.getConfiguration().get<boolean>(\"useGitUserEmail\", values.Generic.useGitUserEmail);\n\n        return values;\n    }\n\n    public readonly paramTemplateReplace: string = \"{param}\";\n    public readonly typeTemplateReplace: string = \"{type}\";\n    public readonly nameTemplateReplace: string = \"{name}\";\n    public readonly authorTemplateReplace: string = \"{author}\";\n    public readonly emailTemplateReplace: string = \"{email}\";\n    public readonly dateTemplateReplace: string = \"{date}\";\n    public readonly yearTemplateReplace: string = \"{year}\";\n    public readonly textTemplateReplace: string = \"{text}\";\n\n    public C: C;\n    public Cpp: Cpp;\n    public File: File;\n    public Generic: Generic;\n\n    constructor() {\n        this.C = new C();\n        this.Cpp = new Cpp();\n        this.File = new File();\n        this.Generic = new Generic();\n    }\n}\n"
  },
  {
    "path": "src/DoxygenCompletionItemProvider.ts",
    "content": "import * as vscode from \"vscode\";\nimport { inComment } from \"./util\";\n\n// tslint:disable:max-line-length\n\n/*https://github.com/cschlosser/doxdocgen/issues/30 */\nexport default class DoxygenCompletionItemProvider implements vscode.CompletionItemProvider {\n    /**\n     * commands are a tuple of <command, snippet, documentation>\n     */\n    public static readonly commands: Array<[string, string, string]> = [\n        /*Special commands */\n        [\"a\", \"${1:word}\", \"Display `<word>` in italics\"],\n        [\"arg\", \"${1:item-description}\", \"Generate a simple, non-nested list of arguments\"],\n        [\"b\", \"${1:word}\", \"Display `<word>` in bold\"],\n        [\"c\", \"${1:word}\", \"Display `<word>` using a typewriter font\"],\n        [\"code\", \"{.${1:language-id}}\\n${2:code}\\n@endcode\", \"Starts a block of code\"], // TODO: match end block symbol with trigger character\n        [\"copydoc\", \"${1:link-object}\", \"Copy a documentation block from the object specified by `<link-object>` and paste it at the location of the command. The link object can point to a member (of a class, file or group), a class, a namespace, a group, a page, or a file. If the member is overloaded, you should specify the argument types explicitly\"],\n        [\"copybrief\", \"${1:link-object}\", \"Work in a similar way as `@copydoc` but will only copy the brief description, not the detailed documentation\"],\n        [\"copydetails\", \"${1:link-object}\", \"Work in a similar way as `@copydoc` but will only copy the detailed documentation, not the brief description\"],\n        [\"docbookonly\", \"$1\\n@enddocbookonly\", \"Start a block of text that only will be verbatim included in the generated DocBook documentation and tagged with `<docbookonly>` in the generated XML output\"],\n        [\"emoji\", \":${1:name}:\", \"Produce an emoji character given its name\"],\n        [\"startuml\", \"${1:file} \\\"${2:caption}\\\" ${3:size_indication}=${4:size}\\n@enduml\", \"Start a text fragment which should contain a valid description of a PlantUML diagram\"],\n        [\"e\", \"${1:word}\", \"Display `<word>` in italics\"],\n        [\"em\", \"${1:word}\", \"Display `<word>` in italics\"],\n        [\"endcode\", \"\", \"End a block of code\"],\n        [\"enddocbookonly\", \"\", \"End a block of text that was started with `@docbookonly` command\"],\n        [\"enduml\", \"\", \"End a block that was started with `@startuml`\"],\n        [\"endhtmlonly\", \"\", \"End a block of text that was started with a `@htmlonly` command\"],\n        [\"endlatexonly\", \"\", \"End a block of text that was started with a `@latexonly` command\"],\n        [\"endmanonly\", \"\", \"End a block of text that was started with a `@manonly` command\"],\n        [\"endxmlonly\", \"\", \"End a block of text that was started with a `@xmlonly` command\"],\n        [\"htmlonly\", \"$1\\n@endhtmlonly\", \"Start a block of text that only will be verbatim included in the generated HTML documentation and tagged with `<htmlonly>` in the generated XML output\"],\n        [\"image\", \"${1|html,latex,docbook,rtf|} ${2:file} ${3:caption} ${4:${5:size_inidication}=${6:size}}\", \"Insert an image into the documentation\"],\n        [\"latexonly\", \"$1\\n@endlatexonly\", \"Start a block of text that only will be verbatim included in the generated LATEX documentation and tagged with `<latexonly>` in the generated XML output\"],\n        [\"manonly\", \"$1\\n@manonly\", \"Start a block of text that only will be verbatim included in the generated MAN documentation and tagged with `<manonly>` in the generated XML output\"],\n        [\"li\", \"${1:item-description}\", \"Generate a simple, non-nested list of arguments\"],\n        [\"n\", \"\", \"Force a new line\"],\n        [\"verbatim\", \"$1\\n@verbatim\", \"Start a block of text that will be verbatim included in the documentation\"],\n        [\"xmlonly\", \"$1\\n@endxmlonly\", \"Start a block of text that will be verbatim included in the documentation\"],\n        /*Section indicators */\n        [\"attention\", \"${1:attention text}\", \"Start a paragraph where a message that needs attention may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@attention` commands will be joined into a single paragraph. The `@attention` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"author\", \"${1:author}\", \"Starts a paragraph where one or more author names may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@author` commands will be joined into a single paragraph. Each author description will start a new line. Alternatively, one `@author` command may mention several authors. The `@author` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"authors\", \"${1:list of authors}\", \"Equivalent to `@author`\"],\n        [\"brief\", \"${1:brief description}\", \"Starts a paragraph that serves as a brief description. For classes and files the brief description will be used in lists and at the start of the documentation page. For class and file members, the brief description will be placed at the declaration of the member and prepended to the detailed description. A brief description may span several lines (although it is advised to keep it brief!). A brief description ends when a blank line or another sectioning command is encountered. If multiple `@brief` commands are present they will be joined.\"],\n        [\"bug\", \"${1:bug description}\", \"Starts a paragraph where one or more bugs may be reported. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@bug` commands will be joined into a single paragraph. Each bug description will start on a new line. Alternatively, one `@bug` command may mention several bugs. The `@bug` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"cond\", \"${1:section label}\", \"Starts a conditional section that ends with a corresponding `@endcond` command, which is typically found in another comment block\"],\n        [\"copyright\", \"${1:copyright description}\", \"Starts a paragraph where the copyright of an entity can be described. This paragraph will be indented.\"],\n        [\"date\", \"${1:date description}\", \"Starts a paragraph where one or more dates may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@date` commands will be joined into a single paragraph. Each date description will start on a new line. Alternatively, one `@date` command may mention several dates. The `@date` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"deprecated\", \"${1:description}\", \"Starts a paragraph indicating that this documentation block belongs to a deprecated entity\"],\n        [\"details\", \"${1:description}\", \"Just like `@brief` starts a brief description, `@details` starts the detailed description. You can also start a new paragraph (blank line) then the `@details` command is not needed.\"],\n        [\"noop\", \"\", \"All the text, including the command, till the end of the line is ignored\"],\n        [\"else\", \"\", \"Starts a conditional section if the previous conditional section was not enabled. The previous section should have been started with a `@if`, `@ifnot`, or `@elseif` command.\"],\n        [\"elseif\", \"${1:section-label}\", \"Starts a conditional documentation section if the previous section was not enabled. A conditional section is disabled by default. To enable it you must put the section-label after the ENABLED_SECTIONS tag in the configuration file. The section label can be a logical expression build of section names, round brackets, && (AND), || (OR) and ! (NOT). Conditional blocks can be nested. A nested section is only enabled if all enclosing sections are enabled as well.\"],\n        [\"endcond\", \"\", \"Ends a conditional section that was started by `@cond`.\"],\n        [\"endif\", \"\", \"Ends a conditional section that was started by `@if` or `@ifnot` For each `@if` or `@ifnot` one and only one matching `@endif` must follow.\"],\n        [\"exception\", \"${1:exception-object} ${2:exception description}\", \"Starts an exception description for an exception object with name `<exception-object>`. Followed by a description of the exception. The existence of the exception object is not checked. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent @exception commands will be joined into a single paragraph. Each exception description will start on a new line. The `@exception` description ends when a blank line or some other sectioning command is encountered\"],\n        [\"if\", \"${1:section-label}\\n$2\\n@endif\", \"Starts a conditional documentation section. The section ends with a matching `@endif` command. A conditional section is disabled by default. To enable it you must put the section-label after the ENABLED_SECTIONS tag in the configuration file. The section label can be a logical expression build of section names, round brackets, && (AND), || (OR) and!(NOT). If you use an expression you need to wrap it in round brackets, i.e. `@cond(!LABEL1 && LABEL2)`.\"],\n        [\"ifnot\", \"${1:section-label}\", \"Starts a conditional documentation section. The section ends with a matching `@endif` command. This conditional section is enabled by default. To disable it you must put the section-label after the ENABLED_SECTIONS tag in the configuration file. The section label can be a logical expression build of section names, round brackets, && (AND), || (OR) and ! (NOT).\"],\n        [\"invariant\", \"${1:description of invariant}\", \"Starts a paragraph where the invariant of an entity can be described. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@invariant` commands will be joined into a single paragraph. Each invariant description will start on a new line. Alternatively, one `@invariant` command may mention several invariants. The `@invariant` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"note\", \"${1:text}\", \"Starts a paragraph where a note can be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@note` commands will be joined into a single paragraph. Each note description will start on a new line. Alternatively, one `@note` command may mention several notes. The `@note` command ends when a blank line or some other sectioning command is encountered\"],\n        [\"par\", \"${1:paragraph title}\\n$2\", \"If a paragraph title is given this command starts a paragraph with a user defined heading. The heading extends until the end of the line. The paragraph following the command will be indented. If no paragraph title is given this command will start a new paragraph. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. The `@par` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"param\", \"${1:parameter-name} ${2:description}\", \"Starts a parameter description for a function parameter with name `<parameter-name>`, followed by a description of the parameter. The existence of the parameter is checked and a warning is given if the documentation of this (or any other) parameter is missing or not present in the function declaration or definition. Multiple adjacent `@param` commands will be joined into a single paragraph. Each parameter description will start on a new line. The `@param` description ends when a blank line or some other sectioning command is encountered. Note that you can also document multiple parameters with a single `@param` command using a comma separated list.\"],\n        [\"parblock\", \"\\n$1\\n@endparblock\", \"For commands that expect a single paragraph as argument (such as `@par`, `@param` and `@warning`), the `@parblock` command allows to start a description that covers multiple paragraphs, which then ends with `@endparblock`.\"],\n        [\"endparblock\", \"\", \"This ends a block of paragraphs started with `@parblock`.\"],\n        [\"tparam\", \"${1:template-parameter-name} ${2:description}\", \"Starts a template parameter for a class or function template parameter with name `<template-parameter-name>`, followed by a description of the template parameter.\"],\n        [\"post\", \"${1:description of the postcondition}\", \"Starts a paragraph where the postcondition of an entity can be described. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@post` commands will be joined into a single paragraph. Each postcondition will start on a new line. Alternatively, one `@post` command may mention several postconditions. The `@post` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"pre\", \"${1:description of the precondition}\", \"Starts a paragraph where the precondition of an entity can be described. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@pre` commands will be joined into a single paragraph. Each precondition will start on a new line. Alternatively, one `@pre` command may mention several preconditions. The `@pre` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"remark\", \"${1:remark text}\", \"Starts a paragraph where one or more remarks may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@remark` commands will be joined into a single paragraph. Each remark will start on a new line. Alternatively, one `@remark` command may mention several remarks. The `@remark` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"remarks\", \"${1:remark text}\", \"Equivalent to `@remark`\"],\n        [\"result\", \"${1:description of the result value}\", \"Equivalent to `@return`\"],\n        [\"return\", \"${1:description of the return value}\", \"Starts a return value description for a function. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@return` commands will be joined into a single paragraph. The `@return` description ends when a blank line or some other sectioning command is encountered\"],\n        [\"returns\", \"${1:description of the return value}\", \"Equivalent to `@return`\"],\n        [\"retval\", \"${1:return value} ${2:description}\", \"Starts a description for a function's return value with name `<return value>`, followed by a description of the return value. The text of the paragraph that forms the description has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@retval` commands will be joined into a single paragraph. Each return value description will start on a new line. The `@retval` description ends when a blank line or some other sectioning command is encountered.\"],\n        [\"sa\", \"${1:reference}\", \"Starts a paragraph where one or more cross-references to classes, functions, methods, variables, files or URL may be specified. Two names joined by either `::` or `#` are understood as referring to a class and one of its members. One of several overloaded methods or constructors may be selected by including a parenthesized list of argument types after the method name.\"],\n        [\"see\", \"${1:reference}\", \"Equivalent to `@sa`\"],\n        [\"short\", \"${1:short description\", \"Equivalent to `@brief`\"],\n        [\"since\", \"${1:text}\", \"This command can be used to specify since when (version or time) an entity is available. The paragraph that follows `@since` does not have any special internal structure. All visual enhancement commands may be used inside the paragraph. The `@since` description ends when a blank line or some other sectioning command is encountered.\"],\n        [\"test\", \"${1:paragraph describing a test case\", \"This command can be used to specify since when (version or time) an entity is available. The paragraph that follows `@since` does not have any special internal structure. All visual enhancement commands may be used inside the paragraph. The `@since` description ends when a blank line or some other sectioning command is encountered.\"],\n        [\"throw\", \"${1:exception-object} ${2:exception description}\", \"Equivalent to `@exception`\"],\n        [\"throws\", \"${1:exception-object} ${2:exception description}\", \"Equivalent to `@exception`\"],\n        [\"todo\", \"${1:paragraph describing what is to be done}\", \"Starts a paragraph where a `TODO` item is described. The description will also add an item to a separate `TODO` list. The two instances of the description will be cross-referenced. Each item in the `TODO` list will be preceded by a header that indicates the origin of the item.\"],\n        [\"version\", \"${1:version number}\", \"Starts a paragraph where one or more version strings may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@version` commands will be joined into a single paragraph. Each version description will start on a new line. Alternatively, one `@version` command may mention several version strings. The `@version` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"warning\", \"${1:warning message}\", \"Starts a paragraph where one or more warning messages may be entered. The paragraph will be indented. The text of the paragraph has no special internal structure. All visual enhancement commands may be used inside the paragraph. Multiple adjacent `@warning` commands will be joined into a single paragraph. Each warning description will start on a new line. Alternatively, one `@warning` command may mention several warnings. The `@warning` command ends when a blank line or some other sectioning command is encountered.\"],\n        [\"xrefitem\", \"${1:key} \\\"${2:heading}\\\" \\\"${3:list title}\\\" ${4:text}\", \"This command is a generalization of commands such as `@todo` and `@bug`. It can be used to create user-defined text sections which are automatically cross-referenced between the place of occurrence and a related page, which will be generated. On the related page all sections of the same type will be collected.\"],\n        /*Commands to create links */\n        [\"addindex\", \"${1:text}\", \"This command adds `text` to the LATEX, DocBook and RTF index.\"],\n        [\"anchor\", \"${1:word}\", \"This command places an invisible, named anchor into the documentation to which you can refer with the `@ref` command.\"],\n        [\"cite\", \"${1:label}\", \"Adds a bibliographic reference in the text and in the list of bibliographic references. The `<label>` must be a valid BibTeX label that can be found in one of the `.bib` files listed in `CITE_BIB_FILES`. For the LATEX output the formatting of the reference in the text can be configured with `LATEX_BIB_STYLE`. For other output formats a fixed representation is used. Note that using this command requires the bibtex tool to be present in the search path.\"],\n        [\"endlink\", \"\", \"This command ends a link that is started with the `@link` command.\"],\n        [\"link\", \"${1:link-object} @endlink\", \"The links that are automatically generated by doxygen always have the name of the object they point to as link-text. The `@link` command can be used to create a link to an object (a file, class, or member) with a user specified link-text. The link command should end with an `@endlink` command. All text between the `@link` and `@endlink` commands serves as text for a link to the `<link-object>` specified as the first argument of `@link`.\"],\n        [\"ref\", \"${1:name} \\\"${2:text}\\\"\", \"Creates a reference to a named section, subsection, page or anchor. For HTML documentation the reference command will generate a link to the section. For a section or subsection the title of the section will be used as the text of the link. For an anchor the optional text between quotes will be used or `<name>` if no text is specified. For LATEX documentation the reference command will generate a section number for sections or the text followed by a page number if `<name>` refers to an anchor.\"],\n        [\"refitem\", \"${1:name}\", \"Just like the `@ref` command, this command creates a reference to a named section, but this reference appears in a list that is started by `@secreflist` and ends with `@endsecreflist`.\"],\n        [\"secreflist\", \"$1\\n@endsecreflist\", \"Starts an index list of item, created with `@refitem` that each link to a named section.\"],\n        [\"endsecreflist\", \"\", \"End an index list started with `@secreflist`.\"],\n        [\"subpage\", \"${1:name} \\\"${2:text}\\\"\", \"This command can be used to create a hierarchy of pages.\"],\n        [\"tableofcontents\", \"{${1|HTML,LaTeX,XML,DocBook|}:${2:level}}\", \"Creates a table of contents at the top of a page, listing all sections and subsections in the page.\"],\n        [\"section\", \"${1:section-name} ${2:section title}\", \"Creates a section with name `<section-name>`.\"],\n        [\"subsection\", \"${1:subsection-name} ${2:subsection title}\", \"Creates a subsection with name `<subsection-name>`.\"],\n        [\"subsubsection\", \"${1:subsubsection-name} ${2:subsubsection title}\", \"Creates a subsubsection with name `<subsubsection-name>`.\"],\n        [\"paragraph\", \"${1:paragraph-name} ${2:paragraph title}\", \"Creates a named paragraph with name `<paragraph-name>`.\"],\n        /*Commands for displaying examples */\n        [\"include\", \"{${1|lineno,doc|}} ${2:file-name}\", \"This command can be used to include a source file as a block of code. Using the `@include` command is equivalent to inserting the file into the documentation block and surrounding it with `@code` and `@endcode` commands.\"],\n        [\"line\", \"${1:pattern}\", \"This command searches line by line through the example that was last included using `@include` or `@dontinclude` until it finds a non-blank line. If that line contains the specified pattern, it is written to the output.\"],\n        [\"skip\", \"${1:pattern}\", \"This command searches line by line through the example that was last included using `@include` or `@dontinclude` until it finds a line that contains the specified pattern.\"],\n        [\"skipline\", \"${1:pattern}\", \"This command searches line by line through the example that was last included using `@include` or `@dontinclude` until it finds a line that contains the specified pattern. It then writes the line to the output.\"],\n        [\"snippet\", \"{${1|lineno,doc|}} ${2:file-name} ${3:block_id}\", \"Where the `@include` command can be used to include a complete file as source code, this command can be used to quote only a fragment of a source file. In case this is used as `<file-name>` the current file is taken as file to take the snippet from.\"],\n        [\"until\", \"${1:pattern}\", \"This command writes all lines of the example that was last included using `@include` or `@dontinclude` to the output, until it finds a line containing the specified pattern. The line containing the pattern will be written as well.\"],\n        [\"verbinclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` verbatim in the documentation. The command is equivalent to pasting the contents of the file in the documentation and placing `@verbatim` and `@endverbatim` commands around it.\"],\n        [\"htmlinclude\", \"${1:[block]} ${2:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the HTML documentation and tagged with `<htmlonly>` in the generated XML output. The command is equivalent to pasting the contents of the file in the documentation and placing `@htmlonly` and `@endhtmlonly` commands around it.\"],\n        [\"latexinclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the LaTeX documentation and tagged with `<latexonly>` in the generated XML output. The command is equivalent to pasting the contents of the file in the documentation and placing `@latexonly` and `@endlatexonly` commands around it.\"],\n        [\"rtfinclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the RTF documentation and tagged with `<rtfonly>` in the generated XML output. The command is equivalent to pasting the contents of the file in the documentation and placing `@rtfonly` and `@endrtfonly` commands around it.\"],\n        [\"maninclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the MAN documentation and tagged with `<manonly>` in the generated XML output. The command is equivalent to pasting the contents of the file in the documentation and placing `@manonly` and `@endmanonly` commands around it.\"],\n        [\"docbookinclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the DocBook documentation and tagged with `<docbookonly>` in the generated XML output. The command is equivalent to pasting the contents of the file in the documentation and placing `@docbookonly` and `@enddocbookonly` commands around it.\"],\n        [\"xmlinclude\", \"${1:file-name}\", \"This command includes the contents of the file `<file-name>` as is in the XML documentation. The command is equivalent to pasting the contents of the file in the documentation and placing `@xmlonly` and `@endxmlonly` commands around it.\"],\n    ];\n    public static completionItems = (() => {\n        const items: vscode.CompletionItem[] = [];\n        const addPrefix = vscode.workspace.getConfiguration(\"doxdocgen.generic\").get<boolean>(\"commandSuggestionAddPrefix\");\n        for (const item of DoxygenCompletionItemProvider.commands) {\n            // TODO: Only \\ can be used, @ as label prefix causes unexpected filtering\n            const newItem = new vscode.CompletionItem(addPrefix ? `\\\\${item[0]}` : item[0]);\n            newItem.documentation = new vscode.MarkdownString(item[2]);\n            newItem.insertText = new vscode.SnippetString(`${item[0]} ${item[1]}`);\n            newItem.kind = vscode.CompletionItemKind.Snippet;\n            items.push(newItem);\n        }\n        return items;\n    })();\n\n    public trigger: string = \"\";\n    public indentSpace: number;\n    public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {\n        if (inComment(vscode.window.activeTextEditor, position.line + 1)) {\n            this.trigger = context.triggerCharacter;\n            this.indentSpace = position.character;\n            return DoxygenCompletionItemProvider.completionItems;\n        }\n        return [];\n    }\n\n    public resolveCompletionItem(item: vscode.CompletionItem, token: vscode.CancellationToken) {\n        let insertion = (item.insertText as vscode.SnippetString).value;\n        if (this.trigger === \"\\\\\") {\n            insertion = insertion.replace(\"@\", \"\\\\\");\n        }\n        const indentPrefix = \"\\n\".concat(\"* \");\n        insertion = insertion.replace(/\\n/g, indentPrefix);\n\n        /*insert an empty line if the snippet is multi-line, so * can be auto-completed */\n        if (insertion.includes(\"\\n\")) {\n            insertion = insertion.concat(indentPrefix);\n        }\n\n        const newItem = new vscode.CompletionItem(item.label, item.kind);\n        newItem.documentation = item.documentation;\n        newItem.insertText = new vscode.SnippetString(insertion);\n        return newItem;\n    }\n}\n"
  },
  {
    "path": "src/GitConfig.ts",
    "content": "import simpleGit, { ConfigValues, SimpleGit } from \"simple-git\";\nimport { workspace } from \"vscode\";\n\nexport default class GitConfig {\n    private gitConfig: ConfigValues;\n\n    public constructor() {\n        let git: SimpleGit;\n        try {\n            git = simpleGit(workspace.workspaceFolders?.[0].uri.fsPath);\n        } catch (error) {\n            git = simpleGit();\n        }\n\n        git.listConfig().then((result) => {\n            this.gitConfig = result.all;\n        });\n    }\n\n    /** git config --get user.name */\n    get UserName(): string {\n        try {\n            return this.gitConfig[\"user.name\"].toString();\n        } catch (error) {\n            return \"\";\n        }\n    }\n\n    /** git config --get user.email */\n    get UserEmail(): string {\n        try {\n            return this.gitConfig[\"user.email\"].toString();\n        } catch (error) {\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Lang/Cpp/CppArgument.ts",
    "content": "import { CppParseTree } from \"./CppParseTree\";\n\nexport class CppArgument {\n    public name: string = null;\n    public type: CppParseTree =  new CppParseTree();\n}\n"
  },
  {
    "path": "src/Lang/Cpp/CppDocGen.ts",
    "content": "import * as moment from \"moment\";\nimport { Position, Range, Selection, TextEditor } from \"vscode\";\nimport { IDocGen } from \"../../Common/IDocGen\";\nimport { Config } from \"../../Config\";\nimport GitConfig from \"../../GitConfig\";\nimport * as templates from \"../../templatedString\";\nimport { getIndentation } from \"../../util\";\nimport { CppArgument } from \"./CppArgument\";\nimport * as CppParser from \"./CppParser\";\nimport { CppToken, CppTokenType } from \"./CppToken\";\n\nexport enum SpecialCase {\n    none,\n    constructor,\n    destructor,\n    getter,\n    setter,\n    factoryMethod,\n}\n\nexport enum CommentType {\n    method,\n    file,\n}\n\nexport enum CasingType {\n    Pascal,\n    camel,\n    snake,\n    SCREAMING_SNAKE,\n    UPPER,\n    uncertain,\n}\n\nexport class CppDocGen implements IDocGen {\n    protected activeEditor: TextEditor;\n\n    protected readonly cfg: Config;\n\n    protected func: CppArgument;\n    protected templateParams: string[];\n    protected params: CppArgument[];\n\n    protected specialCase: SpecialCase;\n    protected commentType: CommentType;\n    protected casingType: CasingType;\n\n    protected smartTextLength: number;\n\n    protected vscodeAutoGeneratedComment: boolean;\n\n    private gitConfig;\n\n    /**\n     * @param  {TextEditor} actEdit Active editor window\n     * @param  {Position} cursorPosition Where the cursor of the user currently is\n     * @param  {string[]} templateParams The template parameters of the declaration.\n     * @param  {CppArgument} func The type and name of the function to generate doxygen.\n     *                          Doesn't contain anything if it is not a function.\n     * @param  {CppArgument[]} params The parameters of the function. Doesn't contain anything if it is not a function.\n     * @param  {boolean} vscodeAutoGeneratedComment Set this to true if VS Code inserted an autogenerated comment closer\n     *                                              on the next line after the comment.\n     */\n    public constructor(\n        actEdit: TextEditor,\n        cursorPosition: Position,\n        cfg: Config,\n        templateParams: string[],\n        func: CppArgument,\n        params: CppArgument[],\n        specialCase: SpecialCase,\n        commentType: CommentType,\n        casingType: CasingType,\n        vscodeAutoGeneratedComment: boolean,\n    ) {\n        this.activeEditor = actEdit;\n        this.cfg = cfg;\n        this.templateParams = templateParams;\n        this.func = func;\n        this.params = params;\n        this.specialCase = specialCase;\n        this.commentType = commentType;\n        this.smartTextLength = 0;\n        this.casingType = casingType;\n        this.vscodeAutoGeneratedComment = vscodeAutoGeneratedComment;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public GenerateDoc(rangeToReplace: Range, gitConfig: GitConfig) {\n        let comment: string = \"\";\n        this.gitConfig = gitConfig;\n        if (this.commentType === CommentType.file) {\n            comment = this.generateFileDescription();\n        } else if (this.commentType === CommentType.method) {\n            comment = this.generateComment();\n        }\n\n        // overwrite any autogenerated comment closer\n        let modifiedRangeToReplace = rangeToReplace;\n        if (this.vscodeAutoGeneratedComment) {\n            const newPos: Position = new Position(\n                modifiedRangeToReplace.end.line + 1,\n                modifiedRangeToReplace.end.character,\n            );\n            modifiedRangeToReplace = new Range(rangeToReplace.start, newPos);\n        }\n\n        this.activeEditor.edit((editBuilder) => {\n            editBuilder.replace(modifiedRangeToReplace, comment); // Insert the comment\n        });\n\n        // Set cursor to first DoxyGen command.\n        this.moveCursurToFirstDoxyCommand(\n            comment,\n            modifiedRangeToReplace.start.line,\n            modifiedRangeToReplace.start.character,\n        );\n    }\n\n    /***************************************************************************\n                                    Implementation\n     ***************************************************************************/\n\n    protected getSmartText(): string {\n        if (!this.cfg.Generic.generateSmartText) {\n            return \"\";\n        }\n        let val: string = \"\";\n        let text: string = \"\";\n        switch (this.specialCase) {\n            case SpecialCase.constructor: {\n                if (this.func.name === null) {\n                    return \"\";\n                } else {\n                    const ctorText = this.func.name.trim();\n                    this.casingType = CppParser.default.checkCasing(ctorText, 0);\n                    val = this.splitCasing(ctorText).trim();\n                    text = this.cfg.Cpp.ctorText;\n                    break;\n                }\n            }\n            case SpecialCase.destructor: {\n                if (this.func.name === null) {\n                    return \"\";\n                } else {\n                    const dtorText = this.func.name.replace(\"~\", \"\").trim();\n                    this.casingType = CppParser.default.checkCasing(dtorText, 0);\n                    val = this.splitCasing(dtorText).trim();\n                    text = this.cfg.Cpp.dtorText;\n                    break;\n                }\n            }\n            case SpecialCase.getter: {\n                val = this.splitCasing(this.func.name.trim()).trim().substr(3).trim();\n                text = this.cfg.C.getterText;\n                break;\n            }\n            case SpecialCase.setter: {\n                val = this.splitCasing(this.func.name.trim()).trim().substr(3).trim();\n                text = this.cfg.C.setterText;\n                break;\n            }\n            case SpecialCase.factoryMethod: {\n                val = this.splitCasing(this.func.name.trim()).trim().substr(6).trim();\n                text = this.cfg.C.factoryMethodText;\n                break;\n            }\n            case SpecialCase.none:\n            default: {\n                return \"\";\n            }\n        }\n        const str = templates.getTemplatedString(text, { toReplace: this.cfg.nameTemplateReplace, with: val });\n        this.smartTextLength = str.length;\n        return str;\n    }\n\n    protected generateBrief(lines: string[]) {\n        lines.push(\n            ...templates.getTemplatedString(\n                this.cfg.Generic.briefTemplate,\n                { toReplace: this.cfg.textTemplateReplace, with: this.getSmartText() },\n            ).split(\"\\n\"),\n        );\n    }\n\n    protected generateReturnParams(): string[] {\n\n        const params: string[] = [];\n\n        // Check if return type is a pointer\n        const ptrReturnIndex = this.func.type.nodes\n            .findIndex((n) => n instanceof CppToken && n.type === CppTokenType.Pointer);\n\n        // Special case for void functions.\n        const voidReturnIndex = this.func.type.nodes\n            .findIndex((n) => n instanceof CppToken && n.type === CppTokenType.Symbol && n.value === \"void\");\n\n        // Special case for bool return type.\n        const boolReturnIndex: number = this.func.type.nodes\n            .findIndex((n) => n instanceof CppToken && n.type === CppTokenType.Symbol && n.value === \"bool\");\n\n        if (boolReturnIndex !== -1 && this.cfg.Generic.boolReturnsTrueFalse === true) {\n            params.push(\"true\");\n            params.push(\"false\");\n        } else if (voidReturnIndex !== -1 && ptrReturnIndex !== -1) {\n            params.push(this.cfg.Generic.includeTypeAtReturn === true ? this.func.type.Yield() : \"\");\n        } else if (voidReturnIndex === -1 && this.func.type.nodes.length > 0) {\n            params.push(this.cfg.Generic.includeTypeAtReturn === true ? this.func.type.Yield() : \"\");\n        } else {\n            if (this.cfg.Generic.includeTypeAtReturn === false) {\n                return [];\n            }\n        }\n        if (this.cfg.Generic.includeTypeAtReturn === false) {\n            return [\"\"];\n        }\n\n        return params;\n    }\n\n    protected generateAuthorTag(lines: string[]) {\n        if (this.cfg.Generic.authorTag.trim().length !== 0) {\n            const authorInfo = this.getAuthorInfo();\n            // Allow substitution of {author} and {email} only\n            lines.push(\n                ...templates.getMultiTemplatedString(\n                    this.cfg.Generic.authorTag,\n                    [\n                        { toReplace: this.cfg.authorTemplateReplace, with: authorInfo.authorName },\n                        { toReplace: this.cfg.emailTemplateReplace, with: authorInfo.authorEmail },\n                    ],\n                ).split(\"\\n\"),\n            );\n        }\n    }\n\n    protected generateFilenameFromTemplate(lines: string[]) {\n        if (this.cfg.File.fileTemplate.trim().length !== 0) {\n            templates.generateFromTemplate(\n                lines,\n                this.cfg.nameTemplateReplace,\n                this.cfg.File.fileTemplate,\n                [this.activeEditor.document.fileName.replace(/^.*[\\\\\\/]/, \"\")],\n            );\n        }\n    }\n\n    protected generateVersionTag(lines: string[]) {\n        if (this.cfg.File.versionTag.trim().length !== 0) {\n            lines.push(...templates.getIndentedTemplate(this.cfg.File.versionTag).split(\"\\n\"));\n        }\n    }\n\n    protected generateCopyrightTag(lines: string[]) {\n        // This currently only supports year substitution\n        this.cfg.File.copyrightTag.forEach((element) => {\n            templates.generateFromTemplate(\n                lines,\n                this.cfg.yearTemplateReplace,\n                element,\n                [moment().format(\"YYYY\")],\n            );\n        });\n    }\n\n    /**\n     * Generate those tags shared between File comment and function comment\n     */\n    protected generateCommonTag(lines: string[], tags: string) {\n        switch (tags) {\n            case \"brief\": {\n                this.insertBrief(lines);\n                break;\n            }\n            case \"empty\": {\n                lines.push(\"\");\n                break;\n            }\n            case \"version\": {\n                this.generateVersionTag(lines);\n                break;\n            }\n            case \"author\": {\n                this.generateAuthorTag(lines);\n                break;\n            }\n            case \"date\": {\n                this.generateDateFromTemplate(lines);\n                break;\n            }\n            case \"copyright\": {\n                this.generateCopyrightTag(lines);\n                break;\n            }\n            default: {\n                break;\n            }\n        }\n    }\n\n    protected generateCustomTag(lines: string[], target = CommentType.file) {\n        let dateFormat: string = \"YYYY-MM-DD\"; // Default to ISO standard if not defined\n        if ( this.cfg.Generic.dateFormat.trim().length !== 0) {\n            dateFormat = this.cfg.Generic.dateFormat; // Overwrite with user format\n        }\n\n        // Have to check this setting, otherwise {author} and {email} will get incorrect result\n        // if useGitUserName and useGitUserEmail is used\n        const authorInfo = this.getAuthorInfo();\n\n        const targetTagArray = target === CommentType.file ? this.cfg.File.customTag : this.cfg.Generic.customTags;\n        // For each line of the customTag\n        targetTagArray.forEach((element) => {\n            if (element !== \"custom\") { // Prevent recursive expansion\n                // Allow any of date, year, author, email to be replaced\n                lines.push(\n                    ...templates.getMultiTemplatedString(\n                        element,\n                        [\n                            { toReplace: this.cfg.authorTemplateReplace, with: authorInfo.authorName },\n                            { toReplace: this.cfg.emailTemplateReplace, with: authorInfo.authorEmail },\n                            { toReplace: this.cfg.dateTemplateReplace, with: moment().format(dateFormat) },\n                            { toReplace: this.cfg.yearTemplateReplace, with: moment().format(\"YYYY\") },\n                            { toReplace: \"{file}\", with: this.activeEditor.document.fileName.replace(/^.*[\\\\\\/]/, \"\")},\n                        ],\n                    ).split(\"\\n\"),\n                );\n            }\n        });\n    }\n\n    protected generateDateFromTemplate(lines: string[]) {\n        if (this.cfg.Generic.dateTemplate.trim().length !== 0 &&\n            this.cfg.Generic.dateFormat.trim().length !== 0) {\n            templates.generateFromTemplate(\n                lines,\n                this.cfg.dateTemplateReplace,\n                this.cfg.Generic.dateTemplate,\n                [moment().format(this.cfg.Generic.dateFormat)],\n            );\n        }\n    }\n\n    protected insertFirstLine(lines: string[]) {\n        if (this.cfg.C.firstLine.trim().length !== 0) {\n            lines.unshift(this.cfg.C.firstLine);\n        }\n    }\n\n    protected insertBrief(lines: string[]) {\n        if (this.cfg.Generic.briefTemplate.trim().length !== 0) {\n            this.generateBrief(lines);\n        }\n    }\n\n    protected insertLastLine(lines: string[]) {\n        if (this.cfg.C.lastLine.trim().length !== 0) {\n            lines.push(this.cfg.C.lastLine);\n        }\n    }\n\n    protected generateFileDescription(): string {\n        let lines: string[] = [];\n\n        this.cfg.File.fileOrder.forEach((element) => {\n            switch (element) {\n                case \"file\": {\n                    this.generateFilenameFromTemplate(lines);\n                    break;\n                }\n                case \"custom\": {\n                    this.generateCustomTag(lines, CommentType.file);\n                    break;\n                }\n                default: {\n                    this.generateCommonTag(lines, element);\n                }\n            }\n        });\n\n        lines = lines.map((line) => `${this.cfg.C.commentPrefix}${line}`);\n        this.insertFirstLine(lines);\n        this.insertLastLine(lines);\n\n        return lines.join(\"\\n\");\n    }\n\n    protected generateComment(): string {\n        let lines: string[] = [];\n\n        this.cfg.Generic.order.forEach((element) => {\n            switch (element) {\n                case \"tparam\": {\n                    if (this.cfg.Cpp.tparamTemplate.trim().length !== 0 && this.templateParams.length > 0) {\n                        templates.generateFromTemplate(\n                            lines,\n                            this.cfg.paramTemplateReplace,\n                            this.cfg.Cpp.tparamTemplate,\n                            this.templateParams,\n                        );\n                    }\n                    break;\n                }\n                case \"param\": {\n                    if (this.cfg.Generic.paramTemplate.trim().length !== 0 && this.params.length > 0) {\n                        const paramNames: string[] = this.params.map((p) => p.name);\n                        templates.generateFromTemplate(\n                            lines,\n                            this.cfg.paramTemplateReplace,\n                            this.cfg.Generic.paramTemplate,\n                            paramNames,\n                        );\n                    }\n                    break;\n                }\n                case \"return\": {\n                    if (this.cfg.Generic.returnTemplate.trim().length !== 0 && this.func.type !== null) {\n                        const returnParams = this.generateReturnParams();\n                        templates.generateFromTemplate(\n                            lines,\n                            this.cfg.typeTemplateReplace,\n                            this.cfg.Generic.returnTemplate,\n                            returnParams,\n                        );\n                    }\n                    break;\n                }\n                case \"custom\": {\n                    this.generateCustomTag(lines, CommentType.method);\n                    break;\n                }\n                default: {\n                    this.generateCommonTag(lines, element);\n                }\n            }\n        });\n\n        lines = lines.map((line) => `${this.cfg.C.commentPrefix}${line}`);\n        this.insertFirstLine(lines);\n        this.insertLastLine(lines);\n\n        return lines.join(`\\n${getIndentation(this.activeEditor)}`);\n    }\n\n    protected moveCursurToFirstDoxyCommand(comment: string, baseLine: number, baseCharacter) {\n        // Find first offset of a new line in the comment. Since that's when the line where the first param starts.\n        let line: number = baseLine;\n        let character: number = comment.indexOf(\"\\n\");\n\n        // If a first line is included find the 2nd line with a newline.\n        if (this.cfg.C.firstLine.trim().length !== 0) {\n            line++;\n            const oldCharacter: number = character;\n            character = comment.indexOf(\"\\n\", oldCharacter + 1) - oldCharacter;\n        }\n\n        // If newline is not found means no first param was found so Set to base line before the newline.\n        if (character < 0) {\n            line = baseLine;\n            character = baseCharacter;\n        }\n        const to: Position = new Position(line, character);\n        this.activeEditor.selection = new Selection(to, to);\n    }\n\n    protected splitCasing(text: string): string {\n        if (!this.cfg.Generic.splitCasingSmartText) {\n            return text;\n        }\n        let txt = text;\n        let vals: string[] = [];\n        switch (this.casingType) {\n            case CasingType.SCREAMING_SNAKE: {\n                txt = txt.toLowerCase();\n            }\n            case CasingType.snake: {\n                vals = txt.split(\"_\");\n                break;\n            }\n            case CasingType.Pascal: {\n                txt = txt.replace(/([A-Z0-9])/g, \" $1\");\n                vals.push(txt);\n                break;\n            }\n            case CasingType.camel: {\n                txt = txt.replace(/([a-zA-Z0-9])(?=[A-Z])/g, \"$1 \");\n                vals.push(txt);\n                break;\n            }\n            case CasingType.UPPER:\n            case CasingType.uncertain:\n            default: {\n                return text;\n            }\n        }\n\n        return vals.join(\" \");\n    }\n\n    /**\n     * Get author info, possibly using info from git config\n     */\n    private getAuthorInfo() {\n        let authorName: string = this.cfg.Generic.authorName;\n        let authorEmail: string = this.cfg.Generic.authorEmail;\n\n        // Check if set to use the git username\n        if (this.cfg.Generic.useGitUserName === true) {\n            authorName = this.gitConfig.UserName;\n        }\n\n        // Check if set to use the git email\n        if (this.cfg.Generic.useGitUserEmail === true) {\n            authorEmail = this.gitConfig.UserEmail;\n        }\n        return {\n            authorEmail,\n            authorName,\n        };\n    }\n}\n"
  },
  {
    "path": "src/Lang/Cpp/CppParseTree.ts",
    "content": "import { CppToken, CppTokenType } from \"./CppToken\";\n\nexport class CppParseTree {\n\n    /**\n     * Create a tree from CppTokens. This consumes the CppTokens.\n     * @param CppTokens The CppTokens to create a tree for.\n     * @param inNested If currently allready nesting.\n     */\n    public static CreateTree(CppTokens: CppToken[], inNested: boolean = false): CppParseTree {\n        const tree: CppParseTree = new CppParseTree();\n\n        while (CppTokens.length > 0) {\n            const token: CppToken = CppTokens.shift();\n            switch (token.type) {\n                case CppTokenType.OpenParenthesis:\n                    tree.nodes.push(this.CreateTree(CppTokens, true));\n                    break;\n                case CppTokenType.CloseParenthesis:\n                    if (inNested === false) {\n                        throw new Error(\"Unmatched closing parenthesis.\");\n                    }\n                    return tree;\n                default:\n                    tree.nodes.push(token);\n                    break;\n            }\n        }\n\n        if (inNested === true) {\n            throw new Error(\"No match found for an opening parenthesis.\");\n        }\n\n        return tree;\n    }\n\n    public nodes: Array<CppToken | CppParseTree> = [];\n\n    /**\n     * Compact empty branches. Example ((foo))(((bar))) will become (foo)(bar)\n     * @param tree The CppParseTree to compact. Defaults to the current tree.\n     */\n    public Compact(tree: CppParseTree = this): CppParseTree {\n        const newTree: CppParseTree = new CppParseTree();\n        newTree.nodes = tree.nodes.map((n) => n);\n        const isNotCompact = (n) => {\n            return n instanceof CppParseTree\n                && n.nodes.length === 1 && n.nodes[0] instanceof CppParseTree;\n        };\n\n        // Compact current level of nodes to the maximum amount.\n        while (newTree.nodes.some((n) => isNotCompact(n))) {\n            newTree.nodes = newTree.nodes\n                .map((n) =>  n instanceof CppParseTree && isNotCompact(n) ? n.nodes[0] : n);\n        }\n\n        // Compact all nested CppParseTrees.\n        newTree.nodes = newTree.nodes\n            .map((n) => n instanceof CppParseTree ? this.Compact(n) : n);\n\n        return newTree;\n    }\n\n    /**\n     * Copy CppParseTree.\n     * @param tree The CppParseTree to compact. Defaults to the current tree.\n     */\n    public Copy(tree: CppParseTree = this): CppParseTree {\n        const newTree: CppParseTree = new CppParseTree();\n        newTree.nodes = tree.nodes\n            .map((n) => n instanceof CppToken ? n : this.Copy(n));\n        return newTree;\n    }\n\n    /**\n     * Create string from the CppParseTree which is a representation of the original code.\n     * @param tree The CppParseTree to compact. Defaults to the current tree.\n     */\n    public Yield(tree: CppParseTree = this): string {\n        let code: string = \"\";\n\n        for (const node of tree.nodes) {\n            if (node instanceof CppParseTree) {\n                code += \"(\" + this.Yield(node) + \")\";\n                continue;\n            }\n\n            switch (node.type) {\n                case CppTokenType.Symbol:\n                    code += code === \"\" ? node.value : \" \" + node.value;\n                    break;\n                case CppTokenType.Pointer:\n                    code += node.value;\n                    break;\n                case CppTokenType.Reference:\n                    code += node.value;\n                    break;\n                case CppTokenType.ArraySubscript:\n                    code += node.value;\n                    break;\n                case CppTokenType.CurlyBlock:\n                    code += node.value;\n                    break;\n                case CppTokenType.Assignment:\n                    code += \" \" + node.value;\n                    break;\n                case CppTokenType.Comma:\n                    code += node.value;\n                    break;\n                case CppTokenType.Arrow:\n                    code += \" \" + node.value;\n                    break;\n                case CppTokenType.Ellipsis:\n                    code += node.value;\n                    break;\n                case CppTokenType.Attribute:\n                    code += code === \"\" ? node.value : \" \" + node.value;\n                    break;\n            }\n        }\n\n        return code;\n    }\n}\n"
  },
  {
    "path": "src/Lang/Cpp/CppParser.ts",
    "content": "import { Position, TextDocumentContentChangeEvent, TextEditor, TextLine, workspace } from \"vscode\";\nimport ICodeParser from \"../../Common/ICodeParser\";\nimport { IDocGen } from \"../../Common/IDocGen\";\nimport { Config } from \"../../Config\";\nimport { CppArgument } from \"./CppArgument\";\nimport { CasingType, CommentType, CppDocGen, SpecialCase } from \"./CppDocGen\";\nimport { CppParseTree } from \"./CppParseTree\";\nimport { CppToken, CppTokenType } from \"./CppToken\";\n\n/**\n *\n * Parses C code for methods and signatures\n *\n * @export\n * @class CParser\n * @implements {ICodeParser}\n */\nexport default class CppParser implements ICodeParser {\n    /**\n     * Get the casing of a specified text\n     *\n     * @private\n     * @param {string} name Text to check\n     * @param {number} validateFrom Check if only a substr is the same casing as the whole string.\n     *                              Set to 0 to disable check.\n     * @returns {CasingType} Detected type of casing\n     *\n     * @memberOf CppParser\n     */\n    public static checkCasing(name: string, validateFrom: number): CasingType {\n        let containsUnderscores = name.indexOf(\"_\") !== -1;\n        if (containsUnderscores) {\n            containsUnderscores = name.indexOf(\"_\") !== name.length - 1; // last character _ may be Google style\n        }\n        // first letter upper case\n        let methodCasing: CasingType;\n        let match = name.match(\"^([_|\\\\d|]*[A-Z]).+\");\n        if (match !== null) {\n            match = name.match(\"^([A-Z|_|\\\\d]{2,})\");\n            if (match !== null) {\n                methodCasing = containsUnderscores ? CasingType.SCREAMING_SNAKE : CasingType.UPPER;\n            } else {\n                methodCasing = containsUnderscores ? CasingType.uncertain : CasingType.Pascal;\n            }\n        } else {\n            methodCasing = containsUnderscores ? CasingType.snake : CasingType.camel;\n        }\n\n        if (validateFrom > 0 && methodCasing !== CasingType.uncertain) {\n            // validate after\n            switch (methodCasing) {\n                case CasingType.SCREAMING_SNAKE: {\n                    // Take the leading _ after removing the characters into consideration\n                    const testCasing = this.checkCasing(name.substr(validateFrom + 1), 0);\n                    // screaming or upper\n                    if (testCasing !== CasingType.SCREAMING_SNAKE && testCasing !== CasingType.UPPER) {\n                        methodCasing = CasingType.uncertain;\n                    }\n                    break;\n                }\n                case CasingType.snake: {\n                    // Take the leading _ after removing the characters into consideration\n                    const textCheck = name.substr(validateFrom + 1);\n                    const testCasing = this.checkCasing(textCheck, 0);\n                    // snake\n                    if (testCasing !== CasingType.snake) {\n                        if (textCheck.match(\"([a-z\\\\d]+)\") === null) {\n                            methodCasing = CasingType.uncertain;\n                        }\n                    }\n                    break;\n                }\n                case CasingType.Pascal:\n                case CasingType.camel: {\n                    const testCasing = this.checkCasing(name.substr(validateFrom), 0);\n                    // pascal\n                    if (testCasing !== CasingType.Pascal) {\n                        methodCasing = CasingType.uncertain;\n                    }\n                    break;\n                }\n                case CasingType.UPPER: {\n                    const testCasing = this.checkCasing(name.substr(validateFrom), 0);\n                    // upper\n                    if (name.substr(validateFrom).match(\"([A-Z\\\\d]+)\") === null) {\n                        methodCasing = CasingType.uncertain;\n                    }\n                    break;\n                }\n                default: {\n                    break; // No op\n                }\n            }\n        }\n\n        return methodCasing;\n    }\n\n    protected activeEditor: TextEditor;\n    protected activeSelection: Position;\n    protected readonly cfg: Config;\n\n    private typeKeywords: string[];\n    private stripKeywords: string[];\n    private keywords: string[];\n    private attributes: string[];\n    private lexerVocabulary;\n\n    private specialCase: SpecialCase;\n    private commentType: CommentType;\n\n    private casingType: CasingType;\n\n    private vscodeAutoGeneratedComment: boolean;\n\n    constructor(cfg: Config) {\n        this.cfg = cfg;\n\n        this.typeKeywords = [\n            \"constexpr\",\n            \"const\",\n            \"struct\",\n            \"enum\",\n            \"restrict\",\n        ];\n\n        this.stripKeywords = [\n            \"final\",\n            \"static\",\n            \"inline\",\n            \"friend\",\n            \"virtual\",\n            \"extern\",\n            \"explicit\",\n            \"class\",\n            \"override\",\n            \"typename\",\n        ];\n\n        this.attributes = [\n            \"noexcept\",\n            \"throw\",\n            \"alignas\",\n        ];\n\n        // Non type keywords will be stripped from the final return type.\n        this.keywords = this.typeKeywords.concat(this.stripKeywords);\n        // Remove keywords that should be filtered\n        this.keywords = this.keywords.concat(this.cfg.Generic.filteredKeywords);\n\n        this.lexerVocabulary = {\n            ArraySubscript: (x: string): string => (x.match(\"^\\\\[[^\\\\[]*?\\\\]\") || [])[0],\n            Arrow: (x: string): string => (x.match(\"^->\") || [])[0],\n            Assignment: (x: string): string => {\n                if (!x.match(\"^=\")) {\n                    return undefined;\n                }\n\n                const nesters: Map<string, string> = new Map<string, string>([\n                    [\"<\", \">\"], [\"(\", \")\"], [\"{\", \"}\"], [\"[\", \"]\"],\n                ]);\n\n                for (let i = 0; i < x.length; i++) {\n                    const v = nesters.get(x[i]);\n                    if (v !== undefined) {\n                        const startEndOffset: number[] = this.GetSubExprStartEnd(x, i, x[i], v);\n                        if (startEndOffset[1] === 0) {\n                            return undefined;\n                        }\n                        i = startEndOffset[1] - 1;\n                    } else if (x[i] === \"\\\"\" || x[i] === \"'\") {\n                        // Check if raw literal. Since those may have unescaped characters\n                        // but require ()\n                        if (x[i - 1] !== \"R\") {\n                            // Skip to next end of the string or char literal.\n                            let found: boolean = false;\n                            for (let j = i + 1; j < x.length; j++) {\n                                if (x[j] === x[i] && x[j - 1] !== \"\\\\\") {\n                                    found = true;\n                                    i = j;\n                                    break;\n                                }\n                            }\n                            if (!found) {\n                                return undefined;\n                            }\n                        } else {\n                            const startEndOffset: number[] = this.GetSubExprStartEnd(x, i, \"(\", \")\");\n                            if (startEndOffset[1] === 0) {\n                                return undefined;\n                            }\n                            i = startEndOffset[1];\n                        }\n                    } else if (x[i] === \",\" || x[i] === \")\") {\n                        return x.slice(0, i);\n                    }\n                }\n\n                return x;\n            },\n            Attribute: (x: string): string => {\n                const attribute: string = (x.match(\"^\\\\[\\\\[[^\\\\[]*?\\\\]\\\\]\") || [])[0];\n                if (attribute !== undefined) {\n                    return attribute;\n                }\n\n                const foundIndex: number = this.attributes\n                    .findIndex((n: string) => x.startsWith(n) === true);\n\n                if (foundIndex === -1) {\n                    return undefined;\n                }\n\n                if (x.slice(this.attributes[foundIndex].length).trim().startsWith(\"(\") === false) {\n                    return x.slice(0, this.attributes[foundIndex].length);\n                }\n\n                const startEndOffset: number[] = this.GetSubExprStartEnd(x, 0, \"(\", \")\");\n                return startEndOffset[1] === 0 ? undefined : x.slice(0, startEndOffset[1]);\n            },\n            CloseParenthesis: (x: string): string => (x.match(\"^\\\\)\") || [])[0],\n            Comma: (x: string): string => (x.match(\"^,\") || [])[0],\n            CommentBlock: (x: string): string => {\n                if (x.startsWith(\"/*\") === false) {\n                    return undefined;\n                }\n\n                let closeOffset: number = x.indexOf(\"*/\");\n                closeOffset = closeOffset === -1 ? x.length : closeOffset + 2;\n                return x.slice(0, closeOffset);\n            },\n            CommentLine: (x: string): string => {\n                if (x.startsWith(\"//\") === false) {\n                    return undefined;\n                }\n\n                let closeOffset: number = x.indexOf(\"\\n\");\n                closeOffset = closeOffset === -1 ? x.length : closeOffset + 1;\n                return x.slice(0, closeOffset);\n            },\n            CurlyBlock: (x: string): string => {\n                if (x.startsWith(\"{\") === false) {\n                    return undefined;\n                }\n                const startEndOffset: number[] = this.GetSubExprStartEnd(x, 0, \"{\", \"}\");\n                return startEndOffset[1] === 0 ? undefined : x.slice(0, startEndOffset[1]);\n            },\n            Ellipsis: (x: string): string => (x.match(\"^\\\\.\\\\.\\\\.\") || [])[0],\n            OpenParenthesis: (x: string): string => (x.match(\"^\\\\(\") || [])[0],\n            Pointer: (x: string): string => (x.match(\"^\\\\*\") || [])[0],\n            Reference: (x: string): string => (x.match(\"^&\") || [])[0],\n            Symbol: (x: string): string => {\n                // Handle specifiers\n                const specifierFound: number = this.attributes\n                    .findIndex((n: string) => x.startsWith(n) === true);\n\n                if (specifierFound !== -1) {\n                    return undefined;\n                }\n\n                // Handle decltype special cases.\n                if (x.startsWith(\"decltype\") === true) {\n                    const startEndOffset: number[] = this.GetSubExprStartEnd(x, 0, \"(\", \")\");\n                    return startEndOffset[1] === 0 ? undefined : x.slice(0, startEndOffset[1]);\n                }\n\n                // Special case group up the fundamental types with the modifiers.\n                // tslint:disable-next-line:max-line-length\n                let reMatch: string = (x.match(\"^(unsigned|signed|short|long|int|char|double|float)(\\\\s*(unsigned|signed|short|long|int|char|double|float)\\\\s)+(?!a-z|A-Z|:|_|\\\\d)\") || [])[0];\n                if (reMatch !== undefined) {\n                    return reMatch.trim();\n                }\n\n                // Regex to handle a part of all symbols and includes all symbol special cases.\n                // This is run in a loop because template parts of a symbol can't be parsed using regex.\n                // Also check if it doesn't start with a number since those are always literals\n                // tslint:disable-next-line:max-line-length\n                const symbolRegex: string = \"^([a-z|A-Z|:|_|~|\\\\d]*operator\\\\s*(\\\"\\\"_[a-z|A-Z|_|\\\\d]+|>>=|<<=|->\\\\*|\\\\+=|-=|\\\\*=|\\\\/=|%=|\\\\^=|&=|\\\\|=|<<|>>|==|!=|<=|->|>=|&&|\\\\|\\\\||\\\\+\\\\+|--|\\\\+|-|\\\\*|\\\\/|%|\\\\^|&|\\||~|!|=|<|>|,|\\\\[\\\\s*\\\\]|\\\\(\\\\s*\\\\)|(new|delete)\\\\s*(\\\\[\\\\s*\\\\]){0,1}){0,1}|[a-z|A-Z|:|_|~|\\\\d]+)\";\n\n                reMatch = (x.match(symbolRegex) || [])[0];\n                if (reMatch === undefined || x.match(/^\\d/)) {\n                    return undefined;\n                }\n\n                let symbol: string = reMatch;\n                while (true) {\n                    if (x.slice(symbol.length).trim().startsWith(\"<\") === true) {\n                        const offsets: number[] = this.GetSubExprStartEnd(x, symbol.length, \"<\", \">\");\n                        if (offsets[1] === 0) {\n                            return undefined;\n                        }\n                        symbol = x.slice(0, offsets[1]);\n                    }\n\n                    reMatch = (x.slice(symbol.length).match(symbolRegex) || [])[0];\n                    if (reMatch === undefined) {\n                        break;\n                    }\n\n                    symbol += reMatch;\n                }\n\n                return symbol.replace(/\\s+$/, \"\");\n            },\n        };\n\n        this.specialCase = SpecialCase.none;\n        this.commentType = CommentType.method;\n        this.vscodeAutoGeneratedComment = false;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public Parse(activeEdit: TextEditor): IDocGen {\n        this.activeEditor = activeEdit;\n        this.activeSelection = this.activeEditor.selection.active;\n\n        let line: string = \"\";\n        try {\n            line = this.getLogicalLine();\n        } catch (err) {\n            // console.dir(err);\n        }\n        const templateArgs: string[] = [];\n        let args: [CppArgument, CppArgument[]] = [new CppArgument(), []];\n\n        if (activeEdit.selection.active.line === 0 && line.length === 0) { // head of file\n            this.commentType = CommentType.file;\n        } else { // method\n            // template parsing is simpler by using heuristics rather then CppTokenizing first.\n            while (line.startsWith(\"template\")) {\n                const template: string = this.GetTemplate(line);\n\n                templateArgs.push.apply(templateArgs, this.GetArgsFromTemplate(template));\n\n                line = line.slice(template.length, line.length + 1).trim();\n            }\n\n            try {\n                args = this.GetReturnAndArgs(line);\n            } catch (err) {\n                // console.dir(err);\n            }\n        }\n\n        if (args[0].name !== null) {\n            const methodName = args[0].name;\n\n            if (methodName.toLowerCase().startsWith(\"get\")) {\n                this.casingType = CppParser.checkCasing(methodName, 3);\n                if (this.casingType !== CasingType.uncertain) {\n                    this.specialCase = SpecialCase.getter;\n                }\n            } else if (methodName.toLowerCase().startsWith(\"set\")) {\n                this.casingType = CppParser.checkCasing(methodName, 3);\n                if (this.casingType !== CasingType.uncertain) {\n                    this.specialCase = SpecialCase.setter;\n                }\n            } else if (methodName.toLowerCase().startsWith(\"create\")) {\n                this.casingType = CppParser.checkCasing(methodName, 6);\n                if (this.casingType !== CasingType.uncertain) {\n                    this.specialCase = SpecialCase.factoryMethod;\n                }\n            }\n        }\n\n        return new CppDocGen(\n            this.activeEditor,\n            this.activeSelection,\n            this.cfg,\n            templateArgs,\n            args[0],\n            args[1],\n            this.specialCase,\n            this.commentType,\n            this.casingType,\n            this.vscodeAutoGeneratedComment,\n        );\n    }\n\n    /***************************************************************************\n                                    Implementation\n     ***************************************************************************/\n    private getLogicalLine(): string {\n        let logicalLine: string = \"\";\n\n        let nextLine: Position = new Position(this.activeSelection.line + 1, this.activeSelection.character);\n\n        let nextLineTxt: string = this.activeEditor.document.lineAt(nextLine.line).text.trim();\n\n        // VSCode may enter a * on itself, we don't want that in our method\n        if (nextLineTxt === \"*\") {\n            nextLineTxt = \"\";\n        }\n\n        let currentNest: number = 0;\n        logicalLine = nextLineTxt;\n\n        // Get method end line\n        let linesToGet: number = this.cfg.Generic.linesToGet;\n        while (linesToGet-- > 0) { // Check for end of expression.\n            nextLine = new Position(nextLine.line + 1, nextLine.character);\n            nextLineTxt = this.activeEditor.document.lineAt(nextLine.line).text.trim();\n            let finalSlice = -1;\n\n            // Check if method has finished if curly brace is opened while\n            // nesting is occuring.\n            for (let i: number = 0; i < nextLineTxt.length; i++) {\n                if (nextLineTxt[i] === \"(\") {\n                    currentNest++;\n                } else if (nextLineTxt[i] === \")\") {\n                    currentNest--;\n                } else if (nextLineTxt[i] === \"{\" && currentNest === 0) {\n                    finalSlice = i;\n                    break;\n                } else if ((nextLineTxt[i] === \";\"\n                    || (nextLineTxt[i] === \":\" && nextLineTxt[i - 1] !== \":\" && nextLineTxt[i + 1] !== \":\"))\n                    && currentNest === 0) {\n                    finalSlice = i;\n                    break;\n                }\n            }\n\n            // Head of file probably\n            if (nextLineTxt.startsWith(\"#include\")) {\n                this.commentType = CommentType.file;\n                return \"\";\n            } else if (nextLineTxt.startsWith(\"#\") && ! nextLineTxt.startsWith(\"#define\")) {\n                return \"\";\n            } else if (nextLine.line === 2) { // Check if there where two empty lines trailing the file\n                if (this.activeEditor.document.lineAt(0).text === this.cfg.C.firstLine\n                    && (\n                        this.activeEditor.document.lineAt(1).text === this.cfg.C.commentPrefix\n                        || this.activeEditor.document.lineAt(1).text.trim() === \"\"\n                     ) && this.activeEditor.document.lineAt(2).text.trim() === \"\") {\n                        this.commentType = CommentType.file;\n                        return \"\";\n                }\n            }\n\n            if (this.isVsCodeAutoComplete(nextLineTxt) === true) {\n                // Can only be true if it's in the next line\n                this.vscodeAutoGeneratedComment = linesToGet === (this.cfg.Generic.linesToGet - 1);\n            } else {\n                logicalLine += \"\\n\";\n                if (finalSlice >= 0) {\n                    logicalLine += nextLineTxt.slice(0, finalSlice);\n                } else {\n                    logicalLine += nextLineTxt;\n                }\n                logicalLine = logicalLine.replace(/\\*\\//g, \"\");\n            }\n\n            if (finalSlice >= 0) {\n                return logicalLine.replace(/^\\s+|\\s+$/g, \"\");\n            }\n        }\n\n        throw new Error(\"More than \" + linesToGet + \" lines were read from editor and no end of expression was found.\");\n    }\n\n    private Tokenize(expression: string): CppToken[] {\n        const CppTokens: CppToken[] = [];\n        expression = expression.replace(/^\\s+|\\s+$/g, \"\");\n\n        while (expression.length !== 0) {\n            const matches: CppToken[] = Object.keys(this.lexerVocabulary)\n                .map((k): CppToken => new CppToken(CppTokenType[k], this.lexerVocabulary[k](expression)))\n                .filter((t) => t.value !== undefined);\n\n            if (matches.length === 0) {\n                throw new Error(\"Next CppToken couldn\\'t be determined: \" + expression);\n            } else if (matches.length > 1) {\n                throw new Error(\"Multiple matches for next CppToken: \" + expression);\n            }\n\n            CppTokens.push(matches[0]);\n            expression = expression.slice(matches[0].value.length, expression.length).replace(/^\\s+|\\s+$/g, \"\");\n        }\n\n        return CppTokens;\n    }\n\n    private GetReturnAndArgs(line: string): [CppArgument, CppArgument[]] {\n        if (this.GetArgumentFromCastOperator(line) !== null) {\n            const opFunc = new CppArgument();\n            opFunc.name = this.GetArgumentFromCastOperator(line)[1].trim();\n            opFunc.type.nodes.push(new CppToken(CppTokenType.Symbol, opFunc.name));\n            return [opFunc, []];\n        }\n        // CppTokenize rest of expression and remove comment CppTokens;\n        const CppTokens: CppToken[] = this.Tokenize(line)\n            .filter((t) => t.type !== CppTokenType.CommentBlock)\n            .filter((t) => t.type !== CppTokenType.CommentLine);\n\n        // Create hierarchical tree based on the parenthesis.\n        const tree: CppParseTree = CppParseTree.CreateTree(CppTokens).Compact();\n\n        // return argument.\n        const func = this.GetArgument(tree);\n        // check if it is a constructor or descructor since these have no name.\n        // Also reverse the assignment of type and name.\n        if (func.name === null) {\n            if (func.type.nodes.length !== 1) {\n                throw new Error(\"Too many symbols found for constructor/descructor.\");\n            } else if (func.type.nodes[0] instanceof CppParseTree) {\n                throw new Error(\"One node found with just a CppParseTree. Malformed input.\");\n            }\n\n            if (line.includes(\"~\")) {\n                this.specialCase = SpecialCase.destructor;\n            } else {\n                this.specialCase = SpecialCase.constructor;\n            }\n\n            func.name = (func.type.nodes[0] as CppToken).value;\n            func.type.nodes = [];\n        }\n\n        // Get arguments list as a CppParseTree and create arguments from them.\n        const params = this.GetArgumentList(tree)\n            .map((a) => this.GetArgument(a));\n\n        return [func, params];\n    }\n\n    private RemoveUnusedTokens(tree: CppParseTree): CppParseTree {\n        tree = tree.Copy();\n\n        // First slice of everything after assignment since that will not be used.\n        const assignmentIndex = tree.nodes\n            .findIndex((n) => n instanceof CppToken && n.type === CppTokenType.Assignment);\n        if (assignmentIndex !== -1) {\n            tree.nodes = tree.nodes.slice(0, assignmentIndex);\n        }\n\n        // Specifiers aren't needed so remove them.\n        tree.nodes = tree.nodes\n            .filter((n) => n instanceof CppParseTree || (n instanceof CppToken && n.type !== CppTokenType.Attribute));\n\n        return tree;\n    }\n\n    private GetArgumentList(tree: CppParseTree): CppParseTree[] {\n        const args: CppParseTree[] = [];\n\n        tree = this.RemoveUnusedTokens(tree);\n\n        let cursor: CppParseTree = tree;\n        while (this.IsFuncPtr(cursor.nodes) === true) {\n            cursor = cursor.nodes.find((n) => n instanceof CppParseTree) as CppParseTree;\n        }\n\n        const argTree: CppParseTree = cursor.nodes.find((n) => n instanceof CppParseTree) as CppParseTree;\n        if (argTree === undefined) {\n            throw new Error(\"Function arguments not found.\");\n        }\n\n        // Split the argument tree on commas\n        let arg: CppParseTree = new CppParseTree();\n        for (const node of argTree.nodes) {\n            if (node instanceof CppToken && node.type === CppTokenType.Comma) {\n                args.push(arg);\n                arg = new CppParseTree();\n            } else {\n                arg.nodes.push(node);\n            }\n        }\n\n        if (arg.nodes.length > 0) {\n            args.push(arg);\n        }\n\n        return args;\n    }\n\n    private IsFuncPtr(nodes: Array<CppToken | CppParseTree>) {\n        return nodes.filter((n) => n instanceof CppParseTree).length === 2;\n    }\n\n    private IsArrayPtr(nodes: Array<CppToken | CppParseTree>) {\n        if (nodes.filter((n) => n instanceof CppParseTree).length === 1) {\n            const treeIdx = nodes.findIndex((n) => n instanceof CppParseTree);\n            if (treeIdx !== -1) {\n                const nextElem = nodes[treeIdx + 1];\n                if (nextElem instanceof CppToken) {\n                    const match = nextElem.value.match(/^\\[[0-9]*\\]$/g);\n                    if (match !== undefined && match !== null) {\n                        return match.length > 0;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    private StripNonTypeNodes(tree: CppParseTree) {\n        tree.nodes = tree.nodes\n            // All strippable keywords.\n            .filter((n) => {\n                return !(n instanceof CppToken\n                    && n.type === CppTokenType.Symbol\n                    && this.stripKeywords.find((k) => k === n.value) !== undefined);\n            });\n    }\n\n    private GetArgumentFromCastOperator(line: string) {\n        const copy = line;\n        return copy.match(\"[explicit|\\\\s]*\\\\s*operator\\\\s*([a-zA-Z].*)\\\\(\\\\).*\");\n    }\n\n    private GetArgumentFromTrailingReturn(tree: CppParseTree, startTrailingReturn: number): CppArgument {\n        const argument: CppArgument = new CppArgument();\n\n        // Find index of auto prior to the first CppParseTree.\n        // If auto is not found something is going wrong since trailing return\n        // requires auto.\n        let autoIndex: number = -1;\n        for (let i: number = 0; i < tree.nodes.length; i++) {\n            const node = tree.nodes[i];\n            if (node instanceof CppParseTree) {\n                break;\n            }\n            if (node.type === CppTokenType.Symbol && node.value === \"auto\") {\n                autoIndex = i;\n                break;\n            }\n        }\n\n        if (autoIndex === -1) {\n            throw new Error(\"Function declaration has trailing return but type is not auto.\");\n        }\n\n        // Get symbol between auto and CppParseTree which is the argument name. It also may not be a keyword.\n        for (let i: number = autoIndex + 1; i < tree.nodes.length; i++) {\n            const node = tree.nodes[i];\n            if (node instanceof CppParseTree) {\n                break;\n            }\n            if (node.type === CppTokenType.Symbol && this.keywords.find((k) => k === node.value) === undefined) {\n                argument.name = node.value;\n                break;\n            }\n        }\n\n        argument.type.nodes = tree.nodes.slice(startTrailingReturn + 1, tree.nodes.length);\n        this.StripNonTypeNodes(argument.type);\n\n        return argument;\n    }\n\n    private GetArgumentFromFuncPtr(tree: CppParseTree): CppArgument {\n        const argument: CppArgument = new CppArgument();\n\n        argument.type = tree;\n\n        let cursor: CppParseTree = tree;\n\n        while (this.IsFuncPtr(cursor.nodes) === true || this.IsArrayPtr(cursor.nodes) === true) {\n            cursor = cursor.nodes.find((n) => n instanceof CppParseTree) as CppParseTree;\n        }\n\n        // Remove CppParseTree. This can be if it is a function declaration.\n        const argumentsIndex = cursor.nodes.findIndex((n) => n instanceof CppParseTree);\n        if (argumentsIndex !== -1) {\n            cursor.nodes.splice(argumentsIndex, 1);\n        }\n\n        // Find first symbol that is the argument name.\n        // Remove it from the tree and set the name to the argument name\n        for (let i: number = 0; i < cursor.nodes.length; i++) {\n            const node = cursor.nodes[i];\n            if (node instanceof CppParseTree) {\n                continue;\n            }\n\n            if (node.type === CppTokenType.Symbol && this.keywords.find((k) => k === node.value) === undefined) {\n                argument.name = node.value;\n                cursor.nodes.splice(i, 1);\n            }\n        }\n\n        this.StripNonTypeNodes(argument.type);\n        return argument;\n    }\n\n    private GetDefaultArgument(tree: CppParseTree): CppArgument {\n        const argument: CppArgument = new CppArgument();\n\n        for (const node of tree.nodes) {\n            if (node instanceof CppParseTree) {\n                break;\n            }\n            const symbolCount = argument.type.nodes\n                .filter((n) => n instanceof CppToken)\n                .map((n) => n as CppToken)\n                .filter((n) => n.type === CppTokenType.Symbol)\n                .filter((n) => this.keywords.find((k) => k === n.value) === undefined)\n                .length;\n\n            if (node.type === CppTokenType.Symbol\n                && this.keywords.find((k) => k === node.value) === undefined\n            ) {\n                if (symbolCount === 1) {\n                    argument.name = node.value;\n                    continue;\n                } else if (symbolCount > 1) {\n                    throw new Error(\"Too many non keyword symbols.\");\n                }\n            }\n\n            argument.type.nodes.push(node);\n        }\n\n        this.StripNonTypeNodes(argument.type);\n        return argument;\n    }\n\n    private GetArgument(tree: CppParseTree): CppArgument {\n        // Copy tree structure leave original untouched.\n        const copy = this.RemoveUnusedTokens(tree);\n\n        // Special case with only ellipsis. C style variadic arguments\n        if (copy.nodes.length === 1) {\n            const node = copy.nodes[0];\n            if (node instanceof CppToken && node.type === CppTokenType.Ellipsis) {\n                const argument: CppArgument = new CppArgument();\n                argument.name = node.value;\n                return argument;\n            }\n        }\n\n        // Check if it is has a trailing return.\n        const startTrailingReturn: number = copy.nodes\n            .findIndex((t) => t instanceof CppToken ? t.type === CppTokenType.Arrow : false);\n\n        // Special case trailing return.\n        if (startTrailingReturn !== -1) {\n            return this.GetArgumentFromTrailingReturn(copy, startTrailingReturn);\n        }\n\n        // Handle function pointers\n        if (this.IsFuncPtr(copy.nodes) === true) {\n            return this.GetArgumentFromFuncPtr(copy);\n        }\n\n        if (this.IsArrayPtr(copy.nodes) === true) {\n            return this.GetArgumentFromFuncPtr(copy);\n        }\n\n        // Handle member pointers\n        for (let token: number = 0; token < copy.nodes.length - 1; token++) {\n            const firstToken: CppToken = copy.nodes[token] as CppToken;\n            const secondToken: CppToken = copy.nodes[token + 1] as CppToken;\n\n            if (firstToken.type === CppTokenType.Symbol && secondToken.type === CppTokenType.Pointer &&\n                firstToken.value.endsWith(\"::\")) {\n                    firstToken.type = CppTokenType.MemberPointer;\n            }\n        }\n\n        return this.GetDefaultArgument(copy);\n    }\n\n    private GetSubExprStartEnd(expression: string, startSearch: number, openExpr: string, closeExpr: string): number[] {\n        let openExprOffset: number = -1;\n        let nestedCount: number = 0;\n        for (let i: number = startSearch; i < expression.length; i++) {\n            if (expression[i] === openExpr && openExprOffset === -1) {\n                openExprOffset = i;\n            }\n\n            if (expression[i] === openExpr) {\n                nestedCount++;\n            } else if (expression[i] === closeExpr && nestedCount > 0) {\n                nestedCount--;\n            }\n\n            if (expression[i] === closeExpr && nestedCount === 0 && openExprOffset !== -1) {\n                return [openExprOffset, i + 1];\n            }\n        }\n\n        return [0, 0];\n    }\n\n    private GetTemplate(expression: string): string {\n        if (expression.startsWith(\"template\") === false) {\n            return \"\";\n        }\n\n        let startTemplateOffset: number = -1;\n        for (let i: number = \"template\".length; i < expression.length; i++) {\n            if (expression[i] === \"<\") {\n                startTemplateOffset = i;\n                break;\n            } else if (expression[i] !== \" \") {\n                return \"\";\n            }\n        }\n\n        if (startTemplateOffset === -1) {\n            return \"\";\n        }\n\n        const [start, end] = this.GetSubExprStartEnd(expression, startTemplateOffset, \"<\", \">\");\n        return expression.slice(0, end);\n    }\n\n    private GetArgsFromTemplate(template: string): string[] {\n        const args: string[] = [];\n        if (template === \"\") {\n            return args;\n        }\n\n        // Remove <> and add a comma to the end to remove edge case.\n        template = template.slice(template.indexOf(\"<\") + 1, template.lastIndexOf(\">\")).replace(/^\\s+|\\s+$/g, \"\") + \",\";\n\n        // Remove = and everything to the right until a , comes up\n        template = template.replace(/(\\W*=\\W*\\S*\\,)/gm, \",\");\n\n        const nestedCounts: { [key: string]: number; } = {\n            \"(\": 0,\n            \"<\": 0,\n            \"{\": 0,\n        };\n\n        let lastSeparator: number = 0;\n        for (let i: number = 0; i < template.length; i++) {\n            const notInSubExpr: boolean = nestedCounts[\"<\"] === 0\n                && nestedCounts[\"(\"] === 0\n                && nestedCounts[\"{\"] === 0;\n\n            if (notInSubExpr === true && template[i] === \",\") {\n                args.push(template.slice(lastSeparator + 1, i).replace(/^\\s+|\\s+$/g, \"\"));\n            } else if (notInSubExpr === true && (template[i] === \" \" || template[i] === \".\")) {\n                lastSeparator = i;\n            }\n\n            if (template[i] === \"(\") {\n                nestedCounts[\"(\"]++;\n            } else if (template[i] === \")\" && nestedCounts[\"(\"] > 0) {\n                nestedCounts[\"(\"]--;\n            } else if (template[i] === \"<\") {\n                nestedCounts[\"<\"]++;\n            } else if (template[i] === \">\" && nestedCounts[\"<\"] > 0) {\n                nestedCounts[\"<\"]--;\n            } else if (template[i] === \"{\") {\n                nestedCounts[\"{\"]++;\n            } else if (template[i] === \"}\" && nestedCounts[\"{\"] > 0) {\n                nestedCounts[\"{\"]--;\n            }\n        }\n\n        return args;\n    }\n\n    private isVsCodeAutoComplete(line: string): boolean {\n        switch (line) {\n            case \"*/\":\n                this.vscodeAutoGeneratedComment = true;\n                return true;\n            default:\n                return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Lang/Cpp/CppToken.ts",
    "content": "export enum CppTokenType {\n    Symbol,\n    Pointer,\n    Reference,\n    ArraySubscript,\n    OpenParenthesis,\n    CloseParenthesis,\n    CurlyBlock,\n    Assignment,\n    Comma,\n    Arrow,\n    CommentBlock,\n    CommentLine,\n    Ellipsis,\n    Attribute,\n    MemberPointer,\n}\n\nexport class CppToken {\n    public type: CppTokenType;\n    public value: string;\n\n    constructor(type: CppTokenType, value: string) {\n        this.type = type;\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "src/extension.ts",
    "content": "\"use strict\";\n// The module 'vscode' contains the VS Code extensibility API\n// Import the module and reference it with the alias vscode in your code below\nimport * as vscode from \"vscode\";\nimport CodeParserController from \"./CodeParserController\";\nimport DoxygenCompletionItemProvider from \"./DoxygenCompletionItemProvider\";\n\nenum Version {\n    CURRENT = \"1.4.0\",\n    PREVIOUS = \"1.3.2\",\n    KEY = \"doxdocgen_version\",\n}\n\n// this method is called when your extension is activated\n// your extension is activated the very first time the command is executed\nexport function activate(context: vscode.ExtensionContext) {\n    const parser = new CodeParserController();\n\n    context.subscriptions.push(parser);\n\n    const version = context.globalState.get<string>(Version.KEY);\n    if (version === undefined) {\n        context.globalState.update(Version.KEY, Version.CURRENT);\n    } else if (version !== Version.CURRENT) {\n        context.globalState.update(Version.KEY, Version.CURRENT);\n    }\n\n    /*register doxygen commands intellisense */\n    if (vscode.workspace.getConfiguration(\"doxdocgen.generic\").get<boolean>(\"commandSuggestion\")) {\n        // tslint:disable-next-line: max-line-length\n        vscode.languages.registerCompletionItemProvider({ language: \"cpp\", scheme: \"file\" }, new DoxygenCompletionItemProvider(), \"@\", \"\\\\\");\n    }\n\n    // After the CompletionItemProvider is registered, it cannot be unregistered\n    // Check the settings everytime when it is triggered would be inefficient\n    // So just prompt the user to restart to take effect\n    vscode.workspace.onDidChangeConfiguration((event) => {\n        if (event.affectsConfiguration(\"doxdocgen.generic.commandSuggestion\")) {\n            vscode.window.showWarningMessage(\"Please restart vscode to apply the changes!\");\n        }\n    });\n}\n"
  },
  {
    "path": "src/templatedString.ts",
    "content": "import { getEnvVars } from \"./util\";\n\n/**\n * Represent a templated variable in string\n */\nexport interface ITemplate {\n    toReplace: string;  // The template to be replaced in string\n    with: string;       // The value to replace with\n}\n\nexport function getIndentedTemplate(replace: string): string {\n    if (replace === \"\") {\n        return \"\";\n    }\n    const snippets = replace.split(/({indent:\\d+})/);\n\n    let indentedString: string = \"\";\n    let indentWidth: number = 0;\n\n    // tslint:disable-next-line:prefer-for-of\n    snippets.forEach((element) => {\n        if (element.match(/{indent:\\d+}/)) {\n            const indents = parseInt(element.match(/{indent:(\\d+)}/)[1], 10);\n            indentWidth = indents;\n            const numSpaces = Math.max(indentWidth - indentedString.length, 0);\n            indentedString += \" \".repeat(numSpaces);\n        } else {\n            // just some text\n            indentedString += element;\n        }\n    });\n\n    return indentedString;\n}\n\n/**\n * Expand variable template in the string\n * @param original the original string\n * @param template variable template to be expanded\n * @returns new string with expanded template\n */\nexport function getTemplatedString(original: string, template: ITemplate): string {\n    const replacedTemplate = original.replace(template.toReplace, template.with);\n    const replacedWithEnv = getEnvVars(replacedTemplate);\n    return getIndentedTemplate(replacedWithEnv);\n}\n\n/**\n * Generate lines of doxygen comments from template\n * @param lines Arrays to store lines of comments\n * @param replace Variable template to be expanded\n * @param template Original string that contains variable templates\n * @param templateWith Arrays of values to replace in the original template string\n */\nexport function generateFromTemplate(\n    lines: string[],\n    replace: string,\n    template: string,\n    templateWith: string[],\n) {\n    templateWith.forEach((element: string) => {\n        // Ignore null values\n        if (element !== null) {\n            lines.push(...getTemplatedString(template, { toReplace: replace, with: element }).split(\"\\n\"));\n        }\n    });\n}\n\n/**\n * Expand multiple variable templates in the string\n * @param original string containing multiple variables to be expanded\n * @param templates variable templates to be expanded\n * @returns new string with expanded templates\n */\nexport function getMultiTemplatedString(\n    original: string,\n    templates: ITemplate[],\n): string {\n    // For each replace entry, attempt to replace it with the corresponding param in the template\n    for (const template of templates) {\n        original = original.replace(template.toReplace, template.with);\n    }\n    return getEnvVars(getIndentedTemplate(original));\n}\n"
  },
  {
    "path": "src/test/CppTests/Attributes.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Attributes Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Attributes on parameter\", () => {\n        const result = testSetup.SetLine(\"int foo([[maybe_unused]] int a, [[maybe_unused]]double& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return int \\n */\");\n    });\n\n    test(\"Attributes on function\", () => {\n        const result = testSetup.SetLine(\"[[nodiscard]] int foo(int a, double& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return int \\n */\");\n    });\n\n    test(\"Multiple attributes on parameter\", () => {\n        const result = testSetup.SetLine(\"int foo([[maybe_unused]] [[carries_dependency]]\"\n            + \" int a, double& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return int \\n */\");\n    });\n\n    test(\"Multiple attributes on function\", () => {\n        const result = testSetup.SetLine(\"[[nodiscard]][[deprecated(\\\"old\\\")]] int foo(int a, double& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return int \\n */\");\n    });\n\n    test(\"Specifier and attribute on class\", () => {\n        const result = testSetup.SetLine(\"class [[nodiscard]] alignas(8) Matrix {\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Specifier and attribute on struct\", () => {\n        const result = testSetup.SetLine(\"struct [[nodiscard]] alignas(8) Matrix {\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Noexcept on function\", () => {\n        let result = testSetup.SetLine(\"constexpr int foo(int a, double& b) noexcept(true);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return constexpr int \\n */\");\n\n        result = testSetup.SetLine(\"constexpr int foo(int a, double& b) noexcept;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return constexpr int \\n */\");\n    });\n\n    test(\"Throw on function\", () => {\n        const result = testSetup.SetLine(\"constexpr int foo(int a, double& b) throw(std::except);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return constexpr int \\n */\");\n    });\n\n    test(\"Newline in function\", () => {\n        const result = testSetup.SetLines([\"static void ResetActionState( BOOL sendNAK )\", \"{\"]).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param sendNAK \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Con-AndDestructor.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Con- and Destructor Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    testSetup.cfg.Generic.generateSmartText = false;\n\n    // Tests\n    test(\"Normal Constructor\", () => {\n        const result = testSetup.SetLine(\"Foo(int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Constructor with initializer list\", () => {\n        const result = testSetup.SetLine(\"Foo(int a) : m_a(a) {\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Explicit Constructor\", () => {\n        const result = testSetup.SetLine(\"explicit Foo(int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Deleted Constructor\", () => {\n        const result = testSetup.SetLine(\"Foo(int a) = delete;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Default Constructor\", () => {\n        const result = testSetup.SetLine(\"Foo() = default;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Destructor\", () => {\n        const result = testSetup.SetLine(\"~Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Virtual Destructor\", () => {\n        const result = testSetup.SetLine(\"virtual ~Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Deleted Destructor\", () => {\n        const result = testSetup.SetLine(\"virtual ~Foo() = 0;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Default Destructor\", () => {\n        const result = testSetup.SetLine(\"~Foo() = default;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Config.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as moment from \"moment\";\nimport * as vscode from \"vscode\";\nimport { Config } from \"../../Config\";\nimport GitConfig from \"../../GitConfig\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Configuration Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Default config\", () => {\n        testSetup.cfg = new Config();\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @param a \\n * \"\n            + \"@return true \\n * @return false \\n */\");\n    });\n\n    test(\"Comment order\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"brief\", \"param\", \"tparam\", \"return\"];\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * @param a \\n * @tparam T \\n * \"\n            + \"@return true \\n * @return false \\n */\");\n    });\n\n    test(\"Non existing order param\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"breif\"];\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n */\");\n    });\n\n    test(\"Modified template\", () => {\n        testSetup.cfg = new Config();\n\n        testSetup.cfg.C.firstLine = \"\";\n        testSetup.cfg.C.lastLine = \"\";\n        testSetup.cfg.C.commentPrefix = \"/// \";\n        testSetup.cfg.Generic.briefTemplate = \"\\\\brief \";\n        testSetup.cfg.Generic.paramTemplate = \"\\\\param {param} \";\n        testSetup.cfg.Cpp.tparamTemplate = \"\\\\tparam {param} \";\n        testSetup.cfg.Generic.returnTemplate = \"\\\\return {type} \";\n\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/// \\\\brief \\n/// \\n/// \\\\tparam T \\n/// \\\\param a \\n\"\n            + \"/// \\\\return true \\n/// \\\\return false \");\n\n    });\n\n    test(\"Disable true false on bool\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.boolReturnsTrueFalse = false;\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @param a \\n\"\n            + \" * @return bool \\n */\");\n    });\n\n    test(\"Disable including return type on function\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.includeTypeAtReturn = false;\n\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @param a \\n\"\n            + \" * @return  \\n */\");\n    });\n\n    test(\"Disable including return type on non-function\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.includeTypeAtReturn = false;\n\n        const result = testSetup.SetLine(\"bool b;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Newlines after params and tparams but not after brief\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"brief\", \"tparam\", \"empty\", \"param\", \"empty\", \"return\"];\n\n        const result = testSetup.SetLine(\"template<typename T> bool foo(T a);\").GetResult();\n        testSetup.cfg.Generic.order = [\"brief\", \"empty\", \"tparam\", \"param\", \"return\"]; // reset to default\n        assert.strictEqual(result, \"/**\\n * @brief \\n * @tparam T \\n * \\n * @param a \\n * \\n\"\n            + \" * @return true \\n * @return false \\n */\");\n    });\n\n    test(\"Function comment indentation test\", () => {\n        testSetup.cfg = new Config();\n        let result = testSetup.SetLine(\"\\ttemplate<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n\\t * @brief \\n\\t * \\n\\t * @tparam T \\n\\t * @param a \\n\\t * \"\n            + \"@return true \\n\\t * @return false \\n\\t */\");\n\n        result = testSetup.SetLine(\"          template<typename T> bool foo(T a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n           * @brief \\n           * \\n           * @tparam T \"\n            + \"\\n           * @param a \\n           * \"\n            + \"@return true \\n           * @return false \\n           */\");\n    });\n\n    test(\"File comment indentation test\", () => {\n        testSetup.cfg.File.fileOrder = [\n            \"file\",\n            \"author\",\n            \"brief\",\n            \"version\",\n            \"date\",\n            \"copyright\",\n        ];\n        testSetup.cfg.File.fileTemplate = \"@file{indent:10}{name}\";\n        testSetup.cfg.Generic.authorTag = \"@author{indent:10}{author}\";\n        testSetup.cfg.Generic.briefTemplate = \"@brief{indent:10}Thing\";\n        testSetup.cfg.File.versionTag = \"@version{indent:10}0.1\";\n        testSetup.cfg.Generic.dateTemplate = \"@date{indent:10}date\";\n        testSetup.cfg.File.copyrightTag = [\"@copyright{indent:10}Copyright(c)\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, `/**\n * @file     MockDocument.h\n * @author   your name\n * @brief    Thing\n * @version  0.1\n * @date     date\n * @copyrightCopyright(c)\n */`);\n    });\n\n    test(\"Lines to get test\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.linesToGet = 2;\n        const positiveResult = testSetup.SetLines([\"template<typename T> bool \\n\", \"foo(T a);\"]).GetResult();\n        assert.strictEqual(positiveResult, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @param a \\n * \"\n            + \"@return true \\n * @return false \\n */\");\n        testSetup.cfg.Generic.linesToGet = 0;\n        testSetup.firstLine = 1;\n        const negativeResult = testSetup.SetLines([\"template<typename T> bool \\n\", \"foo(T a);\"]).GetResult();\n        assert.strictEqual(negativeResult, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"File description order test\", () => {\n        testSetup.cfg = new Config();\n        testSetup.firstLine = 0;\n        testSetup.cfg.File.fileOrder = [\"brief\", \"author\", \"date\", \"file\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * @author your name (you@domain.com)\\n\" +\n            \" * @date \" + moment().format(\"YYYY-MM-DD\") + \"\\n * @file MockDocument.h\\n */\");\n    });\n\n    test(\"Custom smart text Ctor\", () => {\n        testSetup.cfg.Cpp.ctorText = \"Test {name}\";\n        const result = testSetup.SetLine(\"Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test Foo\\n * \\n */\");\n    });\n\n    test(\"Custom smart text Dtor\", () => {\n        testSetup.cfg.Cpp.dtorText = \"Test {name}\";\n        const result = testSetup.SetLine(\"~Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test Foo\\n * \\n */\");\n    });\n\n    test(\"Custom smart text getter\", () => {\n        testSetup.cfg.C.getterText = \"Test {name}\";\n        const result = testSetup.SetLine(\"int getFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test Foo\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Custom smart text setter\", () => {\n        testSetup.cfg.C.setterText = \"Test {name}\";\n        const result = testSetup.SetLine(\"void setFoo(int foo);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test Foo\\n * \\n * @param foo \\n */\");\n    });\n\n    test(\"Custom smart text factory method\", () => {\n        testSetup.cfg.C.factoryMethodText = \"Test {name}\";\n        const result = testSetup.SetLine(\"int createFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test Foo\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Don't split casing for smart text\", () => {\n        testSetup.cfg.C.factoryMethodText = \"Test {name}\";\n        testSetup.cfg.Generic.splitCasingSmartText = false;\n        const result = testSetup.SetLine(\"int createFooObject();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Test FooObject\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Remove inserted '*/' from line\", () => {\n        const result = testSetup.SetLines([\"*/\", \"int foo();\"]).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Single alignment\", () => {\n        testSetup.cfg.Generic.paramTemplate = \"@param{indent:10}{param}\";\n        testSetup.cfg.Cpp.tparamTemplate = \"@tparam{indent:10}{param}\";\n        testSetup.cfg.Generic.returnTemplate = \"@return{indent:10}{type}\";\n        testSetup.cfg.Generic.briefTemplate = \"@brief{indent:10}Brief\";\n\n        const result = testSetup.SetLines([\"template<typename T>\", \"int foo(std::string bar, T foobar);\"]).GetResult();\n        // tslint:disable-next-line:max-line-length\n        assert.strictEqual(result, \"/**\\n * @brief    Brief\\n * \\n * @tparam   T\\n * @param    bar\\n * @param    foobar\\n * @return   int\\n */\");\n    });\n\n    test(\"Multi alignment\", () => {\n        testSetup.cfg.Generic.paramTemplate = \"@param{indent:10}{param}{indent:30}Parameters everywhere\";\n        testSetup.cfg.Cpp.tparamTemplate = \"@tparam{indent:10}{param}{indent:30}I'm a template\";\n        testSetup.cfg.Generic.returnTemplate = \"@return{indent:10}{type}{indent:30}Returns stuff\";\n        testSetup.cfg.Generic.briefTemplate = \"@brief{indent:30}Short desc\";\n\n        const result = testSetup.SetLines([\"template<typename T>\", \"int foo(std::string bar, T foobar);\"]).GetResult();\n        // tslint:disable-next-line:max-line-length\n        assert.equal(result, \"/**\\n * @brief                        Short desc\\n * \\n * @tparam   T                   I'm a template\\n * @param    bar                 Parameters everywhere\\n * @param    foobar              Parameters everywhere\\n * @return   int                 Returns stuff\\n */\");\n    });\n\n    test(\"Negative alignment tests\", () => {\n        testSetup.cfg.Generic.returnTemplate = \"\";\n\n        const result = testSetup.SetLines([\"template<typename T>\", \"int foo(std::string bar, T foobar);\"]).GetResult();\n        // tslint:disable-next-line:max-line-length\n        assert.equal(result, \"/**\\n * @brief                        Short desc\\n * \\n * @tparam   T                   I'm a template\\n * @param    bar                 Parameters everywhere\\n * @param    foobar              Parameters everywhere\\n */\");\n    });\n\n    test(\"Multiline template\", () => {\n        testSetup.cfg.C.commentPrefix = \"/// \";\n        testSetup.cfg.C.firstLine = \"\";\n        testSetup.cfg.C.lastLine = \"\";\n        testSetup.cfg.Generic.briefTemplate = \"<summary>\\n{text}\\n</summary>\";\n        testSetup.cfg.Generic.paramTemplate = \"<param name=\\\"{param}\\\">\\n</param>\";\n        testSetup.cfg.Generic.returnTemplate = \"<returns>\\n</returns>\";\n        const result = testSetup.SetLine(\"    int foo(bool a);\").GetResult();\n        // tslint:disable:no-trailing-whitespace\n        assert.strictEqual(result, \n            result, `/// <summary>\n    /// \n    /// </summary>\n    /// \n    /// <param name=\"a\">\n    /// </param>\n    /// <returns>\n    /// </returns>`,\n        );\n        // tslint:enable:no-trailing-whitespace\n    });\n\n    test(\"Macro define in funtion\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.filteredKeywords = [\"MOCKABLE\"];\n        // tslint:disable-next-line:max-line-length\n        const result = testSetup.SetLine(\"MOCKABLE void processNetworkStatusReset( const common_n::NetworkCommands_s *networkstatus );\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param networkstatus \\n */\");\n    });\n\n    test(\"Custom tag\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"custom\"];\n        testSetup.cfg.Generic.customTags = [\"@note\"];\n        const result = testSetup.SetLine(\"void foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @note\\n */\");\n    });\n\n    test(\"Custom tag expansion in function\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"custom\"];\n        testSetup.cfg.Generic.customTags = [\n            \"@author {author}\",\n            \"@date {date}\",\n            \"@note {email}\",\n            \"@file {file}\",\n        ];\n        const result = testSetup.SetLine(\"void foo();\").GetResult();\n        const date = moment().format(\"YYYY-MM-DD\");\n        assert.strictEqual(result, `/**\\n * @author your name\\n * @date ${date}\\n * @note you@domain.com\\n` +\n        ` * @file MockDocument.h\\n */`);\n    });\n\n    test(\"Env variable\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.order = [\"custom\"];\n        if (process.platform === \"win32\") {\n            testSetup.cfg.Generic.customTags = [\"@author ${env:USERNAME}\"];\n            const res = testSetup.SetLine(\"void foo();\").GetResult();\n            // USERNAME env var is different for everybody\n            assert.notStrictEqual(\"/**\\n * @author USERNAME\\n */\", res);\n        } else {\n            testSetup.cfg.Generic.customTags = [\"@author ${env:USER}\"];\n            const res = testSetup.SetLine(\"void foo();\").GetResult();\n            // USER env var is different for everybody\n            assert.notStrictEqual(\"/**\\n * @author USER\\n */\", res);\n        }\n\n        testSetup.cfg.Generic.customTags = [\"@author ${env:MY_VARIABLE}\"];\n        const result = testSetup.SetLine(\"void foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @author MY_VARIABLE\\n */\");\n    });\n\n    test(\"Use git user.name as author\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.useGitUserName = true;\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author \" +\n            testSetup.gitConfig.UserName +\n            \" (you@domain.com)\\n * @date \" + moment().format(\"YYYY-MM-DD\") + \"\\n */\");\n    });\n\n    test(\"Use git user.email as email\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.useGitUserEmail = true;\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author your name (\" +\n            testSetup.gitConfig.UserEmail +\n            \")\\n * @date \" + moment().format(\"YYYY-MM-DD\") + \"\\n */\");\n    });\n\n    test(\"Substitute author and email by git config\", () => {\n        testSetup.cfg = new Config();\n        testSetup.cfg.Generic.useGitUserName = true;\n        testSetup.cfg.Generic.useGitUserEmail = true;\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author \" +\n            testSetup.gitConfig.UserName + \" (\" + testSetup.gitConfig.UserEmail +\n            \")\\n * @date \" + moment().format(\"YYYY-MM-DD\") + \"\\n */\");\n    });\n\n});\n"
  },
  {
    "path": "src/test/CppTests/FileDescription.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as moment from \"moment\";\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"File Description Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n    testSetup.cfg.File.fileOrder = [\"brief\", \"empty\", \"file\", \"author\", \"date\"];\n    const date = moment().format(\"YYYY-MM-DD\");\n    const year = moment().format(\"YYYY\");\n\n    // Tests\n    test(\"#include on next line\", () => {\n        const result = testSetup.SetLine(\"#include <iostream>\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author your name (you@domain.com)\\n\" +\n            \" * @date \" + date + \"\\n */\");\n    });\n\n    test(\"#pragma on next line\", () => {\n        const result = testSetup.SetLine(\"#pragma Foo\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author your name (you@domain.com)\\n\" +\n            \" * @date \" + date + \"\\n */\");\n    });\n\n    test(\"On first line of document\", () => {\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author your name (you@domain.com)\\n\" +\n            \" * @date \" + date + \"\\n */\");\n    });\n\n    test(\"File description in first line\", () => {\n        const result = testSetup.SetLines([\n            \"/**\",\n            \"\",\n            \"\",\n            \"struct T {\",\n            \"   int i;\",\n            \"};\",\n            ], false).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @file MockDocument.h\\n * @author your name (you@domain.com)\\n\" +\n            \" * @date \" + date + \"\\n */\");\n    });\n\n    test(\"Don't generate non existing commands\", () => {\n        testSetup.cfg.File.fileOrder = [\"dates\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n */\");\n    });\n\n    test(\"version block\", () => {\n        testSetup.cfg.File.fileOrder = [\"version\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @version 0.1\\n */\");\n    });\n\n    test(\"Copyright block\", () => {\n        testSetup.cfg.File.fileOrder = [\"copyright\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @copyright Copyright (c) \" + year + \"\\n */\");\n    });\n\n    test(\"version block\", () => {\n        testSetup.cfg.File.fileOrder = [\"version\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @version 0.1\\n */\");\n    });\n\n    test(\"custom block\", () => {\n        testSetup.cfg.File.fileOrder = [\"custom\"];\n        testSetup.cfg.File.customTag = [\"First Line\", \"{year} Year Line\", \"{date} Date Line\",\n                                        \"{author} Author Line\", \"{email} Email Line\", \"{file} File Line\"];\n        const result = testSetup.SetLine(\"\").GetResult();\n        assert.strictEqual(result, \"/**\\n * First Line\\n * \" + year + \" Year Line\\n * \" + date + \" Date Line\\n\" +\n            \" * your name Author Line\\n * you@domain.com Email Line\\n\" + \" * MockDocument.h File Line\\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/FunctionPointer.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Function pointer Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Function pointer return\", () => {\n        const result = testSetup.SetLine(\"int (*idputs(int a, int b))(char *);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return int(*)(char*) \\n */\");\n    });\n\n    test(\"Nested function pointer return\", () => {\n        const result = testSetup.SetLine(\"int (*(*(*foo(int a, int b))(int))(double))(float);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n\"\n            + \" * @return int(*(*(*)(int))(double))(float) \\n */\");\n    });\n\n    test(\"Function pointer parameter\", () => {\n        const result = testSetup.SetLine(\"int foo(int (*puts)(const char *));\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param puts \\n * @return int \\n */\");\n    });\n\n    test(\"Struct function pointer return with struct FP parameters and keywords\", () => {\n        const result = testSetup.SetLine(\"const struct foo (*idputs(int (*puts)(const char *), const\"\n            + \" struct test(*str)(int *, const struct test(*str2))))(const char *);\").GetResult();\n\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param puts \\n * @param str \"\n            + \"\\n * @return const struct foo(*)(const char*) \\n */\");\n    });\n\n    test(\"Memberpointer in function pointer\", () => {\n        const result = testSetup.SetLine(\"void foo(void (SomeClass::* func)());\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param func \\n */\");\n    });\n\n    test(\"Arraypointer\", () => {\n        const result = testSetup.SetLine(\"void some_function(int (*table)[]);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param table \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Operators.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Operators Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"+ operator\", () => {\n        const result = testSetup.SetLine(\"T operator +(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"- operator\", () => {\n        const result = testSetup.SetLine(\"T operator- (const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"* operator with params\", () => {\n        const result = testSetup.SetLine(\"T operator*(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"/ operator\", () => {\n        const result = testSetup.SetLine(\"T operator/(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"% operator\", () => {\n        const result = testSetup.SetLine(\"T operator%(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"^ operator\", () => {\n        const result = testSetup.SetLine(\"T operator^(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"& operator with params\", () => {\n        const result = testSetup.SetLine(\"T operator&(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"| operator\", () => {\n        const result = testSetup.SetLine(\"T operator|(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"~ operator\", () => {\n        const result = testSetup.SetLine(\"T operator~(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T \\n */\");\n    });\n\n    test(\"<< operator\", () => {\n        const result = testSetup.SetLine(\"T operator<<(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\">> operator\", () => {\n        const result = testSetup.SetLine(\"T operator>>(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return T \\n */\");\n    });\n\n    test(\"! operator\", () => {\n        const result = testSetup.SetLine(\"bool operator!(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return true \\n * @return false \\n */\");\n    });\n\n    test(\"&& operator\", () => {\n        const result = testSetup.SetLine(\"bool operator&&(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"|| operator\", () => {\n        const result = testSetup.SetLine(\"bool operator||(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"!= operator\", () => {\n        const result = testSetup.SetLine(\"bool operator!=(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"== operator\", () => {\n        const result = testSetup.SetLine(\"bool operator==(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"<= operator\", () => {\n        const result = testSetup.SetLine(\"bool operator<=(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\">= operator\", () => {\n        const result = testSetup.SetLine(\"bool operator>=(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"< operator\", () => {\n        const result = testSetup.SetLine(\"bool operator<(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"> operator\", () => {\n        const result = testSetup.SetLine(\"bool operator>(const T& lhs, const T2& rhs);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param lhs \\n * @param rhs \\n * @return true \\n\"\n            + \" * @return false \\n */\");\n    });\n\n    test(\"= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"+= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator+=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"-= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator-=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"*= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator*=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"/= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator/=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"%= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator%=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"^= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator^=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"&= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator&=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"|= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator|=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\">>= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator>>=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"<<= operator\", () => {\n        const result = testSetup.SetLine(\"T& operator<<=(const T& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T& \\n */\");\n    });\n\n    test(\"prefix ++ operator\", () => {\n        const result = testSetup.SetLine(\"T& operator++();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return T& \\n */\");\n    });\n\n    test(\"prefix -- operator\", () => {\n        const result = testSetup.SetLine(\"T& operator--();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return T& \\n */\");\n    });\n\n    test(\"postfix ++ operator\", () => {\n        const result = testSetup.SetLine(\"T operator++(int);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return T \\n */\");\n    });\n\n    test(\"postfix -- operator\", () => {\n        const result = testSetup.SetLine(\"T operator--(int);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return T \\n */\");\n    });\n\n    test(\"() operator\", () => {\n        let result = testSetup.SetLine(\"R operator()(const T& a, const T2& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return R \\n */\");\n\n        result = testSetup.SetLine(\"R operator( )(const T& a, const T2& b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return R \\n */\");\n    });\n\n    test(\", operator\", () => {\n        const result = testSetup.SetLine(\"T2& operator , (const T2& t);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param t \\n * @return T2& \\n */\");\n    });\n\n    test(\"* operator without params\", () => {\n        const result = testSetup.SetLine(\"R& operator*();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return R& \\n */\");\n    });\n\n    test(\"& operator without params\", () => {\n        const result = testSetup.SetLine(\"R* operator&();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return R* \\n */\");\n    });\n\n    test(\"->* operator\", () => {\n        const result = testSetup.SetLine(\"R& operator->*();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return R& \\n */\");\n    });\n\n    test(\"-> operator\", () => {\n        const result = testSetup.SetLine(\"R* operator->();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return R* \\n */\");\n    });\n\n    test(\"[] operator\", () => {\n        let result = testSetup.SetLine(\"R operator[](S b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param b \\n * @return R \\n */\");\n\n        result = testSetup.SetLine(\"R operator[ ](S b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param b \\n * @return R \\n */\");\n    });\n\n    test(\"new operator\", () => {\n        const result = testSetup.SetLine(\"void* operator new ( std::size_t count );\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param count \\n * @return void* \\n */\");\n    });\n\n    test(\"new[] operator\", () => {\n        let result = testSetup.SetLine(\"void* operator new[]( std::size_t count, std::align_val_t al);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param count \\n * @param al \\n * @return void* \\n */\");\n\n        result = testSetup.SetLine(\"void* operator new[ ]( std::size_t count, std::align_val_t al);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param count \\n * @param al \\n * @return void* \\n */\");\n    });\n\n    test(\"delete operator\", () => {\n        const result = testSetup.SetLine(\"void operator delete(void* ptr, std::size_t sz, std::align_val_t al);\")\n            .GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param ptr \\n * @param sz \\n * @param al \\n */\");\n    });\n\n    test(\"delete[] operator\", () => {\n        let result = testSetup.SetLine(\"void operator delete[] (void* ptr);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param ptr \\n */\");\n\n        result = testSetup.SetLine(\"void operator delete [ ] (void* ptr);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param ptr \\n */\");\n    });\n\n    test(\"user literal operator\", () => {\n        let result = testSetup.SetLine(\"long double operator\\\"\\\"_My_C00l_Conversion(const char * str);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param str \\n * @return long double \\n */\");\n\n        result = testSetup.SetLine(\"long double operator \\\"\\\"_My_C00l_Conversion(const char * str);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param str \\n * @return long double \\n */\");\n\n        result = testSetup.SetLine(\"long double operator\\\"\\\"_My_C00l_Conversion (const char * str);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param str \\n * @return long double \\n */\");\n    });\n\n    test(\"Implicit conversion operator\", () => {\n        const result = testSetup.SetLine(\"operator int() const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Explicit conversion operator\", () => {\n        const result = testSetup.SetLine(\"explicit operator int() const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"conversion operator to struct\", () => {\n        const result = testSetup.SetLine(\"explicit operator struct foo() const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return struct foo \\n */\");\n    });\n\n    test(\"conversion operator to struct pointer\", () => {\n        const result = testSetup.SetLine(\"explicit operator struct foo*() const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return struct foo* \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Parameters.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Parameters Tests\", () => {\n\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"No parameters\", () => {\n        const result = testSetup.SetLine(\"void foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Single parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Multiple parameters\", () => {\n        const result = testSetup.SetLine(\"void foo(int a, int b, int c);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @param c \\n */\");\n    });\n\n    test(\"Parameters with numbers in them\", () => {\n        const result = testSetup.SetLine(\"void foo(int a1, int b23);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b23 \\n */\");\n    });\n\n    test(\"Reference parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(int& a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Reference parameter with unsigned interger qualifier\", () => {\n        const result = testSetup.SetLine(\"void foo(unsigned int& a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Reference parameter with const qualifier\", () => {\n        const result = testSetup.SetLine(\"void foo(const int& a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Reference parameter with const and interger qualifier\", () => {\n        const result = testSetup.SetLine(\"void foo(const unsigned int& a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Pointer parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(int* a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n    });\n\n    test(\"Const parameter\", () => {\n        let result = testSetup.SetLine(\"void foo(const int a1);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int const a1);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n */\");\n    });\n\n    test(\"Struct parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(int a1, int b23);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b23 \\n */\");\n    });\n\n    test(\"Template parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(Matrix<T, N, M> mat);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param mat \\n */\");\n    });\n\n    test(\"Enum parameter\", () => {\n        const result = testSetup.SetLine(\"void foo(enum foo bar);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param bar \\n */\");\n    });\n\n    test(\"Const parameter with const pointer to const pointer\", () => {\n        let result = testSetup.SetLine(\"void foo(const int * const * const a1);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int const * const * const a1);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n */\");\n    });\n\n    test(\"Fundamental return type with modifiers\", () => {\n        let result = testSetup.SetLine(\"void foo(unsigned int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned short int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(signed short a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned long long int a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(signed a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned char a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long double a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long unsigned unsigned_a);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param unsigned_a \\n */\");\n    });\n\n    test(\"Parameter type in namespace\", () => {\n        const result = testSetup.SetLine(\"void foo(MyNamespace::Foo a1);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n */\");\n    });\n\n    test(\"Parameter template type in namespace\", () => {\n        const result = testSetup.SetLine(\"void foo(Math::Matrix<A, B, C> mat);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param mat \\n */\");\n    });\n\n    test(\"Parameter template type within templated namespace\", () => {\n        const result = testSetup.SetLine(\"void foo(Matrix<A, B, C>::Matrix<A, B, C> mat);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param mat \\n */\");\n    });\n\n    test(\"Parameter type in nested namespacee\", () => {\n        const result = testSetup.SetLine(\"void foo( Math::LA::Matrix<A, B, C> mat);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param mat \\n */\");\n    });\n\n    test(\"Parameter with default char literal\", () => {\n        let result = testSetup.SetLine(\"void foo(char a1 = 'a', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(char a1 = u'b', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(char a1 = u8'b', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(char a1 = U'a', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(char a1 = l',', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int a1 = 'ab', int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default string literal\", () => {\n        let result = testSetup.SetLine(\"void foo(std::string a1 = \\\"bar\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::string a1 = u\\\"bar, test\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::string a1 = u8\\\"bar\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::string a1 = U\\\"bar\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::string a1 = l\\\"bar\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::string a1 = R\\\"(bar\\\\t\\\\\\\")\\\", int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default integer literal\", () => {\n        let result = testSetup.SetLine(\"void foo(int a1 = 1337, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int a1 = 01337, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int a1 = 1337, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int a1 = 0x0FAB, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(int a1 = 0X0FAB, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::uint8_t a1 = 0b110011, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(std::byte a1 = 0B11111, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long a1 = 1337l, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long long a1 = 1337ll, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned long long a1 = 1337ull, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long a1 = 1337L, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long long a1 = 1337LL, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(unsigned long long a1 = 1337ULL, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default floating point literal\", () => {\n        let result = testSetup.SetLine(\"void foo(double a1 = 1e10, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(double a1 = 1., int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(double a1 = .1, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(double a1 = 0.1e-1, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(float a1 = 1.0f, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(float a1 = 1.0F, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long double a1 = 1.0lf, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(long double a1 = 1.0LF, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(double a1 = 0xa.bp10, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n\n        result = testSetup.SetLine(\"void foo(double a1 = 0xa.bp10l, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default compound literal\", () => {\n        const result = testSetup.SetLine(\"void foo(struct Bar a1 = {2, 3}, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default template function call\", () => {\n        const result = testSetup.SetLine(\"void foo(struct Bar a1 = test::baz<3, 2, 5>(23), int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Parameter with default user defined literal.\", () => {\n        const result = testSetup.SetLine(\"void foo(double a1 = 0xa.bp10l_deg_test, int b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a1 \\n * @param b \\n */\");\n    });\n\n    test(\"Member pointer as parameter\", () => {\n        const result = testSetup.SetLine(\"void test(int foo::* memberPointer);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param memberPointer \\n */\");\n    });\n\n    test(\"Restrict keyword\", () => {\n        const result = testSetup.SetLine(\"void some_function(char *restrict buf, const size_t buflen);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param buf \\n * @param buflen \\n */\");\n    });\n\n    test(\"Type as variable name\", () => {\n        let result = testSetup.SetLine(\"void MapPoint(double latitude, double longtitude) const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param latitude \\n * @param longtitude \\n */\");\n\n        result = testSetup.SetLine(\"void MapPoint(double latitude, double long int floattitude) const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param latitude \\n * @param floattitude \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Preprocessor.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Preprocessor Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"#define MY_MACRO 1\");\n\n    // Tests\n    test(\"Macro\", () => {\n        const result = testSetup.GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    // Tests\n    test(\"Macro with comment afterwards\", () => {\n        const result = testSetup.SetLines([\n            \"#define MY_MACRO 1\",\n            \"/**\",\n            \" */\",\n        ]).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    // These two tests don't seem to belong here but the behavior they're testing only is reproducable\n    // for macros otherwise\n    test(\"detect auto generated closing */\", () => {\n        const result = testSetup.SetLines([\n            \"*/\", // simulate an auto generated closing block comment\n            \"void foo(int bar);\",\n        ]).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param bar \\n */\");\n    });\n\n    test(\"don't detect closing */\", () => {\n        const result = testSetup.SetLines([\n            \"/*\",\n            \" */\",\n            \"void foo(int bar);\",\n        ]).GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/ReturnTypes.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Return type Tests\", () => {\n\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Void return\", () => {\n        const result = testSetup.SetLine(\"void foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Void pointer return\", () => {\n        const result = testSetup.SetLine(\"void* foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return void* \\n */\");\n    });\n\n    test(\"Reference return\", () => {\n        const result = testSetup.SetLine(\"int& foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int& \\n */\");\n    });\n\n    test(\"Simple type return\", () => {\n        const result = testSetup.SetLine(\"int foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Bool return type\", () => {\n        const result = testSetup.SetLine(\"bool foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return true \\n * @return false \\n */\");\n    });\n\n    test(\"Pointer return type\", () => {\n        const result = testSetup.SetLine(\"int* foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int* \\n */\");\n    });\n\n    test(\"Bool pointer return type\", () => {\n        const result = testSetup.SetLine(\"bool* foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return true \\n * @return false \\n */\");\n    });\n\n    test(\"Struct pointer return type\", () => {\n        const result = testSetup.SetLine(\"struct foo* foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return struct foo* \\n */\");\n    });\n\n    test(\"Struct return type\", () => {\n        const result = testSetup.SetLine(\"struct Bar* foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return struct Bar* \\n */\");\n    });\n\n    test(\"Return type with keywords\", () => {\n        const result = testSetup.SetLine(\"static constexpr inline Bar* const foo() \"\n            + \"const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return constexpr Bar* const \\n */\");\n    });\n\n    test(\"Return type struct with keywords\", () => {\n        const result = testSetup.SetLine(\"static constexpr inline struct Bar* foo() \"\n            + \"const;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return constexpr struct Bar* \\n */\");\n    });\n\n    test(\"Const with const pointer to const pointer return type\", () => {\n        let result = testSetup.SetLine(\"const int* const* const foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return const int* const* const \\n */\");\n\n        result = testSetup.SetLine(\"int const* const* const foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int const* const* const \\n */\");\n    });\n\n    test(\"Fundamental return type with modifiers\", () => {\n        let result = testSetup.SetLine(\"unsigned int foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return unsigned int \\n */\");\n\n        result = testSetup.SetLine(\"unsigned short int foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return unsigned short int \\n */\");\n\n        result = testSetup.SetLine(\"signed short foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return signed short \\n */\");\n\n        result = testSetup.SetLine(\"long foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return long \\n */\");\n\n        result = testSetup.SetLine(\"unsigned long long int foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return unsigned long long int \\n */\");\n\n        result = testSetup.SetLine(\"signed foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return signed \\n */\");\n\n        result = testSetup.SetLine(\"unsigned foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return unsigned \\n */\");\n\n        result = testSetup.SetLine(\"unsigned char foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return unsigned char \\n */\");\n\n        result = testSetup.SetLine(\"long double foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return long double \\n */\");\n\n        result = testSetup.SetLine(\"long unsigned unsigned_foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return long unsigned \\n */\");\n    });\n\n    test(\"Function in namespace\", () => {\n        const result = testSetup.SetLine(\"int MyClass::foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Return Type in namespace\", () => {\n        const result = testSetup.SetLine(\"MyNamespace::Foo MakeFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return MyNamespace::Foo \\n */\");\n    });\n\n    test(\"Template return type\", () => {\n        const result = testSetup.SetLine(\"Matrix<A, B, C> foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return Matrix<A, B, C> \\n */\");\n    });\n\n    test(\"Template return type within templated namespace\", () => {\n        const result = testSetup.SetLine(\"Matrix<A, B, C>::Matrix<A, B, C> foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return Matrix<A, B, C>::Matrix<A, B, C> \\n */\");\n    });\n\n    test(\"Function in templated namespace\", () => {\n        const result = testSetup.SetLine(\"int Matrix<A, B, C>::foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Function with nested namespacee\", () => {\n        const result = testSetup.SetLine(\"int Math::LA::Matrix<A, B, C>::foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Return Type in nested namespace\", () => {\n        const result = testSetup.SetLine(\"Math::LA::Matrix<A, B, C> foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return Math::LA::Matrix<A, B, C> \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/SmartText.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"Smart Text Tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Disable smart text Ctor\", () => {\n        testSetup.cfg.Generic.generateSmartText = false;\n        const result = testSetup.SetLine(\"Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Disable smart text Dtor\", () => {\n        testSetup.cfg.Generic.generateSmartText = false;\n        const result = testSetup.SetLine(\"~Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n */\");\n    });\n\n    test(\"Disable smart text getter\", () => {\n        testSetup.cfg.Generic.generateSmartText = false;\n        const result = testSetup.SetLine(\"int getFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Disable smart text setter\", () => {\n        testSetup.cfg.Generic.generateSmartText = false;\n        const result = testSetup.SetLine(\"void setFoo(int foo);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param foo \\n */\");\n    });\n\n    test(\"Disable smart text factory method\", () => {\n        testSetup.cfg.Generic.generateSmartText = false;\n        const result = testSetup.SetLine(\"int createFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Standard smart text Ctor\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Construct a new Foo object\\n * \\n */\");\n    });\n\n    test(\"Standard smart text Dtor\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"~Foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Destroy the Foo object\\n * \\n */\");\n    });\n\n    test(\"Standard smart text getter\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int getFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Get the Foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Standard smart text setter\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"void setFoo(int foo);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Set the Foo object\\n * \\n * @param foo \\n */\");\n    });\n\n    test(\"Standard smart text factory method\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int createFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a Foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: SCREAMING_SNAKE\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int CREATE_FOO();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: snake_case\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int create_foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: PascalCase\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int CreateFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a Foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: camelCase\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int createFoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a Foo object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: UPPERCASE\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int CREATEFOO();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief Create a FOO object\\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: UnCertain_CASE\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n        const result = testSetup.SetLine(\"int Create_FOO();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Casing text split: unidentifieable\", () => {\n        testSetup.cfg.Generic.generateSmartText = true;\n\n        // SCREAMING_SNAKE\n        let result = testSetup.SetLine(\"int CREATE_foo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n\n        // snake_case\n        result = testSetup.SetLine(\"int create_FOO();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n\n        // Pascal\n        result = testSetup.SetLine(\"int Createfoo();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n\n        // camel\n        result = testSetup.SetLine(\"int createFOO();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n\n        // UPPER???\n        result = testSetup.SetLine(\"int CREATE_();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/Templates.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Template tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // Tests\n    test(\"Template class\", () => {\n        const result = testSetup.SetLine(\"template<typename T, std::size_t M, std::size_t N,\"\n            + \"typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>\"\n            + \"class matrix {\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @tparam M \\n * @tparam N \\n * \"\n            + \"@tparam std::enable_if<std::is_arithmetic<T>::value, T>::type \\n */\");\n    });\n\n    test(\"Template function\", () => {\n        const result = testSetup.SetLine(\"template<typename T, typename S>\\nT f(T a, S b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @tparam S \\n * @param a \\n * \"\n            + \"@param b \\n * @return T \\n */\");\n    });\n\n    test(\"Double template\", () => {\n        const result = testSetup.SetLine(\"template<typename T>\\ntemplate<typename S>\\nT f(T a, S b);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @tparam S \\n * @param a \\n * \"\n            + \"@param b \\n * @return T \\n */\");\n    });\n\n    test(\"Template struct\", () => {\n        const result = testSetup.SetLine(\"template<typename T, std::size_t m, std::size_t n>\\n\"\n            + \"struct myStruct {\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @tparam m \\n * @tparam n \\n */\");\n    });\n\n    test(\"Variadic template\", () => {\n        const result = testSetup.SetLine(\"template<typename T, typename... Args>\"\n            + \"\\nT adder(T first, Args... args);\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam T \\n * @tparam Args \\n *\"\n            + \" @param first \\n * @param args \\n * @return T \\n */\");\n    });\n\n    test(\"Default template param value\", () => {\n        const result = testSetup.SetLine(\"template <bool is_foo=false, bool is_bar =true, bool is_nothrow = true>\"\n            + \"\\nstruct Foo;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @tparam is_foo \\n * @tparam is_bar \\n *\"\n            + \" @tparam is_nothrow \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/CppTests/TestSetup.ts",
    "content": "import * as vscode from \"vscode\";\n\nimport CodeParser from \"../../Common/ICodeParser\";\nimport { IDocGen } from \"../../Common/IDocGen\";\nimport { Config } from \"../../Config\";\nimport * as myExtension from \"../../extension\";\nimport GitConfig from \"../../GitConfig\";\nimport CppParser from \"../../Lang/Cpp/CppParser\";\nimport MockDocument from \"../tools/MockDocument\";\nimport MockEditor from \"../tools/MockEditor\";\nimport MockLine from \"../tools/MockLine\";\nimport MockPosition from \"../tools/MockPosition\";\nimport MockSelection from \"../tools/MockSelection\";\n\nexport default class TestSetup {\n    public cfg: Config;\n    public firstLine: number;\n    public gitConfig: GitConfig;\n    private editor: MockEditor;\n\n    constructor(method: string) {\n        this.gitConfig = new GitConfig();\n        this.cfg = new Config();\n        this.firstLine = 0;\n        this.SetLine(method);\n    }\n\n    public SetLine(method: string): TestSetup {\n        return this.SetLines([method]);\n    }\n\n    public SetLines(lines: string[], addIndent = true): TestSetup {\n        let mockLines: MockLine[];\n\n        // Add two empty lines with just the indentation\n        // since one is for the triggersequence line.\n        // And the other is if the next empty line.\n        if (lines.length > 0) {\n            if (addIndent === true) {\n                const indent: string = lines[0].match(\"^\\\\s*\")[0];\n\n                mockLines = [indent, indent].concat(lines)\n                    .map((l) => new MockLine(l));\n            } else {\n                mockLines = lines\n                    .map((l) => new MockLine(l));\n            }\n        }\n\n        const selection: MockSelection =  new MockSelection(new MockPosition(this.firstLine, 0));\n        const doc: MockDocument = new MockDocument(mockLines);\n\n        this.editor = new MockEditor(selection, doc);\n\n        return this;\n    }\n\n    public GetResult(): string {\n        let parser: CodeParser;\n        parser = new CppParser(this.cfg);\n\n        const gen: IDocGen = parser.Parse(this.editor);\n        // tslint:disable-next-line:max-line-length\n        gen.GenerateDoc(new vscode.Range(new vscode.Position(this.firstLine, 0), new vscode.Position(this.firstLine, 0)), this.gitConfig);\n\n        return this.editor.editBuilder.text;\n    }\n}\n"
  },
  {
    "path": "src/test/CppTests/TrailingReturns.test.ts",
    "content": "//\n// Note: This example test is leveraging the Mocha test framework.\n// Please refer to their documentation on https://mochajs.org/ for help.\n//\n\n// The module 'assert' provides assertion methods from node\nimport * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from \"vscode\";\nimport TestSetup from \"./TestSetup\";\n\n// Defines a Mocha test suite to group tests of similar kind together\nsuite(\"C++ - Trailing returns tests\", () => {\n    const testSetup: TestSetup = new TestSetup(\"void foo();\");\n\n    // tests\n    test(\"Trailing return\", () => {\n        const result = testSetup.SetLine(\"auto foo() -> int;\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return int \\n */\");\n    });\n\n    test(\"Trailing return with decltype\", () => {\n        const result = testSetup.SetLine(\"auto foo(int a, double b) -> decltype(a + b);\").GetResult();\n        // tslint:disable-next-line: max-line-length\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return decltype(a + b) \\n */\");\n    });\n\n    test(\"Multiple trailing returns\", () => {\n        const result = testSetup.SetLine(\"auto foo() -> auto(*)() -> tmp<int>(*)();\").GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @return auto(*)() -> tmp<int>(*)() \\n */\");\n    });\n\n    test(\"Trailing return with keywords\", () => {\n        const result = testSetup.SetLine(\"auto foo(const int& a, const double* b) const noexcept -> const double&;\")\n            .GetResult();\n        assert.strictEqual(result, \"/**\\n * @brief \\n * \\n * @param a \\n * @param b \\n * @return const double& \\n */\");\n    });\n});\n"
  },
  {
    "path": "src/test/index.ts",
    "content": "import * as glob from \"glob\";\nimport * as Mocha from \"mocha\";\nimport * as path from \"path\";\n\nfunction setupNyc() {\n    const NYC = require(\"nyc\");\n    // create an nyc instance, config here is the same as your package.json\n    const nyc = new NYC({\n    });\n    nyc.reset();\n    nyc.wrap();\n    return nyc;\n}\n\nexport function run(): Promise<void> {\n  // Create the mocha test\n  const mocha = new Mocha({\n    ui: \"tdd\",\n  });\n\n  const nyc = setupNyc();\n  const testsRoot = path.resolve(__dirname, \".\");\n\n  return new Promise((c, e) => {\n    glob(\"**/**.test.js\", { cwd: testsRoot }, (err, files) => {\n      if (err) {\n        return e(err);\n      }\n\n      // Add files to the test suite\n      files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));\n\n      try {\n        // Run the mocha test\n        mocha.run((failures) => {\n          if (failures > 0) {\n            e(new Error(`${failures} tests failed.`));\n          } else {\n            c();\n          }\n        });\n      } catch (err) {\n        e(err);\n      } finally {\n        nyc.writeCoverageFile();\n        nyc.report();\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "src/test/runTests.ts",
    "content": "import * as path from \"path\";\n\nimport { runTests } from \"vscode-test\";\n\nasync function main() {\n  try {\n    // The folder containing the Extension Manifest package.json\n    // Passed to `--extensionDevelopmentPath`\n    const extensionDevelopmentPath = path.resolve(__dirname, \"../../\");\n\n    // The path to the extension test runner script\n    // Passed to --extensionTestsPath\n    const extensionTestsPath = path.resolve(__dirname, \"./index\");\n\n    // Download VS Code, unzip it and run the integration test\n    await runTests({ extensionDevelopmentPath, extensionTestsPath });\n  } catch (err) {\n    // tslint:disable-next-line: no-console\n    console.error(\"Got error:\");\n    // tslint:disable-next-line: no-console\n    console.error(err);\n    // tslint:disable-next-line: no-console\n    console.error(\"Failed to run tests\");\n    process.exit(1);\n  }\n}\n\nmain();\n"
  },
  {
    "path": "src/test/tools/MockDocument.ts",
    "content": "import * as vscode from \"vscode\";\nimport MockLine from \"./MockLine\";\n\nexport default class MockDocument implements vscode.TextDocument {\n    public uri: vscode.Uri;\n    public fileName: string;\n    public isUntitled: boolean;\n    public languageId: string;\n    public version: number;\n    public isDirty: boolean;\n    public isClosed: boolean;\n    public eol: vscode.EndOfLine;\n    public lineCount: number;\n    private lines: vscode.TextLine[];\n    public constructor(lines: vscode.TextLine[]) {\n        this.lines = lines;\n        this.fileName = \"MockDocument.h\";\n    }\n    public save(): Thenable<boolean> {\n        throw new Error(\"Method not implemented.\");\n    }\n    public lineAt(line: number | vscode.Position): vscode.TextLine;\n    public lineAt(position: any): any {\n        if (position >= this.lines.length) {\n            return new MockLine(\";\");\n        }\n        return this.lines[position];\n    }\n    public offsetAt(position: vscode.Position): number {\n        throw new Error(\"Method not implemented.\");\n    }\n    public positionAt(offset: number): vscode.Position {\n        throw new Error(\"Method not implemented.\");\n    }\n    public getText(range?: vscode.Range): string {\n        throw new Error(\"Method not implemented.\");\n    }\n    public getWordRangeAtPosition(position: vscode.Position, regex?: RegExp): vscode.Range {\n        throw new Error(\"Method not implemented.\");\n    }\n    public validateRange(range: vscode.Range): vscode.Range {\n        throw new Error(\"Method not implemented.\");\n    }\n    public validatePosition(position: vscode.Position): vscode.Position {\n        throw new Error(\"Method not implemented.\");\n    }\n\n}\n"
  },
  {
    "path": "src/test/tools/MockEditor.ts",
    "content": "import * as vscode from \"vscode\";\nimport { Range, TextEditor } from \"vscode\";\nimport MockDocument from \"./MockDocument\";\nimport MockSelection from \"./MockSelection\";\nimport MockTextEditorEdit from \"./MockTextEditorEdit\";\n\nexport default class MockEditor implements TextEditor {\n    public document: vscode.TextDocument;\n    public selection: vscode.Selection;\n    public selections: vscode.Selection[];\n    public options: vscode.TextEditorOptions;\n    public viewColumn?: vscode.ViewColumn;\n    public editBuilder: MockTextEditorEdit;\n    public readonly visibleRanges: Range[];\n    public constructor(s: MockSelection, d: MockDocument) {\n        this.selection = s;\n        this.document = d;\n        this.editBuilder = new MockTextEditorEdit();\n    }\n\n    public edit(callback: (editBuilder: vscode.TextEditorEdit) => void,\n                options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean> {\n        callback(this.editBuilder);\n        return Promise.resolve(true);\n    }\n    public insertSnippet(snippet: vscode.SnippetString,\n                         location?: vscode.Position | vscode.Range | vscode.Position[] | vscode.Range[],\n                         options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean> {\n        throw new Error(\"Method not implemented.\");\n    }\n    public setDecorations(decorationType: vscode.TextEditorDecorationType,\n                          rangesOrOptions: vscode.Range[] | vscode.DecorationOptions[]): void {\n        throw new Error(\"Method not implemented.\");\n    }\n    public revealRange(range: vscode.Range, revealType?: vscode.TextEditorRevealType): void {\n        throw new Error(\"Method not implemented.\");\n    }\n    public show(column?: vscode.ViewColumn): void {\n        throw new Error(\"Method not implemented.\");\n    }\n    public hide(): void {\n        throw new Error(\"Method not implemented.\");\n    }\n}\n"
  },
  {
    "path": "src/test/tools/MockLine.ts",
    "content": "import * as vscode from \"vscode\";\n\nexport default class MockLine implements vscode.TextLine {\n    public lineNumber: number;\n    public text: string;\n    public range: vscode.Range;\n    public rangeIncludingLineBreak: vscode.Range;\n    public firstNonWhitespaceCharacterIndex: number;\n    public isEmptyOrWhitespace: boolean;\n    public constructor(text: string) {\n        this.text = text;\n    }\n}\n"
  },
  {
    "path": "src/test/tools/MockPosition.ts",
    "content": "import * as vscode from \"vscode\";\n\nexport default class MockPosition implements vscode.Position {\n    public line: number;\n    public character: number;\n    public constructor(l: number, c: number) {\n        this.line = l;\n        this.character = c;\n    }\n    public isBefore(other: vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public isBeforeOrEqual(other: vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public isAfter(other: vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public isAfterOrEqual(other: vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public isEqual(other: vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public compareTo(other: vscode.Position): number {\n        throw new Error(\"Method not implemented.\");\n    }\n    public translate(lineDelta?: number, characterDelta?: number): vscode.Position;\n    public translate(change: { lineDelta?: number; characterDelta?: number; }): vscode.Position;\n    public translate(lineDelta?: any, characterDelta?: any): any {\n        throw new Error(\"Method not implemented.\");\n    }\n    public with(line?: number, character?: number): vscode.Position;\n    public with(change: { line?: number; character?: number; }): vscode.Position;\n    public with(line?: any, character?: any): any {\n        throw new Error(\"Method not implemented.\");\n    }\n\n}\n"
  },
  {
    "path": "src/test/tools/MockSelection.ts",
    "content": "import * as vscode from \"vscode\";\nimport MockPosition from \"./MockPosition\";\n\nexport default class MockSelection implements vscode.Selection {\n    public anchor: vscode.Position;\n    public active: vscode.Position;\n    public isReversed: boolean;\n    public start: vscode.Position;\n    public end: vscode.Position;\n    public isEmpty: boolean;\n    public isSingleLine: boolean;\n\n    public constructor(a: MockPosition) {\n        this.active = a;\n        this.start = a;\n    }\n\n    public contains(positionOrRange: vscode.Range | vscode.Position): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public isEqual(other: vscode.Range): boolean {\n        throw new Error(\"Method not implemented.\");\n    }\n    public intersection(range: vscode.Range): vscode.Range {\n        throw new Error(\"Method not implemented.\");\n    }\n    public union(other: vscode.Range): vscode.Range {\n        throw new Error(\"Method not implemented.\");\n    }\n    public with(start?: vscode.Position, end?: vscode.Position): vscode.Range;\n    public with(change: { start?: vscode.Position; end?: vscode.Position; }): vscode.Range;\n    public with(start?: any, end?: any): any {\n        throw new Error(\"Method not implemented.\");\n    }\n}\n"
  },
  {
    "path": "src/test/tools/MockTextEditorEdit.ts",
    "content": "import * as vscode from \"vscode\";\n\nexport default class MockTextEditorEdit implements vscode.TextEditorEdit {\n    public text: string;\n    public replace(location: vscode.Position | vscode.Range | vscode.Selection, value: string): void {\n        this.text = value;\n    }\n    public insert(location: vscode.Position, value: string): void {\n        throw new Error(\"Method not implemented.\");\n    }\n    public delete(location: vscode.Range | vscode.Selection): void {\n        throw new Error(\"Method not implemented.\");\n    }\n    public setEndOfLine(endOfLine: vscode.EndOfLine): void {\n        throw new Error(\"Method not implemented.\");\n    }\n\n}\n"
  },
  {
    "path": "src/util.ts",
    "content": "import * as env from \"env-var\";\nimport * as vscode from \"vscode\";\n\n/**\n * Check if a specific line will be inside a comment block if comment block is inserted,\n * that is a line before the active line\n * @param activeEditor the active editor\n * @param activeLine the !previous! line to be checked\n */\nexport function inComment(activeEditor: vscode.TextEditor, activeLine: number): boolean {\n    if (activeLine === 0) {\n        return false;\n    }\n\n    const txt: string = activeEditor.document.lineAt(activeLine - 1).text.trim();\n    if (!txt.startsWith(\"///\") && !txt.startsWith(\"*\") &&\n        !txt.startsWith(\"/**\") && !txt.startsWith(\"/*!\")) {\n        return false;\n    } else {\n        return true;\n    }\n}\n\n/**\n * Get the indentation string for the current line (line at the current cursor position)\n */\nexport function getIndentation(editor: vscode.TextEditor = vscode.window.activeTextEditor): string {\n    return editor.document.lineAt(editor.selection.start.line).text.match(\"^\\\\s*\")[0];\n}\n\n/**\n * Expand environment variables in the string\n * @param replace string containing environment variables\n * @returns new string with expanded environment variables\n */\nexport function getEnvVars(replace: string): string {\n    let replacement = replace;\n    const regex = /\\$\\{env\\:([\\w|\\d|_]+)\\}/m;\n    let match: RegExpExecArray;\n\n    // tslint:disable-next-line:no-conditional-assignment\n    while ((match = regex.exec(replacement)) !== null) {\n        if (match.index === regex.lastIndex) {\n            regex.lastIndex++;\n        }\n\n        const m = match[1];\n\n        const envVar: string = env.get(m, m).asString();\n\n        replacement = replacement.replace(\"${env:\" + m + \"}\", envVar);\n    }\n\n    return replacement;\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"target\": \"es6\",\n        \"outDir\": \"out\",\n        \"lib\": [\n            \"es6\"\n        ],\n        \"sourceMap\": true,\n        \"rootDir\": \"src\"\n    },\n    \"exclude\": [\n        \"node_modules\",\n        \".vscode-test\"\n    ]\n}"
  },
  {
    "path": "tslint.json",
    "content": "{\n    \"defaultSeverity\": \"error\",\n    \"extends\": [\n        \"tslint:recommended\"\n    ],\n    \"jsRules\": {},\n    \"rules\": {},\n    \"rulesDirectory\": []\n}"
  }
]