106 lines
2.7 KiB
ObjectPascal
106 lines
2.7 KiB
ObjectPascal
unit ATStringProc_WordJump;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
ATStringProc;
|
|
|
|
function SFindWordOffset(const S: atString; AOffset: integer; ANext, ABigJump: boolean;
|
|
const AWordChars: atString): integer;
|
|
procedure SFindWordBounds(const S: atString; AOffset: integer; out AOffset1, AOffset2: integer;
|
|
const AWordChars: atString);
|
|
|
|
implementation
|
|
|
|
const
|
|
//no EOL here, we jump only inside line
|
|
cCharsSp: atString = ' '#9;
|
|
//no chars '@' (email) and '$' (used in php)
|
|
cCharsSymb: atString = '!"#%&''()[]{}<>*+-/=,.:;?\^`|~‚„…‹›‘’“”–—¦«»±';
|
|
|
|
|
|
type
|
|
TCharGr = (cgSp, cgSymb, cgWord);
|
|
|
|
function SCharGr(ch: atChar; const AWordChars: atString): TCharGr;
|
|
begin
|
|
if (AWordChars<>'') and (Pos(ch, AWordChars)>0) then Result:= cgWord else
|
|
if Pos(ch, cCharsSp)>0 then Result:= cgSp else
|
|
if Pos(ch, cCharsSymb)>0 then Result:= cgSymb else
|
|
Result:= cgWord;
|
|
end;
|
|
|
|
function SFindWordOffset(const S: atString; AOffset: integer; ANext,
|
|
ABigJump: boolean; const AWordChars: atString): integer;
|
|
var
|
|
n: integer;
|
|
//------------
|
|
procedure Next;
|
|
var gr: TCharGr;
|
|
begin
|
|
if not ((n>=0) and (n<Length(s))) then Exit;
|
|
gr:= SCharGr(s[n+1], AWordChars);
|
|
repeat Inc(n)
|
|
until
|
|
(n>=Length(s)) or (SCharGr(s[n+1], AWordChars)<>gr);
|
|
end;
|
|
//------------
|
|
procedure Home;
|
|
var gr: TCharGr;
|
|
begin
|
|
if not ((n>0) and (n<Length(s))) then Exit;
|
|
gr:= SCharGr(s[n+1], AWordChars);
|
|
while (n>0) and (SCharGr(s[n], AWordChars)=gr) do
|
|
Dec(n);
|
|
end;
|
|
//------------
|
|
begin
|
|
n:= AOffset;
|
|
if ANext then
|
|
begin
|
|
Next;
|
|
if ABigJump then
|
|
if (n<Length(s)) and (SCharGr(s[n+1], AWordChars)= cgSp) then
|
|
Next;
|
|
end
|
|
else
|
|
begin
|
|
//if we at word middle, jump to word start
|
|
if (n>0) and (n<Length(s)) and (SCharGr(s[n], AWordChars)=SCharGr(s[n+1], AWordChars)) then
|
|
Home
|
|
else
|
|
begin
|
|
//jump lefter, then jump to prev word start
|
|
if (n>0) then
|
|
begin Dec(n); Home end;
|
|
if ABigJump then
|
|
if (n>0) and (SCharGr(s[n+1], AWordChars)= cgSp) then
|
|
begin Dec(n); Home end;
|
|
end
|
|
end;
|
|
Result:= n;
|
|
end;
|
|
|
|
procedure SFindWordBounds(const S: atString; AOffset: integer; out AOffset1,
|
|
AOffset2: integer; const AWordChars: atString);
|
|
begin
|
|
AOffset1:= AOffset;
|
|
AOffset2:= AOffset;
|
|
|
|
if (AOffset>=0) and (AOffset<Length(S)) and
|
|
IsCharWord(S[AOffset+1], AWordChars) then
|
|
begin
|
|
//jump left only if at middle of word
|
|
if (AOffset>0) and IsCharWord(S[AOffset], AWordChars) then
|
|
AOffset1:= SFindWordOffset(S, AOffset, false, false, AWordChars);
|
|
//jump right always
|
|
AOffset2:= SFindWordOffset(S, AOffset, true, false, AWordChars);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|