master 586b3e45fe0a cached
60 files
217.7 KB
49.1k tokens
254 symbols
1 requests
Download .txt
Showing preview only (233K chars total). Download the full file or copy to clipboard to get everything.
Repository: LeetCode-OpenSource/vscode-leetcode
Branch: master
Commit: 586b3e45fe0a
Files: 60
Total size: 217.7 KB

Directory structure:
gitextract_pobireoz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug.md
│   │   ├── feature.md
│   │   └── question.md
│   ├── ISSUE_TEMPLATE.md
│   ├── no-response.yml
│   └── workflows/
│       └── build.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .vscodeignore
├── ACKNOWLEDGEMENTS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── _config.yml
├── docs/
│   └── README_zh-CN.md
├── package.json
├── src/
│   ├── codelens/
│   │   ├── CodeLensController.ts
│   │   └── CustomCodeLensProvider.ts
│   ├── commands/
│   │   ├── cache.ts
│   │   ├── language.ts
│   │   ├── list.ts
│   │   ├── plugin.ts
│   │   ├── session.ts
│   │   ├── show.ts
│   │   ├── star.ts
│   │   ├── submit.ts
│   │   └── test.ts
│   ├── explorer/
│   │   ├── LeetCodeNode.ts
│   │   ├── LeetCodeTreeDataProvider.ts
│   │   ├── LeetCodeTreeItemDecorationProvider.ts
│   │   └── explorerNodeManager.ts
│   ├── extension.ts
│   ├── globalState.ts
│   ├── leetCodeChannel.ts
│   ├── leetCodeExecutor.ts
│   ├── leetCodeManager.ts
│   ├── request/
│   │   └── query-user-data.ts
│   ├── shared.ts
│   ├── statusbar/
│   │   ├── LeetCodeStatusBarItem.ts
│   │   └── leetCodeStatusBarController.ts
│   ├── utils/
│   │   ├── cpUtils.ts
│   │   ├── httpUtils.ts
│   │   ├── osUtils.ts
│   │   ├── problemUtils.ts
│   │   ├── settingUtils.ts
│   │   ├── toolUtils.ts
│   │   ├── trackingUtils.ts
│   │   ├── uiUtils.ts
│   │   ├── workspaceUtils.ts
│   │   └── wslUtils.ts
│   └── webview/
│       ├── LeetCodeWebview.ts
│       ├── leetCodePreviewProvider.ts
│       ├── leetCodeSolutionProvider.ts
│       ├── leetCodeSubmissionProvider.ts
│       └── markdownEngine.ts
├── thirdpartynotice.txt
├── tsconfig.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug.md
================================================
---
name: 🐛 Bug report
about: Create a report to help us improve
---

## 🐛 Bug Report

A clear and concise description of what the bug is.

## To Reproduce

Steps to reproduce the behavior.

## Expected behavior

A clear and concise description of what you expected to happen.

## Extension Output

Paste here the LeetCode extension log from output channel.

Guidance: Press `Ctrl+Shift+U`, and toggle the channel to `LeetCode`.

## Your Environment

- *os*:
- *extension settings*:
- *nodejs version*:
- *vscode version*:
- *extension version*:


================================================
FILE: .github/ISSUE_TEMPLATE/feature.md
================================================
---
name: 🚀 Feature Proposal
about: Submit a proposal for a new feature
---

## 🚀 Feature Proposal

A clear and concise description of what the feature is.

## Motivation

Please outline the motivation for the proposal.

## Contribution

Please describe the solution if you'd like to submit a PR.


================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: 💬 Questions / Help
about: If you have questions, please check our documents first
---

Before you submit an question we recommend you to check out the [DOCUMENT](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/README.md) first.

You can also find more information in:
- [TROUBLESHOOTING](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/Troubleshooting)
- [FAQ](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/FAQ)

## 💬 Questions and Help

Please outline the questions.


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
*It's really recommended to create an issue by a template.*


================================================
FILE: .github/no-response.yml
================================================
daysUntilClose: 14
responseRequiredLabel: need more info
closeComment: >
  This issue has been closed automatically because it needs more information and has not had recent activity. Please reach out if you have or find the answers we need so that we can investigate further.


================================================
FILE: .github/workflows/build.yml
================================================
name: CI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  linux:
    name: Linux
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v2

      - name: Setup Node.js environment
        uses: actions/setup-node@v2
        with:
          node-version: 14

      - name: Install Node.js modules
        run: npm install

      - name: Lint
        run: npm run lint

      - name: VSCE Packge
        run: npx vsce package

  windows:
    name: Windows
    runs-on: windows-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v2

      - name: Setup Node.js environment
        uses: actions/setup-node@v2
        with:
          node-version: 14

      - name: Install Node.js modules
        run: npm install

      - name: Lint
        run: npm run lint

      - name: VSCE Packge
        run: npx vsce package


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Output
out
*.vsix
.vscode-test

# Mac
.DS_Store


================================================
FILE: .vscode/launch.json
================================================
// A launch configuration that compiles the extension and then opens it inside a new window
{
    "version": "0.1.0",
    "configurations": [
        {
            "name": "Launch Extension",
            "type": "extensionHost",
            "request": "launch",
            "runtimeExecutable": "${execPath}",
            "args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
            "stopOnEntry": false,
            "sourceMaps": true,
            "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ],
            "preLaunchTask": "npm"
        },
        {
            "name": "Launch Tests",
            "type": "extensionHost",
            "request": "launch",
            "runtimeExecutable": "${execPath}",
            "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
            "stopOnEntry": false,
            "sourceMaps": true,
            "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
            "preLaunchTask": "npm"
        }
    ]
}

================================================
FILE: .vscode/settings.json
================================================
{
    "editor.formatOnSave": false,
    "editor.insertSpaces": true,
    "editor.tabSize": 4,
    "files.insertFinalNewline": true,
    "files.trimTrailingWhitespace": true,
    "search.exclude": {
        "out": true,
        "**/node_modules": true,
        ".vscode-test": true
    },
    "tslint.autoFixOnSave": true,
    "tslint.ignoreDefinitionFiles": true,
    "prettier.tabWidth": 4,
    "prettier.useTabs": false,
    "prettier.printWidth": 150
}


================================================
FILE: .vscode/tasks.json
================================================
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "npm",
            "type": "shell",
            "command": "npm",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "args": [
                "run",
                "compile",
                "--loglevel",
                "silent"
            ],
            "isBackground": true,
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": "$tsc-watch"
        },
        {
            "type": "npm",
            "script": "lint",
            "problemMatcher": {
                "base": "$tslint5",
                "fileLocation": "absolute"
            }
        }
    ]
}

