Compare commits

...

123 commits

Author SHA1 Message Date
0032dbf0f3
ci: 25.2.0 2025-04-20 16:10:20 +02:00
e7f0bb793a
feat: build.zig integration for run and test line markers 2025-04-20 15:57:37 +02:00
532292068f
feat: debugger improved error message for failed compilation 2025-04-20 15:56:21 +02:00
dd2104065c
ci: update push.sh 2025-04-17 13:57:44 +02:00
8389c66814
ci: 25.1.0 2025-04-17 13:53:19 +02:00
803b25d7fb
fix: [NO BACKPORT] update cpp debugger resolution logic 2025-04-17 13:43:08 +02:00
b3ce6d62a7
ci: add 251 to build and docs 2025-04-17 13:43:08 +02:00
f28cf77347
ci: [NO BACKPORT] switch to IDE 2025.1 2025-04-17 13:42:57 +02:00
c524bbf899
feat: Inlay hint file size limit option 2025-04-17 09:39:10 +02:00
a9c8a3a0d9
ci: 25.0.2 2025-04-16 00:42:41 +02:00
570eeac755
chore: fix some kotlin linter warnings 2025-04-16 00:42:34 +02:00
5efc28ae18
chore: cache suggestion paths 2025-04-16 00:31:25 +02:00
91747319aa
fix: non-scrollable ZLS settings 2025-04-16 00:17:02 +02:00
8a7ca04168
ci: 25.0.1 emergency hotfix 2025-04-11 18:51:27 +02:00
5e4f2d5dfb
ci: 25.0.0 2025-04-11 18:00:43 +02:00
4722613b4c
chore: optimize imports 2025-04-11 18:00:35 +02:00
53f4d1d330
feat: Hide library root if zig not configured 2025-04-11 17:47:33 +02:00
270ac9e113
fix: ZLS config not serializing 2025-04-11 17:32:58 +02:00
a4db054b59
fix: Config shows changed when not yet initialized 2025-04-11 17:32:46 +02:00
bd47cb201f
chore: Add lang for ZLS management 2025-04-11 17:19:54 +02:00
520167414a
docs: update readme 2025-04-11 17:19:52 +02:00
2d0ad8be44
ci: update changelog 2025-04-11 17:19:49 +02:00
9913ceb67e
ci: add etag check to debugger properties download 2025-04-11 17:19:48 +02:00
d5359e5816
feat!: Toolchain rework 2025-04-11 17:19:44 +02:00
8336d2bcc5
toolchain+lsp management feature complete! 2025-04-11 16:47:01 +02:00
281ce0ed4e
almost feature complete - ZLS needs settings GUI 2025-04-11 02:30:17 +02:00
dcede7eb43
initial LSP work 2025-04-10 20:10:27 +02:00
137977f691
modular toolchain config 2025-04-10 17:28:56 +02:00
ab20a57e9e
abstract away UUID storage for LSP code sharing 2025-04-10 16:55:30 +02:00
1725b189a4
wire up synthetic library reloads to new config 2025-04-10 12:14:23 +02:00
68b60e2c77
direnv decoupling 2025-04-10 11:27:22 +02:00
f7ea73ae45
tristate direnv config 2025-04-10 04:14:31 +02:00
3ceb61f2dd
async toolchain resolution and other tweaks 2025-04-10 01:44:43 +02:00
c7e33ea8de
modular project configurables 2025-04-09 23:20:40 +02:00
12e5ffdea1
finishing touches for the toolchain selector 2025-04-09 22:35:44 +02:00
54cd514249
local zig toolchain name, edit button state, sorted recommends 2025-04-09 18:29:06 +02:00
a8f97172d6
ported core to new toolchain api
direnv and zls regressed for now
2025-04-09 16:44:01 +02:00
b485c1e48c
lang for toolchain 2025-04-09 00:48:08 +02:00
ee5a2463b9
fully functional selection logic 2025-04-08 00:36:44 +02:00
9676b70821
Working change sync and downloader 2025-04-07 02:38:12 +02:00
9023026478
nicer suggestion/actual toolchain rendering 2025-04-06 17:31:10 +02:00
8bb4e8bef1
project-level toolchain selector 2025-04-06 17:19:26 +02:00
9541bb9752
refactor toolchain directory structure 2025-04-06 12:10:31 +02:00
2c500d40a5
work work work 2025-04-06 02:25:22 +02:00
e737058cb5
more progress 2025-04-05 19:46:48 +02:00
f53b0e3283
begin implementation of multi-toolchain management 2025-04-05 13:33:31 +02:00
3de2f92bf8
ci: update to lsp4ij 0.12.0 2025-04-04 16:54:15 +02:00
dec12a8041
ci: make cross-subproject dependencies non-transitive 2025-04-04 16:43:25 +02:00
ac90dab503
ci: update gradle dependencies 2025-04-04 16:43:08 +02:00
9830b7ebc9
ci: 24.0.1 2025-03-27 23:04:48 +01:00
efa2f127a9
fix!: bad modality states in some EDT calls 2025-03-27 23:04:16 +01:00
78c4751c53
ci: 24.0.0 2025-03-27 22:06:04 +01:00
1f79f484e5
fix: Make EDT coroutine modality state explicit everywhere and fix deadlocks 2025-03-27 22:05:02 +01:00
6c14ad7113
chore: fix kotlin compiler warnings 2025-03-27 21:36:52 +01:00
ab5948a51b
chore: remove obsolete lang keys 2025-03-27 20:53:00 +01:00
a950c932f5
fix: show build errors in console properly 2025-03-27 20:51:19 +01:00
46069b9a22
fix: file path browse buttons in run configs 2025-03-27 20:50:36 +01:00
0a5a765eaf
feat!: TTY support for zig processes 2025-03-27 20:49:50 +01:00
da38433eb3
fix: IPC wrapper pass exit code 2025-03-27 20:40:47 +01:00
7c1aa36d82
ci: 23.1.2 2025-03-27 11:50:33 +01:00
ceea101170
fix: IDE warning when renaming symbols 2025-03-27 11:49:50 +01:00
6dacf97583
ci: 23.1.1 2025-03-26 23:33:53 +01:00
b497f04e40
fix: ignore zls settings panel contents when project is default 2025-03-26 23:33:15 +01:00
13266d112c
ci: 23.1.0 2025-03-26 16:23:02 +01:00
74f1ceb880
chore: remove obsolete lang keys 2025-03-26 16:22:44 +01:00
af9ebee500
feat: Add support for ctrl+shift+f10 2025-03-26 16:22:42 +01:00
cc062b533e
feat: centralize direnv config 2025-03-26 16:20:25 +01:00
612841724c
ci: jbpublish do not depend on signPlugin 2025-03-23 15:02:31 +01:00
0cbce88d10
ci: next dev 2025-03-23 14:40:34 +01:00
1ce31d786d
ci: 23.0.2 2025-03-23 14:40:34 +01:00
8880f22840
ci: add push.sh 2025-03-23 14:40:33 +01:00
94fe15409a
chore: organize zig lexer 2025-03-23 14:40:33 +01:00
868c37c567
fix: improve comment and multiline string tokenizer 2025-03-23 14:35:21 +01:00
e33c96d658
chore: grammar tidy 2025-03-23 12:12:57 +01:00
f02f50c1a7
ci: next dev 2025-03-20 00:23:35 +01:00
9faa421ad9
ci: 23.0.1 2025-03-20 00:18:12 +01:00
009db1cb0f
chore: Optimize imports 2025-03-20 00:13:32 +01:00
5c682f6bfa
fix: EDT deadlocks 2025-03-20 00:10:31 +01:00
cc7d1393d6
fix: improved mkfifo/bash detection for ZIG_PROGRESS 2025-03-19 16:52:17 +01:00
7ee7e2f3d1
ci: next dev 2025-03-19 16:51:57 +01:00
f138a2a4ba
ci: 23.0.0 2025-03-15 16:46:05 +01:00
7c14ca2944
chore: zls version visualizer get rid of trailing newline 2025-03-15 16:41:06 +01:00
7c0fb4412d
feat: remove custom templates for now 2025-03-15 16:40:48 +01:00
cb4ecb9ff6
chore: remove string builder in IPC wrapper 2025-03-15 16:40:06 +01:00
7da3af7cd0
ci: bump lsp4ij dep 2025-03-15 16:39:42 +01:00
09ec2d79cc
feat: std.Progress support in debugging 2025-03-14 23:41:23 +01:00
2f8bc57fe1
feat!: Zig std.Progress support 2025-03-14 23:40:40 +01:00
b2d4355488
ci: next dev 2025-03-14 11:28:27 +01:00
1382aed48c
docs: update supporters list 2025-03-14 11:28:10 +01:00
404a554654
ci: 22.0.1 2025-03-13 23:06:34 +01:00
206cc1e437
fix: refactor ZLS restart logic 2025-03-13 23:04:08 +01:00
c6f3a8202b
fix: make workspace handler logic more error-resistant 2025-03-13 23:03:02 +01:00
4f9c324af1
fix: don't call modal progress if in write action in validateSync 2025-03-13 22:12:46 +01:00
a9b55ec830
ci: next dev 2025-03-13 16:44:20 +01:00
08a04aff2c
ci: 22.0.0 2025-03-13 16:30:41 +01:00
fbeb7985e4
docs: Add warning about breaking change 2025-03-13 16:30:08 +01:00
c6af369b1c
feat: Version indicator for zls 2025-03-13 16:29:54 +01:00
2ab3570d08
chore: Detected toolchain -> Detected zig 2025-03-13 16:27:58 +01:00
d4a1b69172
feat: Descriptive zig environment errors 2025-03-13 14:42:41 +01:00
91ee38e922
fix: Only split args when passing them to a cmdline, store them as fixed strings 2025-03-13 14:10:05 +01:00
05ff125c1d
feat!: LSP misconfiguration warning banner 2025-03-13 13:52:06 +01:00
03a86defb9
fix: do not directly depend on com.intellij.nativeDebug in the plugin xml 2025-03-13 13:09:44 +01:00
a1c952e019
ci: next dev 2025-03-11 14:30:02 +01:00
5399fbe2a9
chore: remove code of merit 2025-03-11 14:29:48 +01:00
f1bbe84c71
ci: 21.1.0 2025-03-11 14:08:48 +01:00
d80230cba5
feat: zon lsp integration 2025-03-11 14:07:59 +01:00
e2406b406c
feat!: zon lexer/parser rewrite 2025-03-11 14:07:44 +01:00
e177001020
ci: next dev 2025-03-11 02:01:56 +01:00
f57d78f8c3
ci: 21.0.0 2025-03-11 01:31:35 +01:00
683aa7fad1
chore: get rid of weird import 2025-03-11 01:22:50 +01:00
c31a78d547
chore: [NO BACKPORT] fix 25.1 deprecations 2025-03-11 00:43:06 +01:00
16fb4b57b7
feat: Integrate stdlib into workspace model 2025-03-10 23:59:07 +01:00
88df5b1426
feat: Improved missing toolchain resistance 2025-03-10 23:57:56 +01:00
6b8b82e710
fix: zig env IDE error 2025-03-10 22:07:31 +01:00
f26be52940
chore: refactor new project panel and zls settings 2025-03-10 21:23:50 +01:00
0982b3488d
chore: separate out lsp logic from core 2025-03-10 19:14:06 +01:00
0b22a4538b
chore: update copyright year 2025-02-06 01:17:00 +01:00
ec66112700
ci: next dev 2025-02-05 22:23:44 +01:00
8e9968b6f5
ci: 20.3.0 2025-02-05 22:23:29 +01:00
2730b88c18
chore: Fix some invalid xml warning 2025-02-05 22:22:02 +01:00
efdde4aad2
feat: Better default colors 2025-02-05 22:21:44 +01:00
2694b9e1c1
chore: Fix a couple deprecations/obsolete calls 2025-01-31 15:18:37 +01:00
aaa8885081
ci: next dev 2025-01-30 13:25:32 +01:00
278 changed files with 7546 additions and 2542 deletions

