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.
Project group and projects (incl. build, environment options, module sync)
With the Logger functionality you can add messages to the message tool window.
var Helper: 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]);
Or start the Logger with your own group name. This creates a separate tab in the message tool window with that name.
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
var Logger := Helper.Logger('MyLogTab');Use the custom option to create message with different colors or referencing to a file. In that case double cliking 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]);Get the loaded project group as follows:
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
var ProjectGroup := Helper.ProjectGroup;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
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active project
var ProjectHelper := Helper.Project;
var ActiveProject: IOTAProject := ProjectHelper.Get;
// Get the interface for a given project
var ProjectHelper := Helper.Project(OTAProject);With the IToolsApiProject interface you have access to the project options and the build configurations.
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active project
var ProjectHelper := Helper.Project;
// Get the project options to figure out the platforms used, the active platform, etc.
var ProjectOptions: IOTAProjectOptionsConfigurations := ProjectHelper.ProjectConfigurations;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.
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
// Get the active project
var ProjectHelper := Helper.Project;
// Get the base build configuration
var BaseBuildConfig: IToolsApiBuildConfiguration := ProjectHelper.BuildConfigurations.Base;
// Get the search paths
var SearchPaths: TArray<string> := BaseBuildConfig.SearchPaths;
// Change the paths
SearchPaths := SearchPaths + [NewFilePath];
BaseBuildConfig.SearchPaths := SearchPaths;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.
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
// Build the active project without blocking on the progress dialog
var Succeeded := Helper.Project.Build(True);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.
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
var EnvironmentOptions := Helper.EnvironmentOptions;
var ExactName: string;
if EnvironmentOptions.TryFindOptionName('ShowCompilerProgress', ExactName) then
begin
var Value := EnvironmentOptions.GetOption(ExactName);
EnvironmentOptions.SetOption(ExactName, False);
end;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).
var Module: IToolsApiModule := THelper.Module;
if not Module.MatchesDisk then
Module.SyncWithDisk; // reloads if safe, raises on conflictIToolsApiProject.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).
var Helper: IToolsApiHelper := TToolsApiHelper.Create;
Helper.Project.CreateFormUnit('C:\proj\FMain.pas', 'MainForm', 'TForm');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;
// Inspect
for var 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 referenceAddComponent 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, ...).
IToolsApiFormEditor.CaptureImage renders the designed form to a PNG (via TCustomForm.GetFormImage), returned as TBytes.
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 then
begin
var Value := Debugger.Evaluate('Customer.Name');
for var Frame in Debugger.CallStack do
; // Frame.Header, .FileName, .LineNumber
end;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 aTUsesResultrecord -
FindWord: searches the source code for a given word and returns the first match as aTMatchobject -
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.