================================================
FILE: .vscodeignore
================================================
.vscode/**
.vscode-test/**
out/test/**
test/**
src/**
**/*.map
.gitignore
package-lock.json
tsconfig.json
tslint.json
**/*.gif
ACKNOWLEDGEMENTS.md
docs
.github


================================================
FILE: ACKNOWLEDGEMENTS.md
================================================
## Contributors 🙏❤

A big thanks to the following individuals for contributing:

- [@JIEJIAN21](https://github.com/JIEJIAN21) - thanks for logo and icon design
- [@TsFreddie](https://github.com/TsFreddie) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=TsFreddie)
- [@ntt2k](https://github.com/ntt2k) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=ntt2k)
- [@purocean](https://github.com/purocean) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=purocean)
- [@Xeonacid](https://github.com/Xeonacid) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=Xeonacid)
- [@Himself65](https://github.com/Himself65) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=Himself65)
- [@Vigilans](https://github.com/Vigilans) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=Vigilans)
- [@ringcrl](https://github.com/ringcrl) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=ringcrl)
- [@pujiaxun](https://github.com/pujiaxun) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=pujiaxun)
- [@edvardchen](https://github.com/edvardchen) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=edvardchen)
- [@poppinlp](https://github.com/poppinlp) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=poppinlp)
- [@xuzaixian](https://github.com/xuzaixian) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=xuzaixian)
- [@ZainChen](https://github.com/ZainChen) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=ZainChen)
- [@houtianze](https://github.com/houtianze) — [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=houtianze)
- [@magic-akari](https://github.com/magic-akari) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=magic-akari)
- [@SF-Zhou](https://github.com/SF-Zhou) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=SF-Zhou)
- [@fuafa](https://github.com/fuafa) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=fuafa)
- [@iFun](https://github.com/iFun) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=iFun)
- [@hologerry](https://github.com/hologerry) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=hologerry)
- [@yihong0618](https://github.com/yihong0618) - [contributions](https://github.com/LeetCode-OpenSource/vscode-leetcode/commits?author=yihong0618)


================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to the "leetcode" extension will be documented in this file.

Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

## [0.18.4]
### Added
- change graphql path

## [0.18.3]
### Added
- re-add cookie-based login method  [PR#969](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/969)

## [0.18.2]
### Fixed
- fix login issue on VS Code Insiders  [PR#968](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/968)

## [0.18.1]
### Changed
- change login way and add tracking logic option [PR#944](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/944)

## [0.18.0]
### Added
- Add `star` command in shortcuts [PR#601](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/601)
- Add an option to disable endpoint translation [#389](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/389)

### Changed
- LeetCode actions are moved into sub-menu: `LeetCode` in the editor context menu. [PR#712](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/712)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.18.0+is%3Aclosed+label%3Abug)

## [0.17.0]
### Added
- Add TypeScript support [#560](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/560)

### Changed
- Update the UI resources [PR#561](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/561)

## [0.16.2]
### Added
- New Category: `Concurrency` [CLI#42](https://github.com/leetcode-tools/leetcode-cli/pull/42)
- New configuration to better configure how to show the description [#310](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/310)

### Removed
- Removed the deprecated setting `leetcode.enableShortcuts` [PR#520](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/520)
- Removed the deprecated setting `leetcode.outputFolder` [PR#521](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/521)

## [0.16.1]
### Added
- Can show the problem in current workspace even if it's not a LeetCode workspace [#373](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/373)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.16.1+is%3Aclosed+label%3Abug)

## [0.16.0]
### Added
- Support GitHub login and LinkedIn login [PR#496](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/496)

## [0.15.8]
### Added
- Add a new command `Sign In by Cookie` to workaround the issue that [users cannot login to LeetCode](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/478). Please check the [workaround steps](https://github.com/LeetCode-OpenSource/vscode-leetcode/tree/master#%EF%B8%8F-attention-%EF%B8%8F--workaround-to-login-to-leetcode-endpoint) for more details!

### Changed
- Update the explorer icons to be align with the VS Code design [#460](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/460)

## [0.15.7]
### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.7+is%3Aclosed+label%3Abug)

## [0.15.6]
### Added
- Add a link to the solution page [#424](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/424)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.6+is%3Aclosed+label%3Abug)

## [0.15.5]
### Added
- Add a link to the discussion page [#420](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/420)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.5+is%3Aclosed+label%3Abug)

## [0.15.4]
### Added
- Add a new setting `leetcode.filePath`. Now users can use this setting to dynamicly specify the relative folder name and file name. [#PR380](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/380)

### Fixed
- Missing language `Rust` in the supported language list. [#PR412](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/412)
- Cannot show output when the answer is wrong. [#414](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/414)

## [0.15.3]
### Added
- Support `Pick One` [#263](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/263)
- Support toggling the favorite problems [#378](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/378)

### Changed
- Update the activity bar icon [#395](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/263)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.3+is%3Aclosed+label%3Abug)

## [0.15.2]
### Added
- Prompt to open the workspace for LeetCode [#130](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/130)
- Support deleting sessions [#198](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/130)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.2+is%3Aclosed+label%3Abug)

## [0.15.1]
### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.1+is%3Aclosed+label%3Abug)

## [0.15.0]
### Added
- Auto refresh the explorer after submitting [#91](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/91)
- Add a editor shortcut `Description` to show the problem description [#286](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/286)
- Support customizing the shortcuts in editor [#335](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/335)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.0+is%3Aclosed+label%3Abug)

## [0.14.3]
### Added
- Support interpolation for `leetcode.outputFolder` settings [#151](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/151)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+is%3Aclosed+milestone%3A0.14.3+label%3Abug)

## [0.14.2]
### Added
- Add the `All` category in the LeetCode Explorer [#184](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/184)
- Add shortcuts for `Show top voted solution` [#269](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/269)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+is%3Aclosed+label%3Abug+milestone%3A0.14.2)

## [0.14.1]
### Added
- Add setting `leetcode.showCommentDescription` to specify whether including the problem description in comments or not [#287](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/287)

## [0.14.0]
### Added
- Add setting `leetcode.enableShortcuts` to specify whether to show the submit/test shortcuts in editor [#146](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/146)
- Add `Like` and `Dislike` counts in the problem description [#267](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/267)

### Changed
- Improve the `Preview`, `Result` and `Solution` views

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+label%3Abug+is%3Aclosed+milestone%3A0.14.0)

## [0.13.3]
### Fixed
- Fix the bug that the extension cannot be activated

## [0.13.2]
### Added
- Add a setting `leetcode.enableStatusBar` to specify whether the LeetCode status bar will be shown or not [#156](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/156)
- Add a setting `leetcode.nodePath` to specify the `Node.js` executable path [#227](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/227)

### Changed
- Update the activity bar icon, See: [#225](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/225)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.13.2+is%3Aclosed+label%3Abug)

## [0.13.1]
### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.13.1+is%3Aclosed+label%3Abug)

## [0.13.0]
### Added
- Preview the problem description [#131](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/131)
- Show top voted solution [#193](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/193)
- Add `collapse all` for the explorer [#197](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/197)

### Fixed
[Bugs fixed](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues?q=is%3Aissue+is%3Aclosed+milestone%3A0.13.0+label%3Abug)

## [0.12.0]
### Added
- Add new command `LeetCode: Switch Default Language` to support switching the default language [#115](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/115)
- Support `PHP` and `Rust` ([#83](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/83), [#103](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/103))

### Fixed
- Cannot retrieve time and memory result [#105](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/105)
- Power operator displays in a wrong way [#74](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/74)

## [0.11.0]
### Added
- Add new setting: `leetcode.outputFolder` to customize the sub-directory to save the files generated by 'Show Problem' [#119](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/119)
- Add tooltips for sub-category nodes in LeetCode Explorer [#143](https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/143)

### Changed
- Now when triggering 'Show Problem', the extension will not generate a new file if it already exists [#59](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/59)

### Fixed
- Log in timeout when proxy is enabled [#117](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/117)

## [0.10.2]
### Fixed
- Test cases cannot have double quotes [#60](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/60)

## [0.10.1]
### Changed
- Refine the README page.

## [0.10.0]
### Added
- Add an extension setting to hide solved problems [#95](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/95)
- Support categorize problems by company, tag, difficulty and favorite [#67](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/67)

## [0.9.0]
### Changed
- Improve the experience of switching endpoint [#85](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/85)
- Use web view to show the result page [#76](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/76)


## [0.8.2]
### Added
- Add Code Lens for submitting the answer to LeetCode

### Fixed
- Fix the bug that the extension could not automatically sign in [#72](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/72)

## [0.8.1]
### Changed
- Upgrade LeetCode CLI to v2.6.1

## [0.8.0]
### Added
- Support LeetCode CN [#50](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/50)
- Support Windows Subsystem for Linux [#47](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/47)

## [0.7.0]
### Added
- Add spinner when submitting code [#43](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/43)

## [0.6.1]
### Added
- Add Sign in action into LeetCode Explorer title area [#25](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/25)

## [0.6.0]
### Changed
- Move LeetCode explorer into activity bar [#39](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/39)

### Added
- Support trigger test & submit in the editor [#37](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/37)

### Fixed
- Fix the bug that cannot show problem [#41](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/41)

## [0.5.1]
### Fixed
- Fix the bug when user's path contains white spaces [#34](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/34)

## [0.5.0]
### Added
- Support submit and test solution files from the file explorer in VS Code ([#24](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/24), [#26](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/26))

## [0.4.0]
### Added
- Support locked problem [#20](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/20)

### Changed
- Simplify the command 'LeetCode: Test Current File' to 'LeetCode: Test' [#18](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/18)
- Will automatically save current file when 'LeetCode: Test' command is triggered [#17](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/17)

## [0.3.0]
### Added
- Test current solution file [#15](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/15)

## [0.2.1]
### Fixed
- Fix the wrong icon bug in LeetCode Explorer [#9](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/9)
- Fix the switch session bug when login session is expired [#12](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/12)

## [0.2.0]
### Added
- Support setting the default language to solve problems [#5](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/5)

### Fixed
- When user cancels login, no further actions will happen [#10](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/10)

## [0.1.2]
### Fixed
- Fix the duplicated nodes in LeetCode Explorer bug [#6](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/6)

## [0.1.1]
### Fixed
- Fix a bug in LeetCode Explorer [#3](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/3)
- Remove the show problem command from command palette [#4](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/4)

## [0.1.0]
### Added
- Sign in/out to LeetCode
- Switch and create session
- Show problems in explorer
- Search problems by keywords
- Submit solutions to LeetCode


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020-present 力扣
Copyright (c) 2018-2019 jdneo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# LeetCode

> Solve LeetCode problems in VS Code

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/resources/LeetCode.png" alt="">
</p>
<p align="center">
  <a href="https://github.com/LeetCode-OpenSource/vscode-leetcode/actions?query=workflow%3ACI+branch%3Amaster">
    <img src="https://img.shields.io/github/workflow/status/LeetCode-OpenSource/vscode-leetcode/CI/master?style=flat-square" alt="">
  </a>
  <a href="https://gitter.im/vscode-leetcode/Lobby">
    <img src="https://img.shields.io/gitter/room/LeetCode-OpenSource/vscode-leetcode.svg?style=flat-square" alt="">
  </a>
  <a href="https://marketplace.visualstudio.com/items?itemName=LeetCode.vscode-leetcode">
    <img src="https://img.shields.io/visual-studio-marketplace/d/LeetCode.vscode-leetcode.svg?style=flat-square" alt="">
  </a>
  <a href="https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/LICENSE">
    <img src="https://img.shields.io/github/license/LeetCode-OpenSource/vscode-leetcode.svg?style=flat-square" alt="">
  </a>
</p>

- English Document | [中文文档](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/docs/README_zh-CN.md)

## ❗️ Attention ❗️- Workaround to login to LeetCode endpoint

> Note: If you are using `leetcode.cn`, you can just ignore this section.

Recently we observed that [the extension cannot login to leetcode.com endpoint anymore](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/478). The root cause of this issue is that leetcode.com changed its login mechanism and so far there is no ideal way to fix that issue.

Thanks for [@yihong0618](https://github.com/yihong0618) provided a workaround which can somehow mitigate this. Now you can simply click the `Sign In` button and then select `Third Party` login or `Cookie` login.

> Note: If you want to use third-party login(**Recommended**), please make sure your account has been connected to the third-party. If you want to use `Cookie` login, click [here](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/478#issuecomment-564757098) to see the steps.

## Requirements

- [VS Code 1.30.1+](https://code.visualstudio.com/)
- [Node.js 10+](https://nodejs.org)
  > NOTE: Please make sure that `Node` is in your `PATH` environment variable. You can also use the setting `leetcode.nodePath` to specify the location of your `Node.js` executable.

## Quick Start

![demo](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/gifs/demo.gif)

## Features

### Sign In/Out

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/sign_in.png" alt="Sign in" />
</p>

- Simply click `Sign in to LeetCode` in the `LeetCode Explorer` will let you **sign in** with your LeetCode account.

- You can also use the following command to sign in/out:
  - **LeetCode: Sign in**
  - **LeetCode: Sign out**

---

### Switch Endpoint

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/endpoint.png" alt="Switch Endpoint" />
</p>

- By clicking the button ![btn_endpoint](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/btn_endpoint.png) at the **explorer's navigation bar**, you can switch between different endpoints.

- The supported endpoints are:

  - **leetcode.com**
  - **leetcode.cn**

  > Note: The accounts of different endpoints are **not** shared. Please make sure you are using the right endpoint. The extension will use `leetcode.com` by default.

---

### Pick a Problem

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/pick_problem.png" alt="Pick a Problem" />
</p>

- Directly click on the problem or right click the problem in the `LeetCode Explorer` and select `Preview Problem` to see the problem description.
- Select `Show Problem` to directly open the file with the problem description.

  > Note:You can specify the path of the workspace folder to store the problem files by updating the setting `leetcode.workspaceFolder`. The default value is:**$HOME/.leetcode/**.

  > You can specify whether including the problem description in comments or not by updating the setting `leetcode.showCommentDescription`.

  > You can switch the default language by triggering the command: `LeetCode: Switch Default Language`.

---

### Editor Shortcuts

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/shortcuts.png" alt="Editor Shortcuts" />
</p>

- The extension supports 5 editor shortcuts (aka Code Lens):

  - `Submit`: Submit your answer to LeetCode.
  - `Test`: Test your answer with customized test cases.
  - `Star/Unstar`: Star or unstar the current problem.
  - `Solution`: Show the top voted solution for the current problem.
  - `Description`: Show the problem description page.

  > Note: You can customize the shortcuts using the setting: `leetcode.editor.shortcuts`. By default, only `Submit` and `Test` shortcuts are enabled.

---

### Search problems by Keywords

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/search.png" alt="Search problems by Keywords" />
</p>

- By clicking the button ![btn_search](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/btn_search.png) at the **explorer's navigation bar**, you can search the problems by keywords.

---

### Manage Session

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/session.png" alt="Manage Session" />
</p>

- To manage your LeetCode sessions, just clicking the `LeetCode: ***` at the bottom of the status bar. You can **switch** between sessions or **create**, **delete** a session.

## Settings

| Setting Name                      | Description                                                                                                                                                                                                                                                   | Default Value      |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `leetcode.hideSolved`             | Specify to hide the solved problems or not                                                                                                                                                                                                                    | `false`            |
| `leetcode.defaultLanguage`        | Specify the default language used to solve the problem. Supported languages are: `bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`,`rust`, `scala`, `swift`, `typescript`                     | `N/A`              |
| `leetcode.useWsl`                 | Specify whether to use WSL or not                                                                                                                                                                                                                             | `false`            |
| `leetcode.endpoint`               | Specify the active endpoint. Supported endpoints are: `leetcode`, `leetcode-cn`                                                                                                                                                                               | `leetcode`         |
| `leetcode.workspaceFolder`        | Specify the path of the workspace folder to store the problem files.                                                                                                                                                                                          | `""`               |
| `leetcode.filePath`               | Specify the relative path under the workspace and the file name to save the problem files. More details can be found [here](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/Customize-the-Relative-Folder-and-the-File-Name-of-the-Problem-File). |                    |
| `leetcode.enableStatusBar`        | Specify whether the LeetCode status bar will be shown or not.                                                                                                                                                                                                 | `true`             |
| `leetcode.editor.shortcuts`       | Specify the customized shortcuts in editors. Supported values are: `submit`, `test`, `star`, `solution` and `description`.                                                                                                                                    | `["submit, test"]` |
| `leetcode.enableSideMode`         | Specify whether `preview`, `solution` and `submission` tab should be grouped into the second editor column when solving a problem.                                                                                                                            | `true`             |
| `leetcode.nodePath`               | Specify the `Node.js` executable path. for example, C:\Program Files\nodejs\node.exe                                                                                                                                                                          | `node`             |
| `leetcode.showCommentDescription` | Specify whether to include the problem description in the comments                                                                                                                                                                                            | `false`            |
| `leetcode.useEndpointTranslation` | Use endpoint's translation (if available)                                                                                                                                                                                                                     | `true`             |
| `leetcode.colorizeProblems`       | Add difficulty badge and colorize problems files in explorer tree                                                                                                                                                                                             | `true`             |
| `leetcode.problems.sortStrategy`  | Specify sorting strategy for problems list                                                                                                                                                                                                                    | `None`             |
| `leetcode.allowReportData`        | Allow LeetCode to report anonymous usage data to improve the product. list                                                                                                                                                                                    | `true`             |

## Want Help?

When you meet any problem, you can check out the [Troubleshooting](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/Troubleshooting) and [FAQ](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/FAQ) first.

If your problem still cannot be addressed, feel free to reach us in the [Gitter Channel](https://gitter.im/vscode-leetcode/Lobby) or [file an issue](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/new/choose).

## Release Notes

Refer to [CHANGELOG](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/CHANGELOG.md)

## Acknowledgement

- This extension is based on [@skygragon](https://github.com/skygragon)'s [leetcode-cli](https://github.com/skygragon/leetcode-cli) open source project.
- Special thanks to our [contributors](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/ACKNOWLEDGEMENTS.md).


================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman

================================================
FILE: docs/README_zh-CN.md
================================================
# LeetCode

> 在 VS Code 中练习 LeetCode

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/resources/LeetCode.png" alt="">
</p>
<p align="center">
  <a href="https://github.com/LeetCode-OpenSource/vscode-leetcode/actions?query=workflow%3ACI+branch%3Amaster">
    <img src="https://img.shields.io/github/workflow/status/LeetCode-OpenSource/vscode-leetcode/CI/master?style=flat-square" alt="">
  </a>
  <a href="https://gitter.im/vscode-leetcode/Lobby">
    <img src="https://img.shields.io/gitter/room/LeetCode-OpenSource/vscode-leetcode.svg?style=flat-square" alt="">
  </a>
  <a href="https://marketplace.visualstudio.com/items?itemName=LeetCode.vscode-leetcode">
    <img src="https://img.shields.io/visual-studio-marketplace/d/LeetCode.vscode-leetcode.svg?style=flat-square" alt="">
  </a>
  <a href="https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/LICENSE">
    <img src="https://img.shields.io/github/license/LeetCode-OpenSource/vscode-leetcode.svg?style=flat-square" alt="">
  </a>
</p>

- [English Document](https://github.com/LeetCode-OpenSource/vscode-leetcode#requirements) | 中文文档

## ❗️ 注意 ❗️- 无法登录 LeetCode 节点的临时解决办法

> 注意:如果使用的是 `leetcode.cn` 账户,可以跳过此段落。

近期我们发现插件出现了[无法登录 leetcode.com 节点的问题](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/478)。原因是因为近期 leetcode.com 改变了登录机制,目前我们暂时没有找到解决该问题的完美解决方案。

感谢 [@yihong0618](https://github.com/yihong0618) 提供了一个临时解决办法。现在你可以直接点击登录按钮并选择第三方登录或者 `Cookie` 登录。

> 注意:如果你希望使用第三方登录(**推荐**),请确保你的账户已经与第三方账户连接。如果你希望通过 `Cookie` 登录,请点击[该连接](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/478#issuecomment-564757098)查看登录步骤。

## 运行条件

- [VS Code 1.23.0+](https://code.visualstudio.com/)
- [Node.js 10+](https://nodejs.org)
  > 注意:请确保`Node`在`PATH`环境变量中。您也可以通过设定 `leetcode.nodePath` 选项来指定 `Node.js` 可执行文件的路径。

## 快速开始

![demo](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/gifs/demo.gif)

## 功能

### 登入登出

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/sign_in.png" alt="登入登出" />
</p>

- 点击 `LeetCode Explorer` 中的 `Sign in to LeetCode` 即可登入。

- 你也可以使用下来命令登入或利用 cookie 登入或登出:
  - **LeetCode: Sign in**
  - **LeetCode: Sign out**

---

### 切换 LeetCode 版本

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/endpoint.png" alt="切换 LeetCode 版本" />
</p>

- LeetCode 目前有**英文版**和**中文版**两种版本。点击 `LeetCode Explorer` 导航栏中的 ![btn_endpoint](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/btn_endpoint.png) 按钮可切换版本。

- 目前可切换的版本有:

  - **leetcode.com**
  - **leetcode.cn**

  > 注意:两种版本的 LeetCode 账户并**不通用**,请确保当前激活的版本是正确的。插件默认激活的是**英文版**。

---

### 选择题目

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/pick_problem.png" alt="选择题目" />
</p>

- 直接点击题目或者在 `LeetCode Explorer` 中**右键**题目并选择 `Preview Problem` 可查看题目描述
- 选择 `Show Problem` 可直接进行答题。

  > 注意:你可以通过更新配置项 `leetcode.workspaceFolder` 来指定保存题目文件所用的工作区路径。默认工作区路径为:**$HOME/.leetcode/**。

  > 注意:你可以通过更新配置项 `leetcode.showCommentDescription` 来指定是否要在注释中包含题目描述。

  > 注意:你可以通过 `LeetCode: Switch Default Language` 命令变更答题时默认使用编程语言。

---

### 编辑器快捷方式

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/shortcuts.png" alt="Editor Shortcuts" />
</p>

- 插件会在编辑区域内支持五种不同的快捷方式(Code Lens):

  - `Submit`: 提交你的答案至 LeetCode;
  - `Test`: 用给定的测试用例测试你的答案;
  - `Star`: 收藏或取消收藏该问题;
  - `Solution`: 显示该问题的高票解答;
  - `Description`: 显示该问题的题目描述。

  > 注意:你可以通过 `leetcode.editor.shortcuts` 配置项来定制需要激活的快捷方式。默认情况下只有 `Submit` 和 `Test` 会被激活。

---

### 通过关键字搜索题目

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/search.png" alt="通过关键字搜索题目" />
</p>

- 点击 `LeetCode Explorer` 导航栏中的 ![btn_search](https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/btn_search.png) 按钮可按照关键字搜索题目。

---

### 管理存档

<p align="center">
  <img src="https://raw.githubusercontent.com/LeetCode-OpenSource/vscode-leetcode/master/docs/imgs/session.png" alt="管理存档" />
</p>

- 点击位于 VS Code 底部状态栏的 `LeetCode: ***` 管理 `LeetCode 存档`。你可以**切换**存档或者**创建**,**删除**存档。

## 插件配置项

| 配置项名称                        | 描述                                                                                                                                                                                                                                                                                                          | 默认值             |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `leetcode.hideSolved`             | 指定是否要隐藏已解决的问题                                                                                                                                                                                                                                                                                    | `false`            |
| `leetcode.defaultLanguage`        | 指定答题时使用的默认语言,可选语言有:`bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`, `rust`, `scala`, `swift`, `typescript`                                                                                                               | `N/A`              |
| `leetcode.useWsl`                 | 指定是否启用 WSL                                                                                                                                                                                                                                                                                              | `false`            |
| `leetcode.endpoint`               | 指定使用的终端,可用终端有:`leetcode`, `leetcode-cn`                                                                                                                                                                                                                                                         | `leetcode`         |
| `leetcode.workspaceFolder`        | 指定保存文件的工作区目录                                                                                                                                                                                                                                                                                      | `""`               |
| `leetcode.filePath`               | 指定生成题目文件的相对文件夹路径名和文件名。点击查看[更多详细用法](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%98%E7%9B%AE%E6%96%87%E4%BB%B6%E7%9A%84%E7%9B%B8%E5%AF%B9%E6%96%87%E4%BB%B6%E5%A4%B9%E8%B7%AF%E5%BE%84%E5%92%8C%E6%96%87%E4%BB%B6%E5%90%8D)。 |                    |
| `leetcode.enableStatusBar`        | 指定是否在 VS Code 下方显示插件状态栏。                                                                                                                                                                                                                                                                       | `true`             |
| `leetcode.editor.shortcuts`       | 指定在编辑器内所自定义的快捷方式。可用的快捷方式有: `submit`, `test`, `star`, `solution`, `description`。                                                                                                                                                                                                     | `["submit, test"]` |
| `leetcode.enableSideMode`         | 指定在解决一道题时,是否将`问题预览`、`高票答案`与`提交结果`窗口集中在编辑器的第二栏。                                                                                                                                                                                                                        | `true`             |
| `leetcode.nodePath`               | 指定 `Node.js` 可执行文件的路径。如:C:\Program Files\nodejs\node.exe                                                                                                                                                                                                                                         | `node`             |
| `leetcode.showCommentDescription` | 指定是否要在注释中显示题干。                                                                                                                                                                                                                                                                                  | `false`            |
| `leetcode.useEndpointTranslation` | 是否显示翻译版本内容。                                                                                                                                                                                                                                                                                        | `true`             |
| `leetcode.allowReportData`        | 为了更好的产品体验允许上报用户埋数据                                                                                                                                                                                                                                                                          | `true`             |

## 需要帮助?

在遇到任何问题时,可以先查看一下[疑难解答](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/%E7%96%91%E9%9A%BE%E8%A7%A3%E7%AD%94)以及[常见问题](https://github.com/LeetCode-OpenSource/vscode-leetcode/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)寻求帮助。

如果您的问题依然没有解决,可以在 [Gitter Channel](https://gitter.im/vscode-leetcode/Lobby) 联系我们,或者您也可以[记录一个新的 issue](https://github.com/LeetCode-OpenSource/vscode-leetcode/issues/new/choose)。

## 更新日志

请参考[更新日志](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/CHANGELOG.md)

## 鸣谢

- 本插件基于[@skygragon](https://github.com/skygragon)的[leetcode-cli](https://github.com/skygragon/leetcode-cli)开源项目制作。
- 特别鸣谢这些[贡献者们](https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/ACKNOWLEDGEMENTS.md)。


================================================
FILE: package.json
================================================
{
    "name": "vscode-leetcode",
    "displayName": "LeetCode",
    "description": "Solve LeetCode problems in VS Code",
    "version": "0.18.4",
    "author": "LeetCode",
    "publisher": "LeetCode",
    "license": "MIT",
    "icon": "resources/LeetCode.png",
    "engines": {
        "vscode": "^1.57.0"
    },
    "repository": {
        "type": "git",
        "url": "https://github.com/LeetCode-OpenSource/vscode-leetcode"
    },
    "homepage": "https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/README.md",
    "categories": [
        "Other",
        "Snippets"
    ],
    "keywords": [
        "leetcode",
        "algorithm",
        "interview"
    ],
    "preview": true,
    "activationEvents": [
        "onCommand:leetcode.toggleLeetCodeCn",
        "onCommand:leetcode.signin",
        "onCommand:leetcode.signout",
        "onCommand:leetcode.manageSessions",
        "onCommand:leetcode.refreshExplorer",
        "onCommand:leetcode.pickOne",
        "onCommand:leetcode.showProblem",
        "onCommand:leetcode.previewProblem",
        "onCommand:leetcode.searchProblem",
        "onCommand:leetcode.testSolution",
        "onCommand:leetcode.submitSolution",
        "onCommand:leetcode.switchDefaultLanguage",
        "onCommand:leetcode.problems.sort",
        "onView:leetCodeExplorer"
    ],
    "main": "./out/src/extension",
    "contributes": {
        "commands": [
            {
                "command": "leetcode.deleteCache",
                "title": "Delete Cache",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.toggleLeetCodeCn",
                "title": "Switch Endpoint",
                "category": "LeetCode",
                "icon": "$(globe)"
            },
            {
                "command": "leetcode.signin",
                "title": "Sign In",
                "category": "LeetCode",
                "icon": "$(sign-in)"
            },
            {
                "command": "leetcode.signout",
                "title": "Sign Out",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.manageSessions",
                "title": "Manage Sessions",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.refreshExplorer",
                "title": "Refresh",
                "category": "LeetCode",
                "icon": "$(refresh)"
            },
            {
                "command": "leetcode.pickOne",
                "title": "Pick One",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.showProblem",
                "title": "Show Problem",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.previewProblem",
                "title": "Preview Problem",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.searchProblem",
                "title": "Search Problem",
                "category": "LeetCode",
                "icon": "$(search)"
            },
            {
                "command": "leetcode.showSolution",
                "title": "Show Top Voted Solution",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.testSolution",
                "title": "Test in LeetCode",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.submitSolution",
                "title": "Submit to LeetCode",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.addFavorite",
                "title": "Add to Favorite List",
                "category": "LeetCode",
                "icon": {
                    "light": "resources/light/like.png",
                    "dark": "resources/dark/like.png"
                }
            },
            {
                "command": "leetcode.removeFavorite",
                "title": "Remove from Favorite List",
                "category": "LeetCode",
                "icon": {
                    "light": "resources/light/dislike.png",
                    "dark": "resources/dark/dislike.png"
                }
            },
            {
                "command": "leetcode.switchDefaultLanguage",
                "title": "Switch Default Language",
                "category": "LeetCode"
            },
            {
                "command": "leetcode.problems.sort",
                "title": "Sort Problems",
                "category": "LeetCode",
                "icon": "$(sort-precedence)"
            }
        ],
        "viewsContainers": {
            "activitybar": [
                {
                    "id": "leetcode",
                    "title": "LeetCode",
                    "icon": "resources/LeetCode.svg"
                }
            ]
        },
        "views": {
            "leetcode": [
                {
                    "id": "leetCodeExplorer",
                    "name": "Problems"
                }
            ]
        },
        "menus": {
            "view/title": [
                {
                    "command": "leetcode.toggleLeetCodeCn",
                    "when": "view == leetCodeExplorer",
                    "group": "navigation@0"
                },
                {
                    "command": "leetcode.signin",
                    "when": "view == leetCodeExplorer",
                    "group": "navigation@1"
                },
                {
                    "command": "leetcode.searchProblem",
                    "when": "view == leetCodeExplorer",
                    "group": "navigation@2"
                },
                {
                    "command": "leetcode.refreshExplorer",
                    "when": "view == leetCodeExplorer",
                    "group": "navigation@3"
                },
                {
                    "command": "leetcode.signout",
                    "when": "view == leetCodeExplorer",
                    "group": "overflow@1"
                },
                {
                    "command": "leetcode.pickOne",
                    "when": "view == leetCodeExplorer",
                    "group": "overflow@2"
                },
                {
                    "command": "leetcode.problems.sort",
                    "when": "view == leetCodeExplorer",
                    "group": "overflow@3"
                }
            ],
            "view/item/context": [
                {
                    "command": "leetcode.previewProblem",
                    "when": "view == leetCodeExplorer && viewItem =~ /problem*/",
                    "group": "leetcode@1"
                },
                {
                    "command": "leetcode.showProblem",
                    "when": "view == leetCodeExplorer && viewItem =~ /problem*/",
                    "group": "leetcode@2"
                },
                {
                    "command": "leetcode.showSolution",
                    "when": "view == leetCodeExplorer && viewItem =~ /problem*/",
                    "group": "leetcode@3"
                },
                {
                    "command": "leetcode.addFavorite",
                    "when": "view == leetCodeExplorer && viewItem == problem",
                    "group": "inline"
                },
                {
                    "command": "leetcode.removeFavorite",
                    "when": "view == leetCodeExplorer && viewItem == problem-favorite",
                    "group": "inline"
                }
            ],
            "commandPalette": [
                {
                    "command": "leetcode.showProblem",
                    "when": "never"
                },
                {
                    "command": "leetcode.showSolution",
                    "when": "never"
                },
                {
                    "command": "leetcode.previewProblem",
                    "when": "never"
                },
                {
                    "command": "leetcode.addFavorite",
                    "when": "never"
                },
                {
                    "command": "leetcode.removeFavorite",
                    "when": "never"
                }
            ],
            "explorer/context": [
                {
                    "command": "leetcode.testSolution",
                    "when": "explorerResourceIsFolder == false",
                    "group": "leetcode@1"
                },
                {
                    "command": "leetcode.submitSolution",
                    "when": "explorerResourceIsFolder == false",
                    "group": "leetcode@2"
                }
            ],
            "editor/context": [
                {
                    "submenu": "leetcode.editorAction"
                }
            ],
            "leetcode.editorAction": [
                {
                    "command": "leetcode.testSolution",
                    "group": "leetcode@1"
                },
                {
                    "command": "leetcode.submitSolution",
                    "group": "leetcode@2"
                },
                {
                    "command": "leetcode.showSolution",
                    "group": "leetcode@3"
                },
                {
                    "command": "leetcode.previewProblem",
                    "group": "leetcode@4"
                }
            ]
        },
        "submenus": [
            {
                "id": "leetcode.editorAction",
                "label": "LeetCode"
            }
        ],
        "configuration": [
            {
                "title": "LeetCode",
                "properties": {
                    "leetcode.hideSolved": {
                        "type": "boolean",
                        "default": false,
                        "scope": "application",
                        "description": "Hide solved problems."
                    },
                    "leetcode.defaultLanguage": {
                        "type": "string",
                        "enum": [
                            "bash",
                            "c",
                            "cpp",
                            "csharp",
                            "golang",
                            "java",
                            "javascript",
                            "kotlin",
                            "mysql",
                            "php",
                            "python",
                            "python3",
                            "ruby",
                            "rust",
                            "scala",
                            "swift",
                            "typescript"
                        ],
                        "scope": "application",
                        "description": "Default language for solving the problems."
                    },
                    "leetcode.showDescription": {
                        "type": "string",
                        "default": "In Webview",
                        "enum": [
                            "In Webview",
                            "In File Comment",
                            "Both",
                            "None"
                        ],
                        "enumDescriptions": [
                            "Show the problem description in a new webview window",
                            "Show the problem description in the file's comment"
                        ],
                        "scope": "application",
                        "description": "Specify where to show the description."
                    },
                    "leetcode.showCommentDescription": {
                        "type": "boolean",
                        "default": false,
                        "scope": "application",
                        "description": "[Deprecated] Include problem description in comments.",
                        "deprecationMessage": "This setting will be deprecated in 0.17.0, please use 'leetcode.showDescription' instead"
                    },
                    "leetcode.hint.setDefaultLanguage": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Show a hint to set the default language."
                    },
                    "leetcode.hint.configWebviewMarkdown": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Show a hint to change webview appearance through markdown config."
                    },
                    "leetcode.hint.commentDescription": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Show a hint to enable comment description in solution code file."
                    },
                    "leetcode.hint.commandShortcut": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Show a hint to configure commands key binding."
                    },
                    "leetcode.useWsl": {
                        "type": "boolean",
                        "default": false,
                        "scope": "application",
                        "description": "Use the Windows Subsystem for Linux."
                    },
                    "leetcode.endpoint": {
                        "type": "string",
                        "default": "leetcode",
                        "scope": "application",
                        "enum": [
                            "leetcode",
                            "leetcode-cn"
                        ],
                        "description": "Endpoint of the user account."
                    },
                    "leetcode.useEndpointTranslation": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Use endpoint's translation (if available)"
                    },
                    "leetcode.workspaceFolder": {
                        "type": "string",
                        "scope": "application",
                        "description": "The path of the workspace folder to store the problem files.",
                        "default": ""
                    },
                    "leetcode.filePath": {
                        "type": "object",
                        "scope": "application",
                        "description": "The output folder and filename to save the problem files.",
                        "properties": {
                            "default": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string",
                                        "examples": [
                                            "src"
                                        ]
                                    },
                                    "filename": {
                                        "type": "string",
                                        "examples": [
                                            "${camelCaseName}.${ext}",
                                            "${PascalCaseName}.${ext}",
                                            "${id}-${kebab-case-name}.${ext}",
                                            "${id}_${snake_case_name}.${ext}"
                                        ]
                                    }
                                },
                                "required": [
                                    "folder",
                                    "filename"
                                ]
                            },
                            "bash": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "c": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "cpp": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "csharp": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "golang": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "java": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "javascript": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "kotlin": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "mysql": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "php": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "python": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "python3": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "ruby": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "rust": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "scala": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            },
                            "swift": {
                                "type": "object",
                                "properties": {
                                    "folder": {
                                        "type": "string"
                                    },
                                    "filename": {
                                        "type": "string"
                                    }
                                },
                                "minProperties": 1
                            }
                        },
                        "additionalProperties": {
                            "type": "object",
                            "properties": {
                                "folder": {
                                    "type": "string"
                                },
                                "filename": {
                                    "type": "string"
                                }
                            },
                            "minProperties": 1
                        },
                        "default": {
                            "default": {
                                "folder": "",
                                "filename": "${id}.${kebab-case-name}.${ext}"
                            }
                        }
                    },
                    "leetcode.enableStatusBar": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Show the LeetCode status bar or not."
                    },
                    "leetcode.editor.shortcuts": {
                        "type": "array",
                        "default": [
                            "submit",
                            "test"
                        ],
                        "scope": "application",
                        "items": {
                            "type": "string",
                            "enum": [
                                "submit",
                                "test",
                                "star",
                                "solution",
                                "description"
                            ],
                            "enumDescriptions": [
                                "Submit your answer to LeetCode.",
                                "Test your answer with customized test cases.",
                                "Star or unstar the current problem.",
                                "Show the top voted solution for the current problem.",
                                "Show the problem description page."
                            ]
                        },
                        "description": "Customize the shortcuts in editors."
                    },
                    "leetcode.enableSideMode": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Determine whether to group all webview pages into the second editor column when solving problems."
                    },
                    "leetcode.nodePath": {
                        "type": "string",
                        "default": "node",
                        "scope": "application",
                        "description": "The Node.js executable path. for example, C:\\Program Files\\nodejs\\node.exe"
                    },
                    "leetcode.colorizeProblems": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Add difficulty badge and colorize problems files in explorer tree."
                    },
                    "leetcode.problems.sortStrategy": {
                        "type": "string",
                        "default": "None",
                        "scope": "application",
                        "enum": [
                            "None",
                            "Acceptance Rate (Ascending)",
                            "Acceptance Rate (Descending)"
                        ],
                        "description": "Sorting strategy for problems list."
                    },
                    "leetcode.allowReportData": {
                        "type": "boolean",
                        "default": true,
                        "scope": "application",
                        "description": "Allow LeetCode to report anonymous usage data to improve the product."
                    }
                }
            }
        ]
    },
    "scripts": {
        "vscode:prepublish": "npm run compile",
        "compile": "tsc -p ./",
        "watch": "tsc -watch -p ./",
        "lint": "tslint --project tsconfig.json -e src/*.d.ts -t verbose",
        "build": "vsce package",
        "vs-publish": "vsce publish"
    },
    "devDependencies": {
        "@types/fs-extra": "^9.0.11",
        "@types/lodash": "^4.14.170",
        "@types/markdown-it": "0.0.7",
        "@types/mocha": "^2.2.42",
        "@types/node": "^14.14.33",
        "@types/require-from-string": "^1.2.0",
        "@types/vscode": "1.57.0",
        "tslint": "^5.20.1",
        "typescript": "^4.3.2"
    },
    "dependencies": {
        "axios": "^1.6.8",
        "fs-extra": "^10.0.0",
        "highlight.js": "^10.7.2",
        "lodash": "^4.17.21",
        "markdown-it": "^8.4.2",
        "require-from-string": "^2.0.2",
        "unescape-js": "^1.1.4",
        "vsc-leetcode-cli": "2.8.1"
    }
}


