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;