Re: [fpc-pascal] fpDebug extension for Visual Studio Code
> On May 19, 2020, at 4:43 AM, Joost van der Sluis wrote: > > Hi all, > > As I wrote before I'm working on a fpDebug-extension for Visual Studio Code, > based on the DAB (Debug Adapter Protocol). Excellent, I applaud your efforts. I'm busy now but I'll be sure to test this later. I'm using LLDB in VSCode as my primary debugger for Pascal now so I'm eager to see what improvements you may have made. As for the language server I've taken a break from it for a week but I've implemented ~90% of the protocol already and once I get it cleaned up it will be usable also. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
Ok, here are some of my ideas/hopes/dreams/wishes for the IDE They are all "ideas only", with on knowledge of when/if they may be done. I provide them, in the hope they will help choosing a path for the backend. The IDE should receive a "TWatchWhateverValue" from any of the backend, that provides: 1) async interface (that is actually for the benefit of the backends) Currently the IDE would call a method (example callstack) - IDE calls "count" => not yet known = 0 - the backend starts retriving the value, and once the value is avail, it triggers an "changed" event - IDE calls count again. - IDE starts accessing the items in the list. They may be available, but if not the return "evaluating" (or whatever dummy value), and the backend will get them and trigger "change" again. Alternative, there could be a CountState, that would return if the count is already avail. The trigger to get the count, would still be to call "count". However, the backend must be able to retrieve any requested data from fpdebug, and that should be in a format that is ready for the IDE. (TDebuggerIntf classes) Evaluating huge data, may need to be "interruptible" => either called in small blocks (like the callstack at current), or by run in a thread, and check for an "abort state". For single watches this is currently not needed. 2) the IDE must be able to retrieve values in different formats, with minimum work of the backend (but allowing for async) - An ordinal value must either be known as ordinal (none text form), then the IDE can do dec/hex/bin... or it can be retrieved from the TWatchWhateverValue in any of those formats (and does not need complete re-eval) - Hex representation: this can do a re-eval if needed - A structure may have different text formats (more or less verbose...) - objects for fields/members (array element) can be retrieved. array element, probably re-use one instance, changing the value. One would not want to create thousands of instances Because any op can be async, the current way of just calling the getter, and getting a dummy "evaluating" value/object works well. The IDE does not need to differ if the value is final or not. If it is not final a "changed" event is triggered, and the IDE starts again (same as if the debugger entered pause) 3) The TWatchWhateverValue must be able to store (and serialize) its data. Or a part of it. It must be able to "work on the stored data only". Watches are added to debug history. If viewed from history, no further eval is possible. The debugged app has changed its state... Currently this stores the display-text. Limiting changed to display format. It would be up to the IDE how match the watch stores, and the watch would then only be able to return the stored subset of data. It also must be able to serialize, as the history can be saved/loaded to/from xml. - The async part may make things tricky IF a watch asks for the list of fields, it gets TDbgFields or similar. But a field may be an object with fields of its own. So if this TDbgField is asked for its field, that must somehow be async to. Yet the baseclass may not necessary need that implementation.. So PascalBuilder would need to create Fields, but the exact subclass could be given by the backend. Disclaimer: I have not fully thought that through And many thinks should probably only be added, when they will be needed. As I said, just to help keeping the design flexible enough. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 20/05/2020 19:54, Martin Frb wrote: If you look at using FpDebug directly, then you use TFpValue. (returned by PascalParser, or any Parser you want to add) All you need is to encapsulate PascalBuilder into a class. And stick the value and the builder into yet another object, holding both of them. TPascalBuilder would then be a formatter class. It would also deliver the structures for fields, elements, children. TPascalBuilder can be configured, for verbosity. (optino to skip all the typenames, it currently includes) With TPascalBuilder it can also be passed to whatever code builds stackframes. So formatting for those can be affected. (because the class carries the config) And then there is/was the idea with: getting data on request. Creating a list of objects for all the fields of a class, needs to be optional. Well it is, by means of flags passed to Pascalbuilder. What is missing, is the ability to later upgrade. There are 2 considerations. 1) re-reading target mem. There already is a cache for target mem. If TFpValue and TPascalBuilder are hold by a "watch value class", this can control the cache, and keep the memory. This memory is only the class. Vaules by ref, like strings are not included. 2) adding list of fields, to watch that was text only This will also rebuild the text. That can be suppressed, if needed ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 20/05/2020 17:50, Joost van der Sluis wrote: I was very disappointed when i (re?)-discovered that fpDebug has a dependency on DebuggerIntf. It is a bit of a catch22: - On the one hand, FpDebug is/should be stand alone. - On the other hand, it would be a pity to have to copy all the used types. There is basic stuff like TDbgPtr. If needs must, that could be redeclared, with IFDEF But there is also result classes for PascalBuilder (and probably somewhere stackframes). Removing this may add a lot of overhead. FpDebug also uses LazUtils package. And that wont be easy to resolve, unless by "copy and paste" :( Picture1: http://amira.cnoc.nl/fpc/FPDebugDesign1.svg Picture1 show what I want to achieve. I want to use the formatting of variables and such in another environment as Lazarus. And ind the long term I want to make it possible for Lazarus to use other debuggers. Also for other languages. (Using DAB or others) Should the arrows be the other way round? console === "has a / uses " ===> var/type-formatter Picture2: http://amira.cnoc.nl/fpc/FPDebugDesign2.svg Picture2 shows the current situation at a high abstraction level. The logic for displaying variables is all over the place, as you explained. Please correct me, if I'm wrong somewhere. "There are several implementations of DebuggerIntf, each for a specifig debugger" There is only one "DebuggerIntf" (aka API). The Interface is "designed" to provide base-classes for both: the IDE and each backend. So GDBMIDebugger is a "debugger backend". As such it inherits the provided base classes of the DebuggerIntf. The Backends then use an actual debugger (gdb, lldb, fpDebug) Formatting does not really happen in the Frontend (IDE) or DebuggerIntf. It happens either in the "Backend": reformat from what gdb gave us. Or in the debugger: FpDebug/PascalBuilder. Picture3: http://amira.cnoc.nl/fpc/FPDebugDesign3.svg Picture3 shows a possible solution. We add a new class, in the picture called 'formatter' to handle the display of variables. As an input it will need some 'handler' which implements an interface with functions to retrieve debug-information and access memory. It's output can be in something like the TDbgVariable format I showed before. (Needs adaptation, though). I think some arrows go the wrong way round? In the picture I let the IDE make a direct connection to this new 'formatter'. But maybe it is better to do this in DebuggerIntf. I also thought about a migration-path: we can just add this new route, without using it. And then enable it bit-by-bit. We could alse add a 'default' implementation in DebuggerIntf. So all debug-handlers may use it, or add overrides to do it in a different way. DAB and Console => those should be handled like debugger backends. Except they do not need IDE compatibility. But they do the same task. And add FpDebugServer. *** FORMATTER CLASS First of all "Formatter" (PascalBuilder) is already somewhat exchangeable. It is currently up to the "backend" what to call to get text. "Backend" calls Parser (currently PascalParser) to get FpDebug internal value. "Backend" hands result to Formatter (PascalBuilder) The Formatter still needs to read memory. This needs to be the case, as the amount of memory to be read can depend on the format (i.e. a pointer in the data may display the address, or read the data at the address). Some formatting should be responsibility of the IDE (or debugger frontend) 1) I.e Changing decimal to hex => no need for the backend 2) On the other hand, the IDE does not know, how to display a "structure" (record, class, object, or even none Pascal). That is work the backend needs to do. (That is as a single text, not be expanding a [+] subitems view) 3) The backend also needs to deliver different data for hex dump. Most of that exists, in the current classes in TDebuggerIntf. (with some issues though) - If you look at using FpDebug directly, then you use TFpValue. (returned by PascalParser, or any Parser you want to add) All you need is to encapsulate PascalBuilder into a class. And stick the value and the builder into yet another object, holding both of them. TPascalBuilder would then be a formatter class. It would also deliver the structures for fields, elements, children. TPascalBuilder can be configured, for verbosity. (optino to skip all the typenames, it currently includes) With TPascalBuilder it can also be passed to whatever code builds stackframes. So formatting for those can be affected. (because the class carries the config) - For the IDE it is more work. There needs to be an abstraction that works with all backends. And the abstraction must be serializable (for DebugHistory window) / or partly serializable. For the IDE it is important that the "formatter" delivers fields, elements, children in the classes provided by TDebuggerInf. Otherwise the backends, must copy all the data into the
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
Seems like the first message did not make it to the list. Maybe because of the attachments... Retry: Op 19-05-2020 om 16:42 schreef Martin Frb: On 19/05/2020 15:55, Joost van der Sluis wrote: It is not documented, and, to be honest, only name, value and type are being used now. It is just a rough idea, we have to figure things out. Ah, I see. About DebuggerIntf: 1) DebuggerIntf was meant to be the API between IDE and the debugger-backend. The backend is TFpDebugDebugger. FpDebug is not the backend, its used by the backend. But it currently provides for the backend, and that means it uses those classes I was very disappointed when i (re?)-discovered that fpDebug has a dependency on DebuggerIntf. 2) DebuggerIntf was never "designed". It was ripped out of GDBMIDebugger, with the hope to be cleaned up and refactored. That hope is still there That also raises the question what you base your DAB classes on. Some code that you will need, does live in TFpDebugDebugger - Detecting the instantiated class, instead of the declared class. - Checking breakpoint conditions (Though part of this should move into FpDebug) - Handling Exceptions / stepping to except,finally (not sure if that is likely to move) It is even more complex then I could remember. Thanks for the update, very useful. I think it is difficult to discuss a new design/solution at a distance. I've tried to catch the problems in some pictures. Picture1: http://amira.cnoc.nl/fpc/FPDebugDesign1.svg Picture1 show what I want to achieve. I want to use the formatting of variables and such in another environment as Lazarus. And ind the long term I want to make it possible for Lazarus to use other debuggers. Also for other languages. (Using DAB or others) Picture2: http://amira.cnoc.nl/fpc/FPDebugDesign2.svg Picture2 shows the current situation at a high abstraction level. The logic for displaying variables is all over the place, as you explained. Please correct me, if I'm wrong somewhere. Picture3: http://amira.cnoc.nl/fpc/FPDebugDesign3.svg Picture3 shows a possible solution. We add a new class, in the picture called 'formatter' to handle the display of variables. As an input it will need some 'handler' which implements an interface with functions to retrieve debug-information and access memory. It's output can be in something like the TDbgVariable format I showed before. (Needs adaptation, though). In the picture I let the IDE make a direct connection to this new 'formatter'. But maybe it is better to do this in DebuggerIntf. I also thought about a migration-path: we can just add this new route, without using it. And then enable it bit-by-bit. We could alse add a 'default' implementation in DebuggerIntf. So all debug-handlers may use it, or add overrides to do it in a different way. What do you think? Regards, Joost. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 19/05/2020 15:55, Joost van der Sluis wrote: On 5/19/20 12:59 PM, Martin Frb wrote: Where is that documented? Assuming this is part of the API? E.g. what goes into Flags/AdditionalInfo? You misunderstood me. The class above is my own design. The variable-definition of DAB is even simpler. (As you already found out) It is not documented, and, to be honest, only name, value and type are being used now. It is just a rough idea, we have to figure things out. Ah, I see. In that case, the decision to be made is, if the classes from the DebuggerIntf package can be used (potentially after being updated). There already is TFields, and that can be used (and can be generalized) for that kind of thing. About DebuggerIntf: 1) DebuggerIntf was meant to be the API between IDE and the debugger-backend. The backend is TFpDebugDebugger. FpDebug is not the backend, its used by the backend. But it currently provides for the backend, and that means it uses those classes 2) DebuggerIntf was never "designed". It was ripped out of GDBMIDebugger, with the hope to be cleaned up and refactored. That hope is still there That also raises the question what you base your DAB classes on. Some code that you will need, does live in TFpDebugDebugger - Detecting the instantiated class, instead of the declared class. - Checking breakpoint conditions (Though part of this should move into FpDebug) - Handling Exceptions / stepping to except,finally (not sure if that is likely to move) Btw, for Children (I guess Fields of a struct?) we have TDbgFields. So maybe that can be replaced? But it affects all debuggers They don't have to be fields. It can be anything. To the user it is presented as something they can collapse/expand. If you want to give a hint to the GUI how to represent the data, you can set a flag. Of course. Arrays should also be collapse/expand able, so you can inspect each element (important of array of struct). But arrays may contain thousands of elements. So only a subset would be gotten at a time. When designing collapse/expand, it is important to consider, that in the IDE data needs to be retrieved in async calls (i.e. IDE requests, debugger triggers event if data is ready) - This is (not only) because gdb debuggers are slow - This is also because the IDE needs to keep running when many values are queried, and the IDE needs to be able to send "step/run" while eval still runs => debugger should abort eval, if user wants to continue Otherwise stepping becomes very sluggish, if you have a bigger list of watches. At least that's how it is implemented in DAB. I thought it would be a good idea to add a second 'group of children', the AdditionalInfo. For example for the character-set of a string. Things like that. There are different kind of children (and the question is, if they can be mixed) - named structure members - indexed/numbered (array) members (low / high / request any (sub)range) - internal properties (e.g. charset). - Flags (set of enum) Internal properties do not need a name. They could have an ID, which is an enum. FpDebug can only provide internal properties about which it knows. So the full list of possible ID must always be known. It would be a list (unique by ID). Not sure if we need a list of base classes? It be enough to have one (internal property) "base class", and search that recursively. Or allow it to be called with an index. There also is the question, should (all/some/none) of the internal properties be created by default? The structure could have a field "set of (id-list)" which indicates the available internal props. To be created on request. And when creating a watch, one could pass in a set of ID, that should be pre-created. There also may need to be control over caching the memory that was read. If that will still be needed for evaluating further info. (a cache exists, and is used for objects) Though that creates issues: - Calling in correct thread - any data retrieval from the debugger needs to be async. I.e. on callback. The IDE demands the data, and it will be available in/after a callback. However, maybe that can be done in a subclass/wrapper in the TFpDebugDebugger class. That is were the async is currently handled. Maybe. I don't really have a solution yet. Maybe the reference-id is not that bad. (In FPDServer the id is an auto-incremented field. In a map I store the related info, like the thread-id, callstack-index and such. When this info is not available anymore, the item is removed from the map. Seems to work ok) It depends a lot where the cut between FpDebug and FpDebugDebugger goes. FpDebug would not be async. But the design should allow for the caller to easily add that. Also one more note: - It should not affect above design to much - I have not yet looked into how to archive this, but threading may get added to fpdebug at some time (not soon). That needs to reflect that only one
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 5/19/20 12:59 PM, Martin Frb wrote: On 19/05/2020 10:42, Joost van der Sluis wrote: It is basically this class: (see https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas) TDbgVariable = class private FName: string; FValue: string; FType: string; FVisibleInScope: Boolean; FFlags: TStringArray; FAdditionalInfo: TDbgVariableList; FInheritedChildren: TDbgVariableList; FChildren: TDbgVariableList; published property Name: string read FName write FName; property Value: string read FValue write FValue; property : string read FType write FType; property VisibleInScope: Boolean read FVisibleInScope write FVisibleInScope; property Flags: TStringArray read FFlags write FFlags; property AdditionalInfo: TDbgVariableList read FAdditionalInfo; property InheritedChildren: TDbgVariableList read FInheritedChildren; property Children: TDbgVariableList read FChildren; end; Where is that documented? Assuming this is part of the API? E.g. what goes into Flags/AdditionalInfo? You misunderstood me. The class above is my own design. The variable-definition of DAB is even simpler. (As you already found out) It is not documented, and, to be honest, only name, value and type are being used now. It is just a rough idea, we have to figure things out. Btw, for Children (I guess Fields of a struct?) we have TDbgFields. So maybe that can be replaced? But it affects all debuggers They don't have to be fields. It can be anything. To the user it is presented as something they can collapse/expand. If you want to give a hint to the GUI how to represent the data, you can set a flag. At least that's how it is implemented in DAB. I thought it would be a good idea to add a second 'group of children', the AdditionalInfo. For example for the character-set of a string. Things like that. Things like Children should have a Getter, so they can be produced on demand. Yep. But I see this structure more as a an interface. A definition about how the data should be structured. In DAB they resolve this by setting some reference-id. So instead of the children, you get an ID. And if you want to have the children, just send a request with the given Id, and you will receive the children. Not a real solution for our case, I would think. Though that creates issues: - Calling in correct thread - any data retrieval from the debugger needs to be async. I.e. on callback. The IDE demands the data, and it will be available in/after a callback. However, maybe that can be done in a subclass/wrapper in the TFpDebugDebugger class. That is were the async is currently handled. Maybe. I don't really have a solution yet. Maybe the reference-id is not that bad. (In FPDServer the id is an auto-incremented field. In a map I store the related info, like the thread-id, callstack-index and such. When this info is not available anymore, the item is removed from the map. Seems to work ok) Regards, Joost. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 19/05/2020 12:59, Martin Frb wrote: Where is that documented? Assuming this is part of the API? The closest I could find: https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable I would much prefer if "Flags: TStringArray" could be a "set of (...)" And then somehow be mapped. FpDebug could take a "class of TDbgVariable". And then create whatever subclass you need. So your subclass could map that into strings. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 19/05/2020 10:42, Joost van der Sluis wrote: Yes, you write about it earlier. Now it's time to discuss things. Looking at the DAB-protocol I came to some new insights. Microsoft managed to create a simple interface which makes it possible for all kinds of debuggers to work with the same GUI. Just by adding an abstraction layer. Only thing is that I missed a few functions and do not need others. So I've added my own abstraction layer. Now it is in the FPDServer project, but I think it should be made part of fpDebug itself. It is basically this class: (see https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas) TDbgVariable = class private FName: string; FValue: string; FType: string; FVisibleInScope: Boolean; FFlags: TStringArray; FAdditionalInfo: TDbgVariableList; FInheritedChildren: TDbgVariableList; FChildren: TDbgVariableList; published property Name: string read FName write FName; property Value: string read FValue write FValue; property : string read FType write FType; property VisibleInScope: Boolean read FVisibleInScope write FVisibleInScope; property Flags: TStringArray read FFlags write FFlags; property AdditionalInfo: TDbgVariableList read FAdditionalInfo; property InheritedChildren: TDbgVariableList read FInheritedChildren; property Children: TDbgVariableList read FChildren; end; I think that we can give a frontend (Lazarus, Console, DAB) all the information it needs with this structure. The advantage is that it is layered, so a GUI can collapse information. We could expand the TDbgVariableBuilder to create these structures. For strings for example, we could add the length, string-type, binary-representation and character-set of the string in AdditionalInfo. In VS Code this info will end-up as a child of the variable, which a user could expand if needed. A lot of the existing functionality can be used. Where is that documented? Assuming this is part of the API? E.g. what goes into Flags/AdditionalInfo? Btw, for Children (I guess Fields of a struct?) we have TDbgFields. So maybe that can be replaced? But it affects all debuggers Things like Children should have a Getter, so they can be produced on demand. Though that creates issues: - Calling in correct thread - any data retrieval from the debugger needs to be async. I.e. on callback. The IDE demands the data, and it will be available in/after a callback. However, maybe that can be done in a subclass/wrapper in the TFpDebugDebugger class. That is were the async is currently handled. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 5/19/20 12:22 AM, Martin Frb wrote: On 18/05/2020 23:43, Joost van der Sluis wrote: All the basics should work, if someone could test it a bit that would be nice. Threading-support is still very lacking, and how variables are presented is not really nice. I'll be working on that. While this can be changed in PascalBuilder, there are some considerations. Some of those may want to become configurable. So not sure yet. More likely the formatting may want to depend an arguments passed to the functions. In the Lazarus IDE currently representation of the values is entirely to the backend. And that is plain wrong. The IDE will have to have some influence on that. I haven't yet given it much consideration. Just putting it out there for thought Yes, you write about it earlier. Now it's time to discuss things. Looking at the DAB-protocol I came to some new insights. Microsoft managed to create a simple interface which makes it possible for all kinds of debuggers to work with the same GUI. Just by adding an abstraction layer. Only thing is that I missed a few functions and do not need others. So I've added my own abstraction layer. Now it is in the FPDServer project, but I think it should be made part of fpDebug itself. It is basically this class: (see https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas) TDbgVariable = class private FName: string; FValue: string; FType: string; FVisibleInScope: Boolean; FFlags: TStringArray; FAdditionalInfo: TDbgVariableList; FInheritedChildren: TDbgVariableList; FChildren: TDbgVariableList; published property Name: string read FName write FName; property Value: string read FValue write FValue; property : string read FType write FType; property VisibleInScope: Boolean read FVisibleInScope write FVisibleInScope; property Flags: TStringArray read FFlags write FFlags; property AdditionalInfo: TDbgVariableList read FAdditionalInfo; property InheritedChildren: TDbgVariableList read FInheritedChildren; property Children: TDbgVariableList read FChildren; end; I think that we can give a frontend (Lazarus, Console, DAB) all the information it needs with this structure. The advantage is that it is layered, so a GUI can collapse information. We could expand the TDbgVariableBuilder to create these structures. For strings for example, we could add the length, string-type, binary-representation and character-set of the string in AdditionalInfo. In VS Code this info will end-up as a child of the variable, which a user could expand if needed. A lot of the existing functionality can be used. Regards, Joost. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] fpDebug extension for Visual Studio Code
On 18/05/2020 23:43, Joost van der Sluis wrote: All the basics should work, if someone could test it a bit that would be nice. Threading-support is still very lacking, and how variables are presented is not really nice. I'll be working on that. While this can be changed in PascalBuilder, there are some considerations. Some of those may want to become configurable. So not sure yet. More likely the formatting may want to depend an arguments passed to the functions. In the Lazarus IDE currently representation of the values is entirely to the backend. And that is plain wrong. The IDE will have to have some influence on that. I haven't yet given it much consideration. Just putting it out there for thought ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] fpDebug extension for Visual Studio Code
Hi all, As I wrote before I'm working on a fpDebug-extension for Visual Studio Code, based on the DAB (Debug Adapter Protocol). This protocol is also used by other editors. I have a first version ready. It consists of the parts: the fpdserver which implements the DAB-protocal and the fpDebug plugin which is just a wrapper with some configuration-settings. I'm a little bit amazed that the plugin has 10 install already, without ever noticing it. Or maybe these are just bots or something... All the basics should work, if someone could test it a bit that would be nice. Threading-support is still very lacking, and how variables are presented is not really nice. I'll be working on that. And maybe someone can create an icon for it? Here are the links: FPDServer: https://gitlab.freepascal.org/Joost/fpdserver fpDebug plugin: https://marketplace.visualstudio.com/items?itemName=CNOC.fpdebug Regards, Joost. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal