Compare commits
No commits in common. "19.3.0" and "master" have entirely different histories.
512 changed files with 21337 additions and 17889 deletions
100
.gitignore
vendored
100
.gitignore
vendored
|
@ -1,93 +1,5 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,java
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,gradle,java
|
||||
|
||||
### Intellij+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
.idea/artifacts
|
||||
.idea/compiler.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/modules.xml
|
||||
.idea/*.iml
|
||||
.idea/modules
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij+all Patch ###
|
||||
# Ignore everything but code style settings and run configurations
|
||||
# that are supposed to be shared within teams.
|
||||
|
||||
.idea/*
|
||||
|
||||
!.idea/codeStyles
|
||||
!.idea/runConfigurations
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/gradle,java
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=gradle,java
|
||||
|
||||
### Java ###
|
||||
# Compiled class file
|
||||
|
@ -142,9 +54,11 @@ gradle-app.setting
|
|||
# Java heap dump
|
||||
*.hprof
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,java
|
||||
# End of https://www.toptal.com/developers/gitignore/api/gradle,java
|
||||
|
||||
.idea
|
||||
.intellijPlatform
|
||||
jbr
|
||||
secrets
|
||||
.idea/runConfigurations/*.xml
|
||||
.intellijPlatform
|
||||
!**/src/**/build/
|
||||
.kotlin
|
92
.idea/codeStyles/Project.xml
generated
92
.idea/codeStyles/Project.xml
generated
|
@ -1,92 +0,0 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="ANNOTATION_PARAMETER_WRAP" value="2" />
|
||||
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="net.minecraft" withSubpackages="true" static="false" />
|
||||
<package name="net.minecraftforge" withSubpackages="true" static="false" />
|
||||
<package name="cpw" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
|
||||
<option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<ScalaCodeStyleSettings>
|
||||
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
|
||||
</ScalaCodeStyleSettings>
|
||||
<codeStyleSettings language="Glsl">
|
||||
<option name="SPACE_BEFORE_COLON" value="false" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="KEEP_LINE_BREAKS" value="false" />
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
|
||||
<option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" />
|
||||
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
|
||||
<option name="ALIGN_MULTILINE_METHOD_BRACKETS" value="true" />
|
||||
<option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" />
|
||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="RESOURCE_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="THROWS_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="ASSERT_STATEMENT_WRAP" value="1" />
|
||||
<option name="ASSERT_STATEMENT_COLON_ON_NEXT_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="5" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="2" />
|
||||
<option name="WRAP_ON_TYPING" value="0" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
|
@ -1,5 +0,0 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
319
CHANGELOG.md
319
CHANGELOG.md
|
@ -17,6 +17,323 @@ Changelog structure reference:
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [25.2.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Debugger
|
||||
- Notify the user if zig run / zig test debugging starts, but a build.zig is present
|
||||
|
||||
### Changed
|
||||
|
||||
- Project
|
||||
- Line marker task suggestions for main/test now defer to Zig Build if build.zig file is detected.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Debugger
|
||||
- Compilation failures did not open the terminal properly and suppressed the error message
|
||||
|
||||
## [25.1.0]
|
||||
|
||||
### Added
|
||||
|
||||
- IDEA 2025.1 support
|
||||
|
||||
- LSP
|
||||
- Configurable inlay hints file size limit to reduce IDE lag
|
||||
|
||||
## [25.0.2]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- ZLS settings not scrollable in the language server list
|
||||
|
||||
## [25.0.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- Zig.iml file created in every project
|
||||
|
||||
### Changed
|
||||
|
||||
- Project
|
||||
- BREAKING MAJOR UPDATE: Fully reworked toolchain and language server management
|
||||
The configuration menu is now very similar to the intellij java toolchain management,
|
||||
with proper toolchain selection, detection, downloading, etc. This change will require
|
||||
you to re-configure your toolchains!
|
||||
- Zig external library root is now no longer shown if zig is not configured
|
||||
|
||||
## [24.0.1]
|
||||
|
||||
### Added
|
||||
|
||||
- Project, Debugging
|
||||
- TTY support for zig processes
|
||||
|
||||
### Removed
|
||||
|
||||
- Project
|
||||
- "Emulate terminal" and "colored output" config options have been removed from zig run/test/build tasks, as they are no longer required for ZigBrains to work.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Debugger
|
||||
- Build errors didn't get shown in the console
|
||||
|
||||
- Project
|
||||
- File path browse buttons in zig run configurations didn't work
|
||||
- Occasional GUI deadlocks
|
||||
|
||||
- Zig
|
||||
- IPC wrapper wasn't passing exit code
|
||||
|
||||
## [23.1.2]
|
||||
|
||||
### Fixed
|
||||
|
||||
- LSP
|
||||
- IDE warning when renaming symbols
|
||||
|
||||
## [23.1.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- New project creation creates a blank ZLS config
|
||||
|
||||
## [23.1.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Project
|
||||
- Support running file main/tests with hotkey (default: ctrl+shift+f10)
|
||||
|
||||
### Changed
|
||||
|
||||
- Direnv
|
||||
- Centralized all direnv toggling into a single project-level option
|
||||
|
||||
## [23.0.2]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Documentation comment after regular comment was being highlighted as regular comment
|
||||
|
||||
## [23.0.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- mkfifo/bash for zig progress visualization is now detected more reliably (fixes error on macOS)
|
||||
- Deadlock when launching zig build tasks
|
||||
|
||||
## [23.0.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Project
|
||||
- Zig std.Progress visualization in the zig tool window (Linux/macOS only)
|
||||
|
||||
### Removed
|
||||
|
||||
- Project
|
||||
- Executable / Library new project templates temporarily removed until zig stabilizes
|
||||
|
||||
## [22.0.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- LSP
|
||||
- Changing ZLS configs would not restart ZLS
|
||||
|
||||
- Project
|
||||
- Occasional "AWT events are not allowed inside write action" error coming from LSP
|
||||
- IllegalStateException coming from the standard library handler
|
||||
|
||||
## [22.0.0]
|
||||
|
||||
### Added
|
||||
|
||||
- LSP
|
||||
- Error/Warning banner at the top of the editor when ZLS is misconfigured/not running
|
||||
- ZLS version indicator in the zig settings
|
||||
|
||||
- Toolchain
|
||||
- More descriptive error messages when toolchain detection fails
|
||||
|
||||
### Changed
|
||||
|
||||
- Project
|
||||
- !!BREAKING CHANGE!! Changed file format of zig tasks to store command line arguments as strings instead of string lists.
|
||||
This (and newer) versions of the plugin will automatically upgrade tasks from 21.1.0 and before.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Debugging
|
||||
- Breakpoints could not be placed inside zig code in Android Studio
|
||||
|
||||
- Project
|
||||
- Zig run/debug configuration command line arguments would lose quotes around arguments
|
||||
|
||||
## [21.1.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Zon
|
||||
- ZLS integration
|
||||
|
||||
### Changed
|
||||
|
||||
- Zon
|
||||
- Fully refactored the parser for parity with the zig parser
|
||||
|
||||
## [21.0.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Zig
|
||||
- Changing the zig standard library path in the project settings now properly updates the dependency
|
||||
- ZLS
|
||||
- All of the config options are now exposed in the GUI
|
||||
|
||||
### Changed
|
||||
|
||||
- Project
|
||||
- New project panel is now much more compact
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- `zig env` failure causes an IDE error
|
||||
- A local toolchain disappearing (std directory or zig exe deleted) is now handled properly
|
||||
|
||||
## [20.3.0]
|
||||
|
||||
- Zig
|
||||
- Improved default colors
|
||||
|
||||
## [20.2.2]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Debugging
|
||||
- `zig build run` would run the process twice, one without, one with debugging
|
||||
|
||||
## [20.2.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Lexer error when a zig file has a comment or multiline string at the end of file without trailing newline
|
||||
|
||||
## [20.2.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Zig
|
||||
- Live template support
|
||||
|
||||
## [20.1.3]
|
||||
|
||||
### Added
|
||||
|
||||
- Project
|
||||
- `.zig-cache` directory added to autogenerated gitignore in the project generator
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- Zig Build tool window crashes when opening remote projects
|
||||
|
||||
## [20.1.2]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Source file path highlighter made the terminal lag with some files
|
||||
- Non-terminating rule in lexer could make the editor hang
|
||||
|
||||
## [20.1.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Unterminated string at the end of the file soft-locks the editor
|
||||
- Trailing commas in for loop parameters don't get parsed correctly
|
||||
|
||||
## [20.1.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Zig
|
||||
- String, character literal, and `@"identifier"` quote matching
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zon
|
||||
- Broken string quote handling
|
||||
|
||||
## [20.0.4]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Renamed Zig new file task to "Zig File" and moved to the file creation group
|
||||
|
||||
## [20.0.3]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- "Save all documents" hanging when trying to run a zig file
|
||||
|
||||
## [20.0.2]
|
||||
|
||||
### Added
|
||||
|
||||
- Zig
|
||||
- Escape sequence highlighting in char literals
|
||||
|
||||
### Changed
|
||||
|
||||
- Project
|
||||
- Direnv now only runs automatically in trusted projects
|
||||
- Toolchain autodetection is now done in the background on project load
|
||||
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Unicode characters in char literals triggered an error
|
||||
|
||||
## [20.0.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Project
|
||||
- IDE freezes when opening a zig project / doing zig init
|
||||
- Test tasks don't work and try to run the file as an executable
|
||||
|
||||
- Zig
|
||||
- Struct fields being styled as static fields instead of instance fields
|
||||
|
||||
## [20.0.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Debugging
|
||||
- Progress indicator while zig is compiling the debuggable exe
|
||||
|
||||
### Changed
|
||||
|
||||
- The entire plugin has been re-implemented in Kotlin
|
||||
|
||||
### Fixed
|
||||
|
||||
- Most of the internals have been rewritten to be fully asynchronous, so freezes should happen way less
|
||||
|
||||
## [19.3.0]
|
||||
|
||||
### Added
|
||||
|
@ -24,7 +341,7 @@ Changelog structure reference:
|
|||
- Toolchains, Run Configurations
|
||||
- [Direnv](https://github.com/direnv/direnv) support
|
||||
|
||||
### Fixed
|
||||
### Fixed
|
||||
|
||||
- Zig
|
||||
- Missing description for string conversion intentions
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
# Code of Merit
|
||||
|
||||
1. The project creators, lead developers, core team, constitute
|
||||
the managing members of the project and have final say in every decision
|
||||
of the project, technical or otherwise, including overruling previous decisions.
|
||||
There are no limitations to this decisional power.
|
||||
|
||||
2. Contributions are an expected result of your membership on the project.
|
||||
Don't expect others to do your work or help you with your work forever.
|
||||
|
||||
3. All members have the same opportunities to seek any challenge they want
|
||||
within the project.
|
||||
|
||||
4. Authority or position in the project will be proportional
|
||||
to the accrued contribution. Seniority must be earned.
|
||||
|
||||
5. Software is evolutive: the better implementations must supersede lesser
|
||||
implementations. Technical advantage is the primary evaluation metric.
|
||||
|
||||
6. This is a space for technical prowess; topics outside of the project
|
||||
will not be tolerated.
|
||||
|
||||
7. Non technical conflicts will be discussed in a separate space. Disruption
|
||||
of the project will not be allowed.
|
||||
|
||||
8. Individual characteristics, including but not limited to,
|
||||
body, sex, sexual preference, race, language, religion, nationality,
|
||||
or political preferences are irrelevant in the scope of the project and
|
||||
will not be taken into account concerning your value or that of your contribution
|
||||
to the project.
|
||||
|
||||
9. Discuss or debate the idea, not the person.
|
||||
|
||||
10. There is no room for ambiguity: Ambiguity will be met with questioning;
|
||||
further ambiguity will be met with silence. It is the responsibility
|
||||
of the originator to provide requested context.
|
||||
|
||||
11. If something is illegal outside the scope of the project, it is illegal
|
||||
in the scope of the project. This Code of Merit does not take precedence over
|
||||
governing law.
|
||||
|
||||
12. This Code of Merit governs the technical procedures of the project not the
|
||||
activities outside of it.
|
||||
|
||||
13. Participation on the project equates to agreement of this Code of Merit.
|
||||
|
||||
14. No objectives beyond the stated objectives of this project are relevant
|
||||
to the project. Any intent to deviate the project from its original purpose
|
||||
of existence will constitute grounds for remedial action which may include
|
||||
expulsion from the project.
|
||||
|
||||
This document is adapted from the Code of Merit, version 1.0.
|
||||
See: https://codeofmerit.org/.
|
|
@ -1,19 +0,0 @@
|
|||
For now this project is still pretty small, but here are some general guidelines on how to contribute to this repository
|
||||
|
||||
- This project ships with a code style config in .idea, your IDE should automatically apply it when you pull the repo.
|
||||
When making pull requests, please try to keep to this style as much as possible.
|
||||
|
||||
- Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), and scope as much as you can.
|
||||
|
||||
- Do not edit the relationship tree between modules without unanimous agreement from the project lead.
|
||||
|
||||
If you want an "upstream" module (for instance, the LSP) receive data from a "downstream" module
|
||||
(for instance, the project module), you should use service providers, dependency injections, or other ways to implement
|
||||
the dataflow in a way where the upstream module is not directly aware of downstream modules.
|
||||
|
||||
The main purpose of this is to avoid any circular dependencies, which could cause proprietary IDE-only features
|
||||
(for instance, the CLion debugger module) to be depended on by FOSS modules. This restriction is non-negotiable.
|
||||
|
||||
- Any complex language inspection, syntax action, or similar, should be done by ZLS, and ZigBrains will just act as an
|
||||
adapter for these features. This notion of "complexity" is determined by the project maintainer. Open an issue
|
||||
that explains the feature before you start implementing anything!
|
42
LICENSE
42
LICENSE
|
@ -1,36 +1,35 @@
|
|||
All code in this project, unless specified differently, is licensed under the Apache 2.0 license.
|
||||
Graphical assets derived from the Zig logo are governed by a different license, included below.
|
||||
--------------------------------
|
||||
ZigBrains
|
||||
Copyright (C) 2023-2025 FalsePattern
|
||||
All Rights Reserved
|
||||
|
||||
Copyright 2023-2024 FalsePattern
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, only version 3 of the License.
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
--------------------------------
|
||||
The following sections are the licenses of code derived from third party projects:
|
||||
|
||||
--------------------------------
|
||||
The code inside the `lsp` package is derived from the LSP4IntelliJ project, with various modifications, fixes, and
|
||||
additions to fix any outstanding issues i was having with the original code. (https://github.com/ballerina-platform/lsp4intellij)
|
||||
|
||||
The original code is Copyright WSO2 Inc., licensed under the `Apache 2.0` license.
|
||||
--------------------------------
|
||||
The art assets inside src/art/zig, and all copies of them, are derived from the official Zig Programming Language logo,
|
||||
which are the property of the Zig Software Foundation.
|
||||
(https://github.com/ziglang/logo)
|
||||
These art assets are licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0).
|
||||
--------------------------------
|
||||
The art assets inside src/art/zls, and all copies of them, are derived from the Zig Language Server,
|
||||
which are the property of the zigtools organization.
|
||||
(https://github.com/zigtools/zls)
|
||||
These art assets are licensed under MIT license.
|
||||
--------------------------------
|
||||
Parts of the codebase are based on the intellij-zig plugin,
|
||||
developed by HTGAzureX1212 (https://github.com/HTGAzureX1212), licensed under the Apache 2.0 license.
|
||||
--------------------------------
|
||||
|
@ -41,4 +40,7 @@ developed by the intellij-rust team (https://github.com/intellij-rust), licensed
|
|||
All of the licenses listed here are available in the following files, bundled with the plugin:
|
||||
- licenses/APACHE_2.0.LICENSE
|
||||
- licenses/CC_BY_SA_4.0.LICENSE
|
||||
- licenses/INTELLIJ-RUST.LICENSE
|
||||
- licenses/GPL3.LICENSE
|
||||
- licenses/INTELLIJ-RUST.LICENSE
|
||||
- licenses/LGPL3.LICENSE
|
||||
- licenses/ZLS.LICENSE
|
|
@ -1,36 +0,0 @@
|
|||
## What is this?
|
||||
This document describes the relationships between the different "modules" of ZigBrains.
|
||||
|
||||
These relationships are strictly enforced, and modules that do not directly (or indirectly) depend on another
|
||||
module cannot access their classes.
|
||||
|
||||
The primary purpose of this strictly enforced module system is to avoid code compatible with open source IDEs (IDEA/PyCharm Community)
|
||||
from depending on code that only works on proprietary IDEs (IDEA Ultimate/CLion/...).
|
||||
|
||||
NOTE: These "modules" are in no way related to the module system introduced in Java 9. They're just called the same.
|
||||
|
||||
The suffix after the module name signifies which IDE it depends on.
|
||||
|
||||
- IC: IDEA Community
|
||||
- CL: CLion
|
||||
|
||||
IC modules MUST NOT depend on CL modules, as this violates the restrictions set forth above.
|
||||
|
||||
## Modules
|
||||
|
||||
### Common (IC)
|
||||
|
||||
### Zig (IC)
|
||||
- Common (IC)
|
||||
|
||||
### Project (IC)
|
||||
- Common (IC)
|
||||
- Zig (IC)
|
||||
|
||||
### Zon (IC)
|
||||
- Common (IC)
|
||||
|
||||
### Debugger (IU/CL)
|
||||
- Common (IC)
|
||||
- Zig (IC)
|
||||
- Project (IC)
|
96
README.md
96
README.md
|
@ -1,10 +1,10 @@
|
|||
# ZigBrains
|
||||
|
||||
Zig language support for IntelliJ IDEA, CLion, and other JetBrains IDEs.
|
||||
Zig language support for IntelliJ IDEA, CLion, and other JetBrains IDEs. Now written in Kotlin!
|
||||
|
||||
## Installing
|
||||
# Installing
|
||||
|
||||
You can either install this plugin from the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/22456-zigbrains), or from FalsePattern's [website](https://falsepattern.com/zigbrains).
|
||||
You can either install this plugin from the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/22456-zigbrains), or from [FalsePattern's website](https://falsepattern.com/zigbrains).
|
||||
|
||||
See [the quick setup guide](#quick-setup-guide-for-zig-and-zls) for how to set up language server integration.
|
||||
|
||||
|
@ -15,53 +15,13 @@ through the built-in plugin browser:
|
|||
1. Go to `Settings -> Plugins`
|
||||
2. To the right of the `Installed` button at the top, click on the `...` dropdown menu, then select `Manage Plugin Repositories...`
|
||||
3. Click the add button, and then enter the ZigBrains updater URL, based on your IDE version:
|
||||
- `2025.1.*` or newer: https://falsepattern.com/zigbrains/updatePlugins-251.xml
|
||||
- `2024.3.*`: https://falsepattern.com/zigbrains/updatePlugins-243.xml
|
||||
- `2024.2.*`: https://falsepattern.com/zigbrains/updatePlugins-242.xml
|
||||
- `2024.1.*`: https://falsepattern.com/zigbrains/updatePlugins-241.xml
|
||||
- `2023.3.*`: https://falsepattern.com/zigbrains/updatePlugins-233.xml
|
||||
- `2023.2.*`: https://falsepattern.com/zigbrains/updatePlugins-232.xml
|
||||
4. Click `OK`, and your IDE should now automatically detect the latest version
|
||||
(both in the Installed tab and in the Marketplace tab), even if it's not yet verified on the official JetBrains marketplace yet.
|
||||
|
||||
## Developer guide
|
||||
|
||||
### All platforms
|
||||
|
||||
After importing the gradle project, you need to run the `build setup -> generateSources` tasks.
|
||||
|
||||
### NixOS
|
||||
|
||||
In addition to the generated sources, you also need to run the `build setup -> nixos_jbr` task, otherwise java will
|
||||
complain about missing files
|
||||
|
||||
## Special Thanks
|
||||
|
||||
- The [ZigTools](https://github.com/zigtools/) team for developing the Zig Language Server.
|
||||
|
||||
- [HTGAzureX1212](https://github.com/HTGAzureX1212) for developing [intellij-zig](https://github.com/intellij-zig/intellij-zig),
|
||||
which served as a fantastic reference for deep IDE integration features.
|
||||
|
||||
- The members of the `Zig Programming Language` discord server's `#tooling-dev` channel for providing encouragement,
|
||||
feedback, and lots of bug reports.
|
||||
|
||||
- The Ballerina Platform developers for `lsp4intellij`, the language server connector between the IntelliJ platform
|
||||
and the Eclipse LSP4J project.
|
||||
|
||||
- The developers of the [intellij-rust](https://github.com/intellij-rust/intellij-rust/) plugin for providing an
|
||||
excellent example on how to write debugger support that doesn't depend on CLion.
|
||||
|
||||
- All the people who have generously funded the project
|
||||
- gree7
|
||||
- xceno
|
||||
- AnErrupTion
|
||||
|
||||
- Every contributor who helped with bugfixes and extra features
|
||||
- [gatesn](https://github.com/gatesn)
|
||||
- [MarioAriasC](https://github.com/MarioAriasC)
|
||||
- [JensvandeWiel](https://github.com/JensvandeWiel)
|
||||
|
||||
- And everyone who actively reported issues and helped ironing out all the remaining problems
|
||||
|
||||
## Versioning scheme
|
||||
To reduce confusion and to better utilize semver, the plugin uses the following versioning scheme:
|
||||
|
||||
|
@ -74,24 +34,45 @@ Note: before version 11, the version scheme used was 0.X.Y, without separate pat
|
|||
As this plugin will constantly be evolving together with the zig language, it makes no sense to keep the 0 prefix,
|
||||
and might as well utilize the full semver string for extra information.
|
||||
|
||||
# Credits
|
||||
|
||||
## Supporters
|
||||
|
||||
- ### [Techatrix](https://github.com/Techatrix)
|
||||
- ### [nuxusr](https://github.com/nuxusr)
|
||||
- gree7
|
||||
- xceno
|
||||
- AnErrupTion
|
||||
|
||||
## Contributors
|
||||
|
||||
- [gatesn](https://github.com/gatesn)
|
||||
- [MarioAriasC](https://github.com/MarioAriasC)
|
||||
- [JensvandeWiel](https://github.com/JensvandeWiel)
|
||||
|
||||
## Additional Thanks
|
||||
|
||||
- The [ZigTools](https://github.com/zigtools/) team for developing the Zig Language Server.
|
||||
|
||||
- [HTGAzureX1212](https://github.com/HTGAzureX1212) for developing [intellij-zig](https://github.com/intellij-zig/intellij-zig),
|
||||
which served as a fantastic reference for deep IDE integration features.
|
||||
|
||||
- The members of the `Zig Programming Language` discord server's `#tooling-dev` channel for providing encouragement,
|
||||
feedback, and lots of bug reports.
|
||||
|
||||
- The developers of [LSP4IJ](https://github.com/redhat-developer/lsp4ij) for providing a really good LSP backend
|
||||
|
||||
- The developers of the [intellij-rust](https://github.com/intellij-rust/intellij-rust/) plugin for providing an
|
||||
excellent example on how to write debugger support that doesn't depend on CLion.
|
||||
|
||||
- And everyone who actively reported issues and helped ironing out all the remaining problems
|
||||
|
||||
# Description
|
||||
|
||||
<!-- Plugin description -->
|
||||
Adds support for the Zig Language, utilizing the ZLS language server for advanced coding assistance.
|
||||
|
||||
## Quick setup guide for Zig and ZLS
|
||||
|
||||
1. Download the latest version of Zig from https://ziglang.org/download
|
||||
2. Download and compile the ZLS language server, available at https://github.com/zigtools/zls
|
||||
3. Go to `Settings` -> `Languages & Frameworks` -> `Zig`, and point the `Toolchain Location` and `ZLS path` to the correct places
|
||||
|
||||
## Features
|
||||
|
||||
- Integration with the Zig Language Server (ZLS)
|
||||
- Basic syntax highlighting if ZLS is not available
|
||||
- Run and debug configurations for Zig projects (Debugging has some IDE limitations, and on Windows you need to do some extra setup, see below)
|
||||
- Direnv support for loading environment variables from `.envrc` files (requires the direnv executable to be installed system-wide)
|
||||
- Language injection support in Zig strings
|
||||
Before you can properly use the plugin, you need to select or download the Zig toolchain and language server in `Settings` -> `Languages & Frameworks` -> `Zig`.
|
||||
|
||||
## Debugging
|
||||
|
||||
|
@ -105,6 +86,7 @@ Debugging Zig code is supported in any native debugging capable IDE. The followi
|
|||
- RustRover (including the non-commercial free version too)
|
||||
- GoLand
|
||||
- PyCharm Professional
|
||||
- Android Studio
|
||||
|
||||
Additionally, in CLion, the plugin uses the C++ Toolchains for sourcing the debugger (this can be toggled off in the settings).
|
||||
|
||||
|
|
539
build.gradle.kts
539
build.gradle.kts
|
@ -1,414 +1,211 @@
|
|||
import de.undercouch.gradle.tasks.download.Download
|
||||
import groovy.xml.XmlParser
|
||||
import org.jetbrains.changelog.Changelog
|
||||
import org.jetbrains.changelog.markdownToHTML
|
||||
import org.jetbrains.grammarkit.tasks.GenerateLexerTask
|
||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
||||
import org.jetbrains.intellij.platform.gradle.tasks.PatchPluginXmlTask
|
||||
import org.jetbrains.intellij.platform.gradle.tasks.PublishPluginTask
|
||||
import org.jetbrains.intellij.platform.gradle.utils.extensionProvider
|
||||
|
||||
fun properties(key: String) = providers.gradleProperty(key) as Provider<String>
|
||||
fun environment(key: String) = providers.environmentVariable(key) as Provider<String>
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
|
||||
|
||||
plugins {
|
||||
java
|
||||
kotlin("jvm") version "2.1.10" apply false
|
||||
kotlin("plugin.serialization") version "2.1.10" apply false
|
||||
id("org.jetbrains.intellij.platform") version "2.5.0"
|
||||
id("org.jetbrains.changelog") version "2.2.1"
|
||||
id("org.jetbrains.grammarkit") version "2022.3.2.2" apply false
|
||||
idea
|
||||
`maven-publish`
|
||||
`java-library`
|
||||
id("org.jetbrains.intellij.platform") version("2.1.0")
|
||||
id("org.jetbrains.changelog") version("2.2.1")
|
||||
id("org.jetbrains.grammarkit") version("2022.3.2.2")
|
||||
id("de.undercouch.download") version("5.6.0")
|
||||
}
|
||||
|
||||
val publishVersions = listOf("232", "233", "241", "242", "243")
|
||||
|
||||
val gitVersion: groovy.lang.Closure<String> by extra
|
||||
|
||||
val grammarKitGenDir = "build/generated/sources/grammarkit/java"
|
||||
val rootPackage = "com.falsepattern.zigbrains"
|
||||
|
||||
val rootPackagePath = rootPackage.replace('.', '/')
|
||||
|
||||
// Keep these in sync with whatever the oldest IDE version we're targeting in gradle.properties needs
|
||||
val javaLangVersion: JavaLanguageVersion = JavaLanguageVersion.of(21)
|
||||
val javaVersion = JavaVersion.VERSION_21
|
||||
|
||||
val baseIDE = properties("baseIDE").get()
|
||||
val ideaVersion = properties("ideaVersion").get()
|
||||
val clionVersion = properties("clionVersion").get()
|
||||
|
||||
val clionPlugins = listOf("com.intellij.clion", "com.intellij.cidr.lang", "com.intellij.cidr.base", "com.intellij.nativeDebug")
|
||||
|
||||
val lsp4jVersion = "0.21.1"
|
||||
val lsp4ijVersion = "0.7.0"
|
||||
|
||||
val lsp4ijNightly = lsp4ijVersion.contains("-")
|
||||
val lsp4ijDepString = "${if (lsp4ijNightly) "nightly." else ""}com.jetbrains.plugins:com.redhat.devtools.lsp4ij:$lsp4ijVersion"
|
||||
val publishVersions = listOf("241", "242", "243", "251")
|
||||
val pluginVersionFull get() = "$pluginVersion-$pluginSinceBuild"
|
||||
val pluginVersion: String by project
|
||||
val pluginSinceBuild: String by project
|
||||
val pluginUntilBuild: String by project
|
||||
val javaVersion = property("javaVersion").toString().toInt()
|
||||
val lsp4ijVersion: String by project
|
||||
val runIdeTarget: String by project
|
||||
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
||||
val useInstaller = property("useInstaller").toString().toBoolean()
|
||||
val lsp4ijPluginString = "com.redhat.devtools.lsp4ij:$lsp4ijVersion${if (lsp4ijNightly) "@nightly" else ""}"
|
||||
val ideaCommunityVersion: String by project
|
||||
val clionVersion: String by project
|
||||
|
||||
val lsp4ijDep: DependencyHandler.() -> Unit = {
|
||||
intellijPlatformPluginDependency(lsp4ijDepString)
|
||||
compileOnlyApi(lsp4ijDepString)
|
||||
compileOnlyApi("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
|
||||
group = "com.falsepattern"
|
||||
version = pluginVersionFull
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "org.jetbrains.kotlin.jvm")
|
||||
apply(plugin = "org.jetbrains.intellij.platform.module")
|
||||
apply(plugin = "idea")
|
||||
|
||||
extensions.configure<KotlinJvmProjectExtension>("kotlin") {
|
||||
jvmToolchain(javaVersion)
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompilationTask<*>>().configureEach {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll("-Xlambdas=indy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
wrapper {
|
||||
gradleVersion = properties("gradleVersion").get()
|
||||
processResources {
|
||||
from("LICENSE")
|
||||
from("licenses") {
|
||||
into("licenses")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pluginVersion(): Provider<String> {
|
||||
return provider {
|
||||
System.getenv("RELEASE_VERSION")
|
||||
}.orElse(properties("pluginVersion"))
|
||||
}
|
||||
|
||||
fun pluginVersionFull(): Provider<String> {
|
||||
return pluginVersion().map { it + "-" + properties("pluginSinceBuild").get() }
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply {
|
||||
plugin("org.jetbrains.intellij.platform")
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
intellijPlatform {
|
||||
localPlatformArtifacts {
|
||||
content {
|
||||
includeGroup("bundledPlugin")
|
||||
}
|
||||
}
|
||||
marketplace {
|
||||
content {
|
||||
includeGroup("com.jetbrains.plugins")
|
||||
includeGroup("nightly.com.jetbrains.plugins")
|
||||
}
|
||||
}
|
||||
snapshots {
|
||||
content {
|
||||
includeModule("com.jetbrains.intellij.clion", "clion")
|
||||
includeModule("com.jetbrains.intellij.idea", "ideaIC")
|
||||
includeModule("com.jetbrains.intellij.idea", "ideaIU")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:1.18.32")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
if (path !in listOf(":", ":plugin", ":debugger", ":cidr")) {
|
||||
intellijPlatform {
|
||||
intellijIdeaCommunity(ideaVersion, useInstaller = false)
|
||||
}
|
||||
idea {
|
||||
module {
|
||||
isDownloadSources = true
|
||||
}
|
||||
}
|
||||
|
||||
if (path in listOf(":zig", ":zon")) {
|
||||
apply {
|
||||
plugin("org.jetbrains.grammarkit")
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs(
|
||||
"${grammarKitGenDir}/lexer",
|
||||
"${grammarKitGenDir}/parser"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks {
|
||||
|
||||
generateLexer {
|
||||
enabled = true
|
||||
purgeOldFiles = true
|
||||
}
|
||||
|
||||
generateParser {
|
||||
enabled = true
|
||||
targetRootOutputDir = file("${grammarKitGenDir}/parser")
|
||||
}
|
||||
|
||||
|
||||
register<DefaultTask>("generateGrammars") {
|
||||
description = "Generate source code from parser/lexer definitions"
|
||||
group = "build setup"
|
||||
dependsOn("generateLexer")
|
||||
dependsOn("generateParser")
|
||||
}
|
||||
|
||||
compileJava {
|
||||
dependsOn("generateGrammars")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure<JavaPluginExtension> {
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(javaLangVersion)
|
||||
languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
@Suppress("UnstableApiUsage")
|
||||
vendor = JvmVendorSpec.JETBRAINS
|
||||
}
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
sourceCompatibility = JavaVersion.toVersion(javaVersion)
|
||||
targetCompatibility = JavaVersion.toVersion(javaVersion)
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile::class) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
|
||||
group = properties("pluginGroup").get()
|
||||
version = pluginVersionFull().get()
|
||||
|
||||
tasks {
|
||||
runIde { enabled = false }
|
||||
prepareSandbox { enabled = false }
|
||||
buildSearchableOptions { enabled = false }
|
||||
verifyPlugin { enabled = false }
|
||||
buildPlugin { enabled = false }
|
||||
signPlugin { enabled = false }
|
||||
verifyPluginProjectConfiguration { enabled = false }
|
||||
|
||||
withType<PatchPluginXmlTask> {
|
||||
sinceBuild = properties("pluginSinceBuild")
|
||||
untilBuild = properties("pluginUntilBuild").flatMap {provider { it.ifBlank { null } }}
|
||||
}
|
||||
}
|
||||
intellijPlatform {
|
||||
instrumentCode = false
|
||||
buildSearchableOptions = false
|
||||
}
|
||||
}
|
||||
|
||||
project(":common") {
|
||||
|
||||
}
|
||||
|
||||
project(":zig") {
|
||||
apply {
|
||||
plugin("java-library")
|
||||
}
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
lsp4ijDep()
|
||||
intellijPlatform {
|
||||
plugin(lsp4ijPluginString)
|
||||
bundledPlugin("org.intellij.intelliLang")
|
||||
}
|
||||
}
|
||||
tasks {
|
||||
generateLexer {
|
||||
sourceFile = file("src/main/grammar/Zig.flex")
|
||||
targetOutputDir = file("${grammarKitGenDir}/lexer/${rootPackagePath}/zig/lexer")
|
||||
}
|
||||
|
||||
register<GenerateLexerTask>("generateStringLexer") {
|
||||
sourceFile = file("src/main/grammar/ZigString.flex")
|
||||
targetOutputDir = file("${grammarKitGenDir}/lexer/${rootPackagePath}/zig/stringlexer")
|
||||
purgeOldFiles = true
|
||||
}
|
||||
|
||||
generateParser {
|
||||
sourceFile = file("src/main/grammar/Zig.bnf")
|
||||
pathToParser = "${rootPackagePath}/zig/psi/ZigParser.java"
|
||||
pathToPsiRoot = "${rootPackagePath}/zig/psi"
|
||||
}
|
||||
|
||||
named("generateGrammars") {
|
||||
dependsOn("generateStringLexer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project(":project") {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
implementation(project(":zig"))
|
||||
}
|
||||
}
|
||||
|
||||
project(":cidr") {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
implementation(project(":project"))
|
||||
intellijPlatform {
|
||||
clion(clionVersion, useInstaller = false)
|
||||
for (p in clionPlugins) {
|
||||
bundledPlugin(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project(":debugger") {
|
||||
dependencies {
|
||||
implementation(project(":zig"))
|
||||
implementation(project(":project"))
|
||||
implementation(project(":common"))
|
||||
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j.debug:$lsp4jVersion") {
|
||||
exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j")
|
||||
exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j.jsonrpc")
|
||||
exclude("com.google.code.gson", "gson")
|
||||
}
|
||||
intellijPlatform {
|
||||
clion(clionVersion, useInstaller = false)
|
||||
for (p in clionPlugins) {
|
||||
bundledPlugin(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val genOutputDir = layout.buildDirectory.dir("generated-resources")
|
||||
sourceSets["main"].resources.srcDir(genOutputDir)
|
||||
tasks {
|
||||
register<Download>("downloadProps") {
|
||||
src("https://falsepattern.com/zigbrains/msvc.properties")
|
||||
dest(genOutputDir.map { it.file("msvc.properties") })
|
||||
}
|
||||
|
||||
processResources {
|
||||
dependsOn("downloadProps")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project(":zon") {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
}
|
||||
tasks {
|
||||
generateLexer {
|
||||
sourceFile = file("src/main/grammar/Zon.flex")
|
||||
targetOutputDir = file("${grammarKitGenDir}/lexer/${rootPackagePath}/zon/lexer")
|
||||
}
|
||||
|
||||
generateParser {
|
||||
sourceFile = file("src/main/grammar/Zon.bnf")
|
||||
pathToParser = "${rootPackagePath}/zon/psi/ZonParser.java"
|
||||
pathToPsiRoot = "${rootPackagePath}/zon/psi"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project(":plugin") {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
implementation(project(":zig"))
|
||||
implementation(project(":project"))
|
||||
implementation(project(":zon"))
|
||||
implementation(project(":cidr"))
|
||||
implementation(project(":debugger"))
|
||||
intellijPlatform {
|
||||
zipSigner()
|
||||
pluginVerifier()
|
||||
when (baseIDE) {
|
||||
"idea" -> intellijIdeaCommunity(ideaVersion, useInstaller = false)
|
||||
"clion" -> clion(clionVersion, useInstaller = false)
|
||||
}
|
||||
plugin(lsp4ijPluginString)
|
||||
}
|
||||
}
|
||||
|
||||
intellijPlatform {
|
||||
projectName = "ZigBrains"
|
||||
pluginConfiguration {
|
||||
name = properties("pluginName")
|
||||
description = providers.fileContents(rootProject.layout.projectDirectory.file("README.md")).asText.map {
|
||||
val start = "<!-- Plugin description -->"
|
||||
val end = "<!-- Plugin description end -->"
|
||||
|
||||
with(it.lines()) {
|
||||
if (!containsAll(listOf(start, end))) {
|
||||
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
|
||||
}
|
||||
subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML)
|
||||
repositories {
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
setUrl("https://mvn.falsepattern.com/releases")
|
||||
name = "mavenpattern"
|
||||
}
|
||||
}
|
||||
changeNotes = pluginVersion().map { pluginVersion ->
|
||||
with(rootProject.changelog) {
|
||||
renderItem(
|
||||
(getOrNull(pluginVersion) ?: getUnreleased())
|
||||
.withHeader(false)
|
||||
.withEmptySections(false),
|
||||
Changelog.OutputType.HTML,
|
||||
)
|
||||
}
|
||||
}
|
||||
version = pluginVersionFull()
|
||||
}
|
||||
signing {
|
||||
certificateChainFile = rootProject.file("secrets/chain.crt")
|
||||
privateKeyFile = rootProject.file("secrets/private.pem")
|
||||
password = environment("PRIVATE_KEY_PASSWORD")
|
||||
}
|
||||
pluginVerification {
|
||||
ides {
|
||||
ide(IntelliJPlatformType.IntellijIdeaCommunity, ideaVersion, useInstaller = false)
|
||||
ide(IntelliJPlatformType.IntellijIdeaUltimate, ideaVersion, useInstaller = false)
|
||||
ide(IntelliJPlatformType.CLion, clionVersion, useInstaller = false)
|
||||
filter {
|
||||
includeModule("com.redhat.devtools.intellij", "lsp4ij")
|
||||
}
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
|
||||
tasks {
|
||||
runIde {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
prepareSandbox {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
verifyPlugin {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
verifyPluginProjectConfiguration {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
signPlugin {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
verifyPluginSignature {
|
||||
dependsOn(signPlugin)
|
||||
}
|
||||
|
||||
buildPlugin {
|
||||
enabled = true
|
||||
intellijPlatform {
|
||||
defaultRepositories()
|
||||
snapshots()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
when (baseIDE) {
|
||||
"idea" -> intellijIdeaCommunity(ideaVersion, useInstaller = false)
|
||||
"clion" -> clion(clionVersion, useInstaller = false)
|
||||
when(runIdeTarget) {
|
||||
"ideaCommunity" -> create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller)
|
||||
"clion" -> create(IntelliJPlatformType.CLion, clionVersion, useInstaller = useInstaller)
|
||||
}
|
||||
|
||||
pluginVerifier()
|
||||
zipSigner()
|
||||
plugin(lsp4ijPluginString)
|
||||
}
|
||||
|
||||
runtimeOnly(project(":core"))
|
||||
runtimeOnly(project(":cidr"))
|
||||
runtimeOnly(project(":lsp"))
|
||||
}
|
||||
|
||||
intellijPlatform {
|
||||
pluginConfiguration {
|
||||
version = pluginVersionFull
|
||||
|
||||
description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map {
|
||||
val start = "<!-- Plugin description -->"
|
||||
val end = "<!-- Plugin description end -->"
|
||||
|
||||
with(it.lines()) {
|
||||
if (!containsAll(listOf(start, end))) {
|
||||
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
|
||||
}
|
||||
subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML)
|
||||
}
|
||||
}
|
||||
|
||||
val changelog = project.changelog
|
||||
|
||||
changeNotes = provider { pluginVersion }.map { pluginVersion ->
|
||||
with(changelog) {
|
||||
renderItem(
|
||||
(getOrNull(pluginVersion) ?: getUnreleased())
|
||||
.withHeader(false)
|
||||
.withEmptySections(false),
|
||||
Changelog.OutputType.HTML
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ideaVersion {
|
||||
sinceBuild = pluginSinceBuild
|
||||
if (pluginUntilBuild.isNotBlank()) {
|
||||
untilBuild = pluginUntilBuild
|
||||
} else {
|
||||
untilBuild = provider { null }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
certificateChainFile = file("secrets/chain.crt")
|
||||
privateKeyFile = file("secrets/private.pem")
|
||||
password = providers.environmentVariable("PRIVATE_KEY_PASSWORD")
|
||||
}
|
||||
|
||||
pluginVerification {
|
||||
ides {
|
||||
select {
|
||||
types = listOf(
|
||||
IntelliJPlatformType.IntellijIdeaCommunity,
|
||||
IntelliJPlatformType.IntellijIdeaUltimate,
|
||||
IntelliJPlatformType.CLion
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
buildSearchableOptions = false
|
||||
instrumentCode = false
|
||||
}
|
||||
|
||||
changelog {
|
||||
groups.empty()
|
||||
repositoryUrl = providers.gradleProperty("pluginRepositoryUrl")
|
||||
}
|
||||
|
||||
tasks {
|
||||
generateLexer {
|
||||
publishPlugin {
|
||||
dependsOn(patchChangelog)
|
||||
}
|
||||
compileJava {
|
||||
enabled = false
|
||||
}
|
||||
generateParser {
|
||||
classes {
|
||||
enabled = false
|
||||
}
|
||||
verifyPluginSignature {
|
||||
certificateChainFile = file("secrets/chain.crt")
|
||||
inputArchiveFile = signPlugin.map { it.signedArchiveFile }.get()
|
||||
dependsOn(signPlugin)
|
||||
}
|
||||
publishPlugin {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
fun distFile(it: String) = layout.buildDirectory.file("dist/ZigBrains-${pluginVersion().get()}-$it-signed.zip")
|
||||
|
||||
fun distFile(it: String) = layout.buildDirectory.file("dist/ZigBrains-$pluginVersion-$it-signed.zip")
|
||||
|
||||
publishVersions.forEach {
|
||||
tasks.register<PublishPluginTask>("jbpublish-$it").configure {
|
||||
archiveFile = distFile(it)
|
||||
token = environment("IJ_PUBLISH_TOKEN")
|
||||
channels = if (pluginVersion().get().contains("-")) listOf("nightly") else listOf("default")
|
||||
token = providers.environmentVariable("IJ_PUBLISH_TOKEN")
|
||||
channels = if (pluginVersion.contains("-")) listOf("nightly") else listOf("default")
|
||||
setDependsOn(dependsOn.filter { if (it is TaskProvider<*>) it.name != "signPlugin" && it.name != "buildPlugin" else true })
|
||||
}
|
||||
tasks.named("publish").configure {
|
||||
dependsOn("jbpublish-$it")
|
||||
|
@ -420,7 +217,7 @@ publishing {
|
|||
create<MavenPublication>("maven") {
|
||||
groupId = "com.falsepattern"
|
||||
artifactId = "zigbrains"
|
||||
version = pluginVersion().get()
|
||||
version = pluginVersion
|
||||
|
||||
publishVersions.forEach {
|
||||
artifact(distFile(it)) {
|
||||
|
@ -440,22 +237,4 @@ publishing {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun File.isPluginJar(): Boolean {
|
||||
if (!isFile) return false
|
||||
if (extension != "jar") return false
|
||||
return zipTree(this).files.any { it.isManifestFile() }
|
||||
}
|
||||
|
||||
fun File.isManifestFile(): Boolean {
|
||||
if (extension != "xml") return false
|
||||
val rootNode = try {
|
||||
val parser = XmlParser()
|
||||
parser.parse(this)
|
||||
} catch (e: Exception) {
|
||||
logger.error("Failed to parse $path", e)
|
||||
return false
|
||||
}
|
||||
return rootNode.name() == "idea-plugin"
|
||||
}
|
||||
}
|
32
build.sh
32
build.sh
|
@ -1,23 +1,29 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2023-2024 FalsePattern
|
||||
# This file is part of ZigBrains.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# Copyright (C) 2023-2025 FalsePattern
|
||||
# All Rights Reserved
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ZigBrains is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, only version 3 of the License.
|
||||
#
|
||||
# ZigBrains 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
declare -a branches=("master" "242" "241" "233" "232")
|
||||
declare -a branches=("master" "243" "242" "241")
|
||||
|
||||
DEFAULT_BRANCH="${branches[0]}"
|
||||
|
||||
|
@ -64,7 +70,7 @@ fi
|
|||
for i in "${branches[@]}"
|
||||
do
|
||||
echo "Building branch $i"
|
||||
git checkout "$i" && ./gradlew :plugin:verifyPluginSignature
|
||||
git checkout "$i" && ./gradlew verifyPluginSignature
|
||||
RESULT=$?
|
||||
if [ $RESULT != 0 ]; then
|
||||
echo "Failed to build plugin on branch $i!"
|
||||
|
@ -76,6 +82,6 @@ git checkout "$DEFAULT_BRANCH"
|
|||
|
||||
mkdir -p build/dist
|
||||
|
||||
cp modules/plugin/build/distributions/*-signed.zip build/dist/
|
||||
cp build/distributions/*-signed.zip build/dist/
|
||||
|
||||
./gradlew publish
|
46
cidr/build.gradle.kts
Normal file
46
cidr/build.gradle.kts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import de.undercouch.gradle.tasks.download.Download
|
||||
import org.jetbrains.intellij.platform.gradle.Constants
|
||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
||||
|
||||
plugins {
|
||||
id("de.undercouch.download") version("5.6.0")
|
||||
}
|
||||
val lsp4jVersion: String by project
|
||||
val clionVersion: String by project
|
||||
val useInstaller = property("useInstaller").toString().toBoolean()
|
||||
|
||||
val genOutputDir = layout.buildDirectory.dir("generated-resources")
|
||||
sourceSets["main"].resources.srcDir(genOutputDir)
|
||||
|
||||
tasks {
|
||||
register<Download>("downloadProps") {
|
||||
onlyIfModified(true)
|
||||
useETag(true)
|
||||
src("https://falsepattern.com/zigbrains/msvc.properties")
|
||||
dest(genOutputDir.map { it.file("msvc.properties") })
|
||||
}
|
||||
processResources {
|
||||
dependsOn("downloadProps")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create(IntelliJPlatformType.CLion, clionVersion, useInstaller = useInstaller)
|
||||
bundledPlugins("com.intellij.clion", "com.intellij.cidr.base", "com.intellij.nativeDebug")
|
||||
}
|
||||
implementation(project(":core")) {
|
||||
isTransitive = false
|
||||
}
|
||||
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j.debug:$lsp4jVersion") {
|
||||
exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j")
|
||||
exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j.jsonrpc")
|
||||
exclude("com.google.code.gson", "gson")
|
||||
}
|
||||
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
|
||||
}
|
||||
configurations[Constants.Configurations.INTELLIJ_PLATFORM_BUNDLED_PLUGINS].dependencies.configureEach {
|
||||
if (this is ExternalModuleDependency) {
|
||||
this.isTransitive = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.cidr
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.jetbrains.cidr.project.workspace.CidrWorkspace
|
||||
import com.jetbrains.cidr.project.workspace.OCRootsSynchronizer
|
||||
import java.io.File
|
||||
|
||||
class ZigWorkspace(project: Project) : CidrWorkspace(project) {
|
||||
override fun collectRootsInfo(p0: File?): OCRootsSynchronizer.RootsInfo {
|
||||
return OCRootsSynchronizer.RootsInfo()
|
||||
}
|
||||
|
||||
override fun getClientKey(): String {
|
||||
return "ZIG_WORKSPACE"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.cidr
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import com.jetbrains.cidr.project.workspace.CidrWorkspace
|
||||
import com.jetbrains.cidr.project.workspace.CidrWorkspaceManager
|
||||
import com.jetbrains.cidr.project.workspace.CidrWorkspaceProvider
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigWorkspaceProvider: CidrWorkspaceProvider {
|
||||
override fun getWorkspace(project: Project): CidrWorkspace? {
|
||||
getExistingWorkspace(project)?.let { return it }
|
||||
|
||||
val projectDir = project.guessProjectDir()?.toNioPathOrNull() ?: return null
|
||||
try {
|
||||
Files.walk(projectDir).use { files ->
|
||||
if (files.anyMatch { it.fileName.pathString.let { it2 -> it2.endsWith(".zig") || it2.endsWith(".zig.zon") } }) {
|
||||
return ZigWorkspace(project)
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun loadWorkspace(project: Project) {
|
||||
if (getExistingWorkspace(project) != null)
|
||||
return
|
||||
val workspace = getWorkspace(project)
|
||||
if (workspace != null) {
|
||||
val manager = CidrWorkspaceManager.getInstance(project)
|
||||
manager.markInitializing(workspace)
|
||||
manager.markInitialized(workspace)
|
||||
manager.markLoading(workspace)
|
||||
manager.markLoaded(workspace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExistingWorkspace(project: Project): ZigWorkspace? {
|
||||
val workspaces = CidrWorkspaceManager.getInstance(project).workspaces.keys
|
||||
for (ws in workspaces)
|
||||
if (ws is ZigWorkspace)
|
||||
return ws
|
||||
|
||||
return null
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.clion
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebuggerDriverConfigurationProvider
|
||||
import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionGDBDriverConfiguration
|
||||
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionLLDBDriverConfiguration
|
||||
import com.jetbrains.cidr.cpp.toolchains.CPPDebugger
|
||||
import com.jetbrains.cidr.cpp.toolchains.CPPToolchains
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigClionDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfigurationProvider() {
|
||||
override suspend fun getDebuggerConfiguration(
|
||||
project: Project,
|
||||
isElevated: Boolean,
|
||||
emulateTerminal: Boolean
|
||||
): DebuggerDriverConfiguration? {
|
||||
if (SystemInfo.isWindows)
|
||||
return null
|
||||
|
||||
if (!ZigDebuggerSettings.instance.useClion)
|
||||
return null
|
||||
|
||||
val toolchains = CPPToolchains.getInstance()
|
||||
var toolchain = toolchains.getToolchainByNameOrDefault("Zig")
|
||||
if (toolchain == null || !toolchain.isDebuggerSupported) {
|
||||
LOG.info("Couldn't find debug-compatible C++ toolchain with name \"Zig\"")
|
||||
toolchain = toolchains.defaultToolchain
|
||||
}
|
||||
if (toolchain == null || !toolchain.isDebuggerSupported) {
|
||||
LOG.info("Couldn't find debug-compatible C++ default toolchain")
|
||||
return null
|
||||
}
|
||||
return when(toolchain.debuggerKind) {
|
||||
CPPDebugger.Kind.BUNDLED_GDB,
|
||||
CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
|
||||
CPPDebugger.Kind.BUNDLED_LLDB,
|
||||
CPPDebugger.Kind.CUSTOM_LLDB -> CLionLLDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LOG = logger<ZigClionDebuggerDriverConfigurationProvider>()
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugbridge
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
interface ZigDebuggerDriverConfigurationProviderBase {
|
||||
companion object {
|
||||
val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigDebuggerDriverConfigurationProviderBase>("com.falsepattern.zigbrains.debuggerDriverProvider")
|
||||
}
|
||||
suspend fun <T> getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean, klass: Class<T>): T?
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.shared.ZBFeatures
|
||||
|
||||
class DebuggerFeatures: ZBFeatures {
|
||||
override fun getDebug(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.intellij.DynamicBundle
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
import java.util.function.Supplier
|
||||
|
||||
|
||||
internal object ZigDebugBundle {
|
||||
@NonNls
|
||||
const val BUNDLE = "zigbrains.debugger.Bundle"
|
||||
|
||||
private val INSTANCE = DynamicBundle(ZigDebugBundle::class.java, BUNDLE)
|
||||
|
||||
fun message(
|
||||
key: @PropertyKey(resourceBundle = BUNDLE) String,
|
||||
vararg params: Any
|
||||
): @Nls String {
|
||||
return INSTANCE.getMessage(key, *params)
|
||||
}
|
||||
|
||||
fun lazyMessage(
|
||||
key: @PropertyKey(resourceBundle = BUNDLE) String,
|
||||
vararg params: Any
|
||||
): Supplier<@Nls String> {
|
||||
return INSTANCE.getLazyMessage(key, *params)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProviderBase
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
abstract class ZigDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfigurationProviderBase {
|
||||
final override suspend fun <T> getDebuggerConfiguration(
|
||||
project: Project,
|
||||
isElevated: Boolean,
|
||||
emulateTerminal: Boolean,
|
||||
klass: Class<T>
|
||||
): T? {
|
||||
if (klass != DebuggerDriverConfiguration::class.java)
|
||||
return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return getDebuggerConfiguration(project, isElevated, emulateTerminal) as T
|
||||
}
|
||||
protected abstract suspend fun getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean): DebuggerDriverConfiguration?
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.jetbrains.cidr.execution.debugger.CidrDebuggerEditorsExtensionBase
|
||||
|
||||
class ZigDebuggerEditorsExtension: CidrDebuggerEditorsExtensionBase() {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver.DebuggerLanguage
|
||||
|
||||
object ZigDebuggerLanguage: DebuggerLanguage {
|
||||
override fun toString(): String {
|
||||
return "Zig"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider
|
||||
import com.jetbrains.cidr.execution.debugger.CidrDebuggerLanguageSupport
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver
|
||||
|
||||
class ZigDebuggerLanguageSupport: CidrDebuggerLanguageSupport() {
|
||||
override fun getSupportedDebuggerLanguages(): Set<DebuggerDriver.DebuggerLanguage> {
|
||||
return setOf(ZigDebuggerLanguage)
|
||||
}
|
||||
|
||||
override fun createEditor(profile: RunProfile?): XDebuggerEditorsProvider? {
|
||||
if (profile !is ZigExecConfig<*>)
|
||||
return null
|
||||
return createEditorProvider()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.*
|
||||
import com.falsepattern.zigbrains.debugger.win.MSVCDriverConfiguration
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.falsepattern.zigbrains.zig.ZigLanguage
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DoNotAskOption
|
||||
import com.intellij.openapi.ui.MessageDialogBuilder
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.jetbrains.cidr.ArchitectureType
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
import com.jetbrains.cidr.execution.debugger.backend.gdb.GDBDriverConfiguration
|
||||
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration
|
||||
import java.io.File
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigDefaultDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfigurationProvider() {
|
||||
override suspend fun getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean): DebuggerDriverConfiguration? {
|
||||
val settings = ZigDebuggerSettings.instance
|
||||
val service = zigDebuggerToolchainService
|
||||
val kind = settings.debuggerKind
|
||||
if (!availabilityCheck(project, kind))
|
||||
return null
|
||||
|
||||
return when(val availability = service.debuggerAvailability(kind)) {
|
||||
DebuggerAvailability.Bundled -> when(kind) {
|
||||
DebuggerKind.LLDB -> ZigLLDBDriverConfiguration(isElevated, emulateTerminal)
|
||||
DebuggerKind.GDB -> ZigGDBDriverConfiguration(isElevated, emulateTerminal)
|
||||
DebuggerKind.MSVC -> throw AssertionError("MSVC is never bundled")
|
||||
}
|
||||
is DebuggerAvailability.Binaries -> when(val binary = availability.binaries) {
|
||||
is LLDBBinaries -> ZigCustomBinariesLLDBDriverConfiguration(binary, isElevated, emulateTerminal)
|
||||
is GDBBinaries -> ZigCustomBinariesGDBDriverConfiguration(binary, isElevated, emulateTerminal)
|
||||
is MSVCBinaries -> ZigMSVCDriverConfiguration(binary, isElevated, emulateTerminal)
|
||||
else -> throw AssertionError("Unreachable")
|
||||
}
|
||||
DebuggerAvailability.Unavailable,
|
||||
DebuggerAvailability.NeedToDownload,
|
||||
DebuggerAvailability.NeedToUpdate -> throw AssertionError("Unreachable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun availabilityCheck(project: Project, kind: DebuggerKind): Boolean {
|
||||
val service = zigDebuggerToolchainService
|
||||
val availability = service.debuggerAvailability(kind)
|
||||
val (message, action) = when(availability) {
|
||||
DebuggerAvailability.Unavailable -> return false
|
||||
DebuggerAvailability.NeedToDownload ->
|
||||
ZigDebugBundle.message("debugger.run.unavailable.reason.download") to ZigDebugBundle.message("debugger.run.unavailable.reason.download.button")
|
||||
DebuggerAvailability.NeedToUpdate ->
|
||||
ZigDebugBundle.message("debugger.run.unavailable.reason.update") to ZigDebugBundle.message("debugger.run.unavailable.reason.update.button")
|
||||
DebuggerAvailability.Bundled,
|
||||
is DebuggerAvailability.Binaries -> return true
|
||||
}
|
||||
|
||||
val downloadDebugger = if (!ZigDebuggerSettings.instance.downloadAutomatically) {
|
||||
showDialog(project, message, action)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
if (downloadDebugger) {
|
||||
val result = withEDTContext(ModalityState.any()) {
|
||||
service.downloadDebugger(project, kind)
|
||||
}
|
||||
if (result is ZigDebuggerToolchainService.DownloadResult.Ok) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private suspend fun showDialog(project: Project, message: String, action: String): Boolean {
|
||||
val doNotAsk = object: DoNotAskOption.Adapter() {
|
||||
override fun rememberChoice(isSelected: Boolean, exitCode: Int) {
|
||||
if (exitCode == Messages.OK) {
|
||||
ZigDebuggerSettings.instance.downloadAutomatically = isSelected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return withEDTContext(ModalityState.any()) {
|
||||
MessageDialogBuilder
|
||||
.okCancel(ZigDebugBundle.message("debugger.run.unavailable"), message)
|
||||
.yesText(action)
|
||||
.icon(Messages.getErrorIcon())
|
||||
.doNotAsk(doNotAsk)
|
||||
.ask(project)
|
||||
}
|
||||
}
|
||||
|
||||
private open class ZigLLDBDriverConfiguration(private val isElevated: Boolean, private val emulateTerminal: Boolean): LLDBDriverConfiguration() {
|
||||
override fun getDriverName() = "Zig LLDB"
|
||||
override fun isElevated() = isElevated
|
||||
override fun emulateTerminal() = emulateTerminal
|
||||
}
|
||||
private class ZigCustomBinariesLLDBDriverConfiguration(
|
||||
private val binaries: LLDBBinaries,
|
||||
isElevated: Boolean,
|
||||
emulateTerminal: Boolean
|
||||
) : ZigLLDBDriverConfiguration(isElevated, emulateTerminal) {
|
||||
override fun useSTLRenderers() = false
|
||||
override fun getLLDBFrameworkFile(architectureType: ArchitectureType): File = binaries.frameworkFile.toFile()
|
||||
override fun getLLDBFrontendFile(architectureType: ArchitectureType): File = binaries.frontendFile.toFile()
|
||||
}
|
||||
|
||||
private open class ZigGDBDriverConfiguration(private val isElevated: Boolean, private val emulateTerminal: Boolean): GDBDriverConfiguration() {
|
||||
override fun getDriverName() = "Zig GDB"
|
||||
override fun isAttachSupported() = false
|
||||
override fun isElevated() = isElevated
|
||||
override fun emulateTerminal() = emulateTerminal
|
||||
}
|
||||
private class ZigCustomBinariesGDBDriverConfiguration(
|
||||
private val binaries: GDBBinaries,
|
||||
isElevated: Boolean,
|
||||
emulateTerminal: Boolean
|
||||
) : ZigGDBDriverConfiguration(isElevated, emulateTerminal) {
|
||||
override fun getGDBExecutablePath() = binaries.gdbFile.pathString
|
||||
}
|
||||
|
||||
private class ZigMSVCDriverConfiguration(
|
||||
private val binaries: MSVCBinaries,
|
||||
private val isElevated: Boolean,
|
||||
private val emulateTerminal: Boolean
|
||||
): MSVCDriverConfiguration() {
|
||||
override val debuggerExecutable get() = binaries.msvcFile
|
||||
override fun getDriverName() = "Zig MSVC"
|
||||
override fun getConsoleLanguage() = ZigLanguage
|
||||
override fun isElevated() = isElevated
|
||||
override fun emulateTerminal() = emulateTerminal
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.zig.ZigFileType
|
||||
import com.intellij.openapi.fileTypes.FileType
|
||||
import com.jetbrains.cidr.execution.debugger.breakpoints.CidrLineBreakpointFileTypesProvider
|
||||
|
||||
class ZigLineBreakpointFileTypesProvider: CidrLineBreakpointFileTypesProvider {
|
||||
override fun getFileTypes(): Set<FileType> {
|
||||
return setOf(ZigFileType)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.intellij.execution.filters.Filter
|
||||
import com.intellij.execution.filters.TextConsoleBuilder
|
||||
import com.intellij.xdebugger.XDebugSession
|
||||
import com.jetbrains.cidr.execution.RunParameters
|
||||
import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess
|
||||
|
||||
class ZigLocalDebugProcess(parameters: RunParameters, session: XDebugSession, consoleBuilder: TextConsoleBuilder) : CidrLocalDebugProcess(parameters, session, consoleBuilder, { Filter.EMPTY_ARRAY }, true)
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger
|
||||
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.falsepattern.zigbrains.zig.ZigFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.jetbrains.cidr.execution.debugger.backend.LLValue
|
||||
import com.jetbrains.cidr.execution.debugger.evaluation.LocalVariablesFilterHandler
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.future.asCompletableFuture
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ZigLocalVariablesFilterHandler: LocalVariablesFilterHandler {
|
||||
override fun filterVars(proj: Project, pos: XSourcePosition, vars: List<LLValue>): CompletableFuture<List<LLValue>> {
|
||||
return proj.zigCoroutineScope.async {
|
||||
val vf = pos.file
|
||||
if (vf.fileType == ZigFileType) {
|
||||
return@async ArrayList(vars)
|
||||
}
|
||||
return@async listOf()
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
|
||||
override fun canFilterAtPos(proj: Project, pos: XSourcePosition): Boolean {
|
||||
return pos.file.fileType == ZigFileType
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.dap
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InterruptedIOException
|
||||
import java.io.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
|
||||
class BlockingPipedInputStream(src: PipedOutputStream, pipeSize: Int) : PipedInputStream(src, pipeSize) {
|
||||
var closed = false
|
||||
|
||||
@Synchronized
|
||||
override fun read(): Int {
|
||||
if (closed) {
|
||||
throw IOException("stream closed")
|
||||
} else {
|
||||
while (super.`in` < 0) {
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
this as java.lang.Object
|
||||
|
||||
this.notifyAll()
|
||||
|
||||
try {
|
||||
this.wait(750)
|
||||
} catch (e: InterruptedException) {
|
||||
throw InterruptedIOException()
|
||||
}
|
||||
}
|
||||
|
||||
val ret = buffer[this.out++].toUInt()
|
||||
if (this.out >= buffer.size) {
|
||||
this.out = 0
|
||||
}
|
||||
|
||||
if (this.`in` == this.out) {
|
||||
this.`in` = -1
|
||||
}
|
||||
|
||||
return ret.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
closed = true
|
||||
super.close()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.dap
|
||||
|
||||
import com.intellij.openapi.util.Expirable
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.util.UserDataHolderEx
|
||||
import com.jetbrains.cidr.execution.debugger.backend.*
|
||||
import org.eclipse.lsp4j.debug.InitializeRequestArguments
|
||||
|
||||
abstract class DAPDebuggerDriverConfiguration: DebuggerDriverConfiguration() {
|
||||
override fun createEvaluationContext(driver: DebuggerDriver, expirable: Expirable?, llThread: LLThread, llFrame: LLFrame, data: UserDataHolderEx): EvaluationContext {
|
||||
return object : EvaluationContext(driver, expirable, llThread, llFrame, data) {
|
||||
override fun convertToRValue(data: LLValueData, pair: Pair<LLValue, String>): String {
|
||||
return cast(pair.second, pair.first?.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun customizeInitializeArguments(initArgs: InitializeRequestArguments)
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.zigbrains.debugger.dap
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebuggerLanguage
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.findDocument
|
||||
import com.jetbrains.cidr.execution.debugger.backend.*
|
||||
import com.jetbrains.cidr.execution.debugger.memory.Address
|
||||
import com.jetbrains.cidr.execution.debugger.memory.AddressRange
|
||||
import org.eclipse.lsp4j.debug.*
|
||||
import java.nio.file.InvalidPathException
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object Util {
|
||||
fun threadJBFromDAP(DAPThread: Thread): LLThread {
|
||||
return LLThread(DAPThread.id.toLong(), null, null, DAPThread.name, null)
|
||||
}
|
||||
|
||||
fun threadDAPFromJB(JBThread: LLThread): Thread {
|
||||
val DAPThread = Thread()
|
||||
DAPThread.id = JBThread.getId().toInt()
|
||||
return DAPThread
|
||||
}
|
||||
|
||||
fun breakpointJBFromDAP(DAPBreakpoint: Breakpoint): LLBreakpoint {
|
||||
val source = DAPBreakpoint.source
|
||||
var sourcePath = if (source == null) "" else Objects.requireNonNullElseGet(
|
||||
source.path
|
||||
) { Objects.requireNonNullElse(source.origin, "unknown") }
|
||||
sourcePath = toJBPath(sourcePath)
|
||||
return LLBreakpoint(
|
||||
DAPBreakpoint.id,
|
||||
sourcePath,
|
||||
Objects.requireNonNullElse<Int>(DAPBreakpoint.line, 0) - 1,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
fun getLocation(DAPBreakpoint: Breakpoint): LLBreakpointLocation? {
|
||||
val ref = DAPBreakpoint.instructionReference ?: return null
|
||||
val addr = ref.substring(2).toLong(16)
|
||||
var fl: FileLocation? = null
|
||||
val src = DAPBreakpoint.source
|
||||
if (src != null) {
|
||||
fl = FileLocation(src.path, DAPBreakpoint.line)
|
||||
}
|
||||
return LLBreakpointLocation(DAPBreakpoint.id.toString() + "", Address.fromUnsignedLong(addr), fl)
|
||||
}
|
||||
|
||||
fun breakpointDAPFromJB(JBBreakpoint: LLBreakpoint): Breakpoint {
|
||||
val DAPBreakpoint = Breakpoint()
|
||||
DAPBreakpoint.id = JBBreakpoint.getId()
|
||||
DAPBreakpoint.line = JBBreakpoint.getOrigLine() + 1
|
||||
val source = Source()
|
||||
source.path = JBBreakpoint.getOrigFile()
|
||||
DAPBreakpoint.source = source
|
||||
DAPBreakpoint.message = JBBreakpoint.getCondition()
|
||||
return DAPBreakpoint
|
||||
}
|
||||
|
||||
fun moduleJBFromDAP(DAPModule: Module): LLModule {
|
||||
return LLModule(toJBPath(DAPModule.path))
|
||||
}
|
||||
|
||||
fun moduleDAPFromJB(JBModule: LLModule): Module {
|
||||
val DAPModule = Module()
|
||||
DAPModule.path = toJBPath(JBModule.path)
|
||||
DAPModule.name = JBModule.name
|
||||
return DAPModule
|
||||
}
|
||||
|
||||
fun frameJBFromDAP(
|
||||
DAPFrame: StackFrame,
|
||||
helperBreakpoint: DAPDriver.MappedBreakpoint?,
|
||||
modules: Map<Int, DAPDriver.MappedModule>
|
||||
): LLFrame {
|
||||
val ptr = parseAddress(DAPFrame.instructionPointerReference)
|
||||
val name = DAPFrame.name
|
||||
val inline = name.startsWith("[Inline Frame] ")
|
||||
val function = name.substring(name.indexOf('!') + 1, name.indexOf('('))
|
||||
val moduleID = DAPFrame.moduleId
|
||||
var moduleName: String? = null
|
||||
if (moduleID != null) {
|
||||
if (moduleID.isRight) {
|
||||
moduleName = moduleID.right
|
||||
} else {
|
||||
val module = modules[moduleID.left]!!
|
||||
moduleName = module.java.name
|
||||
}
|
||||
}
|
||||
var line = DAPFrame.line
|
||||
var sourcePath: String?
|
||||
run {
|
||||
val src = DAPFrame.source
|
||||
sourcePath = if (src == null) null else toJBPath(src.path)
|
||||
}
|
||||
if (helperBreakpoint != null) {
|
||||
if (line == 0) {
|
||||
line = helperBreakpoint.dap.line
|
||||
}
|
||||
if (sourcePath == null) {
|
||||
val src = helperBreakpoint.dap.source
|
||||
if (src != null) {
|
||||
sourcePath = toJBPath(src.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
return LLFrame(
|
||||
DAPFrame.id,
|
||||
function,
|
||||
sourcePath,
|
||||
null,
|
||||
line - 1,
|
||||
ptr,
|
||||
ZigDebuggerLanguage,
|
||||
false,
|
||||
inline,
|
||||
moduleName
|
||||
)
|
||||
}
|
||||
|
||||
fun toSource(path: String): Source {
|
||||
val src = Source()
|
||||
val absolute = Path.of(path).toAbsolutePath()
|
||||
src.name = absolute.fileName.toString()
|
||||
src.path = toWinPath(absolute.toString())
|
||||
return src
|
||||
}
|
||||
|
||||
fun toWinPath(path: String): String {
|
||||
return path.replace('/', '\\')
|
||||
}
|
||||
|
||||
fun toJBPath(path: String): String {
|
||||
return path.replace('\\', '/')
|
||||
}
|
||||
|
||||
fun parseAddressNullable(address: String?): Long? {
|
||||
if (address == null) return null
|
||||
return parseAddress(address)
|
||||
}
|
||||
|
||||
fun parseAddress(address: String?): Long {
|
||||
if (address == null) return 0L
|
||||
if (!address.startsWith("0x")) return java.lang.Long.parseUnsignedLong(address)
|
||||
return java.lang.Long.parseUnsignedLong(address.substring(2), 16)
|
||||
}
|
||||
|
||||
fun stringifyAddress(address: Long): String {
|
||||
return "0x" + java.lang.Long.toHexString(address)
|
||||
}
|
||||
|
||||
private val HEX_FIX_REGEX: Pattern = Pattern.compile("([0-9A-F]+)(?<!\\W)h")
|
||||
suspend fun instructionJBFromDAP(
|
||||
DAPInstruction: DisassembledInstruction,
|
||||
loc: Source?,
|
||||
startLineIn: Int?,
|
||||
endLineIn: Int?,
|
||||
uniq: Boolean,
|
||||
symbol: LLSymbolOffset?
|
||||
): LLInstruction {
|
||||
var startLine = startLineIn
|
||||
var endLine = endLineIn
|
||||
val address: Address = Address.parseHexString(DAPInstruction.address)
|
||||
val byteStrings =
|
||||
DAPInstruction.instructionBytes.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val bytes = ArrayList<Byte>(byteStrings.size)
|
||||
for (byteString in byteStrings) {
|
||||
bytes.add(byteString.toInt(16).toByte())
|
||||
}
|
||||
var comment: String? = null
|
||||
if (loc != null && startLine != null && endLine != null && uniq) run {
|
||||
val pathStr = toJBPath(loc.path)
|
||||
val path: Path
|
||||
try {
|
||||
path = Path.of(pathStr)
|
||||
} catch (ignored: InvalidPathException) {
|
||||
return@run
|
||||
}
|
||||
val text = readAction {
|
||||
val file = VfsUtil.findFile(path, true) ?: return@readAction null
|
||||
val doc: Document = file.findDocument() ?: return@readAction null
|
||||
doc.immutableCharSequence.toString().split("(\r\n|\r|\n)".toRegex()).dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()
|
||||
}
|
||||
if (text == null) return@run
|
||||
startLine -= 1
|
||||
endLine -= 1
|
||||
if (text.size <= endLine) return@run
|
||||
comment = text[endLine]
|
||||
}
|
||||
val nicerDisassembly = StringBuilder()
|
||||
val disassembly = DAPInstruction.instruction
|
||||
val matcher = HEX_FIX_REGEX.matcher(disassembly)
|
||||
var prevEnd = 0
|
||||
while (matcher.find()) {
|
||||
nicerDisassembly.append(disassembly, prevEnd, matcher.start())
|
||||
val hex = matcher.group(1).lowercase(Locale.getDefault())
|
||||
nicerDisassembly.append("0x").append(hex)
|
||||
prevEnd = matcher.end()
|
||||
}
|
||||
if (prevEnd < disassembly.length) nicerDisassembly.append(disassembly, prevEnd, disassembly.length)
|
||||
return LLInstruction.create(
|
||||
address,
|
||||
bytes,
|
||||
nicerDisassembly.toString(),
|
||||
comment,
|
||||
symbol
|
||||
)
|
||||
}
|
||||
|
||||
fun memoryJBFromDAP(DAPMemory: ReadMemoryResponse): LLMemoryHunk {
|
||||
val address = parseAddress(DAPMemory.address)
|
||||
val bytes = Base64.getDecoder().decode(DAPMemory.data)
|
||||
val range = AddressRange(
|
||||
Address.fromUnsignedLong(address),
|
||||
Address.fromUnsignedLong(address + bytes.size - 1)
|
||||
)
|
||||
return LLMemoryHunk(range, bytes)
|
||||
}
|
||||
|
||||
@Throws(com.intellij.execution.ExecutionException::class)
|
||||
fun <T> get(future: CompletableFuture<T>): T {
|
||||
try {
|
||||
return future[4, TimeUnit.SECONDS]
|
||||
} catch (e: InterruptedException) {
|
||||
throw com.intellij.execution.ExecutionException(e)
|
||||
} catch (e: TimeoutException) {
|
||||
throw com.intellij.execution.ExecutionException(e)
|
||||
} catch (e: ExecutionException) {
|
||||
throw com.intellij.execution.ExecutionException(e.cause)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.execution.binary
|
||||
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||
import com.intellij.execution.configurations.RunConfiguration
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigConfigTypeBinary: ConfigurationTypeBase(
|
||||
IDENTIFIER,
|
||||
ZigDebugBundle.message("configuration.binary.name"),
|
||||
ZigDebugBundle.message("configuration.binary.description"),
|
||||
Icons.Zig
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryBinary(this))
|
||||
}
|
||||
class ConfigFactoryBinary(type: ZigConfigTypeBinary): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigBinary(project, this)
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return IDENTIFIER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val IDENTIFIER = "ZIGBRAINS_BINARY"
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.execution.binary
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.*
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigExecConfigBinary(project: Project, factory: ConfigurationFactory) : ZigExecConfig<ZigExecConfigBinary>(project, factory, ZigDebugBundle.message("exec.type.binary.label")) {
|
||||
var exePath = FilePathConfigurable("exePath", ZigDebugBundle.message("exec.option.label.binary.exe-path"))
|
||||
private set
|
||||
var args = ArgsConfigurable("args", ZigDebugBundle.message("exec.option.label.binary.args"))
|
||||
private set
|
||||
|
||||
override val suggestedName: String
|
||||
get() = ZigDebugBundle.message("configuration.binary.suggested-name")
|
||||
|
||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||
return args.argsSplit()
|
||||
}
|
||||
|
||||
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||
return super.getConfigurables() + listOf(exePath, args)
|
||||
}
|
||||
|
||||
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigBinary> {
|
||||
return ZigProfileStateBinary(environment, this)
|
||||
}
|
||||
|
||||
override fun clone(): ZigExecConfigBinary {
|
||||
val clone = super.clone()
|
||||
clone.exePath = exePath.clone()
|
||||
clone.args = args.clone()
|
||||
return clone
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.execution.binary
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigProfileStateBinary(environment: ExecutionEnvironment, configuration: ZigExecConfigBinary) : ZigProfileState<ZigExecConfigBinary>(environment, configuration) {
|
||||
override suspend fun getCommandLine(toolchain: ZigToolchain, debug: Boolean): GeneralCommandLine {
|
||||
val cli = GeneralCommandLine()
|
||||
val cfg = configuration
|
||||
cfg.workingDirectory.path?.let { cli.withWorkingDirectory(it) }
|
||||
cli.withExePath(cfg.exePath.path?.pathString ?: throw ExecutionException(ZigDebugBundle.message("exception.missing-exe-path")))
|
||||
cli.withCharset(Charsets.UTF_8)
|
||||
cli.addParameters(cfg.args.args)
|
||||
return cli
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
|
||||
interface PreLaunchAware {
|
||||
@Throws(ExecutionException::class)
|
||||
suspend fun preLaunch(listener: PreLaunchProcessListener)
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.falsepattern.zigbrains.project.run.ZigProcessHandler
|
||||
import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.process.ProcessEvent
|
||||
import com.intellij.execution.process.ProcessHandler
|
||||
import com.intellij.execution.process.ProcessListener
|
||||
import com.intellij.execution.ui.ConsoleView
|
||||
import com.intellij.execution.ui.ConsoleViewContentType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.io.awaitExit
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
|
||||
var isBuildFailed: Boolean = false
|
||||
private set
|
||||
lateinit var processHandler: ZigProcessHandler.IPCAware
|
||||
private set
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
suspend fun executeCommandLineWithHook(project: Project, commandLine: GeneralCommandLine): Boolean {
|
||||
return withProgressText(commandLine.commandLineString) {
|
||||
val processHandler = commandLine.startIPCAwareProcess(project)
|
||||
this@PreLaunchProcessListener.processHandler = processHandler
|
||||
hook(processHandler)
|
||||
processHandler.startNotify()
|
||||
withContext(Dispatchers.IO) {
|
||||
processHandler.process.awaitExit()
|
||||
}
|
||||
runInterruptible {
|
||||
processHandler.waitFor()
|
||||
}
|
||||
return@withProgressText isBuildFailed
|
||||
}
|
||||
}
|
||||
|
||||
fun hook(handler: ProcessHandler) {
|
||||
console.attachToProcess(handler)
|
||||
handler.addProcessListener(this)
|
||||
}
|
||||
|
||||
override fun processTerminated(event: ProcessEvent) {
|
||||
if (event.exitCode != 0) {
|
||||
isBuildFailed = true
|
||||
} else {
|
||||
isBuildFailed = false
|
||||
console.print("Build Successful. Starting debug session. \n", ConsoleViewContentType.NORMAL_OUTPUT)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PtyCommandLine
|
||||
import com.jetbrains.cidr.execution.Installer
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.future.asCompletableFuture
|
||||
import java.io.File
|
||||
|
||||
class ZigDebugEmitBinaryInstaller<ProfileState: ZigProfileState<*>>(
|
||||
private val profileState: ProfileState,
|
||||
private val toolchain: ZigToolchain,
|
||||
private val executableFile: File,
|
||||
private val exeArgs: List<String>
|
||||
): Installer {
|
||||
override fun install(): GeneralCommandLine {
|
||||
val cfg = profileState.configuration
|
||||
val cli = PtyCommandLine().withConsoleMode(false).withExePath(executableFile.absolutePath)
|
||||
cfg.workingDirectory.path?.let { x -> cli.withWorkingDirectory(x) }
|
||||
cli.addParameters(exeArgs)
|
||||
cli.withCharset(Charsets.UTF_8)
|
||||
cli.withRedirectErrorStream(true)
|
||||
return profileState.configuration.project.zigCoroutineScope.async{
|
||||
profileState.configuration.patchCommandLine(cli)
|
||||
}.asCompletableFuture().join()
|
||||
}
|
||||
|
||||
override fun getExecutableFile(): File {
|
||||
return executableFile
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.intellij.util.system.CpuArch
|
||||
import com.jetbrains.cidr.ArchitectureType
|
||||
import com.jetbrains.cidr.execution.RunParameters
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
abstract class ZigDebugParametersBase<ProfileState: ZigProfileState<*>>(
|
||||
private val driverConfiguration: DebuggerDriverConfiguration,
|
||||
protected val toolchain: ZigToolchain,
|
||||
protected val profileState: ProfileState
|
||||
): RunParameters() {
|
||||
override fun getDebuggerDriverConfiguration(): DebuggerDriverConfiguration {
|
||||
return driverConfiguration
|
||||
}
|
||||
|
||||
override fun getArchitectureId(): String {
|
||||
return ArchitectureType.forVmCpuArch(CpuArch.CURRENT).id
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.containers.orNull
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.isExecutable
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
abstract class ZigDebugParametersEmitBinaryBase<ProfileState: ZigProfileState<*>>(
|
||||
driverConfiguration: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain,
|
||||
profileState: ProfileState,
|
||||
) : ZigDebugParametersBase<ProfileState>(driverConfiguration, toolchain, profileState), PreLaunchAware {
|
||||
@Volatile
|
||||
protected lateinit var executableFile: File
|
||||
private set
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
private suspend fun compileExe(listener: PreLaunchProcessListener): File {
|
||||
val commandLine = profileState.getCommandLine(toolchain, true)
|
||||
val cliString = commandLine.getCommandLineString(commandLine.exePath.toNioPathOrNull()?.fileName?.pathString)
|
||||
val tmpDir = FileUtil.createTempDirectory("zigbrains_debug", "", true).toPath()
|
||||
|
||||
val exe = tmpDir.resolve("executable")
|
||||
commandLine.addParameters("-femit-bin=${exe.absolutePathString()}")
|
||||
|
||||
if (listener.executeCommandLineWithHook(profileState.environment.project, commandLine))
|
||||
throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.generic", cliString))
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
Files.list(tmpDir).use { stream ->
|
||||
stream.filter { !it.fileName.endsWith(".o") }
|
||||
.filter { it.isExecutable() }
|
||||
.findFirst()
|
||||
.map { it.toFile() }
|
||||
.orNull()
|
||||
}
|
||||
} ?: throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.no-exe"))
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun preLaunch(listener: PreLaunchProcessListener) {
|
||||
this.executableFile = withProgressText("Compiling executable") {
|
||||
compileExe(listener)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.base
|
||||
|
||||
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProviderBase
|
||||
import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess
|
||||
import com.falsepattern.zigbrains.debugger.runner.build.ZigDebugRunnerBuild
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.run.ZigProgramRunner
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.shared.coroutine.runInterruptibleEDT
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.intellij.execution.DefaultExecutionResult
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.executors.DefaultDebugExecutor
|
||||
import com.intellij.execution.filters.Filter
|
||||
import com.intellij.execution.filters.TextConsoleBuilder
|
||||
import com.intellij.execution.process.ProcessTerminatedListener
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.execution.runners.RunContentBuilder
|
||||
import com.intellij.execution.ui.ConsoleView
|
||||
import com.intellij.execution.ui.ConsoleViewContentType
|
||||
import com.intellij.execution.ui.RunContentDescriptor
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.platform.util.progress.reportProgress
|
||||
import com.intellij.xdebugger.XDebugProcess
|
||||
import com.intellij.xdebugger.XDebugProcessStarter
|
||||
import com.intellij.xdebugger.XDebugSession
|
||||
import com.intellij.xdebugger.XDebuggerManager
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgramRunner<ProfileState>(DefaultDebugExecutor.EXECUTOR_ID) {
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun execute(
|
||||
state: ProfileState,
|
||||
toolchain: ZigToolchain,
|
||||
environment: ExecutionEnvironment
|
||||
): RunContentDescriptor? {
|
||||
val project = environment.project
|
||||
val driverProviders = ZigDebuggerDriverConfigurationProviderBase.EXTENSION_POINT_NAME.extensionList
|
||||
for (provider in driverProviders) {
|
||||
val driver = provider.getDebuggerConfiguration(project, isElevated = false, emulateTerminal = true, DebuggerDriverConfiguration::class.java) ?: continue
|
||||
return executeWithDriver(state, toolchain, environment, driver) ?: continue
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
private suspend fun executeWithDriver(
|
||||
state: ProfileState,
|
||||
toolchain: ZigToolchain,
|
||||
environment: ExecutionEnvironment,
|
||||
debuggerDriver: DebuggerDriverConfiguration
|
||||
): RunContentDescriptor? {
|
||||
return reportProgress { reporter ->
|
||||
val runParameters = getDebugParameters(state, debuggerDriver, toolchain)
|
||||
val console = state.consoleBuilder.console
|
||||
if (runParameters is PreLaunchAware) {
|
||||
val listener = PreLaunchProcessListener(console)
|
||||
try {
|
||||
reporter.indeterminateStep {
|
||||
runParameters.preLaunch(listener)
|
||||
}
|
||||
} catch (e: ExecutionException) {
|
||||
console.print("\n", ConsoleViewContentType.ERROR_OUTPUT)
|
||||
e.message?.let { listener.console.print(it, ConsoleViewContentType.ERROR_OUTPUT) }
|
||||
if (this !is ZigDebugRunnerBuild && environment.project.guessProjectDir()?.children?.any { it.name == "build.zig" } == true) {
|
||||
console.print("\n Warning: build.zig file detected in project.\n Did you want to use a Zig Build task instead?", ConsoleViewContentType.ERROR_OUTPUT)
|
||||
}
|
||||
}
|
||||
if (listener.isBuildFailed) {
|
||||
val executionResult = DefaultExecutionResult(console, listener.processHandler.unwrap())
|
||||
return@reportProgress withEDTContext(ModalityState.any()) {
|
||||
val runContentBuilder = RunContentBuilder(executionResult, environment)
|
||||
runContentBuilder.showRunContent(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@reportProgress runInterruptibleEDT(ModalityState.any()) {
|
||||
val debuggerManager = XDebuggerManager.getInstance(environment.project)
|
||||
debuggerManager.startSession(environment, object: XDebugProcessStarter() {
|
||||
override fun start(session: XDebugSession): XDebugProcess {
|
||||
val project = session.project
|
||||
val textConsoleBuilder = state.consoleBuilder
|
||||
val debugProcess = ZigLocalDebugProcess(runParameters, session, textConsoleBuilder)
|
||||
ProcessTerminatedListener.attach(debugProcess.processHandler, project)
|
||||
debugProcess.start()
|
||||
return debugProcess
|
||||
}
|
||||
}).runContentDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
protected abstract fun getDebugParameters(
|
||||
state: ProfileState,
|
||||
debuggerDriver: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain
|
||||
): ZigDebugParametersBase<ProfileState>
|
||||
|
||||
private class SharedConsoleBuilder(private val console: ConsoleView) : TextConsoleBuilder() {
|
||||
override fun getConsole(): ConsoleView {
|
||||
return console
|
||||
}
|
||||
|
||||
override fun addFilter(filter: Filter) {
|
||||
}
|
||||
|
||||
override fun setViewer(isViewer: Boolean) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.binary
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.debugger.execution.binary.ZigProfileStateBinary
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.jetbrains.cidr.execution.Installer
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
|
||||
class ZigDebugParametersBinary @Throws(ExecutionException::class) constructor(driverConfiguration: DebuggerDriverConfiguration, toolchain: ZigToolchain, profileState: ZigProfileStateBinary) :
|
||||
ZigDebugParametersBase<ZigProfileStateBinary>(driverConfiguration, toolchain, profileState) {
|
||||
private val executableFile = profileState.configuration.exePath.path?.toFile() ?: throw ExecutionException(ZigDebugBundle.message("exception.missing-exe-path"))
|
||||
override fun getInstaller(): Installer {
|
||||
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.args.argsSplit())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.binary
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.execution.binary.ZigExecConfigBinary
|
||||
import com.falsepattern.zigbrains.debugger.execution.binary.ZigProfileStateBinary
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugRunnerBinary: ZigDebugRunnerBase<ZigProfileStateBinary>() {
|
||||
override fun getDebugParameters(
|
||||
state: ZigProfileStateBinary,
|
||||
debuggerDriver: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain
|
||||
): ZigDebugParametersBase<ZigProfileStateBinary> {
|
||||
return ZigDebugParametersBinary(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
|
||||
}
|
||||
|
||||
override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateBinary? {
|
||||
return state as? ZigProfileStateBinary
|
||||
}
|
||||
|
||||
override fun canRun(executorId: String, profile: RunProfile): Boolean {
|
||||
return this.executorId == executorId && profile is ZigExecConfigBinary
|
||||
}
|
||||
|
||||
override fun getRunnerId(): String {
|
||||
return "ZigDebugRunnerBinary"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.build
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchAware
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchProcessListener
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.project.execution.build.ZigProfileStateBuild
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.jetbrains.cidr.execution.Installer
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.stream.Stream
|
||||
import kotlin.io.path.isExecutable
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
class ZigDebugParametersBuild(
|
||||
driverConfiguration: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain,
|
||||
profileState: ZigProfileStateBuild
|
||||
) : ZigDebugParametersBase<ZigProfileStateBuild>(driverConfiguration, toolchain, profileState), PreLaunchAware {
|
||||
@Volatile
|
||||
private lateinit var executableFile: File
|
||||
|
||||
override fun getInstaller(): Installer {
|
||||
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.argsSplit())
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun preLaunch(listener: PreLaunchProcessListener) {
|
||||
withProgressText("Building zig project") {
|
||||
withContext(Dispatchers.IO) {
|
||||
val commandLine = profileState.getCommandLine(toolchain, true)
|
||||
if (listener.executeCommandLineWithHook(profileState.environment.project, commandLine))
|
||||
return@withContext
|
||||
val cfg = profileState.configuration
|
||||
val workingDir = cfg.workingDirectory.path
|
||||
val exe = profileState.configuration.exePath.path ?: run {
|
||||
//Attempt autodetect, should work for trivial cases, and make most users happy, while advanced
|
||||
// users can use manual executable paths.
|
||||
if (workingDir == null) {
|
||||
fail("debug.build.compile.failed.no-workdir")
|
||||
}
|
||||
val expectedOutputDir = workingDir.resolve(Path.of("zig-out", "bin"))
|
||||
if (!expectedOutputDir.toFile().exists()) {
|
||||
fail("debug.build.compile.failed.autodetect")
|
||||
}
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
Files.list(expectedOutputDir).use { getExe(it) }
|
||||
}
|
||||
}
|
||||
|
||||
if (!exe.toFile().exists())
|
||||
fail("debug.build.compile.failed.no-file", exe)
|
||||
else if (!exe.isExecutable())
|
||||
fail("debug.build.compile.failed.non-exec-file", exe)
|
||||
|
||||
executableFile = exe.toFile()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
private fun getExe(files: Stream<Path>): Path {
|
||||
var fileStream = files.filter { it.isRegularFile() }
|
||||
if (SystemInfo.isWindows) {
|
||||
fileStream = fileStream.filter { it.fileName.endsWith(".exe") }
|
||||
} else {
|
||||
fileStream = fileStream.filter { it.isExecutable() }
|
||||
}
|
||||
val executables = fileStream.toList()
|
||||
return when(executables.size) {
|
||||
0 -> fail("debug.base.compile.failed.no-exe")
|
||||
1 -> executables[0]
|
||||
else -> fail("debug.build.compile.failed.multiple-exe")
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
private fun fail(@PropertyKey(resourceBundle = ZigDebugBundle.BUNDLE) messageKey: String, vararg params: Any): Nothing {
|
||||
throw ExecutionException(ZigDebugBundle.message("debug.build.compile.failed.boilerplate", ZigDebugBundle.message(messageKey, params)))
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.build
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild
|
||||
import com.falsepattern.zigbrains.project.execution.build.ZigProfileStateBuild
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugRunnerBuild: ZigDebugRunnerBase<ZigProfileStateBuild>() {
|
||||
override fun getDebugParameters(
|
||||
state: ZigProfileStateBuild,
|
||||
debuggerDriver: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain
|
||||
): ZigDebugParametersBase<ZigProfileStateBuild> {
|
||||
return ZigDebugParametersBuild(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
|
||||
}
|
||||
|
||||
override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateBuild? {
|
||||
return state as? ZigProfileStateBuild
|
||||
}
|
||||
|
||||
override fun canRun(executorId: String, profile: RunProfile): Boolean {
|
||||
return this.executorId == executorId && profile is ZigExecConfigBuild
|
||||
}
|
||||
|
||||
override fun getRunnerId(): String {
|
||||
return "ZigDebugRunnerBuild"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.run
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase
|
||||
import com.falsepattern.zigbrains.project.execution.run.ZigProfileStateRun
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.jetbrains.cidr.execution.Installer
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugParametersRun(driverConfiguration: DebuggerDriverConfiguration, toolchain: ZigToolchain, profileState: ZigProfileStateRun) :
|
||||
ZigDebugParametersEmitBinaryBase<ZigProfileStateRun>(driverConfiguration, toolchain, profileState) {
|
||||
override fun getInstaller(): Installer {
|
||||
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.argsSplit())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.run
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.execution.run.ZigExecConfigRun
|
||||
import com.falsepattern.zigbrains.project.execution.run.ZigProfileStateRun
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugRunnerRun: ZigDebugRunnerBase<ZigProfileStateRun>() {
|
||||
override fun getDebugParameters(
|
||||
state: ZigProfileStateRun,
|
||||
debuggerDriver: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain
|
||||
): ZigDebugParametersBase<ZigProfileStateRun> {
|
||||
return ZigDebugParametersRun(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
|
||||
}
|
||||
|
||||
override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateRun? {
|
||||
return state as? ZigProfileStateRun
|
||||
}
|
||||
|
||||
override fun canRun(executorId: String, profile: RunProfile): Boolean {
|
||||
return this.executorId == executorId && (profile is ZigExecConfigRun)
|
||||
}
|
||||
|
||||
override fun getRunnerId(): String {
|
||||
return "ZigDebugRunnerRun"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.test
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase
|
||||
import com.falsepattern.zigbrains.project.execution.test.ZigProfileStateTest
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.jetbrains.cidr.execution.Installer
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugParametersTest(driverConfiguration: DebuggerDriverConfiguration, toolchain: ZigToolchain, profileState: ZigProfileStateTest) :
|
||||
ZigDebugParametersEmitBinaryBase<ZigProfileStateTest>(driverConfiguration, toolchain, profileState) {
|
||||
override fun getInstaller(): Installer {
|
||||
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, listOf())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.runner.test
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
|
||||
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest
|
||||
import com.falsepattern.zigbrains.project.execution.test.ZigProfileStateTest
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
|
||||
|
||||
class ZigDebugRunnerTest: ZigDebugRunnerBase<ZigProfileStateTest>() {
|
||||
override fun getDebugParameters(
|
||||
state: ZigProfileStateTest,
|
||||
debuggerDriver: DebuggerDriverConfiguration,
|
||||
toolchain: ZigToolchain
|
||||
): ZigDebugParametersBase<ZigProfileStateTest> {
|
||||
return ZigDebugParametersTest(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
|
||||
}
|
||||
|
||||
override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateTest? {
|
||||
return state as? ZigProfileStateTest
|
||||
}
|
||||
|
||||
override fun canRun(executorId: String, profile: RunProfile): Boolean {
|
||||
return this.executorId == executorId && profile is ZigExecConfigTest
|
||||
}
|
||||
|
||||
override fun getRunnerId(): String {
|
||||
return "ZigDebugRunnerTest"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.settings
|
||||
|
||||
enum class MSVCDownloadPermission {
|
||||
AskMe,
|
||||
Allow,
|
||||
Deny
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.settings
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.options.ConfigurableUi
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import javax.swing.JComponent
|
||||
|
||||
class ZigDebuggerGeneralSettingsConfigurableUi: ConfigurableUi<ZigDebuggerSettings>, Disposable {
|
||||
private val components = listOf<ZigDebuggerUiComponent>(ZigDebuggerToolchainConfigurableUi()).onEach { Disposer.register(this, it) }
|
||||
|
||||
override fun reset(settings: ZigDebuggerSettings) {
|
||||
components.forEach { it.reset(settings) }
|
||||
}
|
||||
|
||||
override fun isModified(settings: ZigDebuggerSettings): Boolean {
|
||||
return components.any { it.isModified(settings) }
|
||||
}
|
||||
|
||||
override fun apply(settings: ZigDebuggerSettings) {
|
||||
components.forEach { it.apply(settings) }
|
||||
}
|
||||
|
||||
override fun getComponent(): JComponent {
|
||||
return panel {
|
||||
components.forEach { it.buildUi(this) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.settings
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import com.intellij.openapi.options.SimpleConfigurable
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import com.intellij.xdebugger.settings.DebuggerSettingsCategory
|
||||
import com.intellij.xdebugger.settings.XDebuggerSettings
|
||||
import java.util.function.Supplier
|
||||
|
||||
class ZigDebuggerSettings: XDebuggerSettings<ZigDebuggerSettings>("Zig") {
|
||||
var debuggerKind = DebuggerKind.default
|
||||
|
||||
var downloadAutomatically = false
|
||||
var useClion = true
|
||||
var msvcConsent = MSVCDownloadPermission.AskMe
|
||||
|
||||
override fun getState(): ZigDebuggerSettings {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun loadState(p0: ZigDebuggerSettings) {
|
||||
XmlSerializerUtil.copyBean(p0, this)
|
||||
}
|
||||
|
||||
override fun createConfigurables(category: DebuggerSettingsCategory): Collection<Configurable> {
|
||||
val configurable = when(category) {
|
||||
DebuggerSettingsCategory.GENERAL -> createGeneralSettingsConfigurable()
|
||||
else -> null
|
||||
}
|
||||
return configurable?.let { listOf(configurable) } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun createGeneralSettingsConfigurable(): Configurable {
|
||||
return SimpleConfigurable.create(
|
||||
GENERAL_SETTINGS_ID,
|
||||
ZigDebugBundle.message("settings.debugger.title"),
|
||||
ZigDebuggerGeneralSettingsConfigurableUi::class.java,
|
||||
Supplier {
|
||||
instance
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val instance: ZigDebuggerSettings get() = getInstance(ZigDebuggerSettings::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private const val GENERAL_SETTINGS_ID = "Debugger.Zig.General"
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.settings
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.zigDebuggerToolchainService
|
||||
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
||||
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.observable.util.whenItemSelected
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.dsl.builder.DEFAULT_COMMENT_WIDTH
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import javax.swing.ComboBoxModel
|
||||
import javax.swing.DefaultComboBoxModel
|
||||
import javax.swing.JEditorPane
|
||||
|
||||
class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent {
|
||||
private val debuggerKindComboBox = ComboBox(
|
||||
runModalOrBlocking({ ModalTaskOwner.guess() }, { "ZigDebuggerToolchainConfigurableUi" }) {
|
||||
createDebuggerKindComboBoxModel()
|
||||
}
|
||||
)
|
||||
private val downloadAutomaticallyCheckBox = JBCheckBox(
|
||||
ZigDebugBundle.message("settings.debugger.toolchain.download.debugger.automatically.checkbox"),
|
||||
ZigDebuggerSettings.instance.downloadAutomatically
|
||||
)
|
||||
|
||||
private val useClion = JBCheckBox(
|
||||
ZigDebugBundle.message("settings.debugger.toolchain.use.clion.toolchains"),
|
||||
ZigDebuggerSettings.instance.useClion
|
||||
)
|
||||
|
||||
private var comment: JEditorPane? = null
|
||||
|
||||
private val currentDebuggerKind get() = debuggerKindComboBox.item
|
||||
|
||||
override fun reset(settings: ZigDebuggerSettings) {
|
||||
debuggerKindComboBox.item = settings.debuggerKind
|
||||
downloadAutomaticallyCheckBox.isSelected = settings.downloadAutomatically
|
||||
useClion.isSelected = settings.useClion
|
||||
}
|
||||
|
||||
override fun isModified(settings: ZigDebuggerSettings): Boolean {
|
||||
return settings.debuggerKind != debuggerKindComboBox.item ||
|
||||
settings.downloadAutomatically != downloadAutomaticallyCheckBox.isSelected ||
|
||||
settings.useClion != useClion.isSelected
|
||||
}
|
||||
|
||||
override fun apply(settings: ZigDebuggerSettings) {
|
||||
settings.debuggerKind = debuggerKindComboBox.item
|
||||
settings.downloadAutomatically = downloadAutomaticallyCheckBox.isSelected
|
||||
settings.useClion = useClion.isSelected
|
||||
}
|
||||
|
||||
override fun buildUi(panel: Panel): Unit = with(panel) {
|
||||
row(ZigDebugBundle.message("settings.debugger.toolchain.debugger.label")) {
|
||||
comment = cell(debuggerKindComboBox)
|
||||
.comment("", DEFAULT_COMMENT_WIDTH) {
|
||||
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
|
||||
withModalProgress(ModalTaskOwner.component(debuggerKindComboBox), "Downloading debugger", TaskCancellation.cancellable()) {
|
||||
downloadDebugger()
|
||||
}
|
||||
}
|
||||
}
|
||||
.applyToComponent {
|
||||
whenItemSelected(null) {
|
||||
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
|
||||
this@ZigDebuggerToolchainConfigurableUi.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
.comment
|
||||
}
|
||||
row {
|
||||
cell(downloadAutomaticallyCheckBox)
|
||||
}
|
||||
if (PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.clion")) && !SystemInfo.isWindows) {
|
||||
row {
|
||||
cell(useClion)
|
||||
}
|
||||
}
|
||||
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
|
||||
update()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private suspend fun downloadDebugger() {
|
||||
val result = zigDebuggerToolchainService.downloadDebugger(null, currentDebuggerKind)
|
||||
if (result is ZigDebuggerToolchainService.DownloadResult.Ok) {
|
||||
update()
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private suspend fun update() {
|
||||
val availability = zigDebuggerToolchainService.debuggerAvailability(currentDebuggerKind)
|
||||
val text = when (availability) {
|
||||
is DebuggerAvailability.NeedToDownload -> ZigDebugBundle.message("settings.debugger.toolchain.download.comment")
|
||||
is DebuggerAvailability.NeedToUpdate -> ZigDebugBundle.message("settings.debugger.toolchain.update.comment")
|
||||
else -> null
|
||||
}
|
||||
comment?.let {
|
||||
it.text = text
|
||||
it.isVisible = text != null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private suspend fun createDebuggerKindComboBoxModel(): ComboBoxModel<DebuggerKind> {
|
||||
val toolchainService = zigDebuggerToolchainService
|
||||
val availableKinds = DebuggerKind.entries.filter { toolchainService.debuggerAvailability(it) !is DebuggerAvailability.Unavailable }
|
||||
return DefaultComboBoxModel(availableKinds.toTypedArray()).also { it.selectedItem = ZigDebuggerSettings.instance.debuggerKind }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.settings
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.options.ConfigurableUi
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import javax.swing.JComponent
|
||||
|
||||
interface ZigDebuggerUiComponent: ConfigurableUi<ZigDebuggerSettings>, Disposable {
|
||||
fun buildUi(panel: Panel)
|
||||
|
||||
override fun getComponent(): JComponent {
|
||||
return panel {
|
||||
buildUi(this)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.toolchain
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
sealed class DebuggerAvailability<out T> {
|
||||
data object Unavailable: DebuggerAvailability<Nothing>()
|
||||
data object NeedToDownload: DebuggerAvailability<Nothing>()
|
||||
data object NeedToUpdate: DebuggerAvailability<Nothing>()
|
||||
data object Bundled: DebuggerAvailability<Nothing>()
|
||||
data class Binaries<T> (val binaries: T): DebuggerAvailability<T>()
|
||||
}
|
||||
|
||||
data class LLDBBinaries(val frameworkFile: Path, val frontendFile: Path)
|
||||
data class GDBBinaries(val gdbFile: Path)
|
||||
data class MSVCBinaries(val msvcFile: Path)
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.toolchain
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
|
||||
enum class DebuggerKind {
|
||||
LLDB,
|
||||
GDB,
|
||||
MSVC;
|
||||
|
||||
companion object {
|
||||
val default get() = if (SystemInfo.isWindows) MSVC else LLDB
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.toolchain
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.debugger.settings.MSVCDownloadPermission
|
||||
import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings
|
||||
import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService.Companion.downloadPath
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withCurrentEDTModalityContext
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.progress.coroutineToIndicator
|
||||
import com.intellij.openapi.ui.DialogBuilder
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.ui.components.JBPanel
|
||||
import com.intellij.util.download.DownloadableFileService
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import javax.swing.BoxLayout
|
||||
|
||||
private val mutex = Mutex()
|
||||
private var cache: Properties? = null
|
||||
|
||||
suspend fun msvcMetadata(): Properties {
|
||||
cache?.let { return it }
|
||||
mutex.withLock {
|
||||
cache?.let { return it }
|
||||
val settings = ZigDebuggerSettings.instance
|
||||
var permission = settings.msvcConsent
|
||||
if (permission == MSVCDownloadPermission.AskMe) {
|
||||
val allowDownload = withCurrentEDTModalityContext {
|
||||
val dialog = DialogBuilder()
|
||||
dialog.setTitle(ZigDebugBundle.message("msvc.consent.title"))
|
||||
dialog.addCancelAction().setText(ZigDebugBundle.message("msvc.consent.deny"))
|
||||
dialog.addOkAction().setText(ZigDebugBundle.message("msvc.consent.allow"))
|
||||
val centerPanel = JBPanel<JBPanel<*>>()
|
||||
centerPanel.setLayout(BoxLayout(centerPanel, BoxLayout.Y_AXIS))
|
||||
val lines = ZigDebugBundle.message("msvc.consent.body").split('\n')
|
||||
for (line in lines) {
|
||||
centerPanel.add(JBLabel(line))
|
||||
}
|
||||
dialog.centerPanel(centerPanel)
|
||||
dialog.showAndGet()
|
||||
}
|
||||
permission = if (allowDownload) MSVCDownloadPermission.Allow else MSVCDownloadPermission.Deny
|
||||
settings.msvcConsent = permission
|
||||
}
|
||||
val data = if (permission == MSVCDownloadPermission.Allow) {
|
||||
withTimeoutOrNull(3000L) {
|
||||
downloadMSVCProps()
|
||||
} ?: run {
|
||||
Notification(
|
||||
"zigbrains",
|
||||
ZigDebugBundle.message("notification.title.debugger"),
|
||||
ZigDebugBundle.message("notification.content.debugger.metadata.downloading.failed"),
|
||||
NotificationType.ERROR
|
||||
).notify(null)
|
||||
fetchBuiltinMSVCProps()
|
||||
}
|
||||
} else {
|
||||
fetchBuiltinMSVCProps()
|
||||
}
|
||||
cache = data
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun downloadMSVCProps(): Properties {
|
||||
return withProgressText("Downloading debugger metadata") {
|
||||
val service = DownloadableFileService.getInstance()
|
||||
val desc = service.createFileDescription("https://falsepattern.com/zigbrains/msvc.properties", "msvc.properties")
|
||||
val downloader = service.createDownloader(listOf(desc), "Debugger metadata downloading")
|
||||
val downloadDirectory = downloadPath().toFile()
|
||||
val prop = Properties()
|
||||
val downloadResults = coroutineToIndicator {
|
||||
downloader.download(downloadDirectory)
|
||||
}
|
||||
for (result in downloadResults) {
|
||||
if (result.second.defaultFileName == "msvc.properties") {
|
||||
result.first.reader().use { prop.load(it) }
|
||||
}
|
||||
}
|
||||
return@withProgressText prop
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchBuiltinMSVCProps(): Properties {
|
||||
val prop = Properties()
|
||||
try {
|
||||
val resource = ZigDebuggerToolchainService::class.java.getResourceAsStream("/msvc.properties") ?: throw IOException("null")
|
||||
resource.reader().use { prop.load(it) }
|
||||
} catch (ex: IOException) {
|
||||
ex.printStackTrace()
|
||||
Notification(
|
||||
"zigbrains",
|
||||
ZigDebugBundle.message("notification.title.debugger"),
|
||||
ZigDebugBundle.message("notification.content.debugger.metadata.fallback.parse.failed"),
|
||||
NotificationType.ERROR
|
||||
).notify(null)
|
||||
}
|
||||
return prop
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.toolchain
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.ZigDebugBundle
|
||||
import com.falsepattern.zigbrains.shared.Unarchiver
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.progress.coroutineToIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogBuilder
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.platform.util.progress.reportSequentialProgress
|
||||
import com.intellij.ui.BrowserHyperlinkListener
|
||||
import com.intellij.ui.HyperlinkLabel
|
||||
import com.intellij.ui.components.JBPanel
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import com.intellij.util.download.DownloadableFileService
|
||||
import com.intellij.util.system.CpuArch
|
||||
import com.intellij.util.system.OS
|
||||
import com.jetbrains.cidr.execution.debugger.CidrDebuggerPathManager
|
||||
import com.jetbrains.cidr.execution.debugger.backend.bin.UrlProvider
|
||||
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import kotlin.io.path.name
|
||||
|
||||
@Service
|
||||
class ZigDebuggerToolchainService {
|
||||
suspend fun debuggerAvailability(kind: DebuggerKind): DebuggerAvailability<*> {
|
||||
return when(kind) {
|
||||
DebuggerKind.LLDB -> lldbAvailability()
|
||||
DebuggerKind.GDB -> gdbAvailability()
|
||||
DebuggerKind.MSVC -> msvcAvailability()
|
||||
}
|
||||
}
|
||||
|
||||
fun lldbAvailability(): DebuggerAvailability<LLDBBinaries> {
|
||||
if (LLDBDriverConfiguration.hasBundledLLDB()) return DebuggerAvailability.Bundled
|
||||
|
||||
val (frameworkPath, frontendPath) = when {
|
||||
SystemInfo.isMac -> "LLDB.framework" to "LLDBFrontend"
|
||||
SystemInfo.isUnix -> "lib/liblldb.so" to "bin/LLDBFrontend"
|
||||
// SystemInfo.isWindows -> "bin/liblldb.dll" to "bin/LLDBFrontend.exe"
|
||||
else -> return DebuggerAvailability.Unavailable
|
||||
}
|
||||
|
||||
val lldbPath = lldbPath()
|
||||
val frameworkFile = lldbPath.resolve(frameworkPath)
|
||||
val frontendFile = lldbPath.resolve(frontendPath)
|
||||
if (!frameworkFile.toFile().exists() || !frontendFile.toFile().exists()) return DebuggerAvailability.NeedToDownload
|
||||
|
||||
val versions = loadDebuggerVersions(DebuggerKind.LLDB)
|
||||
val (lldbFrameworkUrl, lldbFrontendUrl) = lldbUrls() ?: return DebuggerAvailability.Unavailable
|
||||
|
||||
val lldbFrameworkVersion = fileNameWithoutExtension(lldbFrameworkUrl.toString())
|
||||
val lldbFrontendVersion = fileNameWithoutExtension(lldbFrontendUrl.toString())
|
||||
|
||||
if (versions[LLDB_FRAMEWORK_PROPERTY_NAME] != lldbFrameworkVersion ||
|
||||
versions[LLDB_FRONTEND_PROPERTY_NAME] != lldbFrontendVersion) return DebuggerAvailability.NeedToUpdate
|
||||
|
||||
return DebuggerAvailability.Binaries(LLDBBinaries(frameworkFile, frontendFile))
|
||||
}
|
||||
|
||||
fun gdbAvailability(): DebuggerAvailability<GDBBinaries> {
|
||||
if (SystemInfo.isMac) return DebuggerAvailability.Unavailable
|
||||
if (CidrDebuggerPathManager.getBundledGDBBinary().exists()) return DebuggerAvailability.Bundled
|
||||
|
||||
val gdbBinaryPath = when {
|
||||
SystemInfo.isUnix -> "bin/gdb"
|
||||
// SystemInfo.isWindows -> "bin/gdb.exe"
|
||||
else -> return DebuggerAvailability.Unavailable
|
||||
}
|
||||
|
||||
val gdbFile = gdbPath().resolve(gdbBinaryPath)
|
||||
if (!gdbFile.toFile().exists()) return DebuggerAvailability.NeedToDownload
|
||||
|
||||
val versions = loadDebuggerVersions(DebuggerKind.GDB)
|
||||
val gdbUrl = gdbUrl() ?: return DebuggerAvailability.Unavailable
|
||||
|
||||
val gdbVersion = fileNameWithoutExtension(gdbUrl.toString())
|
||||
|
||||
if (versions[GDB_PROPERTY_NAME] != gdbVersion) return DebuggerAvailability.NeedToUpdate
|
||||
|
||||
return DebuggerAvailability.Binaries(GDBBinaries(gdbFile))
|
||||
}
|
||||
|
||||
suspend fun msvcAvailability(): DebuggerAvailability<MSVCBinaries> {
|
||||
if (!SystemInfo.isWindows) return DebuggerAvailability.Unavailable
|
||||
|
||||
val msvcBinaryPath = "vsdbg.exe"
|
||||
|
||||
val msvcFile = msvcPath().resolve(msvcBinaryPath)
|
||||
if (!msvcFile.toFile().exists()) return DebuggerAvailability.NeedToDownload
|
||||
|
||||
val msvcUrl = msvcUrl() ?: return DebuggerAvailability.Binaries(MSVCBinaries(msvcFile))
|
||||
|
||||
val versions = loadDebuggerVersions(DebuggerKind.MSVC)
|
||||
|
||||
if (versions[MSVC_PROPERTY_NAME] != msvcUrl.version) return DebuggerAvailability.NeedToUpdate
|
||||
|
||||
return DebuggerAvailability.Binaries(MSVCBinaries(msvcFile))
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
private suspend fun doDownloadDebugger(debuggerKind: DebuggerKind): DownloadResult {
|
||||
val baseDir = debuggerKind.basePath()
|
||||
val downloadableBinaries = when(debuggerKind) {
|
||||
DebuggerKind.LLDB -> {
|
||||
val (lldbFrameworkUrl, lldbFrontendUrl) = lldbUrls()?.run { first.toString() to second.toString() } ?: return DownloadResult.NoUrls
|
||||
listOf(
|
||||
DownloadableDebuggerBinary(lldbFrameworkUrl, LLDB_FRAMEWORK_PROPERTY_NAME, fileNameWithoutExtension(lldbFrameworkUrl)),
|
||||
DownloadableDebuggerBinary(lldbFrontendUrl, LLDB_FRONTEND_PROPERTY_NAME, fileNameWithoutExtension(lldbFrontendUrl))
|
||||
)
|
||||
}
|
||||
DebuggerKind.GDB -> {
|
||||
val gdbUrl = gdbUrl()?.run { toString() } ?: return DownloadResult.NoUrls
|
||||
listOf(DownloadableDebuggerBinary(gdbUrl, GDB_PROPERTY_NAME, fileNameWithoutExtension(gdbUrl)))
|
||||
}
|
||||
DebuggerKind.MSVC -> {
|
||||
val msvcUrl = msvcUrl() ?: return DownloadResult.NoUrls
|
||||
|
||||
val dialog = DialogBuilder()
|
||||
dialog.setTitle(msvcUrl.dialogTitle)
|
||||
dialog.addCancelAction().setText("Reject")
|
||||
dialog.addOkAction().setText("Accept")
|
||||
val centerPanel = JBPanel<JBPanel<*>>()
|
||||
val hyperlink = HyperlinkLabel()
|
||||
hyperlink.setTextWithHyperlink(msvcUrl.dialogBody)
|
||||
hyperlink.setHyperlinkTarget(msvcUrl.dialogLink)
|
||||
hyperlink.addHyperlinkListener(BrowserHyperlinkListener())
|
||||
centerPanel.add(hyperlink)
|
||||
dialog.centerPanel(centerPanel)
|
||||
if (!dialog.showAndGet()) return DownloadResult.NoUrls
|
||||
|
||||
listOf(DownloadableDebuggerBinary(msvcUrl.url, MSVC_PROPERTY_NAME, msvcUrl.version, "extension/debugAdapters/vsdbg/bin"))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
downloadAndUnArchive(baseDir, downloadableBinaries)
|
||||
}
|
||||
return DownloadResult.Ok(baseDir)
|
||||
} catch (e: IOException) {
|
||||
//TODO logging
|
||||
e.printStackTrace()
|
||||
return DownloadResult.Failed(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresEdt
|
||||
suspend fun downloadDebugger(project: Project? = null, debuggerKind: DebuggerKind): DownloadResult {
|
||||
val result = doDownloadDebugger(debuggerKind)
|
||||
|
||||
when(result) {
|
||||
is DownloadResult.Ok -> {
|
||||
Notification(
|
||||
"zigbrains",
|
||||
ZigDebugBundle.message("notification.title.debugger"),
|
||||
ZigDebugBundle.message("notification.content.debugger.successfully.downloaded"),
|
||||
NotificationType.INFORMATION
|
||||
).notify(project)
|
||||
}
|
||||
is DownloadResult.Failed -> {
|
||||
Notification(
|
||||
"zigbrains",
|
||||
ZigDebugBundle.message("notification.title.debugger"),
|
||||
ZigDebugBundle.message("notification.content.debugger.downloading.failed"),
|
||||
NotificationType.ERROR
|
||||
).notify(project)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@RequiresEdt
|
||||
private suspend fun downloadAndUnArchive(baseDir: Path, binariesToDownload: List<DownloadableDebuggerBinary>) {
|
||||
reportSequentialProgress { reporter ->
|
||||
val service = DownloadableFileService.getInstance()
|
||||
|
||||
val downloadDir = baseDir.toFile()
|
||||
downloadDir.deleteRecursively()
|
||||
|
||||
val descriptions = binariesToDownload.map {
|
||||
service.createFileDescription(it.url, fileName(it.url))
|
||||
}
|
||||
|
||||
val downloader = service.createDownloader(descriptions, "Debugger downloading")
|
||||
val downloadDirectory = downloadPath().toFile()
|
||||
val downloadResults = reporter.sizedStep(100) {
|
||||
coroutineToIndicator {
|
||||
downloader.download(downloadDirectory)
|
||||
}
|
||||
}
|
||||
val versions = Properties()
|
||||
for (result in downloadResults) {
|
||||
val downloadUrl = result.second.downloadUrl
|
||||
val binaryToDownload = binariesToDownload.first { it.url == downloadUrl }
|
||||
val propertyName = binaryToDownload.propertyName
|
||||
val archiveFile = result.first
|
||||
reporter.indeterminateStep {
|
||||
coroutineToIndicator {
|
||||
Unarchiver.unarchive(archiveFile.toPath(), baseDir, binaryToDownload.prefix)
|
||||
}
|
||||
}
|
||||
archiveFile.delete()
|
||||
versions[propertyName] = binaryToDownload.version
|
||||
}
|
||||
|
||||
saveVersionsFile(baseDir, versions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lldbUrls(): Pair<URL, URL>? {
|
||||
val lldb = UrlProvider.lldb(OS.CURRENT, CpuArch.CURRENT) ?: return null
|
||||
val lldbFrontend = UrlProvider.lldbFrontend(OS.CURRENT, CpuArch.CURRENT) ?: return null
|
||||
return lldb to lldbFrontend
|
||||
}
|
||||
|
||||
private fun gdbUrl(): URL? = UrlProvider.gdb(OS.CURRENT, CpuArch.CURRENT)
|
||||
|
||||
private suspend fun msvcUrl(): MSVCUrl? {
|
||||
val dlKey = when(CpuArch.CURRENT) {
|
||||
CpuArch.X86 -> "downloadX86"
|
||||
CpuArch.X86_64 -> "downloadX86_64"
|
||||
CpuArch.ARM64 -> "downloadARM64"
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val props = msvcMetadata()
|
||||
val version = props.getProperty("version") ?: return null
|
||||
val url = props.getProperty(dlKey) ?: return null
|
||||
return MSVCUrl(url, version, props.getProperty("dialogTitle")!!, props.getProperty("dialogBody")!!, props.getProperty("dialogLink")!!)
|
||||
}
|
||||
|
||||
private data class MSVCUrl(
|
||||
val url: String,
|
||||
val version: String,
|
||||
val dialogTitle: String,
|
||||
val dialogBody: String,
|
||||
val dialogLink: String
|
||||
)
|
||||
|
||||
private fun loadDebuggerVersions(kind: DebuggerKind): Properties = loadVersions(kind.basePath())
|
||||
|
||||
private fun saveVersionsFile(basePath: Path, versions: Properties) {
|
||||
val file = basePath.resolve(DEBUGGER_VERSIONS).toFile()
|
||||
try {
|
||||
versions.store(file.bufferedWriter(), "")
|
||||
} catch (e: IOException) {
|
||||
LOG.warn("Failed to save `${basePath.name}/${file.name}`", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadVersions(basePath: Path): Properties {
|
||||
val versions = Properties()
|
||||
val versionsFile = basePath.resolve(DEBUGGER_VERSIONS).toFile()
|
||||
|
||||
if (versionsFile.exists()) {
|
||||
try {
|
||||
versionsFile.bufferedReader().use { versions.load(it) }
|
||||
} catch (e: IOException) {
|
||||
LOG.warn("Failed to load `${basePath.name}/${versionsFile.name}`", e)
|
||||
}
|
||||
}
|
||||
|
||||
return versions
|
||||
}
|
||||
|
||||
private fun DebuggerKind.basePath(): Path {
|
||||
return when(this) {
|
||||
DebuggerKind.LLDB -> lldbPath()
|
||||
DebuggerKind.GDB -> gdbPath()
|
||||
DebuggerKind.MSVC -> msvcPath()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = logger<ZigDebuggerToolchainService>()
|
||||
|
||||
private const val DEBUGGER_VERSIONS: String = "versions.properties"
|
||||
|
||||
private const val LLDB_FRONTEND_PROPERTY_NAME = "lldbFrontend"
|
||||
private const val LLDB_FRAMEWORK_PROPERTY_NAME = "lldbFramework"
|
||||
private const val GDB_PROPERTY_NAME = "gdb"
|
||||
private const val MSVC_PROPERTY_NAME = "msvc"
|
||||
|
||||
fun downloadPath() = tempPluginDir
|
||||
private fun lldbPath() = pluginDir.resolve("lldb")
|
||||
private fun gdbPath() = pluginDir.resolve("gdb")
|
||||
private fun msvcPath() = pluginDir.resolve("msvc")
|
||||
|
||||
private val pluginDir get() = PathManager.getSystemDir().resolve("zigbrains")
|
||||
|
||||
private val tempPluginDir get(): Path = PathManager.getTempPath().toNioPathOrNull()!!.resolve("zigbrains")
|
||||
|
||||
private fun fileNameWithoutExtension(url: String): String {
|
||||
return url.substringAfterLast("/").removeSuffix(".zip").removeSuffix(".tar.gz")
|
||||
}
|
||||
|
||||
private fun fileName(url: String): String {
|
||||
return url.substringAfterLast("/")
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DownloadResult {
|
||||
class Ok(val baseDir: Path): DownloadResult()
|
||||
data object NoUrls: DownloadResult()
|
||||
class Failed(val message: String?): DownloadResult()
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
private data class DownloadableDebuggerBinary(val url: String, val propertyName: String, val version: String, val prefix: String? = null)
|
||||
}
|
||||
|
||||
val zigDebuggerToolchainService get() = application.service<ZigDebuggerToolchainService>()
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.win
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.dap.DAPDebuggerDriverConfiguration
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.jetbrains.cidr.ArchitectureType
|
||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver
|
||||
import org.eclipse.lsp4j.debug.InitializeRequestArguments
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
abstract class MSVCDriverConfiguration: DAPDebuggerDriverConfiguration() {
|
||||
protected abstract val debuggerExecutable: Path
|
||||
|
||||
override fun createDriver(handler: DebuggerDriver.Handler, arch: ArchitectureType): DebuggerDriver {
|
||||
return WinDAPDriver(handler).also { it.initialize(this) }
|
||||
}
|
||||
|
||||
override fun createDriverCommandLine(driver: DebuggerDriver, arch: ArchitectureType): GeneralCommandLine {
|
||||
val path = debuggerExecutable
|
||||
val cli = GeneralCommandLine()
|
||||
cli.withExePath(path.pathString)
|
||||
cli.addParameters("--interpreter=vscode", "--extconfigdir=%USERPROFILE%\\.cppvsdbg\\extensions")
|
||||
cli.withWorkingDirectory(path.parent)
|
||||
return cli
|
||||
}
|
||||
|
||||
override fun customizeInitializeArguments(initArgs: InitializeRequestArguments) {
|
||||
initArgs.pathFormat = "path"
|
||||
initArgs.adapterID = "cppvsdbg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.debugger.win
|
||||
|
||||
import com.falsepattern.zigbrains.debugger.dap.DAPDriver
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.util.system.CpuArch
|
||||
import com.jetbrains.cidr.ArchitectureType
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.future.asCompletableFuture
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import org.eclipse.lsp4j.debug.Capabilities
|
||||
import org.eclipse.lsp4j.debug.OutputEventArguments
|
||||
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
|
||||
import org.eclipse.lsp4j.debug.util.ToStringBuilder
|
||||
import org.eclipse.lsp4j.jsonrpc.MessageConsumer
|
||||
import org.eclipse.lsp4j.jsonrpc.debug.messages.DebugResponseMessage
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Message
|
||||
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.zip.Inflater
|
||||
|
||||
class WinDAPDriver(handler: Handler) : DAPDriver<IDebugProtocolServer, WinDAPDriver.WinDAPDebuggerClient>(handler) {
|
||||
private val handshakeFinished = Semaphore(1, 1)
|
||||
|
||||
override fun createDebuggerClient(): WinDAPDebuggerClient {
|
||||
return WinDAPDebuggerClient()
|
||||
}
|
||||
|
||||
override fun getServerInterface(): Class<IDebugProtocolServer> {
|
||||
return IDebugProtocolServer::class.java
|
||||
}
|
||||
|
||||
override fun wrapMessageConsumer(mc: MessageConsumer): MessageConsumer {
|
||||
return object: MessageConsumer {
|
||||
private var verifyHandshake = true
|
||||
override fun consume(message: Message) {
|
||||
if (verifyHandshake && message is DebugResponseMessage && message.method == "handshake") {
|
||||
verifyHandshake = false
|
||||
message.setResponseId(1)
|
||||
}
|
||||
mc.consume(message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun postInitialize(capabilities: Capabilities) {
|
||||
handshakeFinished.acquire()
|
||||
}
|
||||
|
||||
inner class WinDAPDebuggerClient: DAPDriver<IDebugProtocolServer, WinDAPDebuggerClient>.DAPDebuggerClient() {
|
||||
override fun output(args: OutputEventArguments) {
|
||||
if ("telemetry" == args.category)
|
||||
return
|
||||
|
||||
super.output(args)
|
||||
}
|
||||
|
||||
@JsonRequest
|
||||
fun handshake(handshake: HandshakeRequest): CompletableFuture<HandshakeResponse> {
|
||||
return zigCoroutineScope.async(Dispatchers.IO) {
|
||||
handshakeSuspend(handshake)
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
|
||||
private fun handshakeSuspend(handshake: HandshakeRequest): HandshakeResponse {
|
||||
val hasher = MessageDigest.getInstance("SHA-256")
|
||||
hasher.update(handshake.value.encodeToByteArray())
|
||||
val inflater = Inflater(true)
|
||||
val coconut = DAPDebuggerClient::class.java.getResourceAsStream("/coconut.jpg")?.use(InputStream::readAllBytes) ?: throw RuntimeException("No coconut")
|
||||
inflater.setInput(coconut, coconut.size - 80, 77)
|
||||
inflater.finished()
|
||||
val b = ByteArray(1)
|
||||
while (inflater.inflate(b) > 0)
|
||||
hasher.update(b)
|
||||
val result = HandshakeResponse(String(coconut, coconut.size - 3, 3) + Base64.getEncoder().encodeToString(hasher.digest()))
|
||||
handshakeFinished.release()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
override fun getArchitecture(): String {
|
||||
return ArchitectureType.forVmCpuArch(CpuArch.CURRENT).id
|
||||
}
|
||||
|
||||
data class HandshakeRequest(var value: String) {
|
||||
constructor() : this("")
|
||||
override fun toString(): String {
|
||||
val b = ToStringBuilder(this)
|
||||
b.add("value", value)
|
||||
return b.toString()
|
||||
}
|
||||
}
|
||||
|
||||
data class HandshakeResponse(var signature: String) {
|
||||
constructor() : this("")
|
||||
|
||||
override fun toString(): String {
|
||||
val b = ToStringBuilder(this)
|
||||
b.add("signature", this.signature)
|
||||
return b.toString()
|
||||
}
|
||||
}
|
||||
}
|
8
cidr/src/main/resources/META-INF/zigbrains-cidr.xml
Normal file
8
cidr/src/main/resources/META-INF/zigbrains-cidr.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<idea-plugin package="com.falsepattern.zigbrains.cidr">
|
||||
<depends>com.intellij.cidr.base</depends>
|
||||
<extensions defaultExtensionNs="cidr.project">
|
||||
<workspaceProvider
|
||||
implementation="com.falsepattern.zigbrains.cidr.ZigWorkspaceProvider"
|
||||
/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
10
cidr/src/main/resources/META-INF/zigbrains-clion.xml
Normal file
10
cidr/src/main/resources/META-INF/zigbrains-clion.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<idea-plugin package="com.falsepattern.zigbrains.clion">
|
||||
<depends>com.intellij.clion</depends>
|
||||
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||
<debuggerDriverProvider
|
||||
id="CLionProvider"
|
||||
implementation="com.falsepattern.zigbrains.clion.ZigClionDebuggerDriverConfigurationProvider"
|
||||
order="before DefaultProvider"
|
||||
/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
60
cidr/src/main/resources/META-INF/zigbrains-debugger.xml
Normal file
60
cidr/src/main/resources/META-INF/zigbrains-debugger.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<idea-plugin package="com.falsepattern.zigbrains.debugger">
|
||||
<depends>com.intellij.modules.cidr.debugger</depends>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<configurationType
|
||||
implementation="com.falsepattern.zigbrains.debugger.execution.binary.ZigConfigTypeBinary"
|
||||
/>
|
||||
<programRunner
|
||||
id="ZigDebugRunnerRun"
|
||||
implementation="com.falsepattern.zigbrains.debugger.runner.run.ZigDebugRunnerRun"
|
||||
/>
|
||||
<programRunner
|
||||
id="ZigDebugRunnerTest"
|
||||
implementation="com.falsepattern.zigbrains.debugger.runner.test.ZigDebugRunnerTest"
|
||||
/>
|
||||
<programRunner
|
||||
id="ZigDebugRunnerBuild"
|
||||
implementation="com.falsepattern.zigbrains.debugger.runner.build.ZigDebugRunnerBuild"
|
||||
/>
|
||||
<programRunner
|
||||
id="ZigDebugRunnerBinary"
|
||||
implementation="com.falsepattern.zigbrains.debugger.runner.binary.ZigDebugRunnerBinary"
|
||||
/>
|
||||
|
||||
<xdebugger.settings
|
||||
implementation="com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings"
|
||||
/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||
<featureProvider
|
||||
implementation="com.falsepattern.zigbrains.debugger.DebuggerFeatures"
|
||||
/>
|
||||
<debuggerDriverProvider
|
||||
id="DefaultProvider"
|
||||
implementation="com.falsepattern.zigbrains.debugger.ZigDefaultDebuggerDriverConfigurationProvider"
|
||||
order="last"
|
||||
/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="cidr.debugger">
|
||||
<languageSupport
|
||||
language="Zig"
|
||||
implementationClass="com.falsepattern.zigbrains.debugger.ZigDebuggerLanguageSupport"
|
||||
/>
|
||||
<editorsExtension
|
||||
language="Zig"
|
||||
implementationClass="com.falsepattern.zigbrains.debugger.ZigDebuggerEditorsExtension"
|
||||
/>
|
||||
<lineBreakpointFileTypesProvider
|
||||
implementation="com.falsepattern.zigbrains.debugger.ZigLineBreakpointFileTypesProvider"
|
||||
/>
|
||||
<localVariablesFilterHandler
|
||||
implementation="com.falsepattern.zigbrains.debugger.ZigLocalVariablesFilterHandler"
|
||||
/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
36
cidr/src/main/resources/zigbrains/debugger/Bundle.properties
Normal file
36
cidr/src/main/resources/zigbrains/debugger/Bundle.properties
Normal file
|
@ -0,0 +1,36 @@
|
|||
notification.title.debugger=Debugger
|
||||
notification.content.debugger.successfully.downloaded=Debugger successfully downloaded
|
||||
notification.content.debugger.downloading.failed=Debugger downloading failed
|
||||
notification.content.debugger.metadata.downloading.failed=Debugger metadata downloading failed, switching to fallback
|
||||
notification.content.debugger.metadata.fallback.parse.failed=Debugger fallback metadata parse failed
|
||||
settings.debugger.toolchain.download.debugger.automatically.checkbox=Download and update the debugger automatically
|
||||
settings.debugger.title=Zig
|
||||
settings.debugger.toolchain.debugger.label=Debugger:
|
||||
settings.debugger.toolchain.download.comment=Need to be <a>downloaded</a>
|
||||
settings.debugger.toolchain.update.comment=Need to be <a>updated</a>
|
||||
settings.debugger.toolchain.use.clion.toolchains=Use Clion toolchains instead
|
||||
debugger.run.unavailable=Unable to Run Debugger
|
||||
debugger.run.unavailable.reason.download=Debugger is not downloaded yet
|
||||
debugger.run.unavailable.reason.download.button=Download
|
||||
debugger.run.unavailable.reason.update=Debugger is outdated
|
||||
debugger.run.unavailable.reason.update.button=Update
|
||||
debug.build.compile.failed.boilerplate={0}\nPlease edit this intellij build configuration and specify the path of the executable created by "zig build" directly!
|
||||
debug.base.compile.failed.generic=Failed to compile executable with command: {0}
|
||||
debug.base.compile.failed.no-exe=Failed to find compiled binary
|
||||
debug.build.compile.failed.multiple-exe=Multiple compiled binaries found
|
||||
debug.build.compile.failed.no-workdir=Cannot find working directory to run debugged executable
|
||||
debug.build.compile.failed.autodetect=Could not auto-detect default executable output directory "zig-out/bin"
|
||||
debug.build.compile.failed.no-file=File `{0}` does not exist
|
||||
debug.build.compile.failed.non-exec-file=File `{0}` is not executable
|
||||
debug.build.compile.failed.generic=Failed to build project
|
||||
exec.type.binary.label=Zig-compiled native executable
|
||||
exec.option.label.binary.exe-path=Executable program path (not the zig compiler)
|
||||
exec.option.label.binary.args=Command line arguments
|
||||
exception.missing-exe-path=Missing executable path
|
||||
configuration.binary.name=Native Application (Zig)
|
||||
configuration.binary.suggested-name=Executable
|
||||
configuration.binary.description=Binary executable compiled from zig code (useful for debugging on Windows)
|
||||
msvc.consent.title=Network Request Consent
|
||||
msvc.consent.deny=Use Bundled
|
||||
msvc.consent.allow=Download
|
||||
msvc.consent.body=Debugging on Windows requires downloading extra metadata from the internet.\nThe bundled fallback metadata will be used if the request is denied.
|
108
core/build.gradle.kts
Normal file
108
core/build.gradle.kts
Normal file
|
@ -0,0 +1,108 @@
|
|||
import org.jetbrains.grammarkit.tasks.GenerateLexerTask
|
||||
import org.jetbrains.grammarkit.tasks.GenerateParserTask
|
||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
||||
|
||||
plugins {
|
||||
id("org.jetbrains.grammarkit")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
val ideaCommunityVersion: String by project
|
||||
val useInstaller = property("useInstaller").toString().toBoolean()
|
||||
val serializationVersion: String by project
|
||||
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller)
|
||||
}
|
||||
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:$serializationVersion") {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
//region grammars
|
||||
run {
|
||||
val grammarGenRoot = layout.buildDirectory.dir("generated/sources/grammarkit")
|
||||
val rootPackagePath = "com/falsepattern/zigbrains"
|
||||
val grammarSources = layout.projectDirectory.dir("src/main/grammar")
|
||||
|
||||
val parserDir = grammarGenRoot.map {it.dir("zig/parser")}
|
||||
val lexerDir = grammarGenRoot.map {it.dir("zig/lexer")}
|
||||
val lexerStringDir = grammarGenRoot.map {it.dir("zig/lexerstring")}
|
||||
val zonParserDir = grammarGenRoot.map {it.dir("zon/parser")}
|
||||
val zonLexerDir = grammarGenRoot.map {it.dir("zon/lexer")}
|
||||
|
||||
val grammarGenDirs = listOf(parserDir, lexerDir, lexerStringDir, zonParserDir, zonLexerDir)
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
grammarGenDirs.forEach { srcDir(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
grammarGenDirs.forEach {
|
||||
val file = it.get().asFile
|
||||
sourceDirs.add(file)
|
||||
generatedSourceDirs.add(file)
|
||||
}
|
||||
sourceDirs.add(grammarSources.asFile)
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
// region grammarkit
|
||||
generateLexer {
|
||||
purgeOldFiles = true
|
||||
sourceFile = grammarSources.file("Zig.flex")
|
||||
targetOutputDir = lexerDir.map { it.dir("$rootPackagePath/zig/lexer") }
|
||||
}
|
||||
|
||||
register<GenerateLexerTask>("generateLexerString") {
|
||||
purgeOldFiles = true
|
||||
sourceFile = grammarSources.file("ZigString.flex")
|
||||
targetOutputDir = lexerStringDir.map { it.dir("$rootPackagePath/zig/lexerstring") }
|
||||
|
||||
}
|
||||
|
||||
generateParser {
|
||||
purgeOldFiles = true
|
||||
sourceFile = grammarSources.file("Zig.bnf")
|
||||
targetRootOutputDir = parserDir
|
||||
pathToParser = "$rootPackagePath/zig/parser/ZigParser.java"
|
||||
pathToPsiRoot = "$rootPackagePath/zig/psi"
|
||||
}
|
||||
|
||||
register<GenerateLexerTask>("generateZonLexer") {
|
||||
purgeOldFiles = true
|
||||
sourceFile = grammarSources.file("Zon.flex")
|
||||
targetOutputDir = zonLexerDir.map { it.dir("$rootPackagePath/zon/lexer") }
|
||||
}
|
||||
|
||||
register<GenerateParserTask>("generateZonParser") {
|
||||
purgeOldFiles = true
|
||||
sourceFile = grammarSources.file("Zon.bnf")
|
||||
targetRootOutputDir = zonParserDir
|
||||
pathToParser = "$rootPackagePath/zon/parser/ZonParser.java"
|
||||
pathToPsiRoot = "$rootPackagePath/zon/psi"
|
||||
}
|
||||
|
||||
register<DefaultTask>("generateGrammars") {
|
||||
group = "grammarkit"
|
||||
dependsOn("generateLexer", "generateLexerString", "generateParser")
|
||||
dependsOn("generateZonLexer", "generateZonParser")
|
||||
}
|
||||
|
||||
compileJava {
|
||||
dependsOn("generateGrammars")
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
dependsOn("generateGrammars")
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion grammars
|
|
@ -1,17 +1,23 @@
|
|||
/*
|
||||
* Copyright 2023-2024 FalsePattern
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
{
|
||||
|
@ -26,9 +32,9 @@
|
|||
psiImplPackage="com.falsepattern.zigbrains.zig.psi.impl"
|
||||
|
||||
elementTypeHolderClass="com.falsepattern.zigbrains.zig.psi.ZigTypes"
|
||||
elementTypeClass="com.falsepattern.zigbrains.zig.psi.ZigElementType"
|
||||
elementTypeClass="com.falsepattern.zigbrains.zig.parser.ZigElementType"
|
||||
|
||||
tokenTypeClass="com.falsepattern.zigbrains.zig.psi.ZigTokenType"
|
||||
tokenTypeClass="com.falsepattern.zigbrains.zig.parser.ZigTokenType"
|
||||
generateTokenAccessors = true
|
||||
tokens=[
|
||||
|
||||
|
@ -159,6 +165,8 @@
|
|||
|
||||
STRING_LITERAL_SINGLE='quoted string literal'
|
||||
STRING_LITERAL_MULTI='multiline string literal'
|
||||
BAD_SQUOT='unterminated character literal'
|
||||
BAD_DQUOT='unterminated string'
|
||||
|
||||
IDENTIFIER='identifier'
|
||||
BUILTINIDENTIFIER='builtin identifier'
|
||||
|
@ -172,11 +180,11 @@
|
|||
Root ::= CONTAINER_DOC_COMMENT? ContainerMembers?
|
||||
|
||||
// *** Top level ***
|
||||
ContainerMembers ::= ContainerDeclarations? (ContainerField COMMA)* (ContainerField | ContainerDeclarations)?
|
||||
ContainerMembers ::= ContainerDeclaration* (ContainerField COMMA)* (ContainerField | ContainerDeclaration*)
|
||||
|
||||
ContainerDeclarations ::= (TestDecl | ComptimeDecl | DOC_COMMENT? KEYWORD_PUB? Decl)+
|
||||
ContainerDeclaration ::= TestDecl | ComptimeDecl | DOC_COMMENT? KEYWORD_PUB? Decl
|
||||
|
||||
TestDecl ::= DOC_COMMENT? KEYWORD_TEST (STRING_LITERAL_SINGLE | IDENTIFIER)? Block {pin=2}
|
||||
TestDecl ::= KEYWORD_TEST (STRING_LITERAL_SINGLE | IDENTIFIER)? Block {pin=1}
|
||||
|
||||
ComptimeDecl ::= KEYWORD_COMPTIME Block
|
||||
|
||||
|
@ -197,6 +205,7 @@ ContainerField ::= DOC_COMMENT? KEYWORD_COMPTIME? !KEYWORD_FN (IDENTIFIER COLON)
|
|||
Statement
|
||||
::= KEYWORD_COMPTIME ComptimeStatement
|
||||
| KEYWORD_NOSUSPEND BlockExprStatement
|
||||
| KEYWORD_SUSPEND BlockExprStatement
|
||||
| KEYWORD_DEFER BlockExprStatement
|
||||
| KEYWORD_ERRDEFER Payload? BlockExprStatement
|
||||
| IfStatement
|
||||
|
@ -407,14 +416,21 @@ WhilePrefix ::= KEYWORD_WHILE ZB_WhilePrefix_Operand PtrPayload? WhileContinueEx
|
|||
|
||||
private ZB_WhilePrefix_Operand ::= LPAREN Expr RPAREN {pin=1}
|
||||
|
||||
ForRange ::= Expr DOT2 Expr?
|
||||
ForOperand ::= ForRange | Expr {recoverWhile="ZB_ForOperand_Recover"}
|
||||
ForPrefix ::= KEYWORD_FOR LPAREN ZB_ForParams RPAREN ForPayload {pin=1}
|
||||
|
||||
private ZB_ForOperand_Recover ::= !(COMMA | RPAREN)
|
||||
private ZB_ForParams ::= ForInput (COMMA ForInput)* COMMA? {recoverWhile="ZB_ForParams_Recover"}
|
||||
|
||||
ForPrefix ::= KEYWORD_FOR ZB_ForPrefix_Operands PtrIndexPayload {pin=1}
|
||||
private ZB_ForParams_Recover ::= !(RPAREN)
|
||||
|
||||
private ZB_ForPrefix_Operands ::= LPAREN (ForOperand COMMA)* ForOperand RPAREN {pin=1}
|
||||
ForInput ::= Expr (DOT2 Expr?)? {recoverWhile="ZB_ForInput_Recover"}
|
||||
|
||||
private ZB_ForInput_Recover ::= !(COMMA | RPAREN)
|
||||
|
||||
ForPayload ::= PIPE ZB_ForPayload_Item (COMMA ZB_ForPayload_Item)* PIPE {pin=1}
|
||||
|
||||
private ZB_ForPayload_Item ::= ASTERISK? IDENTIFIER {recoverWhile="ZB_ForPayload_Recover"}
|
||||
|
||||
private ZB_ForPayload_Recover ::= !(COMMA | PIPE)
|
||||
|
||||
// Payloads
|
||||
Payload ::= PIPE IDENTIFIER PIPE
|
|
@ -1,17 +1,23 @@
|
|||
/*
|
||||
* Copyright 2023-2024 FalsePattern
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.zigbrains.zig.lexer;
|
||||
|
||||
|
@ -28,9 +34,12 @@ import static com.falsepattern.zigbrains.zig.psi.ZigTypes.*;
|
|||
%implements FlexLexer
|
||||
%function advance
|
||||
%type IElementType
|
||||
%unicode
|
||||
|
||||
CRLF=\R
|
||||
WHITE_SPACE=[\s]+
|
||||
WHITE_SPACE=\s+
|
||||
|
||||
// visual studio parity
|
||||
LF=\r\n?|[\n\u0085\u2028\u2029]
|
||||
|
||||
bin=[01]
|
||||
bin_="_"? {bin}
|
||||
|
@ -46,55 +55,14 @@ oct_int={oct} {oct_}*
|
|||
dec_int={dec} {dec_}*
|
||||
hex_int={hex} {hex_}*
|
||||
|
||||
ox80_oxBF=[\200-\277]
|
||||
oxF4=\364
|
||||
ox80_ox8F=[\200-\217]
|
||||
oxF1_oxF3=[\361-\363]
|
||||
oxF0=\360
|
||||
ox90_0xBF=[\220-\277]
|
||||
oxEE_oxEF=[\356-\357]
|
||||
oxED=\355
|
||||
ox80_ox9F=[\200-\237]
|
||||
oxE1_oxEC=[\341-\354]
|
||||
oxE0=\340
|
||||
oxA0_oxBF=[\240-\277]
|
||||
oxC2_oxDF=[\302-\337]
|
||||
|
||||
// From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
|
||||
// First Byte Second Byte Third Byte Fourth Byte
|
||||
// [0x00,0x7F]
|
||||
// [0xC2,0xDF] [0x80,0xBF]
|
||||
// 0xE0 [0xA0,0xBF] [0x80,0xBF]
|
||||
// [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xED [0x80,0x9F] [0x80,0xBF]
|
||||
// [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF]
|
||||
// [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
|
||||
|
||||
mb_utf8_literal= {oxF4} {ox80_ox8F} {ox80_oxBF} {ox80_oxBF}
|
||||
| {oxF1_oxF3} {ox80_oxBF} {ox80_oxBF} {ox80_oxBF}
|
||||
| {oxF0} {ox90_0xBF} {ox80_oxBF} {ox80_oxBF}
|
||||
| {oxEE_oxEF} {ox80_oxBF} {ox80_oxBF}
|
||||
| {oxED} {ox80_ox9F} {ox80_oxBF}
|
||||
| {oxE1_oxEC} {ox80_oxBF} {ox80_oxBF}
|
||||
| {oxE0} {oxA0_oxBF} {ox80_oxBF}
|
||||
| {oxC2_oxDF} {ox80_oxBF}
|
||||
|
||||
ascii_char_not_nl_slash_squote=[\000-\011\013-\046\050-\133\135-\177]
|
||||
|
||||
char_escape= "\\x" {hex} {hex}
|
||||
| "\\u{" {hex}+ "}"
|
||||
| "\\" [nr\\t'\"]
|
||||
char_char= {mb_utf8_literal}
|
||||
| {char_escape}
|
||||
| {ascii_char_not_nl_slash_squote}
|
||||
char_char= \\ .
|
||||
| [^\'\r\n\u0085\u2028\u2029]
|
||||
|
||||
string_char= \\ .
|
||||
| [^\"\n]
|
||||
| [^\"\r\n\u0085\u2028\u2029]
|
||||
|
||||
all_nl_wrap=[^\n]* [ \n]*
|
||||
all_nl_nowrap=[^\n]* \n
|
||||
nl_wrap={LF} (\s|{LF})*
|
||||
all_no_nl=[^\r\n\u0085\u2028\u2029]+
|
||||
|
||||
|
||||
FLOAT= "0x" {hex_int} "." {hex_int} ([pP] [-+]? {dec_int})?
|
||||
|
@ -115,26 +83,38 @@ BUILTINIDENTIFIER="@"[A-Za-z_][A-Za-z0-9_]*
|
|||
%state CHAR_LIT
|
||||
|
||||
%state ID_QUOT
|
||||
%state UNT_QUOT
|
||||
%state UNT_SQUOT
|
||||
%state UNT_DQUOT
|
||||
|
||||
%state CDOC_CMT
|
||||
%state DOC_CMT
|
||||
%state LINE_CMT
|
||||
%state CMT_LINE
|
||||
%state CMT_DOC
|
||||
%state CMT_CDOC
|
||||
%%
|
||||
|
||||
//Comments
|
||||
|
||||
<YYINITIAL> "//!" { yybegin(CDOC_CMT); }
|
||||
<CDOC_CMT> {all_nl_wrap} "//!" { }
|
||||
<CDOC_CMT> {all_nl_nowrap} { yybegin(YYINITIAL); return CONTAINER_DOC_COMMENT; }
|
||||
<YYINITIAL> "//!" { yybegin(CMT_CDOC); }
|
||||
<YYINITIAL> "////" { yybegin(CMT_LINE); }
|
||||
<YYINITIAL> "///" { yybegin(CMT_DOC); }
|
||||
<YYINITIAL> "//" { yybegin(CMT_LINE); }
|
||||
|
||||
<YYINITIAL> "///" { yybegin(DOC_CMT); }
|
||||
<DOC_CMT> {all_nl_wrap} "///" { }
|
||||
<DOC_CMT> {all_nl_nowrap} { yybegin(YYINITIAL); return DOC_COMMENT; }
|
||||
<CMT_LINE> {all_no_nl} { }
|
||||
<CMT_LINE> {nl_wrap} "////" { }
|
||||
<CMT_LINE> {nl_wrap} "///" { yypushback(yylength()); yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
<CMT_LINE> {nl_wrap} "//" { }
|
||||
<CMT_LINE> {LF} { yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
<CMT_LINE> <<EOF>> { yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
|
||||
<YYINITIAL> "//" { yybegin(LINE_CMT); }
|
||||
<LINE_CMT> {all_nl_wrap} "//" { }
|
||||
<LINE_CMT> {all_nl_nowrap} { yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
<CMT_DOC> {all_no_nl} { }
|
||||
<CMT_DOC> {nl_wrap} "////" { yypushback(yylength()); yybegin(YYINITIAL); return DOC_COMMENT; }
|
||||
<CMT_DOC> {nl_wrap} "///" { }
|
||||
<CMT_DOC> {LF} { yybegin(YYINITIAL); return DOC_COMMENT; }
|
||||
<CMT_DOC> <<EOF>> { yybegin(YYINITIAL); return DOC_COMMENT; }
|
||||
|
||||
<CMT_CDOC> {all_no_nl} { }
|
||||
<CMT_CDOC> {nl_wrap} "//!" { }
|
||||
<CMT_CDOC> {LF} { yybegin(YYINITIAL); return CONTAINER_DOC_COMMENT; }
|
||||
<CMT_CDOC> <<EOF>> { yybegin(YYINITIAL); return CONTAINER_DOC_COMMENT; }
|
||||
|
||||
//Symbols
|
||||
<YYINITIAL> "&" { return AMPERSAND; }
|
||||
|
@ -254,28 +234,49 @@ BUILTINIDENTIFIER="@"[A-Za-z_][A-Za-z0-9_]*
|
|||
<YYINITIAL> "volatile" { return KEYWORD_VOLATILE; }
|
||||
<YYINITIAL> "while" { return KEYWORD_WHILE; }
|
||||
|
||||
//Strings
|
||||
|
||||
<YYINITIAL> "'" { yybegin(CHAR_LIT); }
|
||||
<CHAR_LIT> {char_char}"'" { yybegin(YYINITIAL); return CHAR_LITERAL; }
|
||||
<CHAR_LIT> [^] { yypushback(1); yybegin(UNT_QUOT); }
|
||||
<CHAR_LIT> {char_char}*"'" { yybegin(YYINITIAL); return CHAR_LITERAL; }
|
||||
<CHAR_LIT> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<CHAR_LIT> [^] { yypushback(1); yybegin(UNT_SQUOT); }
|
||||
|
||||
<YYINITIAL> "\"" { yybegin(STR_LIT); }
|
||||
<STR_LIT> {string_char}*"\"" { yybegin(YYINITIAL); return STRING_LITERAL_SINGLE; }
|
||||
<STR_LIT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<STR_LIT> [^] { yypushback(1); yybegin(UNT_DQUOT); }
|
||||
|
||||
<YYINITIAL> "\\\\" { yybegin(STR_MULT_LINE); }
|
||||
<STR_MULT_LINE> {all_no_nl} { }
|
||||
<STR_MULT_LINE> {nl_wrap} "\\\\" { }
|
||||
<STR_MULT_LINE> {LF} { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
|
||||
<STR_MULT_LINE> <<EOF>> { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
|
||||
|
||||
//Numbers
|
||||
|
||||
<YYINITIAL> {FLOAT} { return FLOAT; }
|
||||
<YYINITIAL> {INTEGER} { return INTEGER; }
|
||||
|
||||
<YYINITIAL> "\"" { yybegin(STR_LIT); }
|
||||
<STR_LIT> {string_char}*"\"" { yybegin(YYINITIAL); return STRING_LITERAL_SINGLE; }
|
||||
<STR_LIT> [^] { yypushback(1); yybegin(UNT_QUOT); }
|
||||
<YYINITIAL> "\\\\" { yybegin(STR_MULT_LINE); }
|
||||
<STR_MULT_LINE> {all_nl_wrap} "\\\\" { }
|
||||
<STR_MULT_LINE> {all_nl_nowrap} { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
|
||||
//Identifiers
|
||||
|
||||
<YYINITIAL> {IDENTIFIER_PLAIN} { return IDENTIFIER; }
|
||||
<YYINITIAL> "@\"" { yybegin(ID_QUOT); }
|
||||
<ID_QUOT> {string_char}*"\"" { yybegin(YYINITIAL); return IDENTIFIER; }
|
||||
<ID_QUOT> [^] { yypushback(1); yybegin(UNT_QUOT); }
|
||||
<ID_QUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<ID_QUOT> [^] { yypushback(1); yybegin(UNT_DQUOT); }
|
||||
|
||||
<YYINITIAL> {BUILTINIDENTIFIER} { return BUILTINIDENTIFIER; }
|
||||
|
||||
<UNT_QUOT> [^\n]*{CRLF} { yybegin(YYINITIAL); return BAD_CHARACTER; }
|
||||
//Error handling
|
||||
|
||||
<UNT_SQUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<UNT_SQUOT> {LF} { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<UNT_SQUOT> {all_no_nl} { }
|
||||
<UNT_DQUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<UNT_DQUOT> {LF} { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<UNT_DQUOT> {all_no_nl} { }
|
||||
|
||||
//Misc
|
||||
|
||||
<YYINITIAL> {WHITE_SPACE} { return WHITE_SPACE; }
|
||||
|
84
core/src/main/grammar/ZigString.flex
Normal file
84
core/src/main/grammar/ZigString.flex
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.zigbrains.zig.lexerstring;
|
||||
|
||||
import com.intellij.lexer.FlexLexer;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
import static com.intellij.psi.TokenType.WHITE_SPACE;
|
||||
import static com.intellij.psi.TokenType.BAD_CHARACTER;
|
||||
import static com.falsepattern.zigbrains.zig.psi.ZigTypes.*;
|
||||
import static com.intellij.psi.StringEscapesTokenTypes.*;
|
||||
|
||||
%%
|
||||
|
||||
%public
|
||||
%class ZigLexerString
|
||||
%implements FlexLexer
|
||||
%function advance
|
||||
%type IElementType
|
||||
|
||||
hex=[0-9a-fA-F]
|
||||
|
||||
char_escape_unicode= "\\x" {hex} {hex} | "\\u{" {hex}+ "}"
|
||||
char_escape_unicode_invalid= "\\x" .? .? | "\\u" ("{" [^}]* "}"?)?
|
||||
|
||||
char_escape_single_valid= "\\" [nr\\t'\"]
|
||||
char_escape_single_invalid= "\\" [^nr\\t'\"]
|
||||
|
||||
%state STR
|
||||
%state CHAR
|
||||
%state CHAR_END
|
||||
%state CHAR_FINISH
|
||||
%%
|
||||
|
||||
|
||||
<YYINITIAL> {
|
||||
"\"" { yybegin(STR); return STRING_LITERAL_SINGLE; }
|
||||
"'" { yybegin(CHAR); return CHAR_LITERAL; }
|
||||
[^] { return STRING_LITERAL_SINGLE; }
|
||||
}
|
||||
|
||||
<STR> {
|
||||
{char_escape_unicode} { return VALID_STRING_ESCAPE_TOKEN; }
|
||||
{char_escape_unicode_invalid} { return INVALID_UNICODE_ESCAPE_TOKEN; }
|
||||
{char_escape_single_valid} { return VALID_STRING_ESCAPE_TOKEN; }
|
||||
{char_escape_single_invalid} { return INVALID_CHARACTER_ESCAPE_TOKEN; }
|
||||
[^] { return STRING_LITERAL_SINGLE; }
|
||||
}
|
||||
|
||||
<CHAR> {
|
||||
{char_escape_unicode} { yybegin(CHAR_END); return VALID_STRING_ESCAPE_TOKEN; }
|
||||
{char_escape_unicode_invalid} { yybegin(CHAR_END); return INVALID_UNICODE_ESCAPE_TOKEN; }
|
||||
{char_escape_single_valid} { yybegin(CHAR_END); return VALID_STRING_ESCAPE_TOKEN; }
|
||||
{char_escape_single_invalid} { yybegin(CHAR_END); return INVALID_CHARACTER_ESCAPE_TOKEN; }
|
||||
[^] { yybegin(CHAR_END); return CHAR_LITERAL; }
|
||||
}
|
||||
|
||||
<CHAR_END> {
|
||||
"'" { yybegin(CHAR_FINISH); return CHAR_LITERAL; }
|
||||
[^] { return BAD_CHARACTER; }
|
||||
}
|
||||
|
||||
<CHAR_FINISH> {
|
||||
[^] { return BAD_CHARACTER; }
|
||||
}
|
90
core/src/main/grammar/Zon.bnf
Normal file
90
core/src/main/grammar/Zon.bnf
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
{
|
||||
parserClass="com.falsepattern.zigbrains.zon.parser.ZonParser"
|
||||
|
||||
extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
|
||||
|
||||
psiClassPrefix="Zon"
|
||||
psiImplClassSuffix="Impl"
|
||||
psiPackage="com.falsepattern.zigbrains.zon.psi"
|
||||
psiImplPackage="com.falsepattern.zigbrains.zon.psi.impl"
|
||||
|
||||
elementTypeHolderClass="com.falsepattern.zigbrains.zon.psi.ZonTypes"
|
||||
elementTypeClass="com.falsepattern.zigbrains.zon.parser.ZonElementType"
|
||||
tokenTypeClass="com.falsepattern.zigbrains.zon.parser.ZonTokenType"
|
||||
tokens=[
|
||||
LINE_COMMENT='comment'
|
||||
DOT='.'
|
||||
EQUAL='='
|
||||
LBRACE='{'
|
||||
RBRACE='}'
|
||||
COMMA=','
|
||||
KEYWORD_FALSE='false'
|
||||
KEYWORD_TRUE='true'
|
||||
KEYWORD_NULL='null'
|
||||
NUM_NAN='nan'
|
||||
NUM_INF='inf'
|
||||
CHAR_LITERAL='char literal'
|
||||
STRING_LITERAL_SINGLE='string literal'
|
||||
STRING_LITERAL_MULTI='multiline string literal'
|
||||
FLOAT='float'
|
||||
INTEGER='integer'
|
||||
IDENTIFIER='identifier'
|
||||
BAD_SQUOT='unterminated quote'
|
||||
BAD_DQUOT='unterminated double quote'
|
||||
]
|
||||
}
|
||||
|
||||
Root ::= Expr
|
||||
|
||||
Expr
|
||||
::= CHAR_LITERAL
|
||||
| StringLiteral
|
||||
| DOT IDENTIFIER
|
||||
| DOT InitList
|
||||
| Bool
|
||||
| Number
|
||||
| KEYWORD_NULL
|
||||
|
||||
|
||||
InitList
|
||||
::= LBRACE ZB_InitList_Body RBRACE {pin=1}
|
||||
|
||||
private ZB_InitList_Body
|
||||
::= FieldInit (COMMA ZB_InitList_FieldInit)* COMMA?
|
||||
| Expr (COMMA ZB_InitList_Expr)* COMMA?
|
||||
| ()
|
||||
|
||||
private ZB_InitList_FieldInit ::= FieldInit {recoverWhile="ZB_InitList_Recover"}
|
||||
private ZB_InitList_Expr ::= Expr {recoverWhile="ZB_InitList_Recover"}
|
||||
|
||||
private ZB_InitList_Recover ::= !(COMMA | RBRACE)
|
||||
|
||||
FieldInit ::= DOT IDENTIFIER EQUAL Expr
|
||||
|
||||
Bool ::= KEYWORD_TRUE | KEYWORD_FALSE
|
||||
|
||||
Number ::= FLOAT | INTEGER | NUM_NAN | NUM_INF
|
||||
|
||||
StringLiteral ::= STRING_LITERAL_SINGLE | STRING_LITERAL_MULTI
|
159
core/src/main/grammar/Zon.flex
Normal file
159
core/src/main/grammar/Zon.flex
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.zigbrains.zon.lexer;
|
||||
|
||||
import com.intellij.lexer.FlexLexer;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
import static com.intellij.psi.TokenType.WHITE_SPACE;
|
||||
import static com.intellij.psi.TokenType.BAD_CHARACTER;
|
||||
import static com.falsepattern.zigbrains.zon.psi.ZonTypes.*;
|
||||
|
||||
%%
|
||||
|
||||
%class ZonFlexLexer
|
||||
%implements FlexLexer
|
||||
%function advance
|
||||
%type IElementType
|
||||
%unicode
|
||||
|
||||
WHITE_SPACE=\s+
|
||||
|
||||
// visual studio parity
|
||||
LF=\r\n?|[\n\u0085\u2028\u2029]
|
||||
|
||||
bin=[01]
|
||||
bin_="_"? {bin}
|
||||
oct=[0-7]
|
||||
oct_="_"? {oct}
|
||||
hex=[0-9a-fA-F]
|
||||
hex_="_"? {hex}
|
||||
dec=[0-9]
|
||||
dec_="_"? {dec}
|
||||
|
||||
bin_int={bin} {bin_}*
|
||||
oct_int={oct} {oct_}*
|
||||
dec_int={dec} {dec_}*
|
||||
hex_int={hex} {hex_}*
|
||||
|
||||
char_char= \\ .
|
||||
| [^\'\r\n\u0085\u2028\u2029]
|
||||
|
||||
string_char= \\ .
|
||||
| [^\"\r\n\u0085\u2028\u2029]
|
||||
|
||||
nl_wrap={LF} (\s|{LF})*
|
||||
all_no_nl=[^\r\n\u0085\u2028\u2029]+
|
||||
|
||||
|
||||
FLOAT= "0x" {hex_int} "." {hex_int} ([pP] [-+]? {dec_int})?
|
||||
| {dec_int} "." {dec_int} ([eE] [-+]? {dec_int})?
|
||||
| "0x" {hex_int} [pP] [-+]? {dec_int}
|
||||
| {dec_int} [eE] [-+]? {dec_int}
|
||||
|
||||
INTEGER= "0b" {bin_int}
|
||||
| "0o" {oct_int}
|
||||
| "0x" {hex_int}
|
||||
| {dec_int}
|
||||
|
||||
IDENTIFIER_PLAIN=[A-Za-z_][A-Za-z0-9_]*
|
||||
|
||||
%state STR_LIT
|
||||
%state STR_MULT_LINE
|
||||
%state CHAR_LIT
|
||||
|
||||
%state ID_QUOT
|
||||
%state UNT_SQUOT
|
||||
%state UNT_DQUOT
|
||||
|
||||
%state CMT_LINE
|
||||
%%
|
||||
|
||||
//Comments
|
||||
|
||||
<YYINITIAL> "//" { yybegin(CMT_LINE); }
|
||||
<CMT_LINE> {all_no_nl} { }
|
||||
<CMT_LINE> {nl_wrap} "//" { }
|
||||
<CMT_LINE> \R { yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
<CMT_LINE> <<EOF>> { yybegin(YYINITIAL); return LINE_COMMENT; }
|
||||
|
||||
//Symbols
|
||||
|
||||
<YYINITIAL> "." { return DOT; }
|
||||
<YYINITIAL> "=" { return EQUAL; }
|
||||
<YYINITIAL> "{" { return LBRACE; }
|
||||
<YYINITIAL> "}" { return RBRACE; }
|
||||
<YYINITIAL> "," { return COMMA; }
|
||||
|
||||
//Keywords
|
||||
|
||||
<YYINITIAL> "false" { return KEYWORD_FALSE; }
|
||||
<YYINITIAL> "true" { return KEYWORD_TRUE; }
|
||||
<YYINITIAL> "null" { return KEYWORD_NULL; }
|
||||
<YYINITIAL> "nan" { return NUM_NAN; }
|
||||
<YYINITIAL> "inf" { return NUM_INF; }
|
||||
|
||||
//Strings
|
||||
|
||||
<YYINITIAL> "'" { yybegin(CHAR_LIT); }
|
||||
<CHAR_LIT> {char_char}*"'" { yybegin(YYINITIAL); return CHAR_LITERAL; }
|
||||
<CHAR_LIT> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<CHAR_LIT> [^] { yypushback(1); yybegin(UNT_SQUOT); }
|
||||
|
||||
<YYINITIAL> "\"" { yybegin(STR_LIT); }
|
||||
<STR_LIT> {string_char}*"\"" { yybegin(YYINITIAL); return STRING_LITERAL_SINGLE; }
|
||||
<STR_LIT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<STR_LIT> [^] { yypushback(1); yybegin(UNT_DQUOT); }
|
||||
|
||||
<YYINITIAL> "\\\\" { yybegin(STR_MULT_LINE); }
|
||||
<STR_MULT_LINE> {all_no_nl} { }
|
||||
<STR_MULT_LINE> {nl_wrap} "\\\\" { }
|
||||
<STR_MULT_LINE> {LF} { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
|
||||
<STR_MULT_LINE> <<EOF>> { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
|
||||
|
||||
//Numbers
|
||||
|
||||
<YYINITIAL> {FLOAT} { return FLOAT; }
|
||||
<YYINITIAL> {INTEGER} { return INTEGER; }
|
||||
|
||||
//Identifiers
|
||||
|
||||
<YYINITIAL> {IDENTIFIER_PLAIN} { return IDENTIFIER; }
|
||||
<YYINITIAL> "@\"" { yybegin(ID_QUOT); }
|
||||
<ID_QUOT> {string_char}*"\"" { yybegin(YYINITIAL); return IDENTIFIER; }
|
||||
<ID_QUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<ID_QUOT> [^] { yypushback(1); yybegin(UNT_DQUOT); }
|
||||
|
||||
//Error handling
|
||||
|
||||
<UNT_SQUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<UNT_SQUOT> {LF} { yybegin(YYINITIAL); return BAD_SQUOT; }
|
||||
<UNT_SQUOT> {all_no_nl} { }
|
||||
<UNT_DQUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<UNT_DQUOT> {LF} { yybegin(YYINITIAL); return BAD_DQUOT; }
|
||||
<UNT_DQUOT> {all_no_nl} { }
|
||||
|
||||
//Misc
|
||||
|
||||
<YYINITIAL> {WHITE_SPACE} { return WHITE_SPACE; }
|
||||
|
||||
[^] { return BAD_CHARACTER; }
|
34
core/src/main/kotlin/com/falsepattern/zigbrains/Icons.kt
Normal file
34
core/src/main/kotlin/com/falsepattern/zigbrains/Icons.kt
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains
|
||||
|
||||
import com.intellij.openapi.util.IconLoader
|
||||
import org.jetbrains.annotations.NonNls
|
||||
|
||||
@NonNls
|
||||
object Icons {
|
||||
@JvmField
|
||||
val Zig = IconLoader.getIcon("/icons/zig.svg", Icons::class.java)
|
||||
@JvmField
|
||||
val Zon = IconLoader.getIcon("/icons/zon.svg", Icons::class.java)
|
||||
}
|
107
core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt
Normal file
107
core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains
|
||||
|
||||
import com.intellij.ide.BrowserUtil
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationAction
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import com.intellij.openapi.options.ShowSettingsUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class ZBStartup: ProjectActivity {
|
||||
var firstInit = true
|
||||
override suspend fun execute(project: Project) {
|
||||
if (firstInit) {
|
||||
firstInit = false
|
||||
if (!PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.cidr.debugger")) &&
|
||||
PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.nativeDebug-plugin-capable"))) {
|
||||
val notif = Notification(
|
||||
"zigbrains",
|
||||
ZigBrainsBundle.message("notification.title.native-debug"),
|
||||
ZigBrainsBundle.message("notification.content.native-debug"),
|
||||
NotificationType.INFORMATION
|
||||
)
|
||||
if (JBInternalPluginManagerConfigurable.successful) {
|
||||
notif.addAction(object: NotificationAction(ZigBrainsBundle.message("notification.content.native-debug.market")) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
val configurable = JBInternalPluginManagerConfigurable()
|
||||
ShowSettingsUtil.getInstance().editConfigurable(null as Project?, configurable.instance) {
|
||||
configurable.openMarketplaceTab("/vendor:\"JetBrains s.r.o.\" /tag:Debugging \"Native Debugging Support\"")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
notif.addAction(object: NotificationAction(ZigBrainsBundle.message("notification.content.native-debug.browser")) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
BrowserUtil.browse("https://plugins.jetbrains.com/plugin/12775-native-debugging-support")
|
||||
}
|
||||
})
|
||||
notif.notify(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//JetBrains Internal API, but we need to access it, so access it reflectively (hopefully safe enough to pass verifier)
|
||||
private class JBInternalPluginManagerConfigurable {
|
||||
init {
|
||||
if (!successful) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
val instance = constructor.newInstance() as Configurable
|
||||
|
||||
fun openMarketplaceTab(option: String) {
|
||||
openMarketplaceTab.invoke(instance, option)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private lateinit var constructor: Constructor<*>
|
||||
private lateinit var openMarketplaceTab: Method
|
||||
val successful: Boolean
|
||||
|
||||
init {
|
||||
lateinit var constructor: Constructor<*>
|
||||
lateinit var openMarketplaceTab: Method
|
||||
val successful = try {
|
||||
val theClass = Class.forName("com_intellij_ide_plugins_PluginManagerConfigurable".replace('_', '.'))
|
||||
constructor = theClass.getDeclaredConstructor().apply { isAccessible = true }
|
||||
openMarketplaceTab = theClass.getDeclaredMethod("openMarketplaceTab", String::class.java).apply { isAccessible = true }
|
||||
true
|
||||
} catch (_: Throwable) { false }
|
||||
if (successful) {
|
||||
this.constructor = constructor
|
||||
this.openMarketplaceTab = openMarketplaceTab
|
||||
}
|
||||
this.successful = successful
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains
|
||||
|
||||
import com.intellij.DynamicBundle
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.annotations.PropertyKey
|
||||
import java.util.function.Supplier
|
||||
|
||||
@NonNls
|
||||
private const val BUNDLE = "zigbrains.Bundle"
|
||||
|
||||
internal object ZigBrainsBundle {
|
||||
private val INSTANCE = DynamicBundle(ZigBrainsBundle::class.java, BUNDLE)
|
||||
|
||||
fun message(
|
||||
key: @PropertyKey(resourceBundle = BUNDLE) String,
|
||||
vararg params: Any
|
||||
): @Nls String {
|
||||
return INSTANCE.getMessage(key, *params)
|
||||
}
|
||||
|
||||
fun lazyMessage(
|
||||
key: @PropertyKey(resourceBundle = BUNDLE) String,
|
||||
vararg params: Any
|
||||
): Supplier<@Nls String> {
|
||||
return INSTANCE.getLazyMessage(key, *params)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.direnv
|
||||
|
||||
@JvmRecord
|
||||
data class DirenvOutput(val output: String, val error: Boolean)
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.direnv
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.ide.impl.isTrusted
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.notification.Notifications
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.UserDataHolder
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.io.awaitExit
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
@State(
|
||||
name = "Direnv",
|
||||
storages = [Storage("zigbrains.xml")]
|
||||
)
|
||||
class DirenvService(val project: Project): SerializablePersistentStateComponent<DirenvService.State>(State()), IDirenvService {
|
||||
private val mutex = Mutex()
|
||||
|
||||
override val isInstalled: Boolean by lazy {
|
||||
// Using the builtin stuff here instead of Env because it should only scan for direnv on the process path
|
||||
PathEnvironmentVariableUtil.findExecutableInPathOnAnyOS("direnv") != null
|
||||
}
|
||||
|
||||
var isEnabledRaw: DirenvState
|
||||
get() = state.enabled
|
||||
set(value) {
|
||||
updateState {
|
||||
it.copy(enabled = value)
|
||||
}
|
||||
}
|
||||
|
||||
override val isEnabled: DirenvState
|
||||
get() = isEnabledRaw
|
||||
|
||||
override suspend fun import(): Env {
|
||||
if (!isInstalled || !project.isTrusted() || project.isDefault)
|
||||
return Env.empty
|
||||
val workDir = project.guessProjectDir()?.toNioPath() ?: return Env.empty
|
||||
|
||||
val runOutput = run(workDir, "export", "json")
|
||||
if (runOutput.error) {
|
||||
if (runOutput.output.contains("is blocked")) {
|
||||
Notifications.Bus.notify(Notification(
|
||||
GROUP_DISPLAY_ID,
|
||||
ZigBrainsBundle.message("notification.title.direnv-blocked"),
|
||||
ZigBrainsBundle.message("notification.content.direnv-blocked"),
|
||||
NotificationType.ERROR
|
||||
))
|
||||
return Env.empty
|
||||
} else {
|
||||
Notifications.Bus.notify(Notification(
|
||||
GROUP_DISPLAY_ID,
|
||||
ZigBrainsBundle.message("notification.title.direnv-error"),
|
||||
ZigBrainsBundle.message("notification.content.direnv-error", runOutput.output),
|
||||
NotificationType.ERROR
|
||||
))
|
||||
return Env.empty
|
||||
}
|
||||
}
|
||||
return if (runOutput.output.isBlank()) {
|
||||
Env.empty
|
||||
} else {
|
||||
Env(Json.decodeFromString<Map<String, String>>(runOutput.output))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun run(workDir: Path, vararg args: String): DirenvOutput {
|
||||
val cli = GeneralCommandLine("direnv", *args).withWorkingDirectory(workDir)
|
||||
|
||||
val (process, exitCode) = withProgressText("Running ${cli.commandLineString}") {
|
||||
withContext(Dispatchers.IO) {
|
||||
mutex.withLock {
|
||||
val process = cli.createProcess()
|
||||
val exitCode = process.awaitExit()
|
||||
process to exitCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
val stdErr = process.errorStream.bufferedReader().use { it.readText() }
|
||||
return DirenvOutput(stdErr, true)
|
||||
}
|
||||
|
||||
val stdOut = process.inputStream.bufferedReader().use { it.readText() }
|
||||
return DirenvOutput(stdOut, false)
|
||||
}
|
||||
|
||||
fun hasDotEnv(): Boolean {
|
||||
if (!isInstalled)
|
||||
return false
|
||||
val projectDir = project.guessProjectDir()?.toNioPathOrNull() ?: return false
|
||||
return envFiles.any { projectDir.resolve(it).isRegularFile() }
|
||||
}
|
||||
|
||||
data class State(
|
||||
@JvmField
|
||||
@Attribute
|
||||
var enabled: DirenvState = DirenvState.Auto
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val GROUP_DISPLAY_ID = "zigbrains-direnv"
|
||||
fun getInstance(project: Project): IDirenvService = project.service<DirenvService>()
|
||||
|
||||
private val STATE_KEY = Key.create<DirenvState>("DIRENV_STATE")
|
||||
|
||||
fun getStateFor(data: UserDataHolder?, project: Project?): DirenvState {
|
||||
return data?.getUserData(STATE_KEY) ?: project?.let { getInstance(project).isEnabled } ?: DirenvState.Disabled
|
||||
}
|
||||
|
||||
fun setStateFor(data: UserDataHolder, state: DirenvState) {
|
||||
data.putUserData(STATE_KEY, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface IDirenvService {
|
||||
val isInstalled: Boolean
|
||||
val isEnabled: DirenvState
|
||||
suspend fun import(): Env
|
||||
}
|
||||
|
||||
private val envFiles = listOf(".envrc", ".env")
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.direnv
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
enum class DirenvState {
|
||||
Auto,
|
||||
Enabled,
|
||||
Disabled;
|
||||
|
||||
fun isEnabled(project: Project?): Boolean {
|
||||
return when(this) {
|
||||
Enabled -> true
|
||||
Disabled -> false
|
||||
Auto -> project?.service<DirenvService>()?.hasDotEnv() == true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.direnv
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.util.EnvironmentUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.io.File
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.isExecutable
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
@JvmRecord
|
||||
data class Env(val env: Map<String, String>) {
|
||||
private val path get() = getVariable("PATH")?.split(File.pathSeparatorChar)
|
||||
|
||||
private fun getVariable(name: @NonNls String) =
|
||||
env.getOrElse(name) { EnvironmentUtil.getValue(name) }
|
||||
|
||||
fun findAllExecutablesOnPATH(exe: @NonNls String) = flow {
|
||||
val exeName = if (SystemInfo.isWindows) "$exe.exe" else exe
|
||||
val paths = path ?: return@flow
|
||||
for (dir in paths) {
|
||||
val path = dir.toNioPathOrNull()?.absolute() ?: continue
|
||||
if (!path.toFile().exists() || !path.isDirectory())
|
||||
continue
|
||||
val exePath = path.resolve(exeName).absolute()
|
||||
if (!exePath.isRegularFile() || !exePath.isExecutable())
|
||||
continue
|
||||
emit(exePath)
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
companion object {
|
||||
val empty = Env(emptyMap())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.direnv.ui
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.direnv.DirenvService
|
||||
import com.falsepattern.zigbrains.direnv.DirenvState
|
||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
|
||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider.Companion.PROJECT_KEY
|
||||
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import java.awt.event.ItemEvent
|
||||
|
||||
abstract class DirenvEditor<T>(private val sharedState: ZigProjectConfigurationProvider.IUserDataBridge?): SubConfigurable<T> {
|
||||
private var cb: ComboBox<DirenvState>? = null
|
||||
override fun attach(panel: Panel): Unit = with(panel) {
|
||||
row(ZigBrainsBundle.message("settings.direnv.enable.label")) {
|
||||
comboBox(DirenvState.entries).component.let {
|
||||
cb = it
|
||||
if (sharedState != null) {
|
||||
it.addItemListener { e ->
|
||||
if (e.stateChange != ItemEvent.SELECTED)
|
||||
return@addItemListener
|
||||
val item = e.item
|
||||
if (item !is DirenvState)
|
||||
return@addItemListener
|
||||
DirenvService.setStateFor(sharedState, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isModified(context: T): Boolean {
|
||||
return isEnabled(context) != cb?.selectedItem as DirenvState
|
||||
}
|
||||
|
||||
override fun apply(context: T) {
|
||||
setEnabled(context, cb?.selectedItem as DirenvState)
|
||||
}
|
||||
|
||||
override fun reset(context: T?) {
|
||||
if (context == null) {
|
||||
cb?.selectedItem = DirenvState.Auto
|
||||
return
|
||||
}
|
||||
cb?.selectedItem = isEnabled(context)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
abstract fun isEnabled(context: T): DirenvState
|
||||
abstract fun setEnabled(context: T, value: DirenvState)
|
||||
|
||||
class ForProject(sharedState: ZigProjectConfigurationProvider.IUserDataBridge) : DirenvEditor<Project>(sharedState) {
|
||||
override fun isEnabled(context: Project): DirenvState {
|
||||
return DirenvService.getInstance(context).isEnabled
|
||||
}
|
||||
|
||||
override fun setEnabled(context: Project, value: DirenvState) {
|
||||
context.service<DirenvService>().isEnabledRaw = value
|
||||
}
|
||||
}
|
||||
|
||||
class Provider: ZigProjectConfigurationProvider {
|
||||
override fun create(sharedState: ZigProjectConfigurationProvider.IUserDataBridge): SubConfigurable<Project>? {
|
||||
if (sharedState.getUserData(PROJECT_KEY)?.isDefault != false) {
|
||||
return null
|
||||
}
|
||||
DirenvService.setStateFor(sharedState, DirenvState.Auto)
|
||||
return ForProject(sharedState)
|
||||
}
|
||||
|
||||
override val index: Int
|
||||
get() = 100
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.actions
|
||||
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.intellij.ide.actions.CreateFileFromTemplateAction
|
||||
import com.intellij.ide.actions.CreateFileFromTemplateDialog
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiDirectory
|
||||
|
||||
class ZigNewFileAction: CreateFileFromTemplateAction() {
|
||||
override fun buildDialog(project: Project, directory: PsiDirectory, builder: CreateFileFromTemplateDialog.Builder) {
|
||||
builder.setTitle("Zig File")
|
||||
.addKind("Empty file", Icons.Zig, "blank_zig_file")
|
||||
}
|
||||
|
||||
override fun getActionName(directory: PsiDirectory?, newName: String, templateName: String?): String {
|
||||
return "Zig File"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.actions
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig
|
||||
import com.falsepattern.zigbrains.project.execution.run.ZigConfigProducerRun
|
||||
import com.falsepattern.zigbrains.project.execution.run.ZigExecConfigRun
|
||||
import com.falsepattern.zigbrains.project.execution.test.ZigConfigProducerTest
|
||||
import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest
|
||||
import com.intellij.execution.ExecutionManager
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.execution.executors.DefaultRunExecutor
|
||||
import com.intellij.execution.runners.ExecutionEnvironmentBuilder
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
|
||||
class ZigRunFileAction: DumbAwareAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val file = e.getData(CommonDataKeys.PSI_FILE) ?: return
|
||||
val config = getConfig(e) ?: return
|
||||
val project = file.project
|
||||
val builder = ExecutionEnvironmentBuilder.createOrNull(DefaultRunExecutor.getRunExecutorInstance(), config) ?: return
|
||||
ExecutionManager.getInstance(project).restartRunProfile(builder.build())
|
||||
}
|
||||
|
||||
private fun getConfig(e: AnActionEvent): ZigExecConfig<*>? {
|
||||
val context = ConfigurationContext.getFromContext(e.dataContext, e.place)
|
||||
return getRunConfiguration(context) ?: getTestConfiguration(context)
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
e.presentation.isEnabledAndVisible = getConfig(e) != null
|
||||
}
|
||||
|
||||
private fun getRunConfiguration(context: ConfigurationContext): ZigExecConfigRun? {
|
||||
try {
|
||||
val configProducer = RunConfigurationProducer.getInstance(ZigConfigProducerRun::class.java)
|
||||
val settings = configProducer.findExistingConfiguration(context)
|
||||
if (settings != null) {
|
||||
return settings.configuration as? ZigExecConfigRun
|
||||
}
|
||||
val fromContext = configProducer.createConfigurationFromContext(context)
|
||||
if (fromContext != null) {
|
||||
return fromContext.configuration as? ZigExecConfigRun
|
||||
}
|
||||
} catch (_: NullPointerException) {}
|
||||
return null
|
||||
}
|
||||
private fun getTestConfiguration(context: ConfigurationContext): ZigExecConfigTest? {
|
||||
try {
|
||||
val configProducer = RunConfigurationProducer.getInstance(ZigConfigProducerTest::class.java)
|
||||
val settings = configProducer.findExistingConfiguration(context)
|
||||
if (settings != null) {
|
||||
return settings.configuration as? ZigExecConfigTest
|
||||
}
|
||||
val fromContext = configProducer.createConfigurationFromContext(context)
|
||||
if (fromContext != null) {
|
||||
return fromContext.configuration as? ZigExecConfigTest
|
||||
}
|
||||
} catch (_: NullPointerException) {}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.BGT
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.console
|
||||
|
||||
import com.intellij.execution.filters.ConsoleFilterProvider
|
||||
import com.intellij.execution.filters.Filter
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigConsoleFilterProvider: ConsoleFilterProvider {
|
||||
override fun getDefaultFilters(project: Project): Array<Filter> {
|
||||
return arrayOf(ZigSourceFileFilter(project))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.console
|
||||
|
||||
import com.intellij.execution.filters.Filter
|
||||
import com.intellij.execution.filters.Filter.ResultItem
|
||||
import com.intellij.execution.filters.OpenFileHyperlinkInfo
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.vfs.refreshAndFindVirtualFile
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import java.io.File
|
||||
import java.nio.file.InvalidPathException
|
||||
import java.nio.file.Path
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
class ZigSourceFileFilter(private val project: Project): Filter {
|
||||
private val projectPath = runCatching { project.guessProjectDir()?.toNioPathOrNull()?.toFile() }.getOrNull()
|
||||
override fun applyFilter(line: String, entireLength: Int): Filter.Result? {
|
||||
val lineStart = entireLength - line.length
|
||||
val results = ArrayList<ResultItem>()
|
||||
val matcher = LEN_REGEX.findAll(line)
|
||||
for (match in matcher) {
|
||||
val start = match.range.first
|
||||
val pair = findLongestParsablePathFromOffset(line, start)
|
||||
val path = pair?.first ?: return null
|
||||
val file = path.refreshAndFindVirtualFile() ?: return null
|
||||
val lineNumber = max(match.groups[1]!!.value.toInt() - 1, 0)
|
||||
val lineOffset = max(match.groups[2]!!.value.toInt() - 1, 0)
|
||||
results.add(ResultItem(lineStart + pair.second, lineStart + match.range.last + 1, OpenFileHyperlinkInfo(project, file, lineNumber, lineOffset)))
|
||||
}
|
||||
return Filter.Result(results)
|
||||
}
|
||||
|
||||
private fun findLongestParsablePathFromOffset(line: String, end: Int): Pair<Path, Int>? {
|
||||
var longestStart = -1
|
||||
var longest: File? = null
|
||||
for (i in end - 1 downTo 0) {
|
||||
try {
|
||||
val pathStr = line.substring(i, end)
|
||||
var file = File(pathStr)
|
||||
if (!file.isFile) {
|
||||
if (projectPath == null) {
|
||||
continue
|
||||
}
|
||||
file = projectPath.resolve(pathStr)
|
||||
if (!file.isFile) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
longest = file
|
||||
longestStart = i
|
||||
} catch (ignored: InvalidPathException) {
|
||||
}
|
||||
}
|
||||
longest ?: return null
|
||||
return Pair(longest.toPath(), longestStart)
|
||||
}
|
||||
}
|
||||
|
||||
private val LEN_REGEX = Regex(":(\\d+):(\\d+)")
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution
|
||||
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||
import com.intellij.execution.configurations.runConfigurationType
|
||||
|
||||
inline fun <reified T: ConfigurationTypeBase> firstConfigFactory(): ConfigurationFactory {
|
||||
return runConfigurationType<T>().configurationFactories.first()
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution
|
||||
|
||||
import com.intellij.execution.filters.TextConsoleBuilderImpl
|
||||
import com.intellij.execution.ui.ConsoleView
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.terminal.TerminalExecutionConsole
|
||||
|
||||
class ZigConsoleBuilder(private val project: Project, private val emulateTerminal: Boolean = false): TextConsoleBuilderImpl(project) {
|
||||
override fun createConsole(): ConsoleView {
|
||||
return if (emulateTerminal)
|
||||
TerminalExecutionConsole(project, null)
|
||||
else
|
||||
super.createConsole()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigurable.ZigConfigModule
|
||||
import com.falsepattern.zigbrains.shared.cli.translateCommandline
|
||||
import com.falsepattern.zigbrains.shared.element.*
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||
import com.intellij.openapi.options.SettingsEditor
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.components.textFieldWithBrowseButton
|
||||
import com.intellij.ui.dsl.builder.AlignX
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.io.Serializable
|
||||
import java.nio.file.Path
|
||||
import javax.swing.JComponent
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigConfigEditor<T : ZigExecConfig<T>>(private val state: ZigExecConfig<T>) : SettingsEditor<T>() {
|
||||
private val configModules = ArrayList<ZigConfigModule<*>>()
|
||||
|
||||
override fun resetEditorFrom(s: T) {
|
||||
outer@ for (cfg in s.getConfigurables()) {
|
||||
for (module in configModules) {
|
||||
if (module.tryReset(cfg))
|
||||
continue@outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun applyEditorTo(s: T) {
|
||||
outer@ for (cfg in s.getConfigurables()) {
|
||||
for (module in configModules) {
|
||||
if (module.tryApply(cfg)) {
|
||||
continue@outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createEditor(): JComponent {
|
||||
configModules.clear()
|
||||
configModules.addAll(state.getConfigurables().map { it.createEditor() })
|
||||
return panel {
|
||||
for (module in configModules) {
|
||||
module.construct(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disposeEditor() {
|
||||
for (module in configModules) {
|
||||
module.dispose()
|
||||
}
|
||||
configModules.clear()
|
||||
}
|
||||
}
|
||||
|
||||
interface ZigConfigurable<T : ZigConfigurable<T>> : Serializable, Cloneable {
|
||||
fun readExternal(element: Element)
|
||||
fun writeExternal(element: Element)
|
||||
fun createEditor(): ZigConfigModule<T>
|
||||
public override fun clone(): T
|
||||
|
||||
interface ZigConfigModule<T : ZigConfigurable<T>> : Disposable {
|
||||
fun tryMatch(cfg: ZigConfigurable<*>): T?
|
||||
fun apply(configurable: T): Boolean
|
||||
fun reset(configurable: T)
|
||||
fun tryApply(cfg: ZigConfigurable<*>): Boolean {
|
||||
val x = tryMatch(cfg)
|
||||
if (x != null) {
|
||||
return apply(x)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun tryReset(cfg: ZigConfigurable<*>): Boolean {
|
||||
val x = tryMatch(cfg)
|
||||
if (x != null) {
|
||||
reset(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun construct(p: Panel)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PathConfigurable<T : PathConfigurable<T>> : ZigConfigurable<T> {
|
||||
var path: Path? = null
|
||||
|
||||
override fun readExternal(element: Element) {
|
||||
path = element.readString(serializedName)?.ifBlank { null }?.toNioPathOrNull() ?: return
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
element.writeString(serializedName, path?.pathString ?: "")
|
||||
}
|
||||
|
||||
abstract val serializedName: String
|
||||
|
||||
abstract class PathConfigModule<T : PathConfigurable<T>> : ZigConfigModule<T> {
|
||||
override fun apply(configurable: T): Boolean {
|
||||
val str = stringValue
|
||||
if (str.isBlank()) {
|
||||
configurable.path = null
|
||||
} else {
|
||||
configurable.path = str.toNioPathOrNull() ?: return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun reset(configurable: T) {
|
||||
stringValue = configurable.path?.pathString ?: ""
|
||||
}
|
||||
|
||||
protected abstract var stringValue: String
|
||||
}
|
||||
}
|
||||
|
||||
class WorkDirectoryConfigurable(@Transient override val serializedName: String) : PathConfigurable<WorkDirectoryConfigurable>(), Cloneable {
|
||||
override fun createEditor(): ZigConfigModule<WorkDirectoryConfigurable> {
|
||||
return WorkDirectoryConfigModule(serializedName)
|
||||
}
|
||||
|
||||
override fun clone(): WorkDirectoryConfigurable {
|
||||
return super<Cloneable>.clone() as WorkDirectoryConfigurable
|
||||
}
|
||||
|
||||
class WorkDirectoryConfigModule(private val serializedName: String) : PathConfigModule<WorkDirectoryConfigurable>() {
|
||||
private val field = textFieldWithBrowseButton(
|
||||
null,
|
||||
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.working-directory"))
|
||||
).also { Disposer.register(this, it) }
|
||||
|
||||
override var stringValue by field::text
|
||||
|
||||
override fun tryMatch(cfg: ZigConfigurable<*>): WorkDirectoryConfigurable? {
|
||||
return if (cfg is WorkDirectoryConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||
}
|
||||
|
||||
override fun construct(p: Panel): Unit = with(p) {
|
||||
row(ZigBrainsBundle.message("exec.option.label.working-directory")) {
|
||||
cell(field).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
field.dispose()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class FilePathConfigurable(
|
||||
@Transient override val serializedName: String,
|
||||
@Transient @Nls private val guiLabel: String
|
||||
) : PathConfigurable<FilePathConfigurable>(), Cloneable {
|
||||
|
||||
override fun createEditor(): ZigConfigModule<FilePathConfigurable> {
|
||||
return FilePathConfigModule(serializedName, guiLabel)
|
||||
}
|
||||
|
||||
override fun clone(): FilePathConfigurable {
|
||||
return super<Cloneable>.clone() as FilePathConfigurable
|
||||
}
|
||||
|
||||
class FilePathConfigModule(private val serializedName: String, @Nls private val label: String) : PathConfigModule<FilePathConfigurable>() {
|
||||
private val field = textFieldWithBrowseButton(
|
||||
null,
|
||||
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(),
|
||||
)
|
||||
|
||||
override var stringValue by field::text
|
||||
|
||||
override fun tryMatch(cfg: ZigConfigurable<*>): FilePathConfigurable? {
|
||||
return if (cfg is FilePathConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||
}
|
||||
|
||||
override fun construct(p: Panel): Unit = with(p) {
|
||||
row(label) {
|
||||
cell(field).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
Disposer.dispose(field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class CheckboxConfigurable(
|
||||
@Transient private val serializedName: String,
|
||||
@Transient @Nls private val label: String,
|
||||
var value: Boolean
|
||||
) : ZigConfigurable<CheckboxConfigurable>, Cloneable {
|
||||
override fun readExternal(element: Element) {
|
||||
value = element.readBoolean(serializedName) ?: return
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
element.writeBoolean(serializedName, value)
|
||||
}
|
||||
|
||||
override fun createEditor(): ZigConfigModule<CheckboxConfigurable> {
|
||||
return CheckboxConfigModule(serializedName, label)
|
||||
}
|
||||
|
||||
override fun clone(): CheckboxConfigurable {
|
||||
return super<Cloneable>.clone() as CheckboxConfigurable
|
||||
}
|
||||
|
||||
class CheckboxConfigModule(
|
||||
private val serializedName: String,
|
||||
@Nls private val label: String
|
||||
) : ZigConfigModule<CheckboxConfigurable> {
|
||||
private val checkBox = JBCheckBox()
|
||||
|
||||
override fun tryMatch(cfg: ZigConfigurable<*>): CheckboxConfigurable? {
|
||||
return if (cfg is CheckboxConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||
}
|
||||
|
||||
override fun apply(configurable: CheckboxConfigurable): Boolean {
|
||||
configurable.value = checkBox.isSelected
|
||||
return true
|
||||
}
|
||||
|
||||
override fun reset(configurable: CheckboxConfigurable) {
|
||||
checkBox.isSelected = configurable.value
|
||||
}
|
||||
|
||||
override fun construct(p: Panel): Unit = with(p) {
|
||||
row(label) {
|
||||
cell(checkBox)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {}
|
||||
}
|
||||
}
|
||||
|
||||
class OptimizationConfigurable(
|
||||
@Transient private val serializedName: String,
|
||||
var level: OptimizationLevel = OptimizationLevel.Debug,
|
||||
var forced: Boolean = false
|
||||
) : ZigConfigurable<OptimizationConfigurable>, Cloneable {
|
||||
override fun readExternal(element: Element) {
|
||||
element.readChild(serializedName)?.apply {
|
||||
readEnum<OptimizationLevel>("level")?.let { level = it }
|
||||
readBoolean("forced")?.let { forced = it }
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
element.writeChild(serializedName).apply {
|
||||
writeEnum("level", level)
|
||||
writeBoolean("forced", forced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createEditor(): ZigConfigModule<OptimizationConfigurable> {
|
||||
return OptimizationConfigModule(serializedName)
|
||||
}
|
||||
|
||||
override fun clone(): OptimizationConfigurable {
|
||||
return super<Cloneable>.clone() as OptimizationConfigurable
|
||||
}
|
||||
|
||||
class OptimizationConfigModule(private val serializedName: String) : ZigConfigModule<OptimizationConfigurable> {
|
||||
private val levels = ComboBox(OptimizationLevel.entries.toTypedArray())
|
||||
private val forced = JBCheckBox(ZigBrainsBundle.message("exec.option.label.optimization.force"))
|
||||
override fun tryMatch(cfg: ZigConfigurable<*>): OptimizationConfigurable? {
|
||||
return if (cfg is OptimizationConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||
}
|
||||
|
||||
override fun apply(configurable: OptimizationConfigurable): Boolean {
|
||||
configurable.level = levels.item
|
||||
configurable.forced = forced.isSelected
|
||||
return true
|
||||
}
|
||||
|
||||
override fun reset(configurable: OptimizationConfigurable) {
|
||||
levels.item = configurable.level
|
||||
forced.isSelected = configurable.forced
|
||||
}
|
||||
|
||||
override fun construct(p: Panel): Unit = with(p) {
|
||||
row(ZigBrainsBundle.message("exec.option.label.optimization")) {
|
||||
cell(levels)
|
||||
cell(forced)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ArgsConfigurable(
|
||||
@Transient private val serializedName: String,
|
||||
@Transient @Nls private val guiName: String
|
||||
) : ZigConfigurable<ArgsConfigurable>, Cloneable {
|
||||
var args: String = ""
|
||||
|
||||
override fun readExternal(element: Element) {
|
||||
args = element.readString(serializedName) ?: element.readStrings(serializedName)?.joinToString(separator = " ") { if (it.contains(' ')) "\"$it\"" else it } ?: ""
|
||||
}
|
||||
|
||||
fun argsSplit(): List<String> {
|
||||
return translateCommandline(args)
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
element.writeString(serializedName, args)
|
||||
}
|
||||
|
||||
override fun createEditor(): ZigConfigModule<ArgsConfigurable> {
|
||||
return ArgsConfigModule(serializedName, guiName)
|
||||
}
|
||||
|
||||
override fun clone(): ArgsConfigurable {
|
||||
return super<Cloneable>.clone() as ArgsConfigurable
|
||||
}
|
||||
|
||||
class ArgsConfigModule(
|
||||
private val serializedName: String,
|
||||
@Nls private val guiName: String
|
||||
) : ZigConfigModule<ArgsConfigurable> {
|
||||
private val argsField = JBTextField()
|
||||
|
||||
override fun tryMatch(cfg: ZigConfigurable<*>): ArgsConfigurable? {
|
||||
return if (cfg is ArgsConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||
}
|
||||
|
||||
override fun apply(configurable: ArgsConfigurable): Boolean {
|
||||
configurable.args = argsField.text ?: ""
|
||||
return true
|
||||
}
|
||||
|
||||
override fun reset(configurable: ArgsConfigurable) {
|
||||
argsField.text = configurable.args
|
||||
}
|
||||
|
||||
override fun construct(p: Panel): Unit = with(p) {
|
||||
row(guiName) {
|
||||
cell(argsField).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
enum class OptimizationLevel {
|
||||
Debug,
|
||||
ReleaseSafe,
|
||||
ReleaseFast,
|
||||
ReleaseSmall
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigFile
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.ConfigurationFromContext
|
||||
import com.intellij.execution.actions.LazyRunConfigurationProducer
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import com.intellij.psi.PsiElement
|
||||
import java.nio.file.Path
|
||||
|
||||
abstract class ZigConfigProducer<T: ZigExecConfig<T>>: LazyRunConfigurationProducer<T>() {
|
||||
abstract override fun getConfigurationFactory(): ConfigurationFactory
|
||||
|
||||
override fun setupConfigurationFromContext(configuration: T, context: ConfigurationContext, sourceElement: Ref<PsiElement>): Boolean {
|
||||
val element = context.location?.psiElement ?: return false
|
||||
val psiFile = element.containingFile as? ZigFile ?: return false
|
||||
val theFile = psiFile.virtualFile ?: return false
|
||||
val filePath = theFile.toNioPathOrNull() ?: return false
|
||||
return setupConfigurationFromContext(configuration, element, psiFile, filePath, theFile)
|
||||
}
|
||||
|
||||
override fun isConfigurationFromContext(configuration: T, context: ConfigurationContext): Boolean {
|
||||
val element = context.location?.psiElement ?: return false
|
||||
val psiFile = element.containingFile as? ZigFile ?: return false
|
||||
val theFile = psiFile.virtualFile ?: return false
|
||||
val filePath = theFile.toNioPathOrNull() ?: return false
|
||||
return isConfigurationFromContext(configuration, element, psiFile, filePath, theFile)
|
||||
}
|
||||
|
||||
/*
|
||||
TODO implement these
|
||||
@Override
|
||||
protected boolean setupConfigurationFromContext(@NotNull ZigExecConfigRun configuration, PsiElement element, String filePath, VirtualFile theFile) {
|
||||
if (PsiUtil.getElementType(element) == ZigTypes.KEYWORD_TEST) {
|
||||
configuration.command = "test " + filePath;
|
||||
configuration.setName("Test " + theFile.getPresentableName());
|
||||
} else if ("build.zig".equals(theFile.getName())) {
|
||||
configuration.command = "build";
|
||||
configuration.setName("Build");
|
||||
} else {
|
||||
configuration.extraArgs = filePath;
|
||||
configuration.setName(theFile.getPresentableName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConfigurationFromContext(@NotNull ZigExecConfigRun configuration, String filePath, VirtualFile vFile, PsiElement element) {
|
||||
if (!configuration.command.contains(filePath)) {
|
||||
return configuration.command.startsWith("build") && vFile.getName().equals("build.zig");
|
||||
}
|
||||
return (PsiUtil.getElementType(element) == ZigTypes.KEYWORD_TEST) == configuration.command.startsWith("test ");
|
||||
}
|
||||
*/
|
||||
|
||||
protected abstract fun setupConfigurationFromContext(configuration: T, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean
|
||||
protected abstract fun isConfigurationFromContext(configuration: T, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean
|
||||
abstract override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.direnv.DirenvService
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.LocatableConfigurationBase
|
||||
import com.intellij.execution.configurations.RunConfiguration
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.options.SettingsEditor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.util.NlsActions.ActionText
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: ConfigurationFactory, @Nls name: String): LocatableConfigurationBase<ZigProfileState<T>>(project, factory, name) {
|
||||
var workingDirectory = WorkDirectoryConfigurable("workingDirectory").apply { path = project.guessProjectDir()?.toNioPathOrNull() }
|
||||
private set
|
||||
|
||||
abstract val suggestedName: @ActionText String
|
||||
@Throws(ExecutionException::class)
|
||||
abstract suspend fun buildCommandLineArgs(debug: Boolean): List<String>
|
||||
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<T>
|
||||
|
||||
override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration> {
|
||||
return ZigConfigEditor(this)
|
||||
}
|
||||
|
||||
override fun readExternal(element: Element) {
|
||||
super.readExternal(element)
|
||||
getConfigurables().forEach { it.readExternal(element) }
|
||||
}
|
||||
|
||||
override fun writeExternal(element: Element) {
|
||||
super.writeExternal(element)
|
||||
getConfigurables().forEach { it.writeExternal(element) }
|
||||
}
|
||||
|
||||
|
||||
suspend fun patchCommandLine(commandLine: GeneralCommandLine): GeneralCommandLine {
|
||||
val direnv = DirenvService.getInstance(project)
|
||||
if (direnv.isEnabled.isEnabled(project)) {
|
||||
commandLine.withEnvironment(direnv.import().env)
|
||||
}
|
||||
return commandLine
|
||||
}
|
||||
|
||||
override fun clone(): T {
|
||||
val myClone = super.clone() as ZigExecConfig<*>
|
||||
myClone.workingDirectory = workingDirectory.clone()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return myClone as T
|
||||
}
|
||||
|
||||
open fun getConfigurables(): List<ZigConfigurable<*>> = listOf(workingDirectory)
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.ZigConsoleBuilder
|
||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||
import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess
|
||||
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.CommandLineState
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PtyCommandLine
|
||||
import com.intellij.execution.process.ProcessHandler
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
abstract class ZigProfileState<T: ZigExecConfig<T>> (
|
||||
environment: ExecutionEnvironment,
|
||||
val configuration: T
|
||||
): CommandLineState(environment) {
|
||||
|
||||
init {
|
||||
consoleBuilder = ZigConsoleBuilder(environment.project, true)
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override fun startProcess(): ProcessHandler {
|
||||
return runModalOrBlocking({ModalTaskOwner.project(environment.project)}, {"ZigProfileState.startProcess"}) {
|
||||
startProcessSuspend()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
suspend fun startProcessSuspend(): ProcessHandler {
|
||||
val toolchain = ZigToolchainService.getInstance(environment.project).toolchain ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig-profile-state.start-process.no-toolchain"))
|
||||
return getCommandLine(toolchain, false).startIPCAwareProcess(environment.project, emulateTerminal = true)
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
open suspend fun getCommandLine(toolchain: ZigToolchain, debug: Boolean): GeneralCommandLine {
|
||||
val workingDir = configuration.workingDirectory
|
||||
val zigExePath = toolchain.zig.path()
|
||||
|
||||
val cli = PtyCommandLine().withConsoleMode(false)
|
||||
cli.withExePath(zigExePath.pathString)
|
||||
workingDir.path?.let { cli.withWorkingDirectory(it) }
|
||||
cli.withCharset(Charsets.UTF_8)
|
||||
cli.addParameters(configuration.buildCommandLineArgs(debug))
|
||||
return configuration.patchCommandLine(cli)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||
import com.intellij.execution.lineMarker.ExecutorAction
|
||||
import com.intellij.execution.lineMarker.RunLineMarkerContributor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.elementType
|
||||
import javax.swing.Icon
|
||||
|
||||
abstract class ZigTopLevelLineMarker: RunLineMarkerContributor() {
|
||||
private fun getParentIfTopLevel(element: PsiElement): PsiElement? {
|
||||
var parent = getDeclaration(element)
|
||||
|
||||
var nestingLevel = 0
|
||||
while (parent != null && parent !is PsiFile) {
|
||||
if (parent.elementType == ZigTypes.CONTAINER_DECLARATION) {
|
||||
if (nestingLevel != 0)
|
||||
return null
|
||||
nestingLevel++
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
if (nestingLevel != 1)
|
||||
return null
|
||||
return parent
|
||||
}
|
||||
|
||||
fun elementMatches(element: PsiElement): Boolean {
|
||||
return getParentIfTopLevel(element) != null
|
||||
}
|
||||
|
||||
override fun getInfo(element: PsiElement): Info? {
|
||||
if (!elementMatches(element))
|
||||
return null
|
||||
val actions = ExecutorAction.getActions(0)
|
||||
return Info(getIcon(element), actions, null)
|
||||
}
|
||||
|
||||
abstract fun getDeclaration(element: PsiElement): PsiElement?
|
||||
|
||||
abstract fun getIcon(element: PsiElement): Icon
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.base
|
||||
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigFile
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.isFile
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
|
||||
fun ZigFile.hasMainFunction(): Boolean {
|
||||
val members = childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false
|
||||
return members.containerDeclarationList.any { it.decl?.fnProto?.identifier?.textMatches("main") == true }
|
||||
}
|
||||
|
||||
fun ZigFile.hasTests(): Boolean {
|
||||
val members = childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false
|
||||
return members.containerDeclarationList.any { it.testDecl != null }
|
||||
}
|
||||
|
||||
fun VirtualFile.findBuildZig(): VirtualFile? {
|
||||
var parent = this.parent
|
||||
while (parent != null) {
|
||||
parent.children.forEach {
|
||||
if (it.isFile && it.name == "build.zig") {
|
||||
return it
|
||||
}
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun VirtualFile.isBuildZig(): Boolean {
|
||||
return name == "build.zig"
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.build
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
|
||||
import com.falsepattern.zigbrains.project.execution.base.findBuildZig
|
||||
import com.falsepattern.zigbrains.project.execution.base.isBuildZig
|
||||
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigFile
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||
import com.intellij.execution.actions.ConfigurationFromContext
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.elementType
|
||||
import java.nio.file.Path
|
||||
|
||||
class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() {
|
||||
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||
return firstConfigFactory<ZigConfigTypeBuild>()
|
||||
}
|
||||
|
||||
override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
|
||||
if (theFile.isBuildZig()) {
|
||||
configuration.name = ZigBrainsBundle.message("configuration.build.marker-run")
|
||||
configuration.buildSteps.args = "run"
|
||||
configuration.debugBuildSteps.args = "install"
|
||||
return true
|
||||
}
|
||||
val buildZig = theFile.findBuildZig() ?: return false
|
||||
configuration.workingDirectory.path = buildZig.parent.toNioPath()
|
||||
if (element.elementType == ZigTypes.KEYWORD_TEST) {
|
||||
configuration.name = ZigBrainsBundle.message("configuration.build.marker-test")
|
||||
configuration.buildSteps.args = "test"
|
||||
configuration.debugBuildSteps.args = "install_test"
|
||||
return true
|
||||
} else {
|
||||
configuration.name = ZigBrainsBundle.message("configuration.build.marker-run")
|
||||
configuration.buildSteps.args = "run"
|
||||
configuration.debugBuildSteps.args = "install"
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
|
||||
val dir = configuration.workingDirectory.path ?: return false
|
||||
if (theFile.isBuildZig()) {
|
||||
return filePath.parent == dir
|
||||
} else {
|
||||
if (element.elementType == ZigTypes.KEYWORD_TEST) {
|
||||
if (configuration.buildSteps.args != "test")
|
||||
return false
|
||||
}
|
||||
val buildZig = theFile.findBuildZig() ?: return false
|
||||
return buildZig.parent.toNioPath() == dir
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
|
||||
return self.configurationType is ZigConfigTypeBuild
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.build
|
||||
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||
import com.intellij.execution.configurations.RunConfiguration
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigConfigTypeBuild : ConfigurationTypeBase(
|
||||
IDENTIFIER,
|
||||
ZigBrainsBundle.message("configuration.build.name"),
|
||||
ZigBrainsBundle.message("configuration.build.description"),
|
||||
Icons.Zig
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryRun(this))
|
||||
}
|
||||
|
||||
class ConfigFactoryRun(type: ZigConfigTypeBuild): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigBuild(project, this)
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return IDENTIFIER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val IDENTIFIER = "ZIGBRAINS_BUILD"
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.build
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.*
|
||||
import com.falsepattern.zigbrains.shared.ZBFeatures
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigBuild>(project, factory, ZigBrainsBundle.message("exec.type.build.label")) {
|
||||
var buildSteps = ArgsConfigurable("buildSteps", ZigBrainsBundle.message("exec.option.label.build.steps"))
|
||||
private set
|
||||
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
|
||||
private set
|
||||
var debugBuildSteps = ArgsConfigurable("debugBuildSteps", ZigBrainsBundle.message("exec.option.label.build.steps-debug"))
|
||||
private set
|
||||
var debugExtraArgs = ArgsConfigurable("debugCompilerArgs", ZigBrainsBundle.message("exec.option.label.build.args-debug"))
|
||||
private set
|
||||
var exePath = FilePathConfigurable("exePath", ZigBrainsBundle.message("exec.option.label.build.exe-path-debug"))
|
||||
private set
|
||||
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.build.exe-args-debug"))
|
||||
private set
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
result.add("build")
|
||||
val steps = if (debug) debugBuildSteps.argsSplit() else buildSteps.argsSplit()
|
||||
result.addAll(steps)
|
||||
result.addAll(if (debug) debugExtraArgs.argsSplit() else extraArgs.argsSplit())
|
||||
return result
|
||||
}
|
||||
|
||||
override val suggestedName: String
|
||||
get() = ZigBrainsBundle.message("configuration.build.suggested-name")
|
||||
|
||||
override fun clone(): ZigExecConfigBuild {
|
||||
val clone = super.clone()
|
||||
clone.buildSteps = buildSteps.clone()
|
||||
clone.exeArgs = exeArgs.clone()
|
||||
clone.exePath = exePath.clone()
|
||||
clone.exeArgs = exeArgs.clone()
|
||||
return clone
|
||||
}
|
||||
|
||||
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||
val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs)
|
||||
return if (ZBFeatures.debug()) {
|
||||
baseCfg + listOf(debugBuildSteps, debugExtraArgs, exePath, exeArgs)
|
||||
} else {
|
||||
baseCfg
|
||||
}
|
||||
}
|
||||
|
||||
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigBuild> {
|
||||
return ZigProfileStateBuild(environment, this)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.build
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigTopLevelLineMarker
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||
import com.intellij.icons.AllIcons.RunConfigurations.TestState
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.elementType
|
||||
import javax.swing.Icon
|
||||
|
||||
class ZigLineMarkerBuild: ZigTopLevelLineMarker() {
|
||||
override fun getDeclaration(element: PsiElement): PsiElement? {
|
||||
if (element.elementType != ZigTypes.IDENTIFIER)
|
||||
return null
|
||||
|
||||
if (!element.textMatches("build"))
|
||||
return null
|
||||
|
||||
val parent = element.parent ?: return null
|
||||
if (parent.elementType != ZigTypes.FN_PROTO)
|
||||
return null
|
||||
|
||||
val file = element.containingFile ?: return null
|
||||
|
||||
val fileName = file.virtualFile.name
|
||||
if (fileName != "build.zig")
|
||||
return null
|
||||
|
||||
return parent.parent
|
||||
}
|
||||
|
||||
override fun getIcon(element: PsiElement): Icon {
|
||||
return TestState.Run
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.build
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
|
||||
class ZigProfileStateBuild(environment: ExecutionEnvironment, configuration: ZigExecConfigBuild) : ZigProfileState<ZigExecConfigBuild>(environment, configuration)
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.run
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
|
||||
import com.falsepattern.zigbrains.project.execution.base.findBuildZig
|
||||
import com.falsepattern.zigbrains.project.execution.base.hasMainFunction
|
||||
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigFile
|
||||
import com.intellij.execution.actions.ConfigurationFromContext
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import java.nio.file.Path
|
||||
|
||||
class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
|
||||
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||
return firstConfigFactory<ZigConfigTypeRun>()
|
||||
}
|
||||
|
||||
override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
|
||||
if (!psiFile.hasMainFunction()) {
|
||||
return false
|
||||
}
|
||||
if (theFile.findBuildZig() != null) {
|
||||
return false
|
||||
}
|
||||
configuration.filePath.path = filePath
|
||||
configuration.name = theFile.presentableName
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
|
||||
return filePath == configuration.filePath.path
|
||||
}
|
||||
|
||||
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
|
||||
return self.configurationType is ZigConfigTypeRun
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.run
|
||||
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||
import com.intellij.execution.configurations.RunConfiguration
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigConfigTypeRun : ConfigurationTypeBase(
|
||||
IDENTIFIER,
|
||||
ZigBrainsBundle.message("configuration.run.name"),
|
||||
ZigBrainsBundle.message("configuration.run.description"),
|
||||
Icons.Zig
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryRun(this))
|
||||
}
|
||||
|
||||
class ConfigFactoryRun(type: ZigConfigTypeRun): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigRun(project, this)
|
||||
}
|
||||
|
||||
override fun getId(): String {
|
||||
return IDENTIFIER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val IDENTIFIER = "ZIGBRAINS_RUN"
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.run
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.*
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigRun>(project, factory, ZigBrainsBundle.message("exec.type.run.label")) {
|
||||
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
||||
private set
|
||||
var optimization = OptimizationConfigurable("optimization")
|
||||
private set
|
||||
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
|
||||
private set
|
||||
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.exe-args"))
|
||||
private set
|
||||
|
||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
result.add(if (debug) "build-exe" else "run")
|
||||
result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path")))
|
||||
if (!debug || optimization.forced) {
|
||||
result.addAll(listOf("-O", optimization.level.name))
|
||||
}
|
||||
result.addAll(compilerArgs.argsSplit())
|
||||
if (!debug) {
|
||||
result.add("--")
|
||||
result.addAll(exeArgs.argsSplit())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override val suggestedName: String
|
||||
get() = ZigBrainsBundle.message("configuration.run.suggested-name")
|
||||
|
||||
override fun clone(): ZigExecConfigRun {
|
||||
val clone = super.clone()
|
||||
clone.filePath = filePath.clone()
|
||||
clone.compilerArgs = compilerArgs.clone()
|
||||
clone.optimization = optimization.clone()
|
||||
clone.exeArgs = exeArgs.clone()
|
||||
return clone
|
||||
}
|
||||
|
||||
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||
return super.getConfigurables() + listOf(filePath, optimization, compilerArgs, exeArgs)
|
||||
}
|
||||
|
||||
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigRun> {
|
||||
return ZigProfileStateRun(environment, this)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.run
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigTopLevelLineMarker
|
||||
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||
import com.intellij.icons.AllIcons.RunConfigurations.TestState
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.elementType
|
||||
import javax.swing.Icon
|
||||
|
||||
class ZigLineMarkerRun: ZigTopLevelLineMarker() {
|
||||
override fun getDeclaration(element: PsiElement): PsiElement? {
|
||||
if (element.elementType != ZigTypes.IDENTIFIER)
|
||||
return null
|
||||
|
||||
if (!element.textMatches("main"))
|
||||
return null
|
||||
|
||||
val parent = element.parent
|
||||
if (parent.elementType != ZigTypes.FN_PROTO)
|
||||
return null
|
||||
|
||||
return parent.parent
|
||||
}
|
||||
|
||||
override fun getIcon(element: PsiElement): Icon {
|
||||
return TestState.Run
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.execution.run
|
||||
|
||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
|
||||
class ZigProfileStateRun(environment: ExecutionEnvironment, configuration: ZigExecConfigRun) : ZigProfileState<ZigExecConfigRun>(environment, configuration)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue