aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--README.md2
-rw-r--r--Scripts/lldb-dap-proxy.pl23
-rw-r--r--Scripts/main.js34
-rw-r--r--extension.json31
5 files changed, 86 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59dfffe..ef55853 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
1# Changelog 1# Changelog
2 2
3## 0.1.8 — 2026-05-07
4
5- Added a setting to write an LLDB proxy log file for debugging the debug adapter.
6- Improved ZLS error logging in the Extension Console.
7- Updated German localisation.
8- Clarified third-party licences for bundled assets and grammar.
9
3## 0.1.7 — 2026-05-07 10## 0.1.7 — 2026-05-07
4 11
5- Initial release: syntax highlighting, ZLS integration, task templates, and LLDB debugging. 12- Initial release: syntax highlighting, ZLS integration, task templates, and LLDB debugging.
diff --git a/README.md b/README.md
index 16c6443..0f816bd 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ Zig language support – ZLS, LLDB, Tree-Sitter grammar
14 14
15A personal project to learn Zig without leaving Nova and without giving up the comfort of language server and debugging features. 15A personal project to learn Zig without leaving Nova and without giving up the comfort of language server and debugging features.
16 16
17This extension is not endorsed by, affiliated with, or associated with the [Zig Software Foundation](https://ziglang.org/zsf/) or the Zig core team in any way. It is maintained by an independent person, for fun.
18
17## Features 19## Features
18 20
19### Editing 21### Editing
diff --git a/Scripts/lldb-dap-proxy.pl b/Scripts/lldb-dap-proxy.pl
index 5f545b1..beb6eaa 100644
--- a/Scripts/lldb-dap-proxy.pl
+++ b/Scripts/lldb-dap-proxy.pl
@@ -1,6 +1,7 @@
1#!/usr/bin/perl 1#!/usr/bin/perl
2use strict; 2use strict;
3use warnings; 3use warnings;
4use Fcntl qw(O_WRONLY O_APPEND O_CREAT O_NOFOLLOW);
4use IPC::Open3; 5use IPC::Open3;
5use IO::Select; 6use IO::Select;
6use JSON::PP; 7use JSON::PP;
@@ -13,7 +14,7 @@ my @adapter_args = @ARGV > 2 ? @ARGV[2 .. $#ARGV] : ();
13sub log_msg { 14sub log_msg {
14 return unless defined $log_path; 15 return unless defined $log_path;
15 my ($msg) = @_; 16 my ($msg) = @_;
16 open(my $fh, '>>', $log_path) or return; 17 sysopen(my $fh, $log_path, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, 0600) or return;
17 my @t = gmtime(time); 18 my @t = gmtime(time);
18 printf $fh "[%04d-%02d-%02dT%02d:%02d:%02dZ] %s\n", 19 printf $fh "[%04d-%02d-%02dT%02d:%02d:%02dZ] %s\n",
19 $t[5] + 1900, $t[4] + 1, $t[3], $t[2], $t[1], $t[0], $msg; 20 $t[5] + 1900, $t[4] + 1, $t[3], $t[2], $t[1], $t[0], $msg;
@@ -41,8 +42,8 @@ if ($@) {
41 42
42binmode($_, ':raw') for \*STDIN, \*STDOUT, $child_in, $child_out, $child_err; 43binmode($_, ':raw') for \*STDIN, \*STDOUT, $child_in, $child_out, $child_err;
43 44
44$SIG{INT} = sub { kill 'INT', $pid }; 45$SIG{INT} = sub { log_msg('received SIGINT'); kill 'INT', $pid };
45$SIG{TERM} = sub { kill 'TERM', $pid }; 46$SIG{TERM} = sub { log_msg('received SIGTERM'); kill 'TERM', $pid };
46 47
47my $json = JSON::PP->new->utf8; 48my $json = JSON::PP->new->utf8;
48 49
@@ -63,8 +64,15 @@ LOOP: while ($sel->count > 0) {
63 unless (defined $n && $n > 0) { 64 unless (defined $n && $n > 0) {
64 $sel->remove($fh); 65 $sel->remove($fh);
65 my $fn = fileno($fh); 66 my $fn = fileno($fh);
66 close($child_in) if $fn == $stdin_fn; 67 if ($fn == $stdin_fn) {
67 last LOOP if $fn == $child_out_fn; # adapter stdout closing ends the session 68 log_msg('stdin closed');
69 close($child_in);
70 } elsif ($fn == $child_out_fn) {
71 log_msg('adapter stdout closed');
72 last LOOP;
73 } else {
74 log_msg('adapter stderr closed');
75 }
68 next; 76 next;
69 } 77 }
70 my $fn = fileno($fh); 78 my $fn = fileno($fh);
@@ -82,6 +90,7 @@ LOOP: while ($sel->count > 0) {
82} 90}
83 91
84waitpid($pid, 0); 92waitpid($pid, 0);
93log_msg(sprintf 'adapter exited status=%d signal=%d', $? >> 8, $? & 127);
85# $? encodes exit code in the high byte and terminating signal in the low 7 bits. 94# $? encodes exit code in the high byte and terminating signal in the low 7 bits.
86# Re-raise the signal so the parent sees a signal-killed exit rather than exit(0). 95# Re-raise the signal so the parent sees a signal-killed exit rather than exit(0).
87my $signal = $? & 127; 96my $signal = $? & 127;
@@ -90,6 +99,7 @@ if ($signal) {
90 kill $signal, $$; 99 kill $signal, $$;
91 sleep 1; 100 sleep 1;
92} 101}
102log_msg(sprintf 'proxy exit code=%d', $? >> 8);
93exit($? >> 8); 103exit($? >> 8);
94 104
95sub flush_dap { 105sub flush_dap {
@@ -119,7 +129,7 @@ sub flush_dap {
119 syswrite($dest, 'Content-Length: ' . length($out) . "\r\n\r\n"); 129 syswrite($dest, 'Content-Length: ' . length($out) . "\r\n\r\n");
120 syswrite($dest, $out); 130 syswrite($dest, $out);
121 } else { 131 } else {
122 log_msg('non-json message forwarded'); 132 log_msg(sprintf 'non-json message forwarded%s', $@ ? " error=$@" : ' reason=not-a-hash');
123 syswrite($dest, 'Content-Length: ' . $body_len . "\r\n\r\n"); 133 syswrite($dest, 'Content-Length: ' . $body_len . "\r\n\r\n");
124 syswrite($dest, $body); 134 syswrite($dest, $body);
125 } 135 }
@@ -157,6 +167,7 @@ sub rewrite_client_message {
157 command => $command, 167 command => $command,
158 arguments => $msg->{arguments}, 168 arguments => $msg->{arguments},
159 }; 169 };
170 log_msg(sprintf 'client seq map %s=>%s', $orig, $rewrite);
160 } 171 }
161 $msg->{seq} = $rewrite; 172 $msg->{seq} = $rewrite;
162 } 173 }
diff --git a/Scripts/main.js b/Scripts/main.js
index 1058dfe..6f0a54e 100644
--- a/Scripts/main.js
+++ b/Scripts/main.js
@@ -12,6 +12,7 @@ const CONFIG_KEYS = {
12 zlsEnabled: `${EXTENSION_ID}.zls.enabled`, 12 zlsEnabled: `${EXTENSION_ID}.zls.enabled`,
13 zlsBuildOnSave: `${EXTENSION_ID}.zls.build-on-save`, 13 zlsBuildOnSave: `${EXTENSION_ID}.zls.build-on-save`,
14 zlsDebug: `${EXTENSION_ID}.zls.debug`, 14 zlsDebug: `${EXTENSION_ID}.zls.debug`,
15 lldbDapDebug: `${EXTENSION_ID}.debug-adapter.debug`,
15}; 16};
16 17
17let languageServer = null; 18let languageServer = null;
@@ -264,7 +265,7 @@ function lldbDapProxyPath() {
264} 265}
265 266
266function debugAdapterLogPath() { 267function debugAdapterLogPath() {
267 return "/tmp/zig-lldb-dap-proxy.log"; 268 return nova.path.join(nova.extension.globalStoragePath, "lldb-dap-proxy.log");
268} 269}
269 270
270function issueNormalizerScriptPath() { 271function issueNormalizerScriptPath() {
@@ -475,6 +476,21 @@ class ZigLanguageServer {
475 clientOptions 476 clientOptions
476 ); 477 );
477 478
479 client.onNotification("window/logMessage", ({ type, message }) => {
480 // type: 1=Error, 2=Warning, 3=Info, 4=Log
481 const enriched =
482 message === "ParseError"
483 ? "ParseError — ZLS could not fully parse the Zig source (normal while editing)"
484 : message;
485 if (type === 1) {
486 console.error(`[ZLS] ${enriched}`);
487 } else if (type === 2) {
488 console.warn(`[ZLS] ${enriched}`);
489 } else if (debugLogs) {
490 console.log(`[ZLS] ${enriched}`);
491 }
492 });
493
478 this.clientStopDisposable = client.onDidStop((error) => { 494 this.clientStopDisposable = client.onDidStop((error) => {
479 if (error) { 495 if (error) {
480 console.error(`[${LANGUAGE_CLIENT_ID}] ${error.message}`); 496 console.error(`[${LANGUAGE_CLIENT_ID}] ${error.message}`);
@@ -806,12 +822,24 @@ class ZigTaskAssistant {
806 const action = new TaskDebugAdapterAction("zig-lldb-dap"); 822 const action = new TaskDebugAdapterAction("zig-lldb-dap");
807 action.transport = "stdio"; 823 action.transport = "stdio";
808 action.command = "/usr/bin/perl"; 824 action.command = "/usr/bin/perl";
809 action.args = [lldbDapProxyPath(), lldbDapPath, debugAdapterLogPath()]; 825 const debugLog = getBooleanConfigValue(CONFIG_KEYS.lldbDapDebug, false);
826 let logPath;
827 if (debugLog) {
828 try {
829 const p = debugAdapterLogPath();
830 const dir = nova.path.dirname(p);
831 if (!nova.fs.stat(dir)) nova.fs.mkdir(dir);
832 logPath = p;
833 } catch (_) {}
834 }
835 action.args = logPath
836 ? [lldbDapProxyPath(), lldbDapPath, logPath]
837 : [lldbDapProxyPath(), lldbDapPath];
810 action.debugRequest = "launch"; 838 action.debugRequest = "launch";
811 action.env = { 839 action.env = {
812 DYLD_FRAMEWORK_PATH: lldbFrameworkPaths().join(":"), 840 DYLD_FRAMEWORK_PATH: lldbFrameworkPaths().join(":"),
813 NOVA_ZIG_LLDB_DAP_PATH: lldbDapPath, 841 NOVA_ZIG_LLDB_DAP_PATH: lldbDapPath,
814 NOVA_ZIG_DEBUG_LOG: debugAdapterLogPath(), 842 ...(logPath ? { NOVA_ZIG_DEBUG_LOG: logPath } : {}),
815 }; 843 };
816 action.debugArgs = { 844 action.debugArgs = {
817 program: programPath, 845 program: programPath,
diff --git a/extension.json b/extension.json
index f9e76e9..656a218 100644
--- a/extension.json
+++ b/extension.json
@@ -3,7 +3,7 @@
3 "name": "Zig", 3 "name": "Zig",
4 "organization": "David Czihak", 4 "organization": "David Czihak",
5 "description": "Zig language support – ZLS, LLDB, Tree-Sitter grammar", 5 "description": "Zig language support – ZLS, LLDB, Tree-Sitter grammar",
6 "version": "0.1.7", 6 "version": "0.1.8",
7 "license": "BSD 2-Clause License", 7 "license": "BSD 2-Clause License",
8 "categories": ["languages", "completions", "formatters", "tasks", "issues"], 8 "categories": ["languages", "completions", "formatters", "tasks", "issues"],
9 "keywords": ["zig", "zon", "zls"], 9 "keywords": ["zig", "zon", "zls"],
@@ -19,7 +19,7 @@
19 ], 19 ],
20 "entitlements": { 20 "entitlements": {
21 "process": true, 21 "process": true,
22 "filesystem": "readonly" 22 "filesystem": "readwrite"
23 }, 23 },
24 "debugAdapters": { 24 "debugAdapters": {
25 "zig-lldb-dap": { 25 "zig-lldb-dap": {
@@ -88,6 +88,20 @@
88 "description": "Log ZLS traffic to the Extension Console while developing the extension." 88 "description": "Log ZLS traffic to the Extension Console while developing the extension."
89 } 89 }
90 ] 90 ]
91 },
92 {
93 "type": "section",
94 "title": "Debug Adapter",
95 "description": "Controls for the lldb-dap integration.",
96 "children": [
97 {
98 "key": "at.dcz.nova-zig.debug-adapter.debug",
99 "title": "Enable Proxy Log",
100 "type": "boolean",
101 "default": false,
102 "description": "Write lldb-dap-proxy traffic to a log file in the extension's storage directory. For extension development only."
103 }
104 ]
91 } 105 }
92 ], 106 ],
93 "configWorkspace": [ 107 "configWorkspace": [
@@ -143,6 +157,19 @@
143 "description": "Log ZLS traffic to the Extension Console while developing the extension." 157 "description": "Log ZLS traffic to the Extension Console while developing the extension."
144 } 158 }
145 ] 159 ]
160 },
161 {
162 "type": "section",
163 "title": "Debug Adapter",
164 "description": "Controls for the lldb-dap integration.",
165 "children": [
166 {
167 "key": "at.dcz.nova-zig.debug-adapter.debug",
168 "title": "Enable Proxy Log",
169 "type": "boolean",
170 "description": "Write lldb-dap-proxy traffic to a log file in the extension's storage directory. For extension development only."
171 }
172 ]
146 } 173 }
147 ], 174 ],
148 "issueMatchers": { 175 "issueMatchers": {