Compare commits
35 Commits
2.0.0-beta
...
2.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f6e623ca9c | ||
![]() |
1e0f52bbdd | ||
![]() |
6dadd1775a | ||
![]() |
067cc8766a | ||
![]() |
15b0564212 | ||
![]() |
e90fa27ebf | ||
![]() |
ef03d3f583 | ||
![]() |
5c8669d699 | ||
![]() |
9cd91464e3 | ||
![]() |
5a262d42c1 | ||
![]() |
eadc993854 | ||
![]() |
c64ac48fe3 | ||
![]() |
ac502053d7 | ||
![]() |
1d8eb0d544 | ||
![]() |
e94702349b | ||
![]() |
d648159f43 | ||
![]() |
acbd98d0f8 | ||
![]() |
22e02e19b8 | ||
![]() |
7ee6d5ad8f | ||
![]() |
19aa3dd8a5 | ||
![]() |
de4ae232fa | ||
![]() |
5a57576320 | ||
![]() |
8e1feb36ff | ||
![]() |
cdadda85e5 | ||
![]() |
596d54a102 | ||
![]() |
e1b36c6c56 | ||
![]() |
86be874bb0 | ||
![]() |
057904d38d | ||
![]() |
0aef4b328f | ||
![]() |
79b1a306a1 | ||
![]() |
709baaca98 | ||
![]() |
a06a69dff9 | ||
![]() |
561d5fbbd3 | ||
![]() |
df0aafd928 | ||
![]() |
ad2cfc8894 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -2,7 +2,7 @@
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
labels: 'type: bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,7 +2,7 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
labels: 'type: enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
30
.github/workflows/build.yml
vendored
@@ -16,6 +16,7 @@ on:
|
||||
jobs:
|
||||
|
||||
build:
|
||||
if: github.repository == 'arduino/arduino-ide'
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
@@ -50,21 +51,26 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
IS_NIGHTLY: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') }}
|
||||
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
IS_FORK: ${{ github.event.pull_request.head.repo.fork == true }}
|
||||
run: |
|
||||
# See: https://www.electron.build/code-signing
|
||||
if [ "${{ runner.OS }}" = "macOS" ]; then
|
||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.p12"
|
||||
# APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from:
|
||||
# https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate
|
||||
echo "${{ secrets.APPLE_SIGNING_CERTIFICATE_P12 }}" | base64 --decode > "$CSC_LINK"
|
||||
if [ $IS_FORK = true ]; then
|
||||
echo "Skipping the app signing: building from a fork."
|
||||
else
|
||||
if [ "${{ runner.OS }}" = "macOS" ]; then
|
||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.p12"
|
||||
# APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from:
|
||||
# https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate
|
||||
echo "${{ secrets.APPLE_SIGNING_CERTIFICATE_P12 }}" | base64 --decode > "$CSC_LINK"
|
||||
|
||||
export CSC_KEY_PASSWORD="${{ secrets.KEYCHAIN_PASSWORD }}"
|
||||
export CSC_KEY_PASSWORD="${{ secrets.KEYCHAIN_PASSWORD }}"
|
||||
|
||||
elif [ "${{ runner.OS }}" = "Windows" ]; then
|
||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.pfx"
|
||||
echo "${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PFX }}" | base64 --decode > "$CSC_LINK"
|
||||
elif [ "${{ runner.OS }}" = "Windows" ]; then
|
||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.pfx"
|
||||
echo "${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PFX }}" | base64 --decode > "$CSC_LINK"
|
||||
|
||||
export CSC_KEY_PASSWORD="${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}"
|
||||
export CSC_KEY_PASSWORD="${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}"
|
||||
fi
|
||||
fi
|
||||
|
||||
yarn --cwd ./electron/packager/
|
||||
@@ -120,7 +126,7 @@ jobs:
|
||||
|
||||
publish:
|
||||
needs: changelog
|
||||
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
|
||||
if: github.repository == 'arduino/arduino-ide' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main'))
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download [GitHub Actions]
|
||||
@@ -141,7 +147,7 @@ jobs:
|
||||
|
||||
release:
|
||||
needs: changelog
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: github.repository == 'arduino/arduino-ide' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download [GitHub Actions]
|
||||
|
5
.github/workflows/check-certificates.yml
vendored
@@ -15,6 +15,11 @@ env:
|
||||
|
||||
jobs:
|
||||
check-certificates:
|
||||
# Only run when the workflow will have access to the certificate secrets.
|
||||
if: >
|
||||
(github.event_name != 'pull_request' && github.repository == 'arduino/arduino-ide') ||
|
||||
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'arduino/arduino-ide')
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
|
136
BUILDING.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Development
|
||||
|
||||
This page includes technical documentation for developers who want to build the IDE locally and contribute to the project.
|
||||
|
||||
## Architecture overview
|
||||
|
||||
The IDE consists of three major parts:
|
||||
- the _Electron main_ process,
|
||||
- the _backend_, and
|
||||
- the _frontend_.
|
||||
|
||||
The _Electron main_ process is responsible for:
|
||||
- creating the application,
|
||||
- managing the application lifecycle via listeners, and
|
||||
- creating and managing the web pages for the app.
|
||||
|
||||
In Electron, the process that runs the main entry JavaScript file is called the main process. The _Electron main_ process can display a GUI by creating web pages. An Electron app always has exactly on main process.
|
||||
|
||||
By default, whenever the _Electron main_ process creates a web page, it will instantiate a new `BrowserWindow` instance. Since Electron uses Chromium for displaying web pages, Chromium's multi-process architecture is also used. Each web page in Electron runs in its own process, which is called the renderer process. Each `BrowserWindow` instance runs the web page in its own renderer process. When a `BrowserWindow` instance is destroyed, the corresponding renderer process is also terminated. The main process manages all web pages and their corresponding renderer processes. Each renderer process is isolated and only cares about the web page running in it.<sup>[[1]]</sup>
|
||||
|
||||
In normal browsers, web pages usually run in a sandboxed environment, and accessing native resources are disallowed. However, Electron has the power to use Node.js APIs in the web pages allowing lower-level OS interactions. Due to security reasons, accessing native resources is an undesired behavior in the IDE. So by convention, we do not use Node.js APIs. (Note: the Node.js integration is [not yet disabled](https://github.com/eclipse-theia/theia/issues/2018) although it is not used). In the IDE, only the _backend_ allows OS interaction.
|
||||
|
||||
The _backend_ process is responsible for:
|
||||
- providing access to the filesystem,
|
||||
- communicating with the [Arduino CLI](https://github.com/arduino/arduino-cli) via gRPC,
|
||||
- running your terminal,
|
||||
- exposing additional RESTful APIs,
|
||||
- performing the Git commands in the local repositories,
|
||||
- hosting and running any VS Code extensions, or
|
||||
- executing VS Code tasks<sup>[[2]]</sup>.
|
||||
|
||||
The _Electron main_ process spawns the _backend_ process. There is always exactly one _backend_ process. However, due to performance considerations, the _backend_ spawns several sub-processes for the filesystem watching, Git repository discovery, etc. The communication between the _backend_ process and its sub-processes is established via IPC. Besides spawning sub-processes, the _backend_ will start an HTTP server on a random available port, and serves the web application as static content. When the sub-processes are up and running, and the HTTP server is also listening, the _backend_ process sends the HTTP server port to the _Electron main_ process via IPC. The _Electron main_ process will load the _backend_'s endpoint in the `BrowserWindow`.
|
||||
|
||||
The _frontend_ is running as an Electron renderer process and can invoke services implemented on the _backend_. The communication between the _backend_ and the _frontend_ is done via JSON-RPC over a websocket connection. This means, the services running in the _frontend_ are all proxies, and will ask the corresponding service implementation on the _backend_.
|
||||
|
||||
[1]: https://www.electronjs.org/docs/tutorial/application-architecture#differences-between-main-process-and-renderer-process
|
||||
[2]: https://code.visualstudio.com/Docs/editor/tasks
|
||||
|
||||
|
||||
## Build from source
|
||||
|
||||
If you’re familiar with TypeScript, the [Theia IDE](https://theia-ide.org/), and if you want to contribute to the
|
||||
project, you should be able to build the Arduino IDE locally. Please refer to the [Theia IDE prerequisites](https://github.com/theia-ide/theia/blob/master/doc/) documentation for the setup instructions.
|
||||
|
||||
### Build
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
|
||||
### Rebuild the native dependencies
|
||||
```sh
|
||||
yarn rebuild:electron
|
||||
```
|
||||
|
||||
### Start
|
||||
```sh
|
||||
yarn start
|
||||
```
|
||||
|
||||
### CI
|
||||
|
||||
This project is built on [GitHub Actions](https://github.com/arduino/arduino-ide/actions).
|
||||
|
||||
- _Snapshot_ builds run when changes are pushed to the `main` branch, or when a PR is created against the `main` branch. For the sake of the review and verification process, the build artifacts can be downloaded from the GitHub Actions page. Note: [due to a limitation](https://github.com/actions/upload-artifact/issues/80#issuecomment-630030144) with the GH Actions UI, you cannot download a particular build, but you have to get all together inside the `build-artifacts.zip`.
|
||||
- _Nightly_ builds run every day at 03:00 GMT from the `main` branch.
|
||||
- _Release_ builds run when a new tag is pushed to the remote. The tag must follow the [semver](https://semver.org/). For instance, `1.2.3` is a correct tag, but `v2.3.4` won't work. Steps to trigger a new release build:
|
||||
- Create a local tag:
|
||||
```sh
|
||||
git tag -a 1.2.3 -m "Creating a new tag for the `1.2.3` release."
|
||||
```
|
||||
- Push it to the remote:
|
||||
```sh
|
||||
git push origin 1.2.3
|
||||
```
|
||||
|
||||
## Notes for macOS contributors
|
||||
Beginning in macOS 10.14.5, the software [must be notarized to run](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution). The signing and notarization processes for the Arduino IDE are managed by our Continuous Integration (CI) workflows, implemented with GitHub Actions. On every push and pull request, the Arduino IDE is built and saved to a workflow artifact. These artifacts can be used by contributors and beta testers who don't want to set up a build system locally.
|
||||
For security reasons, signing and notarization are disabled for workflow runs for pull requests from forks of this repository. This means that macOS will block you from running those artifacts.
|
||||
Due to this limitation, Mac users have two options for testing contributions from forks:
|
||||
|
||||
### The Safe approach (recommended)
|
||||
|
||||
Follow [the instructions above](#build-from-source) to create the build environment locally, then build the code you want to test.
|
||||
|
||||
### The Risky approach
|
||||
|
||||
*Please note that this approach is risky as you are lowering the security on your system, therefore we strongly discourage you from following it.*
|
||||
1. Use [this guide](https://help.apple.com/xcode/mac/10.2/index.html?localePath=en.lproj#/dev9b7736b0e), in order to disable Gatekeeper (at your own risk!).
|
||||
1. Download the unsigned artifact provided by the CI workflow run related to the Pull Request at each push.
|
||||
1. Re-enable Gatekeeper after tests are done, following the guide linked above.
|
||||
|
||||
### Creating a release
|
||||
|
||||
You will not need to create a new release yourself as the Arduino team takes care of this on a regular basis, but we are documenting the process here. Let's assume the current version is `0.1.3` and you want to release `0.2.0`.
|
||||
|
||||
- Make sure the `main` state represents what you want to release and you're on `main`.
|
||||
- Prepare a release-candidate build on a branch:
|
||||
```bash
|
||||
git branch 0.2.0-rc \
|
||||
&& git checkout 0.2.0-rc
|
||||
```
|
||||
- Bump up the version number. It must be a valid [semver](https://semver.org/) and must be greater than the current one:
|
||||
```bash
|
||||
yarn update:version 0.2.0
|
||||
```
|
||||
- This should generate multiple outgoing changes with the version update.
|
||||
- Commit your changes and push to the remote:
|
||||
```bash
|
||||
git add . \
|
||||
&& git commit -s -m "Updated versions to 0.2.0" \
|
||||
&& git push
|
||||
```
|
||||
- Create the GH PR the workflow starts automatically.
|
||||
- Once you're happy with the RC, merge the changes to the `main`.
|
||||
- Create a tag and push it:
|
||||
```bash
|
||||
git tag -a 0.2.0 -m "0.2.0" \
|
||||
&& git push origin 0.2.0
|
||||
```
|
||||
- The release build starts automatically and uploads the artifacts with the changelog to the [release page](https://github.com/arduino/arduino-ide/releases).
|
||||
- If you do not want to release the `EXE` and `MSI` installers, wipe them manually.
|
||||
- If you do not like the generated changelog, modify it and update the GH release.
|
||||
|
||||
## FAQ
|
||||
|
||||
* *Can I manually change the version of the [`arduino-cli`](https://github.com/arduino/arduino-cli/) used by the IDE?*
|
||||
|
||||
Yes. It is possible but not recommended. The CLI exposes a set of functionality via [gRPC](https://github.com/arduino/arduino-cli/tree/master/rpc) and the IDE uses this API to communicate with the CLI. Before we build a new version of IDE, we pin a specific version of CLI and use the corresponding `proto` files to generate TypeScript modules for gRPC. This means, a particular version of IDE is compliant only with the pinned version of CLI. Mismatching IDE and CLI versions might not be able to communicate with each other. This could cause unpredictable IDE behavior.
|
||||
|
||||
* *I have understood that not all versions of the CLI are compatible with my version of IDE but how can I manually update the `arduino-cli` inside the IDE?*
|
||||
|
||||
[Get](https://arduino.github.io/arduino-cli/installation) the desired version of `arduino-cli` for your platform and manually replace the one inside the IDE. The CLI can be found inside the IDE at:
|
||||
- Windows: `C:\path\to\Arduino IDE\resources\app\node_modules\arduino-ide-extension\build\arduino-cli.exe`,
|
||||
- macOS: `/path/to/Arduino IDE.app/Contents/Resources/app/node_modules/arduino-ide-extension/build/arduino-cli`, and
|
||||
- Linux: `/path/to/Arduino IDE/resources/app/node_modules/arduino-ide-extension/build/arduino-cli`.
|
||||
|
661
LICENSE.txt
Normal file
@@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
156
README.md
@@ -1,36 +1,24 @@
|
||||
# Arduino IDE
|
||||
<img src="https://content.arduino.cc/website/Arduino_logo_teal.svg" height="100" align="right" />
|
||||
|
||||
# Arduino IDE 2.x (beta)
|
||||
|
||||
[](https://github.com/arduino/arduino-ide/actions?query=workflow%3A%22Arduino+IDE%22)
|
||||
|
||||
### Download
|
||||
This repository contains the source code of the Arduino IDE 2.x, which is currently in beta stage. If you're looking for the stable IDE, go to the repository of the 1.x version at https://github.com/arduino/Arduino.
|
||||
|
||||
You can download the latest version of the Arduino IDE application for the supported platforms from the [GitHub release page](https://github.com/arduino/arduino-ide/releases) or following the links in the following table.
|
||||
The Arduino IDE 2.x is a major rewrite, sharing no code with the IDE 1.x. It is based on the [Theia IDE](https://theia-ide.org/) framework and built with [Electron](https://www.electronjs.org/). The backend operations such as compilation and uploading are offloaded to an [arduino-cli](https://github.com/arduino/arduino-cli) instance running in daemon mode. This new IDE was developed with the goal of preserving the same interface and user experience of the previous major version in order to provide a frictionless upgrade.
|
||||
|
||||
#### Latest version
|
||||
> ⚠️ This is **beta** software. Help us test it!
|
||||
|
||||
Platform | 32 bit | 64 bit |
|
||||
--------- | ------------------------ | ------------------------------------------------------------------------------ |
|
||||
Linux | | [Linux 64 bit] |
|
||||
Linux ARM | [🚧 Work in progress...] | [🚧 Work in progress...] |
|
||||
Windows | | [Windows 64 bit installer]<br />[Windows 64 bit MSI]<br />[Windows 64 bit ZIP] |
|
||||
macOS | | [macOS 64 bit] |
|
||||

|
||||
|
||||
[🚧 Work in progress...]: https://github.com/arduino/arduino-ide/issues/287
|
||||
[Linux 64 bit]: https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_Linux_64bit.zip
|
||||
[Windows 64 bit installer]: https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_Windows_64bit.exe
|
||||
[Windows 64 bit MSI]: https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_Windows_64bit.msi
|
||||
[Windows 64 bit ZIP]: https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_Windows_64bit.zip
|
||||
[macOS 64 bit]: https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_macOS_64bit.dmg
|
||||
## Download
|
||||
|
||||
#### Previous versions
|
||||
|
||||
These are available from the [GitHub releases page](https://github.com/arduino/arduino-ide/releases).
|
||||
|
||||
#### Nightly builds
|
||||
You can download the latest version from the [software download page on the Arduino website](https://www.arduino.cc/en/software#experimental-software).
|
||||
### Nightly builds
|
||||
|
||||
These builds are generated every day at 03:00 GMT from the `main` branch and
|
||||
should be considered unstable. In order to get the latest nightly build
|
||||
available for the supported platform, use the following links:
|
||||
should be considered unstable:
|
||||
|
||||
Platform | 32 bit | 64 bit |
|
||||
--------- | ------------------------ | ------------------------------------------------------------------------------------------------------ |
|
||||
@@ -39,7 +27,7 @@ Linux ARM | [🚧 Work in progress...] | [🚧 Work in progress...]
|
||||
Windows | | [Nightly Windows 64 bit installer]<br />[Nightly Windows 64 bit MSI]<br />[Nightly Windows 64 bit ZIP] |
|
||||
macOS | | [Nightly macOS 64 bit] |
|
||||
|
||||
[🚧 Work in progress...]: https://github.com/arduino/arduino-ide/issues/287
|
||||
[🚧 Work in progress...]: https://github.com/arduino/arduino-ide/issues/107
|
||||
[Nightly Linux 64 bit]: https://downloads.arduino.cc/arduino-ide/nightly/arduino-ide_nightly-latest_Linux_64bit.zip
|
||||
[Nightly Windows 64 bit installer]: https://downloads.arduino.cc/arduino-ide/nightly/arduino-ide_nightly-latest_Windows_64bit.exe
|
||||
[Nightly Windows 64 bit MSI]: https://downloads.arduino.cc/arduino-ide/nightly/arduino-ide_nightly-latest_Windows_64bit.msi
|
||||
@@ -49,117 +37,41 @@ macOS | | [Nightly macOS 64 bit]
|
||||
> These links return an HTTP `302: Found` response, redirecting to latest
|
||||
generated builds by replacing `latest` with the latest available build
|
||||
date, using the format YYYYMMDD (i.e for 2019/Aug/06 `latest` is
|
||||
replaced with `20190806` )
|
||||
replaced with `20190806`)
|
||||
|
||||
### Build from source
|
||||
## Support
|
||||
|
||||
If you’re familiar with TypeScript, the [Theia IDE](https://theia-ide.org/), and if you want to contribute to the
|
||||
project, you should be able to build the Arduino IDE locally. Please refer to the [Theia IDE prerequisites](https://github.com/theia-ide/theia/blob/master/doc/) documentation for the setup instructions.
|
||||
If you need assistance, see the [Help Center](https://support.arduino.cc/hc/en-us/categories/360002212660-Software-and-Downloads) and browse the [forum](https://forum.arduino.cc/index.php?board=150.0).
|
||||
|
||||
### Build
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
## Bugs & Issues
|
||||
|
||||
### Rebuild the native dependencies
|
||||
```sh
|
||||
yarn rebuild:electron
|
||||
```
|
||||
If you want to report an issue, you can submit it to the [issue tracker](https://github.com/arduino/arduino-ide/issues) of this repository. A few rules apply:
|
||||
|
||||
### Start
|
||||
```sh
|
||||
yarn start
|
||||
```
|
||||
* Before posting, please check if the same problem has been already reported by someone else to avoid duplicates.
|
||||
* Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. Make sure you're using an original Arduino board.
|
||||
|
||||
### CI
|
||||
### Security
|
||||
|
||||
This project is built on [GitHub Actions](https://github.com/bcmi-labs/arduino-editor/actions?query=workflow%3A%22Arduino+Pro+IDE%22).
|
||||
If you think you found a vulnerability or other security-related bug in this project, please read our
|
||||
[security policy](https://github.com/arduino/arduino-ide/security/policy) and report the bug to our Security Team 🛡️
|
||||
Thank you!
|
||||
|
||||
- _Snapshot_ builds run when changes are pushed to the `main` branch, or when a PR is created against the `main` branch. For the sake of the review and verification process, the build artifacts can be downloaded from the GitHub Actions page. Note: [due to a limitation](https://github.com/actions/upload-artifact/issues/80#issuecomment-630030144) with the GH Actions UI, you cannot download a particular build, but you have to get all together inside the `build-artifacts.zip`.
|
||||
- _Nightly_ builds run every day at 03:00 GMT from the `main` branch.
|
||||
- _Release_ builds run when a new tag is pushed to the remote. The tag must follow the [semver](https://semver.org/). For instance, `1.2.3` is a correct tag, but `v2.3.4` won't work. Steps to trigger a new release build:
|
||||
- Create a local tag:
|
||||
```sh
|
||||
git tag -a 1.2.3 -m "Creating a new tag for the `1.2.3` release."
|
||||
```
|
||||
- Push it to the remote:
|
||||
```sh
|
||||
git push origin 1.2.3
|
||||
```
|
||||
e-mail contact: security@arduino.cc
|
||||
|
||||
### Creating a GH release
|
||||
This section guides you through how to create a new release. Let's assume the current version is `0.1.3` and you want to release `0.2.0`.
|
||||
## Contributions and development
|
||||
|
||||
- Make sure the `main` state represents what you want to release and you're on `main`.
|
||||
- Prepare a release-candidate build on a branch:
|
||||
```bash
|
||||
git branch 0.2.0-rc \
|
||||
&& git checkout 0.2.0-rc
|
||||
```
|
||||
- Bump up the version number. It must be a valid [semver](https://semver.org/) and must be greater than the current one:
|
||||
```bash
|
||||
yarn update:version 0.2.0
|
||||
```
|
||||
- This should generate multiple outgoing changes with the version update.
|
||||
- Commit your changes and push to the remote:
|
||||
```bash
|
||||
git add . \
|
||||
&& git commit -s -m "Updated versions to 0.2.0" \
|
||||
&& git push
|
||||
```
|
||||
- Create the GH PR the workflow starts automatically.
|
||||
- Once you're happy with the RC, merge the changes to the `main`.
|
||||
- Create a tag and push it:
|
||||
```bash
|
||||
git tag -a 0.2.0 -m "0.2.0" \
|
||||
&& git push origin 0.2.0
|
||||
```
|
||||
- The release build starts automatically and uploads the artifacts with the changelog to the Pro IDE [release page](https://github.com/arduino/arduino-ide/releases).
|
||||
- If you do not want to release the `EXE` and `MSI` installers, wipe them manually.
|
||||
- If you do not like the generated changelog, modify it and update the GH release.
|
||||
Contributions are very welcome! You can browse the list of open issues to see what's needed and then you can submit your code using a Pull Request. Please provide detailed descriptions. We also appreciate any help in testing issues and patches contributed by other users.
|
||||
|
||||
This repository contains the main code, but two more repositories are included during the build process:
|
||||
|
||||
### FAQ
|
||||
* [vscode-arduino-tools](https://github.com/arduino/vscode-arduino-tools): provides support for the language server and the debugger
|
||||
* [arduino-language-server](https://github.com/arduino/arduino-language-server): provides the language server that parses Arduino code
|
||||
|
||||
- Q: Can I manually change the version of the [`arduino-cli`](https://github.com/arduino/arduino-cli/) used by the IDE?
|
||||
- A: Yes. It is possible but not recommended. The CLI exposes a set of functionality via [gRPC](https://github.com/arduino/arduino-cli/tree/master/rpc) and the IDE uses this API to communicate with the CLI. Before we build a new version of IDE, we pin a specific version of CLI and use the corresponding `proto` files to generate TypeScript modules for gRPC. This means, a particular version of IDE is compliant only with the pinned version of CLI. Mismatching IDE and CLI versions might not be able to communicate with each other. This could cause unpredictable IDE behavior.
|
||||
See the [BUILDING.md](BUILDING.md) for a technical overview of the application and instructions for building the code.
|
||||
## Donations
|
||||
|
||||
- Q: I have understood that not all versions of the CLI is compatible with my version of IDE but how can I manually update the `arduino-cli` inside the IDE?
|
||||
- A: [Get](https://arduino.github.io/arduino-cli/installation) the desired version of `arduino-cli` for your platform and manually replace the one inside the IDE. The CLI can be found inside the IDE at:
|
||||
- Windows: `C:\path\to\Arduino IDE\resources\app\node_modules\arduino-ide-extension\build\arduino-cli.exe`,
|
||||
- macOS: `/path/to/Arduino IDE.app/Contents/Resources/app/node_modules/arduino-ide-extension/build/arduino-cli`, and
|
||||
- Linux: `/path/to/Arduino IDE/resources/app/node_modules/arduino-ide-extension/build/arduino-cli`.
|
||||
This open source code was written by the Arduino team and is maintained on a daily basis with the help of the community. We invest a considerable amount of time in development, testing and optimization. Please consider [donating](https://www.arduino.cc/en/donate/) or [sponsoring](https://github.com/sponsors/arduino) to support our work, as well as [buying original Arduino boards](https://store.arduino.cc/) which is the best way to make sure our effort can continue in the long term.
|
||||
|
||||
### Architecture overview
|
||||
## License
|
||||
|
||||
The Pro IDE consists of three major parts:
|
||||
- the _Electron main_ process,
|
||||
- the _backend_, and
|
||||
- the _frontend_.
|
||||
|
||||
The _Electron main_ process is responsible for:
|
||||
- creating the application,
|
||||
- managing the application lifecycle via listeners, and
|
||||
- creating and managing the web pages for the app.
|
||||
|
||||
In Electron, the process that runs the main entry JavaScript file is called the main process. The _Electron main_ process can display a GUI by creating web pages. An Electron app always has exactly on main process.
|
||||
|
||||
By default, whenever the _Electron main_ process creates a web page, it will instantiate a new `BrowserWindow` instance. Since Electron uses Chromium for displaying web pages, Chromium's multi-process architecture is also used. Each web page in Electron runs in its own process, which is called the renderer process. Each `BrowserWindow` instance runs the web page in its own renderer process. When a `BrowserWindow` instance is destroyed, the corresponding renderer process is also terminated. The main process manages all web pages and their corresponding renderer processes. Each renderer process is isolated and only cares about the web page running in it.<sup>[[1]]</sup>
|
||||
|
||||
In normal browsers, web pages usually run in a sandboxed environment, and accessing native resources are disallowed. However, Electron has the power to use Node.js APIs in the web pages allowing lower-level OS interactions. Due to security reasons, accessing native resources is an undesired behavior in the Pro IDE. So by convention, we do not use Node.js APIs. (Note: the Node.js integration is [not yet disabled](https://github.com/eclipse-theia/theia/issues/2018) although it is not used). In the Pro IDE, only the _backend_ allows OS interaction.
|
||||
|
||||
The _backend_ process is responsible for:
|
||||
- providing access to the filesystem,
|
||||
- communicating with the Arduino CLI via gRPC,
|
||||
- running your terminal,
|
||||
- exposing additional RESTful APIs,
|
||||
- performing the Git commands in the local repositories,
|
||||
- hosting and running any VS Code extensions, or
|
||||
- executing VS Code tasks<sup>[[2]]</sup>.
|
||||
|
||||
The _Electron main_ process spawns the _backend_ process. There is always exactly one _backend_ process. However, due to performance considerations, the _backend_ spawns several sub-processes for the filesystem watching, Git repository discovery, etc. The communication between the _backend_ process and its sub-processes is established via IPC. Besides spawning sub-processes, the _backend_ will start an HTTP server on a random available port, and serves the web application as static content. When the sub-processes are up and running, and the HTTP server is also listening, the _backend_ process sends the HTTP server port to the _Electron main_ process via IPC. The _Electron main_ process will load the _backend_'s endpoint in the `BrowserWindow`.
|
||||
|
||||
The _frontend_ is running as an Electron renderer process and can invoke services implemented on the _backend_. The communication between the _backend_ and the _frontend_ is done via JSON-RPC over a websocket connection. This means, the services running in the _frontend_ are all proxies, and will ask the corresponding service implementation on the _backend_.
|
||||
|
||||
[1]: https://www.electronjs.org/docs/tutorial/application-architecture#differences-between-main-process-and-renderer-process
|
||||
[2]: https://code.visualstudio.com/Docs/editor/tasks
|
||||
The code contained in this repository and the executable distributions are licensed under the terms of the GNU AGPLv3. The executable distributions contain third-party code licensed under other compatible licenses such as GPLv2, MIT and BSD-3. If you have questions about licensing please contact us at [license@arduino.cc](mailto:license@arduino.cc).
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "arduino-ide-extension",
|
||||
"version": "2.0.0-beta.2",
|
||||
"version": "2.0.0-beta.4",
|
||||
"description": "An extension for Theia building the Arduino IDE",
|
||||
"license": "MIT",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"prepare": "yarn download-cli && yarn download-ls && yarn clean && yarn download-examples && yarn build",
|
||||
"clean": "rimraf lib",
|
||||
@@ -46,6 +46,7 @@
|
||||
"@types/temp": "^0.8.34",
|
||||
"@types/which": "^1.3.1",
|
||||
"ajv": "^6.5.3",
|
||||
"async-mutex": "^0.3.0",
|
||||
"css-element-queries": "^1.2.0",
|
||||
"dateformat": "^3.0.3",
|
||||
"deepmerge": "^4.2.2",
|
||||
@@ -114,16 +115,13 @@
|
||||
"frontend": "lib/browser/theia/core/browser-menu-module",
|
||||
"frontendElectron": "lib/electron-browser/theia/core/electron-menu-module"
|
||||
},
|
||||
{
|
||||
"frontend": "lib/browser/boards/quick-open/boards-quick-open-module"
|
||||
},
|
||||
{
|
||||
"electronMain": "lib/electron-main/arduino-electron-main-module"
|
||||
}
|
||||
],
|
||||
"arduino": {
|
||||
"cli": {
|
||||
"version": "0.16.0"
|
||||
"version": "0.17.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const debounce = require('lodash.debounce');
|
||||
import { Mutex } from 'async-mutex';
|
||||
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService, ILogger } from '@theia/core';
|
||||
import {
|
||||
ContextMenuRenderer,
|
||||
@@ -201,7 +201,6 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
if (selectedBoard) {
|
||||
const { name, fqbn } = selectedBoard;
|
||||
if (fqbn) {
|
||||
await this.hostedPluginSupport.didStart;
|
||||
this.startLanguageServer(fqbn, name);
|
||||
}
|
||||
}
|
||||
@@ -223,35 +222,69 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
webContents.setZoomLevel(event.newValue || 0);
|
||||
}
|
||||
});
|
||||
app.shell.leftPanelHandler.removeMenu('settings-menu');
|
||||
}
|
||||
|
||||
protected startLanguageServer = debounce((fqbn: string, name: string | undefined) => this.doStartLanguageServer(fqbn, name));
|
||||
protected async doStartLanguageServer(fqbn: string, name: string | undefined): Promise<void> {
|
||||
this.logger.info(`Starting language server: ${fqbn}`);
|
||||
const log = this.arduinoPreferences.get('arduino.language.log');
|
||||
let currentSketchPath: string | undefined = undefined;
|
||||
if (log) {
|
||||
const currentSketch = await this.sketchServiceClient.currentSketch();
|
||||
if (currentSketch) {
|
||||
currentSketchPath = await this.fileSystem.fsPath(new URI(currentSketch.uri));
|
||||
protected languageServerFqbn?: string;
|
||||
protected languageServerStartMutex = new Mutex();
|
||||
protected async startLanguageServer(fqbn: string, name: string | undefined): Promise<void> {
|
||||
const release = await this.languageServerStartMutex.acquire();
|
||||
try {
|
||||
await this.hostedPluginSupport.didStart;
|
||||
const details = await this.boardsService.getBoardDetails({ fqbn });
|
||||
if (!details) {
|
||||
// Core is not installed for the selected board.
|
||||
console.info(`Could not start language server for ${fqbn}. The core is not installed for the board.`);
|
||||
if (this.languageServerFqbn) {
|
||||
try {
|
||||
await this.commandRegistry.executeCommand('arduino.languageserver.stop');
|
||||
console.info(`Stopped language server process for ${this.languageServerFqbn}.`);
|
||||
this.languageServerFqbn = undefined;
|
||||
} catch (e) {
|
||||
console.error(`Failed to start language server process for ${this.languageServerFqbn}`, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fqbn === this.languageServerFqbn) {
|
||||
// NOOP
|
||||
return;
|
||||
}
|
||||
this.logger.info(`Starting language server: ${fqbn}`);
|
||||
const log = this.arduinoPreferences.get('arduino.language.log');
|
||||
let currentSketchPath: string | undefined = undefined;
|
||||
if (log) {
|
||||
const currentSketch = await this.sketchServiceClient.currentSketch();
|
||||
if (currentSketch) {
|
||||
currentSketchPath = await this.fileSystem.fsPath(new URI(currentSketch.uri));
|
||||
}
|
||||
}
|
||||
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
|
||||
const [clangdPath, cliPath, lsPath] = await Promise.all([
|
||||
this.fileSystem.fsPath(new URI(clangdUri)),
|
||||
this.fileSystem.fsPath(new URI(cliUri)),
|
||||
this.fileSystem.fsPath(new URI(lsUri)),
|
||||
]);
|
||||
this.languageServerFqbn = await Promise.race([
|
||||
new Promise<undefined>((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${20_000} ms.`)), 20_000)),
|
||||
this.commandRegistry.executeCommand<string>('arduino.languageserver.start', {
|
||||
lsPath,
|
||||
cliPath,
|
||||
clangdPath,
|
||||
log: currentSketchPath ? currentSketchPath : log,
|
||||
board: {
|
||||
fqbn,
|
||||
name: name ? `"${name}"` : undefined
|
||||
}
|
||||
})
|
||||
]);
|
||||
} catch (e) {
|
||||
console.log(`Failed to start language server for ${fqbn}`, e);
|
||||
this.languageServerFqbn = undefined;
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
|
||||
const [clangdPath, cliPath, lsPath] = await Promise.all([
|
||||
this.fileSystem.fsPath(new URI(clangdUri)),
|
||||
this.fileSystem.fsPath(new URI(cliUri)),
|
||||
this.fileSystem.fsPath(new URI(lsUri)),
|
||||
]);
|
||||
this.commandRegistry.executeCommand('arduino.languageserver.start', {
|
||||
lsPath,
|
||||
cliPath,
|
||||
clangdPath,
|
||||
log: currentSketchPath ? currentSketchPath : log,
|
||||
board: {
|
||||
fqbn,
|
||||
name: name ? `"${name}"` : undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
@@ -381,11 +414,20 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
id: 'arduino.toolbar.hoverBackground',
|
||||
defaults: {
|
||||
dark: 'button.hoverBackground',
|
||||
light: 'button.hoverBackground',
|
||||
hc: 'activityBar.inactiveForeground'
|
||||
light: 'button.foreground',
|
||||
hc: 'textLink.foreground'
|
||||
},
|
||||
description: 'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.'
|
||||
},
|
||||
{
|
||||
id: 'arduino.toolbar.toggleBackground',
|
||||
defaults: {
|
||||
dark: 'editor.selectionBackground',
|
||||
light: 'editor.selectionBackground',
|
||||
hc: 'textPreformat.foreground'
|
||||
},
|
||||
description: 'Toggle color of the toolbar items when they are currently toggled (the command is in progress)'
|
||||
},
|
||||
{
|
||||
id: 'arduino.output.foreground',
|
||||
defaults: {
|
||||
|
@@ -35,7 +35,9 @@ import {
|
||||
CommonFrontendContribution as TheiaCommonFrontendContribution,
|
||||
KeybindingRegistry as TheiaKeybindingRegistry,
|
||||
TabBarRendererFactory,
|
||||
ContextMenuRenderer
|
||||
ContextMenuRenderer,
|
||||
createTreeContainer,
|
||||
TreeWidget
|
||||
} from '@theia/core/lib/browser';
|
||||
import { MenuContribution } from '@theia/core/lib/common/menu';
|
||||
import { ApplicationShell } from './theia/core/application-shell';
|
||||
@@ -142,6 +144,15 @@ import { AddFile } from './contributions/add-file';
|
||||
import { ArchiveSketch } from './contributions/archive-sketch';
|
||||
import { OutputToolbarContribution as TheiaOutputToolbarContribution } from '@theia/output/lib/browser/output-toolbar-contribution';
|
||||
import { OutputToolbarContribution } from './theia/output/output-toolbar-contribution';
|
||||
import { AddZipLibrary } from './contributions/add-zip-library';
|
||||
import { WorkspaceVariableContribution as TheiaWorkspaceVariableContribution } from '@theia/workspace/lib/browser/workspace-variable-contribution';
|
||||
import { WorkspaceVariableContribution } from './theia/workspace/workspace-variable-contribution';
|
||||
import { DebugConfigurationManager } from './theia/debug/debug-configuration-manager';
|
||||
import { DebugConfigurationManager as TheiaDebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager';
|
||||
import { SearchInWorkspaceWidget as TheiaSearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget';
|
||||
import { SearchInWorkspaceWidget } from './theia/search-in-workspace/search-in-workspace-widget';
|
||||
import { SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-result-tree-widget';
|
||||
import { SearchInWorkspaceResultTreeWidget } from './theia/search-in-workspace/search-in-workspace-result-tree-widget';
|
||||
|
||||
const ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||
|
||||
@@ -256,6 +267,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
|
||||
bind(WorkspaceService).toSelf().inSingletonScope();
|
||||
rebind(TheiaWorkspaceService).toService(WorkspaceService);
|
||||
bind(WorkspaceVariableContribution).toSelf().inSingletonScope();
|
||||
rebind(TheiaWorkspaceVariableContribution).toService(WorkspaceVariableContribution);
|
||||
|
||||
// Customizing default Theia layout based on the editor mode: `pro-mode` or `classic`.
|
||||
bind(EditorMode).toSelf().inSingletonScope();
|
||||
@@ -293,6 +306,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(MonacoTextModelService).toSelf().inSingletonScope();
|
||||
rebind(TheiaMonacoTextModelService).toService(MonacoTextModelService);
|
||||
|
||||
bind(SearchInWorkspaceWidget).toSelf();
|
||||
rebind(TheiaSearchInWorkspaceWidget).toService(SearchInWorkspaceWidget);
|
||||
rebind(TheiaSearchInWorkspaceResultTreeWidget).toDynamicValue(({ container }) => {
|
||||
const childContainer = createTreeContainer(container);
|
||||
childContainer.bind(SearchInWorkspaceResultTreeWidget).toSelf()
|
||||
childContainer.rebind(TreeWidget).toService(SearchInWorkspaceResultTreeWidget);
|
||||
return childContainer.get(SearchInWorkspaceResultTreeWidget);
|
||||
});
|
||||
|
||||
// Show a disconnected status bar, when the daemon is not available
|
||||
bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope();
|
||||
rebind(TheiaApplicationConnectionStatusContribution).toService(ApplicationConnectionStatusContribution);
|
||||
@@ -354,6 +376,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
Contribution.configure(bind, Help);
|
||||
Contribution.configure(bind, AddFile);
|
||||
Contribution.configure(bind, ArchiveSketch);
|
||||
Contribution.configure(bind, AddZipLibrary);
|
||||
|
||||
bind(OutputServiceImpl).toSelf().inSingletonScope().onActivation(({ container }, outputService) => {
|
||||
WebSocketConnectionProvider.createProxy(container, OutputServicePath, outputService);
|
||||
@@ -388,6 +411,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
// To remove the `Run` menu item from the application menu.
|
||||
bind(DebugFrontendApplicationContribution).toSelf().inSingletonScope();
|
||||
rebind(TheiaDebugFrontendApplicationContribution).toService(DebugFrontendApplicationContribution);
|
||||
// To be able to use a `launch.json` from outside of the workspace.
|
||||
bind(DebugConfigurationManager).toSelf().inSingletonScope();
|
||||
rebind(TheiaDebugConfigurationManager).toService(DebugConfigurationManager);
|
||||
|
||||
// Preferences
|
||||
bindArduinoPreferences(bind);
|
||||
|
@@ -1,11 +1,6 @@
|
||||
import { interfaces } from 'inversify';
|
||||
import {
|
||||
createPreferenceProxy,
|
||||
PreferenceProxy,
|
||||
PreferenceService,
|
||||
PreferenceContribution,
|
||||
PreferenceSchema
|
||||
} from '@theia/core/lib/browser/preferences';
|
||||
import { createPreferenceProxy, PreferenceProxy, PreferenceService, PreferenceContribution, PreferenceSchema } from '@theia/core/lib/browser/preferences';
|
||||
import { CompilerWarningLiterals, CompilerWarnings } from '../common/protocol';
|
||||
|
||||
export const ArduinoConfigSchema: PreferenceSchema = {
|
||||
'type': 'object',
|
||||
@@ -20,6 +15,11 @@ export const ArduinoConfigSchema: PreferenceSchema = {
|
||||
'description': 'True for verbose compile output. False by default',
|
||||
'default': false
|
||||
},
|
||||
'arduino.compile.warnings': {
|
||||
'enum': [...CompilerWarningLiterals],
|
||||
'description': "Tells gcc which warning level to use. It's 'None' by default",
|
||||
'default': 'None'
|
||||
},
|
||||
'arduino.upload.verbose': {
|
||||
'type': 'boolean',
|
||||
'description': 'True for verbose upload output. False by default.',
|
||||
@@ -50,6 +50,7 @@ export const ArduinoConfigSchema: PreferenceSchema = {
|
||||
export interface ArduinoConfiguration {
|
||||
'arduino.language.log': boolean;
|
||||
'arduino.compile.verbose': boolean;
|
||||
'arduino.compile.warnings': CompilerWarnings;
|
||||
'arduino.upload.verbose': boolean;
|
||||
'arduino.upload.verify': boolean;
|
||||
'arduino.window.autoScale': boolean;
|
||||
|
@@ -15,16 +15,10 @@ import {
|
||||
} from '../../common/protocol';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { naturalCompare } from '../../common/utils';
|
||||
import { compareAnything } from '../theia/monaco/comparers';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { CommandService } from '@theia/core';
|
||||
import { ArduinoCommands } from '../arduino-commands';
|
||||
|
||||
interface BoardMatch {
|
||||
readonly board: BoardWithPackage;
|
||||
readonly matches: monaco.filters.IMatch[] | undefined;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
|
||||
@@ -93,7 +87,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
if (!AttachedBoardsChangeEvent.isEmpty(event)) {
|
||||
this.logger.info('Attached boards and available ports changed:');
|
||||
this.logger.info(AttachedBoardsChangeEvent.toString(event));
|
||||
this.logger.info(`------------------------------------------`);
|
||||
this.logger.info('------------------------------------------');
|
||||
}
|
||||
this._attachedBoards = event.newState.boards;
|
||||
this._availablePorts = event.newState.ports;
|
||||
@@ -139,6 +133,17 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
if (selectedBoard && selectedBoard.fqbn) {
|
||||
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
|
||||
// We should not unset the FQBN, if the selected board is an attached, recognized board.
|
||||
// Attach Uno and install AVR, select Uno. Uninstall the AVR core while Uno is selected. We do not want to discard the FQBN of the Uno board.
|
||||
// Dev note: We cannot assume the `selectedBoard` is a type of `AvailableBoard`.
|
||||
// When the user selects an `AvailableBoard` it works, but between app start/stops,
|
||||
// it is just a FQBN, so we need to find the `selected` board among the `AvailableBoards`
|
||||
const selectedAvailableBoard = AvailableBoard.is(selectedBoard)
|
||||
? selectedBoard
|
||||
: this._availableBoards.find(availableBoard => Board.sameAs(availableBoard, selectedBoard));
|
||||
if (selectedAvailableBoard && selectedAvailableBoard.selected && selectedAvailableBoard.state === AvailableBoard.State.recognized) {
|
||||
return;
|
||||
}
|
||||
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
|
||||
const selectedBoardWithoutFqbn = {
|
||||
name: selectedBoard.name
|
||||
@@ -194,38 +199,9 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
}
|
||||
}
|
||||
|
||||
async searchBoards({ query, cores }: { query?: string, cores?: string[] }): Promise<Array<BoardWithPackage>> {
|
||||
const boards = await this.boardsService.allBoards({});
|
||||
const coresFilter = !!cores && cores.length
|
||||
? ((toFilter: BoardWithPackage) => cores.some(core => core === toFilter.packageName || core === toFilter.packageId))
|
||||
: () => true;
|
||||
if (!query) {
|
||||
return boards.filter(coresFilter).sort(Board.compare);
|
||||
}
|
||||
const toMatch = ((toFilter: BoardWithPackage) => (({ board: toFilter, matches: monaco.filters.matchesFuzzy(query, toFilter.name, true) })));
|
||||
const compareEntries = (left: BoardMatch, right: BoardMatch, lookFor: string) => {
|
||||
const leftMatches = left.matches || [];
|
||||
const rightMatches = right.matches || [];
|
||||
if (leftMatches.length && !rightMatches.length) {
|
||||
return -1;
|
||||
}
|
||||
if (!leftMatches.length && rightMatches.length) {
|
||||
return 1;
|
||||
}
|
||||
if (leftMatches.length === 0 && rightMatches.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const leftLabel = left.board.name.replace(/\r?\n/g, ' ');
|
||||
const rightLabel = right.board.name.replace(/\r?\n/g, ' ');
|
||||
return compareAnything(leftLabel, rightLabel, lookFor);
|
||||
}
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
return boards
|
||||
.filter(coresFilter)
|
||||
.map(toMatch)
|
||||
.filter(({ matches }) => !!matches)
|
||||
.sort((left, right) => compareEntries(left, right, normalizedQuery))
|
||||
.map(({ board }) => board);
|
||||
async searchBoards({ query, cores }: { query?: string, cores?: string[] }): Promise<BoardWithPackage[]> {
|
||||
const boards = await this.boardsService.searchBoards({ query });
|
||||
return boards;
|
||||
}
|
||||
|
||||
get boardsConfig(): BoardsConfig.Config {
|
||||
|
@@ -12,7 +12,7 @@ export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendCont
|
||||
widgetName: BoardsListWidget.WIDGET_LABEL,
|
||||
defaultWidgetOptions: {
|
||||
area: 'left',
|
||||
rank: 600
|
||||
rank: 2
|
||||
},
|
||||
toggleCommandId: `${BoardsListWidget.WIDGET_ID}:toggle`,
|
||||
toggleKeybinding: 'CtrlCmd+Shift+B'
|
||||
|
@@ -1,16 +0,0 @@
|
||||
import { ContainerModule } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { CommandContribution } from '@theia/core/lib/common/command';
|
||||
import { QuickOpenContribution } from '@theia/core/lib/browser/quick-open';
|
||||
import { KeybindingContribution } from '@theia/core/lib/browser/keybinding';
|
||||
import { BoardsQuickOpenService } from './boards-quick-open-service';
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bind(BoardsQuickOpenService).toSelf().inSingletonScope();
|
||||
bind(CommandContribution).toService(BoardsQuickOpenService);
|
||||
bind(KeybindingContribution).toService(BoardsQuickOpenService);
|
||||
bind(QuickOpenContribution).toService(BoardsQuickOpenService);
|
||||
bind(ILogger).toDynamicValue(({ container }) => container.get<ILogger>(ILogger).child('boards-quick-open'))
|
||||
.inSingletonScope()
|
||||
.whenTargetNamed('boards-quick-open');
|
||||
});
|
@@ -1,309 +0,0 @@
|
||||
import * as fuzzy from 'fuzzy';
|
||||
import { inject, injectable, postConstruct, named } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { CommandContribution, CommandRegistry, Command } from '@theia/core/lib/common/command';
|
||||
import { KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
|
||||
import { QuickOpenItem, QuickOpenModel, QuickOpenMode, QuickOpenGroupItem } from '@theia/core/lib/common/quick-open-model';
|
||||
import {
|
||||
QuickOpenService,
|
||||
QuickOpenHandler,
|
||||
QuickOpenOptions,
|
||||
QuickOpenItemOptions,
|
||||
QuickOpenContribution,
|
||||
QuickOpenActionProvider,
|
||||
QuickOpenHandlerRegistry,
|
||||
QuickOpenGroupItemOptions
|
||||
} from '@theia/core/lib/browser/quick-open';
|
||||
import { naturalCompare } from '../../../common/utils';
|
||||
import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol';
|
||||
import { BoardsDataStore } from '../boards-data-store';
|
||||
import { BoardsServiceProvider, AvailableBoard } from '../boards-service-provider';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenModel, QuickOpenHandler, CommandContribution, KeybindingContribution, Command {
|
||||
|
||||
readonly id = 'arduino-boards-quick-open';
|
||||
readonly prefix = '|';
|
||||
readonly description = 'Configure Available Boards';
|
||||
readonly label: 'Configure Available Boards';
|
||||
|
||||
@inject(ILogger)
|
||||
@named('boards-quick-open')
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(QuickOpenService)
|
||||
protected readonly quickOpenService: QuickOpenService;
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected notificationCenter: NotificationCenter;
|
||||
|
||||
protected isOpen: boolean = false;
|
||||
protected currentQuery: string = '';
|
||||
// Attached boards plus the user's config.
|
||||
protected availableBoards: AvailableBoard[] = [];
|
||||
// Only for the `selected` one from the `availableBoards`. Note: the `port` of the `selected` is optional.
|
||||
protected data: BoardsDataStore.Data = BoardsDataStore.Data.EMPTY;
|
||||
protected allBoards: Board.Detailed[] = []
|
||||
protected selectedBoard?: (AvailableBoard & { port: Port });
|
||||
|
||||
// `init` name is used by the `QuickOpenHandler`.
|
||||
@postConstruct()
|
||||
protected postConstruct(): void {
|
||||
this.notificationCenter.onIndexUpdated(() => this.update(this.availableBoards));
|
||||
this.boardsServiceClient.onAvailableBoardsChanged(availableBoards => this.update(availableBoards));
|
||||
this.update(this.boardsServiceClient.availableBoards);
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(this, { execute: () => this.open() });
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({ command: this.id, keybinding: 'ctrlCmd+k ctrlCmd+b' });
|
||||
}
|
||||
|
||||
registerQuickOpenHandlers(registry: QuickOpenHandlerRegistry): void {
|
||||
registry.registerHandler(this);
|
||||
}
|
||||
|
||||
getModel(): QuickOpenModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
getOptions(): QuickOpenOptions {
|
||||
let placeholder = '';
|
||||
if (!this.selectedBoard) {
|
||||
placeholder += 'No board selected.';
|
||||
}
|
||||
placeholder += 'Type to filter boards';
|
||||
if (this.data.configOptions.length) {
|
||||
placeholder += ' or use the ↓↑ keys to adjust the board settings...';
|
||||
} else {
|
||||
placeholder += '...';
|
||||
}
|
||||
return {
|
||||
placeholder,
|
||||
fuzzyMatchLabel: true,
|
||||
onClose: () => this.isOpen = false
|
||||
};
|
||||
}
|
||||
|
||||
open(): void {
|
||||
this.isOpen = true;
|
||||
this.quickOpenService.open(this, this.getOptions());
|
||||
}
|
||||
|
||||
onType(
|
||||
lookFor: string,
|
||||
acceptor: (items: QuickOpenItem<QuickOpenItemOptions>[], actionProvider?: QuickOpenActionProvider) => void): void {
|
||||
|
||||
this.currentQuery = lookFor;
|
||||
const fuzzyFilter = this.fuzzyFilter(lookFor);
|
||||
const availableBoards = this.availableBoards.filter(AvailableBoard.hasPort).filter(({ name }) => fuzzyFilter(name));
|
||||
const toAccept: QuickOpenItem<QuickOpenItemOptions>[] = [];
|
||||
|
||||
// Show the selected attached in a different group.
|
||||
if (this.selectedBoard && fuzzyFilter(this.selectedBoard.name)) {
|
||||
toAccept.push(this.toQuickItem(this.selectedBoard, { groupLabel: 'Selected Board' }));
|
||||
}
|
||||
|
||||
// Filter the selected from the attached ones.
|
||||
toAccept.push(...availableBoards.filter(board => board !== this.selectedBoard).map((board, i) => {
|
||||
let group: QuickOpenGroupItemOptions | undefined = undefined;
|
||||
if (i === 0) {
|
||||
// If no `selectedBoard`, then this item is the top one, no borders required.
|
||||
group = { groupLabel: 'Attached Boards', showBorder: !!this.selectedBoard };
|
||||
}
|
||||
return this.toQuickItem(board, group);
|
||||
}));
|
||||
|
||||
// Show the config only if the `input` is empty.
|
||||
if (!lookFor.trim().length) {
|
||||
toAccept.push(...this.data.configOptions.map((config, i) => {
|
||||
let group: QuickOpenGroupItemOptions | undefined = undefined;
|
||||
if (i === 0) {
|
||||
group = { groupLabel: 'Board Settings', showBorder: true };
|
||||
}
|
||||
return this.toQuickItem(config, group);
|
||||
}));
|
||||
} else {
|
||||
toAccept.push(...this.allBoards.filter(({ name }) => fuzzyFilter(name)).map((board, i) => {
|
||||
let group: QuickOpenGroupItemOptions | undefined = undefined;
|
||||
if (i === 0) {
|
||||
group = { groupLabel: 'Boards', showBorder: true };
|
||||
}
|
||||
return this.toQuickItem(board, group);
|
||||
}));
|
||||
}
|
||||
|
||||
acceptor(toAccept);
|
||||
}
|
||||
|
||||
private fuzzyFilter(lookFor: string): (inputString: string) => boolean {
|
||||
const shouldFilter = !!lookFor.trim().length;
|
||||
return (inputString: string) => shouldFilter ? fuzzy.test(lookFor.toLocaleLowerCase(), inputString.toLocaleLowerCase()) : true;
|
||||
}
|
||||
|
||||
protected async update(availableBoards: AvailableBoard[]): Promise<void> {
|
||||
// `selectedBoard` is not an attached board, we need to show the board settings for it (TODO: clarify!)
|
||||
const selectedBoard = availableBoards.filter(AvailableBoard.hasPort).find(({ selected }) => selected);
|
||||
const [data, boards] = await Promise.all([
|
||||
selectedBoard && selectedBoard.fqbn ? this.boardsDataStore.getData(selectedBoard.fqbn) : Promise.resolve(BoardsDataStore.Data.EMPTY),
|
||||
this.boardsService.allBoards({})
|
||||
]);
|
||||
this.allBoards = Board.decorateBoards(selectedBoard, boards)
|
||||
.filter(board => !availableBoards.some(availableBoard => Board.sameAs(availableBoard, board)));
|
||||
this.availableBoards = availableBoards;
|
||||
this.data = data;
|
||||
this.selectedBoard = selectedBoard;
|
||||
|
||||
if (this.isOpen) {
|
||||
// Hack, to update the state without closing and reopening the quick open widget.
|
||||
(this.quickOpenService as any).onType(this.currentQuery);
|
||||
}
|
||||
}
|
||||
|
||||
protected toQuickItem(item: BoardsQuickOpenService.Item, group?: QuickOpenGroupItemOptions): QuickOpenItem<QuickOpenItemOptions> {
|
||||
let options: QuickOpenItemOptions;
|
||||
if (AvailableBoard.is(item)) {
|
||||
const description = `on ${Port.toString(item.port)}`
|
||||
options = {
|
||||
label: `${item.name}`,
|
||||
description,
|
||||
descriptionHighlights: [
|
||||
{
|
||||
start: 0,
|
||||
end: description.length
|
||||
}
|
||||
],
|
||||
run: this.toRun(() => this.boardsServiceClient.boardsConfig = ({ selectedBoard: item, selectedPort: item.port }))
|
||||
};
|
||||
} else if (ConfigOption.is(item)) {
|
||||
const selected = item.values.find(({ selected }) => selected);
|
||||
const value = selected ? selected.label : 'Not set';
|
||||
const label = `${item.label}: ${value}`;
|
||||
options = {
|
||||
label,
|
||||
// Intended to match the value part of a board setting.
|
||||
// NOTE: this does not work, as `fuzzyMatchLabel: true` is set. Manual highlighting is ignored, apparently.
|
||||
labelHighlights: [
|
||||
{
|
||||
start: label.length - value.length,
|
||||
end: label.length
|
||||
}
|
||||
],
|
||||
run: (mode) => {
|
||||
if (mode === QuickOpenMode.OPEN) {
|
||||
this.setConfig(item);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (!selected) {
|
||||
options.description = 'Not set';
|
||||
};
|
||||
} else {
|
||||
options = {
|
||||
label: `${item.name}`,
|
||||
description: `${item.missing ? '' : `[installed with '${item.packageName}']`}`,
|
||||
run: (mode) => {
|
||||
if (mode === QuickOpenMode.OPEN) {
|
||||
this.selectBoard(item);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (group) {
|
||||
return new QuickOpenGroupItem<QuickOpenGroupItemOptions>({ ...options, ...group });
|
||||
} else {
|
||||
return new QuickOpenItem<QuickOpenItemOptions>(options);
|
||||
}
|
||||
}
|
||||
|
||||
protected toRun(run: (() => void)): ((mode: QuickOpenMode) => boolean) {
|
||||
return (mode) => {
|
||||
if (mode !== QuickOpenMode.OPEN) {
|
||||
return false;
|
||||
}
|
||||
run();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
protected async selectBoard(board: Board): Promise<void> {
|
||||
const allPorts = this.availableBoards.filter(AvailableBoard.hasPort).map(({ port }) => port).sort(Port.compare);
|
||||
const toItem = (port: Port) => new QuickOpenItem<QuickOpenItemOptions>({
|
||||
label: Port.toString(port, { useLabel: true }),
|
||||
run: this.toRun(() => {
|
||||
this.boardsServiceClient.boardsConfig = {
|
||||
selectedBoard: board,
|
||||
selectedPort: port
|
||||
};
|
||||
})
|
||||
});
|
||||
const options = {
|
||||
placeholder: `Select a port for '${board.name}'. Press 'Enter' to confirm or 'Escape' to cancel.`,
|
||||
fuzzyMatchLabel: true
|
||||
}
|
||||
this.quickOpenService.open({
|
||||
onType: (lookFor, acceptor) => {
|
||||
const fuzzyFilter = this.fuzzyFilter(lookFor);
|
||||
acceptor(allPorts.filter(({ address }) => fuzzyFilter(address)).map(toItem));
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
||||
protected async setConfig(config: ConfigOption): Promise<void> {
|
||||
const toItem = (value: ConfigValue) => new QuickOpenItem<QuickOpenItemOptions>({
|
||||
label: value.label,
|
||||
iconClass: value.selected ? 'fa fa-check' : '',
|
||||
run: this.toRun(() => {
|
||||
if (!this.selectedBoard) {
|
||||
this.logger.warn(`Could not alter the boards settings. No board selected. ${JSON.stringify(config)}`);
|
||||
return;
|
||||
}
|
||||
if (!this.selectedBoard.fqbn) {
|
||||
this.logger.warn(`Could not alter the boards settings. The selected board does not have a FQBN. ${JSON.stringify(this.selectedBoard)}`);
|
||||
return;
|
||||
}
|
||||
const { fqbn } = this.selectedBoard;
|
||||
this.boardsDataStore.selectConfigOption({
|
||||
fqbn,
|
||||
option: config.option,
|
||||
selectedValue: value.value
|
||||
});
|
||||
})
|
||||
});
|
||||
const options = {
|
||||
placeholder: `Configure '${config.label}'. Press 'Enter' to confirm or 'Escape' to cancel.`,
|
||||
fuzzyMatchLabel: true
|
||||
}
|
||||
this.quickOpenService.open({
|
||||
onType: (lookFor, acceptor) => {
|
||||
const fuzzyFilter = this.fuzzyFilter(lookFor);
|
||||
acceptor(config.values
|
||||
.filter(({ label }) => fuzzyFilter(label))
|
||||
.sort((left, right) => naturalCompare(left.label, right.label))
|
||||
.map(toItem));
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace BoardsQuickOpenService {
|
||||
export type Item = AvailableBoard & { port: Port } | Board.Detailed | ConfigOption;
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { remote } from 'electron';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { InstallationProgressDialog } from '../widgets/progress-dialog';
|
||||
import { LibraryService } from '../../common/protocol';
|
||||
import { ConfirmDialog } from '@theia/core/lib/browser';
|
||||
|
||||
@injectable()
|
||||
export class AddZipLibrary extends SketchContribution {
|
||||
|
||||
@inject(EnvVariablesServer)
|
||||
protected readonly envVariableServer: EnvVariablesServer;
|
||||
|
||||
@inject(LibraryService)
|
||||
protected readonly libraryService: LibraryService;
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(AddZipLibrary.Commands.ADD_ZIP_LIBRARY, {
|
||||
execute: () => this.addZipLibrary()
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
|
||||
// TODO: do we need it? calling `registerSubmenu` multiple times is noop, so it does not hurt.
|
||||
registry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
|
||||
registry.registerMenuAction([...includeLibMenuPath, '1_install'], {
|
||||
commandId: AddZipLibrary.Commands.ADD_ZIP_LIBRARY.id,
|
||||
label: 'Add .ZIP Library...',
|
||||
order: '1'
|
||||
});
|
||||
}
|
||||
|
||||
async addZipLibrary(): Promise<void> {
|
||||
const homeUri = await this.envVariableServer.getHomeDirUri();
|
||||
const defaultPath = await this.fileService.fsPath(new URI(homeUri));
|
||||
const { canceled, filePaths } = await remote.dialog.showOpenDialog({
|
||||
title: "Select a zip file containing the library you'd like to add",
|
||||
defaultPath,
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{
|
||||
name: 'Library',
|
||||
extensions: ['zip']
|
||||
}
|
||||
]
|
||||
});
|
||||
if (!canceled && filePaths.length) {
|
||||
const zipUri = await this.fileSystemExt.getUri(filePaths[0]);
|
||||
try {
|
||||
await this.doInstall(zipUri);
|
||||
} catch (error) {
|
||||
if (error instanceof AlreadyInstalledError) {
|
||||
const result = await new ConfirmDialog({
|
||||
msg: error.message,
|
||||
title: 'Do you want to overwrite the existing library?',
|
||||
ok: 'Yes',
|
||||
cancel: 'No'
|
||||
}).open();
|
||||
if (result) {
|
||||
await this.doInstall(zipUri, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async doInstall(zipUri: string, overwrite?: boolean): Promise<void> {
|
||||
const dialog = new InstallationProgressDialog('Installing library', 'zip');
|
||||
try {
|
||||
this.outputChannelManager.getChannel('Arduino').clear();
|
||||
dialog.open();
|
||||
await this.libraryService.installZip({ zipUri, overwrite });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
const match = error.message.match(/library (.*?) already installed/);
|
||||
if (match && match.length >= 2) {
|
||||
const name = match[1].trim();
|
||||
if (name) {
|
||||
throw new AlreadyInstalledError(`A library folder named ${name} already exists. Do you want to overwrite it?`, name);
|
||||
} else {
|
||||
throw new AlreadyInstalledError('A library already exists. Do you want to overwrite it?');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.messageService.error(error.toString());
|
||||
throw error;
|
||||
} finally {
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AlreadyInstalledError extends Error {
|
||||
|
||||
constructor(message: string, readonly libraryName?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, AlreadyInstalledError.prototype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace AddZipLibrary {
|
||||
export namespace Commands {
|
||||
export const ADD_ZIP_LIBRARY: Command = {
|
||||
id: 'arduino-add-zip-library'
|
||||
};
|
||||
}
|
||||
}
|
@@ -210,7 +210,7 @@ PID: ${PID}`;
|
||||
}
|
||||
|
||||
protected async installedBoards(): Promise<InstalledBoardWithPackage[]> {
|
||||
const allBoards = await this.boardsService.allBoards({});
|
||||
const allBoards = await this.boardsService.searchBoards({});
|
||||
return allBoards.filter(InstalledBoardWithPackage.is);
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
|
||||
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
|
||||
import { MenuModelRegistry, MenuContribution } from '@theia/core/lib/common/menu';
|
||||
import { KeybindingRegistry, KeybindingContribution } from '@theia/core/lib/browser/keybinding';
|
||||
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
@@ -90,6 +91,9 @@ export abstract class SketchContribution extends Contribution {
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
||||
protected async sourceOverride(): Promise<Record<string, string>> {
|
||||
const override: Record<string, string> = {};
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
|
@@ -106,9 +106,11 @@ export class Debug extends SketchContribution {
|
||||
if (!sketch) {
|
||||
return;
|
||||
}
|
||||
const [cliPath, sketchPath] = await Promise.all([
|
||||
const ideTempFolderUri = await this.sketchService.getIdeTempFolderUri(sketch);
|
||||
const [cliPath, sketchPath, configPath] = await Promise.all([
|
||||
this.fileService.fsPath(new URI(executables.cliUri)),
|
||||
this.fileService.fsPath(new URI(sketch.uri))
|
||||
this.fileService.fsPath(new URI(sketch.uri)),
|
||||
this.fileService.fsPath(new URI(ideTempFolderUri)),
|
||||
])
|
||||
const config = {
|
||||
cliPath,
|
||||
@@ -116,7 +118,8 @@ export class Debug extends SketchContribution {
|
||||
fqbn,
|
||||
name
|
||||
},
|
||||
sketchPath
|
||||
sketchPath,
|
||||
configPath
|
||||
};
|
||||
return this.commandService.executeCommand('arduino.debug.start', config);
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import * as PQueue from 'p-queue';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { MenuPath, CompositeMenuNode } from '@theia/core/lib/common/menu';
|
||||
import { MenuPath, CompositeMenuNode, SubMenuOptions } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { OpenSketch } from './open-sketch';
|
||||
import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { ExamplesService, ExampleContainer } from '../../common/protocol/examples-service';
|
||||
import { ExamplesService } from '../../common/protocol/examples-service';
|
||||
import { SketchContribution, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { Board } from '../../common/protocol';
|
||||
import { Board, Sketch, SketchContainer } from '../../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export abstract class Examples extends SketchContribution {
|
||||
@@ -59,18 +59,35 @@ export abstract class Examples extends SketchContribution {
|
||||
}
|
||||
|
||||
registerRecursively(
|
||||
exampleContainerOrPlaceholder: ExampleContainer | string,
|
||||
sketchContainerOrPlaceholder: SketchContainer | (Sketch | SketchContainer)[] | string,
|
||||
menuPath: MenuPath,
|
||||
pushToDispose: DisposableCollection = new DisposableCollection()): void {
|
||||
pushToDispose: DisposableCollection = new DisposableCollection(),
|
||||
subMenuOptions?: SubMenuOptions | undefined): void {
|
||||
|
||||
if (typeof exampleContainerOrPlaceholder === 'string') {
|
||||
const placeholder = new PlaceholderMenuNode(menuPath, exampleContainerOrPlaceholder);
|
||||
if (typeof sketchContainerOrPlaceholder === 'string') {
|
||||
const placeholder = new PlaceholderMenuNode(menuPath, sketchContainerOrPlaceholder);
|
||||
this.menuRegistry.registerMenuNode(menuPath, placeholder);
|
||||
pushToDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuNode(placeholder.id)));
|
||||
} else {
|
||||
const { label, sketches, children } = exampleContainerOrPlaceholder;
|
||||
const submenuPath = [...menuPath, label];
|
||||
this.menuRegistry.registerSubmenu(submenuPath, label);
|
||||
const sketches: Sketch[] = [];
|
||||
const children: SketchContainer[] = [];
|
||||
let submenuPath = menuPath;
|
||||
|
||||
if (SketchContainer.is(sketchContainerOrPlaceholder)) {
|
||||
const { label } = sketchContainerOrPlaceholder;
|
||||
submenuPath = [...menuPath, label];
|
||||
this.menuRegistry.registerSubmenu(submenuPath, label, subMenuOptions);
|
||||
sketches.push(...sketchContainerOrPlaceholder.sketches);
|
||||
children.push(...sketchContainerOrPlaceholder.children);
|
||||
} else {
|
||||
for (const sketchOrContainer of sketchContainerOrPlaceholder) {
|
||||
if (SketchContainer.is(sketchOrContainer)) {
|
||||
children.push(sketchOrContainer);
|
||||
} else {
|
||||
sketches.push(sketchOrContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
children.forEach(child => this.registerRecursively(child, submenuPath, pushToDispose));
|
||||
for (const sketch of sketches) {
|
||||
const { uri } = sketch;
|
||||
@@ -83,7 +100,7 @@ export abstract class Examples extends SketchContribution {
|
||||
}
|
||||
};
|
||||
pushToDispose.push(this.commandRegistry.registerCommand(command, handler));
|
||||
this.menuRegistry.registerMenuAction(submenuPath, { commandId, label: sketch.name });
|
||||
this.menuRegistry.registerMenuAction(submenuPath, { commandId, label: sketch.name, order: sketch.name.toLocaleLowerCase() });
|
||||
pushToDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
|
||||
}
|
||||
}
|
||||
@@ -98,22 +115,20 @@ export class BuiltInExamples extends Examples {
|
||||
this.register(); // no `await`
|
||||
}
|
||||
|
||||
protected async register() {
|
||||
let exampleContainers: ExampleContainer[] | undefined;
|
||||
protected async register(): Promise<void> {
|
||||
let sketchContainers: SketchContainer[] | undefined;
|
||||
try {
|
||||
exampleContainers = await this.examplesService.builtIns();
|
||||
sketchContainers = await this.examplesService.builtIns();
|
||||
} catch (e) {
|
||||
console.error('Could not initialize built-in examples.', e);
|
||||
this.messageService.error('Could not initialize built-in examples.');
|
||||
return;
|
||||
}
|
||||
this.toDispose.dispose();
|
||||
for (const container of ['Built-in examples', ...exampleContainers]) {
|
||||
for (const container of ['Built-in examples', ...sketchContainers]) {
|
||||
this.registerRecursively(container, ArduinoMenus.EXAMPLES__BUILT_IN_GROUP, this.toDispose);
|
||||
}
|
||||
this.menuManager.update();
|
||||
// TODO: remove
|
||||
console.log(typeof this.menuRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -136,7 +151,7 @@ export class LibraryExamples extends Examples {
|
||||
this.register(board);
|
||||
}
|
||||
|
||||
protected async register(board: Board | undefined = this.boardsServiceClient.boardsConfig.selectedBoard) {
|
||||
protected async register(board: Board | undefined = this.boardsServiceClient.boardsConfig.selectedBoard): Promise<void> {
|
||||
return this.queue.add(async () => {
|
||||
this.toDispose.dispose();
|
||||
if (!board || !board.fqbn) {
|
||||
|
@@ -47,6 +47,17 @@ export class IncludeLibrary extends SketchContribution {
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.updateMenuActions());
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
// `Include Library` submenu
|
||||
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
|
||||
registry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
|
||||
// `Manage Libraries...` group.
|
||||
registry.registerMenuAction([...includeLibMenuPath, '0_manage'], {
|
||||
commandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
label: 'Manage Libraries...'
|
||||
});
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY, {
|
||||
execute: async arg => {
|
||||
@@ -68,16 +79,7 @@ export class IncludeLibrary extends SketchContribution {
|
||||
libraries.push(...await this.libraryService.list({ fqbn }));
|
||||
}
|
||||
|
||||
// `Include Library` submenu
|
||||
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
|
||||
this.menuRegistry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
|
||||
// `Manage Libraries...` group.
|
||||
this.menuRegistry.registerMenuAction([...includeLibMenuPath, '0_manage'], {
|
||||
commandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
label: 'Manage Libraries...'
|
||||
});
|
||||
this.toDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction({ commandId: `${LibraryListWidget.WIDGET_ID}:toggle` })));
|
||||
|
||||
// `Add .ZIP Library...`
|
||||
// TODO: implement it
|
||||
|
||||
|
@@ -8,6 +8,8 @@ import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { SketchContribution, Sketch, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
import { ExamplesService } from '../../common/protocol/examples-service';
|
||||
import { BuiltInExamples } from './examples';
|
||||
import { Sketchbook } from './sketchbook';
|
||||
import { SketchContainer } from '../../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class OpenSketch extends SketchContribution {
|
||||
@@ -24,7 +26,10 @@ export class OpenSketch extends SketchContribution {
|
||||
@inject(ExamplesService)
|
||||
protected readonly examplesService: ExamplesService;
|
||||
|
||||
protected readonly toDisposeBeforeCreateNewContextMenu = new DisposableCollection();
|
||||
@inject(Sketchbook)
|
||||
protected readonly sketchbook: Sketchbook;
|
||||
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH, {
|
||||
@@ -33,11 +38,11 @@ export class OpenSketch extends SketchContribution {
|
||||
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH__TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
execute: async (_: Widget, target: EventTarget) => {
|
||||
const sketches = await this.sketchService.getSketches();
|
||||
if (!sketches.length) {
|
||||
const container = await this.sketchService.getSketches({ exclude: ['**/hardware/**'] });
|
||||
if (SketchContainer.isEmpty(container)) {
|
||||
this.openSketch();
|
||||
} else {
|
||||
this.toDisposeBeforeCreateNewContextMenu.dispose();
|
||||
this.toDispose.dispose();
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
@@ -50,21 +55,12 @@ export class OpenSketch extends SketchContribution {
|
||||
commandId: OpenSketch.Commands.OPEN_SKETCH.id,
|
||||
label: 'Open...'
|
||||
});
|
||||
this.toDisposeBeforeCreateNewContextMenu.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(OpenSketch.Commands.OPEN_SKETCH)));
|
||||
for (const sketch of sketches) {
|
||||
const command = { id: `arduino-open-sketch--${sketch.uri}` };
|
||||
const handler = { execute: () => this.openSketch(sketch) };
|
||||
this.toDisposeBeforeCreateNewContextMenu.push(registry.registerCommand(command, handler));
|
||||
this.menuRegistry.registerMenuAction(ArduinoMenus.OPEN_SKETCH__CONTEXT__RECENT_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
this.toDisposeBeforeCreateNewContextMenu.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
|
||||
}
|
||||
this.toDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(OpenSketch.Commands.OPEN_SKETCH)));
|
||||
this.sketchbook.registerRecursively([...container.children, ...container.sketches], ArduinoMenus.OPEN_SKETCH__CONTEXT__RECENT_GROUP, this.toDispose);
|
||||
try {
|
||||
const containers = await this.examplesService.builtIns();
|
||||
for (const container of containers) {
|
||||
this.builtInExamples.registerRecursively(container, ArduinoMenus.OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP, this.toDisposeBeforeCreateNewContextMenu);
|
||||
this.builtInExamples.registerRecursively(container, ArduinoMenus.OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP, this.toDispose);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error when collecting built-in examples.', e);
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { SketchContribution, CommandRegistry, MenuModelRegistry, Sketch } from './contribution';
|
||||
import { CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { OpenSketch } from './open-sketch';
|
||||
import { Examples } from './examples';
|
||||
import { SketchContainer } from '../../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class Sketchbook extends SketchContribution {
|
||||
export class Sketchbook extends Examples {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commandRegistry: CommandRegistry;
|
||||
@@ -21,17 +21,16 @@ export class Sketchbook extends SketchContribution {
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected toDisposePerSketch = new Map<string, DisposableCollection>();
|
||||
|
||||
onStart(): void {
|
||||
this.sketchService.getSketches().then(sketches => {
|
||||
this.register(sketches);
|
||||
this.sketchService.getSketches({}).then(container => {
|
||||
this.register(container);
|
||||
this.mainMenuManager.update();
|
||||
});
|
||||
this.sketchServiceClient.onSketchbookDidChange(({ created, removed }) => {
|
||||
this.unregister(removed);
|
||||
this.register(created);
|
||||
this.mainMenuManager.update();
|
||||
this.sketchServiceClient.onSketchbookDidChange(() => {
|
||||
this.sketchService.getSketches({}).then(container => {
|
||||
this.register(container);
|
||||
this.mainMenuManager.update();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,31 +38,9 @@ export class Sketchbook extends SketchContribution {
|
||||
registry.registerSubmenu(ArduinoMenus.FILE__SKETCHBOOK_SUBMENU, 'Sketchbook', { order: '3' });
|
||||
}
|
||||
|
||||
protected register(sketches: Sketch[]): void {
|
||||
for (const sketch of sketches) {
|
||||
const { uri } = sketch;
|
||||
const toDispose = this.toDisposePerSketch.get(uri);
|
||||
if (toDispose) {
|
||||
toDispose.dispose();
|
||||
}
|
||||
const command = { id: `arduino-sketchbook-open--${uri}` };
|
||||
const handler = { execute: () => this.commandRegistry.executeCommand(OpenSketch.Commands.OPEN_SKETCH.id, sketch) };
|
||||
this.commandRegistry.registerCommand(command, handler);
|
||||
this.menuRegistry.registerMenuAction(ArduinoMenus.FILE__SKETCHBOOK_SUBMENU, { commandId: command.id, label: sketch.name });
|
||||
this.toDisposePerSketch.set(sketch.uri, new DisposableCollection(
|
||||
Disposable.create(() => this.commandRegistry.unregisterCommand(command)),
|
||||
Disposable.create(() => this.menuRegistry.unregisterMenuAction(command))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected unregister(sketches: Sketch[]): void {
|
||||
for (const { uri } of sketches) {
|
||||
const toDispose = this.toDisposePerSketch.get(uri);
|
||||
if (toDispose) {
|
||||
toDispose.dispose();
|
||||
}
|
||||
}
|
||||
protected register(container: SketchContainer): void {
|
||||
this.toDispose.dispose();
|
||||
this.registerRecursively([...container.children, ...container.sketches], ArduinoMenus.FILE__SKETCHBOOK_SUBMENU, this.toDispose);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
@@ -23,18 +23,24 @@ export class UploadSketch extends SketchContribution {
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
|
||||
readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
|
||||
protected uploadInProgress = false;
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH, {
|
||||
execute: () => this.uploadSketch()
|
||||
execute: () => this.uploadSketch(),
|
||||
isEnabled: () => !this.uploadInProgress,
|
||||
});
|
||||
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER, {
|
||||
execute: () => this.uploadSketch(true)
|
||||
execute: () => this.uploadSketch(true),
|
||||
isEnabled: () => !this.uploadInProgress,
|
||||
});
|
||||
registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
isEnabled: () => !this.uploadInProgress,
|
||||
isToggled: () => this.uploadInProgress,
|
||||
execute: () => registry.executeCommand(UploadSketch.Commands.UPLOAD_SKETCH.id)
|
||||
});
|
||||
}
|
||||
@@ -68,11 +74,22 @@ export class UploadSketch extends SketchContribution {
|
||||
id: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id,
|
||||
command: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id,
|
||||
tooltip: 'Upload',
|
||||
priority: 1
|
||||
priority: 1,
|
||||
onDidChange: this.onDidChange
|
||||
});
|
||||
}
|
||||
|
||||
async uploadSketch(usingProgrammer: boolean = false): Promise<void> {
|
||||
|
||||
// even with buttons disabled, better to double check if an upload is already in progress
|
||||
if (this.uploadInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
// toggle the toolbar button and menu item state.
|
||||
// uploadInProgress will be set to false whether the upload fails or not
|
||||
this.uploadInProgress = true;
|
||||
this.onDidChangeEmitter.fire();
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!sketch) {
|
||||
return;
|
||||
@@ -135,6 +152,9 @@ export class UploadSketch extends SketchContribution {
|
||||
} catch (e) {
|
||||
this.messageService.error(e.toString());
|
||||
} finally {
|
||||
this.uploadInProgress = false;
|
||||
this.onDidChangeEmitter.fire();
|
||||
|
||||
if (monitorConfig) {
|
||||
const { board, port } = monitorConfig;
|
||||
try {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
@@ -19,18 +19,24 @@ export class VerifySketch extends SketchContribution {
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
|
||||
readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
|
||||
protected verifyInProgress = false;
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH, {
|
||||
execute: () => this.verifySketch()
|
||||
execute: () => this.verifySketch(),
|
||||
isEnabled: () => !this.verifyInProgress,
|
||||
});
|
||||
registry.registerCommand(VerifySketch.Commands.EXPORT_BINARIES, {
|
||||
execute: () => this.verifySketch(true)
|
||||
execute: () => this.verifySketch(true),
|
||||
isEnabled: () => !this.verifyInProgress,
|
||||
});
|
||||
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
isEnabled: () => !this.verifyInProgress,
|
||||
isToggled: () => this.verifyInProgress,
|
||||
execute: () => registry.executeCommand(VerifySketch.Commands.VERIFY_SKETCH.id)
|
||||
});
|
||||
}
|
||||
@@ -64,12 +70,24 @@ export class VerifySketch extends SketchContribution {
|
||||
id: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id,
|
||||
command: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id,
|
||||
tooltip: 'Verify',
|
||||
priority: 0
|
||||
priority: 0,
|
||||
onDidChange: this.onDidChange
|
||||
});
|
||||
}
|
||||
|
||||
async verifySketch(exportBinaries?: boolean): Promise<void> {
|
||||
|
||||
// even with buttons disabled, better to double check if a verify is already in progress
|
||||
if (this.verifyInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
// toggle the toolbar button and menu item state.
|
||||
// verifyInProgress will be set to false whether the compilation fails or not
|
||||
this.verifyInProgress = true;
|
||||
this.onDidChangeEmitter.fire();
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
|
||||
if (!sketch) {
|
||||
return;
|
||||
}
|
||||
@@ -80,6 +98,7 @@ export class VerifySketch extends SketchContribution {
|
||||
this.sourceOverride()
|
||||
]);
|
||||
const verbose = this.preferences.get('arduino.compile.verbose');
|
||||
const compilerWarnings = this.preferences.get('arduino.compile.warnings');
|
||||
this.outputChannelManager.getChannel('Arduino').clear();
|
||||
await this.coreService.compile({
|
||||
sketchUri: sketch.uri,
|
||||
@@ -87,11 +106,15 @@ export class VerifySketch extends SketchContribution {
|
||||
optimizeForDebug: this.editorMode.compileForDebug,
|
||||
verbose,
|
||||
exportBinaries,
|
||||
sourceOverride
|
||||
sourceOverride,
|
||||
compilerWarnings
|
||||
});
|
||||
this.messageService.info('Done compiling.', { timeout: 1000 });
|
||||
} catch (e) {
|
||||
this.messageService.error(e.toString());
|
||||
} finally {
|
||||
this.verifyInProgress = false;
|
||||
this.onDidChangeEmitter.fire();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -80,22 +80,22 @@
|
||||
}
|
||||
],
|
||||
"colors": {
|
||||
"list.highlightForeground": "#006468",
|
||||
"list.activeSelectionBackground": "#006468",
|
||||
"list.highlightForeground": "#005c5f",
|
||||
"list.activeSelectionBackground": "#005c5f",
|
||||
"editor.background": "#ffffff",
|
||||
"editorCursor.foreground": "#434f54",
|
||||
"editor.foreground": "#434f54",
|
||||
"editorWhitespace.foreground": "#bfbfbf",
|
||||
"editor.lineHighlightBackground": "#434f5410",
|
||||
"editor.selectionBackground": "#ffcb00",
|
||||
"focusBorder": "#4db7bb99",
|
||||
"focusBorder": "#7fcbcd99",
|
||||
"menubar.selectionBackground": "#ffffff",
|
||||
"menubar.selectionForeground": "#212121",
|
||||
"menu.selectionBackground": "#dae3e3",
|
||||
"menu.selectionForeground": "#212121",
|
||||
"editorGroupHeader.tabsBackground": "#f7f9f9",
|
||||
"button.background": "#4db7bb",
|
||||
"titleBar.activeBackground": "#006468",
|
||||
"button.background": "#7fcbcd",
|
||||
"titleBar.activeBackground": "#005c5f",
|
||||
"titleBar.activeForeground": "#ffffff",
|
||||
"terminal.background": "#000000",
|
||||
"terminal.foreground": "#e0e0e0",
|
||||
@@ -103,7 +103,7 @@
|
||||
"dropdown.background": "#ececec",
|
||||
"activityBar.background": "#ececec",
|
||||
"activityBar.foreground": "#616161",
|
||||
"statusBar.background": "#006468",
|
||||
"statusBar.background": "#005c5f",
|
||||
"secondaryButton.background": "#b5c8c9",
|
||||
"secondaryButton.hoverBackground": "#dae3e3",
|
||||
"arduino.branding.primary": "#00979d",
|
||||
|
@@ -1,6 +1,10 @@
|
||||
import { injectable, postConstruct, inject } from 'inversify';
|
||||
import { Message } from '@phosphor/messaging';
|
||||
import { addEventListener } from '@theia/core/lib/browser/widgets/widget';
|
||||
import { AbstractDialog, DialogProps } from '@theia/core/lib/browser/dialogs';
|
||||
import { LibraryPackage, LibraryService } from '../../common/protocol/library-service';
|
||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||
import { Installable } from '../../common/protocol';
|
||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||
|
||||
@injectable()
|
||||
@@ -33,4 +37,113 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
]);
|
||||
}
|
||||
|
||||
protected async install({ item, version }: { item: LibraryPackage, version: Installable.Version }): Promise<void> {
|
||||
const dependencies = await this.service.listDependencies({ item, version, filterSelf: true });
|
||||
let installDependencies: boolean | undefined = undefined;
|
||||
if (dependencies.length) {
|
||||
const message = document.createElement('div');
|
||||
message.innerHTML = `The library <b>${item.name}:${version}</b> needs ${dependencies.length === 1 ? 'another dependency' : 'some other dependencies'} currently not installed:`;
|
||||
const listContainer = document.createElement('div');
|
||||
listContainer.style.maxHeight = '300px';
|
||||
listContainer.style.overflowY = 'auto';
|
||||
const list = document.createElement('ul');
|
||||
list.style.listStyleType = 'none';
|
||||
for (const { name } of dependencies) {
|
||||
const listItem = document.createElement('li');
|
||||
listItem.textContent = ` - ${name}`;
|
||||
listItem.style.fontWeight = 'bold';
|
||||
list.appendChild(listItem);
|
||||
}
|
||||
listContainer.appendChild(list);
|
||||
message.appendChild(listContainer);
|
||||
const question = document.createElement('div');
|
||||
question.textContent = `Would you like to install ${dependencies.length === 1 ? 'the missing dependency' : 'all the missing dependencies'}?`;
|
||||
message.appendChild(question);
|
||||
const result = await new MessageBoxDialog({
|
||||
title: `Dependencies for library ${item.name}:${version}`,
|
||||
message,
|
||||
buttons: [
|
||||
'Install all',
|
||||
`Install ${item.name} only`,
|
||||
'Cancel'
|
||||
],
|
||||
maxWidth: 740 // Aligned with `settings-dialog.css`.
|
||||
}).open();
|
||||
|
||||
if (result) {
|
||||
const { response } = result;
|
||||
if (response === 0) { // All
|
||||
installDependencies = true;
|
||||
} else if (response === 1) { // Current only
|
||||
installDependencies = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The lib does not have any dependencies.
|
||||
installDependencies = false;
|
||||
}
|
||||
|
||||
if (typeof installDependencies === 'boolean') {
|
||||
return this.service.install({ item, version, installDependencies });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MessageBoxDialog extends AbstractDialog<MessageBoxDialog.Result> {
|
||||
|
||||
protected response: number;
|
||||
|
||||
constructor(protected readonly options: MessageBoxDialog.Options) {
|
||||
super(options);
|
||||
this.contentNode.appendChild(this.createMessageNode(this.options.message));
|
||||
(options.buttons || ['OK']).forEach((text, index) => {
|
||||
const button = this.createButton(text);
|
||||
button.classList.add(index === 0 ? 'main' : 'secondary');
|
||||
this.controlPanel.appendChild(button);
|
||||
this.toDisposeOnDetach.push(addEventListener(button, 'click', () => {
|
||||
this.response = index;
|
||||
this.accept();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
protected onCloseRequest(message: Message): void {
|
||||
super.onCloseRequest(message);
|
||||
this.accept();
|
||||
}
|
||||
|
||||
get value(): MessageBoxDialog.Result {
|
||||
return { response: this.response };
|
||||
}
|
||||
|
||||
protected createMessageNode(message: string | HTMLElement): HTMLElement {
|
||||
if (typeof message === 'string') {
|
||||
const messageNode = document.createElement('div');
|
||||
messageNode.textContent = message;
|
||||
return messageNode;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
protected handleEnter(event: KeyboardEvent): boolean | void {
|
||||
this.response = 0;
|
||||
super.handleEnter(event);
|
||||
}
|
||||
|
||||
}
|
||||
export namespace MessageBoxDialog {
|
||||
export interface Options extends DialogProps {
|
||||
/**
|
||||
* When empty, `['OK']` will be inferred.
|
||||
*/
|
||||
buttons?: string[];
|
||||
message: string | HTMLElement;
|
||||
}
|
||||
export interface Result {
|
||||
/**
|
||||
* The index of `buttons` that was clicked.
|
||||
*/
|
||||
readonly response: number;
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ export class LibraryListWidgetFrontendContribution extends AbstractViewContribut
|
||||
widgetName: LibraryListWidget.WIDGET_LABEL,
|
||||
defaultWidgetOptions: {
|
||||
area: 'left',
|
||||
rank: 700
|
||||
rank: 3
|
||||
},
|
||||
toggleCommandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
toggleKeybinding: 'CtrlCmd+Shift+I'
|
||||
|
@@ -3,7 +3,7 @@ import { deepClone } from '@theia/core/lib/common/objects';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { MonitorService, MonitorConfig, MonitorError, Status, MonitorReadEvent } from '../../common/protocol/monitor-service';
|
||||
import { MonitorService, MonitorConfig, MonitorError, Status } from '../../common/protocol/monitor-service';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { Port, Board, BoardsService, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
|
||||
@@ -48,7 +48,7 @@ export class MonitorConnection {
|
||||
/**
|
||||
* This emitter forwards all read events **iff** the connection is established.
|
||||
*/
|
||||
protected readonly onReadEmitter = new Emitter<MonitorReadEvent>();
|
||||
protected readonly onReadEmitter = new Emitter<{ message: string }>();
|
||||
|
||||
/**
|
||||
* Array for storing previous monitor errors received from the server, and based on the number of elements in this array,
|
||||
@@ -60,12 +60,6 @@ export class MonitorConnection {
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
// Forward the messages from the board **iff** connected.
|
||||
this.monitorServiceClient.onRead(event => {
|
||||
if (this.connected) {
|
||||
this.onReadEmitter.fire(event);
|
||||
}
|
||||
});
|
||||
this.monitorServiceClient.onError(async error => {
|
||||
let shouldReconnect = false;
|
||||
if (this.state) {
|
||||
@@ -179,6 +173,15 @@ export class MonitorConnection {
|
||||
console.info(`>>> Creating serial monitor connection for ${Board.toString(config.board)} on port ${Port.toString(config.port)}...`);
|
||||
const connectStatus = await this.monitorService.connect(config);
|
||||
if (Status.isOK(connectStatus)) {
|
||||
const requestMessage = () => {
|
||||
this.monitorService.request().then(({ message }) => {
|
||||
if (this.connected) {
|
||||
this.onReadEmitter.fire({ message });
|
||||
requestMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
requestMessage();
|
||||
this.state = { config };
|
||||
console.info(`<<< Serial monitor connection created for ${Board.toString(config.board, { useFqbn: false })} on port ${Port.toString(config.port)}.`);
|
||||
}
|
||||
@@ -225,7 +228,7 @@ export class MonitorConnection {
|
||||
return this.onConnectionChangedEmitter.event;
|
||||
}
|
||||
|
||||
get onRead(): Event<MonitorReadEvent> {
|
||||
get onRead(): Event<{ message: string }> {
|
||||
return this.onReadEmitter.event;
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,13 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { MonitorServiceClient, MonitorReadEvent, MonitorError } from '../../common/protocol/monitor-service';
|
||||
import { MonitorServiceClient, MonitorError } from '../../common/protocol/monitor-service';
|
||||
|
||||
@injectable()
|
||||
export class MonitorServiceClientImpl implements MonitorServiceClient {
|
||||
|
||||
protected readonly onReadEmitter = new Emitter<MonitorReadEvent>();
|
||||
protected readonly onErrorEmitter = new Emitter<MonitorError>();
|
||||
readonly onRead = this.onReadEmitter.event;
|
||||
readonly onError = this.onErrorEmitter.event;
|
||||
|
||||
notifyRead(event: MonitorReadEvent): void {
|
||||
this.onReadEmitter.fire(event);
|
||||
const { data } = event;
|
||||
console.debug(`Received data: ${data}`);
|
||||
}
|
||||
|
||||
notifyError(error: MonitorError): void {
|
||||
this.onErrorEmitter.fire(error);
|
||||
}
|
||||
|
@@ -294,8 +294,8 @@ export class SerialMonitorOutput extends React.Component<SerialMonitorOutput.Pro
|
||||
componentDidMount(): void {
|
||||
this.scrollToBottom();
|
||||
this.toDisposeBeforeUnmount.pushAll([
|
||||
this.props.monitorConnection.onRead(({ data }) => {
|
||||
const rawLines = data.split('\n');
|
||||
this.props.monitorConnection.onRead(({ message }) => {
|
||||
const rawLines = message.split('\n');
|
||||
const lines: string[] = []
|
||||
const timestamp = () => this.state.timestamp ? `${dateFormat(new Date(), 'H:M:ss.l')} -> ` : '';
|
||||
for (let i = 0; i < rawLines.length; i++) {
|
||||
|
@@ -14,7 +14,7 @@ export class OutputServiceImpl implements OutputService {
|
||||
|
||||
append(message: OutputMessage): void {
|
||||
const { chunk } = message;
|
||||
const channel = this.outputChannelManager.getChannel(`Arduino`);
|
||||
const channel = this.outputChannelManager.getChannel('Arduino');
|
||||
channel.show({ preserveFocus: true });
|
||||
channel.append(chunk);
|
||||
}
|
||||
|
@@ -18,17 +18,19 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { AbstractDialog, DialogProps, PreferenceService, PreferenceScope, DialogError, ReactWidget } from '@theia/core/lib/browser';
|
||||
import { Index } from '../common/types';
|
||||
import { ConfigService, FileSystemExt, Network, ProxySettings } from '../common/protocol';
|
||||
import { CompilerWarnings, CompilerWarningLiterals, ConfigService, FileSystemExt, Network, ProxySettings } from '../common/protocol';
|
||||
|
||||
export interface Settings extends Index {
|
||||
editorFontSize: number; // `editor.fontSize`
|
||||
themeId: string; // `workbench.colorTheme`
|
||||
autoSave: 'on' | 'off'; // `editor.autoSave`
|
||||
quickSuggestions: Record<'other'|'comments'|'strings', boolean>; // `editor.quickSuggestions`
|
||||
|
||||
autoScaleInterface: boolean; // `arduino.window.autoScale`
|
||||
interfaceScale: number; // `arduino.window.zoomLevel` https://github.com/eclipse-theia/theia/issues/8751
|
||||
checkForUpdates?: boolean; // `arduino.ide.autoUpdate`
|
||||
verboseOnCompile: boolean; // `arduino.compile.verbose`
|
||||
compilerWarnings: CompilerWarnings; // `arduino.compile.warnings`
|
||||
verboseOnUpload: boolean; // `arduino.upload.verbose`
|
||||
verifyAfterUpload: boolean; // `arduino.upload.verify`
|
||||
enableLsLogs: boolean; // `arduino.language.log`
|
||||
@@ -83,10 +85,12 @@ export class SettingsService {
|
||||
editorFontSize,
|
||||
themeId,
|
||||
autoSave,
|
||||
quickSuggestions,
|
||||
autoScaleInterface,
|
||||
interfaceScale,
|
||||
// checkForUpdates,
|
||||
verboseOnCompile,
|
||||
compilerWarnings,
|
||||
verboseOnUpload,
|
||||
verifyAfterUpload,
|
||||
enableLsLogs,
|
||||
@@ -95,10 +99,16 @@ export class SettingsService {
|
||||
this.preferenceService.get<number>('editor.fontSize', 12),
|
||||
this.preferenceService.get<string>('workbench.colorTheme', 'arduino-theme'),
|
||||
this.preferenceService.get<'on' | 'off'>('editor.autoSave', 'on'),
|
||||
this.preferenceService.get<object>('editor.quickSuggestion', {
|
||||
'other': false,
|
||||
'comments': false,
|
||||
'strings': false
|
||||
}),
|
||||
this.preferenceService.get<boolean>('arduino.window.autoScale', true),
|
||||
this.preferenceService.get<number>('arduino.window.zoomLevel', 0),
|
||||
// this.preferenceService.get<string>('arduino.ide.autoUpdate', true),
|
||||
this.preferenceService.get<boolean>('arduino.compile.verbose', true),
|
||||
this.preferenceService.get<any>('arduino.compile.warnings', 'None'),
|
||||
this.preferenceService.get<boolean>('arduino.upload.verbose', true),
|
||||
this.preferenceService.get<boolean>('arduino.upload.verify', true),
|
||||
this.preferenceService.get<boolean>('arduino.language.log', true),
|
||||
@@ -110,10 +120,12 @@ export class SettingsService {
|
||||
editorFontSize,
|
||||
themeId,
|
||||
autoSave,
|
||||
quickSuggestions,
|
||||
autoScaleInterface,
|
||||
interfaceScale,
|
||||
// checkForUpdates,
|
||||
verboseOnCompile,
|
||||
compilerWarnings,
|
||||
verboseOnUpload,
|
||||
verifyAfterUpload,
|
||||
enableLsLogs,
|
||||
@@ -151,10 +163,10 @@ export class SettingsService {
|
||||
return `Invalid sketchbook location: ${sketchbookPath}`;
|
||||
}
|
||||
if (editorFontSize <= 0) {
|
||||
return `Invalid editor font size. It must be a positive integer.`;
|
||||
return 'Invalid editor font size. It must be a positive integer.';
|
||||
}
|
||||
if (!ThemeService.get().getThemes().find(({ id }) => id === themeId)) {
|
||||
return `Invalid theme.`;
|
||||
return 'Invalid theme.';
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
@@ -171,10 +183,12 @@ export class SettingsService {
|
||||
editorFontSize,
|
||||
themeId,
|
||||
autoSave,
|
||||
quickSuggestions,
|
||||
autoScaleInterface,
|
||||
interfaceScale,
|
||||
// checkForUpdates,
|
||||
verboseOnCompile,
|
||||
compilerWarnings,
|
||||
verboseOnUpload,
|
||||
verifyAfterUpload,
|
||||
enableLsLogs,
|
||||
@@ -194,10 +208,12 @@ export class SettingsService {
|
||||
this.preferenceService.set('editor.fontSize', editorFontSize, PreferenceScope.User),
|
||||
this.preferenceService.set('workbench.colorTheme', themeId, PreferenceScope.User),
|
||||
this.preferenceService.set('editor.autoSave', autoSave, PreferenceScope.User),
|
||||
this.preferenceService.set('editor.quickSuggestions', quickSuggestions, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.window.autoScale', autoScaleInterface, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.window.zoomLevel', interfaceScale, PreferenceScope.User),
|
||||
// this.preferenceService.set('arduino.ide.autoUpdate', checkForUpdates, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.compile.verbose', verboseOnCompile, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.compile.warnings', compilerWarnings, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.upload.verbose', verboseOnUpload, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.upload.verify', verifyAfterUpload, PreferenceScope.User),
|
||||
this.preferenceService.set('arduino.language.log', enableLsLogs, PreferenceScope.User),
|
||||
@@ -267,6 +283,7 @@ export class SettingsComponent extends React.Component<SettingsComponent.Props,
|
||||
<div className='flex-line'>Interface scale:</div>
|
||||
<div className='flex-line'>Theme:</div>
|
||||
<div className='flex-line'>Show verbose output during:</div>
|
||||
<div className='flex-line'>Compiler warnings:</div>
|
||||
</div>
|
||||
<div className='column'>
|
||||
<div className='flex-line'>
|
||||
@@ -321,6 +338,14 @@ export class SettingsComponent extends React.Component<SettingsComponent.Props,
|
||||
upload
|
||||
</label>
|
||||
</div>
|
||||
<div className='flex-line'>
|
||||
<select
|
||||
className='theia-select'
|
||||
value={this.state.compilerWarnings}
|
||||
onChange={this.compilerWarningsDidChange}>
|
||||
{CompilerWarningLiterals.map(value => <option key={value} value={value}>{value}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label className='flex-line'>
|
||||
@@ -345,6 +370,13 @@ export class SettingsComponent extends React.Component<SettingsComponent.Props,
|
||||
onChange={this.autoSaveDidChange} />
|
||||
Auto save
|
||||
</label>
|
||||
<label className='flex-line'>
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={this.state.quickSuggestions.other === true}
|
||||
onChange={this.quickSuggestionsOtherDidChange} />
|
||||
Editor Quick Suggestions
|
||||
</label>
|
||||
<label className='flex-line'>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -536,6 +568,21 @@ export class SettingsComponent extends React.Component<SettingsComponent.Props,
|
||||
this.setState({ autoSave: event.target.checked ? 'on' : 'off' });
|
||||
};
|
||||
|
||||
protected quickSuggestionsOtherDidChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
// need to persist react events through lifecycle https://reactjs.org/docs/events.html#event-pooling
|
||||
const newVal = event.target.checked ? true : false
|
||||
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
quickSuggestions: {
|
||||
...prevState.quickSuggestions,
|
||||
other: newVal
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
protected themeDidChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { selectedIndex } = event.target.options;
|
||||
const theme = ThemeService.get().getThemes()[selectedIndex];
|
||||
@@ -544,6 +591,14 @@ export class SettingsComponent extends React.Component<SettingsComponent.Props,
|
||||
}
|
||||
};
|
||||
|
||||
protected compilerWarningsDidChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { selectedIndex } = event.target.options;
|
||||
const compilerWarnings = CompilerWarningLiterals[selectedIndex];
|
||||
if (compilerWarnings) {
|
||||
this.setState({ compilerWarnings });
|
||||
}
|
||||
};
|
||||
|
||||
protected verboseOnCompileDidChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ verboseOnCompile: event.target.checked });
|
||||
};
|
||||
|
@@ -37,8 +37,13 @@
|
||||
background-color: var(--theia-warningBackground);
|
||||
}
|
||||
|
||||
/* Overrule the default Theia CSS button styles. */
|
||||
/* Makes the sidepanel a bit wider when opening the widget */
|
||||
.p-DockPanel-widget {
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/* Overrule the default Theia CSS button styles. */
|
||||
button.theia-button,
|
||||
.theia-button {
|
||||
border: 1px solid var(--theia-dropdown-border);
|
||||
|
@@ -15,8 +15,8 @@
|
||||
background: var(--theia-arduino-toolbar-background);
|
||||
}
|
||||
|
||||
.p-TabBar-toolbar .item.arduino-tool-item > div:hover {
|
||||
background: (--theia-arduino-toolbar-hoverBackground);
|
||||
.p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div {
|
||||
background: var(--theia-arduino-toolbar-hoverBackground);
|
||||
}
|
||||
|
||||
.arduino-verify-sketch--toolbar,
|
||||
@@ -24,6 +24,16 @@
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.item.arduino-tool-item.toggled {
|
||||
background-color: unset;
|
||||
opacity: 1;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.item.arduino-tool-item.toggled .arduino-verify-sketch--toolbar {
|
||||
background-color: var(--theia-arduino-toolbar-toggleBackground) !important;
|
||||
}
|
||||
|
||||
.arduino-tool-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
.arduino-settings-dialog .content {
|
||||
padding: 5px;
|
||||
height: 250px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .flex-line {
|
||||
|
@@ -0,0 +1,113 @@
|
||||
import debounce = require('p-debounce');
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { DebugConfiguration } from '@theia/debug/lib/common/debug-common';
|
||||
import { DebugConfigurationModel as TheiaDebugConfigurationModel } from '@theia/debug/lib/browser/debug-configuration-model';
|
||||
import { DebugConfigurationManager as TheiaDebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager';
|
||||
import { SketchesService } from '../../../common/protocol';
|
||||
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
|
||||
import { DebugConfigurationModel } from './debug-configuration-model';
|
||||
import { FileOperationError, FileOperationResult } from '@theia/filesystem/lib/common/files';
|
||||
|
||||
@injectable()
|
||||
export class DebugConfigurationManager extends TheiaDebugConfigurationManager {
|
||||
|
||||
@inject(SketchesService)
|
||||
protected readonly sketchesService: SketchesService;
|
||||
|
||||
@inject(SketchesServiceClientImpl)
|
||||
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
|
||||
@inject(FrontendApplicationStateService)
|
||||
protected readonly appStateService: FrontendApplicationStateService;
|
||||
|
||||
protected onTempContentDidChangeEmitter = new Emitter<TheiaDebugConfigurationModel.JsonContent>();
|
||||
get onTempContentDidChange(): Event<TheiaDebugConfigurationModel.JsonContent> {
|
||||
return this.onTempContentDidChangeEmitter.event;
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
super.init();
|
||||
this.appStateService.reachedState('ready').then(async () => {
|
||||
const tempContent = await this.getTempLaunchJsonContent();
|
||||
if (!tempContent) {
|
||||
// No active sketch.
|
||||
return;
|
||||
}
|
||||
// Watch the file of the container folder.
|
||||
this.fileService.watch(tempContent instanceof URI ? tempContent : tempContent.uri);
|
||||
// Use the normalized temp folder name. We cannot compare Theia URIs here.
|
||||
// /var/folders/k3/d2fkvv1j16v3_rz93k7f74180000gn/T/arduino-ide2-a0337d47f86b24a51df3dbcf2cc17925/launch.json
|
||||
// /private/var/folders/k3/d2fkvv1j16v3_rz93k7f74180000gn/T/arduino-ide2-A0337D47F86B24A51DF3DBCF2CC17925/launch.json
|
||||
const tempFolderName = (tempContent instanceof URI ? tempContent : tempContent.uri.parent).path.base.toLowerCase();
|
||||
this.fileService.onDidFilesChange(event => {
|
||||
for (const { resource } of event.changes) {
|
||||
if (resource.path.base === 'launch.json' && resource.parent.path.base.toLowerCase() === tempFolderName) {
|
||||
this.getTempLaunchJsonContent().then(config => {
|
||||
if (config && !(config instanceof URI)) {
|
||||
this.onTempContentDidChangeEmitter.fire(config);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.updateModels();
|
||||
});
|
||||
}
|
||||
|
||||
protected updateModels = debounce(async () => {
|
||||
await this.appStateService.reachedState('ready');
|
||||
const roots = await this.workspaceService.roots;
|
||||
const toDelete = new Set(this.models.keys());
|
||||
for (const rootStat of roots) {
|
||||
const key = rootStat.resource.toString();
|
||||
toDelete.delete(key);
|
||||
if (!this.models.has(key)) {
|
||||
const tempContent = await this.getTempLaunchJsonContent();
|
||||
if (!tempContent) {
|
||||
continue;
|
||||
}
|
||||
const configurations: DebugConfiguration[] = tempContent instanceof URI ? [] : tempContent.configurations;
|
||||
const uri = tempContent instanceof URI ? undefined : tempContent.uri;
|
||||
const model = new DebugConfigurationModel(key, this.preferences, configurations, uri, this.onTempContentDidChange);
|
||||
model.onDidChange(() => this.updateCurrent());
|
||||
model.onDispose(() => this.models.delete(key));
|
||||
this.models.set(key, model);
|
||||
}
|
||||
}
|
||||
for (const uri of toDelete) {
|
||||
const model = this.models.get(uri);
|
||||
if (model) {
|
||||
model.dispose();
|
||||
}
|
||||
}
|
||||
this.updateCurrent();
|
||||
}, 500);
|
||||
|
||||
protected async getTempLaunchJsonContent(): Promise<TheiaDebugConfigurationModel.JsonContent & { uri: URI } | URI | undefined> {
|
||||
const sketch = await this.sketchesServiceClient.currentSketch();
|
||||
if (!sketch) {
|
||||
return undefined;
|
||||
}
|
||||
const uri = await this.sketchesService.getIdeTempFolderUri(sketch);
|
||||
const tempFolderUri = new URI(uri);
|
||||
await this.fileService.createFolder(tempFolderUri);
|
||||
try {
|
||||
const uri = tempFolderUri.resolve('launch.json');
|
||||
const { value } = await this.fileService.read(uri);
|
||||
const configurations = DebugConfigurationModel.parse(JSON.parse(value));
|
||||
return { uri, configurations };
|
||||
} catch (err) {
|
||||
if (err instanceof FileOperationError && err.fileOperationResult === FileOperationResult.FILE_NOT_FOUND) {
|
||||
return tempFolderUri;
|
||||
}
|
||||
console.error('Could not load debug configuration from IDE2 temp folder.', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { PreferenceService } from '@theia/core/lib/browser/preferences/preference-service';
|
||||
import { DebugConfiguration } from '@theia/debug/lib/common/debug-common';
|
||||
import { DebugConfigurationModel as TheiaDebugConfigurationModel } from '@theia/debug/lib/browser/debug-configuration-model';
|
||||
|
||||
export class DebugConfigurationModel extends TheiaDebugConfigurationModel {
|
||||
|
||||
constructor(
|
||||
readonly workspaceFolderUri: string,
|
||||
protected readonly preferences: PreferenceService,
|
||||
protected readonly config: DebugConfiguration[],
|
||||
protected configUri: URI | undefined,
|
||||
protected readonly onConfigDidChange: Event<TheiaDebugConfigurationModel.JsonContent>) {
|
||||
|
||||
super(workspaceFolderUri, preferences);
|
||||
this.toDispose.push(onConfigDidChange(content => {
|
||||
const { uri, configurations } = content;
|
||||
this.configUri = uri;
|
||||
this.config.length = 0;
|
||||
this.config.push(...configurations);
|
||||
this.reconcile();
|
||||
}));
|
||||
this.reconcile();
|
||||
}
|
||||
|
||||
protected parseConfigurations(): TheiaDebugConfigurationModel.JsonContent {
|
||||
return {
|
||||
uri: this.configUri,
|
||||
configurations: this.config
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace DebugConfigurationModel {
|
||||
export function parse(launchConfig: any): DebugConfiguration[] {
|
||||
const configurations: DebugConfiguration[] = [];
|
||||
if (launchConfig && typeof launchConfig === 'object' && 'configurations' in launchConfig) {
|
||||
if (Array.isArray(launchConfig.configurations)) {
|
||||
for (const configuration of launchConfig.configurations) {
|
||||
if (DebugConfiguration.is(configuration)) {
|
||||
configurations.push(configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
}
|
@@ -6,6 +6,11 @@ import { unregisterSubmenu } from '../../menu/arduino-menus';
|
||||
@injectable()
|
||||
export class DebugFrontendApplicationContribution extends TheiaDebugFrontendApplicationContribution {
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.options.defaultWidgetOptions.rank = 4;
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
super.registerMenus(registry);
|
||||
unregisterSubmenu(DebugMenus.DEBUG, registry);
|
||||
|
@@ -1,368 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// Copied from https://github.com/microsoft/vscode/blob/724c307bf35646ac549a8533a255c51b63fea5c7/src/vs/base/common/comparers.ts
|
||||
// We cannot customize the monaco loader for Theia: https://github.com/eclipse-theia/theia/issues/8220
|
||||
|
||||
import { isWindows } from '@theia/core/lib/common/os';
|
||||
|
||||
const sep = (isWindows ? '\\' : '/');
|
||||
interface IDisposable {
|
||||
dispose(): void;
|
||||
}
|
||||
interface IdleDeadline {
|
||||
readonly didTimeout: boolean;
|
||||
timeRemaining(): number;
|
||||
}
|
||||
let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;
|
||||
declare function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number;
|
||||
declare function cancelIdleCallback(handle: number): void;
|
||||
|
||||
(function () {
|
||||
if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {
|
||||
const dummyIdle: IdleDeadline = Object.freeze({
|
||||
didTimeout: true,
|
||||
timeRemaining() { return 15; }
|
||||
});
|
||||
runWhenIdle = (runner) => {
|
||||
const handle = setTimeout(() => runner(dummyIdle));
|
||||
let disposed = false;
|
||||
return {
|
||||
dispose() {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
clearTimeout(handle);
|
||||
}
|
||||
};
|
||||
};
|
||||
} else {
|
||||
runWhenIdle = (runner, timeout?) => {
|
||||
const handle: number = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);
|
||||
let disposed = false;
|
||||
return {
|
||||
dispose() {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
cancelIdleCallback(handle);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* An implementation of the "idle-until-urgent"-strategy as introduced
|
||||
* here: https://philipwalton.com/articles/idle-until-urgent/
|
||||
*/
|
||||
class IdleValue<T> {
|
||||
|
||||
private readonly _executor: () => void;
|
||||
private readonly _handle: IDisposable;
|
||||
|
||||
private _didRun: boolean = false;
|
||||
private _value?: T;
|
||||
private _error: any;
|
||||
|
||||
constructor(executor: () => T) {
|
||||
this._executor = () => {
|
||||
try {
|
||||
this._value = executor();
|
||||
} catch (err) {
|
||||
this._error = err;
|
||||
} finally {
|
||||
this._didRun = true;
|
||||
}
|
||||
};
|
||||
this._handle = runWhenIdle(() => this._executor());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._handle.dispose();
|
||||
}
|
||||
|
||||
get value(): T {
|
||||
if (!this._didRun) {
|
||||
this._handle.dispose();
|
||||
this._executor();
|
||||
}
|
||||
if (this._error) {
|
||||
throw this._error;
|
||||
}
|
||||
return this._value!;
|
||||
}
|
||||
}
|
||||
|
||||
// When comparing large numbers of strings, such as in sorting large arrays, is better for
|
||||
// performance to create an Intl.Collator object and use the function provided by its compare
|
||||
// property than it is to use String.prototype.localeCompare()
|
||||
|
||||
// A collator with numeric sorting enabled, and no sensitivity to case or to accents
|
||||
const intlFileNameCollatorBaseNumeric: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }> = new IdleValue(() => {
|
||||
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
|
||||
return {
|
||||
collator: collator,
|
||||
collatorIsNumeric: collator.resolvedOptions().numeric
|
||||
};
|
||||
});
|
||||
|
||||
// A collator with numeric sorting enabled.
|
||||
const intlFileNameCollatorNumeric: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => {
|
||||
const collator = new Intl.Collator(undefined, { numeric: true });
|
||||
return {
|
||||
collator: collator
|
||||
};
|
||||
});
|
||||
|
||||
// A collator with numeric sorting enabled, and sensitivity to accents and diacritics but not case.
|
||||
const intlFileNameCollatorNumericCaseInsenstive: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => {
|
||||
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'accent' });
|
||||
return {
|
||||
collator: collator
|
||||
};
|
||||
});
|
||||
|
||||
export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
|
||||
const a = one || '';
|
||||
const b = other || '';
|
||||
const result = intlFileNameCollatorBaseNumeric.value.collator.compare(a, b);
|
||||
|
||||
// Using the numeric option in the collator will
|
||||
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
|
||||
if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && a !== b) {
|
||||
return a < b ? -1 : 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compares filenames by name then extension, sorting numbers numerically instead of alphabetically. */
|
||||
export function compareFileNamesNumeric(one: string | null, other: string | null): number {
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one, true);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other, true);
|
||||
const collatorNumeric = intlFileNameCollatorNumeric.value.collator;
|
||||
const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
|
||||
let result;
|
||||
|
||||
// Check for name differences, comparing numbers numerically instead of alphabetically.
|
||||
result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check for case insensitive extension differences, comparing numbers numerically instead of alphabetically.
|
||||
result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Disambiguate the extension case if needed.
|
||||
if (oneExtension !== otherExtension) {
|
||||
return collatorNumeric.compare(oneExtension, otherExtension);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
|
||||
|
||||
export function noIntlCompareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
|
||||
if (!caseSensitive) {
|
||||
one = one && one.toLowerCase();
|
||||
other = other && other.toLowerCase();
|
||||
}
|
||||
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other);
|
||||
|
||||
if (oneName !== otherName) {
|
||||
return oneName < otherName ? -1 : 1;
|
||||
}
|
||||
|
||||
if (oneExtension === otherExtension) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return oneExtension < otherExtension ? -1 : 1;
|
||||
}
|
||||
|
||||
export function compareFileExtensions(one: string | null, other: string | null): number {
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other);
|
||||
|
||||
let result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneExtension, otherExtension);
|
||||
|
||||
if (result === 0) {
|
||||
// Using the numeric option in the collator will
|
||||
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
|
||||
if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && oneExtension !== otherExtension) {
|
||||
return oneExtension < otherExtension ? -1 : 1;
|
||||
}
|
||||
|
||||
// Extensions are equal, compare filenames
|
||||
result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneName, otherName);
|
||||
|
||||
if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && oneName !== otherName) {
|
||||
return oneName < otherName ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compares filenames by extenson, then by name. Sorts numbers numerically, not alphabetically. */
|
||||
export function compareFileExtensionsNumeric(one: string | null, other: string | null): number {
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one, true);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other, true);
|
||||
const collatorNumeric = intlFileNameCollatorNumeric.value.collator;
|
||||
const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
|
||||
let result;
|
||||
|
||||
// Check for extension differences, ignoring differences in case and comparing numbers numerically.
|
||||
result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compare names.
|
||||
result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Disambiguate extension case if needed.
|
||||
if (oneExtension !== otherExtension) {
|
||||
return collatorNumeric.compare(oneExtension, otherExtension);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Extracts the name and extension from a full filename, with optional special handling for dotfiles */
|
||||
function extractNameAndExtension(str?: string | null, dotfilesAsNames = false): [string, string] {
|
||||
const match = str ? FileNameMatch.exec(str) as Array<string> : ([] as Array<string>);
|
||||
|
||||
let result: [string, string] = [(match && match[1]) || '', (match && match[3]) || ''];
|
||||
|
||||
// if the dotfilesAsNames option is selected, treat an empty filename with an extension,
|
||||
// or a filename that starts with a dot, as a dotfile name
|
||||
if (dotfilesAsNames && (!result[0] && result[1] || result[0] && result[0].charAt(0) === '.')) {
|
||||
result = [result[0] + '.' + result[1], ''];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function compareAndDisambiguateByLength(collator: Intl.Collator, one: string, other: string) {
|
||||
// Check for differences
|
||||
let result = collator.compare(one, other);
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// In a numeric comparison, `foo1` and `foo01` will compare as equivalent.
|
||||
// Disambiguate by sorting the shorter string first.
|
||||
if (one.length !== other.length) {
|
||||
return one.length < other.length ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function comparePathComponents(one: string, other: string, caseSensitive = false): number {
|
||||
if (!caseSensitive) {
|
||||
one = one && one.toLowerCase();
|
||||
other = other && other.toLowerCase();
|
||||
}
|
||||
|
||||
if (one === other) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return one < other ? -1 : 1;
|
||||
}
|
||||
|
||||
export function comparePaths(one: string, other: string, caseSensitive = false): number {
|
||||
const oneParts = one.split(sep);
|
||||
const otherParts = other.split(sep);
|
||||
|
||||
const lastOne = oneParts.length - 1;
|
||||
const lastOther = otherParts.length - 1;
|
||||
let endOne: boolean, endOther: boolean;
|
||||
|
||||
for (let i = 0; ; i++) {
|
||||
endOne = lastOne === i;
|
||||
endOther = lastOther === i;
|
||||
|
||||
if (endOne && endOther) {
|
||||
return compareFileNames(oneParts[i], otherParts[i], caseSensitive);
|
||||
} else if (endOne) {
|
||||
return -1;
|
||||
} else if (endOther) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const result = comparePathComponents(oneParts[i], otherParts[i], caseSensitive);
|
||||
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function compareAnything(one: string, other: string, lookFor: string): number {
|
||||
const elementAName = one.toLowerCase();
|
||||
const elementBName = other.toLowerCase();
|
||||
|
||||
// Sort prefix matches over non prefix matches
|
||||
const prefixCompare = compareByPrefix(one, other, lookFor);
|
||||
if (prefixCompare) {
|
||||
return prefixCompare;
|
||||
}
|
||||
|
||||
// Sort suffix matches over non suffix matches
|
||||
const elementASuffixMatch = elementAName.endsWith(lookFor);
|
||||
const elementBSuffixMatch = elementBName.endsWith(lookFor);
|
||||
if (elementASuffixMatch !== elementBSuffixMatch) {
|
||||
return elementASuffixMatch ? -1 : 1;
|
||||
}
|
||||
|
||||
// Understand file names
|
||||
const r = compareFileNames(elementAName, elementBName);
|
||||
if (r !== 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
// Compare by name
|
||||
return elementAName.localeCompare(elementBName);
|
||||
}
|
||||
|
||||
export function compareByPrefix(one: string, other: string, lookFor: string): number {
|
||||
const elementAName = one.toLowerCase();
|
||||
const elementBName = other.toLowerCase();
|
||||
|
||||
// Sort prefix matches over non prefix matches
|
||||
const elementAPrefixMatch = elementAName.startsWith(lookFor);
|
||||
const elementBPrefixMatch = elementBName.startsWith(lookFor);
|
||||
if (elementAPrefixMatch !== elementBPrefixMatch) {
|
||||
return elementAPrefixMatch ? -1 : 1;
|
||||
}
|
||||
|
||||
// Same prefix: Sort shorter matches to the top to have those on top that match more precisely
|
||||
// tslint:disable-next-line: one-line
|
||||
else if (elementAPrefixMatch && elementBPrefixMatch) {
|
||||
if (elementAName.length < elementBName.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (elementAName.length > elementBName.length) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,12 +1,28 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
|
||||
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
|
||||
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
|
||||
import { FileNavigatorContribution as TheiaFileNavigatorContribution } from '@theia/navigator/lib/browser/navigator-contribution';
|
||||
import { FileNavigatorPreferences } from '@theia/navigator/lib/browser/navigator-preferences';
|
||||
import { OpenerService } from '@theia/core/lib/browser/opener-service';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { FileNavigatorFilter } from '@theia/navigator/lib/browser/navigator-filter';
|
||||
import { WorkspacePreferences } from '@theia/workspace/lib/browser/workspace-preferences';
|
||||
|
||||
@injectable()
|
||||
export class FileNavigatorContribution extends TheiaFileNavigatorContribution {
|
||||
|
||||
constructor(
|
||||
@inject(FileNavigatorPreferences) protected readonly fileNavigatorPreferences: FileNavigatorPreferences,
|
||||
@inject(OpenerService) protected readonly openerService: OpenerService,
|
||||
@inject(FileNavigatorFilter) protected readonly fileNavigatorFilter: FileNavigatorFilter,
|
||||
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService,
|
||||
@inject(WorkspacePreferences) protected readonly workspacePreferences: WorkspacePreferences
|
||||
) {
|
||||
super(fileNavigatorPreferences, openerService, fileNavigatorFilter, workspaceService, workspacePreferences);
|
||||
this.options.defaultWidgetOptions.rank = 1;
|
||||
}
|
||||
|
||||
async initializeLayout(app: FrontendApplication): Promise<void> {
|
||||
// NOOP
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { MenuModelRegistry } from '@theia/core/lib/common/menu';
|
||||
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
|
||||
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
|
||||
import { SearchInWorkspaceFrontendContribution as TheiaSearchInWorkspaceFrontendContribution, SearchInWorkspaceCommands } from '@theia/search-in-workspace/lib/browser/search-in-workspace-frontend-contribution';
|
||||
|
||||
@injectable()
|
||||
export class SearchInWorkspaceFrontendContribution extends TheiaSearchInWorkspaceFrontendContribution {
|
||||
|
||||
async initializeLayout(app: FrontendApplication): Promise<void> {
|
||||
// NOOP
|
||||
constructor() {
|
||||
super();
|
||||
this.options.defaultWidgetOptions.rank = 5;
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
|
@@ -0,0 +1,34 @@
|
||||
import { injectable } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { MEMORY_TEXT } from '@theia/search-in-workspace/lib/browser/in-memory-text-resource';
|
||||
import { SearchInWorkspaceFileNode, SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-result-tree-widget';
|
||||
|
||||
/**
|
||||
* Workaround for https://github.com/eclipse-theia/theia/pull/9192/.
|
||||
*/
|
||||
@injectable()
|
||||
export class SearchInWorkspaceResultTreeWidget extends TheiaSearchInWorkspaceResultTreeWidget {
|
||||
|
||||
protected async createReplacePreview(node: SearchInWorkspaceFileNode): Promise<URI> {
|
||||
const fileUri = new URI(node.fileUri).withScheme('file');
|
||||
const openedEditor = this.editorManager.all.find(({ editor }) => editor.uri.toString() === fileUri.toString());
|
||||
let content: string;
|
||||
if (openedEditor) {
|
||||
content = openedEditor.editor.document.getText();
|
||||
} else {
|
||||
const resource = await this.fileResourceResolver.resolve(fileUri);
|
||||
content = await resource.readContents();
|
||||
}
|
||||
|
||||
const lines = content.split('\n');
|
||||
node.children.map(l => {
|
||||
const leftPositionedNodes = node.children.filter(rl => rl.line === l.line && rl.character < l.character);
|
||||
const diff = (this._replaceTerm.length - this.searchTerm.length) * leftPositionedNodes.length;
|
||||
const start = lines[l.line - 1].substr(0, l.character - 1 + diff);
|
||||
const end = lines[l.line - 1].substr(l.character - 1 + diff + l.length);
|
||||
lines[l.line - 1] = start + this._replaceTerm + end;
|
||||
});
|
||||
|
||||
return fileUri.withScheme(MEMORY_TEXT).withQuery(lines.join('\n'));
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
import { injectable } from 'inversify';
|
||||
import * as React from 'react';
|
||||
import { Key, KeyCode } from '@theia/core/lib/browser';
|
||||
import { SearchInWorkspaceWidget as TheiaSearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget';
|
||||
|
||||
/**
|
||||
* Workaround for https://github.com/eclipse-theia/theia/pull/9183.
|
||||
*/
|
||||
@injectable()
|
||||
export class SearchInWorkspaceWidget extends TheiaSearchInWorkspaceWidget {
|
||||
|
||||
protected renderGlobField(kind: 'include' | 'exclude'): React.ReactNode {
|
||||
const currentValue = this.searchInWorkspaceOptions[kind];
|
||||
const value = currentValue && currentValue.join(', ') || '';
|
||||
return <div className='glob-field'>
|
||||
<div className='label'>{'files to ' + kind}</div>
|
||||
<input
|
||||
className='theia-input'
|
||||
type='text'
|
||||
size={1}
|
||||
defaultValue={value}
|
||||
id={kind + '-glob-field'}
|
||||
onKeyUp={e => {
|
||||
if (e.target) {
|
||||
const targetValue = (e.target as HTMLInputElement).value || '';
|
||||
let shouldSearch = Key.ENTER.keyCode === KeyCode.createKeyCode(e.nativeEvent).key?.keyCode;
|
||||
const currentOptions = (this.searchInWorkspaceOptions[kind] || []).slice().map(s => s.trim()).sort();
|
||||
const candidateOptions = this.splitOnComma(targetValue).map(s => s.trim()).sort();
|
||||
const sameAs = (left: string[], right: string[]) => {
|
||||
if (left.length !== right.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < left.length; i++) {
|
||||
if (left[i] !== right[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (!sameAs(currentOptions, candidateOptions)) {
|
||||
this.searchInWorkspaceOptions[kind] = this.splitOnComma(targetValue);
|
||||
shouldSearch = true;
|
||||
}
|
||||
if (shouldSearch) {
|
||||
this.resultTreeWidget.search(this.searchTerm, this.searchInWorkspaceOptions);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onFocus={kind === 'include' ? this.handleFocusIncludesInputBox : this.handleFocusExcludesInputBox}
|
||||
onBlur={kind === 'include' ? this.handleBlurIncludesInputBox : this.handleBlurExcludesInputBox}></input>
|
||||
</div>;
|
||||
}
|
||||
|
||||
}
|
@@ -8,7 +8,7 @@ import { FrontendApplication } from '@theia/core/lib/browser/frontend-applicatio
|
||||
import { FocusTracker, Widget } from '@theia/core/lib/browser';
|
||||
import { WorkspaceService as TheiaWorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { ConfigService } from '../../../common/protocol/config-service';
|
||||
import { SketchesService, Sketch } from '../../../common/protocol/sketches-service';
|
||||
import { SketchesService, Sketch, SketchContainer } from '../../../common/protocol/sketches-service';
|
||||
import { ArduinoWorkspaceRootResolver } from '../../arduino-workspace-resolver';
|
||||
|
||||
@injectable()
|
||||
@@ -50,7 +50,7 @@ export class WorkspaceService extends TheiaWorkspaceService {
|
||||
const hash = window.location.hash;
|
||||
const [recentWorkspaces, recentSketches] = await Promise.all([
|
||||
this.server.getRecentWorkspaces(),
|
||||
this.sketchService.getSketches().then(sketches => sketches.map(s => s.uri))
|
||||
this.sketchService.getSketches({}).then(container => SketchContainer.toArray(container).map(s => s.uri))
|
||||
]);
|
||||
const toOpen = await new ArduinoWorkspaceRootResolver({
|
||||
isValid: this.isValid.bind(this)
|
||||
|
@@ -0,0 +1,29 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { WorkspaceVariableContribution as TheiaWorkspaceVariableContribution } from '@theia/workspace/lib/browser/workspace-variable-contribution';
|
||||
import { Sketch } from '../../../common/protocol';
|
||||
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
|
||||
|
||||
@injectable()
|
||||
export class WorkspaceVariableContribution extends TheiaWorkspaceVariableContribution {
|
||||
|
||||
@inject(SketchesServiceClientImpl)
|
||||
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
|
||||
protected currentSketch?: Sketch;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.sketchesServiceClient.currentSketch().then().then(sketch => this.currentSketch = sketch);
|
||||
}
|
||||
|
||||
getResourceUri(): URI | undefined {
|
||||
const resourceUri = super.getResourceUri();
|
||||
// https://github.com/arduino/arduino-ide/issues/46
|
||||
// `currentWidget` can be an editor representing a file outside of the workspace. The current sketch should be a fallback.
|
||||
if (!resourceUri && this.currentSketch?.uri) {
|
||||
return new URI(this.currentSketch.uri);
|
||||
}
|
||||
return resourceUri;
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
import { FrontendApplicationContribution, FrontendApplication, Widget, Message } from "@theia/core/lib/browser";
|
||||
import { injectable, inject } from "inversify";
|
||||
import { ArduinoToolbar } from "./arduino-toolbar";
|
||||
import { TabBarToolbarRegistry } from "@theia/core/lib/browser/shell/tab-bar-toolbar";
|
||||
import { CommandRegistry } from "@theia/core";
|
||||
import { LabelParser } from "@theia/core/lib/browser/label-parser";
|
||||
import { FrontendApplicationContribution, FrontendApplication, Widget, Message } from '@theia/core/lib/browser';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ArduinoToolbar } from './arduino-toolbar';
|
||||
import { TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { CommandRegistry } from '@theia/core';
|
||||
import { LabelParser } from '@theia/core/lib/browser/label-parser';
|
||||
|
||||
export class ArduinoToolbarContainer extends Widget {
|
||||
|
||||
|
@@ -13,6 +13,7 @@ export namespace ArduinoToolbarComponent {
|
||||
commands: CommandRegistry,
|
||||
labelParser: LabelParser,
|
||||
commandIsEnabled: (id: string) => boolean,
|
||||
commandIsToggled: (id: string) => boolean,
|
||||
executeCommand: (e: React.MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
export interface State {
|
||||
@@ -39,7 +40,7 @@ export class ArduinoToolbarComponent extends React.Component<ArduinoToolbarCompo
|
||||
}
|
||||
}
|
||||
const command = this.props.commands.getCommand(item.command);
|
||||
const cls = `${ARDUINO_TOOLBAR_ITEM_CLASS} ${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM} ${command && this.props.commandIsEnabled(command.id) ? 'enabled' : ''}`
|
||||
const cls = `${ARDUINO_TOOLBAR_ITEM_CLASS} ${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM} ${command && this.props.commandIsEnabled(command.id) ? 'enabled' : ''} ${command && this.props.commandIsToggled(command.id) ? 'toggled' : ''}`
|
||||
return <div key={item.id} className={cls} >
|
||||
<div className={item.id}>
|
||||
<div
|
||||
@@ -112,6 +113,10 @@ export class ArduinoToolbar extends ReactWidget {
|
||||
protected commandIsEnabled(command: string): boolean {
|
||||
return this.commands.isEnabled(command, this);
|
||||
}
|
||||
protected readonly doCommandIsToggled = (id: string) => this.commandIsToggled(id);
|
||||
protected commandIsToggled(command: string): boolean {
|
||||
return this.commands.isToggled(command, this);
|
||||
}
|
||||
|
||||
protected render(): React.ReactNode {
|
||||
return <ArduinoToolbarComponent
|
||||
@@ -121,6 +126,7 @@ export class ArduinoToolbar extends ReactWidget {
|
||||
items={[...this.items.values()]}
|
||||
commands={this.commands}
|
||||
commandIsEnabled={this.doCommandIsEnabled}
|
||||
commandIsToggled={this.doCommandIsToggled}
|
||||
executeCommand={this.executeCommand}
|
||||
/>
|
||||
}
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import debounce = require('lodash.debounce');
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import { CommandService } from '@theia/core/lib/common/command';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { OutputCommands } from '@theia/output/lib/browser/output-commands';
|
||||
import { ConfirmDialog } from '@theia/core/lib/browser/dialogs';
|
||||
import { Searchable } from '../../../common/protocol/searchable';
|
||||
import { Installable } from '../../../common/protocol/installable';
|
||||
@@ -81,11 +84,38 @@ export class FilterableListContainer<T extends ArduinoComponent> extends React.C
|
||||
}
|
||||
|
||||
protected async install(item: T, version: Installable.Version): Promise<void> {
|
||||
const { installable, searchable, itemLabel } = this.props;
|
||||
const { install, searchable, itemLabel } = this.props;
|
||||
const dialog = new InstallationProgressDialog(itemLabel(item), version);
|
||||
dialog.open();
|
||||
try {
|
||||
await installable.install({ item, version });
|
||||
dialog.open();
|
||||
await this.clearArduinoChannel();
|
||||
await install({ item, version });
|
||||
const items = await searchable.search({ query: this.state.filterText });
|
||||
this.setState({ items: this.sort(items) });
|
||||
} catch (error) {
|
||||
this.props.messageService.error(error instanceof Error ? error.message : String(error));
|
||||
throw error;
|
||||
} finally {
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected async uninstall(item: T): Promise<void> {
|
||||
const ok = await new ConfirmDialog({
|
||||
title: 'Uninstall',
|
||||
msg: `Do you want to uninstall ${item.name}?`,
|
||||
ok: 'Yes',
|
||||
cancel: 'No'
|
||||
}).open();
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
const { uninstall, searchable, itemLabel } = this.props;
|
||||
const dialog = new UninstallationProgressDialog(itemLabel(item));
|
||||
try {
|
||||
await this.clearArduinoChannel();
|
||||
dialog.open();
|
||||
await uninstall({ item });
|
||||
const items = await searchable.search({ query: this.state.filterText });
|
||||
this.setState({ items: this.sort(items) });
|
||||
} finally {
|
||||
@@ -93,26 +123,8 @@ export class FilterableListContainer<T extends ArduinoComponent> extends React.C
|
||||
}
|
||||
}
|
||||
|
||||
protected async uninstall(item: T): Promise<void> {
|
||||
const uninstall = await new ConfirmDialog({
|
||||
title: 'Uninstall',
|
||||
msg: `Do you want to uninstall ${item.name}?`,
|
||||
ok: 'Yes',
|
||||
cancel: 'No'
|
||||
}).open();
|
||||
if (!uninstall) {
|
||||
return;
|
||||
}
|
||||
const { installable, searchable, itemLabel } = this.props;
|
||||
const dialog = new UninstallationProgressDialog(itemLabel(item));
|
||||
dialog.open();
|
||||
try {
|
||||
await installable.uninstall({ item });
|
||||
const items = await searchable.search({ query: this.state.filterText });
|
||||
this.setState({ items: this.sort(items) });
|
||||
} finally {
|
||||
dialog.close();
|
||||
}
|
||||
private async clearArduinoChannel(): Promise<void> {
|
||||
return this.props.commandService.executeCommand(OutputCommands.CLEAR.id, { name: 'Arduino' });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -121,13 +133,16 @@ export namespace FilterableListContainer {
|
||||
|
||||
export interface Props<T extends ArduinoComponent> {
|
||||
readonly container: ListWidget<T>;
|
||||
readonly installable: Installable<T>;
|
||||
readonly searchable: Searchable<T>;
|
||||
readonly itemLabel: (item: T) => string;
|
||||
readonly itemRenderer: ListItemRenderer<T>;
|
||||
readonly resolveContainer: (element: HTMLElement) => void;
|
||||
readonly resolveFocus: (element: HTMLElement | undefined) => void;
|
||||
readonly filterTextChangeEvent: Event<string | undefined>;
|
||||
readonly install: ({ item, version }: { item: T, version: Installable.Version }) => Promise<void>;
|
||||
readonly uninstall: ({ item }: { item: T }) => Promise<void>;
|
||||
readonly messageService: MessageService;
|
||||
readonly commandService: CommandService;
|
||||
}
|
||||
|
||||
export interface State<T> {
|
||||
|
@@ -5,6 +5,8 @@ import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
|
||||
import { CommandService } from '@theia/core/lib/common/command';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { Installable } from '../../../common/protocol/installable';
|
||||
import { Searchable } from '../../../common/protocol/searchable';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
@@ -15,6 +17,12 @@ import { NotificationCenter } from '../../notification-center';
|
||||
@injectable()
|
||||
export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget {
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
@inject(CommandService)
|
||||
protected readonly commandService: CommandService;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@@ -67,6 +75,14 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
||||
|
||||
protected onFocusResolved = (element: HTMLElement | undefined) => {
|
||||
this.focusNode = element;
|
||||
};
|
||||
|
||||
protected async install({ item, version }: { item: T, version: Installable.Version }): Promise<void> {
|
||||
return this.options.installable.install({ item, version });
|
||||
}
|
||||
|
||||
protected async uninstall({ item }: { item: T }): Promise<void> {
|
||||
return this.options.installable.uninstall({ item });
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
@@ -75,10 +91,13 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
||||
resolveContainer={this.deferredContainer.resolve}
|
||||
resolveFocus={this.onFocusResolved}
|
||||
searchable={this.options.searchable}
|
||||
installable={this.options.installable}
|
||||
install={this.install.bind(this)}
|
||||
uninstall={this.uninstall.bind(this)}
|
||||
itemLabel={this.options.itemLabel}
|
||||
itemRenderer={this.options.itemRenderer}
|
||||
filterTextChangeEvent={this.filterTextChangeEmitter.event} />;
|
||||
filterTextChangeEvent={this.filterTextChangeEmitter.event}
|
||||
messageService={this.messageService}
|
||||
commandService={this.commandService} />;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -121,9 +121,7 @@ export interface BoardsService extends Installable<BoardsPackage>, Searchable<Bo
|
||||
getBoardDetails(options: { fqbn: string }): Promise<BoardDetails | undefined>;
|
||||
getBoardPackage(options: { id: string }): Promise<BoardsPackage | undefined>;
|
||||
getContainerBoardPackage(options: { fqbn: string }): Promise<BoardsPackage | undefined>;
|
||||
// The CLI cannot do fuzzy search. This method provides all boards and we do the fuzzy search (with monaco) on the frontend.
|
||||
// https://github.com/arduino/arduino-cli/issues/629
|
||||
allBoards(options: {}): Promise<Array<BoardWithPackage>>;
|
||||
searchBoards({ query }: { query?: string }): Promise<BoardWithPackage[]>;
|
||||
}
|
||||
|
||||
export interface Port {
|
||||
|
@@ -1,9 +1,12 @@
|
||||
import { Programmer } from './boards-service';
|
||||
|
||||
export const CompilerWarningLiterals = ['None', 'Default', 'More', 'All'] as const;
|
||||
export type CompilerWarnings = typeof CompilerWarningLiterals[number];
|
||||
|
||||
export const CoreServicePath = '/services/core-service';
|
||||
export const CoreService = Symbol('CoreService');
|
||||
export interface CoreService {
|
||||
compile(options: CoreService.Compile.Options & Readonly<{ exportBinaries?: boolean }>): Promise<void>;
|
||||
compile(options: CoreService.Compile.Options & Readonly<{ exportBinaries?: boolean, compilerWarnings?: CompilerWarnings }>): Promise<void>;
|
||||
upload(options: CoreService.Upload.Options): Promise<void>;
|
||||
uploadUsingProgrammer(options: CoreService.Upload.Options): Promise<void>;
|
||||
burnBootloader(options: CoreService.Bootloader.Options): Promise<void>;
|
||||
|
@@ -1,14 +1,10 @@
|
||||
import { Sketch } from './sketches-service';
|
||||
import { SketchContainer } from './sketches-service';
|
||||
|
||||
export const ExamplesServicePath = '/services/example-service';
|
||||
export const ExamplesService = Symbol('ExamplesService');
|
||||
export interface ExamplesService {
|
||||
builtIns(): Promise<ExampleContainer[]>;
|
||||
installed(options: { fqbn: string }): Promise<{ user: ExampleContainer[], current: ExampleContainer[], any: ExampleContainer[] }>;
|
||||
builtIns(): Promise<SketchContainer[]>;
|
||||
installed(options: { fqbn: string }): Promise<{ user: SketchContainer[], current: SketchContainer[], any: SketchContainer[] }>;
|
||||
}
|
||||
|
||||
export interface ExampleContainer {
|
||||
readonly label: string;
|
||||
readonly children: ExampleContainer[];
|
||||
readonly sketches: Sketch[];
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,16 @@ export const LibraryServicePath = '/services/library-service';
|
||||
export const LibraryService = Symbol('LibraryService');
|
||||
export interface LibraryService extends Installable<LibraryPackage>, Searchable<LibraryPackage> {
|
||||
list(options: LibraryService.List.Options): Promise<LibraryPackage[]>;
|
||||
/**
|
||||
* When `installDependencies` is not set, it is `true` by default. If you want to skip the installation of required dependencies, set it to `false`.
|
||||
*/
|
||||
install(options: { item: LibraryPackage, version?: Installable.Version, installDependencies?: boolean }): Promise<void>;
|
||||
installZip(options: { zipUri: string, overwrite?: boolean }): Promise<void>;
|
||||
/**
|
||||
* Set `filterSelf` to `true` if you want to avoid having `item` in the result set.
|
||||
* Note: as of today (22.02.2021), the CLI works like this: `./arduino-cli lib deps Adaino@0.1.0 ✕ Adaino 0.1.0 must be installed.`.
|
||||
*/
|
||||
listDependencies({ item, version, filterSelf }: { item: LibraryPackage, version: Installable.Version, filterSelf?: boolean }): Promise<LibraryDependency[]>;
|
||||
}
|
||||
|
||||
export namespace LibraryService {
|
||||
@@ -83,3 +93,9 @@ export namespace LibraryPackage {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LibraryDependency {
|
||||
readonly name: string;
|
||||
readonly requiredVersion: Installable.Version;
|
||||
readonly installedVersion: Installable.Version;
|
||||
}
|
||||
|
@@ -20,7 +20,8 @@ export const MonitorService = Symbol('MonitorService');
|
||||
export interface MonitorService extends JsonRpcServer<MonitorServiceClient> {
|
||||
connect(config: MonitorConfig): Promise<Status>;
|
||||
disconnect(): Promise<Status>;
|
||||
send(data: string | Uint8Array): Promise<Status>;
|
||||
send(message: string): Promise<Status>;
|
||||
request(): Promise<{ message: string }>;
|
||||
}
|
||||
|
||||
export interface MonitorConfig {
|
||||
@@ -51,14 +52,9 @@ export namespace MonitorConfig {
|
||||
|
||||
export const MonitorServiceClient = Symbol('MonitorServiceClient');
|
||||
export interface MonitorServiceClient {
|
||||
notifyRead(event: MonitorReadEvent): void;
|
||||
notifyError(event: MonitorError): void;
|
||||
}
|
||||
|
||||
export interface MonitorReadEvent {
|
||||
readonly data: string;
|
||||
}
|
||||
|
||||
export interface MonitorError {
|
||||
readonly message: string;
|
||||
/**
|
||||
|
@@ -9,6 +9,7 @@ import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
||||
import { ConfigService } from './config-service';
|
||||
import { DisposableCollection, Emitter } from '@theia/core';
|
||||
import { FileChangeType } from '@theia/filesystem/lib/browser';
|
||||
import { SketchContainer } from './sketches-service';
|
||||
|
||||
@injectable()
|
||||
export class SketchesServiceClientImpl implements FrontendApplicationContribution {
|
||||
@@ -35,9 +36,9 @@ export class SketchesServiceClientImpl implements FrontendApplicationContributio
|
||||
|
||||
onStart(): void {
|
||||
this.configService.getConfiguration().then(({ sketchDirUri }) => {
|
||||
this.sketchService.getSketches(sketchDirUri).then(sketches => {
|
||||
this.sketchService.getSketches({ uri: sketchDirUri }).then(container => {
|
||||
const sketchbookUri = new URI(sketchDirUri);
|
||||
for (const sketch of sketches) {
|
||||
for (const sketch of SketchContainer.toArray(container)) {
|
||||
this.sketches.set(sketch.uri, sketch);
|
||||
}
|
||||
this.toDispose.push(this.fileService.watch(new URI(sketchDirUri), { recursive: true, excludes: [] }));
|
||||
|
@@ -5,10 +5,11 @@ export const SketchesService = Symbol('SketchesService');
|
||||
export interface SketchesService {
|
||||
|
||||
/**
|
||||
* Returns with the direct sketch folders from the location of the `fileStat`.
|
||||
* The sketches returns with inverse-chronological order, the first item is the most recent one.
|
||||
* Resolves to a sketch container representing the hierarchical structure of the sketches.
|
||||
* If `uri` is not given, `directories.user` will be user instead. Specify `exclude` global patterns to filter folders from the sketch container.
|
||||
* If `exclude` is not set `['**\/libraries\/**', '**\/hardware\/**']` will be used instead.
|
||||
*/
|
||||
getSketches(uri?: string): Promise<Sketch[]>;
|
||||
getSketches({ uri, exclude }: { uri?: string, exclude?: string[] }): Promise<SketchContainer>;
|
||||
|
||||
/**
|
||||
* This is the TS implementation of `SketchLoad` from the CLI and should be replaced with a gRPC call eventually.
|
||||
@@ -63,6 +64,12 @@ export interface SketchesService {
|
||||
*/
|
||||
archive(sketch: Sketch, destinationUri: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* Counterpart of the CLI's `genBuildPath` functionality.
|
||||
* Based on https://github.com/arduino/arduino-cli/blob/550179eefd2d2bca299d50a4af9e9bfcfebec649/arduino/builder/builder.go#L30-L38
|
||||
*/
|
||||
getIdeTempFolderUri(sketch: Sketch): Promise<string>;
|
||||
|
||||
}
|
||||
|
||||
export interface Sketch {
|
||||
@@ -94,3 +101,51 @@ export namespace Sketch {
|
||||
return Extensions.MAIN.some(ext => arg.endsWith(ext));
|
||||
}
|
||||
}
|
||||
|
||||
export interface SketchContainer {
|
||||
readonly label: string;
|
||||
readonly children: SketchContainer[];
|
||||
readonly sketches: Sketch[];
|
||||
}
|
||||
export namespace SketchContainer {
|
||||
|
||||
export function is(arg: any): arg is SketchContainer {
|
||||
return !!arg
|
||||
&& 'label' in arg && typeof arg.label === 'string'
|
||||
&& 'children' in arg && Array.isArray(arg.children)
|
||||
&& 'sketches' in arg && Array.isArray(arg.sketches);
|
||||
}
|
||||
|
||||
/**
|
||||
* `false` if the `container` recursively contains at least one sketch. Otherwise, `true`.
|
||||
*/
|
||||
export function isEmpty(container: SketchContainer): boolean {
|
||||
const hasSketch = (parent: SketchContainer) => {
|
||||
if (parent.sketches.length || parent.children.some(child => hasSketch(child))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return !hasSketch(container);
|
||||
}
|
||||
|
||||
export function prune<T extends SketchContainer>(container: T): T {
|
||||
for (let i = container.children.length - 1; i >= 0; i--) {
|
||||
if (isEmpty(container.children[i])) {
|
||||
container.children.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
export function toArray(container: SketchContainer): Sketch[] {
|
||||
const visit = (parent: SketchContainer, toPushSketch: Sketch[]) => {
|
||||
toPushSketch.push(...parent.sketches);
|
||||
parent.children.map(child => visit(child, toPushSketch));
|
||||
}
|
||||
const sketches: Sketch[] = [];
|
||||
visit(container, sketches);
|
||||
return sketches;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import { BrowserWindow } from "electron";
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
/**
|
||||
* When splashscreen was shown.
|
||||
@@ -126,11 +126,11 @@ export const initSplashScreen = (config: Config, onCloseRequested?: Event<void>)
|
||||
const window = new BrowserWindow(xConfig.windowOpts);
|
||||
splashScreen = new BrowserWindow(xConfig.splashScreenOpts);
|
||||
splashScreen.loadURL(`file://${xConfig.templateUrl}`);
|
||||
xConfig.closeWindow && splashScreen.on("close", () => {
|
||||
xConfig.closeWindow && splashScreen.on('close', () => {
|
||||
done || window.close();
|
||||
});
|
||||
// Splashscreen is fully loaded and ready to view.
|
||||
splashScreen.webContents.on("did-finish-load", () => {
|
||||
splashScreen.webContents.on('did-finish-load', () => {
|
||||
splashScreenReady = true;
|
||||
showSplash();
|
||||
});
|
||||
|
@@ -8,15 +8,16 @@ import {
|
||||
} from '../common/protocol';
|
||||
import {
|
||||
PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq,
|
||||
PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq
|
||||
PlatformListResp, PlatformUninstallResp, PlatformUninstallReq
|
||||
} from './cli-protocol/commands/core_pb';
|
||||
import { Platform } from './cli-protocol/commands/common_pb';
|
||||
import { BoardDiscovery } from './board-discovery';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb';
|
||||
import { CoreClientAware } from './core-client-provider';
|
||||
import { BoardDetailsReq, BoardDetailsResp, BoardSearchReq } from './cli-protocol/commands/board_pb';
|
||||
import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb';
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceImpl implements BoardsService {
|
||||
export class BoardsServiceImpl extends CoreClientAware implements BoardsService {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
@@ -25,9 +26,6 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
@named('discovery')
|
||||
protected discoveryLogger: ILogger;
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@@ -49,25 +47,6 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
return this.boardDiscovery.getAvailablePorts();
|
||||
}
|
||||
|
||||
private async coreClient(): Promise<CoreClientProvider.Client> {
|
||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
toDispose.dispose();
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
return coreClient;
|
||||
}
|
||||
|
||||
async getBoardDetails(options: { fqbn: string }): Promise<BoardDetails | undefined> {
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
@@ -166,10 +145,33 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
return packages.find(({ boards }) => boards.some(({ fqbn }) => fqbn === expectedFqbn));
|
||||
}
|
||||
|
||||
async allBoards(options: {}): Promise<Array<BoardWithPackage>> {
|
||||
const results = await this.search(options);
|
||||
return results.map(item => item.boards.map(board => ({ ...board, packageName: item.name, packageId: item.id })))
|
||||
.reduce((acc, curr) => acc.concat(curr), []);
|
||||
async searchBoards({ query }: { query?: string }): Promise<BoardWithPackage[]> {
|
||||
const { instance, client } = await this.coreClient();
|
||||
const req = new BoardSearchReq();
|
||||
req.setSearchArgs(query || '');
|
||||
req.setInstance(instance);
|
||||
const boards = await new Promise<BoardWithPackage[]>((resolve, reject) => {
|
||||
client.boardSearch(req, (error, resp) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
const boards: Array<BoardWithPackage> = [];
|
||||
for (const board of resp.getBoardsList()) {
|
||||
const platform = board.getPlatform();
|
||||
if (platform) {
|
||||
boards.push({
|
||||
name: board.getName(),
|
||||
fqbn: board.getFqbn(),
|
||||
packageId: platform.getId(),
|
||||
packageName: platform.getName()
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(boards);
|
||||
})
|
||||
});
|
||||
return boards;
|
||||
}
|
||||
|
||||
async search(options: { query?: string }): Promise<BoardsPackage[]> {
|
||||
@@ -276,7 +278,11 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
resp.on('error', error => {
|
||||
this.outputService.append({ chunk: `Failed to install platform: ${item.id}.\n` });
|
||||
this.outputService.append({ chunk: error.toString() });
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
const items = await this.search({});
|
||||
|
@@ -92,6 +92,9 @@ export class BoardDetailsResp extends jspb.Message {
|
||||
getDebuggingSupported(): boolean;
|
||||
setDebuggingSupported(value: boolean): BoardDetailsResp;
|
||||
|
||||
getSerialnumber(): string;
|
||||
setSerialnumber(value: string): BoardDetailsResp;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): BoardDetailsResp.AsObject;
|
||||
@@ -119,6 +122,7 @@ export namespace BoardDetailsResp {
|
||||
identificationPrefList: Array<IdentificationPref.AsObject>,
|
||||
programmersList: Array<commands_common_pb.Programmer.AsObject>,
|
||||
debuggingSupported: boolean,
|
||||
serialnumber: string,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,6 +539,9 @@ export class DetectedPort extends jspb.Message {
|
||||
setBoardsList(value: Array<BoardListItem>): DetectedPort;
|
||||
addBoards(value?: BoardListItem, index?: number): BoardListItem;
|
||||
|
||||
getSerialNumber(): string;
|
||||
setSerialNumber(value: string): DetectedPort;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DetectedPort.AsObject;
|
||||
@@ -552,6 +559,7 @@ export namespace DetectedPort {
|
||||
protocol: string,
|
||||
protocolLabel: string,
|
||||
boardsList: Array<BoardListItem.AsObject>,
|
||||
serialNumber: string,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,6 +697,12 @@ export class BoardListItem extends jspb.Message {
|
||||
setPid(value: string): BoardListItem;
|
||||
|
||||
|
||||
hasPlatform(): boolean;
|
||||
clearPlatform(): void;
|
||||
getPlatform(): commands_common_pb.Platform | undefined;
|
||||
setPlatform(value?: commands_common_pb.Platform): BoardListItem;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): BoardListItem.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: BoardListItem): BoardListItem.AsObject;
|
||||
@@ -706,5 +720,61 @@ export namespace BoardListItem {
|
||||
isHidden: boolean,
|
||||
vid: string,
|
||||
pid: string,
|
||||
platform?: commands_common_pb.Platform.AsObject,
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardSearchReq extends jspb.Message {
|
||||
|
||||
hasInstance(): boolean;
|
||||
clearInstance(): void;
|
||||
getInstance(): commands_common_pb.Instance | undefined;
|
||||
setInstance(value?: commands_common_pb.Instance): BoardSearchReq;
|
||||
|
||||
getSearchArgs(): string;
|
||||
setSearchArgs(value: string): BoardSearchReq;
|
||||
|
||||
getIncludeHiddenBoards(): boolean;
|
||||
setIncludeHiddenBoards(value: boolean): BoardSearchReq;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): BoardSearchReq.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: BoardSearchReq): BoardSearchReq.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: BoardSearchReq, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): BoardSearchReq;
|
||||
static deserializeBinaryFromReader(message: BoardSearchReq, reader: jspb.BinaryReader): BoardSearchReq;
|
||||
}
|
||||
|
||||
export namespace BoardSearchReq {
|
||||
export type AsObject = {
|
||||
instance?: commands_common_pb.Instance.AsObject,
|
||||
searchArgs: string,
|
||||
includeHiddenBoards: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export class BoardSearchResp extends jspb.Message {
|
||||
clearBoardsList(): void;
|
||||
getBoardsList(): Array<BoardListItem>;
|
||||
setBoardsList(value: Array<BoardListItem>): BoardSearchResp;
|
||||
addBoards(value?: BoardListItem, index?: number): BoardListItem;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): BoardSearchResp.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: BoardSearchResp): BoardSearchResp.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: BoardSearchResp, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): BoardSearchResp;
|
||||
static deserializeBinaryFromReader(message: BoardSearchResp, reader: jspb.BinaryReader): BoardSearchResp;
|
||||
}
|
||||
|
||||
export namespace BoardSearchResp {
|
||||
export type AsObject = {
|
||||
boardsList: Array<BoardListItem.AsObject>,
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ goog.exportSymbol('proto.cc.arduino.cli.commands.BoardListResp', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.BoardListWatchReq', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.BoardListWatchResp', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.BoardPlatform', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.BoardSearchReq', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.BoardSearchResp', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.ConfigOption', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.ConfigValue', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.DetectedPort', null, global);
|
||||
@@ -478,6 +480,48 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardListItem.displayName = 'proto.cc.arduino.cli.commands.BoardListItem';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.BoardSearchReq, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.displayName = 'proto.cc.arduino.cli.commands.BoardSearchReq';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, proto.cc.arduino.cli.commands.BoardSearchResp.repeatedFields_, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.BoardSearchResp, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.displayName = 'proto.cc.arduino.cli.commands.BoardSearchResp';
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -715,7 +759,8 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.toObject = function(includeInstan
|
||||
proto.cc.arduino.cli.commands.IdentificationPref.toObject, includeInstance),
|
||||
programmersList: jspb.Message.toObjectList(msg.getProgrammersList(),
|
||||
commands_common_pb.Programmer.toObject, includeInstance),
|
||||
debuggingSupported: jspb.Message.getBooleanFieldWithDefault(msg, 14, false)
|
||||
debuggingSupported: jspb.Message.getBooleanFieldWithDefault(msg, 14, false),
|
||||
serialnumber: jspb.Message.getFieldWithDefault(msg, 15, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -814,6 +859,10 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.deserializeBinaryFromReader = fun
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setDebuggingSupported(value);
|
||||
break;
|
||||
case 15:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setSerialnumber(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -947,6 +996,13 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.serializeBinaryToWriter = functio
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getSerialnumber();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
15,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1320,6 +1376,24 @@ proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.setDebuggingSupported =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string serialNumber = 15;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.getSerialnumber = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 15, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardDetailsResp} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardDetailsResp.prototype.setSerialnumber = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 15, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4028,7 +4102,8 @@ proto.cc.arduino.cli.commands.DetectedPort.toObject = function(includeInstance,
|
||||
protocol: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
protocolLabel: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
boardsList: jspb.Message.toObjectList(msg.getBoardsList(),
|
||||
proto.cc.arduino.cli.commands.BoardListItem.toObject, includeInstance)
|
||||
proto.cc.arduino.cli.commands.BoardListItem.toObject, includeInstance),
|
||||
serialNumber: jspb.Message.getFieldWithDefault(msg, 5, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -4082,6 +4157,10 @@ proto.cc.arduino.cli.commands.DetectedPort.deserializeBinaryFromReader = functio
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.BoardListItem.deserializeBinaryFromReader);
|
||||
msg.addBoards(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setSerialNumber(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -4140,6 +4219,13 @@ proto.cc.arduino.cli.commands.DetectedPort.serializeBinaryToWriter = function(me
|
||||
proto.cc.arduino.cli.commands.BoardListItem.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getSerialNumber();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4235,6 +4321,24 @@ proto.cc.arduino.cli.commands.DetectedPort.prototype.clearBoardsList = function(
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string serial_number = 5;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.DetectedPort.prototype.getSerialNumber = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.DetectedPort} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.DetectedPort.prototype.setSerialNumber = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
@@ -5060,7 +5164,8 @@ proto.cc.arduino.cli.commands.BoardListItem.toObject = function(includeInstance,
|
||||
fqbn: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
isHidden: jspb.Message.getBooleanFieldWithDefault(msg, 3, false),
|
||||
vid: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
pid: jspb.Message.getFieldWithDefault(msg, 5, "")
|
||||
pid: jspb.Message.getFieldWithDefault(msg, 5, ""),
|
||||
platform: (f = msg.getPlatform()) && commands_common_pb.Platform.toObject(includeInstance, f)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -5117,6 +5222,11 @@ proto.cc.arduino.cli.commands.BoardListItem.deserializeBinaryFromReader = functi
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setPid(value);
|
||||
break;
|
||||
case 6:
|
||||
var value = new commands_common_pb.Platform;
|
||||
reader.readMessage(value,commands_common_pb.Platform.deserializeBinaryFromReader);
|
||||
msg.setPlatform(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -5181,6 +5291,14 @@ proto.cc.arduino.cli.commands.BoardListItem.serializeBinaryToWriter = function(m
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getPlatform();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
6,
|
||||
f,
|
||||
commands_common_pb.Platform.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5274,4 +5392,412 @@ proto.cc.arduino.cli.commands.BoardListItem.prototype.setPid = function(value) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional Platform platform = 6;
|
||||
* @return {?proto.cc.arduino.cli.commands.Platform}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardListItem.prototype.getPlatform = function() {
|
||||
return /** @type{?proto.cc.arduino.cli.commands.Platform} */ (
|
||||
jspb.Message.getWrapperField(this, commands_common_pb.Platform, 6));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?proto.cc.arduino.cli.commands.Platform|undefined} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardListItem} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardListItem.prototype.setPlatform = function(value) {
|
||||
return jspb.Message.setWrapperField(this, 6, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardListItem} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardListItem.prototype.clearPlatform = function() {
|
||||
return this.setPlatform(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardListItem.prototype.hasPlatform = function() {
|
||||
return jspb.Message.getField(this, 6) != null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.BoardSearchReq.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchReq} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
||||
searchArgs: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
includeHiddenBoards: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.BoardSearchReq;
|
||||
return proto.cc.arduino.cli.commands.BoardSearchReq.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchReq} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = new commands_common_pb.Instance;
|
||||
reader.readMessage(value,commands_common_pb.Instance.deserializeBinaryFromReader);
|
||||
msg.setInstance(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setSearchArgs(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setIncludeHiddenBoards(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchReq} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getInstance();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
1,
|
||||
f,
|
||||
commands_common_pb.Instance.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getSearchArgs();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getIncludeHiddenBoards();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional Instance instance = 1;
|
||||
* @return {?proto.cc.arduino.cli.commands.Instance}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.getInstance = function() {
|
||||
return /** @type{?proto.cc.arduino.cli.commands.Instance} */ (
|
||||
jspb.Message.getWrapperField(this, commands_common_pb.Instance, 1));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?proto.cc.arduino.cli.commands.Instance|undefined} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.setInstance = function(value) {
|
||||
return jspb.Message.setWrapperField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.clearInstance = function() {
|
||||
return this.setInstance(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.hasInstance = function() {
|
||||
return jspb.Message.getField(this, 1) != null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string search_args = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.getSearchArgs = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.setSearchArgs = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool include_hidden_boards = 3;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.getIncludeHiddenBoards = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchReq.prototype.setIncludeHiddenBoards = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
* @private {!Array<number>}
|
||||
* @const
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.repeatedFields_ = [1];
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.BoardSearchResp.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchResp} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
boardsList: jspb.Message.toObjectList(msg.getBoardsList(),
|
||||
proto.cc.arduino.cli.commands.BoardListItem.toObject, includeInstance)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchResp}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.BoardSearchResp;
|
||||
return proto.cc.arduino.cli.commands.BoardSearchResp.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchResp} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchResp}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = new proto.cc.arduino.cli.commands.BoardListItem;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.BoardListItem.deserializeBinaryFromReader);
|
||||
msg.addBoards(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardSearchResp} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getBoardsList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedMessage(
|
||||
1,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.BoardListItem.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated BoardListItem boards = 1;
|
||||
* @return {!Array<!proto.cc.arduino.cli.commands.BoardListItem>}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.getBoardsList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.BoardListItem>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.BoardListItem, 1));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<!proto.cc.arduino.cli.commands.BoardListItem>} value
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchResp} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.setBoardsList = function(value) {
|
||||
return jspb.Message.setRepeatedWrapperField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.cc.arduino.cli.commands.BoardListItem=} opt_value
|
||||
* @param {number=} opt_index
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardListItem}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.addBoards = function(opt_value, opt_index) {
|
||||
return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.cc.arduino.cli.commands.BoardListItem, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
* @return {!proto.cc.arduino.cli.commands.BoardSearchResp} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.BoardSearchResp.prototype.clearBoardsList = function() {
|
||||
return this.setBoardsList([]);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.cc.arduino.cli.commands);
|
||||
|
@@ -30,6 +30,7 @@ interface IArduinoCoreService extends grpc.ServiceDefinition<grpc.UntypedService
|
||||
boardAttach: IArduinoCoreService_IBoardAttach;
|
||||
boardList: IArduinoCoreService_IBoardList;
|
||||
boardListAll: IArduinoCoreService_IBoardListAll;
|
||||
boardSearch: IArduinoCoreService_IBoardSearch;
|
||||
boardListWatch: IArduinoCoreService_IBoardListWatch;
|
||||
compile: IArduinoCoreService_ICompile;
|
||||
platformInstall: IArduinoCoreService_IPlatformInstall;
|
||||
@@ -188,6 +189,15 @@ interface IArduinoCoreService_IBoardListAll extends grpc.MethodDefinition<comman
|
||||
responseSerialize: grpc.serialize<commands_board_pb.BoardListAllResp>;
|
||||
responseDeserialize: grpc.deserialize<commands_board_pb.BoardListAllResp>;
|
||||
}
|
||||
interface IArduinoCoreService_IBoardSearch extends grpc.MethodDefinition<commands_board_pb.BoardSearchReq, commands_board_pb.BoardSearchResp> {
|
||||
path: "/cc.arduino.cli.commands.ArduinoCore/BoardSearch";
|
||||
requestStream: false;
|
||||
responseStream: false;
|
||||
requestSerialize: grpc.serialize<commands_board_pb.BoardSearchReq>;
|
||||
requestDeserialize: grpc.deserialize<commands_board_pb.BoardSearchReq>;
|
||||
responseSerialize: grpc.serialize<commands_board_pb.BoardSearchResp>;
|
||||
responseDeserialize: grpc.deserialize<commands_board_pb.BoardSearchResp>;
|
||||
}
|
||||
interface IArduinoCoreService_IBoardListWatch extends grpc.MethodDefinition<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp> {
|
||||
path: "/cc.arduino.cli.commands.ArduinoCore/BoardListWatch";
|
||||
requestStream: true;
|
||||
@@ -396,6 +406,7 @@ export interface IArduinoCoreServer {
|
||||
boardAttach: grpc.handleServerStreamingCall<commands_board_pb.BoardAttachReq, commands_board_pb.BoardAttachResp>;
|
||||
boardList: grpc.handleUnaryCall<commands_board_pb.BoardListReq, commands_board_pb.BoardListResp>;
|
||||
boardListAll: grpc.handleUnaryCall<commands_board_pb.BoardListAllReq, commands_board_pb.BoardListAllResp>;
|
||||
boardSearch: grpc.handleUnaryCall<commands_board_pb.BoardSearchReq, commands_board_pb.BoardSearchResp>;
|
||||
boardListWatch: grpc.handleBidiStreamingCall<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
compile: grpc.handleServerStreamingCall<commands_compile_pb.CompileReq, commands_compile_pb.CompileResp>;
|
||||
platformInstall: grpc.handleServerStreamingCall<commands_core_pb.PlatformInstallReq, commands_core_pb.PlatformInstallResp>;
|
||||
@@ -459,6 +470,9 @@ export interface IArduinoCoreClient {
|
||||
boardListAll(request: commands_board_pb.BoardListAllReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
boardListAll(request: commands_board_pb.BoardListAllReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
boardListAll(request: commands_board_pb.BoardListAllReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
boardSearch(request: commands_board_pb.BoardSearchReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
boardSearch(request: commands_board_pb.BoardSearchReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
boardSearch(request: commands_board_pb.BoardSearchReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
boardListWatch(): grpc.ClientDuplexStream<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
boardListWatch(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
boardListWatch(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
@@ -551,6 +565,9 @@ export class ArduinoCoreClient extends grpc.Client implements IArduinoCoreClient
|
||||
public boardListAll(request: commands_board_pb.BoardListAllReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
public boardListAll(request: commands_board_pb.BoardListAllReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
public boardListAll(request: commands_board_pb.BoardListAllReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardListAllResp) => void): grpc.ClientUnaryCall;
|
||||
public boardSearch(request: commands_board_pb.BoardSearchReq, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
public boardSearch(request: commands_board_pb.BoardSearchReq, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
public boardSearch(request: commands_board_pb.BoardSearchReq, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: commands_board_pb.BoardSearchResp) => void): grpc.ClientUnaryCall;
|
||||
public boardListWatch(options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
public boardListWatch(metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<commands_board_pb.BoardListWatchReq, commands_board_pb.BoardListWatchResp>;
|
||||
public compile(request: commands_compile_pb.CompileReq, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<commands_compile_pb.CompileResp>;
|
||||
|
@@ -157,6 +157,28 @@ function deserialize_cc_arduino_cli_commands_BoardListWatchResp(buffer_arg) {
|
||||
return commands_board_pb.BoardListWatchResp.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_cc_arduino_cli_commands_BoardSearchReq(arg) {
|
||||
if (!(arg instanceof commands_board_pb.BoardSearchReq)) {
|
||||
throw new Error('Expected argument of type cc.arduino.cli.commands.BoardSearchReq');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_cc_arduino_cli_commands_BoardSearchReq(buffer_arg) {
|
||||
return commands_board_pb.BoardSearchReq.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_cc_arduino_cli_commands_BoardSearchResp(arg) {
|
||||
if (!(arg instanceof commands_board_pb.BoardSearchResp)) {
|
||||
throw new Error('Expected argument of type cc.arduino.cli.commands.BoardSearchResp');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_cc_arduino_cli_commands_BoardSearchResp(buffer_arg) {
|
||||
return commands_board_pb.BoardSearchResp.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_cc_arduino_cli_commands_BurnBootloaderReq(arg) {
|
||||
if (!(arg instanceof commands_upload_pb.BurnBootloaderReq)) {
|
||||
throw new Error('Expected argument of type cc.arduino.cli.commands.BurnBootloaderReq');
|
||||
@@ -1004,6 +1026,18 @@ boardListAll: {
|
||||
responseSerialize: serialize_cc_arduino_cli_commands_BoardListAllResp,
|
||||
responseDeserialize: deserialize_cc_arduino_cli_commands_BoardListAllResp,
|
||||
},
|
||||
// Search boards in installed and not installed Platforms.
|
||||
boardSearch: {
|
||||
path: '/cc.arduino.cli.commands.ArduinoCore/BoardSearch',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: commands_board_pb.BoardSearchReq,
|
||||
responseType: commands_board_pb.BoardSearchResp,
|
||||
requestSerialize: serialize_cc_arduino_cli_commands_BoardSearchReq,
|
||||
requestDeserialize: deserialize_cc_arduino_cli_commands_BoardSearchReq,
|
||||
responseSerialize: serialize_cc_arduino_cli_commands_BoardSearchResp,
|
||||
responseDeserialize: deserialize_cc_arduino_cli_commands_BoardSearchResp,
|
||||
},
|
||||
// List boards connection and disconnected events.
|
||||
boardListWatch: {
|
||||
path: '/cc.arduino.cli.commands.ArduinoCore/BoardListWatch',
|
||||
|
@@ -348,9 +348,9 @@ export class OutdatedResp extends jspb.Message {
|
||||
addOutdatedLibrary(value?: commands_lib_pb.InstalledLibrary, index?: number): commands_lib_pb.InstalledLibrary;
|
||||
|
||||
clearOutdatedPlatformList(): void;
|
||||
getOutdatedPlatformList(): Array<commands_core_pb.Platform>;
|
||||
setOutdatedPlatformList(value: Array<commands_core_pb.Platform>): OutdatedResp;
|
||||
addOutdatedPlatform(value?: commands_core_pb.Platform, index?: number): commands_core_pb.Platform;
|
||||
getOutdatedPlatformList(): Array<commands_common_pb.Platform>;
|
||||
setOutdatedPlatformList(value: Array<commands_common_pb.Platform>): OutdatedResp;
|
||||
addOutdatedPlatform(value?: commands_common_pb.Platform, index?: number): commands_common_pb.Platform;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
@@ -366,7 +366,7 @@ export class OutdatedResp extends jspb.Message {
|
||||
export namespace OutdatedResp {
|
||||
export type AsObject = {
|
||||
outdatedLibraryList: Array<commands_lib_pb.InstalledLibrary.AsObject>,
|
||||
outdatedPlatformList: Array<commands_core_pb.Platform.AsObject>,
|
||||
outdatedPlatformList: Array<commands_common_pb.Platform.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2667,7 +2667,7 @@ proto.cc.arduino.cli.commands.OutdatedResp.toObject = function(includeInstance,
|
||||
outdatedLibraryList: jspb.Message.toObjectList(msg.getOutdatedLibraryList(),
|
||||
commands_lib_pb.InstalledLibrary.toObject, includeInstance),
|
||||
outdatedPlatformList: jspb.Message.toObjectList(msg.getOutdatedPlatformList(),
|
||||
commands_core_pb.Platform.toObject, includeInstance)
|
||||
commands_common_pb.Platform.toObject, includeInstance)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -2710,8 +2710,8 @@ proto.cc.arduino.cli.commands.OutdatedResp.deserializeBinaryFromReader = functio
|
||||
msg.addOutdatedLibrary(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = new commands_core_pb.Platform;
|
||||
reader.readMessage(value,commands_core_pb.Platform.deserializeBinaryFromReader);
|
||||
var value = new commands_common_pb.Platform;
|
||||
reader.readMessage(value,commands_common_pb.Platform.deserializeBinaryFromReader);
|
||||
msg.addOutdatedPlatform(value);
|
||||
break;
|
||||
default:
|
||||
@@ -2756,7 +2756,7 @@ proto.cc.arduino.cli.commands.OutdatedResp.serializeBinaryToWriter = function(me
|
||||
writer.writeRepeatedMessage(
|
||||
2,
|
||||
f,
|
||||
commands_core_pb.Platform.serializeBinaryToWriter
|
||||
commands_common_pb.Platform.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -2806,7 +2806,7 @@ proto.cc.arduino.cli.commands.OutdatedResp.prototype.clearOutdatedLibraryList =
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.OutdatedResp.prototype.getOutdatedPlatformList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.Platform>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, commands_core_pb.Platform, 2));
|
||||
jspb.Message.getRepeatedWrapperField(this, commands_common_pb.Platform, 2));
|
||||
};
|
||||
|
||||
|
||||
|
@@ -121,3 +121,83 @@ export namespace Programmer {
|
||||
name: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class Platform extends jspb.Message {
|
||||
getId(): string;
|
||||
setId(value: string): Platform;
|
||||
|
||||
getInstalled(): string;
|
||||
setInstalled(value: string): Platform;
|
||||
|
||||
getLatest(): string;
|
||||
setLatest(value: string): Platform;
|
||||
|
||||
getName(): string;
|
||||
setName(value: string): Platform;
|
||||
|
||||
getMaintainer(): string;
|
||||
setMaintainer(value: string): Platform;
|
||||
|
||||
getWebsite(): string;
|
||||
setWebsite(value: string): Platform;
|
||||
|
||||
getEmail(): string;
|
||||
setEmail(value: string): Platform;
|
||||
|
||||
clearBoardsList(): void;
|
||||
getBoardsList(): Array<Board>;
|
||||
setBoardsList(value: Array<Board>): Platform;
|
||||
addBoards(value?: Board, index?: number): Board;
|
||||
|
||||
getManuallyinstalled(): boolean;
|
||||
setManuallyinstalled(value: boolean): Platform;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Platform.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Platform): Platform.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Platform, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Platform;
|
||||
static deserializeBinaryFromReader(message: Platform, reader: jspb.BinaryReader): Platform;
|
||||
}
|
||||
|
||||
export namespace Platform {
|
||||
export type AsObject = {
|
||||
id: string,
|
||||
installed: string,
|
||||
latest: string,
|
||||
name: string,
|
||||
maintainer: string,
|
||||
website: string,
|
||||
email: string,
|
||||
boardsList: Array<Board.AsObject>,
|
||||
manuallyinstalled: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export class Board extends jspb.Message {
|
||||
getName(): string;
|
||||
setName(value: string): Board;
|
||||
|
||||
getFqbn(): string;
|
||||
setFqbn(value: string): Board;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Board.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Board): Board.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Board, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Board;
|
||||
static deserializeBinaryFromReader(message: Board, reader: jspb.BinaryReader): Board;
|
||||
}
|
||||
|
||||
export namespace Board {
|
||||
export type AsObject = {
|
||||
name: string,
|
||||
fqbn: string,
|
||||
}
|
||||
}
|
||||
|
@@ -14,8 +14,10 @@ var jspb = require('google-protobuf');
|
||||
var goog = jspb;
|
||||
var global = Function('return this')();
|
||||
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Board', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.DownloadProgress', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Instance', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Platform', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Programmer', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.TaskProgress', null, global);
|
||||
/**
|
||||
@@ -102,6 +104,48 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Programmer.displayName = 'proto.cc.arduino.cli.commands.Programmer';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, proto.cc.arduino.cli.commands.Platform.repeatedFields_, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.Platform, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.displayName = 'proto.cc.arduino.cli.commands.Platform';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.Board, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.displayName = 'proto.cc.arduino.cli.commands.Board';
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -862,4 +906,564 @@ proto.cc.arduino.cli.commands.Programmer.prototype.setName = function(value) {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
* @private {!Array<number>}
|
||||
* @const
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.repeatedFields_ = [8];
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.Platform.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
installed: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
latest: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
name: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
maintainer: jspb.Message.getFieldWithDefault(msg, 5, ""),
|
||||
website: jspb.Message.getFieldWithDefault(msg, 6, ""),
|
||||
email: jspb.Message.getFieldWithDefault(msg, 7, ""),
|
||||
boardsList: jspb.Message.toObjectList(msg.getBoardsList(),
|
||||
proto.cc.arduino.cli.commands.Board.toObject, includeInstance),
|
||||
manuallyinstalled: jspb.Message.getBooleanFieldWithDefault(msg, 9, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.Platform;
|
||||
return proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setId(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setInstalled(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setLatest(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setName(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMaintainer(value);
|
||||
break;
|
||||
case 6:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setWebsite(value);
|
||||
break;
|
||||
case 7:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setEmail(value);
|
||||
break;
|
||||
case 8:
|
||||
var value = new proto.cc.arduino.cli.commands.Board;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader);
|
||||
msg.addBoards(value);
|
||||
break;
|
||||
case 9:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setManuallyinstalled(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getId();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getInstalled();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getLatest();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getName();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getMaintainer();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getWebsite();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
6,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getEmail();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
7,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getBoardsList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedMessage(
|
||||
8,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getManuallyinstalled();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
9,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string ID = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getId = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setId = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Installed = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getInstalled = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setInstalled = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Latest = 3;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getLatest = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setLatest = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Name = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getName = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setName = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Maintainer = 5;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getMaintainer = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setMaintainer = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Website = 6;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getWebsite = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setWebsite = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 6, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Email = 7;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getEmail = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setEmail = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 7, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated Board Boards = 8;
|
||||
* @return {!Array<!proto.cc.arduino.cli.commands.Board>}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getBoardsList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.Board>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.Board, 8));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<!proto.cc.arduino.cli.commands.Board>} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setBoardsList = function(value) {
|
||||
return jspb.Message.setRepeatedWrapperField(this, 8, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.cc.arduino.cli.commands.Board=} opt_value
|
||||
* @param {number=} opt_index
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.addBoards = function(opt_value, opt_index) {
|
||||
return jspb.Message.addToRepeatedWrapperField(this, 8, opt_value, proto.cc.arduino.cli.commands.Board, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.clearBoardsList = function() {
|
||||
return this.setBoardsList([]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool ManuallyInstalled = 9;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getManuallyinstalled = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 9, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setManuallyinstalled = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 9, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.Board.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
name: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
fqbn: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.Board;
|
||||
return proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setName(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setFqbn(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getName();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getFqbn();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string name = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.getName = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Board} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.setName = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string fqbn = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.getFqbn = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Board} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.setFqbn = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.cc.arduino.cli.commands);
|
||||
|
@@ -295,9 +295,9 @@ export namespace PlatformSearchReq {
|
||||
|
||||
export class PlatformSearchResp extends jspb.Message {
|
||||
clearSearchOutputList(): void;
|
||||
getSearchOutputList(): Array<Platform>;
|
||||
setSearchOutputList(value: Array<Platform>): PlatformSearchResp;
|
||||
addSearchOutput(value?: Platform, index?: number): Platform;
|
||||
getSearchOutputList(): Array<commands_common_pb.Platform>;
|
||||
setSearchOutputList(value: Array<commands_common_pb.Platform>): PlatformSearchResp;
|
||||
addSearchOutput(value?: commands_common_pb.Platform, index?: number): commands_common_pb.Platform;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
@@ -312,7 +312,7 @@ export class PlatformSearchResp extends jspb.Message {
|
||||
|
||||
export namespace PlatformSearchResp {
|
||||
export type AsObject = {
|
||||
searchOutputList: Array<Platform.AsObject>,
|
||||
searchOutputList: Array<commands_common_pb.Platform.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +350,9 @@ export namespace PlatformListReq {
|
||||
|
||||
export class PlatformListResp extends jspb.Message {
|
||||
clearInstalledPlatformList(): void;
|
||||
getInstalledPlatformList(): Array<Platform>;
|
||||
setInstalledPlatformList(value: Array<Platform>): PlatformListResp;
|
||||
addInstalledPlatform(value?: Platform, index?: number): Platform;
|
||||
getInstalledPlatformList(): Array<commands_common_pb.Platform>;
|
||||
setInstalledPlatformList(value: Array<commands_common_pb.Platform>): PlatformListResp;
|
||||
addInstalledPlatform(value?: commands_common_pb.Platform, index?: number): commands_common_pb.Platform;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
@@ -367,86 +367,6 @@ export class PlatformListResp extends jspb.Message {
|
||||
|
||||
export namespace PlatformListResp {
|
||||
export type AsObject = {
|
||||
installedPlatformList: Array<Platform.AsObject>,
|
||||
}
|
||||
}
|
||||
|
||||
export class Platform extends jspb.Message {
|
||||
getId(): string;
|
||||
setId(value: string): Platform;
|
||||
|
||||
getInstalled(): string;
|
||||
setInstalled(value: string): Platform;
|
||||
|
||||
getLatest(): string;
|
||||
setLatest(value: string): Platform;
|
||||
|
||||
getName(): string;
|
||||
setName(value: string): Platform;
|
||||
|
||||
getMaintainer(): string;
|
||||
setMaintainer(value: string): Platform;
|
||||
|
||||
getWebsite(): string;
|
||||
setWebsite(value: string): Platform;
|
||||
|
||||
getEmail(): string;
|
||||
setEmail(value: string): Platform;
|
||||
|
||||
clearBoardsList(): void;
|
||||
getBoardsList(): Array<Board>;
|
||||
setBoardsList(value: Array<Board>): Platform;
|
||||
addBoards(value?: Board, index?: number): Board;
|
||||
|
||||
getManuallyinstalled(): boolean;
|
||||
setManuallyinstalled(value: boolean): Platform;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Platform.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Platform): Platform.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Platform, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Platform;
|
||||
static deserializeBinaryFromReader(message: Platform, reader: jspb.BinaryReader): Platform;
|
||||
}
|
||||
|
||||
export namespace Platform {
|
||||
export type AsObject = {
|
||||
id: string,
|
||||
installed: string,
|
||||
latest: string,
|
||||
name: string,
|
||||
maintainer: string,
|
||||
website: string,
|
||||
email: string,
|
||||
boardsList: Array<Board.AsObject>,
|
||||
manuallyinstalled: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export class Board extends jspb.Message {
|
||||
getName(): string;
|
||||
setName(value: string): Board;
|
||||
|
||||
getFqbn(): string;
|
||||
setFqbn(value: string): Board;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Board.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: Board): Board.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: Board, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): Board;
|
||||
static deserializeBinaryFromReader(message: Board, reader: jspb.BinaryReader): Board;
|
||||
}
|
||||
|
||||
export namespace Board {
|
||||
export type AsObject = {
|
||||
name: string,
|
||||
fqbn: string,
|
||||
installedPlatformList: Array<commands_common_pb.Platform.AsObject>,
|
||||
}
|
||||
}
|
||||
|
@@ -16,8 +16,6 @@ var global = Function('return this')();
|
||||
|
||||
var commands_common_pb = require('../commands/common_pb.js');
|
||||
goog.object.extend(proto, commands_common_pb);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Board', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.Platform', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.PlatformDownloadReq', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.PlatformDownloadResp', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.PlatformInstallReq', null, global);
|
||||
@@ -282,48 +280,6 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.PlatformListResp.displayName = 'proto.cc.arduino.cli.commands.PlatformListResp';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, proto.cc.arduino.cli.commands.Platform.repeatedFields_, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.Platform, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.displayName = 'proto.cc.arduino.cli.commands.Platform';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.Board, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.displayName = 'proto.cc.arduino.cli.commands.Board';
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2245,7 +2201,7 @@ proto.cc.arduino.cli.commands.PlatformSearchResp.prototype.toObject = function(o
|
||||
proto.cc.arduino.cli.commands.PlatformSearchResp.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
searchOutputList: jspb.Message.toObjectList(msg.getSearchOutputList(),
|
||||
proto.cc.arduino.cli.commands.Platform.toObject, includeInstance)
|
||||
commands_common_pb.Platform.toObject, includeInstance)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -2283,8 +2239,8 @@ proto.cc.arduino.cli.commands.PlatformSearchResp.deserializeBinaryFromReader = f
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = new proto.cc.arduino.cli.commands.Platform;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader);
|
||||
var value = new commands_common_pb.Platform;
|
||||
reader.readMessage(value,commands_common_pb.Platform.deserializeBinaryFromReader);
|
||||
msg.addSearchOutput(value);
|
||||
break;
|
||||
default:
|
||||
@@ -2321,7 +2277,7 @@ proto.cc.arduino.cli.commands.PlatformSearchResp.serializeBinaryToWriter = funct
|
||||
writer.writeRepeatedMessage(
|
||||
1,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter
|
||||
commands_common_pb.Platform.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -2333,7 +2289,7 @@ proto.cc.arduino.cli.commands.PlatformSearchResp.serializeBinaryToWriter = funct
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.PlatformSearchResp.prototype.getSearchOutputList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.Platform>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.Platform, 1));
|
||||
jspb.Message.getRepeatedWrapperField(this, commands_common_pb.Platform, 1));
|
||||
};
|
||||
|
||||
|
||||
@@ -2616,7 +2572,7 @@ proto.cc.arduino.cli.commands.PlatformListResp.prototype.toObject = function(opt
|
||||
proto.cc.arduino.cli.commands.PlatformListResp.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
installedPlatformList: jspb.Message.toObjectList(msg.getInstalledPlatformList(),
|
||||
proto.cc.arduino.cli.commands.Platform.toObject, includeInstance)
|
||||
commands_common_pb.Platform.toObject, includeInstance)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -2654,8 +2610,8 @@ proto.cc.arduino.cli.commands.PlatformListResp.deserializeBinaryFromReader = fun
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = new proto.cc.arduino.cli.commands.Platform;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader);
|
||||
var value = new commands_common_pb.Platform;
|
||||
reader.readMessage(value,commands_common_pb.Platform.deserializeBinaryFromReader);
|
||||
msg.addInstalledPlatform(value);
|
||||
break;
|
||||
default:
|
||||
@@ -2692,7 +2648,7 @@ proto.cc.arduino.cli.commands.PlatformListResp.serializeBinaryToWriter = functio
|
||||
writer.writeRepeatedMessage(
|
||||
1,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter
|
||||
commands_common_pb.Platform.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -2704,7 +2660,7 @@ proto.cc.arduino.cli.commands.PlatformListResp.serializeBinaryToWriter = functio
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.PlatformListResp.prototype.getInstalledPlatformList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.Platform>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.Platform, 1));
|
||||
jspb.Message.getRepeatedWrapperField(this, commands_common_pb.Platform, 1));
|
||||
};
|
||||
|
||||
|
||||
@@ -2736,564 +2692,4 @@ proto.cc.arduino.cli.commands.PlatformListResp.prototype.clearInstalledPlatformL
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
* @private {!Array<number>}
|
||||
* @const
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.repeatedFields_ = [8];
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.Platform.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
installed: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
latest: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
name: jspb.Message.getFieldWithDefault(msg, 4, ""),
|
||||
maintainer: jspb.Message.getFieldWithDefault(msg, 5, ""),
|
||||
website: jspb.Message.getFieldWithDefault(msg, 6, ""),
|
||||
email: jspb.Message.getFieldWithDefault(msg, 7, ""),
|
||||
boardsList: jspb.Message.toObjectList(msg.getBoardsList(),
|
||||
proto.cc.arduino.cli.commands.Board.toObject, includeInstance),
|
||||
manuallyinstalled: jspb.Message.getBooleanFieldWithDefault(msg, 9, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.Platform;
|
||||
return proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setId(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setInstalled(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setLatest(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setName(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMaintainer(value);
|
||||
break;
|
||||
case 6:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setWebsite(value);
|
||||
break;
|
||||
case 7:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setEmail(value);
|
||||
break;
|
||||
case 8:
|
||||
var value = new proto.cc.arduino.cli.commands.Board;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader);
|
||||
msg.addBoards(value);
|
||||
break;
|
||||
case 9:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setManuallyinstalled(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.Platform} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getId();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getInstalled();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getLatest();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getName();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getMaintainer();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getWebsite();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
6,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getEmail();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
7,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getBoardsList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedMessage(
|
||||
8,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getManuallyinstalled();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
9,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string ID = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getId = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setId = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Installed = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getInstalled = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setInstalled = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Latest = 3;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getLatest = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setLatest = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Name = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getName = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setName = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Maintainer = 5;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getMaintainer = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setMaintainer = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 5, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Website = 6;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getWebsite = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setWebsite = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 6, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string Email = 7;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getEmail = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setEmail = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 7, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated Board Boards = 8;
|
||||
* @return {!Array<!proto.cc.arduino.cli.commands.Board>}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getBoardsList = function() {
|
||||
return /** @type{!Array<!proto.cc.arduino.cli.commands.Board>} */ (
|
||||
jspb.Message.getRepeatedWrapperField(this, proto.cc.arduino.cli.commands.Board, 8));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<!proto.cc.arduino.cli.commands.Board>} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setBoardsList = function(value) {
|
||||
return jspb.Message.setRepeatedWrapperField(this, 8, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.cc.arduino.cli.commands.Board=} opt_value
|
||||
* @param {number=} opt_index
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.addBoards = function(opt_value, opt_index) {
|
||||
return jspb.Message.addToRepeatedWrapperField(this, 8, opt_value, proto.cc.arduino.cli.commands.Board, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.clearBoardsList = function() {
|
||||
return this.setBoardsList([]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool ManuallyInstalled = 9;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.getManuallyinstalled = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 9, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Platform} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Platform.prototype.setManuallyinstalled = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 9, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.Board.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
name: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
fqbn: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.Board;
|
||||
return proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.Board}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setName(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setFqbn(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.Board} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getName();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getFqbn();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string name = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.getName = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Board} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.setName = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string fqbn = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.getFqbn = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Board} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Board.prototype.setFqbn = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.cc.arduino.cli.commands);
|
||||
|
@@ -76,6 +76,9 @@ export class LibraryInstallReq extends jspb.Message {
|
||||
getVersion(): string;
|
||||
setVersion(value: string): LibraryInstallReq;
|
||||
|
||||
getNodeps(): boolean;
|
||||
setNodeps(value: boolean): LibraryInstallReq;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): LibraryInstallReq.AsObject;
|
||||
@@ -92,6 +95,7 @@ export namespace LibraryInstallReq {
|
||||
instance?: commands_common_pb.Instance.AsObject,
|
||||
name: string,
|
||||
version: string,
|
||||
nodeps: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,6 +793,9 @@ export class ZipLibraryInstallReq extends jspb.Message {
|
||||
getPath(): string;
|
||||
setPath(value: string): ZipLibraryInstallReq;
|
||||
|
||||
getOverwrite(): boolean;
|
||||
setOverwrite(value: boolean): ZipLibraryInstallReq;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): ZipLibraryInstallReq.AsObject;
|
||||
@@ -804,6 +811,7 @@ export namespace ZipLibraryInstallReq {
|
||||
export type AsObject = {
|
||||
instance?: commands_common_pb.Instance.AsObject,
|
||||
path: string,
|
||||
overwrite: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -841,6 +849,9 @@ export class GitLibraryInstallReq extends jspb.Message {
|
||||
getUrl(): string;
|
||||
setUrl(value: string): GitLibraryInstallReq;
|
||||
|
||||
getOverwrite(): boolean;
|
||||
setOverwrite(value: boolean): GitLibraryInstallReq;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): GitLibraryInstallReq.AsObject;
|
||||
@@ -856,6 +867,7 @@ export namespace GitLibraryInstallReq {
|
||||
export type AsObject = {
|
||||
instance?: commands_common_pb.Instance.AsObject,
|
||||
url: string,
|
||||
overwrite: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -965,7 +965,8 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.toObject = function(includeInsta
|
||||
var f, obj = {
|
||||
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
||||
name: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
version: jspb.Message.getFieldWithDefault(msg, 3, "")
|
||||
version: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
nodeps: jspb.Message.getBooleanFieldWithDefault(msg, 4, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -1015,6 +1016,10 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.deserializeBinaryFromReader = fu
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setVersion(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setNodeps(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -1066,6 +1071,13 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.serializeBinaryToWriter = functi
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getNodeps();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1142,6 +1154,24 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.setVersion = function(
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool noDeps = 4;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.getNodeps = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.LibraryInstallReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.setNodeps = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5848,7 +5878,8 @@ proto.cc.arduino.cli.commands.ZipLibraryInstallReq.prototype.toObject = function
|
||||
proto.cc.arduino.cli.commands.ZipLibraryInstallReq.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
||||
path: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
path: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
overwrite: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -5894,6 +5925,10 @@ proto.cc.arduino.cli.commands.ZipLibraryInstallReq.deserializeBinaryFromReader =
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setPath(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setOverwrite(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -5938,6 +5973,13 @@ proto.cc.arduino.cli.commands.ZipLibraryInstallReq.serializeBinaryToWriter = fun
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getOverwrite();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5996,6 +6038,24 @@ proto.cc.arduino.cli.commands.ZipLibraryInstallReq.prototype.setPath = function(
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool overwrite = 3;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.ZipLibraryInstallReq.prototype.getOverwrite = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.ZipLibraryInstallReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.ZipLibraryInstallReq.prototype.setOverwrite = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6180,7 +6240,8 @@ proto.cc.arduino.cli.commands.GitLibraryInstallReq.prototype.toObject = function
|
||||
proto.cc.arduino.cli.commands.GitLibraryInstallReq.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
||||
url: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
url: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
overwrite: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -6226,6 +6287,10 @@ proto.cc.arduino.cli.commands.GitLibraryInstallReq.deserializeBinaryFromReader =
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setUrl(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setOverwrite(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -6270,6 +6335,13 @@ proto.cc.arduino.cli.commands.GitLibraryInstallReq.serializeBinaryToWriter = fun
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getOverwrite();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6328,6 +6400,24 @@ proto.cc.arduino.cli.commands.GitLibraryInstallReq.prototype.setUrl = function(v
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool overwrite = 3;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.GitLibraryInstallReq.prototype.getOverwrite = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.GitLibraryInstallReq} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.GitLibraryInstallReq.prototype.setOverwrite = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -54,7 +54,7 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
|
||||
|
||||
const instance = initResp.getInstance();
|
||||
if (!instance) {
|
||||
throw new Error(`Could not retrieve instance from the initialize response.`);
|
||||
throw new Error('Could not retrieve instance from the initialize response.');
|
||||
}
|
||||
|
||||
// No `await`. The index update event comes later. This way we do not block app startup with index update when invalid proxy is given.
|
||||
@@ -167,3 +167,30 @@ export namespace CoreClientProvider {
|
||||
readonly instance: Instance;
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export abstract class CoreClientAware {
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
protected async coreClient(): Promise<CoreClientProvider.Client> {
|
||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
toDispose.dispose();
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
return coreClient;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { relative } from 'path';
|
||||
import * as jspb from 'google-protobuf';
|
||||
import { CoreService } from '../common/protocol/core-service';
|
||||
import { CompilerWarnings, CoreService } from '../common/protocol/core-service';
|
||||
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { CoreClientAware } from './core-client-provider';
|
||||
import { UploadReq, UploadResp, BurnBootloaderReq, BurnBootloaderResp, UploadUsingProgrammerReq, UploadUsingProgrammerResp } from './cli-protocol/commands/upload_pb';
|
||||
import { OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationServiceServer } from '../common/protocol';
|
||||
@@ -14,10 +14,7 @@ import { firstToUpperCase, firstToLowerCase } from '../common/utils';
|
||||
import { BoolValue } from 'google-protobuf/google/protobuf/wrappers_pb';
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceImpl implements CoreService {
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
@@ -25,31 +22,34 @@ export class CoreServiceImpl implements CoreService {
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
async compile(options: CoreService.Compile.Options & { exportBinaries?: boolean }): Promise<void> {
|
||||
const { sketchUri, fqbn } = options;
|
||||
async compile(options: CoreService.Compile.Options & { exportBinaries?: boolean, compilerWarnings?: CompilerWarnings }): Promise<void> {
|
||||
const { sketchUri, fqbn, compilerWarnings } = options;
|
||||
const sketchPath = FileUri.fsPath(sketchUri);
|
||||
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
|
||||
const compilerReq = new CompileReq();
|
||||
compilerReq.setInstance(instance);
|
||||
compilerReq.setSketchpath(sketchPath);
|
||||
const compileReq = new CompileReq();
|
||||
compileReq.setInstance(instance);
|
||||
compileReq.setSketchpath(sketchPath);
|
||||
if (fqbn) {
|
||||
compilerReq.setFqbn(fqbn);
|
||||
compileReq.setFqbn(fqbn);
|
||||
}
|
||||
compilerReq.setOptimizefordebug(options.optimizeForDebug);
|
||||
compilerReq.setPreprocess(false);
|
||||
compilerReq.setVerbose(options.verbose);
|
||||
compilerReq.setQuiet(false);
|
||||
if (compilerWarnings) {
|
||||
compileReq.setWarnings(compilerWarnings.toLowerCase());
|
||||
}
|
||||
compileReq.setOptimizefordebug(options.optimizeForDebug);
|
||||
compileReq.setPreprocess(false);
|
||||
compileReq.setVerbose(options.verbose);
|
||||
compileReq.setQuiet(false);
|
||||
if (typeof options.exportBinaries === 'boolean') {
|
||||
const exportBinaries = new BoolValue();
|
||||
exportBinaries.setValue(options.exportBinaries);
|
||||
compilerReq.setExportBinaries(exportBinaries);
|
||||
compileReq.setExportBinaries(exportBinaries);
|
||||
}
|
||||
this.mergeSourceOverrides(compilerReq, options);
|
||||
this.mergeSourceOverrides(compileReq, options);
|
||||
|
||||
const result = client.compile(compilerReq);
|
||||
const result = client.compile(compileReq);
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
result.on('data', (cr: CompileResp) => {
|
||||
@@ -152,25 +152,6 @@ export class CoreServiceImpl implements CoreService {
|
||||
}
|
||||
}
|
||||
|
||||
private async coreClient(): Promise<CoreClientProvider.Client> {
|
||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
toDispose.dispose();
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
return coreClient;
|
||||
}
|
||||
|
||||
private mergeSourceOverrides(req: { getSourceOverrideMap(): jspb.Map<string, string> }, options: CoreService.Compile.Options): void {
|
||||
const sketchPath = FileUri.fsPath(options.sketchUri);
|
||||
for (const uri of Object.keys(options.sourceOverride)) {
|
||||
|
@@ -4,9 +4,9 @@ import * as fs from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { Sketch } from '../common/protocol/sketches-service';
|
||||
import { Sketch, SketchContainer } from '../common/protocol/sketches-service';
|
||||
import { SketchesServiceImpl } from './sketches-service-impl';
|
||||
import { ExamplesService, ExampleContainer } from '../common/protocol/examples-service';
|
||||
import { ExamplesService } from '../common/protocol/examples-service';
|
||||
import { LibraryLocation, LibraryPackage, LibraryService } from '../common/protocol';
|
||||
import { ConfigServiceImpl } from './config-service-impl';
|
||||
|
||||
@@ -22,14 +22,14 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
@inject(ConfigServiceImpl)
|
||||
protected readonly configService: ConfigServiceImpl;
|
||||
|
||||
protected _all: ExampleContainer[] | undefined;
|
||||
protected _all: SketchContainer[] | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.builtIns();
|
||||
}
|
||||
|
||||
async builtIns(): Promise<ExampleContainer[]> {
|
||||
async builtIns(): Promise<SketchContainer[]> {
|
||||
if (this._all) {
|
||||
return this._all;
|
||||
}
|
||||
@@ -40,10 +40,10 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
}
|
||||
|
||||
// TODO: decide whether it makes sense to cache them. Keys should be: `fqbn` + version of containing core/library.
|
||||
async installed({ fqbn }: { fqbn: string }): Promise<{ user: ExampleContainer[], current: ExampleContainer[], any: ExampleContainer[] }> {
|
||||
const user: ExampleContainer[] = [];
|
||||
const current: ExampleContainer[] = [];
|
||||
const any: ExampleContainer[] = [];
|
||||
async installed({ fqbn }: { fqbn: string }): Promise<{ user: SketchContainer[], current: SketchContainer[], any: SketchContainer[] }> {
|
||||
const user: SketchContainer[] = [];
|
||||
const current: SketchContainer[] = [];
|
||||
const any: SketchContainer[] = [];
|
||||
if (fqbn) {
|
||||
const packages: LibraryPackage[] = await this.libraryService.list({ fqbn });
|
||||
for (const pkg of packages) {
|
||||
@@ -66,7 +66,7 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
* folder hierarchy. This method tries to workaround it by falling back to the `installDirUri` and manually creating the
|
||||
* location of the examples. Otherwise it creates the example container from the direct examples FS paths.
|
||||
*/
|
||||
protected async tryGroupExamples({ label, exampleUris, installDirUri }: LibraryPackage): Promise<ExampleContainer> {
|
||||
protected async tryGroupExamples({ label, exampleUris, installDirUri }: LibraryPackage): Promise<SketchContainer> {
|
||||
const paths = exampleUris.map(uri => FileUri.fsPath(uri));
|
||||
if (installDirUri) {
|
||||
for (const example of ['example', 'Example', 'EXAMPLE', 'examples', 'Examples', 'EXAMPLES']) {
|
||||
@@ -75,7 +75,7 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
const isDir = exists && (await promisify(fs.lstat)(examplesPath)).isDirectory();
|
||||
if (isDir) {
|
||||
const fileNames = await promisify(fs.readdir)(examplesPath);
|
||||
const children: ExampleContainer[] = [];
|
||||
const children: SketchContainer[] = [];
|
||||
const sketches: Sketch[] = [];
|
||||
for (const fileName of fileNames) {
|
||||
const subPath = join(examplesPath, fileName);
|
||||
@@ -109,7 +109,7 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
}
|
||||
|
||||
// Built-ins are included inside the IDE.
|
||||
protected async load(path: string): Promise<ExampleContainer> {
|
||||
protected async load(path: string): Promise<SketchContainer> {
|
||||
if (!await promisify(fs.exists)(path)) {
|
||||
throw new Error('Examples are not available');
|
||||
}
|
||||
@@ -119,7 +119,7 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
}
|
||||
const names = await promisify(fs.readdir)(path);
|
||||
const sketches: Sketch[] = [];
|
||||
const children: ExampleContainer[] = [];
|
||||
const children: SketchContainer[] = [];
|
||||
for (const p of names.map(name => join(path, name))) {
|
||||
const stat = await promisify(fs.stat)(p);
|
||||
if (stat.isDirectory()) {
|
||||
|
@@ -59,7 +59,7 @@ export abstract class GrpcClientProvider<C> {
|
||||
const client = await this.createClient(this._port);
|
||||
this._client = client;
|
||||
} catch (error) {
|
||||
this.logger.error('Could create client for gRPC.', error)
|
||||
this.logger.error('Could not create client for gRPC.', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { injectable, inject, postConstruct } from 'inversify';
|
||||
import { LibraryPackage, LibraryService } from '../common/protocol/library-service';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { LibraryDependency, LibraryPackage, LibraryService } from '../common/protocol/library-service';
|
||||
import { CoreClientAware } from './core-client-provider';
|
||||
import {
|
||||
LibrarySearchReq,
|
||||
LibrarySearchResp,
|
||||
@@ -12,48 +12,31 @@ import {
|
||||
LibraryInstallResp,
|
||||
LibraryUninstallReq,
|
||||
LibraryUninstallResp,
|
||||
Library
|
||||
Library,
|
||||
LibraryResolveDependenciesReq,
|
||||
ZipLibraryInstallReq,
|
||||
ZipLibraryInstallResp
|
||||
} from './cli-protocol/commands/lib_pb';
|
||||
import { Installable } from '../common/protocol/installable';
|
||||
import { ILogger, notEmpty } from '@theia/core';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { FileUri } from '@theia/core/lib/node';
|
||||
import { OutputService, NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
|
||||
@injectable()
|
||||
export class LibraryServiceImpl implements LibraryService {
|
||||
export class LibraryServiceImpl extends CoreClientAware implements LibraryService {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationServer: NotificationServiceServer;
|
||||
|
||||
protected ready = new Deferred<void>();
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.coreClientProvider.client().then(client => {
|
||||
if (client) {
|
||||
this.ready.resolve();
|
||||
} else {
|
||||
this.coreClientProvider.onClientReady(() => this.ready.resolve());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async search(options: { query?: string }): Promise<LibraryPackage[]> {
|
||||
await this.ready.promise;
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
return [];
|
||||
}
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
|
||||
const listReq = new LibraryListReq();
|
||||
@@ -96,12 +79,7 @@ export class LibraryServiceImpl implements LibraryService {
|
||||
}
|
||||
|
||||
async list({ fqbn }: { fqbn?: string | undefined }): Promise<LibraryPackage[]> {
|
||||
await this.ready.promise;
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
const req = new LibraryListReq();
|
||||
req.setInstance(instance);
|
||||
@@ -157,20 +135,42 @@ export class LibraryServiceImpl implements LibraryService {
|
||||
}).filter(notEmpty);
|
||||
}
|
||||
|
||||
async install(options: { item: LibraryPackage, version?: Installable.Version }): Promise<void> {
|
||||
await this.ready.promise;
|
||||
async listDependencies({ item, version, filterSelf }: { item: LibraryPackage, version: Installable.Version, filterSelf?: boolean }): Promise<LibraryDependency[]> {
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
const req = new LibraryResolveDependenciesReq();
|
||||
req.setInstance(instance);
|
||||
req.setName(item.name);
|
||||
req.setVersion(version);
|
||||
const dependencies = await new Promise<LibraryDependency[]>((resolve, reject) => {
|
||||
client.libraryResolveDependencies(req, (error, resp) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(resp.getDependenciesList().map(dep => <LibraryDependency>{
|
||||
name: dep.getName(),
|
||||
installedVersion: dep.getVersioninstalled(),
|
||||
requiredVersion: dep.getVersionrequired()
|
||||
}));
|
||||
})
|
||||
});
|
||||
return filterSelf ? dependencies.filter(({ name }) => name !== item.name) : dependencies;
|
||||
}
|
||||
|
||||
async install(options: { item: LibraryPackage, version?: Installable.Version, installDependencies?: boolean }): Promise<void> {
|
||||
const item = options.item;
|
||||
const version = !!options.version ? options.version : item.availableVersions[0];
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
return;
|
||||
}
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
|
||||
const req = new LibraryInstallReq();
|
||||
req.setInstance(instance);
|
||||
req.setName(item.name);
|
||||
req.setVersion(version);
|
||||
if (options.installDependencies === false) {
|
||||
req.setNodeps(true);
|
||||
}
|
||||
|
||||
console.info('>>> Starting library package installation...', item);
|
||||
const resp = client.libraryInstall(req);
|
||||
@@ -182,7 +182,11 @@ export class LibraryServiceImpl implements LibraryService {
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
resp.on('error', error => {
|
||||
this.outputService.append({ chunk: `Failed to install library: ${item.name}${version ? `:${version}` : ''}.\n` });
|
||||
this.outputService.append({ chunk: error.toString() });
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
const items = await this.search({});
|
||||
@@ -191,12 +195,31 @@ export class LibraryServiceImpl implements LibraryService {
|
||||
console.info('<<< Library package installation done.', item);
|
||||
}
|
||||
|
||||
async installZip({ zipUri, overwrite }: { zipUri: string, overwrite?: boolean }): Promise<void> {
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
const req = new ZipLibraryInstallReq();
|
||||
req.setPath(FileUri.fsPath(zipUri));
|
||||
req.setInstance(instance);
|
||||
if (typeof overwrite === 'boolean') {
|
||||
req.setOverwrite(overwrite);
|
||||
}
|
||||
const resp = client.zipLibraryInstall(req);
|
||||
resp.on('data', (r: ZipLibraryInstallResp) => {
|
||||
const task = r.getTaskProgress();
|
||||
if (task && task.getMessage()) {
|
||||
this.outputService.append({ chunk: task.getMessage() });
|
||||
}
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
async uninstall(options: { item: LibraryPackage }): Promise<void> {
|
||||
const item = options.item;
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
return;
|
||||
}
|
||||
const coreClient = await this.coreClient();
|
||||
const { client, instance } = coreClient;
|
||||
|
||||
const req = new LibraryUninstallReq();
|
||||
|
@@ -2,6 +2,7 @@ import { ClientDuplexStream } from '@grpc/grpc-js';
|
||||
import { TextDecoder, TextEncoder } from 'util';
|
||||
import { injectable, inject, named } from 'inversify';
|
||||
import { Struct } from 'google-protobuf/google/protobuf/struct_pb';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { MonitorService, MonitorServiceClient, MonitorConfig, MonitorError, Status } from '../../common/protocol/monitor-service';
|
||||
import { StreamingOpenReq, StreamingOpenResp, MonitorConfig as GrpcMonitorConfig } from '../cli-protocol/monitor/monitor_pb';
|
||||
@@ -46,6 +47,8 @@ export class MonitorServiceImpl implements MonitorService {
|
||||
|
||||
protected client?: MonitorServiceClient;
|
||||
protected connection?: { duplex: ClientDuplexStream<StreamingOpenReq, StreamingOpenResp>, config: MonitorConfig };
|
||||
protected messages: string[] = [];
|
||||
protected onMessageDidReadEmitter = new Emitter<void>();
|
||||
|
||||
setClient(client: MonitorServiceClient | undefined): void {
|
||||
this.client = client;
|
||||
@@ -86,11 +89,10 @@ export class MonitorServiceImpl implements MonitorService {
|
||||
}).bind(this));
|
||||
|
||||
duplex.on('data', ((resp: StreamingOpenResp) => {
|
||||
if (this.client) {
|
||||
const raw = resp.getData();
|
||||
const data = typeof raw === 'string' ? raw : new TextDecoder('utf8').decode(raw);
|
||||
this.client.notifyRead({ data });
|
||||
}
|
||||
const raw = resp.getData();
|
||||
const message = typeof raw === 'string' ? raw : new TextDecoder('utf8').decode(raw);
|
||||
this.messages.push(message);
|
||||
this.onMessageDidReadEmitter.fire();
|
||||
}).bind(this));
|
||||
|
||||
const { type, port } = config;
|
||||
@@ -116,27 +118,31 @@ export class MonitorServiceImpl implements MonitorService {
|
||||
}
|
||||
|
||||
async disconnect(reason?: MonitorError): Promise<Status> {
|
||||
if (!this.connection && reason && reason.code === MonitorError.ErrorCodes.CLIENT_CANCEL) {
|
||||
try {
|
||||
if (!this.connection && reason && reason.code === MonitorError.ErrorCodes.CLIENT_CANCEL) {
|
||||
return Status.OK;
|
||||
}
|
||||
this.logger.info('>>> Disposing monitor connection...');
|
||||
if (!this.connection) {
|
||||
this.logger.warn('<<< Not connected. Nothing to dispose.');
|
||||
return Status.NOT_CONNECTED;
|
||||
}
|
||||
const { duplex, config } = this.connection;
|
||||
duplex.cancel();
|
||||
this.logger.info(`<<< Disposed monitor connection for ${Board.toString(config.board, { useFqbn: false })} on port ${Port.toString(config.port)}.`);
|
||||
this.connection = undefined;
|
||||
return Status.OK;
|
||||
} finally {
|
||||
this.messages.length = 0;
|
||||
}
|
||||
this.logger.info(`>>> Disposing monitor connection...`);
|
||||
if (!this.connection) {
|
||||
this.logger.warn(`<<< Not connected. Nothing to dispose.`);
|
||||
return Status.NOT_CONNECTED;
|
||||
}
|
||||
const { duplex, config } = this.connection;
|
||||
duplex.cancel();
|
||||
this.logger.info(`<<< Disposed monitor connection for ${Board.toString(config.board, { useFqbn: false })} on port ${Port.toString(config.port)}.`);
|
||||
this.connection = undefined;
|
||||
return Status.OK;
|
||||
}
|
||||
|
||||
async send(data: string): Promise<Status> {
|
||||
async send(message: string): Promise<Status> {
|
||||
if (!this.connection) {
|
||||
return Status.NOT_CONNECTED;
|
||||
}
|
||||
const req = new StreamingOpenReq();
|
||||
req.setData(new TextEncoder().encode(data));
|
||||
req.setData(new TextEncoder().encode(message));
|
||||
return new Promise<Status>(resolve => {
|
||||
if (this.connection) {
|
||||
this.connection.duplex.write(req, () => {
|
||||
@@ -148,6 +154,19 @@ export class MonitorServiceImpl implements MonitorService {
|
||||
});
|
||||
}
|
||||
|
||||
async request(): Promise<{ message: string }> {
|
||||
const message = this.messages.shift();
|
||||
if (message) {
|
||||
return { message };
|
||||
}
|
||||
return new Promise<{ message: string }>(resolve => {
|
||||
const toDispose = this.onMessageDidReadEmitter.event(() => {
|
||||
toDispose.dispose();
|
||||
resolve(this.request());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected mapType(type?: MonitorConfig.ConnectionType): GrpcMonitorConfig.TargetType {
|
||||
switch (type) {
|
||||
case MonitorConfig.ConnectionType.SERIAL: return GrpcMonitorConfig.TargetType.SERIAL;
|
||||
|
@@ -53,7 +53,7 @@ export class NotificationServiceServerImpl implements NotificationServiceServer
|
||||
disposeClient(client: NotificationServiceClient): void {
|
||||
const index = this.clients.indexOf(client);
|
||||
if (index === -1) {
|
||||
console.warn(`Could not dispose notification service client. It was not registered.`);
|
||||
console.warn('Could not dispose notification service client. It was not registered.');
|
||||
return;
|
||||
}
|
||||
this.clients.splice(index, 1);
|
||||
|
@@ -1,19 +1,21 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import * as minimatch from 'minimatch';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as temp from 'temp';
|
||||
import * as path from 'path';
|
||||
import * as crypto from 'crypto';
|
||||
import { ncp } from 'ncp';
|
||||
import { promisify } from 'util';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { FileUri } from '@theia/core/lib/node';
|
||||
import { isWindows } from '@theia/core/lib/common/os';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { SketchesService, Sketch } from '../common/protocol/sketches-service';
|
||||
import { SketchesService, Sketch, SketchContainer } from '../common/protocol/sketches-service';
|
||||
import { firstToLowerCase } from '../common/utils';
|
||||
import { NotificationServiceServerImpl } from './notification-service-server';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { CoreClientAware } from './core-client-provider';
|
||||
import { LoadSketchReq, ArchiveSketchReq } from './cli-protocol/commands/commands_pb';
|
||||
|
||||
const WIN32_DRIVE_REGEXP = /^[a-zA-Z]:\\/;
|
||||
@@ -21,21 +23,18 @@ const WIN32_DRIVE_REGEXP = /^[a-zA-Z]:\\/;
|
||||
const prefix = '.arduinoIDE-unsaved';
|
||||
|
||||
@injectable()
|
||||
export class SketchesServiceImpl implements SketchesService {
|
||||
export class SketchesServiceImpl extends CoreClientAware implements SketchesService {
|
||||
|
||||
@inject(ConfigService)
|
||||
protected readonly configService: ConfigService;
|
||||
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(NotificationServiceServerImpl)
|
||||
protected readonly notificationService: NotificationServiceServerImpl;
|
||||
|
||||
@inject(EnvVariablesServer)
|
||||
protected readonly envVariableServer: EnvVariablesServer;
|
||||
|
||||
async getSketches(uri?: string): Promise<SketchWithDetails[]> {
|
||||
async getSketches({ uri, exclude }: { uri?: string, exclude?: string[] }): Promise<SketchContainerWithDetails> {
|
||||
const start = Date.now();
|
||||
let sketchbookPath: undefined | string;
|
||||
if (!uri) {
|
||||
const { sketchDirUri } = await this.configService.getConfiguration();
|
||||
@@ -46,33 +45,65 @@ export class SketchesServiceImpl implements SketchesService {
|
||||
} else {
|
||||
sketchbookPath = FileUri.fsPath(uri);
|
||||
}
|
||||
const container: SketchContainerWithDetails = {
|
||||
label: uri ? path.basename(sketchbookPath) : 'Sketchbook',
|
||||
sketches: [],
|
||||
children: []
|
||||
};
|
||||
if (!await promisify(fs.exists)(sketchbookPath)) {
|
||||
return [];
|
||||
return container;
|
||||
}
|
||||
const stat = await promisify(fs.stat)(sketchbookPath);
|
||||
if (!stat.isDirectory()) {
|
||||
return [];
|
||||
return container;
|
||||
}
|
||||
|
||||
const sketches: Array<SketchWithDetails> = [];
|
||||
const filenames = await promisify(fs.readdir)(sketchbookPath);
|
||||
for (const fileName of filenames) {
|
||||
const filePath = path.join(sketchbookPath, fileName);
|
||||
const sketch = await this._isSketchFolder(FileUri.create(filePath).toString());
|
||||
if (sketch) {
|
||||
const recursivelyLoad = async (fsPath: string, containerToLoad: SketchContainerWithDetails) => {
|
||||
const filenames = await promisify(fs.readdir)(fsPath);
|
||||
for (const name of filenames) {
|
||||
const childFsPath = path.join(fsPath, name);
|
||||
let skip = false;
|
||||
for (const pattern of exclude || ['**/libraries/**', '**/hardware/**']) {
|
||||
if (!skip && minimatch(childFsPath, pattern)) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const stat = await promisify(fs.stat)(filePath);
|
||||
sketches.push({
|
||||
...sketch,
|
||||
mtimeMs: stat.mtimeMs
|
||||
});
|
||||
const stat = await promisify(fs.stat)(childFsPath);
|
||||
if (stat.isDirectory()) {
|
||||
const sketch = await this._isSketchFolder(FileUri.create(childFsPath).toString());
|
||||
if (sketch) {
|
||||
containerToLoad.sketches.push({
|
||||
...sketch,
|
||||
mtimeMs: stat.mtimeMs
|
||||
});
|
||||
} else {
|
||||
const childContainer: SketchContainerWithDetails = {
|
||||
label: name,
|
||||
children: [],
|
||||
sketches: []
|
||||
};
|
||||
await recursivelyLoad(childFsPath, childContainer);
|
||||
if (!SketchContainer.isEmpty(childContainer)) {
|
||||
containerToLoad.children.push(childContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
console.warn(`Could not load sketch from ${filePath}.`);
|
||||
console.warn(`Could not load sketch from ${childFsPath}.`);
|
||||
}
|
||||
}
|
||||
containerToLoad.sketches.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
||||
return containerToLoad;
|
||||
}
|
||||
sketches.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
||||
return sketches;
|
||||
|
||||
await recursivelyLoad(sketchbookPath, container);
|
||||
SketchContainer.prune(container);
|
||||
console.debug(`Loading the sketches from ${sketchbookPath} took ${Date.now() - start} ms.`);
|
||||
return container;
|
||||
}
|
||||
|
||||
async loadSketch(uri: string): Promise<SketchWithDetails> {
|
||||
@@ -301,27 +332,47 @@ void loop() {
|
||||
await this.loadSketch(sketch.uri); // Sanity check.
|
||||
return sketch.uri;
|
||||
}
|
||||
|
||||
const copy = async (sourcePath: string, destinationPath: string) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
ncp.ncp(sourcePath, destinationPath, async error => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
const newName = path.basename(destinationPath);
|
||||
try {
|
||||
const oldPath = path.join(destinationPath, new URI(sketch.mainFileUri).path.base);
|
||||
const newPath = path.join(destinationPath, `${newName}.ino`);
|
||||
if (oldPath !== newPath) {
|
||||
await promisify(fs.rename)(oldPath, newPath);
|
||||
}
|
||||
await this.loadSketch(FileUri.create(destinationPath).toString()); // Sanity check.
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// https://github.com/arduino/arduino-ide/issues/65
|
||||
// When copying `/path/to/sketchbook/sketch_A` to `/path/to/sketchbook/sketch_A/anything` on a non-POSIX filesystem,
|
||||
// `ncp` makes a recursion and copies the folders over and over again. In such cases, we copy the source into a temp folder,
|
||||
// then move it to the desired destination.
|
||||
const destination = FileUri.fsPath(destinationUri);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
ncp.ncp(source, destination, async error => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
let tempDestination = await new Promise<string>((resolve, reject) => {
|
||||
temp.track().mkdir({ prefix }, async (err, dirPath) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
const newName = path.basename(destination);
|
||||
try {
|
||||
const oldPath = path.join(destination, new URI(sketch.mainFileUri).path.base);
|
||||
const newPath = path.join(destination, `${newName}.ino`);
|
||||
if (oldPath !== newPath) {
|
||||
await promisify(fs.rename)(oldPath, newPath);
|
||||
}
|
||||
await this.loadSketch(destinationUri); // Sanity check.
|
||||
resolve();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
resolve(dirPath);
|
||||
});
|
||||
});
|
||||
tempDestination = path.join(tempDestination, sketch.name);
|
||||
await fs.promises.mkdir(tempDestination, { recursive: true });
|
||||
await copy(source, tempDestination);
|
||||
await copy(tempDestination, destination);
|
||||
return FileUri.create(destination).toString();
|
||||
}
|
||||
|
||||
@@ -348,23 +399,16 @@ void loop() {
|
||||
return destinationUri;
|
||||
}
|
||||
|
||||
private async coreClient(): Promise<CoreClientProvider.Client> {
|
||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
||||
const client = await this.coreClientProvider.client();
|
||||
if (client) {
|
||||
toDispose.dispose();
|
||||
resolve(client);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
return coreClient;
|
||||
async getIdeTempFolderUri(sketch: Sketch): Promise<string> {
|
||||
const genBuildPath = await this.getIdeTempFolderPath(sketch);
|
||||
return FileUri.create(genBuildPath).toString();
|
||||
}
|
||||
|
||||
async getIdeTempFolderPath(sketch: Sketch): Promise<string> {
|
||||
const sketchPath = FileUri.fsPath(sketch.uri);
|
||||
await fs.promises.readdir(sketchPath); // Validates the sketch folder and rejects if not accessible.
|
||||
const suffix = crypto.createHash('md5').update(sketchPath).digest('hex');
|
||||
return path.join(os.tmpdir(), `arduino-ide2-${suffix}`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -372,3 +416,8 @@ void loop() {
|
||||
interface SketchWithDetails extends Sketch {
|
||||
readonly mtimeMs: number;
|
||||
}
|
||||
interface SketchContainerWithDetails extends SketchContainer {
|
||||
readonly label: string;
|
||||
readonly children: SketchContainerWithDetails[];
|
||||
readonly sketches: SketchWithDetails[];
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [true, "single", "jsx-single", "avoid-escape", "avoid-template"],
|
||||
"radix": true,
|
||||
"trailing-comma": [false],
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
@@ -34,4 +35,4 @@
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "browser-app",
|
||||
"version": "2.0.0-beta.2",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-beta.4",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@theia/core": "next",
|
||||
"@theia/debug": "next",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@theia/process": "next",
|
||||
"@theia/terminal": "next",
|
||||
"@theia/workspace": "next",
|
||||
"arduino-ide-extension": "2.0.0-beta.2"
|
||||
"arduino-ide-extension": "2.0.0-beta.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "next"
|
||||
@@ -37,7 +37,12 @@
|
||||
"editor.autoSave": "on",
|
||||
"editor.minimap.enabled": false,
|
||||
"editor.tabSize": 2,
|
||||
"editor.scrollBeyondLastLine": false
|
||||
"editor.scrollBeyondLastLine": false,
|
||||
"editor.quickSuggestions": {
|
||||
"other": false,
|
||||
"comments": false,
|
||||
"strings": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "electron-app",
|
||||
"version": "2.0.0-beta.2",
|
||||
"license": "MIT",
|
||||
"version": "2.0.0-beta.4",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "src-gen/frontend/electron-main.js",
|
||||
"dependencies": {
|
||||
"@theia/core": "next",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@theia/process": "next",
|
||||
"@theia/terminal": "next",
|
||||
"@theia/workspace": "next",
|
||||
"arduino-ide-extension": "2.0.0-beta.2"
|
||||
"arduino-ide-extension": "2.0.0-beta.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "next"
|
||||
@@ -40,7 +40,12 @@
|
||||
"editor.autoSave": "on",
|
||||
"editor.minimap.enabled": false,
|
||||
"editor.tabSize": 2,
|
||||
"editor.scrollBeyondLastLine": false
|
||||
"editor.scrollBeyondLastLine": false,
|
||||
"editor.quickSuggestions": {
|
||||
"other": false,
|
||||
"comments": false,
|
||||
"strings": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 72 KiB |
@@ -6,6 +6,10 @@ exports.default = async function notarizing(context) {
|
||||
console.log('Skipping notarization: not on CI.');
|
||||
return;
|
||||
}
|
||||
if (process.env.IS_FORK === 'true') {
|
||||
console.log('Skipping the app notarization: building from a fork.');
|
||||
return;
|
||||
}
|
||||
const { electronPlatformName, appOutDir } = context;
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return;
|
||||
|
@@ -137,7 +137,7 @@
|
||||
"theiaPluginsDir": "plugins",
|
||||
"theiaPlugins": {
|
||||
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
|
||||
"vscode-arduino-language-server": "https://downloads.arduino.cc/vscode-arduino-language-server/nightly/vscode-arduino-language-server-0.0.1.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/nightly/vscode-arduino-tools-0.0.1-beta.1.vsix",
|
||||
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
|
||||
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",
|
||||
"cortex-debug": "https://open-vsx.org/api/marus25/cortex-debug/0.3.7/file/marus25.cortex-debug-0.3.7.vsix"
|
||||
|
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Arduino SA",
|
||||
"license": "MIT",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@types/file-type": "^10.9.1",
|
||||
"@types/temp": "^0.8.32",
|
||||
|
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "arduino-editor",
|
||||
"version": "2.0.0-beta.2",
|
||||
"version": "2.0.0-beta.4",
|
||||
"description": "Arduino IDE",
|
||||
"repository": "https://github.com/bcmi-labs/arduino-editor.git",
|
||||
"author": "Arduino SA",
|
||||
"license": "MIT",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=12.14.1 <13"
|
||||
@@ -36,7 +36,7 @@
|
||||
"theiaPluginsDir": "plugins",
|
||||
"theiaPlugins": {
|
||||
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
|
||||
"vscode-arduino-language-server": "https://downloads.arduino.cc/vscode-arduino-language-server/nightly/vscode-arduino-language-server-0.0.1.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/nightly/vscode-arduino-tools-0.0.1-beta.1.vsix",
|
||||
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
|
||||
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",
|
||||
"cortex-debug": "https://open-vsx.org/api/marus25/cortex-debug/0.3.7/file/marus25.cortex-debug-0.3.7.vsix"
|
||||
|
Before Width: | Height: | Size: 333 KiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
static/screenshot.png
Normal file
After Width: | Height: | Size: 658 KiB |
12
yarn.lock
@@ -3804,6 +3804,13 @@ async-limiter@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
|
||||
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
|
||||
|
||||
async-mutex@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.3.0.tgz#5bc765c271dfc05c48040c12032a92f1dbef2dc3"
|
||||
integrity sha512-6VIpUM7s37EMXvnO3TvujgaS6gx4yJby13BhxovMYSap7nrbS0gJ1UzGcjD+HElNSdTz/+IlAIqj7H48N0ZlyQ==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
async@0.9.x:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
|
||||
@@ -14580,6 +14587,11 @@ tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tslint@^5.5.0:
|
||||
version "5.20.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
|
||||
|