================================================
FILE: src/codelens/CodeLensController.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { ConfigurationChangeEvent, Disposable, languages, workspace } from "vscode";
import { customCodeLensProvider, CustomCodeLensProvider } from "./CustomCodeLensProvider";

class CodeLensController implements Disposable {
    private internalProvider: CustomCodeLensProvider;
    private registeredProvider: Disposable | undefined;
    private configurationChangeListener: Disposable;

    constructor() {
        this.internalProvider = customCodeLensProvider;

        this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
            if (event.affectsConfiguration("leetcode.editor.shortcuts")) {
                this.internalProvider.refresh();
            }
        }, this);

        this.registeredProvider = languages.registerCodeLensProvider({ scheme: "file" }, this.internalProvider);
    }

    public dispose(): void {
        if (this.registeredProvider) {
            this.registeredProvider.dispose();
        }
        this.configurationChangeListener.dispose();
    }
}

export const codeLensController: CodeLensController = new CodeLensController();


================================================
FILE: src/codelens/CustomCodeLensProvider.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { explorerNodeManager } from "../explorer/explorerNodeManager";
import { LeetCodeNode } from "../explorer/LeetCodeNode";
import { getEditorShortcuts } from "../utils/settingUtils";

export class CustomCodeLensProvider implements vscode.CodeLensProvider {

    private onDidChangeCodeLensesEmitter: vscode.EventEmitter<void> = new vscode.EventEmitter<void>();

    get onDidChangeCodeLenses(): vscode.Event<void> {
        return this.onDidChangeCodeLensesEmitter.event;
    }

    public refresh(): void {
        this.onDidChangeCodeLensesEmitter.fire();
    }

    public provideCodeLenses(document: vscode.TextDocument): vscode.ProviderResult<vscode.CodeLens[]> {
        const shortcuts: string[] = getEditorShortcuts();
        if (!shortcuts) {
            return;
        }

        const content: string = document.getText();
        const matchResult: RegExpMatchArray | null = content.match(/@lc app=.* id=(.*) lang=.*/);
        if (!matchResult) {
            return undefined;
        }
        const nodeId: string | undefined = matchResult[1];
        let node: LeetCodeNode | undefined;
        if (nodeId) {
            node = explorerNodeManager.getNodeById(nodeId);
        }

        let codeLensLine: number = document.lineCount - 1;
        for (let i: number = document.lineCount - 1; i >= 0; i--) {
            const lineContent: string = document.lineAt(i).text;
            if (lineContent.indexOf("@lc code=end") >= 0) {
                codeLensLine = i;
                break;
            }
        }

        const range: vscode.Range = new vscode.Range(codeLensLine, 0, codeLensLine, 0);
        const codeLens: vscode.CodeLens[] = [];

        if (shortcuts.indexOf("submit") >= 0) {
            codeLens.push(new vscode.CodeLens(range, {
                title: "Submit",
                command: "leetcode.submitSolution",
                arguments: [document.uri],
            }));
        }

        if (shortcuts.indexOf("test") >= 0) {
            codeLens.push(new vscode.CodeLens(range, {
                title: "Test",
                command: "leetcode.testSolution",
                arguments: [document.uri],
            }));
        }

        if (shortcuts.indexOf("star") >= 0 && node) {
            codeLens.push(new vscode.CodeLens(range, {
                title: node.isFavorite ? "Unstar" : "Star",
                command: node.isFavorite ? "leetcode.removeFavorite" : "leetcode.addFavorite",
                arguments: [node],
            }));
        }

        if (shortcuts.indexOf("solution") >= 0) {
            codeLens.push(new vscode.CodeLens(range, {
                title: "Solution",
                command: "leetcode.showSolution",
                arguments: [document.uri],
            }));
        }

        if (shortcuts.indexOf("description") >= 0) {
            codeLens.push(new vscode.CodeLens(range, {
                title: "Description",
                command: "leetcode.previewProblem",
                arguments: [document.uri],
            }));
        }

        return codeLens;
    }
}

export const customCodeLensProvider: CustomCodeLensProvider = new CustomCodeLensProvider();


================================================
FILE: src/commands/cache.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { leetCodeExecutor } from "../leetCodeExecutor";
import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";

export async function deleteCache(): Promise<void> {
    try {
        await leetCodeExecutor.deleteCache();
    } catch (error) {
        await promptForOpenOutputChannel("Failed to delete cache. Please open the output channel for details.", DialogType.error);
    }
}


================================================
FILE: src/commands/language.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { QuickPickItem, window, workspace, WorkspaceConfiguration } from "vscode";
import { languages } from "../shared";

export async function switchDefaultLanguage(): Promise<void> {
    const leetCodeConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode");
    const defaultLanguage: string | undefined = leetCodeConfig.get<string>("defaultLanguage");
    const languageItems: QuickPickItem[] = [];
    for (const language of languages) {
        languageItems.push({
            label: language,
            description: defaultLanguage === language ? "Currently used" : undefined,
        });
    }
    // Put the default language at the top of the list
    languageItems.sort((a: QuickPickItem, b: QuickPickItem) => {
        if (a.description) {
            return Number.MIN_SAFE_INTEGER;
        } else if (b.description) {
            return Number.MAX_SAFE_INTEGER;
        }
        return a.label.localeCompare(b.label);
    });

    const selectedItem: QuickPickItem | undefined = await window.showQuickPick(languageItems, {
        placeHolder: "Please the default language",
        ignoreFocusOut: true,
    });

    if (!selectedItem) {
        return;
    }

    leetCodeConfig.update("defaultLanguage", selectedItem.label, true /* Global */);
    window.showInformationMessage(`Successfully set the default language to ${selectedItem.label}`);
}


================================================
FILE: src/commands/list.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { IProblem, ProblemState, UserStatus } from "../shared";
import * as settingUtils from "../utils/settingUtils";
import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";

export async function listProblems(): Promise<IProblem[]> {
    try {
        if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
            return [];
        }

        const useEndpointTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
        const result: string = await leetCodeExecutor.listProblems(true, useEndpointTranslation);
        const problems: IProblem[] = [];
        const lines: string[] = result.split("\n");
        const reg: RegExp = /^(.)\s(.{1,2})\s(.)\s\[\s*(\d*)\s*\]\s*(.*)\s*(Easy|Medium|Hard)\s*\((\s*\d+\.\d+ %)\)/;
        const { companies, tags } = await leetCodeExecutor.getCompaniesAndTags();
        for (const line of lines) {
            const match: RegExpMatchArray | null = line.match(reg);
            if (match && match.length === 8) {
                const id: string = match[4].trim();
                problems.push({
                    id,
                    isFavorite: match[1].trim().length > 0,
                    locked: match[2].trim().length > 0,
                    state: parseProblemState(match[3]),
                    name: match[5].trim(),
                    difficulty: match[6].trim(),
                    passRate: match[7].trim(),
                    companies: companies[id] || ["Unknown"],
                    tags: tags[id] || ["Unknown"],
                });
            }
        }
        return problems.reverse();
    } catch (error) {
        await promptForOpenOutputChannel("Failed to list problems. Please open the output channel for details.", DialogType.error);
        return [];
    }
}

function parseProblemState(stateOutput: string): ProblemState {
    if (!stateOutput) {
        return ProblemState.Unknown;
    }
    switch (stateOutput.trim()) {
        case "v":
        case "✔":
        case "√":
            return ProblemState.AC;
        case "X":
        case "✘":
        case "×":
            return ProblemState.NotAC;
        default:
            return ProblemState.Unknown;
    }
}


================================================
FILE: src/commands/plugin.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { IQuickItemEx } from "../shared";
import { Endpoint, SortingStrategy } from "../shared";
import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
import { deleteCache } from "./cache";

export async function switchEndpoint(): Promise<void> {
    const isCnEnabled: boolean = getLeetCodeEndpoint() === Endpoint.LeetCodeCN;
    const picks: Array<IQuickItemEx<string>> = [];
    picks.push(
        {
            label: `${isCnEnabled ? "" : "$(check) "}LeetCode`,
            description: "leetcode.com",
            detail: `Enable LeetCode US`,
            value: Endpoint.LeetCode,
        },
        {
            label: `${isCnEnabled ? "$(check) " : ""}力扣`,
            description: "leetcode.cn",
            detail: `启用中国版 LeetCode`,
            value: Endpoint.LeetCodeCN,
        },
    );
    const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(picks);
    if (!choice || choice.value === getLeetCodeEndpoint()) {
        return;
    }
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    try {
        const endpoint: string = choice.value;
        await leetCodeExecutor.switchEndpoint(endpoint);
        await leetCodeConfig.update("endpoint", endpoint, true /* UserSetting */);
        vscode.window.showInformationMessage(`Switched the endpoint to ${endpoint}`);
    } catch (error) {
        await promptForOpenOutputChannel("Failed to switch endpoint. Please open the output channel for details.", DialogType.error);
    }

    try {
        await vscode.commands.executeCommand("leetcode.signout");
        await deleteCache();
        await promptForSignIn();
    } catch (error) {
        await promptForOpenOutputChannel("Failed to sign in. Please open the output channel for details.", DialogType.error);
    }
}

export function getLeetCodeEndpoint(): string {
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    return leetCodeConfig.get<string>("endpoint", Endpoint.LeetCode);
}

const SORT_ORDER: SortingStrategy[] = [
    SortingStrategy.None,
    SortingStrategy.AcceptanceRateAsc,
    SortingStrategy.AcceptanceRateDesc,
];

export async function switchSortingStrategy(): Promise<void> {
    const currentStrategy: SortingStrategy = getSortingStrategy();
    const picks: Array<IQuickItemEx<string>> = [];
    picks.push(
        ...SORT_ORDER.map((s: SortingStrategy) => {
            return {
                label: `${currentStrategy === s ? "$(check)" : "    "} ${s}`,
                value: s,
            };
        }),
    );

    const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(picks);
    if (!choice || choice.value === currentStrategy) {
        return;
    }

    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    await leetCodeConfig.update("problems.sortStrategy", choice.value, true);
    await leetCodeTreeDataProvider.refresh();
}

export function getSortingStrategy(): SortingStrategy {
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    return leetCodeConfig.get<SortingStrategy>("problems.sortStrategy", SortingStrategy.None);
}


================================================
FILE: src/commands/session.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { IQuickItemEx } from "../shared";
import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";

export async function getSessionList(): Promise<ISession[]> {
    const signInStatus: string | undefined = leetCodeManager.getUser();
    if (!signInStatus) {
        promptForSignIn();
        return [];
    }
    const result: string = await leetCodeExecutor.listSessions();
    const lines: string[] = result.split("\n");
    const sessions: ISession[] = [];
    const reg: RegExp = /(.?)\s*(\d+)\s+(.*)\s+(\d+ \(\s*\d+\.\d+ %\))\s+(\d+ \(\s*\d+\.\d+ %\))/;
    for (const line of lines) {
        const match: RegExpMatchArray | null = line.match(reg);
        if (match && match.length === 6) {
            sessions.push({
                active: !!(match[1].trim()),
                id: match[2].trim(),
                name: match[3].trim(),
                acQuestions: match[4].trim(),
                acSubmits: match[5].trim(),
            });
        }
    }
    return sessions;
}

export async function manageSessions(): Promise<void> {
    const choice: IQuickItemEx<ISession | string> | undefined = await vscode.window.showQuickPick(parseSessionsToPicks(true /* includeOperation */));
    if (!choice || choice.description === "Active") {
        return;
    }
    if (choice.value === ":createSession") {
        await createSession();
        return;
    }
    if (choice.value === ":deleteSession") {
        await deleteSession();
        return;
    }
    try {
        await leetCodeExecutor.enableSession((choice.value as ISession).id);
        vscode.window.showInformationMessage(`Successfully switched to session '${choice.label}'.`);
        await vscode.commands.executeCommand("leetcode.refreshExplorer");
    } catch (error) {
        await promptForOpenOutputChannel("Failed to switch session. Please open the output channel for details.", DialogType.error);
    }
}

async function parseSessionsToPicks(includeOperations: boolean = false): Promise<Array<IQuickItemEx<ISession | string>>> {
    return new Promise(async (resolve: (res: Array<IQuickItemEx<ISession | string>>) => void): Promise<void> => {
        try {
            const sessions: ISession[] = await getSessionList();
            const picks: Array<IQuickItemEx<ISession | string>> = sessions.map((s: ISession) => Object.assign({}, {
                label: `${s.active ? "$(check) " : ""}${s.name}`,
                description: s.active ? "Active" : "",
                detail: `AC Questions: ${s.acQuestions}, AC Submits: ${s.acSubmits}`,
                value: s,
            }));

            if (includeOperations) {
                picks.push(...parseSessionManagementOperations());
            }
            resolve(picks);
        } catch (error) {
            return await promptForOpenOutputChannel("Failed to list sessions. Please open the output channel for details.", DialogType.error);
        }
    });
}

function parseSessionManagementOperations(): Array<IQuickItemEx<string>> {
    return [{
        label: "$(plus) Create a session",
        description: "",
        detail: "Click this item to create a session",
        value: ":createSession",
    }, {
        label: "$(trashcan) Delete a session",
        description: "",
        detail: "Click this item to DELETE a session",
        value: ":deleteSession",
    }];
}

async function createSession(): Promise<void> {
    const session: string | undefined = await vscode.window.showInputBox({
        prompt: "Enter the new session name.",
        validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "Session name must not be empty",
    });
    if (!session) {
        return;
    }
    try {
        await leetCodeExecutor.createSession(session);
        vscode.window.showInformationMessage("New session created, you can switch to it by clicking the status bar.");
    } catch (error) {
        await promptForOpenOutputChannel("Failed to create session. Please open the output channel for details.", DialogType.error);
    }
}

async function deleteSession(): Promise<void> {
    const choice: IQuickItemEx<ISession | string> | undefined = await vscode.window.showQuickPick(
        parseSessionsToPicks(false /* includeOperation */),
        { placeHolder: "Please select the session you want to delete" },
    );
    if (!choice) {
        return;
    }

    const selectedSession: ISession = choice.value as ISession;
    if (selectedSession.active) {
        vscode.window.showInformationMessage("Cannot delete an active session.");
        return;
    }

    const action: vscode.MessageItem | undefined = await vscode.window.showWarningMessage(
        `This operation cannot be reverted. Are you sure to delete the session: ${selectedSession.name}?`,
        DialogOptions.yes,
        DialogOptions.no,
    );
    if (action !== DialogOptions.yes) {
        return;
    }

    const confirm: string | undefined = await vscode.window.showInputBox({
        prompt: "Enter 'yes' to confirm deleting the session",
        validateInput: (value: string): string => {
            if (value === "yes") {
                return "";
            } else {
                return "Enter 'yes' to confirm";
            }
        },
    });

    if (confirm === "yes") {
        await leetCodeExecutor.deleteSession(selectedSession.id);
        vscode.window.showInformationMessage("The session has been successfully deleted.");
    }
}

export interface ISession {
    active: boolean;
    id: string;
    name: string;
    acQuestions: string;
    acSubmits: string;
}


================================================
FILE: src/commands/show.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as _ from "lodash";
import * as path from "path";
import * as unescapeJS from "unescape-js";
import * as vscode from "vscode";
import { explorerNodeManager } from "../explorer/explorerNodeManager";
import { LeetCodeNode } from "../explorer/LeetCodeNode";
import { leetCodeChannel } from "../leetCodeChannel";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { Endpoint, IProblem, IQuickItemEx, languages, PREMIUM_URL_CN, PREMIUM_URL_GLOBAL, ProblemState } from "../shared";
import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils";
import * as settingUtils from "../utils/settingUtils";
import { IDescriptionConfiguration } from "../utils/settingUtils";
import {
    DialogOptions,
    DialogType,
    openSettingsEditor,
    openUrl,
    promptForOpenOutputChannel,
    promptForSignIn,
    promptHintMessage,
} from "../utils/uiUtils";
import { getActiveFilePath, selectWorkspaceFolder } from "../utils/workspaceUtils";
import * as wsl from "../utils/wslUtils";
import { leetCodePreviewProvider } from "../webview/leetCodePreviewProvider";
import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider";
import * as list from "./list";
import { getLeetCodeEndpoint } from "./plugin";
import { globalState } from "../globalState";

export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise<void> {
    let node: IProblem;

    if (input instanceof vscode.Uri) {
        const activeFilePath: string = input.fsPath;
        const id: string = await getNodeIdFromFile(activeFilePath);
        if (!id) {
            vscode.window.showErrorMessage(`Failed to resolve the problem id from file: ${activeFilePath}.`);
            return;
        }
        const cachedNode: IProblem | undefined = explorerNodeManager.getNodeById(id);
        if (!cachedNode) {
            vscode.window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`);
            return;
        }
        node = cachedNode;
        // Move the preview page aside if it's triggered from Code Lens
        isSideMode = true;
    } else {
        node = input;
        const { isPremium } = globalState.getUserStatus() ?? {};
        if (input.locked && !isPremium) {
            const url = getLeetCodeEndpoint() === Endpoint.LeetCode ? PREMIUM_URL_GLOBAL : PREMIUM_URL_CN;
            openUrl(url);
            return;
        }
    }

    const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
    const descString: string = await leetCodeExecutor.getDescription(node.id, needTranslation);
    leetCodePreviewProvider.show(descString, node, isSideMode);
}

export async function pickOne(): Promise<void> {
    const problems: IProblem[] = await list.listProblems();
    const randomProblem: IProblem = problems[Math.floor(Math.random() * problems.length)];
    await showProblemInternal(randomProblem);
}

export async function showProblem(node?: LeetCodeNode): Promise<void> {
    if (!node) {
        return;
    }
    await showProblemInternal(node);
}

export async function searchProblem(): Promise<void> {
    if (!leetCodeManager.getUser()) {
        promptForSignIn();
        return;
    }
    const choice: IQuickItemEx<IProblem> | undefined = await vscode.window.showQuickPick(parseProblemsToPicks(list.listProblems()), {
        matchOnDetail: true,
        placeHolder: "Select one problem",
    });
    if (!choice) {
        return;
    }
    await showProblemInternal(choice.value);
}

export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise<void> {
    let problemInput: string | undefined;
    if (input instanceof LeetCodeNode) {
        // Triggerred from explorer
        problemInput = input.id;
    } else if (input instanceof vscode.Uri) {
        // Triggerred from Code Lens/context menu
        problemInput = `"${input.fsPath}"`;
    } else if (!input) {
        // Triggerred from command
        problemInput = await getActiveFilePath();
    }

    if (!problemInput) {
        vscode.window.showErrorMessage("Invalid input to fetch the solution data.");
        return;
    }

    const language: string | undefined = await fetchProblemLanguage();
    if (!language) {
        return;
    }
    try {
        const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
        const solution: string = await leetCodeExecutor.showSolution(problemInput, language, needTranslation);
        leetCodeSolutionProvider.show(unescapeJS(solution));
    } catch (error) {
        leetCodeChannel.appendLine(error.toString());
        await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error);
    }
}

async function fetchProblemLanguage(): Promise<string | undefined> {
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    let defaultLanguage: string | undefined = leetCodeConfig.get<string>("defaultLanguage");
    if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) {
        defaultLanguage = undefined;
    }
    const language: string | undefined =
        defaultLanguage ||
        (await vscode.window.showQuickPick(languages, {
            placeHolder: "Select the language you want to use",
            ignoreFocusOut: true,
        }));
    // fire-and-forget default language query
    (async (): Promise<void> => {
        if (language && !defaultLanguage && leetCodeConfig.get<boolean>("hint.setDefaultLanguage")) {
            const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
                `Would you like to set '${language}' as your default language?`,
                DialogOptions.yes,
                DialogOptions.no,
                DialogOptions.never
            );
            if (choice === DialogOptions.yes) {
                leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */);
            } else if (choice === DialogOptions.never) {
                leetCodeConfig.update("hint.setDefaultLanguage", false, true /* UserSetting */);
            }
        }
    })();
    return language;
}

async function showProblemInternal(node: IProblem): Promise<void> {
    try {
        const language: string | undefined = await fetchProblemLanguage();
        if (!language) {
            return;
        }

        const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
        const workspaceFolder: string = await selectWorkspaceFolder();
        if (!workspaceFolder) {
            return;
        }

        const fileFolder: string = leetCodeConfig
            .get<string>(`filePath.${language}.folder`, leetCodeConfig.get<string>(`filePath.default.folder`, ""))
            .trim();
        const fileName: string = leetCodeConfig
            .get<string>(`filePath.${language}.filename`, leetCodeConfig.get<string>(`filePath.default.filename`) || genFileName(node, language))
            .trim();

        let finalPath: string = path.join(workspaceFolder, fileFolder, fileName);

        if (finalPath) {
            finalPath = await resolveRelativePath(finalPath, node, language);
            if (!finalPath) {
                leetCodeChannel.appendLine("Showing problem canceled by user.");
                return;
            }
        }

        finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath;

        const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration();
        const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();

        await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation);
        const promises: any[] = [
            vscode.window.showTextDocument(vscode.Uri.file(finalPath), {
                preview: false,
                viewColumn: vscode.ViewColumn.One,
            }),
            promptHintMessage(
                "hint.commentDescription",
                'You can config how to show the problem description through "leetcode.showDescription".',
                "Open settings",
                (): Promise<any> => openSettingsEditor("leetcode.showDescription")
            ),
        ];
        if (descriptionConfig.showInWebview) {
            promises.push(showDescriptionView(node));
        }

        await Promise.all(promises);
    } catch (error) {
        await promptForOpenOutputChannel(`${error} Please open the output channel for details.`, DialogType.error);
    }
}

async function showDescriptionView(node: IProblem): Promise<void> {
    return previewProblem(node, vscode.workspace.getConfiguration("leetcode").get<boolean>("enableSideMode", true));
}
async function parseProblemsToPicks(p: Promise<IProblem[]>): Promise<Array<IQuickItemEx<IProblem>>> {
    return new Promise(async (resolve: (res: Array<IQuickItemEx<IProblem>>) => void): Promise<void> => {
        const picks: Array<IQuickItemEx<IProblem>> = (await p).map((problem: IProblem) =>
            Object.assign(
                {},
                {
                    label: `${parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`,
                    description: "",
                    detail: `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`,
                    value: problem,
                }
            )
        );
        resolve(picks);
    });
}

function parseProblemDecorator(state: ProblemState, locked: boolean): string {
    switch (state) {
        case ProblemState.AC:
            return "$(check) ";
        case ProblemState.NotAC:
            return "$(x) ";
        default:
            return locked ? "$(lock) " : "";
    }
}

async function resolveRelativePath(relativePath: string, node: IProblem, selectedLanguage: string): Promise<string> {
    let tag: string = "";
    if (/\$\{tag\}/i.test(relativePath)) {
        tag = (await resolveTagForProblem(node)) || "";
    }

    let company: string = "";
    if (/\$\{company\}/i.test(relativePath)) {
        company = (await resolveCompanyForProblem(node)) || "";
    }

    return relativePath.replace(/\$\{(.*?)\}/g, (_substring: string, ...args: string[]) => {
        const placeholder: string = args[0].toLowerCase().trim();
        switch (placeholder) {
            case "id":
                return node.id;
            case "name":
                return node.name;
            case "camelcasename":
                return _.camelCase(node.name);
            case "pascalcasename":
                return _.upperFirst(_.camelCase(node.name));
            case "kebabcasename":
            case "kebab-case-name":
                return _.kebabCase(node.name);
            case "snakecasename":
            case "snake_case_name":
                return _.snakeCase(node.name);
            case "ext":
                return genFileExt(selectedLanguage);
            case "language":
                return selectedLanguage;
            case "difficulty":
                return node.difficulty.toLocaleLowerCase();
            case "tag":
                return tag;
            case "company":
                return company;
            default:
                const errorMsg: string = `The config '${placeholder}' is not supported.`;
                leetCodeChannel.appendLine(errorMsg);
                throw new Error(errorMsg);
        }
    });
}

async function resolveTagForProblem(problem: IProblem): Promise<string | undefined> {
    if (problem.tags.length === 1) {
        return problem.tags[0];
    }
    return await vscode.window.showQuickPick(problem.tags, {
        matchOnDetail: true,
        placeHolder: "Multiple tags available, please select one",
        ignoreFocusOut: true,
    });
}

async function resolveCompanyForProblem(problem: IProblem): Promise<string | undefined> {
    if (problem.companies.length === 1) {
        return problem.companies[0];
    }
    return await vscode.window.showQuickPick(problem.companies, {
        matchOnDetail: true,
        placeHolder: "Multiple tags available, please select one",
        ignoreFocusOut: true,
    });
}


================================================
FILE: src/commands/star.ts
================================================

// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { customCodeLensProvider } from "../codelens/CustomCodeLensProvider";
import { LeetCodeNode } from "../explorer/LeetCodeNode";
import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { hasStarShortcut } from "../utils/settingUtils";
import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";

export async function addFavorite(node: LeetCodeNode): Promise<void> {
    try {
        await leetCodeExecutor.toggleFavorite(node, true);
        await leetCodeTreeDataProvider.refresh();
        if (hasStarShortcut()) {
            customCodeLensProvider.refresh();
        }
    } catch (error) {
        await promptForOpenOutputChannel("Failed to add the problem to favorite. Please open the output channel for details.", DialogType.error);
    }
}

export async function removeFavorite(node: LeetCodeNode): Promise<void> {
    try {
        await leetCodeExecutor.toggleFavorite(node, false);
        await leetCodeTreeDataProvider.refresh();
        if (hasStarShortcut()) {
            customCodeLensProvider.refresh();
        }
    } catch (error) {
        await promptForOpenOutputChannel("Failed to remove the problem from favorite. Please open the output channel for details.", DialogType.error);
    }
}


================================================
FILE: src/commands/submit.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
import { getActiveFilePath } from "../utils/workspaceUtils";
import { leetCodeSubmissionProvider } from "../webview/leetCodeSubmissionProvider";

export async function submitSolution(uri?: vscode.Uri): Promise<void> {
    if (!leetCodeManager.getUser()) {
        promptForSignIn();
        return;
    }

    const filePath: string | undefined = await getActiveFilePath(uri);
    if (!filePath) {
        return;
    }

    try {
        const result: string = await leetCodeExecutor.submitSolution(filePath);
        leetCodeSubmissionProvider.show(result);
    } catch (error) {
        await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error);
        return;
    }

    leetCodeTreeDataProvider.refresh();
}


================================================
FILE: src/commands/test.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as fse from "fs-extra";
import * as vscode from "vscode";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { IQuickItemEx, UserStatus } from "../shared";
import { isWindows, usingCmd } from "../utils/osUtils";
import { DialogType, promptForOpenOutputChannel, showFileSelectDialog } from "../utils/uiUtils";
import { getActiveFilePath } from "../utils/workspaceUtils";
import * as wsl from "../utils/wslUtils";
import { leetCodeSubmissionProvider } from "../webview/leetCodeSubmissionProvider";

export async function testSolution(uri?: vscode.Uri): Promise<void> {
    try {
        if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
            return;
        }

        const filePath: string | undefined = await getActiveFilePath(uri);
        if (!filePath) {
            return;
        }
        const picks: Array<IQuickItemEx<string>> = [];
        picks.push(
            {
                label: "$(three-bars) Default test cases",
                description: "",
                detail: "Test with the default cases",
                value: ":default",
            },
            {
                label: "$(pencil) Write directly...",
                description: "",
                detail: "Write test cases in input box",
                value: ":direct",
            },
            {
                label: "$(file-text) Browse...",
                description: "",
                detail: "Test with the written cases in file",
                value: ":file",
            },
        );
        const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(picks);
        if (!choice) {
            return;
        }

        let result: string | undefined;
        switch (choice.value) {
            case ":default":
                result = await leetCodeExecutor.testSolution(filePath);
                break;
            case ":direct":
                const testString: string | undefined = await vscode.window.showInputBox({
                    prompt: "Enter the test cases.",
                    validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "Test case must not be empty.",
                    placeHolder: "Example: [1,2,3]\\n4",
                    ignoreFocusOut: true,
                });
                if (testString) {
                    result = await leetCodeExecutor.testSolution(filePath, parseTestString(testString));
                }
                break;
            case ":file":
                const testFile: vscode.Uri[] | undefined = await showFileSelectDialog(filePath);
                if (testFile && testFile.length) {
                    const input: string = (await fse.readFile(testFile[0].fsPath, "utf-8")).trim();
                    if (input) {
                        result = await leetCodeExecutor.testSolution(filePath, parseTestString(input.replace(/\r?\n/g, "\\n")));
                    } else {
                        vscode.window.showErrorMessage("The selected test file must not be empty.");
                    }
                }
                break;
            default:
                break;
        }
        if (!result) {
            return;
        }
        leetCodeSubmissionProvider.show(result);
    } catch (error) {
        await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error);
    }
}

function parseTestString(test: string): string {
    if (wsl.useWsl() || !isWindows()) {
        return `'${test}'`;
    }

    // In windows and not using WSL
    if (usingCmd()) {
        return `"${test.replace(/"/g, '\\"')}"`;
    } else {
        // Assume using PowerShell
        return `'${test.replace(/"/g, '\\"')}'`;
    }
}


================================================
FILE: src/explorer/LeetCodeNode.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { Command, Uri } from "vscode";
import { IProblem, ProblemState } from "../shared";

export class LeetCodeNode {

    constructor(private data: IProblem, private isProblemNode: boolean = true) { }

    public get locked(): boolean {
        return this.data.locked;
    }
    public get name(): string {
        return this.data.name;
    }

    public get state(): ProblemState {
        return this.data.state;
    }

    public get id(): string {
        return this.data.id;
    }

    public get passRate(): string {
        return this.data.passRate;
    }

    public get difficulty(): string {
        return this.data.difficulty;
    }

    public get tags(): string[] {
        return this.data.tags;
    }

    public get companies(): string[] {
        return this.data.companies;
    }

    public get isFavorite(): boolean {
        return this.data.isFavorite;
    }

    public get isProblem(): boolean {
        return this.isProblemNode;
    }

    public get previewCommand(): Command {
        return {
            title: "Preview Problem",
            command: "leetcode.previewProblem",
            arguments: [this],
        };
    }

    public get acceptanceRate(): number {
        return Number(this.passRate.slice(0, -1).trim());
    }

    public get uri(): Uri {
        return Uri.from({
            scheme: "leetcode",
            authority: this.isProblem ? "problems" : "tree-node",
            path: `/${this.id}`, // path must begin with slash /
            query: `difficulty=${this.difficulty}`,
        });
    }

}


================================================
FILE: src/explorer/LeetCodeTreeDataProvider.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { leetCodeManager } from "../leetCodeManager";
import { Category, defaultProblem, ProblemState } from "../shared";
import { explorerNodeManager } from "./explorerNodeManager";
import { LeetCodeNode } from "./LeetCodeNode";
import { globalState } from "../globalState";

export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCodeNode> {
    private context: vscode.ExtensionContext;

    private onDidChangeTreeDataEvent: vscode.EventEmitter<LeetCodeNode | undefined | null> = new vscode.EventEmitter<
        LeetCodeNode | undefined | null
    >();
    // tslint:disable-next-line:member-ordering
    public readonly onDidChangeTreeData: vscode.Event<any> = this.onDidChangeTreeDataEvent.event;

    public initialize(context: vscode.ExtensionContext): void {
        this.context = context;
    }

    public async refresh(): Promise<void> {
        await explorerNodeManager.refreshCache();
        this.onDidChangeTreeDataEvent.fire(null);
    }

    public getTreeItem(element: LeetCodeNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
        if (element.id === "notSignIn") {
            return {
                label: element.name,
                collapsibleState: vscode.TreeItemCollapsibleState.None,
                command: {
                    command: "leetcode.signin",
                    title: "Sign in to LeetCode",
                },
            };
        }

        let contextValue: string;
        if (element.isProblem) {
            contextValue = element.isFavorite ? "problem-favorite" : "problem";
        } else {
            contextValue = element.id.toLowerCase();
        }

        return {
            label: element.isProblem ? `[${element.id}] ${element.name}` + this.parsePremiumUnLockIconPath(element) : element.name,
            tooltip: this.getSubCategoryTooltip(element),
            collapsibleState: element.isProblem ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
            iconPath: this.parseIconPathFromProblemState(element),
            command: element.isProblem ? element.previewCommand : undefined,
            resourceUri: element.uri,
            contextValue,
        };
    }

    public getChildren(element?: LeetCodeNode | undefined): vscode.ProviderResult<LeetCodeNode[]> {
        if (!leetCodeManager.getUser()) {
            return [
                new LeetCodeNode(
                    Object.assign({}, defaultProblem, {
                        id: "notSignIn",
                        name: "Sign in to LeetCode",
                    }),
                    false
                ),
            ];
        }
        if (!element) {
            // Root view
            return explorerNodeManager.getRootNodes();
        } else {
            switch (element.id) {
                case Category.All:
                    return explorerNodeManager.getAllNodes();
                case Category.Favorite:
                    return explorerNodeManager.getFavoriteNodes();
                case Category.Difficulty:
                    return explorerNodeManager.getAllDifficultyNodes();
                case Category.Tag:
                    return explorerNodeManager.getAllTagNodes();
                case Category.Company:
                    return explorerNodeManager.getAllCompanyNodes();
                default:
                    if (element.isProblem) {
                        return [];
                    }
                    return explorerNodeManager.getChildrenNodesById(element.id);
            }
        }
    }

    private parseIconPathFromProblemState(element: LeetCodeNode): string {
        if (!element.isProblem) {
            return "";
        }
        const { isPremium } = globalState.getUserStatus() ?? {};
        switch (element.state) {
            case ProblemState.AC:
                return this.context.asAbsolutePath(path.join("resources", "check.png"));
            case ProblemState.NotAC:
                return this.context.asAbsolutePath(path.join("resources", "x.png"));
            case ProblemState.Unknown:
                if (element.locked && !isPremium) {
                    return this.context.asAbsolutePath(path.join("resources", "lock.png"));
                }
                return this.context.asAbsolutePath(path.join("resources", "blank.png"));
            default:
                return "";
        }
    }

    private parsePremiumUnLockIconPath(element: LeetCodeNode): string {
        const { isPremium } = globalState.getUserStatus() ?? {};
        if (isPremium && element.locked) {
            return "  🔓";
        }
        return "";
    }

    private getSubCategoryTooltip(element: LeetCodeNode): string {
        // return '' unless it is a sub-category node
        if (element.isProblem || element.id === "ROOT" || element.id in Category) {
            return "";
        }

        const childernNodes: LeetCodeNode[] = explorerNodeManager.getChildrenNodesById(element.id);

        let acceptedNum: number = 0;
        let failedNum: number = 0;
        for (const node of childernNodes) {
            switch (node.state) {
                case ProblemState.AC:
                    acceptedNum++;
                    break;
                case ProblemState.NotAC:
                    failedNum++;
                    break;
                default:
                    break;
            }
        }

        return [`AC: ${acceptedNum}`, `Failed: ${failedNum}`, `Total: ${childernNodes.length}`].join(os.EOL);
    }
}

export const leetCodeTreeDataProvider: LeetCodeTreeDataProvider = new LeetCodeTreeDataProvider();


================================================
FILE: src/explorer/LeetCodeTreeItemDecorationProvider.ts
================================================
import { URLSearchParams } from "url";
import { FileDecoration, FileDecorationProvider, ProviderResult, ThemeColor, Uri, workspace, WorkspaceConfiguration } from "vscode";

export class LeetCodeTreeItemDecorationProvider implements FileDecorationProvider {
    private readonly DIFFICULTY_BADGE_LABEL: { [key: string]: string } = {
        easy: "E",
        medium: "M",
        hard: "H",
    };

    private readonly ITEM_COLOR: { [key: string]: ThemeColor } = {
        easy: new ThemeColor("charts.green"),
        medium: new ThemeColor("charts.yellow"),
        hard: new ThemeColor("charts.red"),
    };

    public provideFileDecoration(uri: Uri): ProviderResult<FileDecoration>  {
        if (!this.isDifficultyBadgeEnabled()) {
            return;
        }

        if (uri.scheme !== "leetcode" && uri.authority !== "problems") {
            return;
        }

        const params: URLSearchParams = new URLSearchParams(uri.query);
        const difficulty: string = params.get("difficulty")!.toLowerCase();
        return {
            badge: this.DIFFICULTY_BADGE_LABEL[difficulty],
            color: this.ITEM_COLOR[difficulty],
        };
    }

    private isDifficultyBadgeEnabled(): boolean {
        const configuration: WorkspaceConfiguration = workspace.getConfiguration();
        return configuration.get<boolean>("leetcode.colorizeProblems", false);
    }
}

export const leetCodeTreeItemDecorationProvider: LeetCodeTreeItemDecorationProvider = new LeetCodeTreeItemDecorationProvider();


================================================
FILE: src/explorer/explorerNodeManager.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as _ from "lodash";
import { Disposable } from "vscode";
import * as list from "../commands/list";
import { getSortingStrategy } from "../commands/plugin";
import { Category, defaultProblem, ProblemState, SortingStrategy } from "../shared";
import { shouldHideSolvedProblem } from "../utils/settingUtils";
import { LeetCodeNode } from "./LeetCodeNode";

class ExplorerNodeManager implements Disposable {
    private explorerNodeMap: Map<string, LeetCodeNode> = new Map<string, LeetCodeNode>();
    private companySet: Set<string> = new Set<string>();
    private tagSet: Set<string> = new Set<string>();

    public async refreshCache(): Promise<void> {
        this.dispose();
        const shouldHideSolved: boolean = shouldHideSolvedProblem();
        for (const problem of await list.listProblems()) {
            if (shouldHideSolved && problem.state === ProblemState.AC) {
                continue;
            }
            this.explorerNodeMap.set(problem.id, new LeetCodeNode(problem));
            for (const company of problem.companies) {
                this.companySet.add(company);
            }
            for (const tag of problem.tags) {
                this.tagSet.add(tag);
            }
        }
    }

    public getRootNodes(): LeetCodeNode[] {
        return [
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: Category.All,
                name: Category.All,
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: Category.Difficulty,
                name: Category.Difficulty,
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: Category.Tag,
                name: Category.Tag,
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: Category.Company,
                name: Category.Company,
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: Category.Favorite,
                name: Category.Favorite,
            }), false),
        ];
    }

    public getAllNodes(): LeetCodeNode[] {
        return this.applySortingStrategy(
            Array.from(this.explorerNodeMap.values()),
        );
    }

    public getAllDifficultyNodes(): LeetCodeNode[] {
        const res: LeetCodeNode[] = [];
        res.push(
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: `${Category.Difficulty}.Easy`,
                name: "Easy",
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: `${Category.Difficulty}.Medium`,
                name: "Medium",
            }), false),
            new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: `${Category.Difficulty}.Hard`,
                name: "Hard",
            }), false),
        );
        this.sortSubCategoryNodes(res, Category.Difficulty);
        return res;
    }

    public getAllCompanyNodes(): LeetCodeNode[] {
        const res: LeetCodeNode[] = [];
        for (const company of this.companySet.values()) {
            res.push(new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: `${Category.Company}.${company}`,
                name: _.startCase(company),
            }), false));
        }
        this.sortSubCategoryNodes(res, Category.Company);
        return res;
    }

    public getAllTagNodes(): LeetCodeNode[] {
        const res: LeetCodeNode[] = [];
        for (const tag of this.tagSet.values()) {
            res.push(new LeetCodeNode(Object.assign({}, defaultProblem, {
                id: `${Category.Tag}.${tag}`,
                name: _.startCase(tag),
            }), false));
        }
        this.sortSubCategoryNodes(res, Category.Tag);
        return res;
    }

    public getNodeById(id: string): LeetCodeNode | undefined {
        return this.explorerNodeMap.get(id);
    }

    public getFavoriteNodes(): LeetCodeNode[] {
        const res: LeetCodeNode[] = [];
        for (const node of this.explorerNodeMap.values()) {
            if (node.isFavorite) {
                res.push(node);
            }
        }
        return this.applySortingStrategy(res);
    }

    public getChildrenNodesById(id: string): LeetCodeNode[] {
        // The sub-category node's id is named as {Category.SubName}
        const metaInfo: string[] = id.split(".");
        const res: LeetCodeNode[] = [];
        for (const node of this.explorerNodeMap.values()) {
            switch (metaInfo[0]) {
                case Category.Company:
                    if (node.companies.indexOf(metaInfo[1]) >= 0) {
                        res.push(node);
                    }
                    break;
                case Category.Difficulty:
                    if (node.difficulty === metaInfo[1]) {
                        res.push(node);
                    }
                    break;
                case Category.Tag:
                    if (node.tags.indexOf(metaInfo[1]) >= 0) {
                        res.push(node);
                    }
                    break;
                default:
                    break;
            }
        }
        return this.applySortingStrategy(res);
    }

    public dispose(): void {
        this.explorerNodeMap.clear();
        this.companySet.clear();
        this.tagSet.clear();
    }

    private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void {
        switch (category) {
            case Category.Difficulty:
                subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
                    function getValue(input: LeetCodeNode): number {
                        switch (input.name.toLowerCase()) {
                            case "easy":
                                return 1;
                            case "medium":
                                return 2;
                            case "hard":
                                return 3;
                            default:
                                return Number.MAX_SAFE_INTEGER;
                        }
                    }
                    return getValue(a) - getValue(b);
                });
                break;
            case Category.Tag:
            case Category.Company:
                subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
                    if (a.name === "Unknown") {
                        return 1;
                    } else if (b.name === "Unknown") {
                        return -1;
                    } else {
                        return Number(a.name > b.name) - Number(a.name < b.name);
                    }
                });
                break;
            default:
                break;
        }
    }

    private applySortingStrategy(nodes: LeetCodeNode[]): LeetCodeNode[] {
        const strategy: SortingStrategy = getSortingStrategy();
        switch (strategy) {
            case SortingStrategy.AcceptanceRateAsc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(x.acceptanceRate) - Number(y.acceptanceRate));
            case SortingStrategy.AcceptanceRateDesc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(y.acceptanceRate) - Number(x.acceptanceRate));
            default: return nodes;
        }
    }
}

