From dd7203eec144a6940f22cabe6dea391e474e6d7d Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Thu, 5 Mar 2026 20:21:23 +0300 Subject: [PATCH 1/7] =?UTF-8?q?=D0=9E=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=202.0?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install/release-notes.md | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/install/release-notes.md b/install/release-notes.md index dd8193e6a..8eeb7d412 100644 --- a/install/release-notes.md +++ b/install/release-notes.md @@ -1,23 +1,15 @@ -# Версия 2.0.0 +# Версия 2.0.1 -Версия нового поколения, основанная на современной платформе .NET. -За счет этого обеспечивается кроссплатформенность без использования Mono на Linux и MacOS. +## Исправление ошибок -## Требования по адаптации +* #1646 Ошибка метода ЗаполнитьЗначенияСвойств на ФиксированнойСтруктуре +* #1647 Исправлена вставка ключа Null в соответствие +* #1649 Исправлена обработка символов '\0' в каталогах WebDAV +* #1654 В методе можно было объявлять параметры, не разделяя их запятой +* #1652 Исправлена обработка аннотаций для списка переменных, объявленных через запятую +* #1657 Исправлен приоритет активации источников в конфиге -За счет новой базовой платформы, потеряна бинарная совместимость с существующими внешними компонентами (dll). -Требуется перекомпиляция компоненты под новую версию .net, как минимум, под слой совместимости netstandard 2.0 +## Рефакторинг и оптимизация -## Изменения по сравнению с ознакомительной версией 2.0.0-rc.10 - -* Уточнена консольная справка по режимам работы -* Исправлена лишняя остановка отладчиком на заголовке цикла Для Каждого -* Исправлены шаги отладчика. Ранее, отладчик ошибочно не останавливался на строке КонецЦикла -* Добавлена поддержка потока в ЗаписьТекста -* Оптимизирована производительность рефлектора -* Оптимизирована производительность компилятора -* Оптимизирована производительность создания таблицы значений -* В отладчике теперь отображаются переменные уровня модуля (ранее отображались только локальные) -* Улучшена совместимость функции СтрНайти с платформой 1С - -Большое спасибо @Mr-Rm, @dmpas, @Bayselonarrend за участие в этом релизе! \ No newline at end of file +* В парсере применен приоритет операторов вместо рекурсивного спуска (улучшена скорость компиляции) +* Загрузчик библиотек теперь разделяет ситуацию ненайденных библиотек и тех, которые не удается загрузить (улучшена диагностика ненайденных библиотек) From 9d176ce1d39982b4668840f8277666ce93c9de7a Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Thu, 5 Mar 2026 20:25:12 +0300 Subject: [PATCH 2/7] =?UTF-8?q?=D0=B1=D0=B0=D0=BC=D0=BF=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=81=D0=B8=D0=B8=20dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index fa13fb1ec..706ed496d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,8 +4,8 @@ pipeline { agent none environment { - VersionPrefix = '2.0.1' - VersionSuffix = 'rc.2'+"+${BUILD_NUMBER}" + VersionPrefix = '2.0.2' + VersionSuffix = 'rc.1'+"+${BUILD_NUMBER}" outputEnc = '65001' } From 8d4c483505995ffb4e3f6c268a034f074732ae85 Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Thu, 12 Mar 2026 21:47:50 +0300 Subject: [PATCH 3/7] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ScriptEngine/Hosting/ConfigurationProviders.cs | 5 ++++- tests/config.os | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ScriptEngine/Hosting/ConfigurationProviders.cs b/src/ScriptEngine/Hosting/ConfigurationProviders.cs index f1fbebeec..9dae5ec81 100644 --- a/src/ScriptEngine/Hosting/ConfigurationProviders.cs +++ b/src/ScriptEngine/Hosting/ConfigurationProviders.cs @@ -26,7 +26,10 @@ public KeyValueConfig CreateConfig() foreach (var provider in _providers) { var values = provider.Load(); - cfg.Merge((IDictionary)values, provider); + if (values != null && values.Count > 0) + { + cfg.Merge((IDictionary)values, provider); + } } return cfg; diff --git a/tests/config.os b/tests/config.os index 73c6144a1..e3d33f62e 100644 --- a/tests/config.os +++ b/tests/config.os @@ -118,7 +118,12 @@ // Проверяем, что значения вернулись (или стали Неопределено) ВосстановленныйЯзык = ПолучитьЗначениеСистемнойНастройки("SystemLanguage"); + ВосстановленнаяКодировка = ПолучитьЗначениеСистемнойНастройки("encoding.script"); + юТест.ПроверитьРавенство(ИсходныйЯзык, ВосстановленныйЯзык, "Язык системы должен вернуться к исходному значению"); + + юТест.ПроверитьРавенство(ИсходнаяКодировка, ВосстановленнаяКодировка, + "Кодировка должна вернуться к исходному значению"); КонецПроцедуры From 2e326de247a7f71c1dca57714983e69bb6cb8184 Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Tue, 24 Mar 2026 22:05:16 +0300 Subject: [PATCH 4/7] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=BD=D1=81=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B8=20=D0=B2=D0=B5=D0=B1-?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D1=81=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/VSCode.DebugAdapter/ConsoleProcess.cs | 13 ++++++++++--- src/VSCode.DebugAdapter/DebugeeProcess.cs | 12 ++++-------- src/VSCode.DebugAdapter/ServerProcess.cs | 12 ++++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/VSCode.DebugAdapter/ConsoleProcess.cs b/src/VSCode.DebugAdapter/ConsoleProcess.cs index a1a740278..99444187e 100644 --- a/src/VSCode.DebugAdapter/ConsoleProcess.cs +++ b/src/VSCode.DebugAdapter/ConsoleProcess.cs @@ -5,10 +5,12 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using Newtonsoft.Json.Linq; +using EvilBeaver.DAP.Dto.Requests; +using EvilBeaver.DAP.Dto.Serialization; using Serilog; namespace VSCode.DebugAdapter @@ -30,10 +32,15 @@ public ConsoleProcess(PathHandlingStrategy pathHandling) : base(pathHandling) public string RuntimeArguments { get; set; } public IDictionary Environment { get; set; } = new Dictionary(); + + public override void Init(LaunchRequestArguments args) + { + var options = args.DeserializeAdditionalProperties(); + InitInternal(options); + } - protected override void InitInternal(JObject args) + private void InitInternal(ConsoleLaunchOptions options) { - var options = args.ToObject(); if (options.Program == null) { throw new InvalidDebugeeOptionsException(1001, "Property 'program' is missing or empty."); diff --git a/src/VSCode.DebugAdapter/DebugeeProcess.cs b/src/VSCode.DebugAdapter/DebugeeProcess.cs index e27ba8738..148103ec9 100644 --- a/src/VSCode.DebugAdapter/DebugeeProcess.cs +++ b/src/VSCode.DebugAdapter/DebugeeProcess.cs @@ -1,4 +1,4 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v.2.0. If a copy of the MPL was not distributed with this file, You can obtain one @@ -11,6 +11,7 @@ This Source Code Form is subject to the terms of the using System.Linq; using System.Runtime.InteropServices; using System.Text; +using EvilBeaver.DAP.Dto.Requests; using Newtonsoft.Json.Linq; using Serilog; using VSCode.DebugAdapter.Transport; @@ -118,11 +119,8 @@ public void InitAttached() } - public void Init(JObject args) - { - InitInternal(args); - } - + public abstract void Init(LaunchRequestArguments args); + public void InitPathsMapper(JObject args) { if (args == null) @@ -151,8 +149,6 @@ public void InitPathsMapper(JObject args) protected abstract Process CreateProcess(); - protected abstract void InitInternal(JObject args); - protected string ConvertClientPathToDebugger(string clientPath) { return _strategy.ConvertClientPathToDebugger(clientPath); diff --git a/src/VSCode.DebugAdapter/ServerProcess.cs b/src/VSCode.DebugAdapter/ServerProcess.cs index 844fea9d6..644bf20aa 100644 --- a/src/VSCode.DebugAdapter/ServerProcess.cs +++ b/src/VSCode.DebugAdapter/ServerProcess.cs @@ -8,7 +8,8 @@ This Source Code Form is subject to the terms of the using System.Collections.Generic; using System.Diagnostics; using System.IO; -using Newtonsoft.Json.Linq; +using EvilBeaver.DAP.Dto.Requests; +using EvilBeaver.DAP.Dto.Serialization; namespace VSCode.DebugAdapter { @@ -51,10 +52,13 @@ protected override Process CreateProcess() return process; } - protected override void InitInternal(JObject args) + public override void Init(LaunchRequestArguments args) + { + InitInternal(args.DeserializeAdditionalProperties()); + } + + private void InitInternal(WebLaunchOptions options) { - var options = args.ToObject(); - // validate argument 'cwd' var workingDirectory = options.AppDir; if (workingDirectory != null) From 6b09491496c6009991bd75a4f70a27f6632fca15 Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Tue, 24 Mar 2026 22:13:30 +0300 Subject: [PATCH 5/7] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=BE=20=D0=BC=D0=B0=D1=81=D1=88=D1=82=D0=B0=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B2=D0=B0=D0=B9=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B8=D0=BD=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/VSCode.DebugAdapter/DebugeeProcess.cs | 8 +- .../OneScriptDebugAdapter.cs | 214 ++++++++++++++++++ .../OscriptDebugEventsListener.cs | 48 +++- src/VSCode.DebugAdapter/Program.cs | 8 + src/VSCode.DebugAdapter/ProtocolExtensions.cs | 18 +- src/VSCode.DebugAdapter/Utilities.cs | 10 + .../VSCode.DebugAdapter.csproj | 8 +- src/VSCode.DebugAdapter/WorkspaceMapper.cs | 1 - 8 files changed, 294 insertions(+), 21 deletions(-) create mode 100644 src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs diff --git a/src/VSCode.DebugAdapter/DebugeeProcess.cs b/src/VSCode.DebugAdapter/DebugeeProcess.cs index 148103ec9..b651b5bca 100644 --- a/src/VSCode.DebugAdapter/DebugeeProcess.cs +++ b/src/VSCode.DebugAdapter/DebugeeProcess.cs @@ -121,17 +121,17 @@ public void InitAttached() public abstract void Init(LaunchRequestArguments args); - public void InitPathsMapper(JObject args) + public void InitPathsMapper(AttachRequestArguments args) { - if (args == null) + if (!args.AdditionalData?.ContainsKey("pathsMapping") ?? false) { PathsMapper = null; return; } - + try { - var mappingToken = args["pathsMapping"]; + var mappingToken = args.AdditionalData?["pathsMapping"]; if (mappingToken == null || mappingToken.Type == JTokenType.Null) { PathsMapper = null; diff --git a/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs new file mode 100644 index 000000000..e2c807f1a --- /dev/null +++ b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs @@ -0,0 +1,214 @@ +// /*---------------------------------------------------------- +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v.2.0. If a copy of the MPL +// was not distributed with this file, You can obtain one +// at http://mozilla.org/MPL/2.0/. +// ----------------------------------------------------------*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using EvilBeaver.DAP.Dto.Base; +using EvilBeaver.DAP.Dto.Events; +using EvilBeaver.DAP.Dto.Requests; +using EvilBeaver.DAP.Dto.Serialization; +using EvilBeaver.DAP.Dto.Types; +using EvilBeaver.DAP.Server; +using Microsoft.Extensions.Logging; +using VSCode.DebugAdapter.Transport; + +namespace VSCode.DebugAdapter +{ + internal class OneScriptDebugAdapter : DebugAdapterBase + { + private DebugeeProcess _debuggee; + private bool _startupPerformed = false; + private ThreadStateContainer _threadState = new ThreadStateContainer(); + + private ILogger Log { get; } + + public OneScriptDebugAdapter(ILogger logger) + { + Log = logger; + } + + protected override async Task OnInitializeAsync(InitializeRequest request, CancellationToken ct) + { + await EventsChannel.SendEventAsync(new InitializedEvent(), ct); + + return new InitializeResponse() + { + Body = new Capabilities + { + SupportsConditionalBreakpoints = true, + SupportsFunctionBreakpoints = false, + SupportsConfigurationDoneRequest = true, + SupportsExceptionFilterOptions = true, + ExceptionBreakpointFilters = new [] + { + new ExceptionBreakpointsFilter + { + Filter = "uncaught", + Label = "Необработанные исключения", + Description = "Остановка при возникновении необработанного исключения", + SupportsCondition = true, + ConditionDescription = "Искомая подстрока текста исключения" + }, + new ExceptionBreakpointsFilter + { + Filter = "all", + Label = "Все исключения", + Description = "Остановка при возникновении любого исключения", + SupportsCondition = true, + ConditionDescription = "Искомая подстрока текста исключения" + } + }, + SupportsEvaluateForHovers = true, + SupportTerminateDebuggee = true + } + }; + } + + public override Task SetBreakpointsAsync(SetBreakpointsRequest request, CancellationToken ct) + { + if (request.Arguments.SourceModified == true) + { + throw new ErrorResponseException("Нельзя установить точку останова на модифицированный файл."); + } + + Debug.Assert(request.Arguments.Source.Path != null, "request.Arguments.Source.Path != null"); + var path = ToNativePath(request.Arguments.Source.Path); + + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + // vscode иногда передает путь, где диск - маленькая буква + path = Utilities.NormalizeDriveLetter(path); + } + + var useConditions = _debuggee.ProtocolVersion >= ProtocolVersions.Version2; + + Debug.Assert(request.Arguments.Breakpoints != null, "request.Arguments.Breakpoints != null"); + var breaks = request.Arguments.Breakpoints + .Select(srcBreakpoint => new OneScript.DebugProtocol.Breakpoint + { + Line = srcBreakpoint.Line, + Source = path, + Condition = useConditions ? srcBreakpoint.Condition ?? string.Empty : string.Empty + }).ToList(); + + var confirmedBreaks = _debuggee.SetBreakpoints(breaks); + var confirmedDapBreaks = new List(confirmedBreaks.Length); + confirmedDapBreaks.AddRange(confirmedBreaks + .Select(t => new Breakpoint + { + Line = t.Line, + Verified = true + }) + ); + + return Task.FromResult(new SetBreakpointsResponse + { + Body = new SetBreakpointsResponseBody + { + Breakpoints = confirmedDapBreaks.ToArray(), + } + }); + } + + public override async Task LaunchAsync(LaunchRequest request, CancellationToken ct) + { + try + { + Log.LogDebug("Initializing process settings"); + var pathStrategy = new PathHandlingStrategy + { + ClientLinesStartAt1 = Client.LinesStartAt1, + ClientPathsAreUri = Client.PathFormat == "uri", + DebuggerLinesStartAt1 = true, + DebuggerPathsAreUri = false + }; + + _debuggee = DebugeeFactory.CreateProcess(Client.AdapterId, pathStrategy); + _debuggee.Init(request.Arguments); + } + catch (InvalidDebugeeOptionsException e) + { + Log.LogError(e, "Wrong options received {ErrorCode}: {Message}", e.ErrorCode, e.Message); + throw new ErrorResponseException(e.Message); + } + + SubscribeForDebuggeeProcessEvents(); + + try + { + Log.LogDebug("Starting debuggee"); + _debuggee.Start(); + Log.LogInformation("Debuggee started"); + } + catch (Exception e) + { + Log.LogError(e, "Can't launch debuggee"); + throw new ErrorResponseException($"Can't launch debuggee ({e.Message})."); + } + + DebugClientFactory debugClientFactory; + try + { + debugClientFactory = ConnectDebugServer(); + } + catch (Exception e) + { + _debuggee.Kill(); + await EventsChannel.SendEventAsync(new TerminatedEvent(), ct); + Log.LogError(e, "Can't connect to debug server"); + throw new ErrorResponseException("Can't connect: " + e.ToString()); + } + + _debuggee.SetClient(debugClientFactory.CreateDebugClient()); + + return new LaunchResponse(); + } + + private void SubscribeForDebuggeeProcessEvents() + { + _debuggee.OutputReceived += (s, e) => + { + Log.LogDebug("Output received {Output}", e.Content); + + if (string.IsNullOrEmpty(e.Content)) + return; + + var data = e.Content; + if (data[data.Length - 1] != '\n') + { + data += '\n'; + } + + EventsChannel.SendEventAsync(new OutputEvent + { + Body = new OutputEventBody + { + Category = e.Category, + Output = data + } + }); + }; + + _debuggee.ProcessExited += (s, e) => + { + Log.LogInformation("Debuggee has exited"); + EventsChannel.SendEventAsync(new TerminatedEvent()); + }; + } + + private DebugClientFactory ConnectDebugServer() + { + var tcpConnection = ConnectionFactory.Connect(_debuggee.DebugPort); + var listener = new OscriptDebugEventsListener(EventsChannel, _threadState); + return new DebugClientFactory(tcpConnection, listener); + } + } +} \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/OscriptDebugEventsListener.cs b/src/VSCode.DebugAdapter/OscriptDebugEventsListener.cs index 1fa55e419..d583596db 100644 --- a/src/VSCode.DebugAdapter/OscriptDebugEventsListener.cs +++ b/src/VSCode.DebugAdapter/OscriptDebugEventsListener.cs @@ -1,25 +1,26 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v.2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ using System.Runtime.CompilerServices; +using EvilBeaver.DAP.Dto.Events; +using EvilBeaver.DAP.Server; using OneScript.DebugProtocol; using Serilog; -using VSCodeDebug; namespace VSCode.DebugAdapter { public class OscriptDebugEventsListener : IDebugEventListener { - private readonly DebugSession _session; + private readonly IClientChannel _channel; private readonly ThreadStateContainer _threadState; private readonly ILogger Log = Serilog.Log.ForContext(); - public OscriptDebugEventsListener(DebugSession session, ThreadStateContainer threadState) + public OscriptDebugEventsListener(IClientChannel channel, ThreadStateContainer threadState) { - _session = session; + _channel = channel; _threadState = threadState; } @@ -27,7 +28,15 @@ public void ThreadStopped(int threadId, ThreadStopReason reason) { LogEventOccured(); _threadState.Reset(); - _session.SendEvent(new StoppedEvent(threadId, reason.ToString())); + _channel.SendEventAsync(new StoppedEvent + { + Body = new StoppedEventBody + { + ThreadId = threadId, + Reason = reason.ToString(), + AllThreadsStopped = true + } + }); } public void ThreadStoppedEx(int threadId, ThreadStopReason reason, string errorMessage) @@ -38,13 +47,27 @@ public void ThreadStoppedEx(int threadId, ThreadStopReason reason, string errorM if (!string.IsNullOrEmpty(errorMessage)) SendOutput("stderr", errorMessage); - _session.SendEvent(new StoppedEvent(threadId, reason.ToString())); + _channel.SendEventAsync(new StoppedEvent + { + Body = new StoppedEventBody + { + ThreadId = threadId, + Reason = reason.ToString(), + AllThreadsStopped = true + } + }); } public void ProcessExited(int exitCode) { LogEventOccured(); - _session.SendEvent(new ExitedEvent(exitCode)); + _channel.SendEventAsync(new ExitedEvent + { + Body = new ExitedEventBody + { + ExitCode = exitCode + } + }); } private void SendOutput(string category, string data) @@ -55,7 +78,14 @@ private void SendOutput(string category, string data) { data += '\n'; } - _session.SendEvent(new OutputEvent(category, data)); + _channel.SendEventAsync(new OutputEvent + { + Body = new OutputEventBody + { + Category = category, + Output = data + } + }); } } diff --git a/src/VSCode.DebugAdapter/Program.cs b/src/VSCode.DebugAdapter/Program.cs index da026d34d..0966206d7 100644 --- a/src/VSCode.DebugAdapter/Program.cs +++ b/src/VSCode.DebugAdapter/Program.cs @@ -9,7 +9,10 @@ This Source Code Form is subject to the terms of the using System.IO; using System.Linq; using System.Net.Sockets; +using EvilBeaver.DAP.Server; +using EvilBeaver.DAP.Server.Transport; using Serilog; +using Serilog.Extensions.Logging; namespace VSCode.DebugAdapter { @@ -47,6 +50,11 @@ private static void StartSession(Stream input, Stream output) .WriteTo.File(file, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message:lj} ({SourceContext}){NewLine}{Exception}") .CreateLogger(); } + + var factory = new SerilogLoggerFactory(Log.Logger); + var adapter = new OneScriptDebugAdapter(factory.CreateLogger("OneScriptDebugAdapter")); + var dapServer = new DapServer(new BufferedTransport(input, output), adapter, factory); + var session = new OscriptDebugSession(); diff --git a/src/VSCode.DebugAdapter/ProtocolExtensions.cs b/src/VSCode.DebugAdapter/ProtocolExtensions.cs index 21fc5fbfb..c013b2bcd 100644 --- a/src/VSCode.DebugAdapter/ProtocolExtensions.cs +++ b/src/VSCode.DebugAdapter/ProtocolExtensions.cs @@ -5,7 +5,8 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ -using VSCodeDebug; +using System.IO; +using EvilBeaver.DAP.Dto.Types; using StackFrame = OneScript.DebugProtocol.StackFrame; namespace VSCode.DebugAdapter @@ -23,14 +24,19 @@ public static Source GetSource(this StackFrame frame) { if (frame.IsStringModule()) { - return new Source(frame.Source, null) + return new Source { - origin = frame.Source, - presentationHint = "deemphasize" + Name = frame.Source, + Origin = frame.Source, + PresentationHint = "deemphasize" }; } - return new Source(frame.Source); + return new Source + { + Name = Path.GetFileName(frame.Source), + Path = frame.Source + }; } } -} \ No newline at end of file +} diff --git a/src/VSCode.DebugAdapter/Utilities.cs b/src/VSCode.DebugAdapter/Utilities.cs index a98912f4b..e628ceb27 100644 --- a/src/VSCode.DebugAdapter/Utilities.cs +++ b/src/VSCode.DebugAdapter/Utilities.cs @@ -6,6 +6,7 @@ This Source Code Form is subject to the terms of the ----------------------------------------------------------*/ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -66,5 +67,14 @@ public static Encoding GetEncodingFromOptions(string optionsValue) return Encoding.GetEncoding(optionsValue); } + + public static string NormalizeDriveLetter(string path) + { + if (Path.IsPathRooted(path)) + return path[0].ToString().ToUpperInvariant() + path.Substring(1); + else + return path; + + } } } diff --git a/src/VSCode.DebugAdapter/VSCode.DebugAdapter.csproj b/src/VSCode.DebugAdapter/VSCode.DebugAdapter.csproj index 7ca054e8a..d342b399d 100644 --- a/src/VSCode.DebugAdapter/VSCode.DebugAdapter.csproj +++ b/src/VSCode.DebugAdapter/VSCode.DebugAdapter.csproj @@ -22,9 +22,10 @@ + - + @@ -43,4 +44,9 @@ + + + + + \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/WorkspaceMapper.cs b/src/VSCode.DebugAdapter/WorkspaceMapper.cs index e9d60018a..d16590507 100644 --- a/src/VSCode.DebugAdapter/WorkspaceMapper.cs +++ b/src/VSCode.DebugAdapter/WorkspaceMapper.cs @@ -12,7 +12,6 @@ namespace VSCode.DebugAdapter { public class WorkspaceMapper { - private Workspace _localWorkspace; private Workspace _remoteWorkspace; From 8d06083db6f10e4a9de636e6b0771a874a36d1fd Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Tue, 24 Mar 2026 22:26:34 +0300 Subject: [PATCH 6/7] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=81=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=BE=D0=B2=D1=83=D1=8E=20=D0=B1=D0=B8=D0=B1?= =?UTF-8?q?=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D1=83=20=D1=81=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BC=D0=BE=D1=89=D1=8C=D1=8E=20=D0=98=D0=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/agents/coder.md | 7 + .cursor/agents/planner.md | 25 + src/VSCode.DebugAdapter/AttachOptions.cs | 15 + src/VSCode.DebugAdapter/DebugSession.cs | 502 ----------------- src/VSCode.DebugAdapter/DebugeeFactory.cs | 8 + .../OneScriptDebugAdapter.cs | 311 ++++++++++- .../OscriptDebugSession.cs | 524 ------------------ src/VSCode.DebugAdapter/Program.cs | 7 +- src/VSCode.DebugAdapter/Protocol.cs | 270 --------- 9 files changed, 365 insertions(+), 1304 deletions(-) create mode 100644 .cursor/agents/coder.md create mode 100644 .cursor/agents/planner.md create mode 100644 src/VSCode.DebugAdapter/AttachOptions.cs delete mode 100644 src/VSCode.DebugAdapter/DebugSession.cs delete mode 100644 src/VSCode.DebugAdapter/OscriptDebugSession.cs delete mode 100644 src/VSCode.DebugAdapter/Protocol.cs diff --git a/.cursor/agents/coder.md b/.cursor/agents/coder.md new file mode 100644 index 000000000..8e2381233 --- /dev/null +++ b/.cursor/agents/coder.md @@ -0,0 +1,7 @@ +--- +name: coder +model: claude-4.6-sonnet-medium +description: Use this agent to implement coding tasks by provided specs only when it's explicitly specified +--- + +Ты профессиональный разработчик ПО высокого уровня. Тебе поступает на вход файл со спецификацией задачи. Реализуй эту задачу. \ No newline at end of file diff --git a/.cursor/agents/planner.md b/.cursor/agents/planner.md new file mode 100644 index 000000000..ba817997c --- /dev/null +++ b/.cursor/agents/planner.md @@ -0,0 +1,25 @@ +--- +name: planner +model: gemini-3-flash +description: Use this agent only when explicitly specified to sequentially run coding subagents when you have numbered list of tasks +readonly: true +--- + +На вход тебе подается каталог, в котором лежат файлы .md со списком задач и файл main-task со спецификацией задачи в целом. +Файлы подзадач пронумерованы префиксом вида 01, 02 и т.д. + +Твоя задача - запустить субагент сoder, передав ему очередную задачу по порядку, дождаться изменений от субагента и запустить новый субагент, уже со следующей задачей из перечня. Ты сам не должен писать код, ты находишься в Ask Mode, твоя задача запускать субагент coder, передавая ему очередную задачу (файл с описанием) + +И так до тех пор, пока перечень задач не будет выполнен целиком. + +Если какая-то задача не может быть выполнена и субагент выдает ошибку или вопрос - прерывай цикл выполнения, задай мне вопрос или сообщи текст ошибки и жди дальнейших инструкций. + +Итого, твои действия: + +1. изучить конечную цель (файл main-task) +2. взять файл с описанием задачи 01-* и сформулировать задачу агенту coder по одному и только одному файлу плана. +3. запустить агент coder, передав ему весь нужный контекст +4. получить ответ от агента coder и если он выполнил задачу успешно, перейти к следующему файлу с задачей (02-*) +5. если агент не смог выполнить задачу - прервать цикл +6. продолжать брать следующие по порядку задачи и снова запускать агент coder, передавая ему только одну задачу из файлов-планов по порядку +7. когда все файлы задач будут реализованы - завершиться. \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/AttachOptions.cs b/src/VSCode.DebugAdapter/AttachOptions.cs new file mode 100644 index 000000000..cd9c0c57f --- /dev/null +++ b/src/VSCode.DebugAdapter/AttachOptions.cs @@ -0,0 +1,15 @@ +// /*---------------------------------------------------------- +// This Source Code Form is subject to the terms of the +// Mozilla Public License, v.2.0. If a copy of the MPL +// was not distributed with this file, You can obtain one +// at http://mozilla.org/MPL/2.0/. +// ----------------------------------------------------------*/ + +namespace VSCode.DebugAdapter +{ + internal class AttachOptions + { + public int DebugPort { get; set; } = 2801; + public WorkspaceMapper PathsMapping { get; set; } + } +} \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/DebugSession.cs b/src/VSCode.DebugAdapter/DebugSession.cs deleted file mode 100644 index ff119d2d1..000000000 --- a/src/VSCode.DebugAdapter/DebugSession.cs +++ /dev/null @@ -1,502 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.IO; -using VSCode.DebugAdapter; - -namespace VSCodeDebug -{ - // ---- Types ------------------------------------------------------------------------- - - public class Message { - public int id { get; } - public string format { get; } - public dynamic variables { get; } - public dynamic showUser { get; } - public dynamic sendTelemetry { get; } - - public Message(int id, string format, dynamic variables = null, bool user = true, bool telemetry = false) { - this.id = id; - this.format = format; - this.variables = variables; - this.showUser = user; - this.sendTelemetry = telemetry; - } - } - - public class StackFrame - { - public int id { get; } - public Source source { get; } - public int line { get; } - public int column { get; } - public string name { get; } - - public StackFrame(int id, string name, Source source, int line, int column) { - this.id = id; - this.name = name; - this.source = source; - this.line = line; - this.column = column; - } - } - - public class Scope - { - public string name { get; } - public int variablesReference { get; } - public bool expensive { get; } - - public Scope(string name, int variablesReference, bool expensive = false) { - this.name = name; - this.variablesReference = variablesReference; - this.expensive = expensive; - } - } - - public class Variable - { - public string name { get; } - public string value { get; } - public string type { get; } - public int variablesReference { get; } - - public Variable(string name, string value, string type, int variablesReference = 0) { - this.name = name; - this.value = value; - this.type = type; - this.variablesReference = variablesReference; - } - } - - public class Thread - { - public int id { get; } - public string name { get; } - - public Thread(int id, string name) { - this.id = id; - if (name == null || name.Length == 0) { - this.name = string.Format("Thread #{0}", id); - } - else { - this.name = name; - } - } - } - - public class Source - { - public string name { get; } - public string path { get; } - public int sourceReference { get; } - - public string origin { get; set; } - - public string presentationHint { get; set; } - - public Source(string name, string path, int sourceReference = 0) { - this.name = name; - this.path = path; - this.sourceReference = sourceReference; - } - - public Source(string path, int sourceReference = 0) { - this.name = Path.GetFileName(path); - this.path = path; - this.sourceReference = sourceReference; - } - } - - public class Breakpoint - { - public bool verified { get; } - public int line { get; } - - public Breakpoint(bool verified) - { - this.verified = verified; - line = 0; - } - - public Breakpoint(bool verified, int line) { - this.verified = verified; - this.line = line; - } - } - - // ---- Events ------------------------------------------------------------------------- - - public class InitializedEvent : Event - { - public InitializedEvent() - : base("initialized") { } - } - - public class StoppedEvent : Event - { - public StoppedEvent(int tid, string reasn, string txt = null) - : base("stopped", new { - threadId = tid, - reason = reasn, - text = txt - }) { } - } - - public class ExitedEvent : Event - { - public ExitedEvent(int exCode) - : base("exited", new { exitCode = exCode } ) { } - } - - public class TerminatedEvent : Event - { - public TerminatedEvent() - : base("terminated") { } - } - - public class ThreadEvent : Event - { - public ThreadEvent(string reasn, int tid) - : base("thread", new { - reason = reasn, - threadId = tid - }) { } - } - - public class OutputEvent : Event - { - public OutputEvent(string cat, string outpt) - : base("output", new { - category = cat, - output = outpt - }) { } - } - - // ---- Response ------------------------------------------------------------------------- - - public class Capabilities : ResponseBody { - - public bool supportsConfigurationDoneRequest; - public bool supportsFunctionBreakpoints; - public bool supportsConditionalBreakpoints; - public bool supportsEvaluateForHovers; - public bool supportsExceptionFilterOptions; - public dynamic[] exceptionBreakpointFilters; - public bool supportTerminateDebuggee; - } - - public class ErrorResponseBody : ResponseBody { - - public Message error { get; } - - public ErrorResponseBody(Message error) { - this.error = error; - } - } - - public class StackTraceResponseBody : ResponseBody - { - public StackFrame[] stackFrames { get; } - - public StackTraceResponseBody(IEnumerable frames = null) { - if (frames == null) - stackFrames = new StackFrame[0]; - else - stackFrames = frames.ToArray(); - } - } - - public class ScopesResponseBody : ResponseBody - { - public Scope[] scopes { get; } - - public ScopesResponseBody(IList scps = null) { - if (scps == null) - scopes = new Scope[0]; - else - scopes = scps.ToArray(); - } - } - - public class VariablesResponseBody : ResponseBody - { - public Variable[] variables { get; } - - public VariablesResponseBody(IList vars = null) { - if (vars == null) - variables = new Variable[0]; - else - variables = vars.ToArray(); - } - } - - public class ThreadsResponseBody : ResponseBody - { - public Thread[] threads { get; } - - public ThreadsResponseBody(List vars = null) { - if (vars == null) - threads = new Thread[0]; - else - threads = vars.ToArray(); - } - } - - public class EvaluateResponseBody : ResponseBody - { - public string result { get; } - - public string type { get; set; } - - public int variablesReference { get; } - - - public EvaluateResponseBody(string value, int reff = 0) { - result = value; - variablesReference = reff; - } - } - - public class SetBreakpointsResponseBody : ResponseBody - { - public Breakpoint[] breakpoints { get; } - - public SetBreakpointsResponseBody(List bpts = null) { - if (bpts == null) - breakpoints = Array.Empty(); - else - breakpoints = bpts.ToArray(); - } - } - - public class SetExceptionBreakpointsResponseBody : ResponseBody - { - public Breakpoint[] breakpoints { get; } - - public SetExceptionBreakpointsResponseBody(List bpts = null) - { - if (bpts == null) - breakpoints = Array.Empty(); - else - breakpoints = bpts.ToArray(); - } - } - - // ---- The Session -------------------------------------------------------- - - public abstract class DebugSession : ProtocolServer - { - private bool _clientLinesStartAt1 = true; - private bool _clientPathsAreUri = true; - - public PathHandlingStrategy PathStrategy { get; } - - public DebugSession(bool debuggerLinesStartAt1, bool debuggerPathsAreURI = false) - { - PathStrategy = new PathHandlingStrategy - { - DebuggerLinesStartAt1 = debuggerLinesStartAt1, - DebuggerPathsAreUri = debuggerPathsAreURI - }; - } - - public void SendResponse(Response response, dynamic body = null) - { - if (body != null) { - response.SetBody(body); - } - SendMessage(response); - } - - public void SendErrorResponse(Response response, int id, string format, dynamic arguments = null, bool user = true, bool telemetry = false) - { - var msg = new Message(id, format, arguments, user, telemetry); - var message = Utilities.ExpandVariables(msg.format, msg.variables); - response.SetErrorBody(message, new ErrorResponseBody(msg)); - SendMessage(response); - } - - protected override void DispatchRequest(string command, dynamic args, Response response) - { - if (args == null) { - args = new { }; - } - - try { - switch (command) { - - case "initialize": - if (args.linesStartAt1 != null) { - _clientLinesStartAt1 = (bool)args.linesStartAt1; - } - var pathFormat = (string)args.pathFormat; - if (pathFormat != null) { - switch (pathFormat) { - case "uri": - _clientPathsAreUri = true; - break; - case "path": - _clientPathsAreUri = false; - break; - default: - SendErrorResponse(response, 1015, "initialize: bad value '{_format}' for pathFormat", new { _format = pathFormat }); - return; - } - } - - SetPathStrategy(); - Initialize(response, args); - break; - - case "launch": - Launch(response, args); - break; - - case "attach": - Attach(response, args); - break; - - case "disconnect": - Disconnect(response, args); - break; - - case "next": - Next(response, args); - break; - - case "continue": - Continue(response, args); - break; - - case "stepIn": - StepIn(response, args); - break; - - case "stepOut": - StepOut(response, args); - break; - - case "pause": - Pause(response, args); - break; - - case "stackTrace": - StackTrace(response, args); - break; - - case "scopes": - Scopes(response, args); - break; - - case "variables": - Variables(response, args); - break; - - case "source": - Source(response, args); - break; - - case "threads": - Threads(response, args); - break; - - case "setBreakpoints": - SetBreakpoints(response, args); - break; - - case "setFunctionBreakpoints": - SetFunctionBreakpoints(response, args); - break; - - case "setExceptionBreakpoints": - SetExceptionBreakpoints(response, args); - break; - - case "evaluate": - Evaluate(response, args); - break; - case "configurationDone": - ConfigurationDone(response, args); - break; - - default: - SendErrorResponse(response, 1014, "unrecognized request: {_request}", new { _request = command }); - break; - } - } - catch (Exception e) { - OnRequestError(e); - SendErrorResponse(response, 1104, "error while processing request '{_request}' (exception: {_exception})", new { _request = command, _exception = e.Message }); - } - - if (command == "disconnect") { - Stop(); - } - } - - private void SetPathStrategy() - { - PathStrategy.ClientLinesStartAt1 = _clientLinesStartAt1; - PathStrategy.ClientPathsAreUri = _clientPathsAreUri; - } - - protected string ConvertClientPathToDebugger(string path) - { - return PathStrategy.ConvertClientPathToDebugger(path); - } - - public abstract void ConfigurationDone(Response response, dynamic args); - - public abstract void Initialize(Response response, dynamic args); - - public abstract void Launch(Response response, dynamic arguments); - - public abstract void Attach(Response response, dynamic arguments); - - public abstract void Disconnect(Response response, dynamic arguments); - - public virtual void SetFunctionBreakpoints(Response response, dynamic arguments) - { - } - - public virtual void SetExceptionBreakpoints(Response response, dynamic arguments) - { - } - - protected virtual void OnRequestError(Exception e) - { - } - - public abstract void SetBreakpoints(Response response, dynamic arguments); - - public abstract void Continue(Response response, dynamic arguments); - - public abstract void Next(Response response, dynamic arguments); - - public abstract void StepIn(Response response, dynamic arguments); - - public abstract void StepOut(Response response, dynamic arguments); - - public abstract void Pause(Response response, dynamic arguments); - - public abstract void StackTrace(Response response, dynamic arguments); - - public abstract void Scopes(Response response, dynamic arguments); - - public abstract void Variables(Response response, dynamic arguments); - - public virtual void Source(Response response, dynamic arguments) - { - SendErrorResponse(response, 1020, "Source not supported"); - } - - public abstract void Threads(Response response, dynamic arguments); - - public abstract void Evaluate(Response response, dynamic arguments); - } -} diff --git a/src/VSCode.DebugAdapter/DebugeeFactory.cs b/src/VSCode.DebugAdapter/DebugeeFactory.cs index d494b21fd..f25d51387 100644 --- a/src/VSCode.DebugAdapter/DebugeeFactory.cs +++ b/src/VSCode.DebugAdapter/DebugeeFactory.cs @@ -25,5 +25,13 @@ public static DebugeeProcess CreateProcess(string adapterId, PathHandlingStrateg throw new ArgumentOutOfRangeException(nameof(adapterId), adapterId, "Unsupported debugger"); } + + public static DebugeeProcess CreateAttachableProcess(string adapterId, PathHandlingStrategy pathStrategy) + { + // Для аттача нам не важно, консольный это процесс или веб-сервер, + // так как мы не запускаем его, а только подключаемся. + // Но нам нужен экземпляр DebugeeProcess. ConsoleProcess подойдет. + return new ConsoleProcess(pathStrategy); + } } } \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs index e2c807f1a..5500d4898 100644 --- a/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs +++ b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs @@ -11,7 +11,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using EvilBeaver.DAP.Dto.Base; using EvilBeaver.DAP.Dto.Events; using EvilBeaver.DAP.Dto.Requests; using EvilBeaver.DAP.Dto.Serialization; @@ -25,8 +24,7 @@ namespace VSCode.DebugAdapter internal class OneScriptDebugAdapter : DebugAdapterBase { private DebugeeProcess _debuggee; - private bool _startupPerformed = false; - private ThreadStateContainer _threadState = new ThreadStateContainer(); + private readonly ThreadStateContainer _threadState = new ThreadStateContainer(); private ILogger Log { get; } @@ -72,6 +70,313 @@ protected override async Task OnInitializeAsync(InitializeRe }; } + public override Task ConfigurationDoneAsync(ConfigurationDoneRequest request, CancellationToken ct) + { + if (_debuggee == null) + { + Log.LogDebug("Config Done. Process is not started"); + return Task.FromResult(new ConfigurationDoneResponse()); + } + + Log.LogDebug("Config Done. Process is started, sending Execute"); + _debuggee.BeginExecution(-1); + + return Task.FromResult(new ConfigurationDoneResponse()); + } + + public override Task DisconnectAsync(DisconnectRequest request, CancellationToken ct) + { + Log.LogDebug("Disconnect requested, terminate={Terminate}", request.Arguments?.TerminateDebuggee); + bool terminateDebuggee = request.Arguments?.TerminateDebuggee == true; + + _debuggee?.HandleDisconnect(terminateDebuggee); + + return Task.FromResult(new DisconnectResponse()); + } + + public override Task ContinueAsync(ContinueRequest request, CancellationToken ct) + { + _debuggee.BeginExecution(-1); + return Task.FromResult(new ContinueResponse()); + } + + public override Task NextAsync(NextRequest request, CancellationToken ct) + { + lock (_debuggee) + { + if (!_debuggee.HasExited) + _debuggee.Next(request.Arguments.ThreadId); + } + return Task.FromResult(new NextResponse()); + } + + public override Task StepInAsync(StepInRequest request, CancellationToken ct) + { + lock (_debuggee) + { + if (!_debuggee.HasExited) + _debuggee.StepIn(request.Arguments.ThreadId); + } + return Task.FromResult(new StepInResponse()); + } + + public override Task StepOutAsync(StepOutRequest request, CancellationToken ct) + { + lock (_debuggee) + { + if (!_debuggee.HasExited) + _debuggee.StepOut(request.Arguments.ThreadId); + } + return Task.FromResult(new StepOutResponse()); + } + + public override Task ThreadsAsync(ThreadsRequest request, CancellationToken ct) + { + var processThreads = _debuggee.GetThreads(); + var threads = new EvilBeaver.DAP.Dto.Types.Thread[processThreads.Length]; + for (int i = 0; i < processThreads.Length; i++) + { + threads[i] = new EvilBeaver.DAP.Dto.Types.Thread + { + Id = processThreads[i], + Name = $"Thread {processThreads[i]}" + }; + } + + return Task.FromResult(new ThreadsResponse + { + Body = new ThreadsResponseBody { Threads = threads } + }); + } + + public override Task StackTraceAsync(StackTraceRequest request, CancellationToken ct) + { + var args = request.Arguments; + var firstFrameIdx = args.StartFrame ?? 0; + var limit = args.Levels ?? 0; + var threadId = args.ThreadId; + + var processFrames = _debuggee.GetStackTrace(threadId, firstFrameIdx, limit); + var frames = new EvilBeaver.DAP.Dto.Types.StackFrame[processFrames.Length]; + for (int i = 0; i < processFrames.Length; i++) + { + frames[i] = new EvilBeaver.DAP.Dto.Types.StackFrame + { + Id = _threadState.RegisterFrame(processFrames[i]), + Name = processFrames[i].MethodName, + Source = processFrames[i].GetSource(), + Line = processFrames[i].LineNumber, + Column = 0 + }; + } + + return Task.FromResult(new StackTraceResponse + { + Body = new StackTraceResponseBody + { + StackFrames = frames, + TotalFrames = frames.Length + } + }); + } + + public override Task ScopesAsync(ScopesRequest request, CancellationToken ct) + { + int frameId = request.Arguments.FrameId; + var frame = _threadState.GetFrameById(frameId); + if (frame == null) + { + throw new ErrorResponseException("No active stackframe"); + } + + var scopes = new List(); + + var localProvider = new LocalScopeProvider(frame.ThreadId, frame.Index); + var localHandle = _threadState.RegisterVariablesProvider(localProvider); + scopes.Add(new Scope + { + Name = "Локальные переменные", + VariablesReference = localHandle + }); + + if (_debuggee.ProtocolVersion >= ProtocolVersions.Version4) + { + var moduleProvider = new ModuleScopeProvider(frame.ThreadId, frame.Index); + var moduleHandle = _threadState.RegisterVariablesProvider(moduleProvider); + scopes.Add(new Scope + { + Name = "Переменные модуля", + VariablesReference = moduleHandle + }); + } + + return Task.FromResult(new ScopesResponse + { + Body = new ScopesResponseBody { Scopes = scopes.ToArray() } + }); + } + + public override Task VariablesAsync(VariablesRequest request, CancellationToken ct) + { + int varsHandle = request.Arguments.VariablesReference; + var provider = _threadState.GetVariablesProviderById(varsHandle); + if (provider == null) + { + throw new ErrorResponseException("Invalid variables reference"); + } + + var variables = _debuggee.FetchVariables(provider); + var responseArray = new Variable[variables.Length]; + + for (int i = 0; i < responseArray.Length; i++) + { + var variable = variables[i]; + int childHandle = 0; + + if (variable.IsStructured) + { + var childProvider = provider.CreateChildProvider(i); + childHandle = _threadState.RegisterVariablesProvider(childProvider); + } + + responseArray[i] = new Variable + { + Name = variable.Name, + Value = variable.Presentation, + Type = variable.TypeName, + VariablesReference = childHandle + }; + } + + return Task.FromResult(new VariablesResponse + { + Body = new VariablesResponseBody { Variables = responseArray } + }); + } + + public override Task EvaluateAsync(EvaluateRequest request, CancellationToken ct) + { + var args = request.Arguments; + int frameId = args.FrameId ?? 0; + var frame = _threadState.GetFrameById(frameId); + if (frame == null) + { + throw new ErrorResponseException("No active stackframe"); + } + + var expression = args.Expression; + var context = args.Context; + + int id = 0; + OneScript.DebugProtocol.Variable evalResult; + try + { + evalResult = _debuggee.Evaluate(frame, expression); + if (evalResult.IsStructured) + { + var provider = new EvaluatedExpressionProvider(expression, frame.ThreadId, frame.Index); + id = _threadState.RegisterVariablesProvider(provider); + } + } + catch (Exception e) + { + evalResult = new OneScript.DebugProtocol.Variable() { Presentation = e.Message, Name = "$evalFault" }; + } + + if (evalResult.Name.Equals("$evalFault") && "hover".Equals(context)) + { + evalResult.Presentation = $"err: {expression}"; + } + + return Task.FromResult(new EvaluateResponse + { + Body = new EvaluateResponseBody + { + Result = evalResult.Presentation, + Type = evalResult.TypeName, + VariablesReference = id + } + }); + } + + public override Task SetExceptionBreakpointsAsync(SetExceptionBreakpointsRequest request, CancellationToken ct) + { + var args = request.Arguments; + var filters = new List<(string Id, string Condition)>(); + var acceptedFilters = new List(); + + if (args.Filters != null) + { + foreach (var filter in args.Filters) + { + filters.Add((filter, "")); + acceptedFilters.Add(new Breakpoint { Verified = true }); + } + } + + if (args.FilterOptions != null) + { + foreach (var filterOption in args.FilterOptions) + { + filters.Add((filterOption.FilterId, filterOption.Condition ?? "")); + acceptedFilters.Add(new Breakpoint { Verified = true }); + } + } + + _debuggee.SetExceptionsBreakpoints(filters.ToArray()); + + return Task.FromResult(new SetExceptionBreakpointsResponse + { + Body = new SetExceptionBreakpointsResponseBody + { + Breakpoints = acceptedFilters.ToArray() + } + }); + } + + public override Task AttachAsync(AttachRequest request, CancellationToken ct) + { + var options = request.Arguments.DeserializeAdditionalProperties(); + + var pathStrategy = new PathHandlingStrategy + { + ClientLinesStartAt1 = Client.LinesStartAt1, + ClientPathsAreUri = Client.PathFormat == "uri", + DebuggerLinesStartAt1 = true, + DebuggerPathsAreUri = false + }; + + _debuggee = DebugeeFactory.CreateAttachableProcess(Client.AdapterId, pathStrategy); + _debuggee.DebugPort = options.DebugPort; + _debuggee.PathsMapper = options.PathsMapping; + + SubscribeForDebuggeeProcessEvents(); + + DebugClientFactory debugClientFactory; + try + { + debugClientFactory = ConnectDebugServer(); + } + catch (Exception e) + { + Log.LogError(e, "Can't connect debuggee"); + throw new ErrorResponseException("Can't connect: " + e.ToString()); + } + + _debuggee.SetClient(debugClientFactory.CreateDebugClient()); + try + { + _debuggee.InitAttached(); + } + catch (Exception e) + { + Log.LogError(e, "Attach failed"); + throw new ErrorResponseException("Attach failed: " + e.ToString()); + } + + return Task.FromResult(new AttachResponse()); + } + public override Task SetBreakpointsAsync(SetBreakpointsRequest request, CancellationToken ct) { if (request.Arguments.SourceModified == true) diff --git a/src/VSCode.DebugAdapter/OscriptDebugSession.cs b/src/VSCode.DebugAdapter/OscriptDebugSession.cs deleted file mode 100644 index 664e4a3e4..000000000 --- a/src/VSCode.DebugAdapter/OscriptDebugSession.cs +++ /dev/null @@ -1,524 +0,0 @@ -/*---------------------------------------------------------- -This Source Code Form is subject to the terms of the -Mozilla Public License, v.2.0. If a copy of the MPL -was not distributed with this file, You can obtain one -at http://mozilla.org/MPL/2.0/. -----------------------------------------------------------*/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using OneScript.DebugProtocol; -using Serilog; -using VSCode.DebugAdapter.Transport; -using VSCodeDebug; - - -namespace VSCode.DebugAdapter -{ - internal class OscriptDebugSession : DebugSession - { - private DebugeeProcess _debuggee; - private bool _startupPerformed = false; - private ThreadStateContainer _threadState = new ThreadStateContainer(); - - private readonly ILogger Log = Serilog.Log.ForContext(); - - public OscriptDebugSession() : base(true, false) - { - } - - private string AdapterID { get; set; } - - public override void Initialize(Response response, dynamic args) - { - LogCommandReceived(); - AdapterID = (string) args.adapterID; - - _debuggee = DebugeeFactory.CreateProcess(AdapterID, PathStrategy); - - SendResponse(response, new Capabilities - { - supportsConditionalBreakpoints = true, - supportsFunctionBreakpoints = false, - supportsConfigurationDoneRequest = true, - supportsExceptionFilterOptions = true, - exceptionBreakpointFilters = new dynamic[] - { - new - { - filter = "uncaught", - label = "Необработанные исключения", - description = "Остановка при возникновении необработанного исключения", - supportsCondition = true, - conditionDescription = "Искомая подстрока текста исключения" - }, - new - { - filter = "all", - label = "Все исключения", - description = "Остановка при возникновении любого исключения", - supportsCondition = true, - conditionDescription = "Искомая подстрока текста исключения" - } - }, - supportsEvaluateForHovers = true, - supportTerminateDebuggee = true - }); - - SendEvent(new InitializedEvent()); - } - - public override void Launch(Response response, dynamic args) - { - LogCommandReceived(); - try - { - Log.Debug("Initializing process settings"); - _debuggee.Init(args); - } - catch (InvalidDebugeeOptionsException e) - { - Log.Error(e, "Wrong options received {ErrorCode}: {Message}", e.ErrorCode, e.Message); - SendErrorResponse(response, e.ErrorCode, e.Message); - return; - } - - SubscribeForDebuggeeProcessEvents(); - - try - { - Log.Verbose("Starting debuggee"); - _debuggee.Start(); - Log.Information("Debuggee started"); - } - catch (Exception e) - { - Log.Error(e, "Can't launch debuggee"); - SendErrorResponse(response, 3012, "Can't launch debugee ({reason}).", new { reason = e.Message }); - return; - } - - DebugClientFactory debugClientFactory; - try - { - debugClientFactory = ConnectDebugServer(); - } - catch (Exception e) - { - _debuggee.Kill(); - SendEvent(new TerminatedEvent()); - Log.Error(e, "Can't connect to debug server"); - SendErrorResponse(response, 4550, "Can't connect: " + e.ToString()); - return; - } - - _debuggee.SetClient(debugClientFactory.CreateDebugClient()); - - SendResponse(response); - } - - private void SubscribeForDebuggeeProcessEvents() - { - _debuggee.OutputReceived += (s, e) => - { - Log.Debug("Output received {Output}", e.Content); - SendOutput(e.Category, e.Content); - }; - - _debuggee.ProcessExited += (s, e) => - { - Log.Information("Debuggee has exited"); - SendEvent(new TerminatedEvent()); - }; - } - - public override void Attach(Response response, dynamic arguments) - { - LogCommandReceived(); - SubscribeForDebuggeeProcessEvents(); - - _debuggee.DebugPort = GetFromContainer(arguments, "debugPort", 2801); - _debuggee.InitPathsMapper(arguments); - - DebugClientFactory debugClientFactory; - try - { - debugClientFactory = ConnectDebugServer(); - } - catch (Exception e) - { - Log.Error(e, "Can't connect debuggee"); - SendErrorResponse(response, 4550, "Can't connect: " + e.ToString()); - return; - } - - _debuggee.SetClient(debugClientFactory.CreateDebugClient()); - try - { - _debuggee.InitAttached(); - } - catch (Exception e) - { - Log.Error(e, "Attach failed"); - SendErrorResponse(response, 4550, "Attach failed: " + e.ToString()); - return; - } - - SendResponse(response); - } - - private DebugClientFactory ConnectDebugServer() - { - var tcpConnection = ConnectionFactory.Connect(_debuggee.DebugPort); - var listener = new OscriptDebugEventsListener(this, _threadState); - return new DebugClientFactory(tcpConnection, listener); - } - - public override void Disconnect(Response response, dynamic arguments) - { - LogCommandReceived(new { Terminate = arguments.terminateDebuggee }); - bool terminateDebuggee = arguments.terminateDebuggee == true; - - _debuggee.HandleDisconnect(terminateDebuggee); - SendResponse(response); - } - - public override void SetExceptionBreakpoints(Response response, dynamic arguments) - { - LogCommandReceived(); - var acceptedFilters = new List(); - var filters = new List<(string Id, string Condition)>(); - - foreach(var filter in arguments.filters) - { - filters.Add((filter, "")); - acceptedFilters.Add(new VSCodeDebug.Breakpoint(true)); - } - - foreach (var filterOption in arguments.filterOptions) - { - filters.Add((filterOption.filterId, filterOption.condition ?? "")); - acceptedFilters.Add(new VSCodeDebug.Breakpoint(true)); - } - - _debuggee.SetExceptionsBreakpoints(filters.ToArray()); - - SendResponse(response, new SetExceptionBreakpointsResponseBody(acceptedFilters)); - } - - public override void SetBreakpoints(Response response, dynamic arguments) - { - LogCommandReceived(); - - if ((bool)arguments.sourceModified) - { - if (_startupPerformed) - { - SendErrorResponse(response, 1102, "Нельзя установить точку останова на модифицированный файл."); - return; - } - SendResponse(response, new SetBreakpointsResponseBody()); - return; - } - - var path = (string) arguments.source.path; - path = ConvertClientPathToDebugger(path); - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - // vscode иногда передает путь, где диск - маленькая буква - path = NormalizeDriveLetter(path); - } - - var breaks = new List(); - - var useConditions = _debuggee.ProtocolVersion >= ProtocolVersions.Version2; - - foreach (var srcBreakpoint in arguments.breakpoints) - { - var bpt = new OneScript.DebugProtocol.Breakpoint - { - Line = (int)srcBreakpoint.line, - Source = path, - Condition = useConditions ? srcBreakpoint.condition ?? string.Empty : string.Empty - }; - breaks.Add(bpt); - } - - if(breaks.Count == 0) // в целях сохранения интерфейса WCF придется сделать костыль на перех. период - { - var bpt = new OneScript.DebugProtocol.Breakpoint - { - Line = 0, - Source = path - }; - breaks.Add(bpt); - } - - var confirmedBreaks = _debuggee.SetBreakpoints(breaks); - var confirmedBreaksVSCode = new List(confirmedBreaks.Length); - for (int i = 0; i < confirmedBreaks.Length; i++) - { - confirmedBreaksVSCode.Add(new VSCodeDebug.Breakpoint(true, confirmedBreaks[i].Line)); - } - - SendResponse(response, new SetBreakpointsResponseBody(confirmedBreaksVSCode)); - } - - private string NormalizeDriveLetter(string path) - { - if (Path.IsPathRooted(path)) - return path[0].ToString().ToUpperInvariant() + path.Substring(1); - else - return path; - - } - - public override void ConfigurationDone(Response response, dynamic args) - { - if (_debuggee == null) - { - Log.Debug("Config Done. Process is not started"); - SendResponse(response); - return; - } - Log.Debug("Config Done. Process is started, sending Execute"); - _debuggee.BeginExecution(-1); - _startupPerformed = true; - SendResponse(response); - } - - public override void Continue(Response response, dynamic arguments) - { - LogCommandReceived(); - SendResponse(response); - _debuggee.BeginExecution(-1); - } - - public override void Next(Response response, dynamic arguments) - { - LogCommandReceived(); - SendResponse(response); - lock (_debuggee) - { - if (!_debuggee.HasExited) - { - _debuggee.Next((int)arguments.threadId); - } - } - - } - - public override void StepIn(Response response, dynamic arguments) - { - LogCommandReceived(); - SendResponse(response); - lock (_debuggee) - { - if (!_debuggee.HasExited) - { - _debuggee.StepIn((int)arguments.threadId); - } - } - } - - public override void StepOut(Response response, dynamic arguments) - { - LogCommandReceived(); - SendResponse(response); - lock (_debuggee) - { - if (!_debuggee.HasExited) - { - _debuggee.StepOut((int)arguments.threadId); - } - } - } - - public override void Pause(Response response, dynamic arguments) - { - LogCommandReceived(); - throw new NotImplementedException(); - } - - public override void StackTrace(Response response, dynamic arguments) - { - LogCommandReceived(); - var firstFrameIdx = (int?)arguments.startFrame ?? 0; - var limit = (int?) arguments.levels ?? 0; - var threadId = (int) arguments.threadId; - var processFrames = _debuggee.GetStackTrace(threadId, firstFrameIdx, limit); - var frames = new VSCodeDebug.StackFrame[processFrames.Length]; - for (int i = 0; i < processFrames.Length; i++) - { - frames[i] = new VSCodeDebug.StackFrame( - _threadState.RegisterFrame(processFrames[i]), - processFrames[i].MethodName, - processFrames[i].GetSource(), - processFrames[i].LineNumber, 0); - } - - SendResponse(response, new StackTraceResponseBody(frames)); - } - - public override void Scopes(Response response, dynamic arguments) - { - LogCommandReceived(); - int frameId = GetFromContainer(arguments, "frameId", 0); - var frame = _threadState.GetFrameById(frameId); - if (frame == null) - { - SendErrorResponse(response, 10001, "No active stackframe"); - return; - } - - var scopes = new List(); - - // Scope 1: Локальные переменные - var localProvider = new LocalScopeProvider(frame.ThreadId, frame.Index); - var localHandle = _threadState.RegisterVariablesProvider(localProvider); - scopes.Add(new Scope("Локальные переменные", localHandle)); - - // Scope 2: Переменные модуля (начиная с протокола версии 4) - if (_debuggee.ProtocolVersion >= ProtocolVersions.Version4) - { - var moduleProvider = new ModuleScopeProvider(frame.ThreadId, frame.Index); - var moduleHandle = _threadState.RegisterVariablesProvider(moduleProvider); - scopes.Add(new Scope("Переменные модуля", moduleHandle)); - } - - SendResponse(response, new ScopesResponseBody(scopes.ToArray())); - } - - public override void Variables(Response response, dynamic arguments) - { - LogCommandReceived(); - int varsHandle = GetFromContainer(arguments, "variablesReference", 0); - var provider = _threadState.GetVariablesProviderById(varsHandle); - if (provider == null) - { - SendErrorResponse(response, 10001, "Invalid variables reference"); - return; - } - - // Получаем переменные через провайдер - var variables = _debuggee.FetchVariables(provider); - var responseArray = new VSCodeDebug.Variable[variables.Length]; - - for (int i = 0; i < responseArray.Length; i++) - { - var variable = variables[i]; - int childHandle = 0; - - if (variable.IsStructured) - { - var childProvider = provider.CreateChildProvider(i); - childHandle = _threadState.RegisterVariablesProvider(childProvider); - } - - responseArray[i] = new VSCodeDebug.Variable( - variable.Name, - variable.Presentation, - variable.TypeName, - childHandle); - } - - SendResponse(response, new VariablesResponseBody(responseArray)); - } - - public override void Threads(Response response, dynamic arguments) - { - LogCommandReceived(); - var threads = new List(); - var processThreads = _debuggee.GetThreads(); - for (int i = 0; i < processThreads.Length; i++) - { - threads.Add(new VSCodeDebug.Thread(processThreads[i], $"Thread {processThreads[i]}")); - } - - SendResponse(response, new ThreadsResponseBody(threads)); - } - - public override void Evaluate(Response response, dynamic arguments) - { - LogCommandReceived(); - // expression, frameId, context - int frameId = GetFromContainer(arguments, "frameId", 0); - var frame = _threadState.GetFrameById(frameId); - if (frame == null) - { - SendErrorResponse(response, 10001, "No active stackframe"); - return; - } - - var expression = (string) arguments.expression; - var context = (string) arguments.context; - - Log.Debug("Evaluate {Expression} in {Context}", expression, context); - - int id = 0; - OneScript.DebugProtocol.Variable evalResult; - try - { - evalResult = _debuggee.Evaluate(frame, expression); - - if (evalResult.IsStructured) - { - var provider = new EvaluatedExpressionProvider(expression, frame.ThreadId, frame.Index); - id = _threadState.RegisterVariablesProvider(provider); - } - } - catch (Exception e) - { - evalResult = new OneScript.DebugProtocol.Variable() { Presentation = e.Message, Name = "$evalFault" }; - } - - if (evalResult.Name.Equals("$evalFault") && context.Equals("hover")) - { - evalResult.Presentation = $"err: {expression}"; - } - - var protResult = new EvaluateResponseBody(evalResult.Presentation, id) {type = evalResult.TypeName}; - SendResponse(response, protResult); - } - - - private void SendOutput(string category, string data) - { - if (!String.IsNullOrEmpty(data)) - { - if (data[data.Length - 1] != '\n') - { - data += '\n'; - } - SendEvent(new OutputEvent(category, data)); - } - } - - private static T GetFromContainer(dynamic container, string propertyName, T defaultValue = default) - { - try - { - return (T)container[propertyName]; - } - catch (Exception) - { - // ignore and return default value - } - return defaultValue; - } - - protected override void OnRequestError(Exception e) - { - Log.Error(e, "Unhandled request processing error"); - } - - private void LogCommandReceived(dynamic args = null, [CallerMemberName] string commandName = "") - { - if (args == null) - Log.Debug("Command received {Command}", commandName); - else - Log.Debug("Command received {Command}: {@Args}", commandName, args); - } - } -} diff --git a/src/VSCode.DebugAdapter/Program.cs b/src/VSCode.DebugAdapter/Program.cs index 0966206d7..9cae5a4e7 100644 --- a/src/VSCode.DebugAdapter/Program.cs +++ b/src/VSCode.DebugAdapter/Program.cs @@ -1,4 +1,4 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v.2.0. If a copy of the MPL was not distributed with this file, You can obtain one @@ -55,13 +55,10 @@ private static void StartSession(Stream input, Stream output) var adapter = new OneScriptDebugAdapter(factory.CreateLogger("OneScriptDebugAdapter")); var dapServer = new DapServer(new BufferedTransport(input, output), adapter, factory); - - var session = new OscriptDebugSession(); - try { Log.Logger.Information("Starting debug adapter"); - session.Start(input, output); + dapServer.RunAsync(System.Threading.CancellationToken.None).GetAwaiter().GetResult(); } catch (Exception e) { diff --git a/src/VSCode.DebugAdapter/Protocol.cs b/src/VSCode.DebugAdapter/Protocol.cs deleted file mode 100644 index fad6cd03b..000000000 --- a/src/VSCode.DebugAdapter/Protocol.cs +++ /dev/null @@ -1,270 +0,0 @@ -/*---------------------------------------------------------- -This Source Code Form is subject to the terms of the -Mozilla Public License, v.2.0. If a copy of the MPL -was not distributed with this file, You can obtain one -at http://mozilla.org/MPL/2.0/. -----------------------------------------------------------*/ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -using System; -using System.Text; -using System.IO; -using System.Text.RegularExpressions; -using Newtonsoft.Json; -using Serilog; - -namespace VSCodeDebug -{ - public class ProtocolMessage - { - public int seq; - public string type { get; } - - public ProtocolMessage(string typ) { - type = typ; - } - - public ProtocolMessage(string typ, int sq) { - type = typ; - seq = sq; - } - } - - public class Request : ProtocolMessage - { - public string command; - public dynamic arguments; - - public Request(int id, string cmd, dynamic arg) : base("request", id) { - command = cmd; - arguments = arg; - } - } - - /* - * subclasses of ResponseBody are serialized as the body of a response. - * Don't change their instance variables since that will break the debug protocol. - */ - public class ResponseBody { - // empty - } - - public class Response : ProtocolMessage - { - public bool success { get; private set; } - public string message { get; private set; } - public int request_seq { get; } - public string command { get; } - public ResponseBody body { get; private set; } - - public Response(Request req) : base("response") { - success = true; - request_seq = req.seq; - command = req.command; - } - - public void SetBody(ResponseBody bdy) { - success = true; - body = bdy; - } - - public void SetErrorBody(string msg, ResponseBody bdy = null) { - success = false; - message = msg; - body = bdy; - } - } - - public class Event : ProtocolMessage - { - [JsonProperty(PropertyName = "event")] - public string eventType { get; } - public dynamic body { get; } - - public Event(string type, dynamic bdy = null) : base("event") { - eventType = type; - body = bdy; - } - } - - /* - * The ProtocolServer can be used to implement a server that uses the VSCode debug protocol. - */ - public abstract class ProtocolServer - { - protected const int BUFFER_SIZE = 4096; - protected const string TWO_CRLF = "\r\n\r\n"; - protected static readonly Regex CONTENT_LENGTH_MATCHER = new Regex(@"Content-Length: (\d+)"); - - protected static readonly Encoding Encoding = System.Text.Encoding.UTF8; - - private int _sequenceNumber = 1; - - private Stream _outputStream; - - private ByteBuffer _rawData = new ByteBuffer(); - private int _bodyLength = -1; - - private bool _stopRequested; - - - public void Start(Stream inputStream, Stream outputStream) - { - _outputStream = outputStream; - - byte[] buffer = new byte[BUFFER_SIZE]; - - _stopRequested = false; - while (!_stopRequested) { - var read = inputStream.Read(buffer, 0, buffer.Length); - - if (read == 0) { - // end of stream - break; - } - - if (read > 0) { - _rawData.Append(buffer, read); - ProcessData(); - } - } - } - - public void Stop() - { - _stopRequested = true; - } - - public void SendEvent(Event e) - { - SendMessage(e); - } - - protected abstract void DispatchRequest(string command, dynamic args, Response response); - - // ---- private ------------------------------------------------------------------------ - - private void ProcessData() - { - while (true) { - if (_bodyLength >= 0) { - if (_rawData.Length >= _bodyLength) { - var buf = _rawData.RemoveFirst(_bodyLength); - - _bodyLength = -1; - - Dispatch(Encoding.GetString(buf)); - - continue; // there may be more complete messages to process - } - } - else { - string s = _rawData.GetString(Encoding); - var idx = s.IndexOf(TWO_CRLF); - if (idx != -1) { - Match m = CONTENT_LENGTH_MATCHER.Match(s); - if (m.Success && m.Groups.Count == 2) { - _bodyLength = Convert.ToInt32(m.Groups[1].ToString()); - - _rawData.RemoveFirst(idx + TWO_CRLF.Length); - - continue; // try to handle a complete message - } - } - } - break; - } - } - - private void Dispatch(string req) - { - var request = JsonConvert.DeserializeObject(req); - if (request != null && request.type == "request") { - Log.Verbose("Got {Command} with args {Args}", request.command, JsonConvert.SerializeObject(request.arguments)); - - var response = new Response(request); - - DispatchRequest(request.command, request.arguments, response); - - SendMessage(response); - } - } - - protected void SendMessage(ProtocolMessage message) - { - message.seq = _sequenceNumber++; - - if (message.type == "response") { - Log.Verbose("Response {Response}", JsonConvert.SerializeObject(message)); - } - if (message.type == "event") { - Event e = (Event)message; - Log.Verbose("Event {EventType} with args {Args}", e.eventType, JsonConvert.SerializeObject(e.body)); - } - - var data = ConvertToBytes(message); - try { - _outputStream.Write(data, 0, data.Length); - _outputStream.Flush(); - } - catch (Exception) { - // ignore - } - } - - private static byte[] ConvertToBytes(ProtocolMessage request) - { - var asJson = JsonConvert.SerializeObject(request); - byte[] jsonBytes = Encoding.GetBytes(asJson); - - string header = string.Format("Content-Length: {0}{1}", jsonBytes.Length, TWO_CRLF); - byte[] headerBytes = Encoding.GetBytes(header); - - byte[] data = new byte[headerBytes.Length + jsonBytes.Length]; - System.Buffer.BlockCopy(headerBytes, 0, data, 0, headerBytes.Length); - System.Buffer.BlockCopy(jsonBytes, 0, data, headerBytes.Length, jsonBytes.Length); - - return data; - } - } - - //-------------------------------------------------------------------------------------- - - class ByteBuffer - { - private byte[] _buffer; - - public ByteBuffer() { - _buffer = new byte[0]; - } - - public int Length { - get { return _buffer.Length; } - } - - public string GetString(Encoding enc) - { - return enc.GetString(_buffer); - } - - public void Append(byte[] b, int length) - { - byte[] newBuffer = new byte[_buffer.Length + length]; - System.Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _buffer.Length); - System.Buffer.BlockCopy(b, 0, newBuffer, _buffer.Length, length); - _buffer = newBuffer; - } - - public byte[] RemoveFirst(int n) - { - byte[] b = new byte[n]; - System.Buffer.BlockCopy(_buffer, 0, b, 0, n); - byte[] newBuffer = new byte[_buffer.Length - n]; - System.Buffer.BlockCopy(_buffer, n, newBuffer, 0, _buffer.Length - n); - _buffer = newBuffer; - return b; - } - } -} From 6858bd0856760cc52308dc6d83831e9c5601bb0b Mon Sep 17 00:00:00 2001 From: EvilBeaver Date: Wed, 25 Mar 2026 10:42:12 +0300 Subject: [PATCH 7/7] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=20debuggee?= =?UTF-8?q?=20=D0=B2=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B8?= =?UTF-8?q?=D0=BA=20initialized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/VSCode.DebugAdapter/DebugeeFactory.cs | 8 ----- .../OneScriptDebugAdapter.cs | 30 ++++++++----------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/VSCode.DebugAdapter/DebugeeFactory.cs b/src/VSCode.DebugAdapter/DebugeeFactory.cs index f25d51387..d494b21fd 100644 --- a/src/VSCode.DebugAdapter/DebugeeFactory.cs +++ b/src/VSCode.DebugAdapter/DebugeeFactory.cs @@ -25,13 +25,5 @@ public static DebugeeProcess CreateProcess(string adapterId, PathHandlingStrateg throw new ArgumentOutOfRangeException(nameof(adapterId), adapterId, "Unsupported debugger"); } - - public static DebugeeProcess CreateAttachableProcess(string adapterId, PathHandlingStrategy pathStrategy) - { - // Для аттача нам не важно, консольный это процесс или веб-сервер, - // так как мы не запускаем его, а только подключаемся. - // Но нам нужен экземпляр DebugeeProcess. ConsoleProcess подойдет. - return new ConsoleProcess(pathStrategy); - } } } \ No newline at end of file diff --git a/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs index 5500d4898..e98313f71 100644 --- a/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs +++ b/src/VSCode.DebugAdapter/OneScriptDebugAdapter.cs @@ -35,6 +35,17 @@ public OneScriptDebugAdapter(ILogger logger) protected override async Task OnInitializeAsync(InitializeRequest request, CancellationToken ct) { + var pathStrategy = new PathHandlingStrategy + { + ClientLinesStartAt1 = Client.LinesStartAt1, + ClientPathsAreUri = Client.PathFormat == "uri", + DebuggerLinesStartAt1 = true, + DebuggerPathsAreUri = false + }; + + _debuggee = DebugeeFactory.CreateProcess(Client.AdapterId, pathStrategy); + Log.LogDebug("Debuggee created"); + await EventsChannel.SendEventAsync(new InitializedEvent(), ct); return new InitializeResponse() @@ -338,15 +349,6 @@ public override Task AttachAsync(AttachRequest request, Cancella { var options = request.Arguments.DeserializeAdditionalProperties(); - var pathStrategy = new PathHandlingStrategy - { - ClientLinesStartAt1 = Client.LinesStartAt1, - ClientPathsAreUri = Client.PathFormat == "uri", - DebuggerLinesStartAt1 = true, - DebuggerPathsAreUri = false - }; - - _debuggee = DebugeeFactory.CreateAttachableProcess(Client.AdapterId, pathStrategy); _debuggee.DebugPort = options.DebugPort; _debuggee.PathsMapper = options.PathsMapping; @@ -428,15 +430,7 @@ public override async Task LaunchAsync(LaunchRequest request, Ca try { Log.LogDebug("Initializing process settings"); - var pathStrategy = new PathHandlingStrategy - { - ClientLinesStartAt1 = Client.LinesStartAt1, - ClientPathsAreUri = Client.PathFormat == "uri", - DebuggerLinesStartAt1 = true, - DebuggerPathsAreUri = false - }; - - _debuggee = DebugeeFactory.CreateProcess(Client.AdapterId, pathStrategy); + _debuggee.Init(request.Arguments); } catch (InvalidDebugeeOptionsException e)