mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-10 19:05:31 +00:00
Refactor the file-opening code so it can be used by Keyman Developer UI as well as command-line, and then add support for opening files in per-project instances from File|Open and friends. Also moves the initialization code out of tike.dpr into Keyman.Developer.System.Main.pas, which makes it easier to maintain and read.
183 lines
4.4 KiB
ObjectPascal
183 lines
4.4 KiB
ObjectPascal
unit Keyman.Developer.System.LaunchProjects;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.Classes,
|
|
System.Generics.Collections,
|
|
System.SysUtils,
|
|
|
|
Keyman.Developer.System.TikeMultiProcess;
|
|
|
|
type
|
|
TLaunchProjectStatus = (lpsWaiting, lpsCurrentInstance, lpsOtherInstance, lpsNewInstance, lpsError);
|
|
TLaunchProject = class
|
|
private
|
|
FProjectFilename: string;
|
|
FFilenames: TStringList;
|
|
FStatus: TLaunchProjectStatus;
|
|
public
|
|
constructor Create(const AProjectFilename: string);
|
|
destructor Destroy; override;
|
|
function LaunchAsNewInstance: Boolean;
|
|
function PassToRunningProcess(AProcesses: TTikeProcessList): Boolean;
|
|
property ProjectFilename: string read FProjectFilename;
|
|
property Filenames: TStringList read FFilenames;
|
|
property Status: TLaunchProjectStatus read FStatus;
|
|
end;
|
|
|
|
TLaunchProjects = class(TObjectList<TLaunchProject>)
|
|
private
|
|
FReserveStartupProject: Boolean;
|
|
function GetStartupProject: TLaunchProject;
|
|
public
|
|
constructor Create(AReserveStartupProject: Boolean);
|
|
procedure GroupFilenamesIntoProjects(const Filenames: TStringList);
|
|
function LaunchAll(AProcesses: TTikeProcessList): Boolean;
|
|
function Find(const ProjectFilename: string): TLaunchProject;
|
|
property ReserveStartupProject: Boolean read FReserveStartupProject;
|
|
property StartupProject: TLaunchProject read GetStartupProject;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Winapi.Windows,
|
|
|
|
Keyman.Developer.System.ProjectOwningFile,
|
|
utilexecute;
|
|
|
|
{ TLaunchProject }
|
|
|
|
constructor TLaunchProject.Create(const AProjectFilename: string);
|
|
begin
|
|
inherited Create;
|
|
FProjectFilename := AProjectFilename;
|
|
FFilenames := TStringList.Create;
|
|
FStatus := lpsWaiting;
|
|
end;
|
|
|
|
destructor TLaunchProject.Destroy;
|
|
begin
|
|
FFilenames.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TLaunchProject.LaunchAsNewInstance: Boolean;
|
|
var
|
|
filename, cmdline: string;
|
|
begin
|
|
cmdline := '"'+ParamStr(0)+'" --sub-process "'+Self.ProjectFilename+'"';
|
|
for filename in Self.Filenames do
|
|
cmdline := cmdline + ' "'+filename+'"';
|
|
|
|
Result := TUtilExecute.Execute(cmdline, GetCurrentDir, SW_SHOWNORMAL);
|
|
|
|
if Result
|
|
then FStatus := lpsNewInstance
|
|
else FStatus := lpsError;
|
|
end;
|
|
|
|
function TLaunchProject.PassToRunningProcess(AProcesses: TTikeProcessList): Boolean;
|
|
var
|
|
tp: TTikeProcess;
|
|
filename: string;
|
|
begin
|
|
for tp in AProcesses do
|
|
begin
|
|
if tp.OwnsProject(Self.ProjectFilename) then
|
|
begin
|
|
FStatus := lpsOtherInstance;
|
|
|
|
if Self.Filenames.Count = 0 then
|
|
begin
|
|
// Ensure that the project file tab is opened
|
|
tp.OpenFile(Self.ProjectFilename);
|
|
end;
|
|
|
|
for filename in Self.Filenames do
|
|
begin
|
|
tp.OpenFile(filename);
|
|
end;
|
|
Exit(True);
|
|
end;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
{ TLaunchProjects }
|
|
|
|
constructor TLaunchProjects.Create(AReserveStartupProject: Boolean);
|
|
begin
|
|
inherited Create(True);
|
|
FReserveStartupProject := AReserveStartupProject;
|
|
end;
|
|
|
|
function TLaunchProjects.Find(const ProjectFilename: string): TLaunchProject;
|
|
begin
|
|
for Result in Self do
|
|
begin
|
|
if Result.ProjectFilename = ProjectFilename then
|
|
begin
|
|
Exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TLaunchProjects.GetStartupProject: TLaunchProject;
|
|
begin
|
|
for Result in Self do
|
|
if Result.Status = lpsCurrentInstance then
|
|
Exit;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TLaunchProjects.GroupFilenamesIntoProjects(const Filenames: TStringList);
|
|
var
|
|
projectFilename, filename: string;
|
|
p: TLaunchProject;
|
|
begin
|
|
for filename in filenames do
|
|
begin
|
|
projectFilename := FindOwnerProjectForFile(filename);
|
|
|
|
p := Self.Find(projectFilename);
|
|
if p = nil then
|
|
begin
|
|
p := TLaunchProject.Create(projectFilename);
|
|
Self.Add(p);
|
|
end;
|
|
p.Filenames.Add(filename);
|
|
end;
|
|
end;
|
|
|
|
function TLaunchProjects.LaunchAll(AProcesses: TTikeProcessList): Boolean;
|
|
var
|
|
p: TLaunchProject;
|
|
begin
|
|
Result := False;
|
|
|
|
// Hand off files to existing processes, based on project folder
|
|
for p in Self do
|
|
begin
|
|
if not p.PassToRunningProcess(AProcesses) then
|
|
begin
|
|
// If there isn't an existing process, then we need to launch a new
|
|
// process for the project
|
|
if not Result and ReserveStartupProject then
|
|
begin
|
|
// For performance, we'll take the first project for the current process
|
|
// if requested
|
|
p.FStatus := lpsCurrentInstance;
|
|
Result := True;
|
|
end
|
|
else
|
|
begin
|
|
p.LaunchAsNewInstance;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|