export const explorerNodeManager: ExplorerNodeManager = new ExplorerNodeManager();


================================================
FILE: src/extension.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { codeLensController } from "./codelens/CodeLensController";
import * as cache from "./commands/cache";
import { switchDefaultLanguage } from "./commands/language";
import * as plugin from "./commands/plugin";
import * as session from "./commands/session";
import * as show from "./commands/show";
import * as star from "./commands/star";
import * as submit from "./commands/submit";
import * as test from "./commands/test";
import { explorerNodeManager } from "./explorer/explorerNodeManager";
import { LeetCodeNode } from "./explorer/LeetCodeNode";
import { leetCodeTreeDataProvider } from "./explorer/LeetCodeTreeDataProvider";
import { leetCodeTreeItemDecorationProvider } from "./explorer/LeetCodeTreeItemDecorationProvider";
import { leetCodeChannel } from "./leetCodeChannel";
import { leetCodeExecutor } from "./leetCodeExecutor";
import { leetCodeManager } from "./leetCodeManager";
import { leetCodeStatusBarController } from "./statusbar/leetCodeStatusBarController";
import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils";
import { leetCodePreviewProvider } from "./webview/leetCodePreviewProvider";
import { leetCodeSolutionProvider } from "./webview/leetCodeSolutionProvider";
import { leetCodeSubmissionProvider } from "./webview/leetCodeSubmissionProvider";
import { markdownEngine } from "./webview/markdownEngine";
import TrackData from "./utils/trackingUtils";
import { globalState } from "./globalState";

export async function activate(context: vscode.ExtensionContext): Promise<void> {
    try {
        if (!(await leetCodeExecutor.meetRequirements(context))) {
            throw new Error("The environment doesn't meet requirements.");
        }

        leetCodeManager.on("statusChanged", () => {
            leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser());
            leetCodeTreeDataProvider.refresh();
        });

        leetCodeTreeDataProvider.initialize(context);
        globalState.initialize(context);

        context.subscriptions.push(
            leetCodeStatusBarController,
            leetCodeChannel,
            leetCodePreviewProvider,
            leetCodeSubmissionProvider,
            leetCodeSolutionProvider,
            leetCodeExecutor,
            markdownEngine,
            codeLensController,
            explorerNodeManager,
            vscode.window.registerFileDecorationProvider(leetCodeTreeItemDecorationProvider),
            vscode.window.createTreeView("leetCodeExplorer", { treeDataProvider: leetCodeTreeDataProvider, showCollapseAll: true }),
            vscode.commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()),
            vscode.commands.registerCommand("leetcode.toggleLeetCodeCn", () => plugin.switchEndpoint()),
            vscode.commands.registerCommand("leetcode.signin", () => leetCodeManager.signIn()),
            vscode.commands.registerCommand("leetcode.signout", () => leetCodeManager.signOut()),
            vscode.commands.registerCommand("leetcode.manageSessions", () => session.manageSessions()),
            vscode.commands.registerCommand("leetcode.previewProblem", (node: LeetCodeNode) => {
                TrackData.report({
                    event_key: `vscode_open_problem`,
                    type: "click",
                    extra: JSON.stringify({
                        problem_id: node.id,
                        problem_name: node.name,
                    }),
                });
                show.previewProblem(node);
            }),
            vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(node)),
            vscode.commands.registerCommand("leetcode.pickOne", () => show.pickOne()),
            vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()),
            vscode.commands.registerCommand("leetcode.showSolution", (input: LeetCodeNode | vscode.Uri) => show.showSolution(input)),
            vscode.commands.registerCommand("leetcode.refreshExplorer", () => leetCodeTreeDataProvider.refresh()),
            vscode.commands.registerCommand("leetcode.testSolution", (uri?: vscode.Uri) => {
                TrackData.report({
                    event_key: `vscode_runCode`,
                    type: "click",
                    extra: JSON.stringify({
                        path: uri?.path,
                    }),
                });
                return test.testSolution(uri);
            }),
            vscode.commands.registerCommand("leetcode.submitSolution", (uri?: vscode.Uri) => {
                TrackData.report({
                    event_key: `vscode_submit`,
                    type: "click",
                    extra: JSON.stringify({
                        path: uri?.path,
                    }),
                });
                return submit.submitSolution(uri);
            }),
            vscode.commands.registerCommand("leetcode.switchDefaultLanguage", () => switchDefaultLanguage()),
            vscode.commands.registerCommand("leetcode.addFavorite", (node: LeetCodeNode) => star.addFavorite(node)),
            vscode.commands.registerCommand("leetcode.removeFavorite", (node: LeetCodeNode) => star.removeFavorite(node)),
            vscode.commands.registerCommand("leetcode.problems.sort", () => plugin.switchSortingStrategy())
        );

        await leetCodeExecutor.switchEndpoint(plugin.getLeetCodeEndpoint());
        await leetCodeManager.getLoginStatus();
        vscode.window.registerUriHandler({ handleUri: leetCodeManager.handleUriSignIn });
    } catch (error) {
        leetCodeChannel.appendLine(error.toString());
        promptForOpenOutputChannel("Extension initialization failed. Please open output channel for details.", DialogType.error);
    }
}

export function deactivate(): void {
    // Do nothing.
}


================================================
FILE: src/globalState.ts
================================================
// Copyright (c) leo.zhao. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";

const CookieKey = "leetcode-cookie";
const UserStatusKey = "leetcode-user-status";

export type UserDataType = {
    isSignedIn: boolean;
    isPremium: boolean;
    username: string;
    avatar: string;
    isVerified?: boolean;
};

class GlobalState {
    private context: vscode.ExtensionContext;
    private _state: vscode.Memento;
    private _cookie: string;
    private _userStatus: UserDataType;

    public initialize(context: vscode.ExtensionContext): void {
        this.context = context;
        this._state = this.context.globalState;
    }

    public setCookie(cookie: string): any {
        this._cookie = cookie;
        return this._state.update(CookieKey, this._cookie);
    }
    public getCookie(): string | undefined {
        return this._cookie ?? this._state.get(CookieKey);
    }

    public setUserStatus(userStatus: UserDataType): any {
        this._userStatus = userStatus;
        return this._state.update(UserStatusKey, this._userStatus);
    }

    public getUserStatus(): UserDataType | undefined {
        return this._userStatus ?? this._state.get(UserStatusKey);
    }

    public removeCookie(): void {
        this._state.update(CookieKey, undefined);
    }

    public removeAll(): void {
        this._state.update(CookieKey, undefined);
        this._state.update(UserStatusKey, undefined);
    }
}

export const globalState: GlobalState = new GlobalState();


================================================
FILE: src/leetCodeChannel.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";

class LeetCodeChannel implements vscode.Disposable {
    private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("LeetCode");

    public appendLine(message: string): void {
        this.channel.appendLine(message);
    }

    public append(message: string): void {
        this.channel.append(message);
    }

    public show(): void {
        this.channel.show();
    }

    public dispose(): void {
        this.channel.dispose();
    }
}

export const leetCodeChannel: LeetCodeChannel = new LeetCodeChannel();


================================================
FILE: src/leetCodeExecutor.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as cp from "child_process";
import * as fse from "fs-extra";
import * as os from "os";
import * as path from "path";
import * as requireFromString from "require-from-string";
import { ExtensionContext } from "vscode";
import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace, WorkspaceConfiguration } from "vscode";
import { Endpoint, IProblem, leetcodeHasInited, supportedPlugins } from "./shared";
import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils";
import { DialogOptions, openUrl } from "./utils/uiUtils";
import * as wsl from "./utils/wslUtils";
import { toWslPath, useWsl } from "./utils/wslUtils";

class LeetCodeExecutor implements Disposable {
    private leetCodeRootPath: string;
    private nodeExecutable: string;
    private configurationChangeListener: Disposable;

    constructor() {
        this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "vsc-leetcode-cli");
        this.nodeExecutable = this.getNodePath();
        this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
            if (event.affectsConfiguration("leetcode.nodePath")) {
                this.nodeExecutable = this.getNodePath();
            }
        }, this);
    }

    public async getLeetCodeBinaryPath(): Promise<string> {
        if (wsl.useWsl()) {
            return `${await wsl.toWslPath(`"${path.join(this.leetCodeRootPath, "bin", "leetcode")}"`)}`;
        }
        return `"${path.join(this.leetCodeRootPath, "bin", "leetcode")}"`;
    }

    public async meetRequirements(context: ExtensionContext): Promise<boolean> {
        const hasInited: boolean | undefined = context.globalState.get(leetcodeHasInited);
        if (!hasInited) {
            await this.removeOldCache();
        }
        if (this.nodeExecutable !== "node") {
            if (!await fse.pathExists(this.nodeExecutable)) {
                throw new Error(`The Node.js executable does not exist on path ${this.nodeExecutable}`);
            }
            // Wrap the executable with "" to avoid space issue in the path.
            this.nodeExecutable = `"${this.nodeExecutable}"`;
            if (useWsl()) {
                this.nodeExecutable = await toWslPath(this.nodeExecutable);
            }
        }
        try {
            await this.executeCommandEx(this.nodeExecutable, ["-v"]);
        } catch (error) {
            const choice: MessageItem | undefined = await window.showErrorMessage(
                "LeetCode extension needs Node.js installed in environment path",
                DialogOptions.open,
            );
            if (choice === DialogOptions.open) {
                openUrl("https://nodejs.org");
            }
            return false;
        }
        for (const plugin of supportedPlugins) {
            try { // Check plugin
                await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-e", plugin]);
            } catch (error) { // Remove old cache that may cause the error download plugin and activate
                await this.removeOldCache();
                await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-i", plugin]);
            }
        }
        // Set the global state HasInited true to skip delete old cache after init
        context.globalState.update(leetcodeHasInited, true);
        return true;
    }

    public async deleteCache(): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "cache", "-d"]);
    }

    public async getUserInfo(): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "user"]);
    }

    public async signOut(): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "user", "-L"]);
    }

    public async listProblems(showLocked: boolean, needTranslation: boolean): Promise<string> {
        const cmd: string[] = [await this.getLeetCodeBinaryPath(), "list"];
        if (!needTranslation) {
            cmd.push("-T"); // use -T to prevent translation
        }
        if (!showLocked) {
            cmd.push("-q");
            cmd.push("L");
        }
        return await this.executeCommandEx(this.nodeExecutable, cmd);
    }

    public async showProblem(problemNode: IProblem, language: string, filePath: string, showDescriptionInComment: boolean = false, needTranslation: boolean): Promise<void> {
        const templateType: string = showDescriptionInComment ? "-cx" : "-c";
        const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", problemNode.id, templateType, "-l", language];

        if (!needTranslation) {
            cmd.push("-T"); // use -T to force English version
        }

        if (!await fse.pathExists(filePath)) {
            await fse.createFile(filePath);
            const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, cmd);
            await fse.writeFile(filePath, codeTemplate);
        }
    }

    /**
     * This function returns solution of a problem identified by input
     *
     * @remarks
     * Even though this function takes the needTranslation flag, it is important to note
     * that as of vsc-leetcode-cli 2.8.0, leetcode-cli doesn't support querying solution
     * on CN endpoint yet. So this flag doesn't have any effect right now.
     *
     * @param input - parameter to pass to cli that can identify a problem
     * @param language - the source code language of the solution desired
     * @param needTranslation - whether or not to use endPoint translation on solution query
     * @returns promise of the solution string
     */
    public async showSolution(input: string, language: string, needTranslation: boolean): Promise<string> {
        // solution don't support translation
        const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", input, "--solution", "-l", language];
        if (!needTranslation) {
            cmd.push("-T");
        }
        const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", this.nodeExecutable, cmd);
        return solution;
    }

    public async getDescription(problemNodeId: string, needTranslation: boolean): Promise<string> {
        const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", problemNodeId, "-x"];
        if (!needTranslation) {
            cmd.push("-T");
        }
        return await this.executeCommandWithProgressEx("Fetching problem description...", this.nodeExecutable, cmd);
    }

    public async listSessions(): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session"]);
    }

    public async enableSession(name: string): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-e", name]);
    }

    public async createSession(id: string): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-c", id]);
    }

    public async deleteSession(id: string): Promise<string> {
        return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-d", id]);
    }

    public async submitSolution(filePath: string): Promise<string> {
        try {
            return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]);
        } catch (error) {
            if (error.result) {
                return error.result;
            }
            throw error;
        }
    }

    public async testSolution(filePath: string, testString?: string): Promise<string> {
        if (testString) {
            return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `${testString}`]);
        }
        return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]);
    }

    public async switchEndpoint(endpoint: string): Promise<string> {
        switch (endpoint) {
            case Endpoint.LeetCodeCN:
                return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]);
            case Endpoint.LeetCode:
            default:
                return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]);
        }
    }

    public async toggleFavorite(node: IProblem, addToFavorite: boolean): Promise<void> {
        const commandParams: string[] = [await this.getLeetCodeBinaryPath(), "star", node.id];
        if (!addToFavorite) {
            commandParams.push("-d");
        }
        await this.executeCommandWithProgressEx("Updating the favorite list...", "node", commandParams);
    }

    public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }, tags: { [key: string]: string[] } }> {
        // preprocess the plugin source
        const companiesTagsPath: string = path.join(this.leetCodeRootPath, "lib", "plugins", "company.js");
        const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace(
            "module.exports = plugin",
            "module.exports = { COMPONIES, TAGS }",
        );
        const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath);
        return { companies: COMPONIES, tags: TAGS };
    }

    public get node(): string {
        return this.nodeExecutable;
    }

    public dispose(): void {
        this.configurationChangeListener.dispose();
    }

    private getNodePath(): string {
        const extensionConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode", null);
        return extensionConfig.get<string>("nodePath", "node" /* default value */);
    }

    private async executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
        if (wsl.useWsl()) {
            return await executeCommand("wsl", [command].concat(args), options);
        }
        return await executeCommand(command, args, options);
    }

    private async executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
        if (wsl.useWsl()) {
            return await executeCommandWithProgress(message, "wsl", [command].concat(args), options);
        }
        return await executeCommandWithProgress(message, command, args, options);
    }

    private async removeOldCache(): Promise<void> {
        const oldPath: string = path.join(os.homedir(), ".lc");
        if (await fse.pathExists(oldPath)) {
            await fse.remove(oldPath);
        }
    }

}

export const leetCodeExecutor: LeetCodeExecutor = new LeetCodeExecutor();


================================================
FILE: src/leetCodeManager.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as cp from "child_process";
import { EventEmitter } from "events";
import * as vscode from "vscode";
import { leetCodeChannel } from "./leetCodeChannel";
import { leetCodeExecutor } from "./leetCodeExecutor";
import { Endpoint, IQuickItemEx, loginArgsMapping, urls, urlsCn, UserStatus } from "./shared";
import { createEnvOption } from "./utils/cpUtils";
import { DialogType, openUrl, promptForOpenOutputChannel } from "./utils/uiUtils";
import * as wsl from "./utils/wslUtils";
import { getLeetCodeEndpoint } from "./commands/plugin";
import { globalState } from "./globalState";
import { queryUserData } from "./request/query-user-data";
import { parseQuery } from "./utils/toolUtils";

class LeetCodeManager extends EventEmitter {
    private currentUser: string | undefined;
    private userStatus: UserStatus;
    private readonly successRegex: RegExp = /(?:.*)Successfully .*login as (.*)/i;
    private readonly failRegex: RegExp = /.*\[ERROR\].*/i;

    constructor() {
        super();
        this.currentUser = undefined;
        this.userStatus = UserStatus.SignedOut;
        this.handleUriSignIn = this.handleUriSignIn.bind(this);
    }

    public async getLoginStatus(): Promise<void> {
        try {
            const result: string = await leetCodeExecutor.getUserInfo();
            this.currentUser = this.tryParseUserName(result);
            this.userStatus = UserStatus.SignedIn;
        } catch (error) {
            this.currentUser = undefined;
            this.userStatus = UserStatus.SignedOut;
            globalState.removeAll();
        } finally {
            this.emit("statusChanged");
        }
    }

    private async updateUserStatusWithCookie(cookie: string): Promise<void> {
        globalState.setCookie(cookie);
        const data = await queryUserData();
        globalState.setUserStatus(data);
        await this.setCookieToCli(cookie, data.username);
        if (data.username) {
            vscode.window.showInformationMessage(`Successfully ${data.username}.`);
            this.currentUser = data.username;
            this.userStatus = UserStatus.SignedIn;
            this.emit("statusChanged");
        }
    }

    public async handleUriSignIn(uri: vscode.Uri): Promise<void> {
        try {
            await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>) => {
                progress.report({ message: "Fetching user data..." });
                const queryParams = parseQuery(uri.query);
                const cookie = queryParams["cookie"];
                if (!cookie) {
                    promptForOpenOutputChannel(`Failed to get cookie. Please log in again`, DialogType.error);
                    return;
                }

                await this.updateUserStatusWithCookie(cookie)

            });
        } catch (error) {
            promptForOpenOutputChannel(`Failed to log in. Please open the output channel for details`, DialogType.error);
        }
    }

    public async handleInputCookieSignIn(): Promise<void> {
        const cookie: string | undefined = await vscode.window.showInputBox({
            prompt: 'Enter LeetCode Cookie',
            password: true,
            ignoreFocusOut: true,
            validateInput: (s: string): string | undefined =>
                s ? undefined : 'Cookie must not be empty',
        })

        await this.updateUserStatusWithCookie(cookie || '')
    }

    public async signIn(): Promise<void> {
        const picks: Array<IQuickItemEx<string>> = []
        picks.push(
            {
                label: 'Web Authorization',
                detail: 'Open browser to authorize login on the website',
                value: 'WebAuth',
                description: '[Recommended]'
            },
            {
                label: 'LeetCode Cookie',
                detail: 'Use LeetCode cookie copied from browser to login',
                value: 'Cookie',
            }
        )

        const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(picks)
        if (!choice) {
            return
        }
        const loginMethod: string = choice.value

        if (loginMethod === 'WebAuth') {
            openUrl(this.getAuthLoginUrl())
            return
        }

        try {
            await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: "Fetching user data..." }, async () => {
                await this.handleInputCookieSignIn()
            });
        } catch (error) {
            promptForOpenOutputChannel(`Failed to log in. Please open the output channel for details`, DialogType.error);
        }
    }

    public async signOut(): Promise<void> {
        try {
            await leetCodeExecutor.signOut();
            vscode.window.showInformationMessage("Successfully signed out.");
            this.currentUser = undefined;
            this.userStatus = UserStatus.SignedOut;
            globalState.removeAll();
            this.emit("statusChanged");
        } catch (error) {
            // swallow the error when sign out.
        }
    }

    public getStatus(): UserStatus {
        return this.userStatus;
    }

    public getUser(): string | undefined {
        return this.currentUser;
    }

    private tryParseUserName(output: string): string {
        const reg: RegExp = /^\s*.\s*(.+?)\s*https:\/\/leetcode/m;
        const match: RegExpMatchArray | null = output.match(reg);
        if (match && match.length === 2) {
            return match[1].trim();
        }

        return "Unknown";
    }

    public getAuthLoginUrl(): string {
        switch (getLeetCodeEndpoint()) {
            case Endpoint.LeetCodeCN:
                return urlsCn.authLoginUrl;
            case Endpoint.LeetCode:
            default:
                return urls.authLoginUrl;
        }
    }

    public setCookieToCli(cookie: string, name: string): Promise<void> {
        return new Promise(async (resolve: (res: void) => void, reject: (e: Error) => void) => {
            const leetCodeBinaryPath: string = await leetCodeExecutor.getLeetCodeBinaryPath();

            const childProc: cp.ChildProcess = wsl.useWsl()
                ? cp.spawn("wsl", [leetCodeExecutor.node, leetCodeBinaryPath, "user", loginArgsMapping.get("Cookie") ?? ""], {
                      shell: true,
                  })
                : cp.spawn(leetCodeExecutor.node, [leetCodeBinaryPath, "user", loginArgsMapping.get("Cookie") ?? ""], {
                      shell: true,
                      env: createEnvOption(),
                  });

            childProc.stdout?.on("data", async (data: string | Buffer) => {
                data = data.toString();
                leetCodeChannel.append(data);
                const successMatch: RegExpMatchArray | null = data.match(this.successRegex);
                if (successMatch && successMatch[1]) {
                    childProc.stdin?.end();
                    return resolve();
                } else if (data.match(this.failRegex)) {
                    childProc.stdin?.end();
                    return reject(new Error("Faile to login"));
                } else if (data.match(/login: /)) {
                    childProc.stdin?.write(`${name}\n`);
                } else if (data.match(/cookie: /)) {
                    childProc.stdin?.write(`${cookie}\n`);
                }
            });

            childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString()));

            childProc.on("error", reject);
        });
    }
}

export const leetCodeManager: LeetCodeManager = new LeetCodeManager();


