Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - GDKsoftware/ToolsAPI-helper · GitHub
Skip to content

Latest commit

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ToolsAPI-helper

DelphiLicense

This library contains several helpers and classes to make working with the ToolsAPI much easier. It's so much fun to extend the IDE with your own tools and options, but it is sometimes very hard to find out how to do it. With this library we will contribute to the Delphi community and make it more simple to build your own IDE extensions.

Content

Logging / Messages

Project group and projects (incl. build, environment options, module sync)

Form creation and designer

Debugger

Uses manager

Getting Started

IDE extensions run inside the Delphi IDE, so the library is used from a package (.dpk) project:

  1. Clone this repository
  2. Add the repository root to the search path of your package project, or add the units you need directly
  3. Make sure your package requires DesignIDE, like the included GdkToolsApiHelper.dpk
  4. Create a TToolsApiHelper instance and explore the examples below

The included GdkToolsApiGroupProject.groupproj contains the library package and the DUnitX unit tests (UnitTesting folder).

Requirements

  • Delphi 10.3 Rio or later (the code uses inline variable declarations)

Logger

Simple messages

With the Logger functionality you can add messages to the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger;
// Log just a message
Logger.Log('This is an example logging');
// Log a message with formatting
Logger.Log('This is a message for project: %s', [Project.Name]);

Custom message tab / group

Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');

Custom messages

Use the custom option to create message with different colors or referencing to a file. In that case double clicking the message will open the file.

var CustomMessage := Logger.Custom;
// Setup
CustomMessage.TextColor := clGreen;
CustomMessage.SetFileReference(FilePath, LineNumber);
// Show message
CustomMessage.Add('[%s] Error on line %d', [FilePath, LineNumber]);

Project group and projects

Project Group

Get the loaded project group as follows:

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;

Project

For a project the IToolsApiProject interface is used. This interface groups a list of project related features. This interface can be received in two ways: for the active project or for the given project

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given projectvar ProjectHelper := Helper.Project(OTAProject);

Project options

With the IToolsApiProject interface you have access to the project options and the build configurations.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;

Build configurations

The build configurations are wrapped in IToolsApiBuildConfigurations and IToolsApiBuildConfiguration. With a specific build configuration interface it's easy to get and change the search paths for a project.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active projectvar ProjectHelper := Helper.Project;
// Get the base build configurationvar BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search pathsvar SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;

Building a project

The Build function builds the project with the IDE compiler, like Project > Build. It returns True when the build succeeded.

By default the IDE shows the compile progress dialog. When a build fails, that dialog stays open as a modal dialog until the user dismisses it, and Build only returns after that. For unattended builds (for example builds triggered by an IDE plugin) pass HideProgressDialog := True: the "Show compiler progress" option is then disabled during the build and restored afterwards, so a failing build returns immediately. The compiler messages still appear in the message tool window.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialogvar Succeeded := Helper.Project.Build(True);

Environment options

The IDE environment options (Tools > Options) are wrapped in IToolsApiEnvironmentOptions. Option names can differ between IDE versions, so TryFindOptionName looks up the exact registered name first.

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) thenbeginvarValue := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;

Module buffer/disk sync

A file open in the IDE can be newer in memory than on disk (or vice versa when an external tool edits it). IToolsApiModule exposes IsDirty, MatchesDisk and SyncWithDisk to reason about this. SyncWithDisk reloads the module from disk when the buffer is unmodified, and raises EToolsApiModuleOutOfSync when both sides changed (a real conflict).

varModule: IToolsApiModule := THelper.Module;
ifnotModule.MatchesDisk thenModule.SyncWithDisk; // reloads if safe, raises on conflict

Form creation and designer

Creating a form unit

IToolsApiProject.CreateFormUnit creates a new form unit through IOTAModuleServices.CreateModule, adds it to the project and opens the designer. The unit and .dfm source are generated by the library (not left to the IDE default template, which mangles the class name), so the class is exactly T<FormName>. AncestorName is without the leading T (empty means TForm).

varHelper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');

Editing components on a form

IToolsApiModule.FormDesigner returns an IToolsApiFormEditor for component-level access to an open form designer, like the palette and Object Inspector:

var Designer := THelper.Module.FormDesigner;
// Inspectforvar Component in Designer.Components do
; // Component.Name, .ClassName, ...var Events := Designer.AssignedEvents(Designer.Root); // ['OnClick=Button1Click', ...]// Add a control to a named container (forced to the exact parent, e.g. a TabSheet)var Edit := Designer.AddComponent('TEdit', 'pnlDetail', 8, 8, 200, 23);
// Set published properties by text, including nested paths, sets, events and// component references:
Designer.SetComponentProperty('Edit1', 'Text', 'hello');
Designer.SetComponentProperty('Edit1', 'Font.Size', '12');
Designer.SetComponentProperty('Button1', 'OnClick', 'Button1Click'); // binds/creates handler
Designer.SetComponentProperty('PageControl1', 'ActivePage', 'TabSheet1'); // component reference

AddComponent captures the native container before creating and forces the new control's Parent, so it lands on exactly the requested tab/page (not the active one). Any installed component class works (VCL, TMS, DevExpress, ...).

Rendering a form to an image

IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.

Debugger

IToolsApiHelper.Debugger returns an IToolsApiDebugger around IOTADebuggerServices: source breakpoints, process control (continue/step/pause/terminate), expression evaluation (deferred-aware) and the call stack.

var Debugger := THelper.Debugger;
Debugger.AddBreakpoint('C:\proj\FMain.pas', 42);
// ... run the project ...if Debugger.State = TToolsApiProcessState.Stopped thenbeginvarValue := Debugger.Evaluate('Customer.Name');
forvar Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumberend;

Uses manager

The TToolsApiUsesManager class is located in GDK.ToolsAPI.UsesManager.pas and provides the following methods:

  • WithSource: sets the source code of the unit to be parsed

  • FindUses: searches the source code for the interface and implementation sections, as well as the uses clause, and returns the results as a TUsesResult record

  • FindWord: searches the source code for a given word and returns the first match as a TMatch object

  • FindPositionToAdd: searches the source code for the position where a new unit should be added to the uses clause, and calls a callback function with the position and a Boolean indicating whether the uses clause is currently empty

The TToolsApiUsesManager class also defines some private methods for finding the positions of certain keywords in the source code.

The IToolsApiUsesManager interface is used to define the public methods of the TToolsApiUsesManager class. The interface includes the same methods as the class.

License

MIT License, see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About

No description, website, or topics provided.

Resources

Stars

49 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages