procedure TWordCompletion.GetWordList(aWordList: TStrings;
const Filter: String;
ContainsFilter, CaseSensitive: boolean;
MaxResults: ptrint);
var i, Line, x, FilterLen, MaxHash, LineLen: ptrint;
UpFilter, LineText, UpLineText, UpWordBuffer: string;
SourceText: TStrings;
HashList: ^ptrint;// index list. Every entry points to a word in the aWordList
SourceTextIndex, SourceTopLine, SourceBottomLine: ptrint;
LastCharType: TCharType;
IgnoreWordPos: TPoint;
procedure Add(const aWord:string);
// if aWord is not already in list then add it to aWordList
var a,Hash,HashTry: ptrint;
aLowWord: string;
begin
aLowWord:=lowercase(aWord);
Hash:=0;
a:=1;
while (a <= length(aLowWord)) and (a < 20) do begin
inc(Hash,ord(aLowWord[a]) and $7f);
inc(a);
end;
Hash:= (Hash*137) mod MaxHash;
HashTry:= 0;
while (HashTry<MaxHash) do begin
a:= HashList[(Hash+HashTry) mod MaxHash];
if a >= 0 then begin
if (aWordList[a] = aWord) then
// word already in list -> do not add
exit;
end else begin
// word not in list -> add
HashList[(Hash+HashTry) mod MaxHash]:= aWordList.Add(aWord);
exit;
end;
inc(HashTry);
end;
end;
procedure AddIfMatch(const ALine, ALineUp:string; const AFirstPos, ALength: ptrint);
var
AAdd: Boolean;
begin
if FilterLen = 0 then
AAdd:= True
else
begin
AAdd:= False;
if CaseSensitive then begin
if ContainsFilter then
AAdd:= MyPos(Filter, ALine, AFirstPos, AFirstPos+ALength-1) > 0
else
AAdd:= strlcomp(PChar(@ALine[AFirstPos]),PChar(Filter),FilterLen) = 0;
end else
begin
if ContainsFilter then
AAdd:= MyPos(UpFilter, ALineUp, AFirstPos, AFirstPos+ALength-1) > 0
else
AAdd:= strlcomp(PChar(@ALineUp[AFirstPos]),PChar(UpFilter),FilterLen) = 0;
end;
end;
if AAdd then
Add(Copy(ALine, AFirstPos, ALength));
end;
// TWordCompletion.GetWordList
begin
aWordList.Clear;
if MaxResults < 1 then MaxResults:= 1;
MaxHash:= MaxResults*3;
GetMem(HashList,MaxHash*SizeOf(ptrint));
try
for i:= 0 to MaxHash-1 do HashList[i]:= -1;
FilterLen:= length(Filter);
aWordList.Capacity:= MaxResults;
UpFilter:= uppercase(Filter);
// first add all recently used words
i:= fWordBuffer.Count-1;
UpWordBuffer:= '';
while (i >= 0) and (aWordList.Count < MaxResults) do begin
if not CaseSensitive then
UpWordBuffer:= UpperCase(fWordBuffer[i]);
AddIfMatch(fWordBuffer[i], UpWordBuffer, 1, Length(fWordBuffer[i]));
dec(i);
end;
if aWordList.Count >= MaxResults then exit;
// then search in all sources for more words that could fit
SourceTextIndex:= 0;
SourceText:= nil;
SourceTopLine:= 0;
SourceBottomLine:= -1;
IgnoreWordPos:= Point(-1,-1);
DoGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex);
UpLineText:= '';
repeat
if SourceText <> nil then begin
Line:= SourceTopLine;
if SourceBottomLine < 0 then
SourceBottomLine:= SourceText.Count-1;
while (Line <= SourceBottomLine) do begin
LineText:= SourceText[line];
LineLen:= length(LineText);
if not CaseSensitive then
UpLineText:= uppercase(LineText);
x:= 1;
LastCharType:= ctNone;
while (x <= LineLen) do begin
if (LastCharType = ctNone) and (CharTable[LineText[x]] = ctWordBegin)
then begin
// word found
i:= x;
repeat
inc(i);
until (i > LineLen) or (CharTable[LineText[i]] = ctNone);
if (i-x >= FilterLen) and not ((Line = IgnoreWordPos.Y) and (x <= IgnoreWordPos.X) and (IgnoreWordPos.X<=i)) then begin
AddIfMatch(LineText,UpLineText,x,i-x);
if aWordList.Count >= MaxResults then exit;
end;
x:= i;
end else
inc(x);
LastCharType:= CharTable[LineText[x-1]];
end;
inc(line);
end;
end;
inc(SourceTextIndex);
SourceText:= nil;
SourceTopLine:= 0;
SourceBottomLine:= -1;
IgnoreWordPos:= Point(-1,-1);
DoGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex);
until SourceText = nil;
finally
FreeMem(HashList);
end;
end;