================================================
FILE: src/request/query-user-data.ts
================================================
import { UserDataType } from "../globalState";
import { getUrl } from "../shared";
import { LcAxios } from "../utils/httpUtils";

const graphqlStr = `
    query globalData {
        userStatus {
            isPremium
            isVerified
            username
            avatar
            isSignedIn
        }
    }
`;

export const queryUserData = async (): Promise<UserDataType> => {
    return LcAxios(getUrl("userGraphql"), {
        method: "POST",
        data: {
            query: graphqlStr,
            variables: {},
        },
    }).then((res) => res.data.data.userStatus);
};


================================================
FILE: src/shared.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";

export interface IQuickItemEx<T> extends vscode.QuickPickItem {
    value: T;
}

export enum UserStatus {
    SignedIn = 1,
    SignedOut = 2,
}

export const loginArgsMapping: Map<string, string> = new Map([
    ["LeetCode", "-l"],
    ["Cookie", "-c"],
    ["GitHub", "-g"],
    ["LinkedIn", "-i"],
]);

export const languages: string[] = [
    "bash",
    "c",
    "cpp",
    "csharp",
    "golang",
    "java",
    "javascript",
    "kotlin",
    "mysql",
    "php",
    "python",
    "python3",
    "ruby",
    "rust",
    "scala",
    "swift",
    "typescript",
];

export const langExt: Map<string, string> = new Map([
    ["bash", "sh"],
    ["c", "c"],
    ["cpp", "cpp"],
    ["csharp", "cs"],
    ["golang", "go"],
    ["java", "java"],
    ["javascript", "js"],
    ["kotlin", "kt"],
    ["mysql", "sql"],
    ["php", "php"],
    ["python", "py"],
    ["python3", "py"],
    ["ruby", "rb"],
    ["rust", "rs"],
    ["scala", "scala"],
    ["swift", "swift"],
    ["typescript", "ts"],
]);

export enum ProblemState {
    AC = 1,
    NotAC = 2,
    Unknown = 3,
    Locked = 4,
}

export enum Endpoint {
    LeetCode = "leetcode",
    LeetCodeCN = "leetcode-cn",
}

export interface IProblem {
    isFavorite: boolean;
    locked: boolean;
    state: ProblemState;
    id: string;
    name: string;
    difficulty: string;
    passRate: string;
    companies: string[];
    tags: string[];
}

export const defaultProblem: IProblem = {
    isFavorite: false,
    locked: false,
    state: ProblemState.Unknown,
    id: "",
    name: "",
    difficulty: "",
    passRate: "",
    companies: [] as string[],
    tags: [] as string[],
};

export enum Category {
    All = "All",
    Difficulty = "Difficulty",
    Tag = "Tag",
    Company = "Company",
    Favorite = "Favorite",
}

export const supportedPlugins: string[] = ["company", "solution.discuss", "leetcode.cn"];

export enum DescriptionConfiguration {
    InWebView = "In Webview",
    InFileComment = "In File Comment",
    Both = "Both",
    None = "None",
}

export const leetcodeHasInited: string = "leetcode.hasInited";

export enum SortingStrategy {
    None = "None",
    AcceptanceRateAsc = "Acceptance Rate (Ascending)",
    AcceptanceRateDesc = "Acceptance Rate (Descending)",
    FrequencyAsc = "Frequency (Ascending)",
    FrequencyDesc = "Frequency (Descending)",
}

export const PREMIUM_URL_CN = "https://leetcode.cn/premium-payment/?source=vscode";
export const PREMIUM_URL_GLOBAL = "https://leetcode.com/subscribe/?ref=lp_pl&source=vscode";

const protocol = vscode.env.appName.includes('Insiders') ? "vscode-insiders" : "vscode"

export const urls = {
    // base urls
    base: "https://leetcode.com",
    graphql: "https://leetcode.com/graphql",
    userGraphql: "https://leetcode.com/graphql",
    login: "https://leetcode.com/accounts/login/",
    authLoginUrl: `https://leetcode.com/authorize-login/${protocol}/?path=leetcode.vscode-leetcode`,
};

export const urlsCn = {
    // base urls
    base: "https://leetcode.cn",
    graphql: "https://leetcode.cn/graphql",
    userGraphql: "https://leetcode.cn/graphql/",
    login: "https://leetcode.cn/accounts/login/",
    authLoginUrl: `https://leetcode.cn/authorize-login/${protocol}/?path=leetcode.vscode-leetcode`,
};

export const getUrl = (key: string) => {
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    const point = leetCodeConfig.get<string>("endpoint", Endpoint.LeetCode);
    switch (point) {
        case Endpoint.LeetCodeCN:
            return urlsCn[key];
        case Endpoint.LeetCode:
        default:
            return urls[key];
    }
};


================================================
FILE: src/statusbar/LeetCodeStatusBarItem.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { UserStatus } from "../shared";

export class LeetCodeStatusBarItem implements vscode.Disposable {
    private readonly statusBarItem: vscode.StatusBarItem;

    constructor() {
        this.statusBarItem = vscode.window.createStatusBarItem();
        this.statusBarItem.command = "leetcode.manageSessions";
    }

    public updateStatusBar(status: UserStatus, user?: string): void {
        switch (status) {
            case UserStatus.SignedIn:
                this.statusBarItem.text = `LeetCode: ${user}`;
                break;
            case UserStatus.SignedOut:
            default:
                this.statusBarItem.text = "";
                break;
        }
    }

    public show(): void {
        this.statusBarItem.show();
    }

    public hide(): void {
        this.statusBarItem.hide();
    }

    public dispose(): void {
        this.statusBarItem.dispose();
    }
}


================================================
FILE: src/statusbar/leetCodeStatusBarController.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { ConfigurationChangeEvent, Disposable, workspace, WorkspaceConfiguration } from "vscode";
import { UserStatus } from "../shared";
import { LeetCodeStatusBarItem } from "./LeetCodeStatusBarItem";

class LeetCodeStatusBarController implements Disposable {
    private statusBar: LeetCodeStatusBarItem;
    private configurationChangeListener: Disposable;

    constructor() {
        this.statusBar = new LeetCodeStatusBarItem();
        this.setStatusBarVisibility();

        this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
            if (event.affectsConfiguration("leetcode.enableStatusBar")) {
                this.setStatusBarVisibility();
            }
        }, this);
    }

    public updateStatusBar(status: UserStatus, user?: string): void {
        this.statusBar.updateStatusBar(status, user);
    }

    public dispose(): void {
        this.statusBar.dispose();
        this.configurationChangeListener.dispose();
    }

    private setStatusBarVisibility(): void {
        if (this.isStatusBarEnabled()) {
            this.statusBar.show();
        } else {
            this.statusBar.hide();
        }
    }

    private isStatusBarEnabled(): boolean {
        const configuration: WorkspaceConfiguration = workspace.getConfiguration();
        return configuration.get<boolean>("leetcode.enableStatusBar", true);
    }
}

export const leetCodeStatusBarController: LeetCodeStatusBarController = new LeetCodeStatusBarController();


================================================
FILE: src/utils/cpUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as cp from "child_process";
import * as vscode from "vscode";
import { leetCodeChannel } from "../leetCodeChannel";

interface IExecError extends Error {
    result?: string;
}

export async function executeCommand(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
    return new Promise((resolve: (res: string) => void, reject: (e: Error) => void): void => {
        let result: string = "";

        const childProc: cp.ChildProcess = cp.spawn(command, args, { ...options, env: createEnvOption() });

        childProc.stdout?.on("data", (data: string | Buffer) => {
            data = data.toString();
            result = result.concat(data);
            leetCodeChannel.append(data);
        });

        childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString()));

        childProc.on("error", reject);

        childProc.on("close", (code: number) => {
            if (code !== 0 || result.indexOf("ERROR") > -1) {
                const error: IExecError = new Error(`Command "${command} ${args.toString()}" failed with exit code "${code}".`);
                if (result) {
                    error.result = result; // leetcode-cli may print useful content by exit with error code
                }
                reject(error);
            } else {
                resolve(result);
            }
        });
    });
}

export async function executeCommandWithProgress(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
    let result: string = "";
    await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (p: vscode.Progress<{}>) => {
        return new Promise<void>(async (resolve: () => void, reject: (e: Error) => void): Promise<void> => {
            p.report({ message });
            try {
                result = await executeCommand(command, args, options);
                resolve();
            } catch (e) {
                reject(e);
            }
        });
    });
    return result;
}

// clone process.env and add http proxy
export function createEnvOption(): {} {
    const proxy: string | undefined = getHttpAgent();
    if (proxy) {
        const env: any = Object.create(process.env);
        env.http_proxy = proxy;
        return env;
    }
    return process.env;
}

function getHttpAgent(): string | undefined {
    return vscode.workspace.getConfiguration("http").get<string>("proxy");
}


================================================
FILE: src/utils/httpUtils.ts
================================================
import axios, { AxiosRequestConfig, AxiosPromise } from "axios";
import { omit } from "lodash";
import { globalState } from "../globalState";
import { DialogType, promptForOpenOutputChannel } from "./uiUtils";

const referer = "vscode-lc-extension";

export function LcAxios<T = any>(path: string, settings?: AxiosRequestConfig): AxiosPromise<T> {
    const cookie = globalState.getCookie();
    if (!cookie) {
        promptForOpenOutputChannel(
            `Failed to obtain the cookie. Please log in again.`,
            DialogType.error
        );
        return Promise.reject("Failed to obtain the cookie.");
    }
    return axios(path, {
        headers: {
            referer,
            "content-type": "application/json",
            cookie,
            ...(settings && settings.headers),
        },
        xsrfCookieName: "csrftoken",
        xsrfHeaderName: "X-CSRFToken",
        ...(settings && omit(settings, "headers")),
    });
}


================================================
FILE: src/utils/osUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

export function isWindows(): boolean {
    return process.platform === "win32";
}

export function usingCmd(): boolean {
    const comSpec: string | undefined = process.env.ComSpec;
    // 'cmd.exe' is used as a fallback if process.env.ComSpec is unavailable.
    if (!comSpec) {
        return true;
    }

    if (comSpec.indexOf("cmd.exe") > -1) {
        return true;
    }
    return false;
}


================================================
FILE: src/utils/problemUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as fse from "fs-extra";
import * as _ from "lodash";
import * as path from "path";
import { IProblem, langExt } from "../shared";

export function genFileExt(language: string): string {
    const ext: string | undefined = langExt.get(language);
    if (!ext) {
        throw new Error(`The language "${language}" is not supported.`);
    }
    return ext;
}

export function genFileName(node: IProblem, language: string): string {
    const slug: string = _.kebabCase(node.name);
    const ext: string = genFileExt(language);
    return `${node.id}.${slug}.${ext}`;
}

export async function getNodeIdFromFile(fsPath: string): Promise<string> {
    const fileContent: string = await fse.readFile(fsPath, "utf8");
    let id: string = "";
    const matchResults: RegExpMatchArray | null = fileContent.match(/@lc.+id=(.+?) /);
    if (matchResults && matchResults.length === 2) {
        id = matchResults[1];
    }
    // Try to get id from file name if getting from comments failed
    if (!id) {
        id = path.basename(fsPath).split(".")[0];
    }

    return id;
}


================================================
FILE: src/utils/settingUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { workspace, WorkspaceConfiguration } from "vscode";
import { DescriptionConfiguration } from "../shared";

export function getWorkspaceConfiguration(): WorkspaceConfiguration {
    return workspace.getConfiguration("leetcode");
}

export function shouldHideSolvedProblem(): boolean {
    return getWorkspaceConfiguration().get<boolean>("hideSolved", false);
}

export function getWorkspaceFolder(): string {
    return getWorkspaceConfiguration().get<string>("workspaceFolder", "");
}

export function getEditorShortcuts(): string[] {
    return getWorkspaceConfiguration().get<string[]>("editor.shortcuts", ["submit", "test"]);
}

export function hasStarShortcut(): boolean {
    const shortcuts: string[] = getWorkspaceConfiguration().get<string[]>("editor.shortcuts", ["submit", "test"]);
    return shortcuts.indexOf("star") >= 0;
}

export function shouldUseEndpointTranslation(): boolean {
    return getWorkspaceConfiguration().get<boolean>("useEndpointTranslation", true);
}

export function getDescriptionConfiguration(): IDescriptionConfiguration {
    const setting: string = getWorkspaceConfiguration().get<string>("showDescription", DescriptionConfiguration.InWebView);
    const config: IDescriptionConfiguration = {
        showInComment: false,
        showInWebview: true,
    };
    switch (setting) {
        case DescriptionConfiguration.Both:
            config.showInComment = true;
            config.showInWebview = true;
            break;
        case DescriptionConfiguration.None:
            config.showInComment = false;
            config.showInWebview = false;
            break;
        case DescriptionConfiguration.InFileComment:
            config.showInComment = true;
            config.showInWebview = false;
            break;
        case DescriptionConfiguration.InWebView:
            config.showInComment = false;
            config.showInWebview = true;
            break;
    }

    // To be compatible with the deprecated setting:
    if (getWorkspaceConfiguration().get<boolean>("showCommentDescription")) {
        config.showInComment = true;
    }

    return config;
}

export interface IDescriptionConfiguration {
    showInComment: boolean;
    showInWebview: boolean;
}


================================================
FILE: src/utils/toolUtils.ts
================================================
export function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

export function parseQuery(query: string): { [key: string]: string } {
    const queryObject: { [key: string]: string } = {};

    if (!query) {
        return queryObject;
    }

    const keyValuePairs = query.split("&");
    keyValuePairs.forEach((pair) => {
        const firstEqualsIndex = pair.indexOf("=");
        if (firstEqualsIndex !== -1) {
            const key = pair.substring(0, firstEqualsIndex);
            const value = pair.substring(firstEqualsIndex + 1);
            queryObject[decodeURIComponent(key)] = decodeURIComponent(value);
        } else {
            // If no equals sign is found, treat the whole string as key with empty value
            queryObject[decodeURIComponent(pair)] = "";
        }
    });

    return queryObject;
}


================================================
FILE: src/utils/trackingUtils.ts
================================================
import * as vscode from "vscode";
import axios from "axios";
import { getLeetCodeEndpoint } from "../commands/plugin";
import { Endpoint } from "../shared";
import { leetCodeManager } from "../leetCodeManager";

const getTimeZone = (): string => {
    const endPoint: string = getLeetCodeEndpoint();
    if (endPoint === Endpoint.LeetCodeCN) {
        return "Asia/Shanghai";
    } else {
        return "UTC";
    }
};

interface IReportData {
    event_key: string;
    type?: "click" | "expose" | string;
    anonymous_id?: string;
    tid?: number;
    ename?: string; // event name
    href?: string;
    referer?: string;
    extra?: string;
    target?: string;
}

interface ITrackData {
    reportCache: IReportData[];
    isSubmit: boolean;
    report: (reportItems: IReportData | IReportData[]) => void;
    submitReport: (useSendBeason: boolean) => Promise<void>;
    reportUrl: string;
}

const testReportUrl = "https://analysis.lingkou.xyz/i/event";
const prodReportUrl = "https://analysis.leetcode.cn/i/event";

function getReportUrl() {
    if (process.env.NODE_ENV === "production") {
        return prodReportUrl;
    } else {
        return testReportUrl;
    }
}

const _charStr = "abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+=";

function RandomIndex(min: number, max: number, i: number) {
    let index = Math.floor(Math.random() * (max - min + 1) + min);
    const numStart = _charStr.length - 10;
    if (i === 0 && index >= numStart) {
        index = RandomIndex(min, max, i);
    }
    return index;
}

function getRandomString(len: number) {
    const min = 0;
    const max = _charStr.length - 1;
    let _str = "";
    len = len || 15;
    for (let i = 0, index; i < len; i++) {
        index = RandomIndex(min, max, i);
        _str += _charStr[index];
    }
    return _str;
}

function getAllowReportDataConfig() {
    const leetCodeConfig = vscode.workspace.getConfiguration("leetcode");
    const allowReportData = !!leetCodeConfig.get<boolean>("allowReportData");
    return allowReportData;
}

class TrackData implements ITrackData {
    public reportCache: IReportData[] = [];

    public isSubmit: boolean = false;

    public reportUrl: string = getReportUrl();

    private sendTimer: NodeJS.Timeout | undefined;

    public report = (reportItems: IReportData | IReportData[]) => {
        if (!getAllowReportDataConfig()) return;

        this.sendTimer && clearTimeout(this.sendTimer);

        if (!Array.isArray(reportItems)) {
            reportItems = [reportItems];
        }
        const randomId = getRandomString(60);
        reportItems.forEach((item) => {
            this.reportCache.push({
                ...item,
                referer: "vscode",
                target: leetCodeManager.getUser() ?? "",
                anonymous_id: item.anonymous_id ?? (randomId as string),
            });
        });
        this.sendTimer = setTimeout(this.submitReport, 800);
    };

    public submitReport = async () => {
        if (!getAllowReportDataConfig()) return;
        const dataList = JSON.stringify(this.reportCache);

        if (!this.reportCache.length || this.isSubmit) {
            return;
        }
        this.reportCache = [];
        try {
            this.isSubmit = true;
            axios.defaults.withCredentials = true;
            await axios.post(this.reportUrl, `dataList=${encodeURIComponent(dataList)}`, {
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded",
                    "x-timezone": getTimeZone(),
                },
            });
        } catch (e) {
            this.reportCache = this.reportCache.concat(JSON.parse(dataList));
        } finally {
            this.isSubmit = false;
        }
    };
}

export default new TrackData();


================================================
FILE: src/utils/uiUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { getLeetCodeEndpoint } from "../commands/plugin";
import { leetCodeChannel } from "../leetCodeChannel";
import { getWorkspaceConfiguration } from "./settingUtils";

export namespace DialogOptions {
    export const open: vscode.MessageItem = { title: "Open" };
    export const yes: vscode.MessageItem = { title: "Yes" };
    export const no: vscode.MessageItem = { title: "No", isCloseAffordance: true };
    export const never: vscode.MessageItem = { title: "Never" };
    export const singUp: vscode.MessageItem = { title: "Sign up" };
}

export async function promptForOpenOutputChannel(message: string, type: DialogType): Promise<void> {
    let result: vscode.MessageItem | undefined;
    switch (type) {
        case DialogType.info:
            result = await vscode.window.showInformationMessage(message, DialogOptions.open, DialogOptions.no);
            break;
        case DialogType.warning:
            result = await vscode.window.showWarningMessage(message, DialogOptions.open, DialogOptions.no);
            break;
        case DialogType.error:
            result = await vscode.window.showErrorMessage(message, DialogOptions.open, DialogOptions.no);
            break;
        default:
            break;
    }

    if (result === DialogOptions.open) {
        leetCodeChannel.show();
    }
}

export async function promptForSignIn(): Promise<void> {
    const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
        "Please sign in to LeetCode.",
        DialogOptions.yes,
        DialogOptions.no,
        DialogOptions.singUp,
    );
    switch (choice) {
        case DialogOptions.yes:
            await vscode.commands.executeCommand("leetcode.signin");
            break;
        case DialogOptions.singUp:
            if (getLeetCodeEndpoint()) {
                openUrl("https://leetcode.cn");
            } else {
                openUrl("https://leetcode.com");
            }
            break;
        default:
            break;
    }
}

export async function promptHintMessage(config: string, message: string, choiceConfirm: string, onConfirm: () => Promise<any>): Promise<void> {
    if (getWorkspaceConfiguration().get<boolean>(config)) {
        const choiceNoShowAgain: string = "Don't show again";
        const choice: string | undefined = await vscode.window.showInformationMessage(
            message, choiceConfirm, choiceNoShowAgain,
        );
        if (choice === choiceConfirm) {
            await onConfirm();
        } else if (choice === choiceNoShowAgain) {
            await getWorkspaceConfiguration().update(config, false, true /* UserSetting */);
        }
    }
}

export async function openSettingsEditor(query?: string): Promise<void> {
    await vscode.commands.executeCommand("workbench.action.openSettings", query);
}

export async function openKeybindingsEditor(query?: string): Promise<void> {
    await vscode.commands.executeCommand("workbench.action.openGlobalKeybindings", query);
}

export async function showFileSelectDialog(fsPath?: string): Promise<vscode.Uri[] | undefined> {
    const defaultUri: vscode.Uri | undefined = getBelongingWorkspaceFolderUri(fsPath);
    const options: vscode.OpenDialogOptions = {
        defaultUri,
        canSelectFiles: true,
        canSelectFolders: false,
        canSelectMany: false,
        openLabel: "Select",
    };
    return await vscode.window.showOpenDialog(options);
}

function getBelongingWorkspaceFolderUri(fsPath: string | undefined): vscode.Uri | undefined {
    let defaultUri: vscode.Uri | undefined;
    if (fsPath) {
        const workspaceFolder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(fsPath));
        if (workspaceFolder) {
            defaultUri = workspaceFolder.uri;
        }
    }
    return defaultUri;
}

export async function showDirectorySelectDialog(fsPath?: string): Promise<vscode.Uri[] | undefined> {
    const defaultUri: vscode.Uri | undefined = getBelongingWorkspaceFolderUri(fsPath);
    const options: vscode.OpenDialogOptions = {
        defaultUri,
        canSelectFiles: false,
        canSelectFolders: true,
        canSelectMany: false,
        openLabel: "Select",
    };
    return await vscode.window.showOpenDialog(options);
}

export async function openUrl(url: string): Promise<void> {
    vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(url));
}

export enum DialogType {
    info = "info",
    warning = "warning",
    error = "error",
}


================================================
FILE: src/utils/workspaceUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as fse from "fs-extra";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { IQuickItemEx } from "../shared";
import { getWorkspaceConfiguration, getWorkspaceFolder } from "./settingUtils";
import { showDirectorySelectDialog } from "./uiUtils";
import * as wsl from "./wslUtils";