View file

@ -17,6 +17,205 @@ 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

View file

@ -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/.

10
LICENSE
View file

@ -1,5 +1,5 @@
ZigBrains
Copyright (C) 2023-2024 FalsePattern
Copyright (C) 2023-2025 FalsePattern
All Rights Reserved
The above copyright notice and this permission notice shall be included
@ -25,6 +25,11 @@ 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.
--------------------------------
@ -37,4 +42,5 @@ All of the licenses listed here are available in the following files, bundled wi
- licenses/CC_BY_SA_4.0.LICENSE
- licenses/GPL3.LICENSE
- licenses/INTELLIJ-RUST.LICENSE
- licenses/LGPL3.LICENSE
- licenses/LGPL3.LICENSE
- licenses/ZLS.LICENSE

View file

@ -15,6 +15,7 @@ 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
@ -38,6 +39,7 @@ and might as well utilize the full semver string for extra information.
## Supporters
- ### [Techatrix](https://github.com/Techatrix)
- ### [nuxusr](https://github.com/nuxusr)
- gree7
- xceno
- AnErrupTion
@ -70,11 +72,7 @@ excellent example on how to write debugger support that doesn't depend on CLion.
<!-- 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
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
@ -88,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).

View file

@ -6,15 +6,15 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
plugins {
kotlin("jvm") version "2.0.21" apply false
kotlin("plugin.serialization") version "2.0.21" apply false
id("org.jetbrains.intellij.platform") version "2.2.1"
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`
}
val publishVersions = listOf("241", "242", "243")
val publishVersions = listOf("241", "242", "243", "251")
val pluginVersionFull get() = "$pluginVersion-$pluginSinceBuild"
val pluginVersion: String by project
val pluginSinceBuild: String by project
@ -60,7 +60,6 @@ tasks {
allprojects {
idea {
module {
isDownloadJavadoc = false
isDownloadSources = true
}
}
@ -110,6 +109,7 @@ dependencies {
runtimeOnly(project(":core"))
runtimeOnly(project(":cidr"))
runtimeOnly(project(":lsp"))
}
intellijPlatform {
@ -205,6 +205,7 @@ publishVersions.forEach {
archiveFile = distFile(it)
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")

View file

@ -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")
declare -a branches=("master" "243" "242" "241")
DEFAULT_BRANCH="${branches[0]}"

View file

@ -14,6 +14,8 @@ 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") })
}
@ -27,7 +29,9 @@ dependencies {
create(IntelliJPlatformType.CLion, clionVersion, useInstaller = useInstaller)
bundledPlugins("com.intellij.clion", "com.intellij.cidr.base", "com.intellij.nativeDebug")
}
implementation(project(":core"))
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")

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,7 +24,6 @@ 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.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.SystemInfo
@ -58,8 +57,9 @@ class ZigClionDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfiguratio
}
return when(toolchain.debuggerKind) {
CPPDebugger.Kind.BUNDLED_GDB,
CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain)
CPPDebugger.Kind.BUNDLED_LLDB -> CLionLLDBDriverConfiguration(project, toolchain)
CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
CPPDebugger.Kind.BUNDLED_LLDB,
CPPDebugger.Kind.CUSTOM_LLDB -> CLionLLDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
}
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,6 +27,7 @@ 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
@ -85,7 +86,7 @@ private suspend fun availabilityCheck(project: Project, kind: DebuggerKind): Boo
}
if (downloadDebugger) {
val result = withEDTContext {
val result = withEDTContext(ModalityState.any()) {
service.downloadDebugger(project, kind)
}
if (result is ZigDebuggerToolchainService.DownloadResult.Ok) {
@ -104,7 +105,7 @@ private suspend fun showDialog(project: Project, message: String, action: String
}
}
return withEDTContext {
return withEDTContext(ModalityState.any()) {
MessageDialogBuilder
.okCancel(ZigDebugBundle.message("debugger.run.unavailable"), message)
.yesText(action)

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -22,9 +22,10 @@
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)
class ZigLocalDebugProcess(parameters: RunParameters, session: XDebugSession, consoleBuilder: TextConsoleBuilder) : CidrLocalDebugProcess(parameters, session, consoleBuilder, { Filter.EMPTY_ARRAY }, true)

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -26,11 +26,7 @@ import com.falsepattern.zigbrains.project.run.ZigProcessHandler
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.PtyCommandLine
import com.intellij.execution.process.BaseProcessHandler
import com.intellij.execution.process.ProcessAdapter
import com.intellij.execution.process.ProcessEvent
import com.intellij.execution.process.ProcessListener
import com.intellij.execution.process.ProcessOutputType
import com.intellij.execution.process.*
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.KeyWithDefaultValue
import com.intellij.openapi.util.io.toNioPathOrNull
@ -45,9 +41,12 @@ import com.jetbrains.cidr.execution.debugger.memory.AddressRange
import com.jetbrains.cidr.system.HostMachine
import com.jetbrains.cidr.system.LocalHost
import io.ktor.util.*
import kotlinx.coroutines.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.future.asCompletableFuture
import kotlinx.coroutines.future.asDeferred
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.eclipse.lsp4j.debug.*
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
@ -58,8 +57,7 @@ import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream
import java.io.PipedOutputStream
import java.lang.Exception
import java.util.TreeMap
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import kotlin.math.min
@ -213,7 +211,7 @@ abstract class DAPDriver<Server : IDebugProtocolServer, Client : IDebugProtocolC
val cli = installer.install()
val args = HashMap<String, Any>()
args["program"] = Util.toWinPath(cli.exePath)
args["cmd"] = cli.workDirectory.toString()
args["cmd"] = cli.workingDirectory.toString()
args["name"] = "CPP Debug"
args["type"] = "cppvsdbg"
args["request"] = "launch"
@ -953,7 +951,7 @@ abstract class DAPDriver<Server : IDebugProtocolServer, Client : IDebugProtocolC
fun runInTerminalAsync(args: RunInTerminalRequestArguments): RunInTerminalResponse {
val cli = PtyCommandLine(args.args.toList())
cli.charset = Charsets.UTF_8
cli.withCharset(Charsets.UTF_8)
val cwd = args.cwd?.ifBlank { null }?.toNioPathOrNull()
if (cwd != null) {
cli.withWorkingDirectory(cwd)

View file

@ -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.debugger.dap

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -39,7 +39,7 @@ class ZigExecConfigBinary(project: Project, factory: ConfigurationFactory) : Zig
get() = ZigDebugBundle.message("configuration.binary.suggested-name")
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
return args.args
return args.argsSplit()
}
override fun getConfigurables(): List<ZigConfigurable<*>> {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,14 +24,14 @@ 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.AbstractZigToolchain
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: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
override suspend fun getCommandLine(toolchain: ZigToolchain, debug: Boolean): GeneralCommandLine {
val cli = GeneralCommandLine()
val cfg = configuration
cfg.workingDirectory.path?.let { cli.withWorkingDirectory(it) }

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,6 +23,7 @@
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
@ -30,6 +31,7 @@ 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
@ -39,17 +41,17 @@ import kotlinx.coroutines.withContext
class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
var isBuildFailed: Boolean = false
private set
lateinit var processHandler: ProcessHandler
lateinit var processHandler: ZigProcessHandler.IPCAware
private set
@Throws(ExecutionException::class)
suspend fun executeCommandLineWithHook(commandLine: GeneralCommandLine): Boolean {
suspend fun executeCommandLineWithHook(project: Project, commandLine: GeneralCommandLine): Boolean {
return withProgressText(commandLine.commandLineString) {
val processHandler = ZigProcessHandler(commandLine)
val processHandler = commandLine.startIPCAwareProcess(project)
this@PreLaunchProcessListener.processHandler = processHandler
hook(processHandler)
processHandler.startNotify()
withContext(Dispatchers.Default) {
withContext(Dispatchers.IO) {
processHandler.process.awaitExit()
}
runInterruptible {
@ -66,10 +68,6 @@ class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
override fun processTerminated(event: ProcessEvent) {
if (event.exitCode != 0) {
console.print(
"Process finished with exit code " + event.exitCode,
ConsoleViewContentType.NORMAL_OUTPUT
)
isBuildFailed = true
} else {
isBuildFailed = false

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,9 +23,10 @@
package com.falsepattern.zigbrains.debugger.runner.base
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
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
@ -33,13 +34,13 @@ import java.io.File
class ZigDebugEmitBinaryInstaller<ProfileState: ZigProfileState<*>>(
private val profileState: ProfileState,
private val toolchain: AbstractZigToolchain,
private val toolchain: ZigToolchain,
private val executableFile: File,
private val exeArgs: List<String>
): Installer {
override fun install(): GeneralCommandLine {
val cfg = profileState.configuration
val cli = GeneralCommandLine().withExePath(executableFile.absolutePath)
val cli = PtyCommandLine().withConsoleMode(false).withExePath(executableFile.absolutePath)
cfg.workingDirectory.path?.let { x -> cli.withWorkingDirectory(x) }
cli.addParameters(exeArgs)
cli.withCharset(Charsets.UTF_8)

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,7 +23,7 @@
package com.falsepattern.zigbrains.debugger.runner.base
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
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
@ -31,7 +31,7 @@ import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
abstract class ZigDebugParametersBase<ProfileState: ZigProfileState<*>>(
private val driverConfiguration: DebuggerDriverConfiguration,
protected val toolchain: AbstractZigToolchain,
protected val toolchain: ZigToolchain,
protected val profileState: ProfileState
): RunParameters() {
override fun getDebuggerDriverConfiguration(): DebuggerDriverConfiguration {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,9 +24,10 @@ 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.AbstractZigToolchain
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
@ -36,10 +37,11 @@ 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: AbstractZigToolchain,
toolchain: ZigToolchain,
profileState: ProfileState,
) : ZigDebugParametersBase<ProfileState>(driverConfiguration, toolchain, profileState), PreLaunchAware {
@Volatile
@ -49,13 +51,14 @@ abstract class ZigDebugParametersEmitBinaryBase<ProfileState: ZigProfileState<*>
@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(commandLine))
throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.generic"))
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 ->

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,9 +24,10 @@ 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.AbstractZigToolchain
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
@ -40,6 +41,8 @@ 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
@ -51,13 +54,13 @@ abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgra
@Throws(ExecutionException::class)
override suspend fun execute(
state: ProfileState,
toolchain: AbstractZigToolchain,
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 = false, DebuggerDriverConfiguration::class.java) ?: continue
val driver = provider.getDebuggerConfiguration(project, isElevated = false, emulateTerminal = true, DebuggerDriverConfiguration::class.java) ?: continue
return executeWithDriver(state, toolchain, environment, driver) ?: continue
}
return null
@ -66,7 +69,7 @@ abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgra
@Throws(ExecutionException::class)
private suspend fun executeWithDriver(
state: ProfileState,
toolchain: AbstractZigToolchain,
toolchain: ZigToolchain,
environment: ExecutionEnvironment,
debuggerDriver: DebuggerDriverConfiguration
): RunContentDescriptor? {
@ -81,22 +84,25 @@ abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgra
}
} catch (e: ExecutionException) {
console.print("\n", ConsoleViewContentType.ERROR_OUTPUT)
e.message?.let { listener.console.print(it, ConsoleViewContentType.SYSTEM_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)
return@reportProgress withEDTContext {
val executionResult = DefaultExecutionResult(console, listener.processHandler.unwrap())
return@reportProgress withEDTContext(ModalityState.any()) {
val runContentBuilder = RunContentBuilder(executionResult, environment)
runContentBuilder.showRunContent(null)
}
}
}
return@reportProgress runInterruptibleEDT {
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 = SharedConsoleBuilder(console)
val textConsoleBuilder = state.consoleBuilder
val debugProcess = ZigLocalDebugProcess(runParameters, session, textConsoleBuilder)
ProcessTerminatedListener.attach(debugProcess.processHandler, project)
debugProcess.start()
@ -111,7 +117,7 @@ abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgra
protected abstract fun getDebugParameters(
state: ProfileState,
debuggerDriver: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain
toolchain: ZigToolchain
): ZigDebugParametersBase<ProfileState>
private class SharedConsoleBuilder(private val console: ConsoleView) : TextConsoleBuilder() {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -26,16 +26,16 @@ 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.AbstractZigToolchain
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: AbstractZigToolchain, profileState: ZigProfileStateBinary) :
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.args)
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.args.argsSplit())
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,8 +27,8 @@ import com.falsepattern.zigbrains.debugger.execution.binary.ZigProfileStateBinar
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.AbstractZigToolchain
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
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
@ -36,7 +36,7 @@ class ZigDebugRunnerBinary: ZigDebugRunnerBase<ZigProfileStateBinary>() {
override fun getDebugParameters(
state: ZigProfileStateBinary,
debuggerDriver: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain
toolchain: ZigToolchain
): ZigDebugParametersBase<ZigProfileStateBinary> {
return ZigDebugParametersBinary(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -28,7 +28,7 @@ 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.AbstractZigToolchain
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
@ -46,14 +46,14 @@ import kotlin.io.path.isRegularFile
class ZigDebugParametersBuild(
driverConfiguration: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain,
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.args)
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.argsSplit())
}
@Throws(ExecutionException::class)
@ -61,8 +61,8 @@ class ZigDebugParametersBuild(
withProgressText("Building zig project") {
withContext(Dispatchers.IO) {
val commandLine = profileState.getCommandLine(toolchain, true)
if (listener.executeCommandLineWithHook(commandLine))
throw ExecutionException(ZigDebugBundle.message("debug.build.compile.failed.generic"))
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 {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,8 +27,8 @@ 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.AbstractZigToolchain
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
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
@ -36,7 +36,7 @@ class ZigDebugRunnerBuild: ZigDebugRunnerBase<ZigProfileStateBuild>() {
override fun getDebugParameters(
state: ZigProfileStateBuild,
debuggerDriver: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain
toolchain: ZigToolchain
): ZigDebugParametersBase<ZigProfileStateBuild> {
return ZigDebugParametersBuild(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -25,13 +25,13 @@ 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.AbstractZigToolchain
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: AbstractZigToolchain, profileState: ZigProfileStateRun) :
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.args)
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.argsSplit())
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,8 +27,8 @@ 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.AbstractZigToolchain
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
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
@ -36,7 +36,7 @@ class ZigDebugRunnerRun: ZigDebugRunnerBase<ZigProfileStateRun>() {
override fun getDebugParameters(
state: ZigProfileStateRun,
debuggerDriver: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain
toolchain: ZigToolchain
): ZigDebugParametersBase<ZigProfileStateRun> {
return ZigDebugParametersRun(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -25,11 +25,11 @@ 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.AbstractZigToolchain
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: AbstractZigToolchain, profileState: ZigProfileStateTest) :
class ZigDebugParametersTest(driverConfiguration: DebuggerDriverConfiguration, toolchain: ZigToolchain, profileState: ZigProfileStateTest) :
ZigDebugParametersEmitBinaryBase<ZigProfileStateTest>(driverConfiguration, toolchain, profileState) {
override fun getInstaller(): Installer {
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, listOf())

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,8 +27,8 @@ 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.AbstractZigToolchain
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
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
@ -36,7 +36,7 @@ class ZigDebugRunnerTest: ZigDebugRunnerBase<ZigProfileStateTest>() {
override fun getDebugParameters(
state: ZigProfileStateTest,
debuggerDriver: DebuggerDriverConfiguration,
toolchain: AbstractZigToolchain
toolchain: ZigToolchain
): ZigDebugParametersBase<ZigProfileStateTest> {
return ZigDebugParametersTest(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -31,6 +31,7 @@ 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
@ -88,7 +89,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent {
row(ZigDebugBundle.message("settings.debugger.toolchain.debugger.label")) {
comment = cell(debuggerKindComboBox)
.comment("", DEFAULT_COMMENT_WIDTH) {
zigCoroutineScope.launchWithEDT {
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
withModalProgress(ModalTaskOwner.component(debuggerKindComboBox), "Downloading debugger", TaskCancellation.cancellable()) {
downloadDebugger()
}
@ -96,7 +97,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent {
}
.applyToComponent {
whenItemSelected(null) {
zigCoroutineScope.launchWithEDT {
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
this@ZigDebuggerToolchainConfigurableUi.update()
}
}
@ -111,7 +112,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent {
cell(useClion)
}
}
zigCoroutineScope.launchWithEDT {
zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
update()
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -27,10 +27,8 @@ 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.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.intellij.notification.Notification
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.progress.coroutineToIndicator
import com.intellij.openapi.ui.DialogBuilder
import com.intellij.platform.util.progress.withProgressText

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,6 +23,7 @@
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
@ -34,22 +35,20 @@ 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.io.Decompressor
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.runInterruptible
import kotlinx.coroutines.withContext
import java.io.File
import java.io.IOException
import java.net.URL
import java.nio.file.Path
@ -169,7 +168,9 @@ class ZigDebuggerToolchainService {
}
try {
downloadAndUnArchive(baseDir, downloadableBinaries)
withContext(Dispatchers.IO) {
downloadAndUnArchive(baseDir, downloadableBinaries)
}
return DownloadResult.Ok(baseDir)
} catch (e: IOException) {
//TODO logging
@ -208,34 +209,40 @@ class ZigDebuggerToolchainService {
@Throws(IOException::class)
@RequiresEdt
private suspend fun downloadAndUnArchive(baseDir: Path, binariesToDownload: List<DownloadableDebuggerBinary>) {
val service = DownloadableFileService.getInstance()
reportSequentialProgress { reporter ->
val service = DownloadableFileService.getInstance()
val downloadDir = baseDir.toFile()
downloadDir.deleteRecursively()
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 = withContext(Dispatchers.IO) {
coroutineToIndicator {
downloader.download(downloadDirectory)
val descriptions = binariesToDownload.map {
service.createFileDescription(it.url, fileName(it.url))
}
}
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
Unarchiver.unarchive(archiveFile, downloadDir, binaryToDownload.prefix)
archiveFile.delete()
versions[propertyName] = binaryToDownload.version
}
saveVersionsFile(baseDir, versions)
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>? {
@ -330,38 +337,6 @@ class ZigDebuggerToolchainService {
}
}
private enum class Unarchiver {
ZIP {
override val extension = "zip"
override fun createDecompressor(file: File) = Decompressor.Zip(file)
},
TAR {
override val extension = "tar.gz"
override fun createDecompressor(file: File) = Decompressor.Tar(file)
},
VSIX {
override val extension = "vsix"
override fun createDecompressor(file: File) = Decompressor.Zip(file)
};
protected abstract val extension: String
protected abstract fun createDecompressor(file: File): Decompressor
companion object {
@Throws(IOException::class)
suspend fun unarchive(archivePath: File, dst: File, prefix: String? = null) {
runInterruptible {
val unarchiver = entries.find { archivePath.name.endsWith(it.extension) } ?: error("Unexpected archive type: $archivePath")
val dec = unarchiver.createDecompressor(archivePath)
if (prefix != null) {
dec.removePrefixPath(prefix)
}
dec.extract(dst)
}
}
}
}
sealed class DownloadResult {
class Ok(val baseDir: Path): DownloadResult()
data object NoUrls: DownloadResult()

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -40,7 +40,7 @@ abstract class MSVCDriverConfiguration: DAPDebuggerDriverConfiguration() {
override fun createDriverCommandLine(driver: DebuggerDriver, arch: ArchitectureType): GeneralCommandLine {
val path = debuggerExecutable
val cli = GeneralCommandLine()
cli.exePath = path.pathString
cli.withExePath(path.pathString)
cli.addParameters("--interpreter=vscode", "--extconfigdir=%USERPROFILE%\\.cppvsdbg\\extensions")
cli.withWorkingDirectory(path.parent)
return cli

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -39,9 +39,8 @@ 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.lang.RuntimeException
import java.security.MessageDigest
import java.util.Base64
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.zip.Inflater

View file

@ -1,5 +1,5 @@
<idea-plugin package="com.falsepattern.zigbrains.debugger">
<depends>com.intellij.nativeDebug</depends>
<depends>com.intellij.modules.cidr.debugger</depends>
<extensions defaultExtensionNs="com.intellij">
<configurationType

View file

@ -15,7 +15,7 @@ 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
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

View file

@ -7,18 +7,17 @@ plugins {
kotlin("plugin.serialization")
}
val lsp4ijVersion: String by project
val lsp4jVersion: String by project
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("com.redhat.devtools.intellij:lsp4ij:$lsp4ijVersion")
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3")
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:$serializationVersion") {
isTransitive = false
}
}
//region grammars

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -34,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}
@ -53,13 +56,13 @@ dec_int={dec} {dec_}*
hex_int={hex} {hex_}*
char_char= \\ .
| [^\'\n]
| [^\'\r\n\u0085\u2028\u2029]
string_char= \\ .
| [^\"\n]
| [^\"\r\n\u0085\u2028\u2029]
all_nl_wrap=[^\n]* [ \n]*
all_no_nl=[^\n]+
nl_wrap={LF} (\s|{LF})*
all_no_nl=[^\r\n\u0085\u2028\u2029]+
FLOAT= "0x" {hex_int} "." {hex_int} ([pP] [-+]? {dec_int})?
@ -83,30 +86,35 @@ BUILTINIDENTIFIER="@"[A-Za-z_][A-Za-z0-9_]*
%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_no_nl} { }
<CDOC_CMT> \n { yybegin(YYINITIAL); return CONTAINER_DOC_COMMENT; }
<CDOC_CMT> <<EOF>> { 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_no_nl} { }
<DOC_CMT> \n { yybegin(YYINITIAL); return DOC_COMMENT; }
<DOC_CMT> <<EOF>> { 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_no_nl} { }
<LINE_CMT> \n { yybegin(YYINITIAL); return LINE_COMMENT; }
<LINE_CMT> <<EOF>> { 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; }
@ -226,24 +234,31 @@ 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> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
<CHAR_LIT> [^] { yypushback(1); yybegin(UNT_SQUOT); }
<YYINITIAL> {FLOAT} { return FLOAT; }
<YYINITIAL> {INTEGER} { return INTEGER; }
<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_nl_wrap} "\\\\" { }
<STR_MULT_LINE> {all_no_nl} { }
<STR_MULT_LINE> \n { yybegin(YYINITIAL); return STRING_LITERAL_MULTI; }
<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; }
@ -252,13 +267,17 @@ BUILTINIDENTIFIER="@"[A-Za-z_][A-Za-z0-9_]*
<YYINITIAL> {BUILTINIDENTIFIER} { return BUILTINIDENTIFIER; }
//Error handling
<UNT_SQUOT> <<EOF>> { yybegin(YYINITIAL); return BAD_SQUOT; }
<UNT_SQUOT> {CRLF} { 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> {CRLF} { 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; }

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -34,46 +34,57 @@
elementTypeClass="com.falsepattern.zigbrains.zon.parser.ZonElementType"
tokenTypeClass="com.falsepattern.zigbrains.zon.parser.ZonTokenType"
tokens=[
LINE_COMMENT='comment'
DOT='.'
EQUAL='='
LBRACE='{'
RBRACE='}'
EQ='='
COMMA=','
COMMENT='comment'
ID='identifier'
STRING_LITERAL_SINGLE='string'
LINE_STRING='multiline string'
BAD_STRING='unterminated string'
BOOL_TRUE='true'
BOOL_FALSE='false'
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'
]
//Mixins
mixin("entry")="com.falsepattern.zigbrains.zon.psi.impl.mixins.ZonEntryMixinImpl"
implements("entry")="com.falsepattern.zigbrains.zon.psi.mixins.ZonEntryMixin"
mixin("identifier")="com.falsepattern.zigbrains.zon.psi.impl.mixins.ZonIdentifierMixinImpl"
implements("identifier")="com.falsepattern.zigbrains.zon.psi.mixins.ZonIdentifierMixin"
}
zonFile ::= entry
Root ::= Expr
entry ::= DOT LBRACE (list | struct | ()) RBRACE
Expr
::= CHAR_LITERAL
| StringLiteral
| DOT IDENTIFIER
| DOT InitList
| Bool
| Number
| KEYWORD_NULL
struct ::= (property | property_placeholder) (COMMA (property_placeholder? property property_placeholder? | property_placeholder))* COMMA?
list ::= value (COMMA value)* COMMA?
InitList
::= LBRACE ZB_InitList_Body RBRACE {pin=1}
property ::= DOT identifier EQ value
private ZB_InitList_Body
::= FieldInit (COMMA ZB_InitList_FieldInit)* COMMA?
| Expr (COMMA ZB_InitList_Expr)* COMMA?
| ()
identifier ::= ID
private ZB_InitList_FieldInit ::= FieldInit {recoverWhile="ZB_InitList_Recover"}
private ZB_InitList_Expr ::= Expr {recoverWhile="ZB_InitList_Recover"}
property_placeholder ::= DOT? INTELLIJ_COMPLETION_DUMMY
private ZB_InitList_Recover ::= !(COMMA | RBRACE)
private value ::= entry | boolean | STRING_LITERAL | value_placeholder
FieldInit ::= DOT IDENTIFIER EQUAL Expr
value_placeholder ::= INTELLIJ_COMPLETION_DUMMY
Bool ::= KEYWORD_TRUE | KEYWORD_FALSE
boolean ::= BOOL_TRUE | BOOL_FALSE
Number ::= FLOAT | INTEGER | NUM_NAN | NUM_INF
STRING_LITERAL ::= STRING_LITERAL_SINGLE | LINE_STRING+
StringLiteral ::= STRING_LITERAL_SINGLE | STRING_LITERAL_MULTI

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -36,54 +36,124 @@ import static com.falsepattern.zigbrains.zon.psi.ZonTypes.*;
%type IElementType
%unicode
CRLF=\R
WHITE_SPACE=[\s]+
LINE_COMMENT="//" [^\n]* | "////" [^\n]*
COMMENT="///".*
WHITE_SPACE=\s+
ID=[A-Za-z_][A-Za-z0-9_]*
// visual studio parity
LF=\r\n?|[\n\u0085\u2028\u2029]
bin=[01]
bin_="_"? {bin}
oct=[0-7]
oct_="_"? {oct}
hex=[0-9a-fA-F]
char_escape
= "\\x" {hex} {hex}
| "\\u{" {hex}+ "}"
| "\\" [nr\\t'\"]
hex_="_"? {hex}
dec=[0-9]
dec_="_"? {dec}
string_char
= {char_escape}
| [^\\\"\n]
bin_int={bin} {bin_}*
oct_int={oct} {oct_}*
dec_int={dec} {dec_}*
hex_int={hex} {hex_}*
LINE_STRING=("\\\\" [^\n]* [ \n]*)+
char_char= \\ .
| [^\'\r\n\u0085\u2028\u2029]
%state STRING_LITERAL
%state ID_STRING
%state UNCLOSED_STRING
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> {WHITE_SPACE} { return WHITE_SPACE; }
<YYINITIAL> "." { return DOT; }
<YYINITIAL> "IntellijIdeaRulezzz" { return INTELLIJ_COMPLETION_DUMMY; }
<YYINITIAL> "=" { return EQUAL; }
<YYINITIAL> "{" { return LBRACE; }
<YYINITIAL> "}" { return RBRACE; }
<YYINITIAL> "=" { return EQ; }
<YYINITIAL> "," { return COMMA; }
<YYINITIAL> "true" { return BOOL_TRUE; }
<YYINITIAL> "false" { return BOOL_FALSE; }
<YYINITIAL> {COMMENT} { return COMMENT; }
<YYINITIAL> {LINE_COMMENT} { return COMMENT; }
<YYINITIAL> {ID} { return ID; }
<YYINITIAL> "@\"" { yybegin(ID_STRING); }
<ID_STRING> {string_char}*"\"" { yybegin(YYINITIAL); return ID; }
<ID_STRING> [^] { yypushback(1); yybegin(UNCLOSED_STRING); }
//Keywords
<YYINITIAL> "\"" { yybegin(STRING_LITERAL); }
<STRING_LITERAL> {string_char}*"\"" { yybegin(YYINITIAL); return STRING_LITERAL_SINGLE; }
<STRING_LITERAL> [^] { yypushback(1); yybegin(UNCLOSED_STRING); }
<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; }
<UNCLOSED_STRING>[^\n]*{CRLF} { yybegin(YYINITIAL); return BAD_STRING; }
//Strings
<YYINITIAL> {LINE_STRING} { return LINE_STRING; }
<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; }

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -22,13 +22,6 @@
package com.falsepattern.zigbrains
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.direnv.emptyEnv
import com.falsepattern.zigbrains.direnv.getDirenv
import com.falsepattern.zigbrains.lsp.settings.zlsSettings
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider
import com.intellij.ide.BrowserUtil
import com.intellij.ide.plugins.PluginManager
import com.intellij.notification.Notification
@ -40,10 +33,8 @@ 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 com.intellij.openapi.util.UserDataHolderBase
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import kotlin.io.path.pathString
class ZBStartup: ProjectActivity {
var firstInit = true
@ -76,30 +67,6 @@ class ZBStartup: ProjectActivity {
notif.notify(null)
}
}
//Autodetection
val zigProjectState = project.zigProjectSettings.state
if (zigProjectState.toolchainPath.isNullOrBlank()) {
val data = UserDataHolderBase()
data.putUserData(LocalZigToolchain.DIRENV_KEY,
DirenvCmd.direnvInstalled() && !project.isDefault && zigProjectState.direnv
)
val tc = ZigToolchainProvider.suggestToolchain(project, data) ?: return
if (tc is LocalZigToolchain) {
zigProjectState.toolchainPath = tc.location.pathString
project.zigProjectSettings.state = zigProjectState
}
}
val zlsState = project.zlsSettings.state
if (zlsState.zlsPath.isBlank()) {
val env = if (DirenvCmd.direnvInstalled() && !project.isDefault && zlsState.direnv)
project.getDirenv()
else
emptyEnv
env.findExecutableOnPATH("zls")?.let {
zlsState.zlsPath = it.pathString
project.zlsSettings.state = zlsState
}
}
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -29,23 +29,53 @@ 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
object DirenvCmd {
suspend fun importDirenv(project: Project): Env {
if (!direnvInstalled() || !project.isTrusted())
return emptyEnv
val workDir = project.guessProjectDir()?.toNioPath() ?: return emptyEnv
@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()
val runOutput = run(project, workDir, "export", "json")
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(
@ -54,7 +84,7 @@ object DirenvCmd {
ZigBrainsBundle.message("notification.content.direnv-blocked"),
NotificationType.ERROR
))
return emptyEnv
return Env.empty
} else {
Notifications.Bus.notify(Notification(
GROUP_DISPLAY_ID,
@ -62,22 +92,22 @@ object DirenvCmd {
ZigBrainsBundle.message("notification.content.direnv-error", runOutput.output),
NotificationType.ERROR
))
return emptyEnv
return Env.empty
}
}
return if (runOutput.output.isBlank()) {
emptyEnv
Env.empty
} else {
Env(Json.decodeFromString<Map<String, String>>(runOutput.output))
}
}
private suspend fun run(project: Project, workDir: Path, vararg args: String): DirenvOutput {
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) {
project.direnvService.mutex.withLock {
mutex.withLock {
val process = cli.createProcess()
val exitCode = process.awaitExit()
process to exitCode
@ -94,17 +124,39 @@ object DirenvCmd {
return DirenvOutput(stdOut, false)
}
private const val GROUP_DISPLAY_ID = "zigbrains-direnv"
private val _direnvInstalled 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
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)
}
}
fun direnvInstalled() = _direnvInstalled
}
suspend fun Project?.getDirenv(): Env {
if (this == null)
return emptyEnv
return DirenvCmd.importDirenv(this)
}
sealed interface IDirenvService {
val isInstalled: Boolean
val isEnabled: DirenvState
suspend fun import(): Env
}
private val envFiles = listOf(".envrc", ".env")

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -22,14 +22,19 @@
package com.falsepattern.zigbrains.direnv
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import kotlinx.coroutines.sync.Mutex
@Service(Service.Level.PROJECT)
class DirenvProjectService {
val mutex = Mutex()
}
enum class DirenvState {
Auto,
Enabled,
Disabled;
val Project.direnvService get() = service<DirenvProjectService>()
fun isEnabled(project: Project?): Boolean {
return when(this) {
Enabled -> true
Disabled -> false
Auto -> project?.service<DirenvService>()?.hasDotEnv() == true
}
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -25,20 +25,26 @@ 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 java.nio.file.Path
import kotlin.io.path.*
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 findExecutableOnPATH(exe: @NonNls String): Path? {
fun findAllExecutablesOnPATH(exe: @NonNls String) = flow {
val exeName = if (SystemInfo.isWindows) "$exe.exe" else exe
val paths = path ?: return null
val paths = path ?: return@flow
for (dir in paths) {
val path = dir.toNioPathOrNull()?.absolute() ?: continue
if (!path.toFile().exists() || !path.isDirectory())
@ -46,10 +52,11 @@ data class Env(val env: Map<String, String>) {
val exePath = path.resolve(exeName).absolute()
if (!exePath.isRegularFile() || !exePath.isExecutable())
continue
return exePath
emit(exePath)
}
return null
}.flowOn(Dispatchers.IO)
companion object {
val empty = Env(emptyMap())
}
}
val emptyEnv = Env(emptyMap())

View file

@ -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
}
}

View file

@ -1,39 +0,0 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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/>.
*/
@file:Suppress("HardCodedStringLiteral")
package com.falsepattern.zigbrains.lsp.config
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.NonNls
@Serializable
data class ZLSConfig(
@SerialName("zig_exe_path") val zigExePath: @NonNls String? = null,
@SerialName("zig_lib_path") val zigLibPath: @NonNls String? = null,
@SerialName("enable_build_on_save") val buildOnSave: Boolean? = null,
@SerialName("build_on_save_step") val buildOnSaveStep: @NonNls String? = null,
@SerialName("dangerous_comptime_experiments_do_not_enable") val comptimeInterpreter: Boolean? = null,
@SerialName("highlight_global_var_declarations") val globalVarDeclarations: Boolean? = null
)

View file

@ -1,119 +0,0 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.falsepattern.zigbrains.direnv.emptyEnv
import com.falsepattern.zigbrains.direnv.getDirenv
import com.falsepattern.zigbrains.lsp.ZLSBundle
import com.intellij.openapi.components.*
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.util.application
import kotlinx.coroutines.runBlocking
import java.nio.file.Path
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import kotlin.io.path.isExecutable
import kotlin.io.path.isRegularFile
@Service(Service.Level.PROJECT)
@State(
name = "ZLSSettings",
storages = [Storage(value = "zigbrains.xml")]
)
class ZLSProjectSettingsService(val project: Project): PersistentStateComponent<ZLSSettings> {
@Volatile
private var state = ZLSSettings()
@Volatile
private var dirty = true
@Volatile
private var valid = false
private val mutex = ReentrantLock()
override fun getState(): ZLSSettings {
return state.copy()
}
fun setState(value: ZLSSettings) {
mutex.withLock {
this.state = value
dirty = true
}
}
override fun loadState(state: ZLSSettings) {
mutex.withLock {
this.state = state
dirty = true
}
}
fun isModified(otherData: ZLSSettings): Boolean {
return state != otherData
}
fun validate(): Boolean {
mutex.withLock {
if (dirty) {
val state = this.state
valid = if (application.isDispatchThread) {
runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
doValidate(project, state)
}
} else {
runBlocking {
doValidate(project, state)
}
}
dirty = false
}
return valid
}
}
}
private suspend fun doValidate(project: Project, state: ZLSSettings): Boolean {
val zlsPath: Path = state.zlsPath.let { zlsPath ->
if (zlsPath.isEmpty()) {
val env = if (state.direnv) project.getDirenv() else emptyEnv
env.findExecutableOnPATH("zls") ?: run {
return false
}
} else {
zlsPath.toNioPathOrNull() ?: run {
return false
}
}
}
if (!zlsPath.toFile().exists()) {
return false
}
if (!zlsPath.isRegularFile() || !zlsPath.isExecutable()) {
return false
}
return true
}
val Project.zlsSettings get() = service<ZLSProjectSettingsService>()

View file

@ -1,59 +0,0 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.falsepattern.zigbrains.lsp.startLSP
import com.falsepattern.zigbrains.shared.SubConfigurable
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.ui.dsl.builder.Panel
class ZLSSettingsConfigurable(private val project: Project): SubConfigurable {
private var appSettingsComponent: ZLSSettingsPanel? = null
override fun createComponent(panel: Panel) {
appSettingsComponent = ZLSSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) }
}
override fun isModified(): Boolean {
val data = appSettingsComponent?.data ?: return false
return project.zlsSettings.state != data
}
override fun apply() {
val data = appSettingsComponent?.data ?: return
val settings = project.zlsSettings
val reloadZLS = settings.isModified(data)
settings.state = data
if (reloadZLS) {
startLSP(project, true)
}
}
override fun reset() {
appSettingsComponent?.data = project.zlsSettings.state
}
override fun dispose() {
appSettingsComponent = null
}
}

View file

@ -1,146 +0,0 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.direnv.Env
import com.falsepattern.zigbrains.direnv.emptyEnv
import com.falsepattern.zigbrains.direnv.getDirenv
import com.falsepattern.zigbrains.lsp.ZLSBundle
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.openapi.Disposable
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
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.components.fields.ExtendableTextField
import com.intellij.ui.components.textFieldWithBrowseButton
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.Panel
import kotlin.io.path.pathString
class ZLSSettingsPanel(private val project: Project?) : Disposable {
private val zlsPath = textFieldWithBrowseButton(
project,
FileChooserDescriptorFactory.createSingleFileDescriptor().withTitle(ZLSBundle.message("settings.zls-path.browse.title")),
).also { Disposer.register(this, it) }
private val zlsConfigPath = textFieldWithBrowseButton(
project,
FileChooserDescriptorFactory.createSingleFileDescriptor().withTitle(ZLSBundle.message("settings.zls-config-path.browse.title"))
).also { Disposer.register(this, it) }
private val buildOnSave = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.build-on-save.tooltip") }
private val buildOnSaveStep = ExtendableTextField().apply { toolTipText = ZLSBundle.message("settings.build-on-save-step.tooltip") }
private val globalVarDeclarations = JBCheckBox()
private val comptimeInterpreter = JBCheckBox()
private val inlayHints = JBCheckBox()
private val inlayHintsCompact = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.inlay-hints-compact.tooltip") }
private val messageTrace = JBCheckBox()
private val debug = JBCheckBox()
private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label")).apply { addActionListener {
dispatchAutodetect(true)
} }
fun attach(panel: Panel) = with(panel) {
group(ZLSBundle.message("settings.group.title")) {
row(ZLSBundle.message("settings.zls-path.label")) {
cell(zlsPath).resizableColumn().align(AlignX.FILL)
if (DirenvCmd.direnvInstalled() && project?.isDefault == false) {
cell(direnv)
}
}
row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) }
row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) }
row(ZLSBundle.message("settings.inlay-hints-compact.label")) { cell(inlayHintsCompact) }
row(ZLSBundle.message("settings.build-on-save.label")) { cell(buildOnSave) }
row(ZLSBundle.message("settings.build-on-save-step.label")) { cell(buildOnSaveStep).resizableColumn().align(AlignX.FILL) }
row(ZLSBundle.message("settings.global-var-declarations.label")) { cell(globalVarDeclarations) }
row(ZLSBundle.message("settings.comptime-interpreter.label")) { cell(comptimeInterpreter) }
}
group(ZLSBundle.message("dev-settings.group.title")) {
row(ZLSBundle.message("dev-settings.debug.label")) { cell(debug) }
row(ZLSBundle.message("dev-settings.message-trace.label")) { cell(messageTrace) }
}
dispatchAutodetect(false)
}
var data
get() = ZLSSettings(
direnv.isSelected,
zlsPath.text,
zlsConfigPath.text,
debug.isSelected,
messageTrace.isSelected,
buildOnSave.isSelected,
buildOnSaveStep.text,
globalVarDeclarations.isSelected,
comptimeInterpreter.isSelected,
inlayHints.isSelected,
inlayHintsCompact.isSelected
)
set(value) {
direnv.isSelected = value.direnv
zlsPath.text = value.zlsPath
zlsConfigPath.text = value.zlsConfigPath
debug.isSelected = value.debug
messageTrace.isSelected = value.messageTrace
buildOnSave.isSelected = value.buildOnSave
buildOnSaveStep.text = value.buildOnSaveStep
globalVarDeclarations.isSelected = value.globalVarDeclarations
comptimeInterpreter.isSelected = value.comptimeInterpreter
inlayHints.isSelected = value.inlayHints
inlayHintsCompact.isSelected = value.inlayHintsCompact
}
private fun dispatchAutodetect(force: Boolean) {
project.zigCoroutineScope.launchWithEDT {
withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) {
autodetect(force)
}
}
}
suspend fun autodetect(force: Boolean) {
if (force || zlsPath.text.isBlank()) {
getDirenv().findExecutableOnPATH("zls")?.let {
if (force || zlsPath.text.isBlank()) {
zlsPath.text = it.pathString
}
}
}
}
override fun dispose() {
}
private suspend fun getDirenv(): Env {
if (DirenvCmd.direnvInstalled() && project?.isDefault == false && direnv.isSelected)
return project.getDirenv()
return emptyEnv
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View 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
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -20,20 +20,18 @@
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.zigbrains.lsp.settings
package com.falsepattern.zigbrains.project.execution
import org.jetbrains.annotations.NonNls
import com.intellij.execution.filters.TextConsoleBuilderImpl
import com.intellij.execution.ui.ConsoleView
import com.intellij.openapi.project.Project
import com.intellij.terminal.TerminalExecutionConsole
data class ZLSSettings(
var direnv: Boolean = false,
var zlsPath: @NonNls String = "",
var zlsConfigPath: @NonNls String = "",
var debug: Boolean = false,
var messageTrace: Boolean = false,
var buildOnSave: Boolean = false,
var buildOnSaveStep: @NonNls String = "install",
var globalVarDeclarations: Boolean = false,
var comptimeInterpreter: Boolean = false,
var inlayHints: Boolean = true,
var inlayHintsCompact: Boolean = true
)
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()
}
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,20 +24,17 @@ 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.project.settings.zigProjectSettings
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.project.Project
import com.intellij.openapi.ui.ComboBox
import com.intellij.openapi.ui.TextBrowseFolderListener
import com.intellij.openapi.ui.TextFieldWithBrowseButton
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
@ -161,12 +158,10 @@ class WorkDirectoryConfigurable(@Transient override val serializedName: String)
}
class WorkDirectoryConfigModule(private val serializedName: String) : PathConfigModule<WorkDirectoryConfigurable>() {
private val field = TextFieldWithBrowseButton(
TextBrowseFolderListener(
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.working-directory"))
),
this
)
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
@ -201,9 +196,9 @@ class FilePathConfigurable(
}
class FilePathConfigModule(private val serializedName: String, @Nls private val label: String) : PathConfigModule<FilePathConfigurable>() {
private val field = TextFieldWithBrowseButton(
TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleFileDescriptor()),
this
private val field = textFieldWithBrowseButton(
null,
FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(),
)
override var stringValue by field::text
@ -274,18 +269,6 @@ open class CheckboxConfigurable(
}
}
class ColoredConfigurable(serializedName: String): CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.colored-terminal"), true) {
override fun clone(): ColoredConfigurable {
return super.clone() as ColoredConfigurable
}
}
class DirenvConfigurable(serializedName: String, project: Project): CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.direnv"), project.zigProjectSettings.state.direnv) {
override fun clone(): DirenvConfigurable {
return super.clone() as DirenvConfigurable
}
}
class OptimizationConfigurable(
@Transient private val serializedName: String,
var level: OptimizationLevel = OptimizationLevel.Debug,
@ -347,14 +330,18 @@ class ArgsConfigurable(
@Transient private val serializedName: String,
@Transient @Nls private val guiName: String
) : ZigConfigurable<ArgsConfigurable>, Cloneable {
var args: List<String> = emptyList()
var args: String = ""
override fun readExternal(element: Element) {
args = element.readStrings(serializedName) ?: return
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.writeStrings(serializedName, args)
element.writeString(serializedName, args)
}
override fun createEditor(): ZigConfigModule<ArgsConfigurable> {
@ -376,12 +363,12 @@ class ArgsConfigurable(
}
override fun apply(configurable: ArgsConfigurable): Boolean {
configurable.args = translateCommandline(argsField.text)
configurable.args = argsField.text ?: ""
return true
}
override fun reset(configurable: ArgsConfigurable) {
argsField.text = configurable.args.joinToString(separator = " ")
argsField.text = configurable.args
}
override fun construct(p: Panel): Unit = with(p) {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -41,7 +41,7 @@ abstract class ZigConfigProducer<T: ZigExecConfig<T>>: LazyRunConfigurationProdu
val psiFile = element.containingFile as? ZigFile ?: return false
val theFile = psiFile.virtualFile ?: return false
val filePath = theFile.toNioPathOrNull() ?: return false
return setupConfigurationFromContext(configuration, element, filePath, theFile)
return setupConfigurationFromContext(configuration, element, psiFile, filePath, theFile)
}
override fun isConfigurationFromContext(configuration: T, context: ConfigurationContext): Boolean {
@ -49,7 +49,7 @@ abstract class ZigConfigProducer<T: ZigExecConfig<T>>: LazyRunConfigurationProdu
val psiFile = element.containingFile as? ZigFile ?: return false
val theFile = psiFile.virtualFile ?: return false
val filePath = theFile.toNioPathOrNull() ?: return false
return isConfigurationFromContext(configuration, element, filePath, theFile)
return isConfigurationFromContext(configuration, element, psiFile, filePath, theFile)
}
/*
@ -78,7 +78,7 @@ abstract class ZigConfigProducer<T: ZigExecConfig<T>>: LazyRunConfigurationProdu
}
*/
protected abstract fun setupConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean
protected abstract fun isConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean
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
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -22,8 +22,7 @@
package com.falsepattern.zigbrains.project.execution.base
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.direnv.DirenvService
import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
@ -42,10 +41,6 @@ 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
var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false)
private set
var direnv = DirenvConfigurable("direnv", project)
private set
abstract val suggestedName: @ActionText String
@Throws(ExecutionException::class)
@ -68,24 +63,19 @@ abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: Con
suspend fun patchCommandLine(commandLine: GeneralCommandLine): GeneralCommandLine {
if (direnv.value) {
commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
val direnv = DirenvService.getInstance(project)
if (direnv.isEnabled.isEnabled(project)) {
commandLine.withEnvironment(direnv.import().env)
}
return commandLine
}
fun emulateTerminal(): Boolean {
return pty.value
}
override fun clone(): T {
val myClone = super.clone() as ZigExecConfig<*>
myClone.workingDirectory = workingDirectory.clone()
myClone.pty = pty.clone()
myClone.direnv = direnv.clone()
@Suppress("UNCHECKED_CAST")
return myClone as T
}
open fun getConfigurables(): List<ZigConfigurable<*>> = listOf(workingDirectory, pty, direnv)
open fun getConfigurables(): List<ZigConfigurable<*>> = listOf(workingDirectory)
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,18 +23,16 @@
package com.falsepattern.zigbrains.project.execution.base
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.run.ZigProcessHandler
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
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.build.BuildTextConsoleView
import com.intellij.execution.DefaultExecutionResult
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.process.ProcessTerminatedListener
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.platform.ide.progress.ModalTaskOwner
import kotlin.io.path.pathString
@ -44,6 +42,10 @@ abstract class ZigProfileState<T: ZigExecConfig<T>> (
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"}) {
@ -53,37 +55,20 @@ abstract class ZigProfileState<T: ZigExecConfig<T>> (
@Throws(ExecutionException::class)
suspend fun startProcessSuspend(): ProcessHandler {
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig-profile-state.start-process.no-toolchain"))
return ZigProcessHandler(getCommandLine(toolchain, false))
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: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
open suspend fun getCommandLine(toolchain: ZigToolchain, debug: Boolean): GeneralCommandLine {
val workingDir = configuration.workingDirectory
val zigExePath = toolchain.zig.path()
// TODO remove this check once JetBrains implements colored terminal in the debugger
// https://youtrack.jetbrains.com/issue/CPP-11622/ANSI-color-codes-not-honored-in-Debug-Run-Configuration-output-window
val cli = if (configuration.emulateTerminal() && !debug) PtyCommandLine().withConsoleMode(true).withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE) else GeneralCommandLine()
cli.exePath = zigExePath.pathString
val cli = PtyCommandLine().withConsoleMode(false)
cli.withExePath(zigExePath.pathString)
workingDir.path?.let { cli.withWorkingDirectory(it) }
cli.charset = Charsets.UTF_8
cli.withCharset(Charsets.UTF_8)
cli.addParameters(configuration.buildCommandLineArgs(debug))
return configuration.patchCommandLine(cli)
}
}
@Throws(ExecutionException::class)
fun executeCommandLine(commandLine: GeneralCommandLine, environment: ExecutionEnvironment): DefaultExecutionResult {
val handler = startProcess(commandLine)
val console = BuildTextConsoleView(environment.project, false, emptyList())
console.attachToProcess(handler)
return DefaultExecutionResult(console, handler)
}
@Throws(ExecutionException::class)
fun startProcess(commandLine: GeneralCommandLine): ProcessHandler {
val handler = ZigProcessHandler(commandLine)
ProcessTerminatedListener.attach(handler)
return handler
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -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"
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,11 +24,16 @@ 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>() {
@ -36,21 +41,43 @@ class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() {
return firstConfigFactory<ZigConfigTypeBuild>()
}
override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
if (LINE_MARKER.elementMatches(element)) {
configuration.name = ZigBrainsBundle.message("configuration.build.marker-name")
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
}
return false
}
override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
return filePath.parent == (configuration.workingDirectory.path ?: return false)
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
}
}
private val LINE_MARKER = ZigLineMarkerBuild()

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -25,7 +25,6 @@ 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.falsepattern.zigbrains.shared.cli.coloredCliFlags
import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
@ -37,7 +36,9 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx
private set
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
private set
var colored = ColoredConfigurable("colored")
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
@ -48,22 +49,9 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
val result = ArrayList<String>()
result.add("build")
val steps = if (debug) {
val truncatedSteps = ArrayList<String>()
for (step in buildSteps.args) {
if (step == "run")
continue
if (step == "test")
throw ExecutionException(ZigBrainsBundle.message("exception.zig-build.debug.test-not-supported"))
truncatedSteps.add(step)
}
truncatedSteps
} else buildSteps.args
val steps = if (debug) debugBuildSteps.argsSplit() else buildSteps.argsSplit()
result.addAll(steps)
result.addAll(coloredCliFlags(colored.value, debug))
result.addAll(extraArgs.args)
result.addAll(if (debug) debugExtraArgs.argsSplit() else extraArgs.argsSplit())
return result
}
@ -74,16 +62,15 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx
val clone = super.clone()
clone.buildSteps = buildSteps.clone()
clone.exeArgs = exeArgs.clone()
clone.colored = colored.clone()
clone.exePath = exePath.clone()
clone.exeArgs = exeArgs.clone()
return clone
}
override fun getConfigurables(): List<ZigConfigurable<*>> {
val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs, colored)
val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs)
return if (ZBFeatures.debug()) {
baseCfg + listOf(exePath, exeArgs)
baseCfg + listOf(debugBuildSteps, debugExtraArgs, exePath, exeArgs)
} else {
baseCfg
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -23,7 +23,10 @@
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
@ -35,16 +38,19 @@ class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
return firstConfigFactory<ZigConfigTypeRun>()
}
override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
if (LINE_MARKER.elementMatches(element)) {
configuration.filePath.path = filePath
configuration.name = theFile.presentableName
return true
override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
if (!psiFile.hasMainFunction()) {
return false
}
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, filePath: Path, theFile: VirtualFile): Boolean {
override fun isConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
return filePath == configuration.filePath.path
}
@ -52,5 +58,3 @@ class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
return self.configurationType is ZigConfigTypeRun
}
}
private val LINE_MARKER = ZigLineMarkerRun()

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,7 +24,6 @@ package com.falsepattern.zigbrains.project.execution.run
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.*
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
@ -35,8 +34,6 @@ 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 colored = ColoredConfigurable("colored")
private set
var optimization = OptimizationConfigurable("optimization")
private set
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
@ -47,15 +44,14 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
val result = ArrayList<String>()
result.add(if (debug) "build-exe" else "run")
result.addAll(coloredCliFlags(colored.value, debug))
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.args)
result.addAll(compilerArgs.argsSplit())
if (!debug) {
result.add("--")
result.addAll(exeArgs.args)
result.addAll(exeArgs.argsSplit())
}
return result
}
@ -66,7 +62,6 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
override fun clone(): ZigExecConfigRun {
val clone = super.clone()
clone.filePath = filePath.clone()
clone.colored = colored.clone()
clone.compilerArgs = compilerArgs.clone()
clone.optimization = optimization.clone()
clone.exeArgs = exeArgs.clone()
@ -74,7 +69,7 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
}
override fun getConfigurables(): List<ZigConfigurable<*>> {
return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs, exeArgs)
return super.getConfigurables() + listOf(filePath, optimization, compilerArgs, exeArgs)
}
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigRun> {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,7 +24,10 @@ package com.falsepattern.zigbrains.project.execution.test
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.hasTests
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
@ -36,22 +39,23 @@ class ZigConfigProducerTest: ZigConfigProducer<ZigExecConfigTest>() {
return firstConfigFactory<ZigConfigTypeTest>()
}
override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
if (LINE_MARKER.elementMatches(element)) {
configuration.filePath.path = filePath
configuration.name = ZigBrainsBundle.message("configuration.test.marker-name", theFile.presentableName)
return true
override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
if (!psiFile.hasTests()) {
return false
}
return false
if (theFile.findBuildZig() != null) {
return false
}
configuration.filePath.path = filePath
configuration.name = ZigBrainsBundle.message("configuration.test.marker-name", theFile.presentableName)
return true
}
override fun isConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
override fun isConfigurationFromContext(configuration: ZigExecConfigTest, 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 ZigConfigTypeTest
}
}
private val LINE_MARKER = ZigLineMarkerTest()
}

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included
@ -24,7 +24,6 @@ package com.falsepattern.zigbrains.project.execution.test
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.*
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
@ -35,8 +34,6 @@ import kotlin.io.path.pathString
class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigTest>(project, factory, ZigBrainsBundle.message("exec.type.test.label")) {
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
private set
var colored = ColoredConfigurable("colored")
private set
var optimization = OptimizationConfigurable("optimization")
private set
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
@ -46,12 +43,11 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
val result = ArrayList<String>()
result.add("test")
result.addAll(coloredCliFlags(colored.value, debug))
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.args)
result.addAll(compilerArgs.argsSplit())
if (debug) {
result.add("--test-no-exec")
}
@ -64,14 +60,13 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe
override fun clone(): ZigExecConfigTest {
val clone = super.clone()
clone.filePath = filePath.clone()
clone.colored = colored.clone()
clone.compilerArgs = compilerArgs.clone()
clone.optimization = optimization.clone()
return clone
}
override fun getConfigurables(): List<ZigConfigurable<*>> {
return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs)
return super.getConfigurables() + listOf(filePath, optimization, compilerArgs)
}
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigTest> {

View file

@ -1,7 +1,7 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 FalsePattern
* Copyright (C) 2023-2025 FalsePattern
* All Rights Reserved
*
* The above copyright notice and this permission notice shall be included

Some files were not shown because too many files have changed in this diff Show more