├── .editorconfig ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── general---other.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci-cd.yml ├── .gitignore ├── .gitpod.dockerfile ├── .gitpod.yml ├── .npmignore ├── .theia └── settings.json ├── .vscode ├── c_cpp_properties.json ├── extensions.json ├── launch.json ├── settings.json └── theia.code-snippets ├── .yarnrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── NOTICE.md ├── README.md ├── configs ├── base.eslintrc.json ├── base.tsconfig.json ├── build.eslintrc.json ├── errors.eslintrc.json ├── mocha.opts ├── nyc.json ├── root-compilation.tsconfig.json ├── typedoc-tsconfig.json ├── typedoc.json ├── warnings.eslintrc.json └── xss.eslintrc.json ├── examples ├── browser │ ├── package.json │ └── webpack.config.js ├── cpp-debug-workspace │ ├── .theia │ │ ├── launch.json │ │ └── tasks.json │ ├── README.md │ └── a.cpp └── electron │ ├── .eslintrc.js │ ├── compile.tsconfig.json │ ├── package.json │ ├── test │ └── basic-example.spec.ts │ └── webpack.config.js ├── lerna.json ├── logo ├── EF_GRY-OR_svg.svg ├── theia-logo-no-text-black.svg ├── theia-logo-no-text-white.svg ├── theia-logo-white.svg ├── theia-logo.svg └── theia.svg ├── package.json ├── packages └── cpp-debug │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── compile.tsconfig.json │ ├── package.json │ └── src │ ├── browser │ ├── cpp-debug-frontend-contribution.ts │ ├── cpp-debug-frontend-module.ts │ ├── diff-widget │ │ ├── memory-diff-options-widget.tsx │ │ ├── memory-diff-select-widget.tsx │ │ ├── memory-diff-table-widget.tsx │ │ └── memory-diff-widget-types.ts │ ├── editable-widget │ │ └── memory-editable-table-widget.tsx │ ├── memory-provider │ │ ├── cdt-gdb-memory-provider.ts │ │ ├── memory-provider-service.ts │ │ ├── memory-provider.spec.ts │ │ └── memory-provider.ts │ ├── memory-widget │ │ ├── memory-options-widget.tsx │ │ ├── memory-table-widget.tsx │ │ └── memory-widget.ts │ ├── register-widget │ │ ├── register-filter-service.ts │ │ ├── register-options-widget.tsx │ │ ├── register-table-widget.tsx │ │ ├── register-widget-types.ts │ │ └── register-widget.css │ ├── style │ │ ├── index.css │ │ ├── memory-lock.svg │ │ ├── memory-view.svg │ │ ├── register-lock.svg │ │ └── register-view.svg │ ├── utils │ │ ├── memory-commands.ts │ │ ├── memory-hover-renderer.ts │ │ ├── memory-recents.ts │ │ ├── memory-widget-components.tsx │ │ ├── memory-widget-manager.ts │ │ ├── memory-widget-utils.tsx │ │ ├── memory-widget-variable-utils.ts │ │ ├── multi-select-bar.css │ │ └── multi-select-bar.tsx │ └── wrapper-widgets │ │ ├── memory-dock-panel.ts │ │ ├── memory-dockpanel-placeholder-widget.tsx │ │ └── memory-layout-widget.tsx │ └── common │ ├── util.ts │ └── utils.spec.ts ├── scripts ├── check-publish.js ├── check_git_status.sh ├── compile-references.js ├── lerna.js ├── post-install.js ├── prepare-initial.js └── run-reverse-topo.js ├── tsconfig.json ├── tsfmt.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | end_of_line = lf 6 | indent_style = space 7 | 8 | [*.{js,ts,md}] 9 | indent_size = 4 10 | 11 | [*.{json,yml}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | './configs/base.eslintrc.json', 6 | './configs/warnings.eslintrc.json', 7 | './configs/errors.eslintrc.json', 8 | './configs/xss.eslintrc.json' 9 | ], 10 | ignorePatterns: [ 11 | '**/{node_modules,lib}', 12 | 'plugins' 13 | ], 14 | parserOptions: { 15 | tsconfigRootDir: __dirname, 16 | project: 'tsconfig.json' 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description** 11 | 12 | 13 | **How to reproduce:** 14 | 15 | 16 | **Expected behavior** 17 | 18 | 19 | **Environment** 20 | - _OS_: 21 | - _Browser_: 22 | - _Theia Version_: 23 | 24 | **Additional information** 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description** 11 | 12 | 13 | **Additional information** 14 | 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general---other.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General - Other 3 | about: General issue for the project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description** 11 | 12 | 13 | **Additional Information** 14 | 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | #### What it does 9 | 10 | 11 | #### How to test 12 | 13 | 14 | #### Review checklist 15 | 16 | - [ ] as an author, I have thoroughly tested my changes and carefully followed [the review guidelines](https://github.com/theia-ide/theia/blob/master/doc/pull-requests.md#requesting-a-review) 17 | 18 | #### Reminder for reviewers 19 | 20 | - as a reviewer, I agree to behave in accordance with [the review guidelines](https://github.com/theia-ide/theia/blob/master/doc/pull-requests.md#reviewing) 21 | -------------------------------------------------------------------------------- /.github/workflows/ci-cd.yml: -------------------------------------------------------------------------------- 1 | name: CI-CD 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | schedule: 11 | - cron: '0 0 * * *' 12 | workflow_dispatch: 13 | 14 | 15 | jobs: 16 | build: 17 | runs-on: ${{ matrix.os }} 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | os: [windows-2019, ubuntu-18.04, macos-10.15] 23 | node: [12] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v2 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Use Node.js ${{ matrix.node }} 32 | uses: actions/setup-node@v1 33 | with: 34 | node-version: ${{ matrix.node }} 35 | 36 | - name: Build 37 | shell: bash 38 | run: | 39 | yarn install --no-lockfile 40 | yarn prepare 41 | env: 42 | NODE_OPTIONS: "--max_old_space_size=4096" 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9 44 | 45 | - name: Test 46 | uses: nick-invision/retry@v2 47 | with: 48 | timeout_minutes: 2 49 | max_attempts: 3 50 | retry_on: error 51 | command: npx lerna run --concurrency=1 --stream --scope "@theia/!(example-)*" test 52 | 53 | publish: 54 | needs: build 55 | if: ${{ github.event_name == 'push' }} 56 | 57 | runs-on: ubuntu-latest 58 | 59 | strategy: 60 | matrix: 61 | node: [12] 62 | 63 | steps: 64 | - name: Checkout 65 | uses: actions/checkout@v2 66 | with: 67 | persist-credentials: false 68 | 69 | - name: Use Node.js ${{ matrix.node }} 70 | uses: actions/setup-node@v1 71 | with: 72 | node-version: ${{ matrix.node }} 73 | registry-url: 'https://registry.npmjs.org' 74 | 75 | - name: Pre-Publish 76 | shell: bash 77 | run: yarn 78 | env: 79 | NODE_OPTIONS: --max_old_space_size=4096 80 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9 81 | 82 | - name: Publish 83 | uses: nick-invision/retry@v2 84 | with: 85 | timeout_minutes: 5 86 | retry_wait_seconds: 60 87 | max_attempts: 3 88 | retry_on: error 89 | command: yarn run publish:next 90 | env: 91 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} # The variable name comes from here: https://github.com/actions/setup-node/blob/70b9252472eee7495c93bb1588261539c3c2b98d/src/authutil.ts#L48 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | build 4 | lib 5 | *.log 6 | .idea 7 | .metadata 8 | *.iml 9 | jdt.ls-java-project 10 | lerna-debug.log 11 | .nyc_output 12 | coverage 13 | errorShots 14 | examples/*/src-gen 15 | examples/*/gen-webpack.config.js 16 | examples/*/.theia 17 | examples/*/.vscode 18 | examples/*/.test 19 | .browser_modules 20 | **/docs/api 21 | package-backup.json 22 | .history 23 | .Trash-* 24 | packages/plugin/typedoc 25 | plugins 26 | gh-pages 27 | .vscode/ipch 28 | dev-packages/electron/compile_commands.json 29 | *.tsbuildinfo 30 | .eslintcache 31 | -------------------------------------------------------------------------------- /.gitpod.dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM gitpod/workspace-full-vnc:latest 3 | 4 | # Docker build does not rebuild an image when a base image is changed, increase this counter to trigger it. 5 | ENV TRIGGER_REBUILD 3 6 | 7 | # Install custom tools, runtime, etc. 8 | RUN sudo apt-get update \ 9 | # window manager 10 | && sudo apt-get install -y jwm \ 11 | # electron 12 | && sudo apt-get install -y libgtk-3-0 libnss3 libasound2 libgbm1 \ 13 | # native-keymap 14 | && sudo apt-get install -y libx11-dev libxkbfile-dev \ 15 | && sudo rm -rf /var/lib/apt/lists/* 16 | 17 | ENV NODE_VERSION="12.14.1" 18 | RUN bash -c ". .nvm/nvm.sh \ 19 | && nvm install $NODE_VERSION \ 20 | && nvm use $NODE_VERSION \ 21 | && nvm alias default $NODE_VERSION \ 22 | && npm install -g yarn" 23 | ENV PATH=$HOME/.nvm/versions/node/v${NODE_VERSION}/bin:$PATH 24 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.dockerfile 3 | ports: 4 | - port: 3000 5 | - port: 6080 6 | onOpen: ignore 7 | - port: 5900 8 | onOpen: ignore 9 | tasks: 10 | - init: yarn 11 | command: > 12 | jwm & 13 | yarn --cwd browser-app start ../examples/cpp-debug-workspace/ 14 | github: 15 | prebuilds: 16 | pullRequestsFromForks: true 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | build 4 | *.log 5 | .idea 6 | .metadata 7 | jdt.ls-java-project 8 | lerna-debug.log 9 | .nyc_output 10 | coverage 11 | .browser_modules 12 | download 13 | *ui-spec.ts 14 | *slow-spec.ts 15 | test-resources 16 | -------------------------------------------------------------------------------- /.theia/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.insertSpaces": true, 4 | "[typescript]": { 5 | "editor.tabSize": 4 6 | }, 7 | "[json]": { 8 | "editor.tabSize": 2 9 | }, 10 | "[jsonc]": { 11 | "editor.tabSize": 2 12 | }, 13 | "typescript.tsdk": "node_modules/typescript/lib", 14 | "clang-format.language.typescript.enable": false 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "@theia/electron (Linux)", 5 | "compileCommands": "${workspaceFolder}/dev-packages/electron/compile_commands.json", 6 | "defines": [], 7 | "cStandard": "c89", 8 | "intelliSenseMode": "${default}" 9 | }, 10 | { 11 | "name": "@theia/electron Debug (Windows)", 12 | "compileCommands": "${workspaceFolder}\\dev-packages\\electron\\Debug\\compile_commands.json", 13 | "defines": [], 14 | "cStandard": "c89", 15 | "intelliSenseMode": "${default}" 16 | }, 17 | { 18 | "name": "@theia/electron Release (Windows)", 19 | "compileCommands": "${workspaceFolder}\\dev-packages\\electron\\Release\\compile_commands.json", 20 | "defines": [], 21 | "cStandard": "c89", 22 | "intelliSenseMode": "${default}" 23 | } 24 | ], 25 | "version": 4 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | // List of extensions which should be recommended for users of this workspace. 5 | "recommendations": [ 6 | "dbaeumer.vscode-eslint" 7 | ], 8 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 9 | "unwantedRecommendations": [] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Start Browser Backend", 11 | "program": "${workspaceRoot}/browser-app/src-gen/backend/main.js", 12 | "args": [ 13 | "--loglevel=debug", 14 | "--port=3000", 15 | "--no-cluster" 16 | ], 17 | "env": { 18 | "NODE_ENV": "development" 19 | }, 20 | "sourceMaps": true, 21 | "outFiles": [ 22 | "${workspaceRoot}/node_modules/@theia/*/lib/**/*.js", 23 | "${workspaceRoot}/browser-app/lib/**/*.js", 24 | "${workspaceRoot}/browser-app/src-gen/**/*.js" 25 | ], 26 | "smartStep": true, 27 | "internalConsoleOptions": "openOnSessionStart", 28 | "outputCapture": "std" 29 | }, 30 | { 31 | "type": "node", 32 | "request": "launch", 33 | "name": "Start Electron Backend", 34 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", 35 | "windows": { 36 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" 37 | }, 38 | "program": "${workspaceRoot}/electron-app/src-gen/frontend/electron-main.js", 39 | "protocol": "inspector", 40 | "args": [ 41 | "--loglevel=debug", 42 | "--hostname=localhost", 43 | "--no-cluster" 44 | ], 45 | "env": { 46 | "NODE_ENV": "development" 47 | }, 48 | "sourceMaps": true, 49 | "outFiles": [ 50 | "${workspaceRoot}/electron-app/src-gen/frontend/electron-main.js", 51 | "${workspaceRoot}/electron-app/src-gen/backend/main.js", 52 | "${workspaceRoot}/electron-app/lib/**/*.js", 53 | "${workspaceRoot}/node_modules/@theia/*/lib/**/*.js" 54 | ], 55 | "smartStep": true, 56 | "internalConsoleOptions": "openOnSessionStart", 57 | "outputCapture": "std" 58 | }, 59 | { 60 | "name": "Launch Frontend", 61 | "type": "chrome", 62 | "request": "launch", 63 | "url": "http://localhost:3000/", 64 | "webRoot": "${workspaceRoot}", 65 | "sourceMapPathOverrides": { 66 | "*": "${webRoot}/*" 67 | } 68 | }, 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // If one would like to add/remove/modify user preferences without modifying the content of the 2 | // workspace settings file, then one would need to modify the `settings.json` under here: 3 | // - Windows: %APPDATA%\Code\User\settings.json 4 | // - Linux: $HOME/.config/Code/User/settings.json 5 | // - Mac: $HOME/Library/Application Support/Code/User/settings.json 6 | { 7 | "tslint.enable": true, 8 | "editor.formatOnSave": true, 9 | "search.exclude": { 10 | "**/node_modules": true, 11 | "**/lib": true, 12 | "**/coverage": true 13 | }, 14 | "lcov.path": [ 15 | "packages/core/coverage/lcov.info", 16 | "packages/editor/coverage/lcov.info", 17 | "packages/filesystem/coverage/lcov.info", 18 | "packages/go/coverage/lcov.info", 19 | "packages/java/coverage/lcov.info", 20 | "packages/languages/coverage/lcov.info", 21 | "packages/monaco/coverage/lcov.info", 22 | "packages/navigator/coverage/lcov.info", 23 | "packages/keymaps/coverage/lcov.info", 24 | "packages/preferences/coverage/lcov.info", 25 | "packages/process/coverage/lcov.info", 26 | "packages/python/coverage/lcov.info", 27 | "packages/terminal/coverage/lcov.info", 28 | "packages/workspace/coverage/lcov.info", 29 | "packages/task/coverage/lcov.info", 30 | "packages/monaco-textmate/coverage/lcov.info" 31 | ], 32 | "lcov.watch": [ 33 | { 34 | "pattern": "**/*.spec.ts", 35 | "command": "yarn test:theia" 36 | } 37 | ], 38 | "editor.insertSpaces": true, 39 | "[typescript]": { 40 | "editor.tabSize": 4, 41 | "editor.defaultFormatter": "vscode.typescript-language-features", 42 | }, 43 | "[javascript]": { 44 | "editor.tabSize": 4, 45 | "editor.defaultFormatter": "vscode.typescript-language-features" 46 | }, 47 | "[json]": { 48 | "editor.tabSize": 2, 49 | "editor.defaultFormatter": "vscode.json-language-features", 50 | }, 51 | "[jsonc]": { 52 | "editor.tabSize": 2, 53 | "editor.defaultFormatter": "vscode.json-language-features", 54 | }, 55 | "typescript.tsdk": "node_modules/typescript/lib", 56 | "files.insertFinalNewline": true, 57 | "clang-format.language.typescript.enable": false, 58 | "editor.rulers": [ 59 | 180 60 | ], // ESLint `max-len` rule. 61 | } 62 | -------------------------------------------------------------------------------- /.vscode/theia.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Copyright-JS/JSX/TS/TSX/CSS": { 3 | "prefix": [ 4 | "header", 5 | "copyright" 6 | ], 7 | "body": "/********************************************************************************\n * Copyright (C) $CURRENT_YEAR ${YourCompany} and others.\n *\n * This program and the accompanying materials are made available under the\n * terms of the Eclipse Public License v. 2.0 which is available at\n * http://www.eclipse.org/legal/epl-2.0.\n *\n * This Source Code may also be made available under the following Secondary\n * Licenses when the conditions for such availability set forth in the Eclipse\n * Public License v. 2.0 are satisfied: GNU General Public License, version 2\n * with the GNU Classpath Exception which is available at\n * https://www.gnu.org/software/classpath/license.html.\n *\n * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0\n ********************************************************************************/\n\n$0", 8 | "description": "Adds the copyright...", 9 | "scope": "javascript,javascriptreact,typescript,typescriptreact,css" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | unsafe-disable-integrity-migration true 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | # Community Code of Conduct 9 | Version 1.0 10 | June 23, 2015 11 | 12 | As members of the Eclipse community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting code reviews, pull requests, patches, and other activities. 13 | 14 | We are committed to making participation in the Eclipse community a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion or analogous grounds. 15 | 16 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 17 | 18 | Eclipse Foundation staff have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project leaders, committers and contributors who do not follow the Code of Conduct may be removed from the project. 19 | 20 | This code of conduct applies within Eclipse project spaces, or in public spaces when an individual is representing the project or the Eclipse community. 21 | 22 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by emailing the Eclipse Management Organization: codeofconduct@eclipse.org. 23 | 24 | This Code of Conduct is adapted from the Contributor Covenant (http://contributor-covenant.org), version 1.1.0, available at http://contributor-covenant.org/version/1/1/0/ 25 | 26 | 27 | 31 | 32 | ---- 33 | Note: Please see [here](https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php) for the latest version of this document, hosted at the Eclipse Foundation -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Eclipse Theia C/C++ Extensions 2 | 3 | This repository is the home to Theia's C/C++ extensions. 4 | 5 | See Theia's main repository to get more information about the IDE: 6 | https://github.com/eclipse/theia 7 | 8 | ## How Can I Contribute? 9 | 10 | In the following some of the typical ways of contribution are described. 11 | 12 | ### Asking Questions 13 | 14 | It's totally fine to ask questions by opening an issue in the Theia GitHub 15 | repository. We will close it once it's answered and tag it with the 'question' 16 | label. Please check if the question has been asked before there or on [Stack 17 | Overflow](https://stackoverflow.com). 18 | 19 | ### Reporting Bugs 20 | 21 | If you have found a bug, you should first check if it has already been filed 22 | and maybe even fixed. If you find an existing unresolved issue, please add your 23 | case. If you could not find an existing bug report, please file a new one. In 24 | any case, please add all information you can share and that will help to 25 | reproduce and solve the problem. 26 | 27 | ### Reporting Feature Requests 28 | 29 | You may want to see a feature or have an idea. You can file a request and we 30 | can discuss it. If such a feature request already exists, please add a comment 31 | or some other form of feedback to indicate you are interested too. Also in this 32 | case any concrete use case scenario is appreciated to understand the motivation 33 | behind it. 34 | 35 | ### Pull Requests 36 | 37 | Before you get started investing significant time in something you want to get 38 | merged and maintained as part of Theia, you should talk with the team through 39 | an issue. Simply choose the issue you would want to work on, and tell everyone 40 | that you are willing to do so and how you would approach it. The team will be 41 | happy to guide you and give feedback. 42 | 43 | ## Coding Guidelines 44 | 45 | We follow the coding guidelines described 46 | [here](https://github.com/eclipse/theia/wiki/Coding-Guidelines). 47 | 48 | ## Eclipse Contributor Agreement 49 | 50 | Before your contribution can be accepted by the project team contributors must 51 | electronically sign the Eclipse Contributor Agreement (ECA). 52 | 53 | * http://www.eclipse.org/legal/ECA.php 54 | 55 | Commits that are provided by non-committers must have a Signed-off-by field in 56 | the footer indicating that the author is aware of the terms by which the 57 | contribution has been provided to the project. The non-committer must 58 | additionally have an Eclipse Foundation account and must have a signed Eclipse 59 | Contributor Agreement (ECA) on file. 60 | 61 | For more information, please see the Eclipse Committer Handbook: 62 | https://www.eclipse.org/projects/handbook/#resources-commit 63 | 64 | ## Sign your work 65 | 66 | The sign-off is a simple line at the end of the explanation for the patch. Your 67 | signature certifies that you wrote the patch or otherwise have the right to 68 | pass it on as an open-source patch. 69 | 70 | Signed-off-by: Joe Smith 71 | 72 | Use your real name (sorry, no pseudonyms or anonymous contributions.) 73 | 74 | If you set your `user.name` and `user.email` git configs, you can sign your 75 | commit automatically with `git commit -s`. 76 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | # Notices for Eclipse Theia - Cpp Extension 2 | 3 | This content is produced and maintained by the Eclipse Theia project. 4 | 5 | * Project home: https://projects.eclipse.org/projects/ecd.theia 6 | 7 | ## Copyright 8 | 9 | All content is the property of the respective authors or their employers. For 10 | more information regarding authorship of content, please consult the listed 11 | source code repository logs. 12 | 13 | ## Declared Project Licenses 14 | 15 | This program and the accompanying materials are made available under the terms 16 | of the Eclipse Public License v. 2.0 which is available at 17 | http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made 18 | available under the following Secondary Licenses when the conditions for such 19 | availability set forth in the Eclipse Public License v. 2.0 are satisfied: GNU 20 | General Public License, version 2 with the GNU Classpath Exception which is 21 | available at https://www.gnu.org/software/classpath/license.html. 22 | 23 | SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 24 | 25 | ## Third-party Content 26 | 27 | See overall third-party content notices in the main repository at 28 | https://github.com/eclipse-theia/theia/blob/master/NOTICE.md#third-party-content 29 | 30 | ## Cryptography 31 | 32 | Content may contain encryption software. The country in which you are currently 33 | may have restrictions on the import, possession, and use, and/or re-export to 34 | another country, of encryption software. BEFORE using any encryption software, 35 | please check the country's laws, regulations and policies concerning the import, 36 | possession, or use, and re-export of encryption software, to see if this is 37 | permitted. 38 | 39 | ## Electron 40 | 41 | NOTICE: 42 | 43 | Please note Electron combines Chromium and Node.js into a single runtime. 44 | While Electron, Chromium and Node.js are generally licensed under very 45 | permissive MIT and BSD-3-Clause licenses, both Electron and Chromium distribute 46 | FFmpeg. While FFmpeg is under the LGPL-2.1-or-later license it incorporates 47 | several optional parts and optimizations that are covered by the 48 | GPL-2.0-or-later. We understand both Electron and Chromium do not distribute 49 | versions of FFmpeg with GPL content enabled; however, FFmpeg may be configured 50 | enabled to work with proprietary codecs. It is our understanding these 51 | proprietary codecs may be patented; and as a result, may be subject to 52 | licensing fees. 53 | 54 | We strongly recommend downstream consumers verify the type of FFmpeg support 55 | configured and modify as required. More information on instructions to verify 56 | can be found here 57 | https://electronjs.org/docs/development/upgrading-chromium#verify-ffmpeg-support 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | theia logo 4 | 5 |

ECLIPSE THEIA - C/C++ EXTENSIONS

6 | 7 |
8 | 9 | [![Gitpod - Code Now](https://img.shields.io/badge/Gitpod-code%20now-blue.svg?longCache=true)](https://gitpod.io#https://github.com/eclipse-theia/theia-cpp-extensions) 10 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-curved)](https://github.com/eclipse-theia/theia-cpp-extensions/labels/help%20wanted) 11 | [![CI-CD](https://github.com/eclipse-theia/theia-cpp-extensions/workflows/CI-CD/badge.svg?branch=master)](https://github.com/eclipse-theia/theia-cpp-extensions/actions?query=branch%3Amaster) 12 | [![Open questions](https://img.shields.io/badge/Open-questions-blue.svg?style=flat-curved)](https://github.com/eclipse-theia/theia-cpp-extensions/labels/question) 13 | [![Open bugs](https://img.shields.io/badge/Open-bugs-red.svg?style=flat-curved)](https://github.com/eclipse-theia/theia-cpp-extensions/labels/bug) 14 | 15 | 16 |
17 | 18 |
19 | 20 | ## Overview 21 | Collection of Theia extensions related to C/C++ development. 22 | 23 | ## Features 24 | - `@theia/cpp-debug`: 25 | - Debugging support using `GDB` through the `cdt-gdb-vscode` extension. 26 | - Memory view (monitor process memory during debug sessions). 27 | - `@theia/cpp` **deprecated** and **removed** ([past sources](https://github.com/eclipse-theia/theia-cpp-extensions/tree/184f7751f13e1ec021ccae3f076915867168d28d/packages/cpp)): 28 | - **Deprecated** C/C++ language-features extension.\ 29 | (Language-features should instead be contributed by VS Code extensions). 30 | 31 | ## How to build 32 | The `browser-app` and `electron-app` directories contain examples of Theia-based applications which use the extensions 33 | provided by the repository. 34 | 35 | - `browser-app` build instructions: 36 | ```bash 37 | $ yarn 38 | $ yarn rebuild:browser 39 | $ cd browser-app && yarn start 40 | ``` 41 | 42 | - `electron-app` build instructions: 43 | ```bash 44 | $ yarn 45 | $ yarn rebuild:electron 46 | $ cd electron-app && yarn start 47 | ``` 48 | 49 | ## Example Workspaces 50 | - [`cpp-debug-workspace`](./examples/cpp-debug-workspace/README.md) 51 | - provides an easy and reproducible way to test the functionality present in the `@theia/cpp-debug` extension. Includes a simple C/C++ program, debug launch configuration file (`launch.json`), and a task in order to compile the program (`tasks.json`). 52 | 53 | ## License 54 | 55 | - [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/) 56 | - [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp) 57 | 58 | ## Trademark 59 | "Theia" is a trademark of the Eclipse Foundation 60 | https://www.eclipse.org/theia 61 | -------------------------------------------------------------------------------- /configs/base.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 6, 6 | "ecmaFeatures": { 7 | "jsx": true 8 | } 9 | }, 10 | "plugins": [ 11 | "@typescript-eslint", 12 | "@typescript-eslint/tslint", 13 | "import", 14 | "no-null" 15 | ], 16 | "env": { 17 | "browser": true, 18 | "mocha": true, 19 | "node": true 20 | }, 21 | "ignorePatterns": [ 22 | "node_modules", 23 | "lib" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /configs/base.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "skipLibCheck": true, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "noImplicitAny": true, 7 | "noEmitOnError": false, 8 | "noImplicitThis": true, 9 | "noUnusedLocals": true, 10 | "strictNullChecks": true, 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata": true, 13 | "downlevelIteration": true, 14 | "resolveJsonModule": true, 15 | "module": "commonjs", 16 | "moduleResolution": "node", 17 | "target": "ES2017", 18 | "jsx": "react", 19 | "lib": [ 20 | "ES2017", 21 | "dom" 22 | ], 23 | "sourceMap": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /configs/build.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "./base.eslintrc.json", 4 | "./errors.eslintrc.json" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /configs/errors.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/eslintrc", 3 | "rules": { 4 | "@typescript-eslint/consistent-type-definitions": "error", 5 | "@typescript-eslint/indent": "off", 6 | "@typescript-eslint/no-explicit-any": "error", 7 | "@typescript-eslint/quotes": [ 8 | "error", 9 | "single", 10 | { 11 | "avoidEscape": true 12 | } 13 | ], 14 | "@typescript-eslint/semi": [ 15 | "error", 16 | "always" 17 | ], 18 | "@typescript-eslint/type-annotation-spacing": "error", 19 | "arrow-body-style": [ 20 | "error", 21 | "as-needed" 22 | ], 23 | "arrow-parens": [ 24 | "error", 25 | "as-needed" 26 | ], 27 | "camelcase": "off", 28 | "comma-dangle": "off", 29 | "curly": "error", 30 | "eol-last": "error", 31 | "eqeqeq": [ 32 | "error", 33 | "smart" 34 | ], 35 | "guard-for-in": "error", 36 | "id-blacklist": "off", 37 | "id-match": "off", 38 | "max-len": [ 39 | "error", 40 | { 41 | "code": 180 42 | } 43 | ], 44 | "no-magic-numbers": "off", 45 | "no-multiple-empty-lines": [ 46 | "error", 47 | { 48 | "max": 1 49 | } 50 | ], 51 | "no-new-wrappers": "error", 52 | "no-null/no-null": "error", 53 | "no-shadow": "off", 54 | "@typescript-eslint/no-shadow": [ 55 | "error", 56 | { 57 | "hoist": "all" 58 | } 59 | ], 60 | "no-tabs": "error", 61 | "no-throw-literal": "error", 62 | "no-trailing-spaces": "error", 63 | "no-underscore-dangle": "off", 64 | "no-unused-expressions": "error", 65 | "no-var": "error", 66 | "no-void": "error", 67 | "one-var": [ 68 | "error", 69 | "never" 70 | ], 71 | "prefer-const": [ 72 | "error", 73 | { 74 | "destructuring": "all" 75 | } 76 | ], 77 | "radix": "off", 78 | "space-before-function-paren": [ 79 | "error", 80 | { 81 | "anonymous": "always", 82 | "named": "never", 83 | "asyncArrow": "always" 84 | } 85 | ], 86 | "spaced-comment": [ 87 | "error", 88 | "always", 89 | { 90 | "exceptions": [ 91 | "*", 92 | "+", 93 | "-", 94 | "/" 95 | ] 96 | } 97 | ], 98 | "@typescript-eslint/tslint/config": [ 99 | "error", 100 | { 101 | "rules": { 102 | "file-header": [ 103 | true, 104 | "SPDX-License-Identifier: EPL-2\\.0 OR GPL-2\\.0 WITH Classpath-exception-2\\.0" 105 | ], 106 | "jsdoc-format": [ 107 | true, 108 | "check-multiline-start" 109 | ], 110 | "one-line": [ 111 | true, 112 | "check-open-brace", 113 | "check-catch", 114 | "check-else", 115 | "check-whitespace" 116 | ], 117 | "typedef": [ 118 | true, 119 | "call-signature", 120 | "property-declaration" 121 | ], 122 | "whitespace": [ 123 | true, 124 | "check-branch", 125 | "check-decl", 126 | "check-operator", 127 | "check-separator", 128 | "check-type" 129 | ] 130 | } 131 | } 132 | ], 133 | "import/no-extraneous-dependencies": "error" 134 | }, 135 | "overrides": [ 136 | { 137 | "files": [ 138 | "dev-packages", 139 | "*.{spec,espec,slow-spec}.{js,ts}" 140 | ], 141 | "rules": { 142 | "@theia/shared-dependencies": "off", 143 | "import/no-extraneous-dependencies": "off" 144 | } 145 | } 146 | ] 147 | } 148 | -------------------------------------------------------------------------------- /configs/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ignore-styles 2 | --require reflect-metadata/Reflect 3 | --reporter spec 4 | --watch-extensions js 5 | --exit 6 | -------------------------------------------------------------------------------- /configs/nyc.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/**/*.ts" 4 | ], 5 | "exclude": [ 6 | "src/typings", 7 | "src/**/*.spec.ts" 8 | ], 9 | "reporter": [ 10 | "html", 11 | "lcov" 12 | ], 13 | "extension": [ 14 | ".ts" 15 | ], 16 | "all": true 17 | } -------------------------------------------------------------------------------- /configs/root-compilation.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./base.tsconfig", 3 | "include": [], 4 | "compilerOptions": { 5 | "composite": true, 6 | "rootDir": "src", 7 | "outDir": "lib" 8 | }, 9 | "references": [ 10 | { 11 | "path": "../examples/electron/compile.tsconfig.json" 12 | }, 13 | { 14 | "path": "../packages/cpp-debug/compile.tsconfig.json" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /configs/typedoc-tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | "skipLibCheck": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /configs/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignoreCompilerErrors": true, 3 | "mode": "modules", 4 | "out": "gh-pages/docs/next", 5 | "excludeExternals": true, 6 | "includeDeclarations": true, 7 | "readme": "README.md", 8 | "module": "commonjs", 9 | "target": "ES2017", 10 | "hideGenerator": true, 11 | "external-modulemap": ".*\/packages\/([\\w\\-_]+)\/", 12 | "name": "Theia TypeDoc", 13 | "exclude": [ 14 | "**/+(dev-packages|examples|typings)/**/*", 15 | "**/*spec.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /configs/warnings.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "deprecation" 4 | ], 5 | "rules": { 6 | "@typescript-eslint/await-thenable": "warn", 7 | "no-return-await": "warn", 8 | "deprecation/deprecation": "warn" 9 | } 10 | } -------------------------------------------------------------------------------- /configs/xss.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:no-unsanitized/DOM"], 3 | "plugins": ["no-unsanitized", "react"], 4 | "parserOptions": { 5 | "ecmaFeatures": { 6 | "jsx": true 7 | } 8 | }, 9 | "rules": { 10 | "no-unsanitized/method": [ 11 | "warn", { 12 | "escape": { 13 | "methods": ["DOMPurify.sanitize"] 14 | } 15 | } 16 | ], 17 | "no-unsanitized/property": [ 18 | "warn", { 19 | "escape": { 20 | "methods": ["DOMPurify.sanitize"] 21 | } 22 | } 23 | ], 24 | "no-eval": "warn", 25 | "no-implied-eval": "warn", 26 | "react/no-danger-with-children": "warn", 27 | "react/no-danger": "warn" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "@cpp-debug/example-browser", 4 | "version": "1.19.0", 5 | "license": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0", 6 | "theia": { 7 | "frontend": { 8 | "config": { 9 | "applicationName": "Theia C/++ Browser Example", 10 | "preferences": { 11 | "files.enableTrash": false 12 | } 13 | } 14 | } 15 | }, 16 | "dependencies": { 17 | "@theia/core": "1.27.0", 18 | "@theia/cpp-debug": "1.27.0", 19 | "@theia/editor": "1.27.0", 20 | "@theia/file-search": "1.27.0", 21 | "@theia/filesystem": "1.27.0", 22 | "@theia/markers": "1.27.0", 23 | "@theia/messages": "1.27.0", 24 | "@theia/monaco": "1.27.0", 25 | "@theia/navigator": "1.27.0", 26 | "@theia/plugin-ext-vscode": "1.27.0", 27 | "@theia/preferences": "1.27.0", 28 | "@theia/process": "1.27.0", 29 | "@theia/task": "1.27.0", 30 | "@theia/terminal": "1.27.0", 31 | "@theia/typehierarchy": "1.27.0", 32 | "@theia/workspace": "1.27.0" 33 | }, 34 | "scripts": { 35 | "prepare": "yarn run clean && yarn build", 36 | "clean": "theia clean", 37 | "build": "theia build --mode development", 38 | "watch": "yarn build --watch", 39 | "start": "theia start --plugins=local-dir:../../plugins", 40 | "start:debug": "yarn start --log-level=debug", 41 | "test": "echo 'No tests implemented' || theia test . --plugins=local-dir:../../plugins --test-spec=../api-tests/**/*.spec.js", 42 | "test:debug": "yarn test --test-inspect", 43 | "coverage": "yarn test --test-coverage && yarn coverage:report", 44 | "coverage:report": "nyc report --reporter=html", 45 | "coverage:clean": "rimraf .nyc_output && rimraf coverage" 46 | }, 47 | "devDependencies": { 48 | "@theia/cli": "1.27.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/browser/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file can be edited to customize webpack configuration. 3 | * To reset delete this file and rerun theia build again. 4 | */ 5 | // @ts-check 6 | const config = require('./gen-webpack.config.js'); 7 | 8 | /** 9 | * Expose bundled modules on window.theia.moduleName namespace, e.g. 10 | * window['theia']['@theia/core/lib/common/uri']. 11 | * Such syntax can be used by external code, for instance, for testing. 12 | */ 13 | config.module.rules.push({ 14 | test: /\.js$/, 15 | loader: require.resolve('@theia/application-manager/lib/expose-loader') 16 | }); 17 | 18 | module.exports = config; 19 | -------------------------------------------------------------------------------- /examples/cpp-debug-workspace/.theia/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "test-cpp", 5 | "request": "launch", 6 | "type": "gdb", 7 | "program": "${workspaceFolder}/build/a", 8 | "verbose": true, 9 | "logFile": "/tmp/a.out" 10 | }, 11 | { 12 | "name": "cpp local remote", 13 | "type": "gdbtarget", 14 | "program": "${workspaceFolder}/build/a", 15 | "request": "launch" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examples/cpp-debug-workspace/.theia/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "label": "compile example", 5 | "type": "shell", 6 | "command": "mkdir -p build && cd build && g++ -g3 -O0 ../a.cpp -o a", 7 | "options": { 8 | "cwd": "${workspaceFolder}" 9 | }, 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "problemMatcher": [] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /examples/cpp-debug-workspace/README.md: -------------------------------------------------------------------------------- 1 | ## Eclipse Theia - `@theia/cpp-debug` example workspace 2 | 3 | --- 4 | 5 | ### Description 6 | 7 | The workspace provides an easy and reproducible way to test the functionality present in the `@theia/cpp-debug` extension. 8 | 9 | note: ATM debugging does not work in Gitpod. Since GDB uses ptrace to attach to the debuggee and ptrace requires the docker container to be started with special permissions. 10 | 11 | ### Key Features 12 | 13 | 1. `a.cpp`: simple C/C++ program for debug purposes 14 | 2. `tasks.json`: task configuration file (executes the compilation of the C/C++ program) 15 | 3. `launch.json`: debug launch configuration file (launches the debug session) 16 | 17 | ### Use Cases 18 | 19 | **Testing the `memory-view`** 20 | 21 | 1. open `cpp-debug-workspace` as a workspace. 22 | 2. compile the program (use `F1` + `Run Task...` and select `compile example`) 23 | 3. set breakpoint(s) in `a.cpp` 24 | 4. start the debug session using `Debug` + `Start Debugging` from the main menu 25 | 5. open the `memory-view` using `View` + `Memory` from the main menu 26 | 6. in the memory view, input `$sp` in the location input field (the `memory-view` should display output) 27 | -------------------------------------------------------------------------------- /examples/cpp-debug-workspace/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | void printInt(int a) 6 | { 7 | cout << "value: " << a << endl; 8 | } 9 | 10 | char get_char(int i) 11 | { 12 | switch (i) { 13 | case 10: 14 | return 'a'; 15 | case 11: 16 | return 'f'; 17 | case 12: 18 | return 't'; 19 | case 13: 20 | return 'e'; 21 | case 14: 22 | return 'r'; 23 | case 15: 24 | return '!'; 25 | default: 26 | return '\n'; 27 | } 28 | } 29 | 30 | int main() 31 | { 32 | int i, j; 33 | char single_char[] = {'b', 'e', 'f', 'o', 'r', 'e'}; 34 | for (i = 10; i < 20; i++) { 35 | j += 5; 36 | if (i >= 10 && i <= 15) 37 | { 38 | single_char[i-10] = get_char(i); 39 | } 40 | printInt(j); 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /examples/electron/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: [ 4 | '../../configs/build.eslintrc.json' 5 | ], 6 | parserOptions: { 7 | tsconfigRootDir: __dirname, 8 | project: 'compile.tsconfig.json' 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /examples/electron/compile.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../configs/base.tsconfig", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "lib/test" 6 | }, 7 | "include": [ 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../../packages/cpp-debug/compile.tsconfig.json" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /examples/electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "@cpp-debug/example-electron", 4 | "productName": "Theia CPP Extensions Electron Example", 5 | "version": "1.19.0", 6 | "main": "src-gen/frontend/electron-main.js", 7 | "license": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0", 8 | "theia": { 9 | "target": "electron", 10 | "frontend": { 11 | "config": { 12 | "applicationName": "Theia C/++ Electron Example" 13 | } 14 | } 15 | }, 16 | "dependencies": { 17 | "@theia/core": "1.27.0", 18 | "@theia/cpp-debug": "1.27.0", 19 | "@theia/editor": "1.27.0", 20 | "@theia/electron": "1.27.0", 21 | "@theia/file-search": "1.27.0", 22 | "@theia/filesystem": "1.27.0", 23 | "@theia/markers": "1.27.0", 24 | "@theia/messages": "1.27.0", 25 | "@theia/monaco": "1.27.0", 26 | "@theia/navigator": "1.27.0", 27 | "@theia/plugin-ext-vscode": "1.27.0", 28 | "@theia/preferences": "1.27.0", 29 | "@theia/process": "1.27.0", 30 | "@theia/task": "1.27.0", 31 | "@theia/terminal": "1.27.0", 32 | "@theia/typehierarchy": "1.27.0", 33 | "@theia/workspace": "1.27.0" 34 | }, 35 | "scripts": { 36 | "lint": "if-env SKIP_LINT=true && echo 'skip lint check' || eslint --cache=true --no-error-on-unmatched-pattern=true \"{src,test}/**/*.{ts,tsx}\"", 37 | "clean": "theia clean", 38 | "build": "tsc -b compile.tsconfig.json && yarn bundle", 39 | "bundle": "theia build --mode development", 40 | "watch": "concurrently -n compile,bundle \"tsc -p compile.tsconfig.json -w --preserveWatchOutput\" \"theia build --watch --mode development\"", 41 | "start": "theia start --plugins=local-dir:../../plugins", 42 | "start:debug": "yarn start --log-level=debug", 43 | "test": "electron-mocha --timeout 60000 \"./lib/test/**/*.espec.js\"" 44 | }, 45 | "devDependencies": { 46 | "@theia/cli": "1.27.0", 47 | "electron": "^15.3.5" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/electron/test/basic-example.spec.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2017 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { app, BrowserWindow } from '@theia/core/electron-shared/@electron/remote'; 18 | import * as chai from 'chai'; 19 | import * as path from 'path'; 20 | 21 | const expect = chai.expect; 22 | 23 | describe.skip('basic-example-spec', () => { 24 | 25 | const mainWindow = new BrowserWindow({ show: false }); 26 | mainWindow.on('ready-to-show', () => mainWindow.show()); 27 | 28 | describe('01 #start example app', () => { 29 | it('should start the electron example app', async () => { 30 | if (!app.isReady()) { 31 | await new Promise(resolve => app.on('ready', resolve)); 32 | } 33 | 34 | require('../src-gen/backend/main'); // start the express server 35 | 36 | mainWindow.webContents.openDevTools(); 37 | mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`); 38 | 39 | // eslint-disable-next-line no-unused-expressions 40 | expect(mainWindow.isVisible()).to.be.true; 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /examples/electron/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file can be edited to customize webpack configuration. 3 | * To reset delete this file and rerun theia build again. 4 | */ 5 | // @ts-check 6 | const config = require('./gen-webpack.config.js'); 7 | 8 | /** 9 | * Expose bundled modules on window.theia.moduleName namespace, e.g. 10 | * window['theia']['@theia/core/lib/common/uri']. 11 | * Such syntax can be used by external code, for instance, for testing. 12 | config.module.rules.push({ 13 | test: /\.js$/, 14 | loader: require.resolve('@theia/application-manager/lib/expose-loader') 15 | }); */ 16 | 17 | module.exports = config; 18 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.13.2", 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "version": "1.27.0", 6 | "command": { 7 | "run": { 8 | "stream": true 9 | }, 10 | "publish": { 11 | "forcePublish": true, 12 | "skipGit": true, 13 | "registry": "https://registry.npmjs.org/" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /logo/EF_GRY-OR_svg.svg: -------------------------------------------------------------------------------- 1 | EF_all_colours_ai -------------------------------------------------------------------------------- /logo/theia-logo-no-text-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /logo/theia-logo-no-text-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /logo/theia-logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /logo/theia-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /logo/theia.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "@theia/cpp-extensions", 4 | "version": "0.0.0", 5 | "engines": { 6 | "yarn": "1.0.x || >=1.2.1", 7 | "node": ">=14" 8 | }, 9 | "resolutions": { 10 | "**/@types/node": "12", 11 | "**/node-abi": "^2.18.0" 12 | }, 13 | "devDependencies": { 14 | "@theia/cli": "1.27.0", 15 | "@typescript-eslint/eslint-plugin": "^4.8.1", 16 | "@typescript-eslint/eslint-plugin-tslint": "^4.8.1", 17 | "@typescript-eslint/parser": "^4.8.1", 18 | "electron-mocha": "^8.2.0", 19 | "eslint": "^7.14.0", 20 | "eslint-plugin-deprecation": "^1.1.0", 21 | "eslint-plugin-import": "^2.22.1", 22 | "eslint-plugin-no-null": "^1.0.2", 23 | "eslint-plugin-no-unsanitized": "^3.1.4", 24 | "eslint-plugin-react": "^7.21.5", 25 | "if-env": "^1.0.4", 26 | "ignore-styles": "^5.0.1", 27 | "lerna": "3.13.2", 28 | "nyc": "^15.0.0", 29 | "rimraf": "3.0.2", 30 | "tslint": "^5.12.0", 31 | "typescript": "~4.5.5" 32 | }, 33 | "dependencies": { 34 | "@types/node": "12", 35 | "node-abi": "^2.18.0" 36 | }, 37 | "scripts": { 38 | "preinstall": "node-gyp install", 39 | "postinstall": "node scripts/post-install.js", 40 | "prepare": "yarn prepare:references && yarn prepare:build && yarn prepare:hoisting && yarn download:plugins", 41 | "prepare:references": "node scripts/compile-references.js", 42 | "prepare:build": "yarn build && lerna run lint && lerna run build \"@theia/example-*\" --stream --parallel", 43 | "prepare:hoisting": "theia check:hoisted -s", 44 | "clean": "yarn lint:clean && node scripts/run-reverse-topo.js yarn clean", 45 | "build": "tsc -b configs/root-compilation.tsconfig.json", 46 | "watch": "tsc -b configs/root-compilation.tsconfig.json -w", 47 | "lint": "lerna run lint", 48 | "lint:clean": "rimraf .eslintcache", 49 | "lint:oneshot": "node --max-old-space-size=4096 node_modules/eslint/bin/eslint.js --cache=true \"{dev-packages,packages,examples}/**/*.{ts,tsx}\"", 50 | "test": "yarn test:references && yarn test:theia && yarn test:electron && yarn test:browser", 51 | "test:references": "node scripts/compile-references --dry-run", 52 | "test:theia": "lerna run test \"@theia/!(example-)*\" --stream --concurrency=1", 53 | "test:browser": "yarn rebuild:browser && lerna run test \"@theia/example-browser\"", 54 | "test:electron": "yarn rebuild:electron && lerna run test \"@theia/example-electron\"", 55 | "rebuild:clean": "rimraf .browser_modules", 56 | "rebuild:browser": "theia rebuild:browser", 57 | "rebuild:electron": "theia rebuild:electron", 58 | "rebuild:electron:debug": "DEBUG=electron-rebuild && yarn rebuild:electron", 59 | "publish": "yarn && yarn test && yarn publish:latest", 60 | "publish:latest": "lerna publish --exact && yarn publish:check", 61 | "publish:next": "yarn next:publish && yarn next:publish --skip-npm && yarn publish:check", 62 | "next:publish": "lerna publish --exact --canary=next --npm-tag=next --yes", 63 | "publish:check": "node scripts/check-publish.js", 64 | "start:browser": "yarn rebuild:browser && yarn --cwd examples/browser start", 65 | "start:electron": "yarn rebuild:electron && yarn --cwd examples/electron start", 66 | "download:plugins": "theia download:plugins" 67 | }, 68 | "workspaces": [ 69 | "dev-packages/*", 70 | "packages/*", 71 | "examples/*" 72 | ], 73 | "theiaPluginsDir": "plugins", 74 | "theiaPlugins": { 75 | "vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.45.1/file/vscode.cpp-1.45.1.vsix", 76 | "vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix", 77 | "vscode-builtin-markdown": "https://open-vsx.org/api/vscode/markdown/1.45.1/file/vscode.markdown-1.45.1.vsix", 78 | "vscode-builtin-npm": "https://open-vsx.org/api/vscode/npm/1.45.1/file/vscode.npm-1.45.1.vsix", 79 | "vscode-builtin-typescript": "https://open-vsx.org/api/vscode/typescript/1.45.1/file/vscode.typescript-1.45.1.vsix", 80 | "vscode-builtin-typescript-language-features": "https://open-vsx.org/api/vscode/typescript-language-features/1.45.1/file/vscode.typescript-language-features-1.45.1.vsix", 81 | "vscode-clangd": "https://open-vsx.org/api/llvm-vs-code-extensions/vscode-clangd/0.1.7/file/llvm-vs-code-extensions.vscode-clangd-0.1.7.vsix", 82 | "cdt-gdb-vscode": "https://open-vsx.org/api/eclipse-cdt/cdt-gdb-vscode/0.0.92/file/eclipse-cdt.cdt-gdb-vscode-0.0.92.vsix" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/cpp-debug/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: [ 4 | '../../configs/build.eslintrc.json' 5 | ], 6 | parserOptions: { 7 | tsconfigRootDir: __dirname, 8 | project: 'compile.tsconfig.json' 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/cpp-debug/.gitignore: -------------------------------------------------------------------------------- 1 | download 2 | -------------------------------------------------------------------------------- /packages/cpp-debug/README.md: -------------------------------------------------------------------------------- 1 | # cpp-debug 2 | 3 | This extension contributes a set of widgets for viewing memory in different ways. 4 | 5 | ## Requirements 6 | 7 | This extension must be used in conjunction with a Debug Adapter that implements a ReadMemoryRequest handler or alternative custom request that returns memory data. It has been tested against the [CDT-GDB Adapter](https://github.com/eclipse-cdt/cdt-gdb-adapter) used as the backend for the 8 | [CDT-GDB VSCode](https://github.com/eclipse-cdt/cdt-gdb-vscode) plugin. This repository is configured to download that plugin as part of its build routine. 9 | If you intend to use this extension with a different debug adapter, you may need to implement a custom 10 | [`MemoryProvider`](./src/browser/memory-provider/memory-provider-service.ts) to handle any peculiarities of the requests and responses used by your adapter. 11 | 12 | ## The Widgets 13 | 14 | ### Memory Widget 15 | 16 | The basic [`MemoryWidget` class](./src/browser/memory-widget/memory-widget.ts) is a wrapper around two functional widgets, a `MemoryOptionsWidget` and 17 | a`MemoryTableWidget`. The [`MemoryOptionsWidget`](./src/browser/memory-widget/memory-options-widget.tsx) is responsible for configuring the display 18 | and fetching memory, and the [`MemoryTableWidget`](./src/browser/memory-widget/memory-table-widget.tsx) renders the memory according to the options 19 | specified by the user in the `MemoryOptionsWidget`. The basic combination of these three classes offers variable highlighting, ascii display, and 20 | dynamic updating in response to events from the debug session, as well as the option to lock the view to ignore changes from the session. 21 | 22 | ### Diff Widget 23 | 24 | The [`MemoryDiffWidget`](./src/browser/diff-widget/memory-diff-widget-types.ts) is an elaboration of the `MemoryWidget` type that allows side-by-side 25 | comparison of the contents of two `MemoryWidgets`. 26 | 27 | ### Register Widget 28 | 29 | Although it is not supported by the `cdt-gdb-vscode` debug adapter, the Debug Adapter Protocol supports including registers as a scope inside the 30 | response to a variables request. The [`RegisterWidget`](./src/browser/register-widget/register-widget-types.ts) offers functionality to view and 31 | manipulate those values when using a debug adapter that reports register contents. 32 | 33 | ### Editable Widget 34 | 35 | Another feature not presently available from `cdt-gdb-vscode` but 36 | [proposed for the Debug Adapter Protocol](https://github.com/microsoft/debug-adapter-protocol/issues/163) and available for implementation as a custom 37 | request to a GDB backend is direct writing of memory by address. The 38 | [`MemoryEditableTableWidget`](./src/browser/editable-widget/memory-editable-table-widget.tsx) adds UI functionality to allow users to modify values in 39 | the table display and send them to a backend that supports that operation. 40 | 41 | ## Using the Widgets 42 | 43 | The widgets are created by the [`MemoryWidgetManager`](./src/browser/utils/memory-widget-manager.ts), and modifying the `createNewMemoryWidget()` 44 | method of that service allows you to change what kind of widget is instantiated and under what circumstances. The widgets get memory through the 45 | [`MemoryProviderService`](./src/browser/memory-provider/memory-provider-service.ts), which delegates to implementations `MemoryProvider` interface 46 | that are bound as `MemoryProvider` contributions. 47 | -------------------------------------------------------------------------------- /packages/cpp-debug/compile.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../configs/base.tsconfig", 3 | "compilerOptions": { 4 | "composite": true, 5 | "rootDir": "src", 6 | "outDir": "lib" 7 | }, 8 | "include": [ 9 | "src" 10 | ], 11 | "references": [] 12 | } 13 | -------------------------------------------------------------------------------- /packages/cpp-debug/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@theia/cpp-debug", 3 | "version": "1.27.0", 4 | "description": "Theia - C/C++ Debug Extension", 5 | "dependencies": { 6 | "@theia/core": "1.27.0", 7 | "@theia/debug": "1.27.0", 8 | "long": "^4.0.0", 9 | "vscode-debugprotocol": "^1.48.0" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "theiaExtensions": [ 15 | { 16 | "frontend": "lib/browser/cpp-debug-frontend-module" 17 | } 18 | ], 19 | "keywords": [ 20 | "theia-extension", 21 | "cpp", 22 | "debug" 23 | ], 24 | "license": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/eclipse/theia-cpp-extension.git" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/eclipse/theia-cpp-extension/issues" 31 | }, 32 | "homepage": "https://github.com/eclipse/theia-cpp-extension", 33 | "files": [ 34 | "data", 35 | "lib", 36 | "src" 37 | ], 38 | "scripts": { 39 | "postinstall": "node -e \"require('@theia/debug/bin/download-adapters.js')\"", 40 | "download": "download-debug-adapters", 41 | "lint": "if-env SKIP_LINT=true && echo 'skip lint check' || eslint --cache=true --no-error-on-unmatched-pattern=true \"{src,test}/**/*.{ts,tsx}\"", 42 | "build": "tsc -b compile.tsconfig.json", 43 | "watch": "tsc -p compile.tsconfig.json -w", 44 | "clean": "rimraf lib *.tsbuildinfo && rimraf .eslintcache && rimraf .nyc_output coverage", 45 | "test": "mocha --opts ../../configs/mocha.opts \"./lib/**/*.*spec.js\"" 46 | }, 47 | "devDependencies": { 48 | "@types/long": "^4.0.0" 49 | }, 50 | "nyc": { 51 | "extends": "../../configs/nyc.json" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/cpp-debug-frontend-module.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import '../../src/browser/style/index.css'; 18 | import '../../src/browser/utils/multi-select-bar.css'; 19 | import '../../src/browser/register-widget/register-widget.css'; 20 | import { ContainerModule } from '@theia/core/shared/inversify'; 21 | import { bindViewContribution, WidgetFactory, FrontendApplicationContribution } from '@theia/core/lib/browser'; 22 | import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; 23 | import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution'; 24 | import { DefaultMemoryProvider, MemoryProvider } from './memory-provider/memory-provider'; 25 | import { MemoryWidgetManager } from './utils/memory-widget-manager'; 26 | import { DebugFrontendContribution } from './cpp-debug-frontend-contribution'; 27 | import { MemoryDiffWidgetData, MemoryWidgetOptions, RegisterWidgetOptions } from './utils/memory-widget-utils'; 28 | import { MemoryDiffOptionsWidget } from './diff-widget/memory-diff-options-widget'; 29 | import { MemoryDiffSelectWidget } from './diff-widget/memory-diff-select-widget'; 30 | import { MemoryDiffWidget, MemoryDiffTableWidget } from './diff-widget/memory-diff-table-widget'; 31 | import { EditableMemoryWidget, MemoryEditableTableWidget } from './editable-widget/memory-editable-table-widget'; 32 | import { MemoryHoverRendererService } from './utils/memory-hover-renderer'; 33 | import { MemoryLayoutWidget } from './wrapper-widgets/memory-layout-widget'; 34 | import { RegisterOptionsWidget } from './register-widget/register-options-widget'; 35 | import { RegisterWidget } from './register-widget/register-widget-types'; 36 | import { RegisterTableWidget } from './register-widget/register-table-widget'; 37 | import { MemoryTableWidget } from './memory-widget/memory-table-widget'; 38 | import { MemoryOptionsWidget } from './memory-widget/memory-options-widget'; 39 | import { MemoryWidget } from './memory-widget/memory-widget'; 40 | import { MemoryDockPanel } from './wrapper-widgets/memory-dock-panel'; 41 | import { MemoryDockpanelPlaceholder } from './wrapper-widgets/memory-dockpanel-placeholder-widget'; 42 | import { MemoryProviderService } from './memory-provider/memory-provider-service'; 43 | import { CDTGDBMemoryProvider } from './memory-provider/cdt-gdb-memory-provider'; 44 | import { bindContributionProvider } from '@theia/core'; 45 | 46 | // eslint-disable-next-line max-lines-per-function 47 | export default new ContainerModule(bind => { 48 | bindViewContribution(bind, DebugFrontendContribution); 49 | bind(ColorContribution).toService(DebugFrontendContribution); 50 | bind(TabBarToolbarContribution).toService(DebugFrontendContribution); 51 | bind(FrontendApplicationContribution).toService(DebugFrontendContribution); 52 | 53 | bind(MemoryProviderService).toSelf().inSingletonScope(); 54 | bind(DefaultMemoryProvider).toSelf().inSingletonScope(); 55 | bindContributionProvider(bind, MemoryProvider); 56 | bind(MemoryProvider).to(CDTGDBMemoryProvider).inSingletonScope(); 57 | bind(MemoryLayoutWidget).toSelf().inSingletonScope(); 58 | bind(MemoryDiffSelectWidget).toSelf().inSingletonScope(); 59 | bind(MemoryDockpanelPlaceholder).toSelf().inSingletonScope(); 60 | bind(MemoryHoverRendererService).toSelf().inSingletonScope(); 61 | bind(MemoryWidgetManager).toSelf().inSingletonScope(); 62 | 63 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 64 | id: MemoryDockPanel.ID, 65 | createWidget: (): MemoryDockPanel => MemoryDockPanel.createWidget(container), 66 | })); 67 | 68 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 69 | id: MemoryLayoutWidget.ID, 70 | createWidget: (): MemoryLayoutWidget => container.get(MemoryLayoutWidget), 71 | })).inSingletonScope(); 72 | 73 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 74 | id: MemoryWidget.ID, 75 | createWidget: (options: MemoryWidgetOptions): MemoryWidget => MemoryWidget.createWidget( 76 | container, 77 | MemoryOptionsWidget, 78 | MemoryTableWidget, 79 | MemoryWidgetOptions, 80 | options, 81 | ), 82 | })); 83 | 84 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 85 | id: EditableMemoryWidget.ID, 86 | createWidget: (options: MemoryWidgetOptions): EditableMemoryWidget => MemoryWidget 87 | .createWidget( 88 | container, 89 | MemoryOptionsWidget, 90 | MemoryEditableTableWidget, 91 | MemoryWidgetOptions, 92 | options, 93 | ), 94 | })); 95 | 96 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 97 | id: MemoryDiffWidget.ID, 98 | createWidget: (options: MemoryDiffWidgetData): MemoryDiffWidget => MemoryWidget 99 | .createWidget( 100 | container, 101 | MemoryDiffOptionsWidget, 102 | MemoryDiffTableWidget, 103 | MemoryDiffWidgetData, 104 | options, 105 | ), 106 | })); 107 | 108 | bind(WidgetFactory).toDynamicValue(({ container }) => ({ 109 | id: RegisterWidget.ID, 110 | createWidget: (options: RegisterWidgetOptions): RegisterWidget => RegisterWidget 111 | .createContainer( 112 | container, 113 | RegisterOptionsWidget, 114 | RegisterTableWidget, 115 | RegisterWidgetOptions, 116 | options, 117 | ).get(MemoryWidget), 118 | })); 119 | }); 120 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/diff-widget/memory-diff-options-widget.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Key, KeyCode } from '@theia/core/lib/browser'; 18 | import { ThemeType } from '@theia/core/lib/common/theme'; 19 | import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; 20 | import * as React from '@theia/core/shared/react'; 21 | import { LENGTH_FIELD_ID, LOCATION_OFFSET_FIELD_ID, MemoryOptionsWidget } from '../memory-widget/memory-options-widget'; 22 | import { MWInput } from '../utils/memory-widget-components'; 23 | import { Interfaces, MemoryDiffWidgetData, Utils } from '../utils/memory-widget-utils'; 24 | import { DiffLabels } from './memory-diff-widget-types'; 25 | 26 | export interface DiffMemoryOptions extends Interfaces.MemoryOptions { 27 | beforeOffset: number; 28 | afterOffset: number; 29 | } 30 | 31 | @injectable() 32 | export class MemoryDiffOptionsWidget extends MemoryOptionsWidget { 33 | @inject(MemoryDiffWidgetData) protected memoryWidgetOptions: MemoryDiffWidgetData; 34 | 35 | protected themeType: ThemeType; 36 | 37 | get options(): DiffMemoryOptions { 38 | return this.storeState(); 39 | } 40 | 41 | updateDiffData(newDiffData: Partial): void { 42 | this.memoryWidgetOptions = { ...this.memoryWidgetOptions, ...newDiffData }; 43 | this.init(); 44 | } 45 | 46 | @postConstruct() 47 | protected init(): void { 48 | this.addClass(MemoryOptionsWidget.ID); 49 | this.addClass('diff-options-widget'); 50 | const { identifier, beforeBytes, afterBytes } = this.memoryWidgetOptions; 51 | this.id = `${MemoryDiffOptionsWidget.ID}-${identifier}`; 52 | this.title.label = `Diff: ${identifier}`; 53 | this.title.caption = this.title.label; 54 | this.title.iconClass = this.iconClass; 55 | this.title.closable = true; 56 | 57 | this.toDispose.push(this.onOptionsChanged(() => this.update())); 58 | 59 | beforeBytes.label = DiffLabels.Before; 60 | afterBytes.label = DiffLabels.After; 61 | 62 | this.columnsDisplayed = { 63 | beforeAddress: { label: 'Address', doRender: true }, 64 | beforeData: { label: this.memoryWidgetOptions.titles[0], doRender: true }, 65 | afterAddress: { label: 'Address', doRender: true }, 66 | afterData: { label: this.memoryWidgetOptions.titles[1], doRender: true }, 67 | variables: { label: 'Variables', doRender: false }, 68 | ascii: { label: 'ASCII', doRender: false }, 69 | }; 70 | 71 | this.update(); 72 | } 73 | 74 | protected acceptFocus(): void { 75 | const settingsCog = this.node.querySelector('.toggle-settings-click-zone') as HTMLDivElement; 76 | settingsCog?.focus(); 77 | } 78 | 79 | protected renderMemoryLocationGroup(): React.ReactNode { 80 | const { titles: [beforeTitle, afterTitle] } = this.memoryWidgetOptions; 81 | return ( 82 |
83 | 92 | 101 | 108 |
109 | ); 110 | } 111 | 112 | protected getObligatoryColumnIds(): string[] { 113 | return ['beforeAddress', 'beforeData', 'afterAddress', 'afterData']; 114 | } 115 | 116 | protected doRefresh = (event: React.KeyboardEvent | React.MouseEvent): void => { 117 | if ('key' in event && KeyCode.createKeyCode(event.nativeEvent).key?.keyCode !== Key.ENTER.keyCode) { 118 | return; 119 | } 120 | this.fireDidChangeOptions(); 121 | }; 122 | 123 | storeState(): DiffMemoryOptions { 124 | return { 125 | ...super.storeState(), 126 | // prefix a 0. It'll do nothing if it's a number, but if it's an empty string or garbage, it'll make parseInt return 0. 127 | beforeOffset: parseInt(`0${this.offsetField?.value ?? 0}`), 128 | afterOffset: parseInt(`0${this.readLengthField?.value ?? 0}`), 129 | }; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/diff-widget/memory-diff-select-widget.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import * as React from '@theia/core/shared/react'; 18 | import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; 19 | import { Key, KeyCode, Message, ReactWidget } from '@theia/core/lib/browser'; 20 | import { MWSelect } from '../utils/memory-widget-components'; 21 | import { MemoryWidgetManager } from '../utils/memory-widget-manager'; 22 | import { Interfaces } from '../utils/memory-widget-utils'; 23 | import { VariableRange } from '../utils/memory-widget-variable-utils'; 24 | import { RegisterWidget } from '../register-widget/register-widget-types'; 25 | import { MemoryDiffWidget } from './memory-diff-table-widget'; 26 | import * as Long from 'long'; 27 | import { MemoryWidget } from '../memory-widget/memory-widget'; 28 | 29 | interface DiffMemory { 30 | beforeAddress: Long; 31 | beforeBytes: Interfaces.LabeledUint8Array; 32 | beforeVariables: VariableRange[]; 33 | afterAddress: Long; 34 | afterBytes: Interfaces.LabeledUint8Array; 35 | afterVariables: VariableRange[]; 36 | } 37 | 38 | @injectable() 39 | export class MemoryDiffSelectWidget extends ReactWidget { 40 | static DIFF_SELECT_CLASS = 'memory-diff-select'; 41 | 42 | protected beforeWidgetLabel = ''; 43 | protected afterWidgetLabel = ''; 44 | 45 | protected labelToWidgetMap = new Map(); 46 | 47 | @inject(MemoryWidgetManager) protected readonly memoryWidgetManager: MemoryWidgetManager; 48 | 49 | @postConstruct() 50 | protected init(): void { 51 | this.addClass(MemoryDiffSelectWidget.DIFF_SELECT_CLASS); 52 | this.id = MemoryDiffSelectWidget.DIFF_SELECT_CLASS; 53 | this.updateWidgetMap(); 54 | this.update(); 55 | this.toDispose.push(this.memoryWidgetManager.onChanged(() => this.updateWidgetMap())); 56 | this.scrollOptions = { ...this.scrollOptions, suppressScrollX: false }; 57 | this.hide(); 58 | } 59 | 60 | onActivateRequest(msg: Message): void { 61 | super.onActivateRequest(msg); 62 | this.node.querySelector('select')?.focus(); 63 | } 64 | 65 | protected assignBaseValue = (e: React.ChangeEvent): void => { 66 | this.beforeWidgetLabel = e.target.value; 67 | this.update(); 68 | }; 69 | 70 | protected assignLaterValue = (e: React.ChangeEvent): void => { 71 | this.afterWidgetLabel = e.target.value; 72 | this.update(); 73 | }; 74 | 75 | render(): React.ReactNode { 76 | const optionLabels = [...this.labelToWidgetMap.keys()]; 77 | const currentBase = this.getBeforeLabel(optionLabels); 78 | const currentChanged = this.getAfterLabel(optionLabels, currentBase); 79 | return optionLabels.length > 1 && ( 80 |
81 |
82 |
83 | 90 |
91 |
92 | label !== currentBase)} 97 | onChange={this.assignLaterValue} 98 | onKeyDown={this.diffIfEnter} 99 | /> 100 |
101 |
102 | 109 |
110 | ); 111 | } 112 | 113 | protected diffIfEnter = (e: React.KeyboardEvent): void => { 114 | if (KeyCode.createKeyCode(e.nativeEvent).key?.keyCode === Key.ENTER.keyCode) { 115 | this.doDiff(); 116 | } 117 | }; 118 | 119 | protected updateWidgetMap(): void { 120 | const widgets = this.memoryWidgetManager.availableWidgets.filter(widget => !MemoryDiffWidget.is(widget) && !RegisterWidget.is(widget)); 121 | this.labelToWidgetMap = new Map(widgets.map((widget): [string, MemoryWidget] => [widget.title.label, widget])); 122 | this.update(); 123 | } 124 | 125 | protected getBeforeLabel(optionLabels: string[] = [...this.labelToWidgetMap.keys()]): string { 126 | return this.labelToWidgetMap.has(this.beforeWidgetLabel) && this.beforeWidgetLabel || optionLabels[0]; 127 | } 128 | 129 | protected getAfterLabel(optionLabels: string[], beforeWidgetLabel: string = this.getBeforeLabel(optionLabels)): string { 130 | return (this.afterWidgetLabel && this.afterWidgetLabel !== beforeWidgetLabel 131 | ? this.afterWidgetLabel 132 | : optionLabels.find(label => label !== beforeWidgetLabel)) ?? ''; 133 | } 134 | 135 | protected diff = (): void => this.doDiff(); 136 | 137 | protected doDiff(): void { 138 | const labels = [...this.labelToWidgetMap.keys()]; 139 | const baseLabel = this.getBeforeLabel(labels); 140 | const changedLabel = this.getAfterLabel(labels, baseLabel); 141 | const baseWidget = this.labelToWidgetMap.get(baseLabel); 142 | const changedWidget = this.labelToWidgetMap.get(changedLabel); 143 | if (baseWidget && changedWidget) { 144 | const memoryAndAddresses = this.getMemoryArrays(baseWidget, changedWidget); 145 | this.memoryWidgetManager.doDiff({ ...memoryAndAddresses, titles: [baseLabel, changedLabel] }); 146 | } 147 | } 148 | 149 | protected getMemoryArrays(beforeWidget: MemoryWidget, afterWidget: MemoryWidget): DiffMemory { 150 | const { memory: beforeMemory } = beforeWidget.optionsWidget; 151 | const { memory: afterMemory } = afterWidget.optionsWidget; 152 | return { 153 | beforeBytes: beforeMemory.bytes, 154 | afterBytes: afterMemory.bytes, 155 | beforeAddress: beforeMemory.address, 156 | afterAddress: afterMemory.address, 157 | beforeVariables: beforeMemory.variables, 158 | afterVariables: afterMemory.variables, 159 | }; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/diff-widget/memory-diff-widget-types.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { MemoryTable } from '../memory-widget/memory-table-widget'; 18 | import { VariableDecoration } from '../utils/memory-widget-variable-utils'; 19 | 20 | export enum DiffLabels { 21 | Before = 'before', 22 | After = 'after' 23 | } 24 | 25 | export interface RowData { 26 | groups: React.ReactNodeArray; 27 | variables: VariableDecoration[]; 28 | ascii: string; 29 | } 30 | 31 | export interface DiffRowOptions { 32 | beforeAddress: string; 33 | afterAddress: string; 34 | before: RowData; 35 | after: RowData; 36 | doShowDivider: boolean; 37 | isModified: boolean; 38 | } 39 | 40 | export interface DiffExtraColumnOptions extends Pick { 41 | afterAscii: string; 42 | afterVariables: VariableDecoration[]; 43 | variables: VariableDecoration[]; 44 | ascii: string; 45 | } 46 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/memory-provider/cdt-gdb-memory-provider.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Interfaces } from '../utils/memory-widget-utils'; 18 | import { injectable } from '@theia/core/shared/inversify'; 19 | import { hexStrToUnsignedLong } from '../../common/util'; 20 | import { MemoryProvider } from './memory-provider'; 21 | import { DebugSession } from '@theia/debug/lib/browser/debug-session'; 22 | import { DebugProtocol } from 'vscode-debugprotocol'; 23 | 24 | /** 25 | * Convert a hex-encoded string of bytes to the Uint8Array equivalent. 26 | */ 27 | export function hex2bytes(hex: string): Interfaces.LabeledUint8Array { 28 | return Buffer.from(hex, 'hex'); 29 | } 30 | 31 | /** 32 | * Read memory through the current debug session, using the cdt-gdb-adapter 33 | * extension to read memory. 34 | */ 35 | @injectable() 36 | export class CDTGDBMemoryProvider implements MemoryProvider { 37 | 38 | canHandle(session: DebugSession): boolean { 39 | return session.configuration.type === 'gdb'; 40 | } 41 | 42 | async readMemory(session: DebugSession, readMemoryArguments: DebugProtocol.ReadMemoryArguments): Promise { 43 | const result = await session.sendRequest('readMemory', readMemoryArguments) as DebugProtocol.ReadMemoryResponse; 44 | 45 | if (result.body?.data) { 46 | const bytes = hex2bytes(result.body.data); 47 | const address = hexStrToUnsignedLong(result.body.address); 48 | return { bytes, address }; 49 | } 50 | throw new Error('Received no data from debug adapter.'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/memory-provider/memory-provider-service.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { ContributionProvider } from '@theia/core'; 18 | import { inject, injectable, named } from '@theia/core/shared/inversify'; 19 | import { DebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager'; 20 | import { DebugProtocol } from 'vscode-debugprotocol'; 21 | import { Interfaces } from '../utils/memory-widget-utils'; 22 | import { MemoryProvider, DefaultMemoryProvider } from './memory-provider'; 23 | 24 | @injectable() 25 | export class MemoryProviderService { 26 | @inject(DebugSessionManager) protected readonly sessionManager: DebugSessionManager; 27 | @inject(DefaultMemoryProvider) protected readonly defaultProvider: DefaultMemoryProvider; 28 | @inject(ContributionProvider) @named(MemoryProvider) 29 | protected readonly contributions: ContributionProvider; 30 | 31 | readMemory(readMemoryArguments: DebugProtocol.ReadMemoryArguments): Promise { 32 | const session = this.sessionManager.currentSession; 33 | if (!session) { 34 | throw new Error('Cannot read memory. No active debug session.'); 35 | } 36 | if (!session.capabilities.supportsReadMemoryRequest) { 37 | throw new Error('Cannot read memory. The current session does not support the request.'); 38 | } 39 | const provider = this.contributions.getContributions().find(candidate => candidate.canHandle(session)) ?? this.defaultProvider; 40 | return provider.readMemory(session, readMemoryArguments); 41 | } 42 | 43 | writeMemory(writeMemoryArguments: DebugProtocol.WriteMemoryArguments): Promise { 44 | const session = this.sessionManager.currentSession; 45 | if (!session) { 46 | throw new Error('Cannot write memory. No active debug session.'); 47 | } 48 | if (!session.capabilities.supportsWriteMemoryRequest) { 49 | throw new Error('Cannot write memory. The current session does not support the request.'); 50 | } 51 | const provider: Required = this.contributions.getContributions() 52 | .find((candidate): candidate is Required => !!candidate.writeMemory && candidate.canHandle(session)) 53 | ?? this.defaultProvider; 54 | 55 | return provider.writeMemory(session, writeMemoryArguments); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/memory-provider/memory-provider.spec.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { expect } from 'chai'; 18 | 19 | describe('cpp-debug', () => { 20 | it('should pass', () => { 21 | expect(true).to.equal(true); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/memory-provider/memory-provider.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Interfaces } from '../utils/memory-widget-utils'; 18 | import { injectable } from '@theia/core/shared/inversify'; 19 | import { DebugProtocol } from 'vscode-debugprotocol'; 20 | import Long = require('long'); 21 | import { DebugSession } from '@theia/debug/lib/browser/debug-session'; 22 | 23 | export const MemoryProvider = Symbol('MemoryProvider'); 24 | /** 25 | * Representation of a memory provider. It is only necessary to implement a new Memory Provider if the behavior of the Debug Adapter for a given session type 26 | * deviates from the Debug Adapter Protocol. Otherwise, the DefaultMemoryProvider should handle standard DAP requests and responses. 27 | * 28 | * Specific peculiarities that might require special handling include: restrictions on the formatting of memory location identifiers (only hex numbers, e.g.) 29 | * or deviations from the DAP in the format of the response to a given request. 30 | */ 31 | export interface MemoryProvider { 32 | /** 33 | * @param session 34 | * @return whether the given MemoryProvider can handle memory reading / writing for a session of the type submitted. 35 | */ 36 | canHandle(session: DebugSession): boolean; 37 | readMemory(session: DebugSession, readMemoryArguments: DebugProtocol.ReadMemoryArguments): Promise; 38 | 39 | writeMemory?(session: DebugSession, writeMemoryArguments: DebugProtocol.WriteMemoryArguments): Promise; 40 | } 41 | 42 | /** 43 | * Convert a base64-encoded string of bytes to the Uint8Array equivalent. 44 | */ 45 | export function base64ToBytes(base64: string): Interfaces.LabeledUint8Array { 46 | return Buffer.from(base64, 'base64'); 47 | } 48 | 49 | @injectable() 50 | export class DefaultMemoryProvider implements MemoryProvider { 51 | // This provider should only be used a fallback - it shouldn't volunteer to handle any session. 52 | canHandle(): false { 53 | return false; 54 | } 55 | 56 | async readMemory(session: DebugSession, readMemoryArguments: DebugProtocol.ReadMemoryArguments): Promise { 57 | const result = await session.sendRequest('readMemory', readMemoryArguments) as DebugProtocol.ReadMemoryResponse; 58 | 59 | if (result.body?.data) { 60 | const { body: { data, address } } = result; 61 | const bytes = base64ToBytes(data); 62 | const longAddress = result.body.address.startsWith('0x') ? Long.fromString(address, true, 16) : Long.fromString(address, true, 10); 63 | return { bytes, address: longAddress }; 64 | } 65 | throw new Error('Received no data from debug adapter.'); 66 | } 67 | 68 | async writeMemory(session: DebugSession, writeMemoryArguments: DebugProtocol.WriteMemoryArguments): Promise { 69 | return session.sendRequest('writeMemory', writeMemoryArguments); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/memory-widget/memory-widget.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { BaseWidget, PanelLayout } from '@theia/core/lib/browser'; 18 | import { postConstruct, injectable, inject, interfaces, Container } from '@theia/core/shared/inversify'; 19 | import { MemoryWidgetOptions } from '../utils/memory-widget-utils'; 20 | import { MemoryOptionsWidget } from './memory-options-widget'; 21 | import { MemoryTableWidget } from './memory-table-widget'; 22 | 23 | @injectable() 24 | export class MemoryWidget< 25 | O extends MemoryOptionsWidget = MemoryOptionsWidget, 26 | T extends MemoryTableWidget = MemoryTableWidget 27 | > 28 | extends BaseWidget { 29 | static ID = 'memory-view-wrapper'; 30 | static LABEL = 'Memory'; 31 | 32 | @inject(MemoryWidgetOptions) protected readonly memoryWidgetOptions: MemoryWidgetOptions; 33 | @inject(MemoryOptionsWidget) readonly optionsWidget: O; 34 | @inject(MemoryTableWidget) readonly tableWidget: T; 35 | 36 | static createWidget< 37 | Options extends MemoryOptionsWidget = MemoryOptionsWidget, 38 | Table extends MemoryTableWidget = MemoryTableWidget 39 | >( 40 | parent: interfaces.Container, 41 | optionsWidget: interfaces.ServiceIdentifier, 42 | tableWidget: interfaces.ServiceIdentifier, 43 | optionSymbol: interfaces.ServiceIdentifier = MemoryWidgetOptions, 44 | options?: MemoryWidgetOptions, 45 | ): MemoryWidget { 46 | const child = MemoryWidget.createContainer(parent, optionsWidget, tableWidget, optionSymbol, options); 47 | return child.get(MemoryWidget); 48 | } 49 | 50 | static createContainer( 51 | parent: interfaces.Container, 52 | optionsWidget: interfaces.ServiceIdentifier, 53 | tableWidget: interfaces.ServiceIdentifier, 54 | optionSymbol: interfaces.ServiceIdentifier = MemoryWidgetOptions, 55 | options?: MemoryWidgetOptions, 56 | ): interfaces.Container { 57 | const child = new Container({ defaultScope: 'Singleton' }); 58 | child.parent = parent; 59 | child.bind(optionsWidget).toSelf(); 60 | child.bind(tableWidget).toSelf(); 61 | child.bind(MemoryWidgetOptions).toConstantValue(options); 62 | if (optionsWidget !== MemoryOptionsWidget) { 63 | child.bind(MemoryOptionsWidget).toService(optionsWidget); 64 | } 65 | if (tableWidget !== MemoryTableWidget) { 66 | child.bind(MemoryTableWidget).toService(tableWidget); 67 | } 68 | if (optionSymbol !== MemoryWidgetOptions) { 69 | child.bind(optionSymbol).toConstantValue(options); 70 | } 71 | child.bind(MemoryWidget).toSelf(); 72 | return child; 73 | } 74 | 75 | static getIdentifier(optionsWidgetID: string): string { 76 | return `${MemoryWidget.ID}-${optionsWidgetID}`; 77 | } 78 | 79 | @postConstruct() /* eslint-disable-line @typescript-eslint/require-await */ // Extenders may want real async 80 | protected async init(): Promise { 81 | this.id = MemoryWidget.getIdentifier(this.memoryWidgetOptions.identifier.toString()); 82 | this.addClass(MemoryWidget.ID); 83 | 84 | this.title.label = this.optionsWidget.title.label; 85 | this.title.caption = this.optionsWidget.title.caption; 86 | this.title.iconClass = this.optionsWidget.title.iconClass; 87 | this.title.closable = this.optionsWidget.title.closable; 88 | 89 | const layout = this.layout = new PanelLayout(); 90 | layout.addWidget(this.optionsWidget); 91 | layout.addWidget(this.tableWidget); 92 | 93 | this.toDispose.pushAll([ 94 | this.layout, 95 | this.optionsWidget, 96 | this.tableWidget, 97 | ]); 98 | 99 | this.optionsWidget.title.changed.connect(title => { 100 | this.title.label = title.label; 101 | this.title.caption = title.caption; 102 | this.title.iconClass = title.iconClass; 103 | }); 104 | } 105 | 106 | protected onActivateRequest(): void { 107 | this.optionsWidget.activate(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/register-widget/register-filter-service.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; 18 | 19 | export enum AllOrCustom { 20 | All = 'All', 21 | Custom = 'Custom' 22 | } 23 | 24 | export const RegisterFilterService = Symbol('RegisterFilterService'); 25 | export interface RegisterFilterService { 26 | currentFilterLabel: string; 27 | filterLabels: string[]; 28 | setFilter(filterLabel: string): void; 29 | shouldDisplayRegister(registerName: string): boolean; 30 | currentFilterRegisters(): string[]; 31 | } 32 | export const RegisterFilterServiceOptions = Symbol('RegisterFilterServiceOptions'); 33 | export interface RegisterFilterServiceOptions { 34 | [key: string]: string[]; 35 | } 36 | 37 | @injectable() 38 | export class RegisterFilterServiceImpl implements RegisterFilterService { 39 | @inject(RegisterFilterServiceOptions) protected readonly options: RegisterFilterServiceOptions; 40 | 41 | protected filters: Map | undefined> = new Map(); 42 | protected currentFilter: string = AllOrCustom.All; 43 | 44 | get filterLabels(): string[] { 45 | return [...this.filters.keys()]; 46 | } 47 | 48 | get currentFilterLabel(): string { 49 | return this.currentFilter; 50 | } 51 | 52 | @postConstruct() 53 | protected init(): Promise { 54 | this.filters.set(AllOrCustom.All, undefined); 55 | this.filters.set(AllOrCustom.Custom, new Set()); 56 | for (const [key, values] of Object.entries(this.options)) { 57 | this.filters.set(key, new Set(values)); 58 | } 59 | return Promise.resolve(); 60 | } 61 | 62 | setFilter(filterLabel: string): void { 63 | if (this.filters.has(filterLabel)) { 64 | this.currentFilter = filterLabel; 65 | } 66 | } 67 | 68 | shouldDisplayRegister(registerName: string): boolean { 69 | const currentFilter = this.filters.get(this.currentFilter); 70 | return !currentFilter || currentFilter.has(registerName); 71 | } 72 | 73 | currentFilterRegisters(): string[] { 74 | const currentFilterRegisters = this.filters.get(this.currentFilter); 75 | return currentFilterRegisters ? Array.from(currentFilterRegisters) : []; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/register-widget/register-table-widget.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import * as React from '@theia/core/shared/react'; 18 | import { Key, KeyCode } from '@theia/core/lib/browser'; 19 | import { DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items'; 20 | import { inject, postConstruct } from '@theia/core/shared/inversify'; 21 | import { MemoryTableWidget, MemoryTable } from '../memory-widget/memory-table-widget'; 22 | import { RegisterReadResult } from '../utils/memory-widget-variable-utils'; 23 | import { RegisterOptions, RegisterOptionsWidget } from './register-options-widget'; 24 | 25 | export namespace RegisterTable { 26 | 27 | export const ROW_CLASS = 't-mv-view-row'; 28 | export const ROW_DIVIDER_CLASS = 't-mv-view-row-highlight'; 29 | export const REGISTER_NAME_CLASS = 't-mv-view-address'; 30 | export const REGISTER_DATA_CLASS = 't-mv-view-data'; 31 | export const EXTRA_COLUMN_DATA_CLASS = 't-mv-view-code'; 32 | export const HEADER_ROW_CLASS = 't-mv-header'; 33 | 34 | export interface RowOptions { 35 | regName: string; 36 | regVal: string; 37 | hexadecimal?: string; 38 | decimal?: string; 39 | octal?: string; 40 | binary?: string; 41 | doShowDivider?: boolean; 42 | isChanged?: boolean; 43 | } 44 | 45 | export interface StylableNodeAttributes { 46 | className?: string; 47 | style?: React.CSSProperties; 48 | title?: string; 49 | isChanged?: boolean; 50 | } 51 | 52 | export interface RowDecorator { 53 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 54 | (...args: any[]): Partial; 55 | } 56 | } 57 | 58 | export class RegisterTableWidget extends MemoryTableWidget { 59 | static CONTEXT_MENU = ['register.view.context.menu']; 60 | static ID = 'register-table-widget'; 61 | 62 | @inject(RegisterOptionsWidget) readonly optionsWidget: RegisterOptionsWidget; 63 | 64 | protected readonly registerNotSaved = ''; 65 | protected registers: RegisterReadResult; 66 | protected previousRegisters: RegisterReadResult | undefined; 67 | protected options: RegisterOptions; 68 | 69 | @postConstruct() /* eslint-disable-line @typescript-eslint/require-await */ // extenders may want real async 70 | protected async init(): Promise { 71 | this.id = RegisterTableWidget.ID; 72 | this.addClass(RegisterTableWidget.ID); 73 | this.scrollOptions = { ...this.scrollOptions, suppressScrollX: false }; 74 | this.toDispose.push(this.optionsWidget.onOptionsChanged(optionId => this.handleOptionChange(optionId))); 75 | this.toDispose.push(this.optionsWidget.onRegisterChanged(e => this.handleRegisterChange(e))); 76 | this.toDispose.push(this.themeService.onDidColorThemeChange(e => this.handleThemeChange(e))); 77 | 78 | this.getStateAndUpdate(); 79 | } 80 | 81 | handleSetValue(dVar: DebugVariable | undefined): void { 82 | if (dVar) { 83 | dVar.open(); 84 | } 85 | } 86 | 87 | protected handleRegisterChange(newRegister: [RegisterReadResult, boolean]): void { 88 | const regResult = newRegister[0]; 89 | const updatePrevRegs = !newRegister[1]; 90 | if (this.registers.threadId !== regResult.threadId) { 91 | // if not same thread Id, dont highlighting register changes 92 | this.previousRegisters = undefined; 93 | } else { 94 | if (updatePrevRegs) { 95 | this.previousRegisters = this.registers; 96 | } 97 | } 98 | this.getStateAndUpdate(); 99 | } 100 | 101 | protected getState(): void { 102 | this.options = this.optionsWidget.options; 103 | this.registers = this.optionsWidget.registers; 104 | } 105 | 106 | protected getTableRows(): React.ReactNode { 107 | return [...this.renderRegRows()]; 108 | } 109 | 110 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 111 | protected *renderRegRows(result: RegisterReadResult = this.registers): IterableIterator { 112 | let rowsYielded = 0; 113 | // For each row... 114 | for (const reg of result.registers) { 115 | if (this.optionsWidget.displayReg(reg.name)) { 116 | const notSaved = reg.value === this.registerNotSaved; 117 | const isChanged = this.previousRegisters && reg.value !== this.getPrevRegVal(reg.name, this.previousRegisters); 118 | const options: RegisterTable.RowOptions = { 119 | regName: reg.name, 120 | regVal: reg.value, 121 | hexadecimal: notSaved ? reg.value : this.optionsWidget.handleRadixRendering(reg.value, 16, reg.name), 122 | decimal: notSaved ? reg.value : this.optionsWidget.handleRadixRendering(reg.value, 10), 123 | octal: notSaved ? reg.value : this.optionsWidget.handleRadixRendering(reg.value, 8), 124 | binary: notSaved ? reg.value : this.optionsWidget.handleRadixRendering(reg.value, 2, reg.name), 125 | doShowDivider: (rowsYielded % 4) === 3, 126 | isChanged, 127 | }; 128 | yield this.renderRegRow(options); 129 | rowsYielded += 1; 130 | } 131 | } 132 | } 133 | 134 | protected getPrevRegVal(regName: string, inRegs: RegisterReadResult): string | undefined { 135 | return inRegs.registers.find(element => element.name === regName)?.value; 136 | } 137 | 138 | protected renderRegRow( 139 | options: RegisterTable.RowOptions, 140 | getRowAttributes: RegisterTable.RowDecorator = this.getRowAttributes.bind(this), 141 | ): React.ReactNode { 142 | const { regName } = options; 143 | const { className, style, title } = getRowAttributes(options); 144 | return ( 145 | 158 | 159 | {this.getExtraRegColumn(options)} 160 | 161 | ); 162 | } 163 | 164 | protected getRowAttributes(options: Partial): Partial { 165 | let className = RegisterTable.ROW_CLASS; 166 | if (options.doShowDivider) { 167 | className += ` ${RegisterTable.ROW_DIVIDER_CLASS}`; 168 | } 169 | if (options.isChanged) { 170 | // use the eight-bits change CSS class 171 | className += ' eight-bits changed'; 172 | } 173 | return { className }; 174 | } 175 | 176 | protected getExtraRegColumn(options: Pick): React.ReactNodeArray { 177 | const additionalColumns = []; 178 | if (this.options.columnsDisplayed.hexadecimal.doRender) { 179 | additionalColumns.push(); 180 | } 181 | if (this.options.columnsDisplayed.decimal.doRender) { 182 | additionalColumns.push(); 183 | } 184 | if (this.options.columnsDisplayed.octal.doRender) { 185 | additionalColumns.push(); 186 | } 187 | if (this.options.columnsDisplayed.binary.doRender) { 188 | additionalColumns.push(); 189 | } 190 | 191 | return additionalColumns; 192 | } 193 | 194 | protected getWrapperHandlers(): MemoryTable.WrapperHandlers { 195 | return this.options.isFrozen || this.options.noRadixColumnDisplayed 196 | ? super.getWrapperHandlers() 197 | : { 198 | onMouseMove: this.handleTableMouseMove, 199 | onContextMenu: this.handleTableRightClick, 200 | }; 201 | } 202 | 203 | protected doHandleTableMouseMove(targetElement: React.MouseEvent['target']): void { 204 | const tempTarget = targetElement as HTMLElement; 205 | const target = tempTarget.parentElement?.tagName === 'TR' ? tempTarget.parentElement : tempTarget; 206 | if (target.tagName === 'TR') { 207 | const { x, y } = target.getBoundingClientRect(); 208 | const anchor = { x: Math.round(x), y: Math.round(y + target.clientHeight) }; 209 | const value = Number(target.getAttribute('data-value')); 210 | if (!isNaN(value)) { 211 | const register = target.getAttribute('data-id') as string; 212 | const properties = { 213 | register, 214 | hex: `0x${value.toString(16)}`, 215 | binary: `0b${value.toString(2)}`, 216 | decimal: value.toString(10), 217 | octal: `0o${value.toString(8)}`, 218 | }; 219 | return this.hoverRenderer.render(this.node, anchor, properties); 220 | } 221 | } 222 | return this.hoverRenderer.hide(); 223 | } 224 | 225 | private handleRowKeyDown = (event: React.KeyboardEvent): void => { 226 | const keyCode = KeyCode.createKeyCode(event.nativeEvent).key?.keyCode; 227 | switch (keyCode) { 228 | case Key.ENTER.keyCode: 229 | this.openDebugVariableByCurrentTarget(event); 230 | break; 231 | default: 232 | break; 233 | } 234 | }; 235 | 236 | protected openDebugVariableByCurrentTarget = (event: React.KeyboardEvent | React.MouseEvent): void => { 237 | this.openDebugVariableByDataId(event.currentTarget); 238 | }; 239 | 240 | protected openDebugVariableByDataId(element: HTMLElement): void { 241 | const registerName = element.getAttribute('data-id'); 242 | if (registerName) { 243 | this.openDebugVariableByName(registerName); 244 | } 245 | } 246 | 247 | protected openDebugVariableByName(registerName: string): void { 248 | const debugVariable = this.registers.registers.find(element => element.name === registerName); 249 | this.handleSetValue(debugVariable); 250 | } 251 | 252 | protected doHandleTableRightClick(event: React.MouseEvent): void { 253 | event.preventDefault(); 254 | const curTarget = event.currentTarget as HTMLElement; 255 | if (curTarget.tagName === 'TR') { 256 | this.update(); 257 | event.stopPropagation(); 258 | this.contextMenuRenderer.render({ 259 | menuPath: RegisterTableWidget.CONTEXT_MENU, 260 | anchor: event.nativeEvent, 261 | args: this.getContextMenuArgs(event), 262 | }); 263 | } 264 | } 265 | 266 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 267 | protected getContextMenuArgs(event: React.MouseEvent): any[] { 268 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 269 | const args: any[] = [this]; 270 | const regName = (event.currentTarget as HTMLElement).getAttribute('data-id'); 271 | if (regName) { 272 | const dVar = this.registers.registers.find(element => element.name === regName); 273 | args.push(dVar); 274 | } 275 | return args; 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/register-widget/register-widget-types.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { interfaces } from '@theia/core/shared/inversify'; 18 | import { MemoryOptionsWidget } from '../memory-widget/memory-options-widget'; 19 | import { MemoryTableWidget } from '../memory-widget/memory-table-widget'; 20 | import { MemoryWidget } from '../memory-widget/memory-widget'; 21 | import { MemoryWidgetOptions } from '../utils/memory-widget-utils'; 22 | import { RegisterFilterService, RegisterFilterServiceImpl, RegisterFilterServiceOptions } from './register-filter-service'; 23 | import { RegisterOptionsWidget } from './register-options-widget'; 24 | import { RegisterTableWidget } from './register-table-widget'; 25 | 26 | export type RegisterWidget = MemoryWidget; 27 | export namespace RegisterWidget { 28 | export const ID = 'register-view-options-widget'; 29 | export const LABEL = 'Register'; 30 | export const is = (widget: MemoryWidget): boolean => widget.optionsWidget instanceof RegisterOptionsWidget; 31 | 32 | export const createContainer = ( 33 | parent: interfaces.Container, 34 | optionsWidget: interfaces.ServiceIdentifier, 35 | tableWidget: interfaces.ServiceIdentifier, 36 | optionSymbol: interfaces.ServiceIdentifier = MemoryWidgetOptions, 37 | options?: MemoryWidgetOptions, 38 | ): interfaces.Container => { 39 | const child = MemoryWidget.createContainer(parent, optionsWidget, tableWidget, optionSymbol, options); 40 | child.bind(RegisterFilterService).to(RegisterFilterServiceImpl).inSingletonScope(); 41 | child.bind(RegisterFilterServiceOptions).toConstantValue({}); 42 | return child; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/register-widget/register-widget.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | .register-table-widget table.t-mv-view { 18 | table-layout: fixed; 19 | width: 100%; 20 | } 21 | 22 | .register-table-widget table.t-mv-view td, 23 | .register-table-widget table.t-mv-view th { 24 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | } 27 | 28 | .reg-options-widget .t-mv-group.view-group { 29 | grid-template-columns: 3fr 2fr 30px; 30 | } 31 | 32 | .reg-options-widget .multi-select-bar { 33 | height:100%; 34 | } 35 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/style/memory-lock.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/style/memory-view.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/style/register-lock.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/style/register-view.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-commands.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Command } from '@theia/core'; 18 | 19 | export const MemoryCommand: Command = { id: 'cpp-command' }; 20 | 21 | export const ViewVariableInMemoryCommand: Command = { 22 | id: 'view-variable-in-memory', 23 | label: 'Show variable in memory inspector', 24 | }; 25 | 26 | export const ViewVariableInRegisterViewCommand: Command = { 27 | id: 'view-variable-in-register-view', 28 | label: 'Show register in memory inspector', 29 | }; 30 | 31 | export const ResetModifiedCellCommand: Command = { 32 | id: 'reset-modified-cell', 33 | label: 'Reset value', 34 | }; 35 | 36 | export const CreateNewMemoryViewCommand: Command = { 37 | id: 'create-new-memory-view', 38 | label: 'Create new memory inspector', 39 | iconClass: 'memory-view-icon toolbar', 40 | }; 41 | 42 | export const FollowPointerTableCommand: Command = { 43 | id: 'follow-pointer-table', 44 | label: 'Follow pointer', 45 | }; 46 | 47 | export const FollowPointerDebugCommand: Command = { 48 | id: 'follow-pointer-debug', 49 | label: 'Follow pointer in memory inspector', 50 | }; 51 | 52 | export const CreateNewRegisterViewCommand: Command = { 53 | id: 'create-new-register-view', 54 | label: 'Create new register view', 55 | iconClass: 'register-view-icon toolbar', 56 | }; 57 | 58 | export const RegisterSetVariableCommand: Command = { 59 | id: 'register-set-variable-value', 60 | label: 'Set Value', 61 | }; 62 | 63 | export const ToggleDiffSelectWidgetVisibilityCommand: Command = { 64 | id: 'toggle-diff-select-visibility', 65 | iconClass: 'codicon codicon-git-compare', 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-hover-renderer.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Disposable } from '@theia/core'; 18 | import { Anchor } from '@theia/core/lib/browser'; 19 | import { injectable } from '@theia/core/shared/inversify'; 20 | 21 | export interface EasilyMappedObject { 22 | [key: string]: string | number; 23 | } 24 | 25 | @injectable() 26 | export class MemoryHoverRendererService implements Disposable { 27 | protected readonly container: HTMLDivElement; 28 | protected isShown = false; 29 | protected currentRenderContainer: HTMLElement; 30 | 31 | constructor() { 32 | this.container = document.createElement('div'); 33 | this.container.classList.add('t-mv-hover', 'hidden'); 34 | document.body.appendChild(this.container); 35 | } 36 | 37 | render(container: HTMLElement, anchor: Anchor, properties?: EasilyMappedObject): void { 38 | this.clearAll(); 39 | if (!this.isShown) { 40 | document.addEventListener('mousemove', this.closeIfHoverOff); 41 | this.currentRenderContainer = container; 42 | } 43 | 44 | if (properties) { 45 | for (const [key, value] of Object.entries(properties)) { 46 | const label = key.toLowerCase().replace(/[\W]/g, '-'); 47 | const keySpan = document.createElement('span'); 48 | keySpan.classList.add('t-mv-hover-key', label); 49 | keySpan.textContent = `${key}:`; 50 | const valueSpan = document.createElement('span'); 51 | valueSpan.classList.add('t-mv-hover-value', label); 52 | // stringify as decimal number by default. 53 | valueSpan.textContent = value.toString(10); 54 | this.container.appendChild(keySpan); 55 | this.container.appendChild(valueSpan); 56 | } 57 | } 58 | 59 | if (this.container.children.length) { 60 | this.show(anchor); 61 | this.isShown = true; 62 | } else { 63 | this.hide(); 64 | } 65 | } 66 | 67 | hide(): void { 68 | if (this.isShown) { 69 | document.removeEventListener('mousemove', this.closeIfHoverOff); 70 | this.container.classList.add('hidden'); 71 | this.isShown = false; 72 | } 73 | } 74 | 75 | show({ x, y }: Anchor): void { 76 | this.container.classList.remove('hidden'); 77 | this.container.style.top = `${y}px`; 78 | this.container.style.left = `${x}px`; 79 | setTimeout(() => this.checkNotOffScreen()); 80 | } 81 | 82 | protected checkNotOffScreen(): void { 83 | const left = parseInt((this.container.style.left ?? '').replace('px', '')); 84 | const width = this.container.clientWidth; 85 | const overflow = left + width - document.body.clientWidth; 86 | if (overflow > 0) { 87 | const safeLeft = Math.round(left - overflow); 88 | this.container.style.left = `${safeLeft}px`; 89 | } 90 | } 91 | 92 | protected clearAll(): void { 93 | let toRemove = this.container.lastChild; 94 | while (toRemove) { 95 | this.container.removeChild(toRemove); 96 | toRemove = this.container.lastChild; 97 | } 98 | } 99 | 100 | protected closeIfHoverOff = (e: MouseEvent): void => { 101 | const { target } = e; 102 | if (!(target instanceof HTMLElement)) { 103 | return; 104 | } 105 | if (!this.currentRenderContainer.contains(target) && !this.container.contains(target)) { 106 | this.hide(); 107 | } 108 | }; 109 | 110 | dispose(): void { 111 | this.container.remove(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-recents.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | /* 18 | * Utility for storing and sorting an array of most recently visited memory locations 19 | */ 20 | interface RecentsOptions { 21 | maxValues?: number; 22 | } 23 | 24 | export class Recents { 25 | protected maxValues: number; 26 | protected _values: string[] = []; 27 | get values(): string[] { 28 | return this._values; 29 | } 30 | 31 | constructor(initialVals?: string[], opts?: RecentsOptions) { 32 | this.maxValues = opts?.maxValues ?? 10; 33 | if (initialVals) { 34 | if (initialVals.length <= this.maxValues) { 35 | this._values = initialVals; 36 | return; 37 | } 38 | console.error('Initial values length is greater than allowed length, resetting to empty array'); 39 | } 40 | this._values = []; 41 | } 42 | 43 | add(locationString: string): void { 44 | const indexOf = this.has(locationString); 45 | if (indexOf > -1) { 46 | this._values.splice(indexOf, 1); 47 | } else { 48 | if (this._values.length === this.maxValues) { 49 | this._values.shift(); 50 | } 51 | } 52 | this._values.push(locationString); 53 | } 54 | 55 | has(locationString: string): number { 56 | return this._values.indexOf(locationString); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-widget-components.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { Key, KeyCode } from '@theia/core/lib/browser'; 18 | import * as React from '@theia/core/shared/react'; 19 | import { Interfaces } from './memory-widget-utils'; 20 | 21 | export interface MWLabelProps { id: string; label: string; disabled?: boolean; classNames?: string[] } 22 | 23 | export const MWLabel: React.FC = ({ id, label, disabled, classNames }) => { 24 | const additionalClassNames = classNames ? classNames.join(' ') : ''; 25 | return ( 26 | 32 | ); 33 | }; 34 | 35 | export interface InputProps { 36 | id: string; 37 | label: string; 38 | defaultValue?: string; 39 | value?: string; 40 | onChange?: React.EventHandler; 41 | onKeyDown?: React.EventHandler>; 42 | passRef?: React.ClassAttributes['ref']; 43 | title?: string; 44 | disabled?: boolean; 45 | placeholder?: string; 46 | } 47 | 48 | export const MWInput: React.FC> = ({ id, label, passRef, defaultValue, onChange, title, onKeyDown, disabled }) => ( 49 | <> 50 | 51 | 64 | 65 | ); 66 | 67 | export interface LabelAndSelectProps extends InputProps { 68 | options: string[]; 69 | } 70 | 71 | export const MWSelect: React.FC = ({ id, label, options, passRef, onChange, title, value, disabled }) => ( 72 | <> 73 | 74 | 86 | 87 | ); 88 | 89 | export interface LabelAndSelectWithNameProps extends InputProps { 90 | options: Array<[string, string]>; 91 | } 92 | 93 | export const MWSelectWithName: React.FC = ({ id, label, options, passRef, onChange, title, value, disabled }) => ( 94 | <> 95 | 96 | 108 | 109 | ); 110 | 111 | export interface InputWithSelectProps extends InputProps { 112 | options: string[]; 113 | onSelectChange?(e: React.ChangeEvent): void; 114 | onInputChange?(e: React.ChangeEvent): void; 115 | } 116 | export const MWInputWithSelect: React.FC> = ( 117 | { id, label, passRef, onKeyDown, title, options, onSelectChange, defaultValue, disabled, placeholder }, 118 | ) => ( 119 | <> 120 | 121 |
122 | 135 | 142 |
143 | 144 | ); 145 | 146 | export interface MoreMemoryProps { 147 | options: number[]; 148 | direction: 'above' | 'below'; 149 | handler(opts: Interfaces.MoreMemoryOptions): void; 150 | } 151 | 152 | export const MWMoreMemorySelect: React.FC = ({ options, handler, direction }) => { 153 | const [numBytes, setNumBytes] = React.useState(options[0]); 154 | const containerRef = React.createRef(); 155 | const onSelectChange = (e: React.ChangeEvent): void => { 156 | e.stopPropagation(); 157 | const { value } = e.currentTarget; 158 | setNumBytes(parseInt(value)); 159 | }; 160 | 161 | const loadMoreMemory = (e: React.MouseEvent | React.KeyboardEvent): void => { 162 | containerRef.current?.blur(); 163 | const doHandle = !('key' in e) || KeyCode.createKeyCode(e.nativeEvent).key?.keyCode === Key.ENTER.keyCode; 164 | if (doHandle) { 165 | handler({ 166 | numBytes, 167 | direction, 168 | }); 169 | } 170 | }; 171 | 172 | return ( 173 |
181 |
182 | Load 183 | 196 | {`more bytes ${direction}`} 197 |
198 |
199 | ); 200 | }; 201 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-widget-manager.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | import { Disposable, DisposableCollection, Emitter, MessageService } from '@theia/core'; 17 | import { ApplicationShell, OpenViewArguments, WidgetManager } from '@theia/core/lib/browser'; 18 | import { injectable, inject, postConstruct } from '@theia/core/shared/inversify'; 19 | import { MemoryDiffTableWidget, MemoryDiffWidget } from '../diff-widget/memory-diff-table-widget'; 20 | import { MemoryWidget } from '../memory-widget/memory-widget'; 21 | import { RegisterWidget } from '../register-widget/register-widget-types'; 22 | import { MemoryDiffWidgetData, MemoryWidgetOptions } from './memory-widget-utils'; 23 | 24 | @injectable() 25 | export class MemoryWidgetManager implements Disposable { 26 | protected createdWidgetCount = 0; 27 | protected widgetDisplayId = 0; 28 | protected readonly toDispose = new DisposableCollection(); 29 | 30 | @inject(WidgetManager) protected readonly widgetManager: WidgetManager; 31 | @inject(ApplicationShell) protected readonly shell: ApplicationShell; 32 | @inject(MessageService) protected readonly messageService: MessageService; 33 | 34 | protected readonly onNewWidgetCreated = new Emitter(); 35 | readonly onDidCreateNewWidget = this.onNewWidgetCreated.event; 36 | 37 | protected readonly onSelectedWidgetChanged = new Emitter(); 38 | readonly onDidChangeSelectedWidget = this.onSelectedWidgetChanged.event; 39 | 40 | protected readonly onChangedEmitter = new Emitter(); 41 | readonly onChanged = this.onChangedEmitter.event; 42 | 43 | protected readonly _availableWidgets = new Map(); 44 | protected _focusedWidget: MemoryWidget | undefined; 45 | protected _canCompare = false; 46 | 47 | get availableWidgets(): MemoryWidget[] { 48 | return Array.from(this._availableWidgets.values()); 49 | } 50 | 51 | get canCompare(): boolean { 52 | return this._canCompare; 53 | } 54 | 55 | @postConstruct() 56 | protected init(): void { 57 | this.toDispose.pushAll([ 58 | this.shell.onDidChangeActiveWidget(({ newValue }) => { 59 | if (newValue instanceof MemoryWidget) { 60 | this._focusedWidget = newValue; 61 | } 62 | }), 63 | this.widgetManager.onDidCreateWidget(e => { 64 | const { widget } = e; 65 | if (widget instanceof MemoryWidget) { 66 | this._availableWidgets.set(widget.id, widget); 67 | this.toDispose.push(widget.onDidDispose(() => { 68 | this._availableWidgets.delete(widget.id); 69 | if (widget === this._focusedWidget) { 70 | this.focusedWidget = undefined; 71 | } 72 | this.onChangedEmitter.fire(); 73 | })); 74 | } 75 | }), 76 | this.onChanged(() => this.setCanCompare()), 77 | this.onNewWidgetCreated, 78 | this.onChangedEmitter, 79 | this.onSelectedWidgetChanged, 80 | ]); 81 | } 82 | 83 | get focusedWidget(): MemoryWidget | undefined { 84 | return this._focusedWidget ?? this._availableWidgets.values().next().value; 85 | } 86 | 87 | set focusedWidget(title: MemoryWidget | undefined) { 88 | this._focusedWidget = title; 89 | this.onSelectedWidgetChanged.fire(title); 90 | } 91 | 92 | protected setCanCompare(): void { 93 | this._canCompare = this.availableWidgets.filter(widget => !RegisterWidget.is(widget) && !MemoryDiffWidget.is(widget)).length > 1; 94 | } 95 | 96 | async createNewMemoryWidget(kind: 'register' | 'memory' = 'memory'): Promise { 97 | this.widgetDisplayId = this._availableWidgets.size !== 0 ? this.widgetDisplayId + 1 : 1; 98 | const options: MemoryWidgetOptions = { identifier: this.createdWidgetCount += 1, displayId: this.widgetDisplayId }; 99 | const widgetId = kind === 'memory' 100 | ? MemoryWidget.ID 101 | : RegisterWidget.ID; 102 | const widget = await this.widgetManager.getOrCreateWidget(widgetId, options); 103 | this._availableWidgets.set(widget.id, widget); 104 | widget.title.changed.connect(() => this.onChangedEmitter.fire()); 105 | widget.activate(); 106 | this.fireNewWidget(widget); 107 | return widget; 108 | } 109 | 110 | dispose(): void { 111 | this.toDispose.dispose(); 112 | } 113 | 114 | protected fireNewWidget(widget: MemoryWidget): void { 115 | this.onNewWidgetCreated.fire(widget); 116 | this.onChangedEmitter.fire(); 117 | } 118 | 119 | async doDiff(options: Omit): Promise { 120 | if (options.beforeBytes.length === 0) { 121 | this.messageService.warn( 122 | `You must load memory in both widgets you would like to compare. ${options.titles[0]} has no memory loaded.`, 123 | ); 124 | return undefined; 125 | } else if (options.afterBytes.length === 0) { 126 | this.messageService.warn( 127 | `You must load memory in both widgets you would like to compare. ${options.titles[1]} has no memory loaded.`, 128 | ); 129 | return undefined; 130 | } 131 | 132 | const fullOptions: MemoryDiffWidgetData = { ...options, dynamic: false, identifier: options.titles.join('-') }; 133 | 134 | const existingWidget = this._availableWidgets.get(MemoryWidget.getIdentifier(fullOptions.identifier.toString())) as MemoryDiffWidget; 135 | 136 | if (existingWidget && existingWidget.tableWidget instanceof MemoryDiffTableWidget) { 137 | existingWidget.tableWidget.updateDiffData(options); 138 | } 139 | 140 | const widget = existingWidget ?? await this.widgetManager 141 | .getOrCreateWidget( 142 | MemoryDiffWidget.ID, 143 | { ...options, dynamic: false, identifier: options.titles.join('-') }, 144 | ); 145 | 146 | const tabBar = this.shell.getTabBarFor(widget); 147 | if (!tabBar) { 148 | // The widget is not attached yet, so add it to the shell 149 | const widgetArgs: OpenViewArguments = { 150 | area: 'main', 151 | }; 152 | await this.shell.addWidget(widget, widgetArgs); 153 | } 154 | await this.shell.activateWidget(widget.id); 155 | 156 | return widget; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-widget-utils.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import * as Long from 'long'; 18 | import { VariableRange, VariableDecoration } from './memory-widget-variable-utils'; 19 | 20 | export namespace Constants { 21 | export const DEBOUNCE_TIME = 200; 22 | export const ERROR_TIMEOUT = 5000; 23 | } 24 | export namespace Utils { 25 | export const validateNumericalInputs = (e: React.ChangeEvent, allowNegative = true): void => { 26 | const toReplace = allowNegative ? /[^\d-]/g : /[^\d]/g; 27 | // eslint-disable-next-line no-param-reassign 28 | e.target.value = e.target.value.replace(toReplace, ''); 29 | }; 30 | 31 | export const isPrintableAsAscii = (byte: number): boolean => byte >= 32 && byte < (128 - 1); 32 | } 33 | 34 | export namespace Interfaces { 35 | export interface MemoryReadResult { 36 | bytes: LabeledUint8Array; 37 | address: Long; 38 | } 39 | export interface WidgetMemoryState extends MemoryReadResult { 40 | variables: VariableRange[]; 41 | } 42 | 43 | export interface MemoryOptions { 44 | address: string | number; 45 | offset: number; 46 | length: number; 47 | byteSize: number; 48 | bytesPerGroup: number; 49 | groupsPerRow: number; 50 | endianness: Endianness; 51 | doDisplaySettings: boolean; 52 | doUpdateAutomatically: boolean; 53 | columnsDisplayed: ColumnsDisplayed; 54 | recentLocationsArray: string[]; 55 | isFrozen: boolean; 56 | } 57 | export interface MoreMemoryOptions { 58 | numBytes: number; 59 | direction: 'above' | 'below'; 60 | } 61 | 62 | export enum Endianness { 63 | Little = 'Little Endian', 64 | Big = 'Big Endian' 65 | } 66 | export interface LabeledUint8Array extends Uint8Array { 67 | label?: string; 68 | } 69 | 70 | export interface StylableNodeAttributes { 71 | className?: string; 72 | style?: React.CSSProperties; 73 | variable?: VariableDecoration; 74 | title?: string; 75 | isHighlighted?: boolean; 76 | } 77 | 78 | export interface FullNodeAttributes extends StylableNodeAttributes { 79 | content: string; 80 | } 81 | 82 | export interface BitDecorator { 83 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 84 | (...args: any[]): Partial; 85 | } 86 | export interface RowDecorator { 87 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 88 | (...args: any[]): Partial; 89 | } 90 | export interface ByteFromChunkData { 91 | address: Long; 92 | /** 93 | * A single eight-bit byte 94 | */ 95 | value: string; 96 | } 97 | 98 | export interface Column { 99 | label: string; 100 | doRender: boolean; 101 | } 102 | 103 | export interface ColumnIDs { 104 | label: string; 105 | id: string; 106 | } 107 | 108 | export interface ColumnsDisplayed { 109 | [id: string]: Column; 110 | } 111 | } 112 | 113 | export const MemoryWidgetOptions = Symbol('MemoryWidgetOptions'); 114 | export interface MemoryWidgetOptions { 115 | identifier: string | number; 116 | displayId?: string | number; 117 | dynamic?: boolean; 118 | } 119 | 120 | export const MemoryDiffWidgetData = Symbol('MemoryDiffWidgetData'); 121 | export interface MemoryDiffWidgetData extends MemoryWidgetOptions { 122 | beforeAddress: Long; 123 | beforeBytes: Interfaces.LabeledUint8Array; 124 | beforeVariables: VariableRange[]; 125 | afterAddress: Long; 126 | afterBytes: Interfaces.LabeledUint8Array; 127 | afterVariables: VariableRange[]; 128 | dynamic: false; 129 | titles: [string, string]; 130 | } 131 | 132 | export const RegisterWidgetOptions = Symbol('ReigsterWidgetData'); 133 | export type RegisterWidgetOptions = MemoryWidgetOptions; 134 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/memory-widget-variable-utils.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { DebugSession } from '@theia/debug/lib/browser/debug-session'; 18 | import { DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items'; 19 | import * as Long from 'long'; 20 | import { hexStrToUnsignedLong } from '../../common/util'; 21 | 22 | export interface VariableRange { 23 | name: string; 24 | address: Long; 25 | pastTheEndAddress: Long; 26 | type?: string; 27 | value?: string; 28 | } 29 | 30 | export interface VariableDecoration { 31 | name: string; 32 | color: string; 33 | firstAppearance?: boolean; 34 | } 35 | 36 | export interface RegisterReadResult { 37 | threadId: string | undefined; 38 | registers: DebugVariable[]; 39 | } 40 | 41 | /* eslint-disable no-await-in-loop */ 42 | /** 43 | * Get the local variables of the currently selected frame. 44 | */ 45 | export async function getLocals(session: DebugSession | undefined): Promise { 46 | if (session === undefined) { 47 | console.warn('No active debug session.'); 48 | return []; 49 | } 50 | 51 | const frame = session.currentFrame; 52 | if (frame === undefined) { 53 | throw new Error('No active stack frame.'); 54 | } 55 | 56 | const ranges: VariableRange[] = []; 57 | 58 | const scopes = await frame.getScopes(); 59 | const scopesWithoutRegisters = scopes.filter(x => x.render() !== 'Registers'); 60 | for (const scope of scopesWithoutRegisters) { 61 | const variables = await scope.getElements(); 62 | for (const v of variables) { 63 | if (v instanceof DebugVariable) { 64 | const addrExp = `&${v.name}`; 65 | const sizeExp = `sizeof(${v.name})`; 66 | const addrResp = await session.sendRequest('evaluate', { 67 | expression: addrExp, 68 | context: 'watch', 69 | frameId: frame.raw.id, 70 | }); 71 | const sizeResp = await session.sendRequest('evaluate', { 72 | expression: sizeExp, 73 | context: 'watch', 74 | frameId: frame.raw.id, 75 | }); 76 | 77 | // Make sure the address is in the format we expect. 78 | const addressPart = /0x[0-9a-f]+/i.exec(addrResp.body.result); 79 | if (!addressPart) { 80 | continue; 81 | } 82 | 83 | if (!/^[0-9]+$/.test(sizeResp.body.result)) { 84 | continue; 85 | } 86 | 87 | const size = parseInt(sizeResp.body.result); 88 | const address = hexStrToUnsignedLong(addressPart[0]); 89 | const pastTheEndAddress = address.add(size); 90 | 91 | ranges.push({ 92 | name: v.name, 93 | address, 94 | pastTheEndAddress, 95 | type: v.type, 96 | value: v.value, 97 | }); 98 | } 99 | } 100 | } 101 | 102 | return ranges; 103 | } 104 | 105 | // const HSL_BASIS = 360; 106 | 107 | export class VariableFinder { 108 | protected readonly HIGH_CONTRAST_COLORS = [ 109 | 'var(--theia-contrastActiveBorder)', 110 | 'var(--theia-contrastBorder)', 111 | ]; 112 | 113 | protected readonly NON_HC_COLORS = [ 114 | 'var(--theia-terminal-ansiBlue)', 115 | 'var(--theia-terminal-ansiGreen)', 116 | 'var(--theia-terminal-ansiRed)', 117 | 'var(--theia-terminal-ansiYellow)', 118 | 'var(--theia-terminal-ansiMagenta)', 119 | ]; 120 | 121 | protected readonly variables: VariableRange[]; 122 | private currentIndex = -1; 123 | private currentVariable: VariableRange | undefined = undefined; 124 | private handledVariables = new Map(); 125 | private workingColors: string[]; 126 | private lastCall = Long.MAX_UNSIGNED_VALUE; 127 | 128 | constructor(variables: VariableRange[], highContrast = false) { 129 | this.variables = variables.sort((a, b) => a.address.lessThan(b.address) ? -1 : 1); 130 | this.workingColors = highContrast ? this.HIGH_CONTRAST_COLORS : this.NON_HC_COLORS; 131 | } 132 | 133 | /** 134 | * @param address the address of interest. 135 | * 136 | * This function should be called with a sequence of addresses in increasing order 137 | */ 138 | getVariableForAddress(address: Long): VariableDecoration | undefined { 139 | if (address.lessThan(this.lastCall)) { 140 | this.initialize(address); 141 | } 142 | this.lastCall = address; 143 | if (this.currentVariable && address.greaterThanOrEqual(this.currentVariable.pastTheEndAddress)) { 144 | this.currentIndex += 1; 145 | this.currentVariable = this.variables[this.currentIndex]; 146 | } 147 | if (!this.currentVariable) { 148 | return undefined; 149 | } 150 | const { name } = this.currentVariable; 151 | // const color = `hsl(${HSL_BASIS * this.currentIndex / this.variables.length}, 60%, 60%)`; 152 | const color = this.workingColors[this.currentIndex % this.workingColors.length]; 153 | const decoration: VariableDecoration = { 154 | name, 155 | color, 156 | firstAppearance: this.handledVariables.get(name) === address || !this.handledVariables.has(name), 157 | }; 158 | if (address.greaterThanOrEqual(this.currentVariable.address) && address.lessThan(this.currentVariable.pastTheEndAddress)) { 159 | this.handledVariables.set(name, address); 160 | return decoration; 161 | } 162 | return undefined; 163 | } 164 | 165 | protected initialize(address: Long): void { 166 | this.handledVariables.clear(); 167 | const firstCandidateIndex = this.variables.findIndex(variable => address.lessThan(variable.pastTheEndAddress)); 168 | if (firstCandidateIndex === -1) { 169 | this.currentIndex = this.variables.length; 170 | } else { 171 | this.currentVariable = this.variables[firstCandidateIndex]; 172 | this.currentIndex = firstCandidateIndex; 173 | } 174 | } 175 | 176 | searchForVariable(addressOrName: Long | string): VariableRange | undefined { 177 | if (typeof addressOrName === 'string') { 178 | return this.variables.find(variable => variable.name === addressOrName); 179 | } 180 | let upperLimit = this.variables.length - 1; 181 | let lowerLimit = 0; 182 | while (upperLimit >= lowerLimit) { 183 | const target = Math.floor((lowerLimit + upperLimit) / 2); 184 | const candidate = this.variables[target]; 185 | if (addressOrName >= candidate.address && addressOrName < candidate.pastTheEndAddress) { 186 | return candidate; 187 | } 188 | if (addressOrName < candidate.address) { 189 | upperLimit = target - 1; 190 | } 191 | if (addressOrName >= candidate.pastTheEndAddress) { 192 | lowerLimit = target + 1; 193 | } 194 | } 195 | return undefined; 196 | } 197 | } 198 | 199 | /** 200 | * Get the Registers of the currently selected frame. 201 | */ 202 | export async function getRegisters(session: DebugSession | undefined): Promise { 203 | if (session === undefined) { 204 | console.warn('No active debug session.'); 205 | return []; 206 | } 207 | 208 | const frame = session.currentFrame; 209 | if (frame === undefined) { 210 | throw new Error('No active stack frame.'); 211 | } 212 | 213 | const registers: DebugVariable[] = []; 214 | 215 | const scopes = await frame.getScopes(); 216 | const regScope = scopes.find(x => x.render() === 'Registers'); 217 | if (regScope !== undefined) { 218 | const variables = await regScope.getElements(); 219 | for (const v of variables) { 220 | if (v instanceof DebugVariable) { 221 | registers.push(v); 222 | } 223 | } 224 | } else { 225 | throw new Error('No Register scope in active stack frame.'); 226 | } 227 | return registers; 228 | } 229 | 230 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/multi-select-bar.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | .multi-select-bar { 18 | display: flex; 19 | flex-flow: row nowrap; 20 | user-select: none; 21 | box-sizing: border-box; 22 | } 23 | 24 | .multi-select-checkbox-wrapper { 25 | display: flex; 26 | position: relative; 27 | flex: auto; 28 | text-align: center; 29 | } 30 | 31 | .multi-select-label { 32 | height: 100%; 33 | flex: auto; 34 | display: flex; 35 | align-items: center; 36 | justify-content: center; 37 | border: 1px solid; 38 | padding: 0 var(--theia-ui-padding); 39 | background-color: var(--theia-editor-background); 40 | border-color: var(--theia-dropdown-border); 41 | box-sizing: border-box; 42 | } 43 | 44 | .multi-select-checkbox-wrapper input:checked ~ .multi-select-label { 45 | background-color: var(--theia-input-background); 46 | border-color: var(--theia-sideBar-foreground); 47 | text-decoration: underline; 48 | font-weight: bolder; 49 | } 50 | 51 | 52 | .multi-select-checkbox { 53 | appearance: none; 54 | -webkit-appearance: none; 55 | position: absolute; 56 | left: 0; 57 | top: 0; 58 | margin: 0; 59 | height: 100%; 60 | width: 100%; 61 | cursor: pointer; 62 | } 63 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/utils/multi-select-bar.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import * as React from '@theia/core/shared/react'; 18 | import { MWLabel, MWLabelProps } from './memory-widget-components'; 19 | 20 | export interface SingleSelectItemProps { 21 | id: string; 22 | label: string; 23 | defaultChecked?: boolean; 24 | } 25 | interface MultiSelectBarProps { 26 | items: SingleSelectItemProps[]; 27 | id?: string; 28 | onSelectionChanged: (labelSelected: string, newSelectionState: boolean) => unknown; 29 | } 30 | 31 | export const MultiSelectBar: React.FC = ({ items, onSelectionChanged, id }) => { 32 | const changeHandler: React.ChangeEventHandler = React.useCallback(e => { 33 | onSelectionChanged(e.target.id, e.target.checked); 34 | }, [onSelectionChanged]); 35 | 36 | return ( 37 |
38 | {items.map(({ label, id: itemId, defaultChecked }) => ())} 45 |
46 | ); 47 | }; 48 | 49 | interface LabeledCheckboxProps { 50 | label: string; 51 | id: string; 52 | onChange: React.ChangeEventHandler; 53 | defaultChecked: boolean; 54 | } 55 | 56 | const LabeledCheckbox: React.FC = ({ defaultChecked, label, onChange, id }) => ( 57 |
58 | 66 | 67 |
68 | ); 69 | 70 | export const MWMultiSelect: React.FC = ({ id, label, disabled, items, onSelectionChanged }) => ( 71 | <> 72 | 73 | 74 | 75 | ); 76 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/wrapper-widgets/memory-dock-panel.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { DockPanelRendererFactory } from '@theia/core/lib/browser'; 18 | import { TheiaDockPanel } from '@theia/core/lib/browser/shell/theia-dock-panel'; 19 | import { interfaces } from '@theia/core/shared/inversify'; 20 | /* eslint-disable import/export */ 21 | 22 | export class MemoryDockPanel extends TheiaDockPanel { 23 | toggleMaximized(): void { /* don't */ } 24 | } 25 | 26 | export namespace MemoryDockPanel { 27 | export const ID = 'memory-dock-panel-widget'; 28 | const DOCK_PANEL_ID = 'theia-main-content-panel'; 29 | const THEIA_TABBAR_CLASSES = ['theia-app-centers', 'theia-app-main']; 30 | const CPP_TABBAR_CLASS = 'memory-dock-tabbar'; 31 | const DOCK_PANEL_CLASS = 'memory-dock-panel'; 32 | 33 | const createDockPanel = (factory: DockPanelRendererFactory): MemoryDockPanel => { 34 | const renderer = factory(); 35 | renderer.tabBarClasses.push(...THEIA_TABBAR_CLASSES, CPP_TABBAR_CLASS); 36 | const dockPanel = new MemoryDockPanel({ 37 | mode: 'multiple-document', 38 | renderer, 39 | spacing: 0, 40 | }); 41 | dockPanel.addClass(DOCK_PANEL_CLASS); 42 | dockPanel.id = DOCK_PANEL_ID; 43 | 44 | return dockPanel; 45 | }; 46 | 47 | export const createWidget = (parent: interfaces.Container): MemoryDockPanel => { 48 | const dockFactory = parent.get(DockPanelRendererFactory); 49 | const dockPanel = createDockPanel(dockFactory); 50 | return dockPanel; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/wrapper-widgets/memory-dockpanel-placeholder-widget.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | import { ReactWidget } from '@theia/core/lib/browser'; 17 | import { injectable, postConstruct } from '@theia/core/shared/inversify'; 18 | import * as React from '@theia/core/shared/react'; 19 | 20 | @injectable() 21 | export class MemoryDockpanelPlaceholder extends ReactWidget { 22 | static ID = 'memory-dockpanel-placeholder'; 23 | 24 | @postConstruct() 25 | init(): void { 26 | this.id = MemoryDockpanelPlaceholder.ID; 27 | this.addClass(MemoryDockpanelPlaceholder.ID); 28 | this.update(); 29 | } 30 | 31 | render(): React.ReactNode { 32 | return ( 33 |
34 | Click the 35 | {' '} 36 | 37 | {' '} 38 | icon to add a new memory view or the 39 | {' '} 40 | 41 | {' '} 42 | icon to add a register view. 43 |
44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/browser/wrapper-widgets/memory-layout-widget.tsx: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2021 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { injectable, inject, postConstruct } from '@theia/core/shared/inversify'; 18 | import { ApplicationShell, Message, Panel, Widget, WidgetManager } from '@theia/core/lib/browser'; 19 | import { Disposable, DisposableCollection, Emitter } from '@theia/core'; 20 | import { MemoryWidgetManager } from '../utils/memory-widget-manager'; 21 | import { MemoryWidget } from '../memory-widget/memory-widget'; 22 | import { MemoryDiffSelectWidget } from '../diff-widget/memory-diff-select-widget'; 23 | import { MemoryDockPanel } from './memory-dock-panel'; 24 | import { MemoryDockpanelPlaceholder } from './memory-dockpanel-placeholder-widget'; 25 | 26 | @injectable() 27 | export class MemoryLayoutWidget extends Panel implements Disposable, ApplicationShell.TrackableWidgetProvider { 28 | static readonly ID = 'memory-layout-widget'; 29 | static readonly LABEL = 'Memory Inspector'; 30 | 31 | // Necessary to inherit theia's tabbar styling 32 | static readonly DOCK_PANEL_ID = 'theia-main-content-panel'; 33 | static readonly THEIA_TABBAR_CLASSES = ['theia-app-centers', 'theia-app-main']; 34 | static readonly CPP_TABBAR_CLASS = 'memory-dock-tabbar'; 35 | static readonly DOCK_PANEL_CLASS = 'memory-dock-panel'; 36 | 37 | @inject(WidgetManager) protected readonly widgetManager: WidgetManager; 38 | @inject(MemoryWidgetManager) protected readonly memoryWidgetManager: MemoryWidgetManager; 39 | @inject(MemoryDiffSelectWidget) protected readonly diffSelectWidget: MemoryDiffSelectWidget; 40 | @inject(MemoryDockpanelPlaceholder) protected readonly placeholderWidget: MemoryDockpanelPlaceholder; 41 | @inject(ApplicationShell) protected readonly shell: ApplicationShell; 42 | 43 | protected readonly onDidChangeTrackableWidgetsEmitter = new Emitter(); 44 | readonly onDidChangeTrackableWidgets = this.onDidChangeTrackableWidgetsEmitter.event; 45 | 46 | protected readonly toDispose = new DisposableCollection(); 47 | protected dockPanel: MemoryDockPanel; 48 | protected hasGeneratedWidgetAutomatically = false; 49 | 50 | @postConstruct() 51 | protected async init(): Promise { 52 | this.id = MemoryLayoutWidget.ID; 53 | this.addClass(MemoryLayoutWidget.ID); 54 | this.title.label = MemoryLayoutWidget.LABEL; 55 | this.title.caption = MemoryLayoutWidget.LABEL; 56 | this.title.closable = true; 57 | this.title.iconClass = 'memory-view-icon'; 58 | this.dockPanel = await this.widgetManager.getOrCreateWidget(MemoryDockPanel.ID); 59 | this.addWidget(this.dockPanel); 60 | this.addWidget(this.diffSelectWidget); 61 | this.addWidget(this.placeholderWidget); 62 | this.toDispose.push(this.memoryWidgetManager.onDidCreateNewWidget(widget => { 63 | this.dockPanel.addWidget(widget); 64 | this.dockPanel.activateWidget(widget); 65 | this.onDidChangeTrackableWidgetsEmitter.fire([widget]); 66 | })); 67 | this.toDispose.push(this.memoryWidgetManager.onChanged(() => { 68 | if (!this.memoryWidgetManager.canCompare) { 69 | this.diffSelectWidget.hide(); 70 | } 71 | })); 72 | this.dockPanel.widgetRemoved.connect(this.handleWidgetRemoved.bind(this), this); 73 | this.dockPanel.widgetAdded.connect(this.handleWidgetsChanged.bind(this), this); 74 | this.toDispose.push(this.onDidChangeTrackableWidgetsEmitter); 75 | this.diffSelectWidget.hide(); 76 | this.update(); 77 | } 78 | 79 | toggleComparisonVisibility(): void { 80 | if (this.diffSelectWidget.isHidden) { 81 | this.diffSelectWidget.show(); 82 | } else { 83 | this.diffSelectWidget.hide(); 84 | } 85 | this.update(); 86 | } 87 | 88 | dispose(): void { 89 | this.toDispose.dispose(); 90 | super.dispose(); 91 | } 92 | 93 | protected dockPanelHoldsWidgets(): boolean { 94 | const iter = this.dockPanel.tabBars(); 95 | let tabBar = iter.next(); 96 | while (tabBar) { 97 | if (tabBar.titles.length) { 98 | return true; 99 | } 100 | tabBar = iter.next(); 101 | } 102 | return false; 103 | } 104 | 105 | protected handleWidgetsChanged(): void { 106 | if (this.dockPanelHoldsWidgets()) { 107 | this.placeholderWidget.hide(); 108 | } else { 109 | this.placeholderWidget.show(); 110 | } 111 | } 112 | 113 | protected handleWidgetRemoved(_sender: Widget, widgetRemoved: Widget): void { 114 | if (widgetRemoved instanceof MemoryWidget) { // Sometimes it's the tabbar. 115 | this.handleWidgetsChanged(); 116 | this.shell.activateWidget(this.id); 117 | } 118 | } 119 | 120 | protected async createAndFocusWidget(): Promise { 121 | const widget = await this.memoryWidgetManager.createNewMemoryWidget(); 122 | widget.activate(); 123 | } 124 | 125 | protected async onAfterShow(msg: Message): Promise { 126 | if (!this.hasGeneratedWidgetAutomatically && !this.dockPanelHoldsWidgets()) { 127 | await this.createAndFocusWidget(); 128 | this.hasGeneratedWidgetAutomatically = true; 129 | } 130 | super.onAfterShow(msg); 131 | } 132 | 133 | getTrackableWidgets(): Widget[] { 134 | const children: Widget[] = []; 135 | const childIterator = this.dockPanel.children(); 136 | let currentChild = childIterator.next(); 137 | while (currentChild) { 138 | children.push(currentChild); 139 | currentChild = childIterator.next(); 140 | } 141 | return children; 142 | } 143 | 144 | activateWidget(id: string): Widget | undefined { 145 | const widget = this.getTrackableWidgets().find(candidateWidget => candidateWidget.id === id); 146 | if (widget) { 147 | this.dockPanel.activateWidget(widget); 148 | } 149 | return widget; 150 | } 151 | 152 | onActivateRequest(msg: Message): void { 153 | const displayedWidget = this.dockPanel.currentTabBar?.currentTitle?.owner; 154 | if (displayedWidget) { 155 | displayedWidget.activate(); 156 | } else { 157 | // Only happens if you remove all widgets, then close the view. 158 | this.node.tabIndex = -1; 159 | this.node.focus(); 160 | } 161 | super.onActivateRequest(msg); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/common/util.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import * as Long from 'long'; 18 | 19 | /** 20 | * Parse `hexStr` as an hexadecimal string (with or without the leading 0x) 21 | * and return the value as a Long. 22 | */ 23 | export function hexStrToUnsignedLong(hexStr: string): Long { 24 | if (hexStr.trim().length === 0) { 25 | return new Long(0, 0, true); 26 | } 27 | return Long.fromString(hexStr, true, 16); 28 | } 29 | -------------------------------------------------------------------------------- /packages/cpp-debug/src/common/utils.spec.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2019 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 17 | import { hexStrToUnsignedLong } from './util'; 18 | import { expect } from 'chai'; 19 | import * as Long from 'long'; 20 | 21 | describe('utils', function (): void { 22 | it('hexStrToUnsignedLong', function (): void { 23 | let val = hexStrToUnsignedLong(''); 24 | expect(val).eql(new Long(0, 0, true)); 25 | 26 | val = hexStrToUnsignedLong('0x'); 27 | expect(val).eql(new Long(0, 0, true)); 28 | 29 | val = hexStrToUnsignedLong('0x0'); 30 | expect(val).eql(new Long(0, 0, true)); 31 | 32 | val = hexStrToUnsignedLong('0x1'); 33 | expect(val).eql(new Long(0x1, 0, true)); 34 | 35 | val = hexStrToUnsignedLong('0x12345678abcd'); 36 | expect(val).eql(new Long(0x5678abcd, 0x1234, true)); 37 | 38 | val = hexStrToUnsignedLong('0x12345678abcd1234'); 39 | expect(val).eql(new Long(0xabcd1234, 0x12345678, true)); 40 | }); 41 | 42 | it('Handles -1 correctly', () => { 43 | const val = hexStrToUnsignedLong('-0x1'); 44 | expect(val).eql(Long.fromInt(-1, true)); 45 | }); 46 | 47 | it('Handles long decimal numbers (up to 2^64-1)', () => { 48 | const input = '18446744073709551615'; 49 | const val = Long.fromString(input, true, 10); 50 | expect(val.toString(10)).eql(input); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /scripts/check-publish.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (c) 2019 TypeFox and others 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | // @ts-check 17 | 18 | const path = require('path'); 19 | const chalk = require('chalk').default; 20 | const cp = require('child_process'); 21 | 22 | let code = 0; 23 | const workspaces = JSON.parse(cp.execSync('yarn --silent workspaces info').toString()); 24 | for (const name in workspaces) { 25 | const workspace = workspaces[name]; 26 | const location = path.resolve(process.cwd(), workspace.location); 27 | const packagePath = path.resolve(location, 'package.json'); 28 | const pck = require(packagePath); 29 | if (!pck.private) { 30 | const pckName = `${pck.name}@${pck.version}`; 31 | if (cp.execSync(`npm view ${pckName} version --json`).toString().trim()) { 32 | console.info(`${pckName}: published`); 33 | } else { 34 | console.error(`(${chalk.red('ERR')}) ${pckName}: ${chalk.red('NOT')} published`); 35 | code = 1; 36 | } 37 | } 38 | } 39 | process.exit(code); 40 | -------------------------------------------------------------------------------- /scripts/check_git_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ $(git status --porcelain | wc -c) -gt 0 ]; 3 | then 4 | echo "\nERR: The git repository state changed after the build, this should not happen.\n" 5 | git status 6 | echo "\nHINT: Did you update and commit your 'yarn.lock' ?" 7 | echo "\n You can also check your '.gitgnore'." 8 | exit 1 9 | fi 10 | -------------------------------------------------------------------------------- /scripts/lerna.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2017 TypeFox and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | // @ts-check 17 | const path = require('path'); 18 | 19 | const lernaPath = path.resolve(__dirname, '..', 'node_modules', 'lerna', 'bin', 'lerna'); 20 | 21 | if (process.argv.indexOf('--reject-cycles') === -1) { 22 | process.argv.push('--reject-cycles'); 23 | } 24 | require(lernaPath); 25 | -------------------------------------------------------------------------------- /scripts/post-install.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /******************************************************************************** 3 | * Copyright (C) 2019 Ericsson and others. 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0. 8 | * 9 | * This Source Code may also be made available under the following Secondary 10 | * Licenses when the conditions for such availability set forth in the Eclipse 11 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 12 | * with the GNU Classpath Exception which is available at 13 | * https://www.gnu.org/software/classpath/license.html. 14 | * 15 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 16 | ********************************************************************************/ 17 | 'use-strict'; 18 | 19 | // @ts-check 20 | 21 | const fs = require('fs'); 22 | const path = require('path'); 23 | 24 | async function main() { 25 | const electronCodecTestLogPath = path.resolve('dev-packages/electron/post-install.log'); 26 | if (fs.existsSync(electronCodecTestLogPath)) { 27 | console.log('@theia/electron last logs:'); 28 | console.log(fs.readFileSync(electronCodecTestLogPath, { encoding: 'utf8' }).trimRight()); 29 | } else if (!process.env.THEIA_ELECTRON_SKIP_REPLACE_FFMPEG) { 30 | console.error('Cannot find the log file for the Electron codecs test.'); 31 | } 32 | } 33 | 34 | main().catch(error => { 35 | console.error(error); 36 | process.exit(1); 37 | }); 38 | -------------------------------------------------------------------------------- /scripts/prepare-initial.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /******************************************************************************** 3 | * Copyright (c) 2018 TypeFox and others 4 | * 5 | * This program and the accompanying materials are made available under the 6 | * terms of the Eclipse Public License v. 2.0 which is available at 7 | * http://www.eclipse.org/legal/epl-2.0. 8 | * 9 | * This Source Code may also be made available under the following Secondary 10 | * Licenses when the conditions for such availability set forth in the Eclipse 11 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 12 | * with the GNU Classpath Exception which is available at 13 | * https://www.gnu.org/software/classpath/license.html. 14 | * 15 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 16 | ********************************************************************************/ 17 | // @ts-check 18 | 19 | const fs = require('fs'); 20 | const path = require('path'); 21 | const child_process = require('child_process'); 22 | 23 | function replaceCopyrights() { 24 | const fileNames = child_process.execSync(`git grep --name-only 'Copyright'`, { encoding: 'utf8' }) 25 | .split(new RegExp('\r?\n')) 26 | .filter(_ => _.trim().length !== 0); 27 | for (const fileName of fileNames) { 28 | try { 29 | const content = fs.readFileSync(fileName, { encoding: 'UTF-8' }); 30 | const result = content.replace(new RegExp('\\/\\*.*\r?\n.*(Copyright.*\\d{4}.*)(\r?\n|.)*?\\*\\/'), `/******************************************************************************** 31 | * $1 32 | * 33 | * This program and the accompanying materials are made available under the 34 | * terms of the Eclipse Public License v. 2.0 which is available at 35 | * http://www.eclipse.org/legal/epl-2.0. 36 | * 37 | * This Source Code may also be made available under the following Secondary 38 | * Licenses when the conditions for such availability set forth in the Eclipse 39 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 40 | * with the GNU Classpath Exception which is available at 41 | * https://www.gnu.org/software/classpath/license.html. 42 | * 43 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 44 | ********************************************************************************/`); 45 | fs.writeFileSync(fileName, result); 46 | } catch (e) { 47 | console.error(`Failed to replace copyrights for ${fileName}`, e); 48 | } 49 | } 50 | } 51 | 52 | function replaceLicenses() { 53 | const fileNames = child_process.execSync(`git grep --name-only 'Apache-2.0'`, { encoding: 'utf8' }) 54 | .split(new RegExp('\r?\n')) 55 | .filter(_ => _.trim().length !== 0); 56 | for (const fileName of fileNames) { 57 | try { 58 | if (path.basename(fileName) === 'README.md') { 59 | const content = fs.readFileSync(fileName, { encoding: 'UTF-8' }); 60 | const result = content.replace('[Apache-2.0](https://github.com/eclipse-theia/theia/blob/master/LICENSE)', `- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/) 61 | - [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)`); 62 | fs.writeFileSync(fileName, result); 63 | } 64 | if (path.basename(fileName) === 'package.json') { 65 | const content = fs.readFileSync(fileName, { encoding: 'UTF-8' }); 66 | const result = content.replace('"license": "Apache-2.0"', '"license": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0"'); 67 | fs.writeFileSync(fileName, result); 68 | } 69 | } catch (e) { 70 | console.error(`Failed to replace license for ${fileName}`, e); 71 | } 72 | } 73 | } 74 | 75 | replaceCopyrights(); 76 | replaceLicenses(); 77 | -------------------------------------------------------------------------------- /scripts/run-reverse-topo.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Copyright (C) 2020 Ericsson and others. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0 which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the Eclipse 10 | * Public License v. 2.0 are satisfied: GNU General Public License, version 2 11 | * with the GNU Classpath Exception which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | ********************************************************************************/ 16 | 'use-strict'; 17 | 18 | /** 19 | * This script will run a subcommand for each package in reverse-topology order. 20 | * 21 | * The command will be ran once per package, you can use the __PACKAGE__ tag in 22 | * your command and arguments and it will get replaced by the current package 23 | * from the iteration. 24 | */ 25 | 26 | // @ts-check 27 | 28 | const cp = require('child_process'); 29 | 30 | /** @type {LernaPackage[]} */ 31 | const LERNA_SORT = JSON.parse(cp.execSync('yarn --silent lerna ls --sort --json').toString()); 32 | 33 | /** @type {{ [key: string]: YarnWorkspace }} */ 34 | const YARN_WORKSPACES = JSON.parse(cp.execSync('yarn --silent workspaces info').toString()); 35 | 36 | // reverse topology order 37 | LERNA_SORT.reverse(); 38 | 39 | for (const package of LERNA_SORT) { 40 | const workspace = YARN_WORKSPACES[package.name]; 41 | const command = process.argv[2]; 42 | const args = process.argv.slice(3).map(arg => arg.replace(/__PACKAGE__/g, package.name)); 43 | console.log(`${package.name}: $ ${command} ${args.join(' ')}`); 44 | cp.spawnSync(command, args, { 45 | stdio: ['ignore', 'ignore', 'inherit'], 46 | cwd: workspace.location, 47 | }); 48 | } 49 | 50 | /** 51 | * @typedef LernaPackage 52 | * @property {string} name 53 | */ 54 | 55 | /** 56 | * @typedef YarnWorkspace 57 | * @property {string} location 58 | */ 59 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "README": [ 3 | "THIS FILE SHOULD NOT BE USED FOR COMPILATION.", 4 | "THIS FILE IS WRITTEN FOR TSSERVER TO UNDERSTAND OUR MONOREPO.", 5 | "SEE `compile.tsconfig.json` FOR COMPILATION CONFIGURATION." 6 | ], 7 | "extends": "./configs/base.tsconfig.json", 8 | "include": [ 9 | "dev-packages/*/src", 10 | "packages/*/src", 11 | "examples/*/src", 12 | "examples/browser/src-gen" 13 | ], 14 | "compilerOptions": { 15 | "allowJs": true, 16 | "noEmit": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@theia/example-browser/*": [ 20 | "examples/browser/*" 21 | ], 22 | "@theia/example-electron/*": [ 23 | "examples/electron/*" 24 | ], 25 | "@theia/cpp-debug/lib/*": [ 26 | "packages/cpp-debug/src/*" 27 | ], 28 | "@cpp-debug/example-electron/*": [ 29 | "examples/electron/*" 30 | ], 31 | "@cpp-debug/example-browser/*": [ 32 | "examples/browser/*" 33 | ] 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tsfmt.json: -------------------------------------------------------------------------------- 1 | { 2 | "insertSpaceAfterFunctionKeywordForAnonymousFunctions": true 3 | } 4 | --------------------------------------------------------------------------------
{regName}
{options.hexadecimal}{options.decimal}{options.octal}{options.binary}