├── .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 |
4 |
5 |
6 |
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 |
28 |
29 |
30 |
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 |
4 |
5 |
ECLIPSE THEIA - C/C++ EXTENSIONS
6 |
7 |
8 |
9 | [](https://gitpod.io#https://github.com/eclipse-theia/theia-cpp-extensions)
10 | [](https://github.com/eclipse-theia/theia-cpp-extensions/labels/help%20wanted)
11 | [](https://github.com/eclipse-theia/theia-cpp-extensions/actions?query=branch%3Amaster)
12 | [](https://github.com/eclipse-theia/theia-cpp-extensions/labels/question)
13 | [](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 |
106 | Go
107 |
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 |
107 | Go
108 |
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 | {regName}
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({options.hexadecimal} );
180 | }
181 | if (this.options.columnsDisplayed.decimal.doRender) {
182 | additionalColumns.push({options.decimal} );
183 | }
184 | if (this.options.columnsDisplayed.octal.doRender) {
185 | additionalColumns.push({options.octal} );
186 | }
187 | if (this.options.columnsDisplayed.binary.doRender) {
188 | additionalColumns.push({options.binary} );
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 |
30 | {label}
31 |
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 |
84 | {options.map(option => {option} )}
85 |
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 |
106 | {options.map(option => {option[1]} )}
107 |
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 |
140 | {options.reverse().map(option => {option} )}
141 |
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 |
188 | {options.map(option => (
189 |
193 | {option}
194 | ))}
195 |
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 |
--------------------------------------------------------------------------------