backport: 20.0.2

This commit is contained in:
FalsePattern 2024-11-11 09:56:50 +01:00
parent 24e886f13c
commit 90744797b6
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
17 changed files with 138 additions and 91 deletions

View file

@ -17,6 +17,24 @@ Changelog structure reference:
## [Unreleased]
## [20.0.2]
### Added
- Zig
- Escape sequence highlighting in char literals
### Changed
- Project
- Direnv now only runs automatically in trusted projects
- Toolchain autodetection is now done in the background on project load
### Fixed
- Zig
- Unicode characters in char literals triggered an error
## [20.0.1]
### Fixed

View file

@ -52,49 +52,8 @@ oct_int={oct} {oct_}*
dec_int={dec} {dec_}*
hex_int={hex} {hex_}*
ox80_oxBF=[\200-\277]
oxF4=\364
ox80_ox8F=[\200-\217]
oxF1_oxF3=[\361-\363]
oxF0=\360
ox90_0xBF=[\220-\277]
oxEE_oxEF=[\356-\357]
oxED=\355
ox80_ox9F=[\200-\237]
oxE1_oxEC=[\341-\354]
oxE0=\340
oxA0_oxBF=[\240-\277]
oxC2_oxDF=[\302-\337]
// From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
// First Byte Second Byte Third Byte Fourth Byte
// [0x00,0x7F]
// [0xC2,0xDF] [0x80,0xBF]
// 0xE0 [0xA0,0xBF] [0x80,0xBF]
// [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF]
// 0xED [0x80,0x9F] [0x80,0xBF]
// [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF]
// 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF]
// [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
// 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
mb_utf8_literal= {oxF4} {ox80_ox8F} {ox80_oxBF} {ox80_oxBF}
| {oxF1_oxF3} {ox80_oxBF} {ox80_oxBF} {ox80_oxBF}
| {oxF0} {ox90_0xBF} {ox80_oxBF} {ox80_oxBF}
| {oxEE_oxEF} {ox80_oxBF} {ox80_oxBF}
| {oxED} {ox80_ox9F} {ox80_oxBF}
| {oxE1_oxEC} {ox80_oxBF} {ox80_oxBF}
| {oxE0} {oxA0_oxBF} {ox80_oxBF}
| {oxC2_oxDF} {ox80_oxBF}
ascii_char_not_nl_slash_squote=[\000-\011\013-\046\050-\133\135-\177]
char_escape= "\\x" {hex} {hex}
| "\\u{" {hex}+ "}"
| "\\" [nr\\t'\"]
char_char= {mb_utf8_literal}
| {char_escape}
| {ascii_char_not_nl_slash_squote}
char_char= \\ .
| [^\'\n]
string_char= \\ .
| [^\"\n]
@ -261,7 +220,7 @@ BUILTINIDENTIFIER="@"[A-Za-z_][A-Za-z0-9_]*
<YYINITIAL> "while" { return KEYWORD_WHILE; }
<YYINITIAL> "'" { yybegin(CHAR_LIT); }
<CHAR_LIT> {char_char}"'" { yybegin(YYINITIAL); return CHAR_LITERAL; }
<CHAR_LIT> {char_char}*"'" { yybegin(YYINITIAL); return CHAR_LITERAL; }
<CHAR_LIT> [^] { yypushback(1); yybegin(UNT_QUOT); }
<YYINITIAL> {FLOAT} { return FLOAT; }

View file

@ -40,17 +40,21 @@ import static com.intellij.psi.StringEscapesTokenTypes.*;
hex=[0-9a-fA-F]
char_escape_unicode= "\\x" {hex} {hex} | "\\u{" {hex}+ "}"
char_escape_unicode_invalid= "\\x" | "\\u"
char_escape_unicode_invalid= "\\x" .? .? | "\\u" ("{" [^}]* "}"?)?
char_escape_single_valid= "\\" [nr\\t'\"]
char_escape_single_invalid= "\\" [^nr\\t'\"]
%state STR
%state CHAR
%state CHAR_END
%state CHAR_FINISH
%%
<YYINITIAL> {
"\"" { yybegin(STR); return STRING_LITERAL_SINGLE; }
"'" { yybegin(CHAR); return CHAR_LITERAL; }
[^] { return STRING_LITERAL_SINGLE; }
}
@ -61,3 +65,20 @@ char_escape_single_invalid= "\\" [^nr\\t'\"]
{char_escape_single_invalid} { return INVALID_CHARACTER_ESCAPE_TOKEN; }
[^] { return STRING_LITERAL_SINGLE; }
}
<CHAR> {
{char_escape_unicode} { yybegin(CHAR_END); return VALID_STRING_ESCAPE_TOKEN; }
{char_escape_unicode_invalid} { yybegin(CHAR_END); return INVALID_UNICODE_ESCAPE_TOKEN; }
{char_escape_single_valid} { yybegin(CHAR_END); return VALID_STRING_ESCAPE_TOKEN; }
{char_escape_single_invalid} { yybegin(CHAR_END); return INVALID_CHARACTER_ESCAPE_TOKEN; }
[^] { yybegin(CHAR_END); return CHAR_LITERAL; }
}
<CHAR_END> {
"'" { yybegin(CHAR_FINISH); return CHAR_LITERAL; }
[^] { return BAD_CHARACTER; }
}
<CHAR_FINISH> {
[^] { return BAD_CHARACTER; }
}

View file

@ -22,6 +22,13 @@
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
@ -33,8 +40,10 @@ 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
@ -67,6 +76,30 @@ 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

@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.direnv
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
import com.intellij.ide.impl.isTrusted
import com.intellij.notification.Notification
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
@ -40,7 +41,7 @@ import java.nio.file.Path
object DirenvCmd {
suspend fun importDirenv(project: Project): Env {
if (!direnvInstalled())
if (!direnvInstalled() || !project.isTrusted())
return emptyEnv
val workDir = project.guessProjectDir()?.toNioPath() ?: return emptyEnv
@ -94,10 +95,13 @@ object DirenvCmd {
}
private const val GROUP_DISPLAY_ID = "zigbrains-direnv"
fun direnvInstalled() =
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 direnvInstalled() = _direnvInstalled
}
suspend fun Project?.getDirenv(): Env {
if (this == null)

View file

@ -25,7 +25,7 @@ package com.falsepattern.zigbrains.lsp.settings
import org.jetbrains.annotations.NonNls
data class ZLSSettings(
var direnv: Boolean = true,
var direnv: Boolean = false,
var zlsPath: @NonNls String = "",
var zlsConfigPath: @NonNls String = "",
var debug: Boolean = false,

View file

@ -64,22 +64,17 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
private val messageTrace = JBCheckBox()
private val debug = JBCheckBox()
private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label"))
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 != null && !project.isDefault) {
if (DirenvCmd.direnvInstalled() && project?.isDefault == false) {
cell(direnv)
}
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
project.zigCoroutineScope.launchWithEDT {
withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) {
autodetect()
}
}
}
}
row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) }
row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) }
@ -93,6 +88,7 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
row(ZLSBundle.message("dev-settings.debug.label")) { cell(debug) }
row(ZLSBundle.message("dev-settings.message-trace.label")) { cell(messageTrace) }
}
dispatchAutodetect(false)
}
var data
@ -123,16 +119,30 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
inlayHintsCompact.isSelected = value.inlayHintsCompact
}
suspend fun autodetect() {
getDirenv().findExecutableOnPATH("zls")?.let { zlsPath.text = it.pathString }
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 (!direnv.isSelected)
return emptyEnv
if (DirenvCmd.direnvInstalled() && project?.isDefault == false && direnv.isSelected)
return project.getDirenv()
return emptyEnv
}
}

