mirror of https://gitlab.com/basile.b/dexed.git
736 lines
18 KiB
Plaintext
736 lines
18 KiB
Plaintext
unit u_dcd;
|
|
|
|
{$I u_defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, process, forms, strutils, LazFileUtils,
|
|
{$IFDEF WINDOWS}
|
|
windows,
|
|
{$ENDIF}
|
|
u_common, u_writableComponent, u_interfaces, u_observer, u_synmemo,
|
|
u_stringrange, u_projutils, u_semver;
|
|
|
|
type
|
|
|
|
TIntOpenArray = array of integer;
|
|
|
|
(**
|
|
* Wrap the dcd-server and dcd-client processes.
|
|
*
|
|
* Projects folders are automatically imported: IProjectObserver.
|
|
* Completion, hints and declaration finder automatically work on the current
|
|
* document: IDocumentObserver.
|
|
*)
|
|
TDcdWrapper = class(TWritableLfmTextComponent, IProjectObserver, IDocumentObserver)
|
|
private
|
|
fTempLines: TStringList;
|
|
fInputSource: string;
|
|
fImportCache: TStringHashSet;
|
|
fPortNum: Word;
|
|
fCurrentSessionPortNum: Word;
|
|
fServerWasRunning: boolean;
|
|
fClient, fServer: TProcess;
|
|
fAvailable: boolean;
|
|
fServerListening: boolean;
|
|
fDoc: TDexedMemo;
|
|
fProj: ICommonProject;
|
|
fPortAsProcParam: string;
|
|
fVersion: TSemVer;
|
|
fCanRemove: boolean;
|
|
procedure killServer;
|
|
procedure terminateClient; {$IFNDEF DEBUG}inline;{$ENDIF}
|
|
procedure waitClient; {$IFNDEF DEBUG}inline;{$ENDIF}
|
|
procedure updateServerlistening;
|
|
procedure writeSourceToInput; {$IFNDEF DEBUG}inline;{$ENDIF}
|
|
function checkDcdSocket: boolean;
|
|
function getIfLaunched: boolean;
|
|
procedure tryAddTcpParams; {$IFNDEF DEBUG}inline;{$ENDIF}
|
|
procedure updateImportPathsFromProject;
|
|
//
|
|
procedure projNew(project: ICommonProject);
|
|
procedure projChanged(project: ICommonProject);
|
|
procedure projClosing(project: ICommonProject);
|
|
procedure projFocused(project: ICommonProject);
|
|
procedure projCompiling(project: ICommonProject);
|
|
procedure projCompiled(project: ICommonProject; success: boolean);
|
|
//
|
|
procedure docNew(document: TDexedMemo);
|
|
procedure docFocused(document: TDexedMemo);
|
|
procedure docChanged(document: TDexedMemo);
|
|
procedure docClosing(document: TDexedMemo);
|
|
published
|
|
property port: word read fPortNum write fPortNum default 0;
|
|
public
|
|
constructor create(aOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
//
|
|
class procedure relaunch; static;
|
|
class function noDcdPassedAsArg: boolean; static;
|
|
//
|
|
procedure addImportFolders(const folders: TStrings);
|
|
procedure addImportFolder(const folder: string);
|
|
procedure remImportFolder(const folder: string);
|
|
procedure remImportFolders(const folders: TStrings);
|
|
procedure getComplAtCursor(list: TStringList);
|
|
procedure getCallTip(out tips: string);
|
|
procedure getDdocFromCursor(out comment: string);
|
|
procedure getDeclFromCursor(out fname: string; out position: Integer);
|
|
procedure getLocalSymbolUsageFromCursor(var locs: TIntOpenArray);
|
|
//
|
|
property available: boolean read fAvailable;
|
|
property launchedByCe: boolean read getIfLaunched;
|
|
end;
|
|
|
|
function DCDWrapper: TDcdWrapper;
|
|
|
|
implementation
|
|
|
|
var
|
|
fDcdWrapper: TDcdWrapper = nil;
|
|
|
|
const
|
|
clientName = 'dcd-client' + exeExt;
|
|
serverName = 'dcd-server' + exeExt;
|
|
optsname = 'dcdoptions.txt';
|
|
|
|
|
|
{$REGION Standard Comp/Obj------------------------------------------------------}
|
|
constructor TDcdWrapper.create(aOwner: TComponent);
|
|
var
|
|
fname: string;
|
|
i: integer = 0;
|
|
r: TSemVer;
|
|
begin
|
|
inherited;
|
|
|
|
fVersion.init('v0.0.0');
|
|
fname := getDocPath + optsname;
|
|
if fname.fileExists then
|
|
loadFromFile(fname);
|
|
fCurrentSessionPortNum := fPortNum;
|
|
fPortAsProcParam := '-p' + intToStr(fCurrentSessionPortNum);
|
|
|
|
fAvailable := exeInSysPath(clientName) and exeInSysPath(serverName)
|
|
and not noDcdPassedAsArg();
|
|
if not fAvailable then
|
|
exit;
|
|
|
|
fClient := TProcess.Create(self);
|
|
fClient.Executable := exeFullName(clientName);
|
|
fClient.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
|
|
fClient.ShowWindow := swoHIDE;
|
|
|
|
fServerWasRunning := AppIsRunning((serverName));
|
|
if not fServerWasRunning then
|
|
begin
|
|
fServer := TProcess.Create(self);
|
|
fServer.Executable := exeFullName(serverName);
|
|
fServer.Options := [{$IFDEF WINDOWS} poNewConsole{$ENDIF}];
|
|
{$IFNDEF DEBUG}
|
|
fServer.ShowWindow := swoHIDE;
|
|
{$ENDIF}
|
|
if fCurrentSessionPortNum <> 0 then
|
|
begin
|
|
fServer.Parameters.Add('--tcp');
|
|
fServer.Parameters.Add(fPortAsProcParam);
|
|
end;
|
|
end;
|
|
fTempLines := TStringList.Create;
|
|
fImportCache := TStringHashSet.Create;
|
|
|
|
fClient.Parameters.Add('--version');
|
|
fClient.Execute;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
fVersion.init(fTempLines.strictText);
|
|
r.major := 0;
|
|
r.minor := 9;
|
|
r.patch := 10;
|
|
fCanRemove := fVersion > r;
|
|
|
|
if fServer.isNotNil then
|
|
begin
|
|
fServer.Execute;
|
|
while true do
|
|
begin
|
|
if (i = 10) or checkDcdSocket then
|
|
break;
|
|
i += 1;
|
|
end;
|
|
end;
|
|
updateServerlistening;
|
|
|
|
EntitiesConnector.addObserver(self);
|
|
end;
|
|
|
|
class function TDcdWrapper.noDcdPassedAsArg(): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
result := false;
|
|
for i := 1 to argc-1 do
|
|
if ParamStr(i) = '-nodcd' then
|
|
begin
|
|
result :=true;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
class procedure TDcdWrapper.relaunch;
|
|
begin
|
|
fDcdWrapper.Free;
|
|
fDcdWrapper := TDcdWrapper.create(nil);
|
|
end;
|
|
|
|
function TDcdWrapper.getIfLaunched: boolean;
|
|
begin
|
|
result := fServer.isNotNil;
|
|
end;
|
|
|
|
procedure TDcdWrapper.updateServerlistening;
|
|
begin
|
|
fServerListening := AppIsRunning((serverName));
|
|
end;
|
|
|
|
destructor TDcdWrapper.destroy;
|
|
var
|
|
i: integer = 0;
|
|
begin
|
|
saveToFile(getDocPath + optsname);
|
|
EntitiesConnector.removeObserver(self);
|
|
fImportCache.Free;
|
|
if fTempLines.isNotNil then
|
|
fTempLines.Free;
|
|
if fServer.isNotNil then
|
|
begin
|
|
if not fServerWasRunning then
|
|
begin
|
|
killServer;
|
|
while true do
|
|
begin
|
|
if (not checkDcdSocket) or (i = 10) then
|
|
break;
|
|
i +=1;
|
|
end;
|
|
end;
|
|
fServer.Terminate(0);
|
|
fServer.Free;
|
|
end;
|
|
fClient.Free;
|
|
inherited;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION IProjectObserver ----------------------------------------------------}
|
|
procedure TDcdWrapper.updateImportPathsFromProject;
|
|
var
|
|
i: Integer;
|
|
fold: string;
|
|
folds: TStringList;
|
|
begin
|
|
if not assigned(fProj) then
|
|
exit;
|
|
|
|
folds := TStringList.Create;
|
|
try
|
|
fold := u_projutils.projectSourcePath(fProj);
|
|
if fold.dirExists then
|
|
folds.Add(fold);
|
|
for i := 0 to fProj.importsPathCount-1 do
|
|
begin
|
|
fold := fProj.importPath(i);
|
|
if fold.dirExists and (folds.IndexOf(fold) = -1) then
|
|
folds.Add(fold);
|
|
end;
|
|
addImportFolders(folds);
|
|
finally
|
|
folds.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TDcdWrapper.projNew(project: ICommonProject);
|
|
begin
|
|
fProj := project;
|
|
end;
|
|
|
|
procedure TDcdWrapper.projChanged(project: ICommonProject);
|
|
begin
|
|
if (fProj = nil) or (fProj <> project) then
|
|
exit;
|
|
updateImportPathsFromProject();
|
|
end;
|
|
|
|
procedure TDcdWrapper.projClosing(project: ICommonProject);
|
|
begin
|
|
if fProj <> project then
|
|
exit;
|
|
fProj := nil;
|
|
end;
|
|
|
|
procedure TDcdWrapper.projFocused(project: ICommonProject);
|
|
begin
|
|
fProj := project;
|
|
updateImportPathsFromProject();
|
|
end;
|
|
|
|
procedure TDcdWrapper.projCompiling(project: ICommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TDcdWrapper.projCompiled(project: ICommonProject; success: boolean);
|
|
begin
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION IDocumentObserver ---------------------------------------------------}
|
|
procedure TDcdWrapper.docNew(document: TDexedMemo);
|
|
begin
|
|
fDoc := document;
|
|
end;
|
|
|
|
procedure TDcdWrapper.docFocused(document: TDexedMemo);
|
|
begin
|
|
fDoc := document;
|
|
end;
|
|
|
|
procedure TDcdWrapper.docChanged(document: TDexedMemo);
|
|
begin
|
|
if fDoc <> document then
|
|
exit;
|
|
end;
|
|
|
|
procedure TDcdWrapper.docClosing(document: TDexedMemo);
|
|
begin
|
|
if fDoc <> document then
|
|
exit;
|
|
fDoc := nil;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
{$REGION DCD things ------------------------------------------------------------}
|
|
procedure TDcdWrapper.terminateClient;
|
|
begin
|
|
if fClient.Running then
|
|
fClient.Terminate(0);
|
|
end;
|
|
|
|
function TDcdWrapper.checkDcdSocket: boolean;
|
|
var
|
|
str: string;
|
|
prt: word = 9166;
|
|
prc: TProcess;
|
|
lst: TStringList;
|
|
begin
|
|
sleep(100);
|
|
// nix/osx: the file might exists from a previous session that crashed
|
|
// however the 100 ms might be enough for DCD initialization
|
|
if fCurrentSessionPortNum = 0 then
|
|
begin
|
|
{$IFDEF LINUX}
|
|
str := sysutils.GetEnvironmentVariable('XDG_RUNTIME_DIR');
|
|
if (str + DirectorySeparator + 'dcd.socket').fileExists then
|
|
exit(true);
|
|
str := sysutils.GetEnvironmentVariable('UID');
|
|
if ('/tmp/dcd-' + str + '.socket').fileExists then
|
|
exit(true);
|
|
{$ENDIF}
|
|
{$IFDEF DARWIN}
|
|
str := sysutils.GetEnvironmentVariable('UID');
|
|
if ('/var/tmp/dcd-' + str + '.socket').fileExists then
|
|
exit(true);
|
|
{$ENDIF}
|
|
end;
|
|
result := false;
|
|
if port <> 0 then
|
|
prt := port;
|
|
prc := TProcess.Create(nil);
|
|
try
|
|
prc.Options:= [poUsePipes, poNoConsole];
|
|
prc.Executable := 'netstat';
|
|
prc.Parameters.Add('-o');
|
|
prc.Parameters.Add('-a');
|
|
prc.Parameters.Add('-n');
|
|
prc.Execute;
|
|
lst := TStringList.Create;
|
|
try
|
|
processOutputToStrings(prc,lst);
|
|
while prc.Running do ;
|
|
for str in lst do
|
|
if AnsiContainsText(str, '127.0.0.1:' + intToStr(prt))
|
|
and AnsiContainsText(str, 'TCP')
|
|
and AnsiContainsText(str, 'LISTEN') then
|
|
begin
|
|
result := true;
|
|
break;
|
|
end;
|
|
finally
|
|
lst.Free;
|
|
end;
|
|
finally
|
|
prc.Free;
|
|
end;
|
|
exit(result);
|
|
end;
|
|
|
|
procedure TDcdWrapper.tryAddTcpParams;
|
|
begin
|
|
if fCurrentSessionPortNum <> 0 then
|
|
begin
|
|
fClient.Parameters.Add('--tcp');
|
|
fClient.Parameters.Add(fPortAsProcParam);
|
|
end;
|
|
end;
|
|
|
|
procedure TDcdWrapper.killServer;
|
|
begin
|
|
if not fAvailable or not fServerListening then
|
|
exit;
|
|
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('--shutdown');
|
|
fClient.Execute;
|
|
while fServer.Running or fClient.Running do
|
|
sleep(50);
|
|
end;
|
|
|
|
procedure TDcdWrapper.waitClient;
|
|
begin
|
|
while fClient.Running do
|
|
sleep(5);
|
|
end;
|
|
|
|
procedure TDcdWrapper.writeSourceToInput;
|
|
begin
|
|
fInputSource := fDoc.Text;
|
|
fClient.Input.Write(fInputSource[1], fInputSource.length);
|
|
fClient.CloseInput;
|
|
end;
|
|
|
|
procedure TDcdWrapper.addImportFolder(const folder: string);
|
|
begin
|
|
if not fAvailable or not fServerListening or fImportCache.contains(folder) then
|
|
exit;
|
|
|
|
fImportCache.insert(folder);
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-I' + folder);
|
|
fClient.Execute;
|
|
while fClient.Running do ;
|
|
end;
|
|
|
|
procedure TDcdWrapper.addImportFolders(const folders: TStrings);
|
|
var
|
|
i: string;
|
|
c: integer;
|
|
begin
|
|
if not fAvailable or not fServerListening then
|
|
exit;
|
|
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
c := folders.Count;
|
|
for i in folders do
|
|
begin
|
|
if fImportCache.contains(i) then
|
|
continue;
|
|
fImportCache.insert(i);
|
|
fClient.Parameters.Add('-I' + i);
|
|
dec(c);
|
|
end;
|
|
if c <> folders.Count then
|
|
begin
|
|
fClient.Execute;
|
|
while fClient.Running do ;
|
|
end;
|
|
end;
|
|
|
|
procedure TDcdWrapper.remImportFolder(const folder: string);
|
|
begin
|
|
if not fCanRemove then
|
|
exit;
|
|
if not fAvailable or not fServerListening or not fImportCache.contains(folder) then
|
|
exit;
|
|
|
|
fImportCache.delete(folder);
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-R' + folder);
|
|
fClient.Execute;
|
|
while fClient.Running do ;
|
|
end;
|
|
|
|
procedure TDcdWrapper.remImportFolders(const folders: TStrings);
|
|
var
|
|
i: string;
|
|
c: integer;
|
|
begin
|
|
if not fCanRemove then
|
|
exit;
|
|
if not fAvailable or not fServerListening then
|
|
exit;
|
|
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
c := folders.Count;
|
|
for i in folders do
|
|
begin
|
|
if not fImportCache.contains(i) then
|
|
continue;
|
|
fImportCache.delete(i);
|
|
fClient.Parameters.Add('-R' + i);
|
|
dec(c);
|
|
end;
|
|
if c <> folders.Count then
|
|
begin
|
|
fClient.Execute;
|
|
while fClient.Running do ;
|
|
end;
|
|
end;
|
|
|
|
procedure TDcdWrapper.getCallTip(out tips: string);
|
|
begin
|
|
if not fAvailable or not fServerListening or fDoc.isNil then
|
|
exit;
|
|
|
|
terminateClient;
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-c');
|
|
fClient.Parameters.Add(intToStr(fDoc.SelStart - 1));
|
|
fClient.Execute;
|
|
writeSourceToInput;
|
|
|
|
fTempLines.Clear;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
if fTempLines.Count = 0 then
|
|
begin
|
|
updateServerlistening;
|
|
exit;
|
|
end;
|
|
if not (fTempLines[0] = 'calltips') then
|
|
exit;
|
|
|
|
fTempLines.Delete(0);
|
|
tips := fTempLines.Text;
|
|
{$IFDEF WINDOWS}
|
|
tips := tips[1..tips.length-2];
|
|
{$ELSE}
|
|
tips := tips[1..tips.length-1];
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function compareknd(List: TStringList; Index1, Index2: Integer): Integer;
|
|
var
|
|
k1, k2: byte;
|
|
begin
|
|
k1 := Byte(PtrUint(List.Objects[Index1]));
|
|
k2 := Byte(PtrUint(List.Objects[Index2]));
|
|
if k1 > k2 then
|
|
result := 1
|
|
else if k1 < k2 then
|
|
result := -1
|
|
else
|
|
result := CompareStr(list[Index1], list[Index2]);
|
|
end;
|
|
|
|
procedure TDcdWrapper.getComplAtCursor(list: TStringList);
|
|
var
|
|
i: Integer;
|
|
kind: Char;
|
|
item: string;
|
|
kindObj: TObject = nil;
|
|
begin
|
|
if not fAvailable or not fServerListening or fDoc.isNil then
|
|
exit;
|
|
|
|
terminateClient;
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-c');
|
|
fClient.Parameters.Add(intToStr(fDoc.SelStart - 1));
|
|
fClient.Execute;
|
|
writeSourceToInput;
|
|
|
|
fTempLines.Clear;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
if fTempLines.Count = 0 then
|
|
begin
|
|
updateServerlistening;
|
|
exit;
|
|
end;
|
|
if not (fTempLines[0] = 'identifiers') then
|
|
exit;
|
|
|
|
list.Clear;
|
|
for i := 1 to fTempLines.Count-1 do
|
|
begin
|
|
item := fTempLines[i];
|
|
kind := item[item.length];
|
|
setLength(item, item.length-2);
|
|
case kind of
|
|
'c': kindObj := TObject(PtrUint(dckClass));
|
|
'i': kindObj := TObject(PtrUint(dckInterface));
|
|
's': kindObj := TObject(PtrUint(dckStruct));
|
|
'u': kindObj := TObject(PtrUint(dckUnion));
|
|
'v': kindObj := TObject(PtrUint(dckVariable));
|
|
'm': kindObj := TObject(PtrUint(dckMember));
|
|
'k': kindObj := TObject(PtrUint(dckReserved));
|
|
'f': kindObj := TObject(PtrUint(dckFunction));
|
|
'g': kindObj := TObject(PtrUint(dckEnum));
|
|
'e': kindObj := TObject(PtrUint(dckEnum_member));
|
|
'P': kindObj := TObject(PtrUint(dckPackage));
|
|
'M': kindObj := TObject(PtrUint(dckModule));
|
|
'a': kindObj := TObject(PtrUint(dckArray));
|
|
'A': kindObj := TObject(PtrUint(dckAA));
|
|
'l': kindObj := TObject(PtrUint(dckAlias));
|
|
't': kindObj := TObject(PtrUint(dckTemplate));
|
|
'T': kindObj := TObject(PtrUint(dckMixin));
|
|
'h': kindObj := TObject(PtrUint(dckMember));
|
|
'p': kindObj := TObject(PtrUint(dckMember));
|
|
// internal DCD stuff, Should not to happen...report bug if it does.
|
|
'*', '?': continue;
|
|
end;
|
|
list.AddObject(item, kindObj);
|
|
end;
|
|
//list.CustomSort(@compareknd);
|
|
end;
|
|
|
|
procedure TDcdWrapper.getDdocFromCursor(out comment: string);
|
|
var
|
|
i: Integer;
|
|
len: Integer;
|
|
str: string;
|
|
begin
|
|
if not fAvailable or not fServerListening or fDoc.isNil then
|
|
exit;
|
|
|
|
i := fDoc.MouseBytePosition;
|
|
if i = 0 then
|
|
exit;
|
|
|
|
terminateClient;
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-d');
|
|
fClient.Parameters.Add('-c');
|
|
fClient.Parameters.Add(intToStr(i - 1));
|
|
fClient.Execute;
|
|
writeSourceToInput;
|
|
|
|
comment := '';
|
|
fTempLines.Clear;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
len := fTempLines.Count-1;
|
|
if len = -1 then
|
|
updateServerlistening;
|
|
for i := 0 to len do
|
|
begin
|
|
str := fTempLines[i];
|
|
with TStringRange.create(str) do while not empty do
|
|
begin
|
|
comment += takeUntil('\').yield;
|
|
if startsWith('\\') then
|
|
begin
|
|
comment += '\';
|
|
popFrontN(2);
|
|
end
|
|
else if startsWith('\n') then
|
|
begin
|
|
comment += LineEnding;
|
|
popFrontN(2);
|
|
end
|
|
end;
|
|
if i <> len then
|
|
comment += LineEnding + LineEnding;
|
|
end;
|
|
end;
|
|
|
|
procedure TDcdWrapper.getDeclFromCursor(out fname: string; out position: Integer);
|
|
var
|
|
i: Integer;
|
|
str, loc: string;
|
|
begin
|
|
if not fAvailable or not fServerListening or fDoc.isNil then
|
|
exit;
|
|
|
|
terminateClient;
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-l');
|
|
fClient.Parameters.Add('-c');
|
|
fClient.Parameters.Add(intToStr(fDoc.SelStart));
|
|
fClient.Execute;
|
|
writeSourceToInput;
|
|
|
|
fTempLines.Clear;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
if fTempLines.Count > 0 then
|
|
begin
|
|
str := fTempLines[0];
|
|
if str.isNotEmpty then
|
|
begin
|
|
i := Pos(#9, str);
|
|
if i = -1 then
|
|
exit;
|
|
loc := str[i+1..str.length];
|
|
fname := TrimFilename(str[1..i-1]);
|
|
loc := ReplaceStr(loc, LineEnding, '');
|
|
position := strToIntDef(loc, -1);
|
|
end;
|
|
end
|
|
else updateServerlistening;
|
|
end;
|
|
|
|
procedure TDcdWrapper.getLocalSymbolUsageFromCursor(var locs: TIntOpenArray);
|
|
var
|
|
i: Integer;
|
|
str: string;
|
|
begin
|
|
if not fAvailable or not fServerListening or fDoc.isNil then
|
|
exit;
|
|
|
|
terminateClient;
|
|
fClient.Parameters.Clear;
|
|
tryAddTcpParams;
|
|
fClient.Parameters.Add('-u');
|
|
fClient.Parameters.Add('-c');
|
|
fClient.Parameters.Add(intToStr(fDoc.SelStart - 1));
|
|
fClient.Execute;
|
|
writeSourceToInput;
|
|
|
|
setLength(locs, 0);
|
|
fTempLines.Clear;
|
|
processOutputToStrings(fClient, fTempLines);
|
|
while fClient.Running do ;
|
|
if fTempLines.Count < 2 then
|
|
exit;
|
|
str := fTempLines[0];
|
|
// symbol is not in current module, too complex for now
|
|
if str[1..5] <> 'stdin' then
|
|
exit;
|
|
|
|
setLength(locs, fTempLines.count-1);
|
|
for i:= 1 to fTempLines.count-1 do
|
|
locs[i-1] := StrToIntDef(fTempLines[i], -1);
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
function DCDWrapper: TDcdWrapper;
|
|
begin
|
|
if fDcdWrapper.isNil then
|
|
fDcdWrapper := TDcdWrapper.create(nil);
|
|
exit(fDcdWrapper);
|
|
end;
|
|
|
|
finalization
|
|
DcdWrapper.Free;
|
|
end.
|