export async function selectWorkspaceFolder(): Promise<string> {
    let workspaceFolderSetting: string = getWorkspaceFolder();
    if (workspaceFolderSetting.trim() === "") {
        workspaceFolderSetting = await determineLeetCodeFolder();
        if (workspaceFolderSetting === "") {
            // User cancelled
            return workspaceFolderSetting;
        }
    }
    let needAsk: boolean = true;
    await fse.ensureDir(workspaceFolderSetting);
    for (const folder of vscode.workspace.workspaceFolders || []) {
        if (isSubFolder(folder.uri.fsPath, workspaceFolderSetting)) {
            needAsk = false;
        }
    }

    if (needAsk) {
        const choice: string | undefined = await vscode.window.showQuickPick(
            [
                OpenOption.justOpenFile,
                OpenOption.openInCurrentWindow,
                OpenOption.openInNewWindow,
                OpenOption.addToWorkspace,
            ],
            { placeHolder: "The LeetCode workspace folder is not opened in VS Code, would you like to open it?" },
        );

        // Todo: generate file first
        switch (choice) {
            case OpenOption.justOpenFile:
                return workspaceFolderSetting;
            case OpenOption.openInCurrentWindow:
                await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), false);
                return "";
            case OpenOption.openInNewWindow:
                await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), true);
                return "";
            case OpenOption.addToWorkspace:
                vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders?.length ?? 0, 0, { uri: vscode.Uri.file(workspaceFolderSetting) });
                break;
            default:
                return "";
        }
    }

    return wsl.useWsl() ? wsl.toWslPath(workspaceFolderSetting) : workspaceFolderSetting;
}

export async function getActiveFilePath(uri?: vscode.Uri): Promise<string | undefined> {
    let textEditor: vscode.TextEditor | undefined;
    if (uri) {
        textEditor = await vscode.window.showTextDocument(uri, { preview: false });
    } else {
        textEditor = vscode.window.activeTextEditor;
    }

    if (!textEditor) {
        return undefined;
    }
    if (textEditor.document.isDirty && !await textEditor.document.save()) {
        vscode.window.showWarningMessage("Please save the solution file first.");
        return undefined;
    }
    return wsl.useWsl() ? wsl.toWslPath(textEditor.document.uri.fsPath) : textEditor.document.uri.fsPath;
}

function isSubFolder(from: string, to: string): boolean {
    const relative: string = path.relative(from, to);
    if (relative === "") {
        return true;
    }
    return !relative.startsWith("..") && !path.isAbsolute(relative);
}

async function determineLeetCodeFolder(): Promise<string> {
    let result: string;
    const picks: Array<IQuickItemEx<string>> = [];
    picks.push(
        {
            label: `Default location`,
            detail: `${path.join(os.homedir(), ".leetcode")}`,
            value: `${path.join(os.homedir(), ".leetcode")}`,
        },
        {
            label: "$(file-directory) Browse...",
            value: ":browse",
        },
    );
    const choice: IQuickItemEx<string> | undefined = await vscode.window.showQuickPick(
        picks,
        { placeHolder: "Select where you would like to save your LeetCode files" },
    );
    if (!choice) {
        result = "";
    } else if (choice.value === ":browse") {
        const directory: vscode.Uri[] | undefined = await showDirectorySelectDialog();
        if (!directory || directory.length < 1) {
            result = "";
        } else {
            result = directory[0].fsPath;
        }
    } else {
        result = choice.value;
    }

    getWorkspaceConfiguration().update("workspaceFolder", result, vscode.ConfigurationTarget.Global);

    return result;
}

enum OpenOption {
    justOpenFile = "Just open the problem file",
    openInCurrentWindow = "Open in current window",
    openInNewWindow = "Open in new window",
    addToWorkspace = "Add to workspace",
}


================================================
FILE: src/utils/wslUtils.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import * as vscode from "vscode";
import { executeCommand } from "./cpUtils";
import { isWindows } from "./osUtils";

export function useWsl(): boolean {
    const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
    return isWindows() && leetCodeConfig.get<boolean>("useWsl") === true;
}

export async function toWslPath(path: string): Promise<string> {
    return (await executeCommand("wsl", ["wslpath", "-u", `"${path.replace(/\\/g, "/")}"`])).trim();
}

export async function toWinPath(path: string): Promise<string> {
    if (path.startsWith("\\mnt\\")) {
        return (await executeCommand("wsl", ["wslpath", "-w", `"${path.replace(/\\/g, "/").substr(0, 6)}"`])).trim() + path.substr(7);
    }
    return (await executeCommand("wsl", ["wslpath", "-w", "/"])).trim() + path;
}


================================================
FILE: src/webview/LeetCodeWebview.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { commands, ConfigurationChangeEvent, Disposable, ViewColumn, WebviewPanel, window, workspace } from "vscode";
import { openSettingsEditor, promptHintMessage } from "../utils/uiUtils";
import { markdownEngine } from "./markdownEngine";

export abstract class LeetCodeWebview implements Disposable {

    protected readonly viewType: string = "leetcode.webview";
    protected panel: WebviewPanel | undefined;
    private listeners: Disposable[] = [];

    public dispose(): void {
        if (this.panel) {
            this.panel.dispose();
        }
    }

    protected showWebviewInternal(): void {
        const { title, viewColumn, preserveFocus } = this.getWebviewOption();
        if (!this.panel) {
            this.panel = window.createWebviewPanel(this.viewType, title, { viewColumn, preserveFocus }, {
                enableScripts: true,
                enableCommandUris: true,
                enableFindWidget: true,
                retainContextWhenHidden: true,
                localResourceRoots: markdownEngine.localResourceRoots,
            });
            this.panel.onDidDispose(this.onDidDisposeWebview, this, this.listeners);
            this.panel.webview.onDidReceiveMessage(this.onDidReceiveMessage, this, this.listeners);
            workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.listeners);
        } else {
            this.panel.title = title;
            if (viewColumn === ViewColumn.Two) {
                // Make sure second group exists. See vscode#71608 issue
                commands.executeCommand("workbench.action.focusSecondEditorGroup").then(() => {
                    this.panel!.reveal(viewColumn, preserveFocus);
                });
            } else {
                this.panel.reveal(viewColumn, preserveFocus);
            }
        }
        this.panel.webview.html = this.getWebviewContent();
        this.showMarkdownConfigHint();
    }

    protected onDidDisposeWebview(): void {
        this.panel = undefined;
        for (const listener of this.listeners) {
            listener.dispose();
        }
        this.listeners = [];
    }

    protected async onDidChangeConfiguration(event: ConfigurationChangeEvent): Promise<void> {
        if (this.panel && event.affectsConfiguration("markdown")) {
            this.panel.webview.html = this.getWebviewContent();
        }
    }

    protected async onDidReceiveMessage(_message: any): Promise<void> { /* no special rule */ }

    protected abstract getWebviewOption(): ILeetCodeWebviewOption;

    protected abstract getWebviewContent(): string;

    private async showMarkdownConfigHint(): Promise<void> {
        await promptHintMessage(
            "hint.configWebviewMarkdown",
            'You can change the webview appearance ("fontSize", "lineWidth" & "fontFamily") in "markdown.preview" configuration.',
            "Open settings",
            (): Promise<any> => openSettingsEditor("markdown.preview"),
        );
    }
}

export interface ILeetCodeWebviewOption {
    title: string;
    viewColumn: ViewColumn;
    preserveFocus?: boolean;
}


================================================
FILE: src/webview/leetCodePreviewProvider.ts
================================================
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.

import { commands, ViewColumn } from "vscode";
import { getLeetCodeEndpoint } from "../commands/plugin";
import { Endpoint, IProblem } from "../shared";
import { ILeetCodeWebviewOption, LeetCodeWebview } from "./LeetCodeWebview";
import { markdownEngine } from "./markdownEngine";

class LeetCodePreviewProvider extends LeetCodeWebview {
    protected readonly viewType: string = "leetcode.preview";
    private node: IProblem;
    private description: IDescription;
    private sideMode: boolean = false;

    public isSideMode(): boolean {
        return this.sideMode;
    }

    public show(descString: string, node: IProblem, isSideMode: boolean = false): void {
        this.description = this.parseDescription(descString, node);
        this.node = node;
        this.sideMode = isSideMode;
        this.showWebviewInternal();
    }

    protected getWebviewOption(): ILeetCodeWebviewOption {
        if (!this.sideMode) {
            return {
                title: `${this.node.name}: Preview`,
                viewColumn: ViewColumn.One,
            };
        } else {
            return {
                title: "Description",
                viewColumn: ViewColumn.Two,
                preserveFocus: true,
            };
        }
    }