View file

@ -48,7 +48,7 @@ class ZigModuleBuilder: ModuleBuilder() {
}
override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep? {
val step = ZigModuleWizardStep()
val step = ZigModuleWizardStep(parentDisposable)
parentDisposable?.let { Disposer.register(it, step.peer) }
return step
}
@ -63,8 +63,8 @@ class ZigModuleBuilder: ModuleBuilder() {
}
}
inner class ZigModuleWizardStep: ModuleWizardStep() {
internal val peer = ZigProjectGeneratorPeer(true)
inner class ZigModuleWizardStep(parent: Disposable?): ModuleWizardStep() {
internal val peer = ZigProjectGeneratorPeer(true).also { Disposer.register(parent ?: return@also, it) }
override fun getComponent(): JComponent {
return peer.component.withBorder()
@ -77,7 +77,6 @@ class ZigModuleBuilder: ModuleBuilder() {
override fun updateDataModel() {
this@ZigModuleBuilder.configurationData = peer.settings
}
}
}

View file

@ -89,11 +89,6 @@ class ZigNewProjectPanel(private var handleGit: Boolean): Disposable {
zlsConf.attach(p)
}
suspend fun autodetect() {
projConf.autodetect()
zlsConf.autodetect()
}
override fun dispose() {
}
}

View file

@ -31,7 +31,9 @@ import com.intellij.ui.dsl.builder.panel
import javax.swing.JComponent
class ZigProjectGeneratorPeer(var handleGit: Boolean): ProjectGeneratorPeer<ZigProjectConfigurationData>, Disposable {
private val newProjectPanel: ZigNewProjectPanel = ZigNewProjectPanel(handleGit).also { Disposer.register(this, it) }
private val newProjectPanel by lazy {
ZigNewProjectPanel(handleGit).also { Disposer.register(this, it) }
}
private val myComponent: JComponent by lazy {
panel {
newProjectPanel.attach(this)

View file

@ -64,7 +64,7 @@ abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: run {
Notification(
"zigbrains",
"Zig project toolchain not set, cannot execute program!",
"Zig project toolchain not set, cannot execute program! Please configure it in [Settings | Languages & Frameworks | Zig]",
NotificationType.ERROR
).notify(environment.project)
return null

View file

@ -28,7 +28,7 @@ import com.intellij.util.xmlb.annotations.Transient
import kotlin.io.path.pathString
data class ZigProjectSettings(
var direnv: Boolean = true,
var direnv: Boolean = false,
var overrideStdPath: Boolean = false,
var explicitPathToStd: String? = null,
var toolchainPath: String? = null

View file

@ -56,7 +56,9 @@ import kotlin.io.path.notExists
import kotlin.io.path.pathString
class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv"))
private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv")).apply { addActionListener {
dispatchAutodetect(true)
} }
private val pathToToolchain = textFieldWithBrowseButton(
project,
ZigBrainsBundle.message("dialog.title.zig-toolchain"),
@ -87,16 +89,28 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
).also { Disposer.register(this, it) }
private var debounce: Job? = null
suspend fun autodetect() {
private fun dispatchAutodetect(force: Boolean) {
project.zigCoroutineScope.launchWithEDT {
withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) {
autodetect(force)
}
}
}
suspend fun autodetect(force: Boolean) {
if (!force && pathToToolchain.text.isNotBlank())
return
val data = UserDataHolderBase()
data.putUserData(LocalZigToolchain.DIRENV_KEY, direnv.isSelected)
data.putUserData(LocalZigToolchain.DIRENV_KEY, DirenvCmd.direnvInstalled() && project?.isDefault == false && direnv.isSelected)
val tc = ZigToolchainProvider.suggestToolchain(project, data) ?: return
if (tc !is LocalZigToolchain) {
TODO("Implement non-local zig toolchain in config")
}
if (force || pathToToolchain.text.isBlank()) {
pathToToolchain.text = tc.location.pathString
dispatchUpdateUI()
}
}
var data
get() = ZigProjectSettings(
@ -123,13 +137,6 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
if (DirenvCmd.direnvInstalled() && !project.isDefault) {
cell(direnv)
}
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
project.zigCoroutineScope.launchWithEDT {
withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) {
autodetect()
}
}
}
}
row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) {
cell(toolchainVersion)
@ -139,6 +146,7 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
cell(stdFieldOverride)
}
}
dispatchAutodetect(false)
}
private fun dispatchUpdateUI() {

View file

@ -34,9 +34,9 @@ class ZigHighlightingLexer: LayeredLexer(ZigLexerAdapter()) {
registerSelfStoppingLayer(
MergingLexerAdapter(
ZigLexerStringAdapter(),
TokenSet.create(ZigTypes.STRING_LITERAL_SINGLE)
TokenSet.create(ZigTypes.STRING_LITERAL_SINGLE, ZigTypes.CHAR_LITERAL)
),
arrayOf(ZigTypes.STRING_LITERAL_SINGLE),
arrayOf(ZigTypes.STRING_LITERAL_SINGLE, ZigTypes.CHAR_LITERAL),
IElementType.EMPTY_ARRAY
)
}

View file

@ -105,7 +105,6 @@ configuration.build.marker-name=Build and Run
settings.project.group.title=Zig Settings
settings.project.label.direnv=Use direnv
settings.project.label.toolchain=Toolchain location
settings.project.label.toolchain-autodetect=Autodetect
settings.project.label.toolchain-version=Toolchain version
settings.project.label.override-std=Override standard library
settings.project.label.std-location=Standard library location

View file

@ -13,7 +13,6 @@ settings.build-on-save-step.tooltip=Which step should be executed on build-on-sa
settings.global-var-declarations.label=Highlight global variable declarations
settings.comptime-interpreter.label=Use the ZLS comptime interpreter (dangerous)
settings.zls-path.use-direnv.label=Use direnv
settings.zls-path.autodetect.label=Autodetect
dev-settings.group.title=ZLS Developer Settings
dev-settings.debug.label=Debug log
dev-settings.message-trace.label=Message trace

View file

@ -1,7 +1,7 @@
pluginName=ZigBrains
pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains
pluginVersion=20.0.1
pluginVersion=20.0.2
pluginSinceBuild=241
pluginUntilBuild=241.*