    protected getWebviewContent(): string {
        const button: { element: string; script: string; style: string } = {
            element: `<button id="solve">Code Now</button>`,
            script: `const button = document.getElementById('solve');
                    button.onclick = () => vscode.postMessage({
                        command: 'ShowProblem',
                    });`,
            style: `<style>
                #solve {
                    position: fixed;
                    bottom: 1rem;
                    right: 1rem;
                    border: 0;
                    margin: 1rem 0;
                    padding: 0.2rem 1rem;
                    color: white;
                    background-color: var(--vscode-button-background);
                }
                #solve:hover {
                    background-color: var(--vscode-button-hoverBackground);
                }
                #solve:active {
                    border: 0;
                }
                </style>`,
        };
        const { title, url, category, difficulty, likes, dislikes, body } = this.description;
        const head: string = markdownEngine.render(`# [${title}](${url})`);
        const info: string = markdownEngine.render(
            [
                `| Category | Difficulty | Likes | Dislikes |`,
                `| :------: | :--------: | :---: | :------: |`,
                `| ${category} | ${difficulty} | ${likes} | ${dislikes} |`,
            ].join("\n")
        );
        const tags: string = [
            `<details>`,
            `<summary><strong>Tags</strong></summary>`,
            markdownEngine.render(this.description.tags.map((t: string) => `[\`${t}\`](${this.getTagLink(t)})`).join(" | ")),
            `</details>`,
        ].join("\n");
     
Download .txt
gitextract_pobireoz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug.md
│   │   ├── feature.md
│   │   └── question.md
│   ├── ISSUE_TEMPLATE.md
│   ├── no-response.yml
│   └── workflows/
│       └── build.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .vscodeignore
├── ACKNOWLEDGEMENTS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── _config.yml
├── docs/
│   └── README_zh-CN.md
├── package.json
├── src/
│   ├── codelens/
│   │   ├── CodeLensController.ts
│   │   └── CustomCodeLensProvider.ts
│   ├── commands/
│   │   ├── cache.ts
│   │   ├── language.ts
│   │   ├── list.ts
│   │   ├── plugin.ts
│   │   ├── session.ts
│   │   ├── show.ts
│   │   ├── star.ts
│   │   ├── submit.ts
│   │   └── test.ts
│   ├── explorer/
│   │   ├── LeetCodeNode.ts
│   │   ├── LeetCodeTreeDataProvider.ts
│   │   ├── LeetCodeTreeItemDecorationProvider.ts
│   │   └── explorerNodeManager.ts
│   ├── extension.ts
│   ├── globalState.ts
│   ├── leetCodeChannel.ts
│   ├── leetCodeExecutor.ts
│   ├── leetCodeManager.ts
│   ├── request/
│   │   └── query-user-data.ts
│   ├── shared.ts
│   ├── statusbar/
│   │   ├── LeetCodeStatusBarItem.ts
│   │   └── leetCodeStatusBarController.ts
│   ├── utils/
│   │   ├── cpUtils.ts
│   │   ├── httpUtils.ts
│   │   ├── osUtils.ts
│   │   ├── problemUtils.ts
│   │   ├── settingUtils.ts
│   │   ├── toolUtils.ts
│   │   ├── trackingUtils.ts
│   │   ├── uiUtils.ts
│   │   ├── workspaceUtils.ts
│   │   └── wslUtils.ts
│   └── webview/
│       ├── LeetCodeWebview.ts
│       ├── leetCodePreviewProvider.ts
│       ├── leetCodeSolutionProvider.ts
│       ├── leetCodeSubmissionProvider.ts
│       └── markdownEngine.ts
├── thirdpartynotice.txt
├── tsconfig.json
└── tslint.json
Download .txt
SYMBOL INDEX (254 symbols across 38 files)

FILE: src/codelens/CodeLensController.ts
  class CodeLensController (line 7) | class CodeLensController implements Disposable {
    method constructor (line 12) | constructor() {
    method dispose (line 24) | public dispose(): void {

FILE: src/codelens/CustomCodeLensProvider.ts
  class CustomCodeLensProvider (line 9) | class CustomCodeLensProvider implements vscode.CodeLensProvider {
    method onDidChangeCodeLenses (line 13) | get onDidChangeCodeLenses(): vscode.Event<void> {
    method refresh (line 17) | public refresh(): void {
    method provideCodeLenses (line 21) | public provideCodeLenses(document: vscode.TextDocument): vscode.Provid...

FILE: src/commands/cache.ts
  function deleteCache (line 7) | async function deleteCache(): Promise<void> {

FILE: src/commands/language.ts
  function switchDefaultLanguage (line 7) | async function switchDefaultLanguage(): Promise<void> {

FILE: src/commands/list.ts
  function listProblems (line 10) | async function listProblems(): Promise<IProblem[]> {
  function parseProblemState (line 46) | function parseProblemState(stateOutput: string): ProblemState {

FILE: src/commands/plugin.ts
  function switchEndpoint (line 12) | async function switchEndpoint(): Promise<void> {
  function getLeetCodeEndpoint (line 52) | function getLeetCodeEndpoint(): string {
  constant SORT_ORDER (line 57) | const SORT_ORDER: SortingStrategy[] = [
  function switchSortingStrategy (line 63) | async function switchSortingStrategy(): Promise<void> {
  function getSortingStrategy (line 85) | function getSortingStrategy(): SortingStrategy {

FILE: src/commands/session.ts
  function getSessionList (line 10) | async function getSessionList(): Promise<ISession[]> {
  function manageSessions (line 35) | async function manageSessions(): Promise<void> {
  function parseSessionsToPicks (line 57) | async function parseSessionsToPicks(includeOperations: boolean = false):...
  function parseSessionManagementOperations (line 78) | function parseSessionManagementOperations(): Array<IQuickItemEx<string>> {
  function createSession (line 92) | async function createSession(): Promise<void> {
  function deleteSession (line 108) | async function deleteSession(): Promise<void> {
  type ISession (line 149) | interface ISession {

FILE: src/commands/show.ts
  function previewProblem (line 34) | async function previewProblem(input: IProblem | vscode.Uri, isSideMode: ...
  function pickOne (line 67) | async function pickOne(): Promise<void> {
  function showProblem (line 73) | async function showProblem(node?: LeetCodeNode): Promise<void> {
  function searchProblem (line 80) | async function searchProblem(): Promise<void> {
  function showSolution (line 95) | async function showSolution(input: LeetCodeNode | vscode.Uri): Promise<v...
  function fetchProblemLanguage (line 127) | async function fetchProblemLanguage(): Promise<string | undefined> {
  function showProblemInternal (line 158) | async function showProblemInternal(node: IProblem): Promise<void> {
  function showDescriptionView (line 216) | async function showDescriptionView(node: IProblem): Promise<void> {
  function parseProblemsToPicks (line 219) | async function parseProblemsToPicks(p: Promise<IProblem[]>): Promise<Arr...
  function parseProblemDecorator (line 236) | function parseProblemDecorator(state: ProblemState, locked: boolean): st...
  function resolveRelativePath (line 247) | async function resolveRelativePath(relativePath: string, node: IProblem,...
  function resolveTagForProblem (line 293) | async function resolveTagForProblem(problem: IProblem): Promise<string |...
  function resolveCompanyForProblem (line 304) | async function resolveCompanyForProblem(problem: IProblem): Promise<stri...

FILE: src/commands/star.ts
  function addFavorite (line 12) | async function addFavorite(node: LeetCodeNode): Promise<void> {
  function removeFavorite (line 24) | async function removeFavorite(node: LeetCodeNode): Promise<void> {

FILE: src/commands/submit.ts
  function submitSolution (line 12) | async function submitSolution(uri?: vscode.Uri): Promise<void> {

FILE: src/commands/test.ts
  function testSolution (line 15) | async function testSolution(uri?: vscode.Uri): Promise<void> {
  function parseTestString (line 90) | function parseTestString(test: string): string {

FILE: src/explorer/LeetCodeNode.ts
  class LeetCodeNode (line 7) | class LeetCodeNode {
    method constructor (line 9) | constructor(private data: IProblem, private isProblemNode: boolean = t...
    method locked (line 11) | public get locked(): boolean {
    method name (line 14) | public get name(): string {
    method state (line 18) | public get state(): ProblemState {
    method id (line 22) | public get id(): string {
    method passRate (line 26) | public get passRate(): string {
    method difficulty (line 30) | public get difficulty(): string {
    method tags (line 34) | public get tags(): string[] {
    method companies (line 38) | public get companies(): string[] {
    method isFavorite (line 42) | public get isFavorite(): boolean {
    method isProblem (line 46) | public get isProblem(): boolean {
    method previewCommand (line 50) | public get previewCommand(): Command {
    method acceptanceRate (line 58) | public get acceptanceRate(): number {
    method uri (line 62) | public get uri(): Uri {

FILE: src/explorer/LeetCodeTreeDataProvider.ts
  class LeetCodeTreeDataProvider (line 13) | class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCo...
    method initialize (line 22) | public initialize(context: vscode.ExtensionContext): void {
    method refresh (line 26) | public async refresh(): Promise<void> {
    method getTreeItem (line 31) | public getTreeItem(element: LeetCodeNode): vscode.TreeItem | Thenable<...
    method getChildren (line 61) | public getChildren(element?: LeetCodeNode | undefined): vscode.Provide...
    method parseIconPathFromProblemState (line 97) | private parseIconPathFromProblemState(element: LeetCodeNode): string {
    method parsePremiumUnLockIconPath (line 117) | private parsePremiumUnLockIconPath(element: LeetCodeNode): string {
    method getSubCategoryTooltip (line 125) | private getSubCategoryTooltip(element: LeetCodeNode): string {

FILE: src/explorer/LeetCodeTreeItemDecorationProvider.ts
  class LeetCodeTreeItemDecorationProvider (line 4) | class LeetCodeTreeItemDecorationProvider implements FileDecorationProvid...
    method provideFileDecoration (line 17) | public provideFileDecoration(uri: Uri): ProviderResult<FileDecoration>  {
    method isDifficultyBadgeEnabled (line 34) | private isDifficultyBadgeEnabled(): boolean {

FILE: src/explorer/explorerNodeManager.ts
  class ExplorerNodeManager (line 12) | class ExplorerNodeManager implements Disposable {
    method refreshCache (line 17) | public async refreshCache(): Promise<void> {
    method getRootNodes (line 34) | public getRootNodes(): LeetCodeNode[] {
    method getAllNodes (line 59) | public getAllNodes(): LeetCodeNode[] {
    method getAllDifficultyNodes (line 65) | public getAllDifficultyNodes(): LeetCodeNode[] {
    method getAllCompanyNodes (line 85) | public getAllCompanyNodes(): LeetCodeNode[] {
    method getAllTagNodes (line 97) | public getAllTagNodes(): LeetCodeNode[] {
    method getNodeById (line 109) | public getNodeById(id: string): LeetCodeNode | undefined {
    method getFavoriteNodes (line 113) | public getFavoriteNodes(): LeetCodeNode[] {
    method getChildrenNodesById (line 123) | public getChildrenNodesById(id: string): LeetCodeNode[] {
    method dispose (line 151) | public dispose(): void {
    method sortSubCategoryNodes (line 157) | private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], categor...
    method applySortingStrategy (line 193) | private applySortingStrategy(nodes: LeetCodeNode[]): LeetCodeNode[] {

FILE: src/extension.ts
  function activate (line 30) | async function activate(context: vscode.ExtensionContext): Promise<void> {
  function deactivate (line 112) | function deactivate(): void {

FILE: src/globalState.ts
  type UserDataType (line 9) | type UserDataType = {
  class GlobalState (line 17) | class GlobalState {
    method initialize (line 23) | public initialize(context: vscode.ExtensionContext): void {
    method setCookie (line 28) | public setCookie(cookie: string): any {
    method getCookie (line 32) | public getCookie(): string | undefined {
    method setUserStatus (line 36) | public setUserStatus(userStatus: UserDataType): any {
    method getUserStatus (line 41) | public getUserStatus(): UserDataType | undefined {
    method removeCookie (line 45) | public removeCookie(): void {
    method removeAll (line 49) | public removeAll(): void {

FILE: src/leetCodeChannel.ts
  class LeetCodeChannel (line 6) | class LeetCodeChannel implements vscode.Disposable {
    method appendLine (line 9) | public appendLine(message: string): void {
    method append (line 13) | public append(message: string): void {
    method show (line 17) | public show(): void {
    method dispose (line 21) | public dispose(): void {

FILE: src/leetCodeExecutor.ts
  class LeetCodeExecutor (line 17) | class LeetCodeExecutor implements Disposable {
    method constructor (line 22) | constructor() {
    method getLeetCodeBinaryPath (line 32) | public async getLeetCodeBinaryPath(): Promise<string> {
    method meetRequirements (line 39) | public async meetRequirements(context: ExtensionContext): Promise<bool...
    method deleteCache (line 79) | public async deleteCache(): Promise<string> {
    method getUserInfo (line 83) | public async getUserInfo(): Promise<string> {
    method signOut (line 87) | public async signOut(): Promise<string> {
    method listProblems (line 91) | public async listProblems(showLocked: boolean, needTranslation: boolea...
    method showProblem (line 103) | public async showProblem(problemNode: IProblem, language: string, file...
    method showSolution (line 131) | public async showSolution(input: string, language: string, needTransla...
    method getDescription (line 141) | public async getDescription(problemNodeId: string, needTranslation: bo...
    method listSessions (line 149) | public async listSessions(): Promise<string> {
    method enableSession (line 153) | public async enableSession(name: string): Promise<string> {
    method createSession (line 157) | public async createSession(id: string): Promise<string> {
    method deleteSession (line 161) | public async deleteSession(id: string): Promise<string> {
    method submitSolution (line 165) | public async submitSolution(filePath: string): Promise<string> {
    method testSolution (line 176) | public async testSolution(filePath: string, testString?: string): Prom...
    method switchEndpoint (line 183) | public async switchEndpoint(endpoint: string): Promise<string> {
    method toggleFavorite (line 193) | public async toggleFavorite(node: IProblem, addToFavorite: boolean): P...
    method getCompaniesAndTags (line 201) | public async getCompaniesAndTags(): Promise<{ companies: { [key: strin...
    method node (line 212) | public get node(): string {
    method dispose (line 216) | public dispose(): void {
    method getNodePath (line 220) | private getNodePath(): string {
    method executeCommandEx (line 225) | private async executeCommandEx(command: string, args: string[], option...
    method executeCommandWithProgressEx (line 232) | private async executeCommandWithProgressEx(message: string, command: s...
    method removeOldCache (line 239) | private async removeOldCache(): Promise<void> {

FILE: src/leetCodeManager.ts
  class LeetCodeManager (line 18) | class LeetCodeManager extends EventEmitter {
    method constructor (line 24) | constructor() {
    method getLoginStatus (line 31) | public async getLoginStatus(): Promise<void> {
    method updateUserStatusWithCookie (line 45) | private async updateUserStatusWithCookie(cookie: string): Promise<void> {
    method handleUriSignIn (line 58) | public async handleUriSignIn(uri: vscode.Uri): Promise<void> {
    method handleInputCookieSignIn (line 77) | public async handleInputCookieSignIn(): Promise<void> {
    method signIn (line 89) | public async signIn(): Promise<void> {
    method signOut (line 125) | public async signOut(): Promise<void> {
    method getStatus (line 138) | public getStatus(): UserStatus {
    method getUser (line 142) | public getUser(): string | undefined {
    method tryParseUserName (line 146) | private tryParseUserName(output: string): string {
    method getAuthLoginUrl (line 156) | public getAuthLoginUrl(): string {
    method setCookieToCli (line 166) | public setCookieToCli(cookie: string, name: string): Promise<void> {

FILE: src/shared.ts
  type IQuickItemEx (line 6) | interface IQuickItemEx<T> extends vscode.QuickPickItem {
  type UserStatus (line 10) | enum UserStatus {
  type ProblemState (line 62) | enum ProblemState {
  type Endpoint (line 69) | enum Endpoint {
  type IProblem (line 74) | interface IProblem {
  type Category (line 98) | enum Category {
  type DescriptionConfiguration (line 108) | enum DescriptionConfiguration {
  type SortingStrategy (line 117) | enum SortingStrategy {
  constant PREMIUM_URL_CN (line 125) | const PREMIUM_URL_CN = "https://leetcode.cn/premium-payment/?source=vsco...
  constant PREMIUM_URL_GLOBAL (line 126) | const PREMIUM_URL_GLOBAL = "https://leetcode.com/subscribe/?ref=lp_pl&so...

FILE: src/statusbar/LeetCodeStatusBarItem.ts
  class LeetCodeStatusBarItem (line 7) | class LeetCodeStatusBarItem implements vscode.Disposable {
    method constructor (line 10) | constructor() {
    method updateStatusBar (line 15) | public updateStatusBar(status: UserStatus, user?: string): void {
    method show (line 27) | public show(): void {
    method hide (line 31) | public hide(): void {
    method dispose (line 35) | public dispose(): void {

FILE: src/statusbar/leetCodeStatusBarController.ts
  class LeetCodeStatusBarController (line 8) | class LeetCodeStatusBarController implements Disposable {
    method constructor (line 12) | constructor() {
    method updateStatusBar (line 23) | public updateStatusBar(status: UserStatus, user?: string): void {
    method dispose (line 27) | public dispose(): void {
    method setStatusBarVisibility (line 32) | private setStatusBarVisibility(): void {
    method isStatusBarEnabled (line 40) | private isStatusBarEnabled(): boolean {

FILE: src/utils/cpUtils.ts
  type IExecError (line 8) | interface IExecError extends Error {
  function executeCommand (line 12) | async function executeCommand(command: string, args: string[], options: ...
  function executeCommandWithProgress (line 42) | async function executeCommandWithProgress(message: string, command: stri...
  function createEnvOption (line 59) | function createEnvOption(): {} {
  function getHttpAgent (line 69) | function getHttpAgent(): string | undefined {

FILE: src/utils/httpUtils.ts
  function LcAxios (line 8) | function LcAxios<T = any>(path: string, settings?: AxiosRequestConfig): ...

FILE: src/utils/osUtils.ts
  function isWindows (line 4) | function isWindows(): boolean {
  function usingCmd (line 8) | function usingCmd(): boolean {

FILE: src/utils/problemUtils.ts
  function genFileExt (line 9) | function genFileExt(language: string): string {
  function genFileName (line 17) | function genFileName(node: IProblem, language: string): string {
  function getNodeIdFromFile (line 23) | async function getNodeIdFromFile(fsPath: string): Promise<string> {

FILE: src/utils/settingUtils.ts
  function getWorkspaceConfiguration (line 7) | function getWorkspaceConfiguration(): WorkspaceConfiguration {
  function shouldHideSolvedProblem (line 11) | function shouldHideSolvedProblem(): boolean {
  function getWorkspaceFolder (line 15) | function getWorkspaceFolder(): string {
  function getEditorShortcuts (line 19) | function getEditorShortcuts(): string[] {
  function hasStarShortcut (line 23) | function hasStarShortcut(): boolean {
  function shouldUseEndpointTranslation (line 28) | function shouldUseEndpointTranslation(): boolean {
  function getDescriptionConfiguration (line 32) | function getDescriptionConfiguration(): IDescriptionConfiguration {
  type IDescriptionConfiguration (line 65) | interface IDescriptionConfiguration {

FILE: src/utils/toolUtils.ts
  function sleep (line 1) | function sleep(ms) {
  function parseQuery (line 5) | function parseQuery(query: string): { [key: string]: string } {

FILE: src/utils/trackingUtils.ts
  type IReportData (line 16) | interface IReportData {
  type ITrackData (line 28) | interface ITrackData {
  function getReportUrl (line 39) | function getReportUrl() {
  function RandomIndex (line 49) | function RandomIndex(min: number, max: number, i: number) {
  function getRandomString (line 58) | function getRandomString(len: number) {
  function getAllowReportDataConfig (line 70) | function getAllowReportDataConfig() {
  class TrackData (line 76) | class TrackData implements ITrackData {

FILE: src/utils/uiUtils.ts
  function promptForOpenOutputChannel (line 17) | async function promptForOpenOutputChannel(message: string, type: DialogT...
  function promptForSignIn (line 38) | async function promptForSignIn(): Promise<void> {
  function promptHintMessage (line 61) | async function promptHintMessage(config: string, message: string, choice...
  function openSettingsEditor (line 75) | async function openSettingsEditor(query?: string): Promise<void> {
  function openKeybindingsEditor (line 79) | async function openKeybindingsEditor(query?: string): Promise<void> {
  function showFileSelectDialog (line 83) | async function showFileSelectDialog(fsPath?: string): Promise<vscode.Uri...
  function getBelongingWorkspaceFolderUri (line 95) | function getBelongingWorkspaceFolderUri(fsPath: string | undefined): vsc...
  function showDirectorySelectDialog (line 106) | async function showDirectorySelectDialog(fsPath?: string): Promise<vscod...
  function openUrl (line 118) | async function openUrl(url: string): Promise<void> {
  type DialogType (line 122) | enum DialogType {

FILE: src/utils/workspaceUtils.ts
  function selectWorkspaceFolder (line 13) | async function selectWorkspaceFolder(): Promise<string> {
  function getActiveFilePath (line 62) | async function getActiveFilePath(uri?: vscode.Uri): Promise<string | und...
  function isSubFolder (line 80) | function isSubFolder(from: string, to: string): boolean {
  function determineLeetCodeFolder (line 88) | async function determineLeetCodeFolder(): Promise<string> {
  type OpenOption (line 124) | enum OpenOption {

FILE: src/utils/wslUtils.ts
  function useWsl (line 8) | function useWsl(): boolean {
  function toWslPath (line 13) | async function toWslPath(path: string): Promise<string> {
  function toWinPath (line 17) | async function toWinPath(path: string): Promise<string> {

FILE: src/webview/LeetCodeWebview.ts
  method dispose (line 14) | public dispose(): void {
  method showWebviewInternal (line 20) | protected showWebviewInternal(): void {
  method onDidDisposeWebview (line 48) | protected onDidDisposeWebview(): void {
  method onDidChangeConfiguration (line 56) | protected async onDidChangeConfiguration(event: ConfigurationChangeEvent...
  method onDidReceiveMessage (line 62) | protected async onDidReceiveMessage(_message: any): Promise<void> { /* n...
  method showMarkdownConfigHint (line 68) | private async showMarkdownConfigHint(): Promise<void> {
  type ILeetCodeWebviewOption (line 78) | interface ILeetCodeWebviewOption {

FILE: src/webview/leetCodePreviewProvider.ts
  class LeetCodePreviewProvider (line 10) | class LeetCodePreviewProvider extends LeetCodeWebview {
    method isSideMode (line 16) | public isSideMode(): boolean {
    method show (line 20) | public show(descString: string, node: IProblem, isSideMode: boolean = ...
    method getWebviewOption (line 27) | protected getWebviewOption(): ILeetCodeWebviewOption {
    method getWebviewContent (line 42) | protected getWebviewContent(): string {
    method onDidDisposeWebview (line 119) | protected onDidDisposeWebview(): void {
    method onDidReceiveMessage (line 124) | protected async onDidReceiveMessage(message: IWebViewMessage): Promise...
    method parseDescription (line 138) | private parseDescription(descString: string, problem: IProblem): IDesc...
    method getTagLink (line 171) | private getTagLink(tag: string): string {
    method getSolutionsLink (line 182) | private getSolutionsLink(url: string): string {
    method getSubmissionsLink (line 185) | private getSubmissionsLink(url: string): string {
  type IDescription (line 190) | interface IDescription {
  type IWebViewMessage (line 202) | interface IWebViewMessage {

FILE: src/webview/leetCodeSolutionProvider.ts
  class LeetCodeSolutionProvider (line 9) | class LeetCodeSolutionProvider extends LeetCodeWebview {
    method show (line 15) | public show(solutionString: string): void {
    method getWebviewOption (line 20) | protected getWebviewOption(): ILeetCodeWebviewOption {
    method getWebviewContent (line 35) | protected getWebviewContent(): string {
    method onDidDisposeWebview (line 65) | protected onDidDisposeWebview(): void {
    method parseSolution (line 69) | private parseSolution(raw: string): Solution {
  class Solution (line 85) | class Solution {

FILE: src/webview/leetCodeSubmissionProvider.ts
  class LeetCodeSubmissionProvider (line 9) | class LeetCodeSubmissionProvider extends LeetCodeWebview {
    method show (line 14) | public show(resultString: string): void {
    method getWebviewOption (line 20) | protected getWebviewOption(): ILeetCodeWebviewOption {
    method getWebviewContent (line 27) | protected getWebviewContent(): string {
    method onDidDisposeWebview (line 60) | protected onDidDisposeWebview(): void {
    method showKeybindingsHint (line 64) | private async showKeybindingsHint(): Promise<void> {
    method parseResult (line 73) | private parseResult(raw: string): IResult {
  type IResult (line 101) | interface IResult {

FILE: src/webview/markdownEngine.ts
  class MarkdownEngine (line 12) | class MarkdownEngine implements vscode.Disposable {
    method constructor (line 18) | public constructor() {
    method localResourceRoots (line 27) | public get localResourceRoots(): vscode.Uri[] {
    method dispose (line 31) | public dispose(): void {
    method reload (line 35) | public reload(): void {
    method render (line 40) | public render(md: string, env?: any): string {
    method getStyles (line 44) | public getStyles(): string {
    method getBuiltinStyles (line 51) | private getBuiltinStyles(): string {
    method getSettingsStyles (line 62) | private getSettingsStyles(): string {
    method initEngine (line 74) | private initEngine(): MarkdownIt {
    method addCodeBlockHighlight (line 102) | private addCodeBlockHighlight(md: MarkdownIt): void {
    method addImageUrlCompletion (line 120) | private addImageUrlCompletion(md: MarkdownIt): void {
    method addLinkValidator (line 132) | private addLinkValidator(md: MarkdownIt): void {
  class MarkdownConfiguration (line 142) | class MarkdownConfiguration {
    method constructor (line 149) | public constructor() {
    method resolveFontFamily (line 157) | private resolveFontFamily(config: vscode.WorkspaceConfiguration): stri...
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (236K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug.md",
    "chars": 546,
    "preview": "---\nname: 🐛 Bug report\nabout: Create a report to help us improve\n---\n\n## 🐛 Bug Report\n\nA clear and concise description o"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature.md",
    "chars": 297,
    "preview": "---\nname: 🚀 Feature Proposal\nabout: Submit a proposal for a new feature\n---\n\n## 🚀 Feature Proposal\n\nA clear and concise "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "chars": 523,
    "preview": "---\nname: 💬 Questions / Help\nabout: If you have questions, please check our documents first\n---\n\nBefore you submit an qu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 60,
    "preview": "*It's really recommended to create an issue by a template.*\n"
  },
  {
    "path": ".github/no-response.yml",
    "chars": 276,
    "preview": "daysUntilClose: 14\nresponseRequiredLabel: need more info\ncloseComment: >\n  This issue has been closed automatically beca"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 909,
    "preview": "name: CI\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\njobs:\n  linux:\n    name: Linux\n    "
  },
  {
    "path": ".gitignore",
    "chars": 934,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directo"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1023,
    "preview": "// A launch configuration that compiles the extension and then opens it inside a new window\n{\n    \"version\": \"0.1.0\",\n  "
  },
  {
    "path": ".vscode/settings.json",
    "chars": 456,
    "preview": "{\n    \"editor.formatOnSave\": false,\n    \"editor.insertSpaces\": true,\n    \"editor.tabSize\": 4,\n    \"files.insertFinalNewl"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 762,
    "preview": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"npm\",\n            \"type\": \"shell\",\n            "
  },
  {
    "path": ".vscodeignore",
    "chars": 160,
    "preview": ".vscode/**\n.vscode-test/**\nout/test/**\ntest/**\nsrc/**\n**/*.map\n.gitignore\npackage-lock.json\ntsconfig.json\ntslint.json\n**"
  },
  {
    "path": "ACKNOWLEDGEMENTS.md",
    "chars": 2839,
    "preview": "## Contributors 🙏❤\n\nA big thanks to the following individuals for contributing:\n\n- [@JIEJIAN21](https://github.com/JIEJI"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 13822,
    "preview": "# Change Log\nAll notable changes to the \"leetcode\" extension will be documented in this file.\n\nCheck [Keep a Changelog]("
  },
  {
    "path": "LICENSE",
    "chars": 1097,
    "preview": "MIT License\n\nCopyright (c) 2020-present 力扣\nCopyright (c) 2018-2019 jdneo\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "README.md",
    "chars": 12194,
    "preview": "# LeetCode\n\n> Solve LeetCode problems in VS Code\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/LeetC"
  },
  {
    "path": "_config.yml",
    "chars": 26,
    "preview": "theme: jekyll-theme-cayman"
  },
  {
    "path": "docs/README_zh-CN.md",
    "chars": 10288,
    "preview": "# LeetCode\n\n> 在 VS Code 中练习 LeetCode\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/LeetCode-OpenSour"
  },
  {
    "path": "package.json",
    "chars": 30045,
    "preview": "{\n    \"name\": \"vscode-leetcode\",\n    \"displayName\": \"LeetCode\",\n    \"description\": \"Solve LeetCode problems in VS Code\","
  },
  {
    "path": "src/codelens/CodeLensController.ts",
    "chars": 1208,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { ConfigurationChangeEvent, Disp"
  },
  {
    "path": "src/codelens/CustomCodeLensProvider.ts",
    "chars": 3284,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/commands/cache.ts",
    "chars": 483,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { leetCodeExecutor } from \"../le"
  },
  {
    "path": "src/commands/language.ts",
    "chars": 1464,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { QuickPickItem, window, workspa"
  },
  {
    "path": "src/commands/list.ts",
    "chars": 2399,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { leetCodeExecutor } from \"../le"
  },
  {
    "path": "src/commands/plugin.ts",
    "chars": 3565,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/commands/session.ts",
    "chars": 5844,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/commands/show.ts",
    "chars": 12397,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as _ from \"lodash\";\nimport * a"
  },
  {
    "path": "src/commands/star.ts",
    "chars": 1406,
    "preview": "\n// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { customCodeLensProvider } from"
  },
  {
    "path": "src/commands/submit.ts",
    "chars": 1183,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/commands/test.ts",
    "chars": 3909,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as fse from \"fs-extra\";\nimport"
  },
  {
    "path": "src/explorer/LeetCodeNode.ts",
    "chars": 1643,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { Command, Uri } from \"vscode\";\n"
  },
  {
    "path": "src/explorer/LeetCodeTreeDataProvider.ts",
    "chars": 5808,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as os from \"os\";\nimport * as p"
  },
  {
    "path": "src/explorer/LeetCodeTreeItemDecorationProvider.ts",
    "chars": 1515,
    "preview": "import { URLSearchParams } from \"url\";\nimport { FileDecoration, FileDecorationProvider, ProviderResult, ThemeColor, Uri,"
  },
  {
    "path": "src/explorer/explorerNodeManager.ts",
    "chars": 7581,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as _ from \"lodash\";\nimport { D"
  },
  {
    "path": "src/extension.ts",
    "chars": 5988,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/globalState.ts",
    "chars": 1522,
    "preview": "// Copyright (c) leo.zhao. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\n\nc"
  },
  {
    "path": "src/leetCodeChannel.ts",
    "chars": 657,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\n\nclas"
  },
  {
    "path": "src/leetCodeExecutor.ts",
    "chars": 11413,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as cp from \"child_process\";\nim"
  },
  {
    "path": "src/leetCodeManager.ts",
    "chars": 7761,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as cp from \"child_process\";\nim"
  },
  {
    "path": "src/request/query-user-data.ts",
    "chars": 593,
    "preview": "import { UserDataType } from \"../globalState\";\nimport { getUrl } from \"../shared\";\nimport { LcAxios } from \"../utils/htt"
  },
  {
    "path": "src/shared.ts",
    "chars": 3772,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\n\nexpo"
  },
  {
    "path": "src/statusbar/LeetCodeStatusBarItem.ts",
    "chars": 1015,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/statusbar/leetCodeStatusBarController.ts",
    "chars": 1598,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { ConfigurationChangeEvent, Disp"
  },
  {
    "path": "src/utils/cpUtils.ts",
    "chars": 2601,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as cp from \"child_process\";\nim"
  },
  {
    "path": "src/utils/httpUtils.ts",
    "chars": 950,
    "preview": "import axios, { AxiosRequestConfig, AxiosPromise } from \"axios\";\nimport { omit } from \"lodash\";\nimport { globalState } f"
  },
  {
    "path": "src/utils/osUtils.ts",
    "chars": 479,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nexport function isWindows(): boolean {\n"
  },
  {
    "path": "src/utils/problemUtils.ts",
    "chars": 1160,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as fse from \"fs-extra\";\nimport"
  },
  {
    "path": "src/utils/settingUtils.ts",
    "chars": 2314,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { workspace, WorkspaceConfigurat"
  },
  {
    "path": "src/utils/toolUtils.ts",
    "chars": 857,
    "preview": "export function sleep(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function parseQuery("
  },
  {
    "path": "src/utils/trackingUtils.ts",
    "chars": 3809,
    "preview": "import * as vscode from \"vscode\";\nimport axios from \"axios\";\nimport { getLeetCodeEndpoint } from \"../commands/plugin\";\ni"
  },
  {
    "path": "src/utils/uiUtils.ts",
    "chars": 4633,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/utils/workspaceUtils.ts",
    "chars": 4656,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as fse from \"fs-extra\";\nimport"
  },
  {
    "path": "src/utils/wslUtils.ts",
    "chars": 912,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as vscode from \"vscode\";\nimpor"
  },
  {
    "path": "src/webview/LeetCodeWebview.ts",
    "chars": 3184,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { commands, ConfigurationChangeE"
  },
  {
    "path": "src/webview/leetCodePreviewProvider.ts",
    "chars": 7148,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { commands, ViewColumn } from \"v"
  },
  {
    "path": "src/webview/leetCodeSolutionProvider.ts",
    "chars": 3576,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { ViewColumn } from \"vscode\";\nim"
  },
  {
    "path": "src/webview/leetCodeSubmissionProvider.ts",
    "chars": 3782,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport { ViewColumn } from \"vscode\";\nim"
  },
  {
    "path": "src/webview/markdownEngine.ts",
    "chars": 6538,
    "preview": "// Copyright (c) jdneo. All rights reserved.\n// Licensed under the MIT license.\n\nimport * as hljs from \"highlight.js\";\ni"
  },
  {
    "path": "thirdpartynotice.txt",
    "chars": 10662,
    "preview": "THIRD-PARTY SOFTWARE NOTICES AND INFORMATION\nFor vscode-leetcode extension\n\nThis extension uses Open Source components. "
  },
  {
    "path": "tsconfig.json",
    "chars": 481,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"target\": \"es6\",\n        \"outDir\": \"out\",\n        \"lib\""
  },
  {
    "path": "tslint.json",
    "chars": 891,
    "preview": "{\n    \"defaultSeverity\": \"error\",\n    \"extends\": [\"tslint:recommended\"],\n    \"jsRules\": {},\n    \"rules\": {\n        \"obje"
  }
]

About this extraction

This page contains the full source code of the LeetCode-OpenSource/vscode-leetcode GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (217.7 KB), approximately 49.1k tokens, and a symbol index with 254 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!