mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-10 03:48:27 +02:00
SynEdit: partly implement handling of space followed by combining mark. Issue #41228
This commit is contained in:
parent
79be6943b5
commit
ed45ec5224
@ -35,6 +35,7 @@ type
|
||||
ExpandedExtraBytes: Integer; // tab and space expansion
|
||||
HasTabs: Boolean; // ExtraWidth may still be 0
|
||||
HasDoubleWidth: Boolean;
|
||||
NeedsEto: Boolean;
|
||||
|
||||
NextPos: TLazSynDisplayTokenBound; // Next toxen, may be BIDI
|
||||
NextRtlInfo: TLazSynDisplayRtlInfo;
|
||||
@ -463,6 +464,7 @@ begin
|
||||
ATokenInfo.ExpandedExtraBytes := 0;
|
||||
ATokenInfo.HasTabs := False;
|
||||
ATokenInfo.HasDoubleWidth := False; // TODO: True, but needs charwidth for painter
|
||||
ATokenInfo.NeedsEto := False;
|
||||
end
|
||||
else begin
|
||||
if ATokenInfo.NextRtlInfo.IsRtl <> FCurMarkupNextRtlInfo.IsRtl then begin
|
||||
@ -740,7 +742,7 @@ var
|
||||
PrevLogicIdx, PrevPhysPos: Integer;
|
||||
PhysTokenStop: Integer;
|
||||
TabExtra: Integer;
|
||||
HasTabs, HasDouble: Boolean;
|
||||
HasTabs, HasDouble, NeedsEto: Boolean;
|
||||
begin
|
||||
ATokenInfo.Attr := nil;
|
||||
while True do begin
|
||||
@ -762,6 +764,7 @@ begin
|
||||
LogicEnd := LogicIdx + FCurViewToken.TokenLength;
|
||||
//assert(GetCharWidthData(LogicIdx)<>0, 'GetNextHighlighterTokenFromView: Token starts with char');
|
||||
|
||||
NeedsEto := False;
|
||||
case FCurViewinRTL of
|
||||
False: // Left To Right
|
||||
begin
|
||||
@ -812,8 +815,13 @@ begin
|
||||
else
|
||||
if j > 1 then
|
||||
HasDouble := True;
|
||||
if c = ' ' then
|
||||
if c = ' ' then begin
|
||||
inc(TabExtra, FSpaceExtraByteCount);
|
||||
{$IfDef WINDOWS}
|
||||
if not NeedsEto then
|
||||
NeedsEto := IsCombiningCodePoint(FCurViewToken.TokenStart + i + 1);
|
||||
{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
|
||||
repeat
|
||||
@ -851,6 +859,7 @@ begin
|
||||
ATokenInfo.ExpandedExtraBytes := TabExtra;
|
||||
ATokenInfo.HasTabs := HasTabs;
|
||||
ATokenInfo.HasDoubleWidth := HasDouble;
|
||||
ATokenInfo.NeedsEto := NeedsEto;
|
||||
assert(ATokenInfo.StartPos.Offset >= 0, 'FCurViewScannerPos.Offset >= 0');
|
||||
assert(ATokenInfo.EndPos.Offset <= 0, 'FCurViewToken.EndPos.Offset <= 0');
|
||||
|
||||
@ -937,8 +946,13 @@ begin
|
||||
else
|
||||
if j > 1 then
|
||||
HasDouble := True;
|
||||
if c = ' ' then
|
||||
if c = ' ' then begin
|
||||
inc(TabExtra, FSpaceExtraByteCount);
|
||||
{$IfDef WINDOWS}
|
||||
if not NeedsEto then
|
||||
NeedsEto := IsCombiningCodePoint(FCurViewToken.TokenStart + i + 1);
|
||||
{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
|
||||
repeat
|
||||
@ -979,6 +993,7 @@ begin
|
||||
ATokenInfo.ExpandedExtraBytes := TabExtra;
|
||||
ATokenInfo.HasTabs := HasTabs;
|
||||
ATokenInfo.HasDoubleWidth := HasDouble;
|
||||
ATokenInfo.NeedsEto := NeedsEto;
|
||||
assert(ATokenInfo.StartPos.Offset >= 0, 'FCurViewScannerPos.Offset >= 0');
|
||||
assert(ATokenInfo.EndPos.Offset <= 0, 'FCurViewToken.EndPos.Offset <= 0');
|
||||
|
||||
@ -1634,7 +1649,7 @@ var
|
||||
end;
|
||||
|
||||
NeedExpansion := (ATokenInfo.ExpandedExtraBytes > 0) or (ATokenInfo.HasTabs);
|
||||
NeedTransform := FTextDrawer.NeedsEto or ATokenInfo.HasDoubleWidth or NeedExpansion
|
||||
NeedTransform := FTextDrawer.NeedsEto or ATokenInfo.HasDoubleWidth or ATokenInfo.NeedsEto or NeedExpansion
|
||||
{$IFDEF Windows} or ATokenInfo.RtlInfo.IsRtl {$ENDIF}
|
||||
;
|
||||
Len := ATokenInfo.Tk.TokenLength;
|
||||
@ -1663,7 +1678,7 @@ var
|
||||
end;
|
||||
|
||||
// Prepare FETOBuf
|
||||
if FTextDrawer.NeedsEto or ATokenInfo.HasDoubleWidth
|
||||
if FTextDrawer.NeedsEto or ATokenInfo.HasDoubleWidth or ATokenInfo.NeedsEto
|
||||
{$IFDEF Windows} or ATokenInfo.RtlInfo.IsRtl {$ENDIF} // RTL may have script with ligature
|
||||
then begin
|
||||
FEtoBuf := FTextDrawer.Eto;
|
||||
@ -1705,7 +1720,9 @@ var
|
||||
if FetoBuf <> nil then FEtoBuf.EtoData[e] := c;
|
||||
inc(e);
|
||||
end;
|
||||
if (vscTabAtLast in FVisibleSpecialChars) and ((pl-1)^=' ') and (j < CWLen) then begin
|
||||
if (vscTabAtLast in FVisibleSpecialChars) and ((pl-1)^=' ') and (j < CWLen) and
|
||||
(not IsCombiningCodePoint(pt+1))
|
||||
then begin
|
||||
(pl-1)^ := #194;
|
||||
pl^ := #187; inc(pl);
|
||||
if FetoBuf <> nil then FEtoBuf.EtoData[e] := c;
|
||||
@ -1713,7 +1730,9 @@ var
|
||||
end;
|
||||
end;
|
||||
' ': begin
|
||||
if (vscSpace in FVisibleSpecialChars) and (j < CWLen) then begin
|
||||
if (vscSpace in FVisibleSpecialChars) and (j < CWLen) and
|
||||
(not IsCombiningCodePoint(pt+1))
|
||||
then begin
|
||||
pl^ := #194; inc(pl);
|
||||
pl^ := #183; inc(pl);
|
||||
end
|
||||
|
@ -43,7 +43,7 @@ uses
|
||||
Classes, SysUtils,
|
||||
LazStringUtils,
|
||||
SynEditMiscClasses, LazSynEditText, SynEditPointClasses,
|
||||
SynEditKeyCmds, SynEditTypes;
|
||||
SynEditKeyCmds, SynEditTypes, SynEditMiscProcs;
|
||||
|
||||
type
|
||||
|
||||
@ -672,11 +672,7 @@ var
|
||||
begin
|
||||
p := PChar(Line);
|
||||
if Assigned(p) then begin
|
||||
Result := 0;
|
||||
while p^ in [#1..#32] do begin
|
||||
Inc(p);
|
||||
Inc(Result);
|
||||
end;
|
||||
Result := CountLeadWhiteSpace(p);
|
||||
if Physical and (Result>0) then
|
||||
Result := FCurrentLines.LogicalToPhysicalCol(Line, -1, Result+1)-1; // TODO, Need the real index of the line
|
||||
end else
|
||||
|
@ -5805,9 +5805,7 @@ begin
|
||||
ALine:=FTheLinesView[FBlockSelection.StartLinePos - 1];
|
||||
x2:=length(ALine)+1;
|
||||
if not WithLeadSpaces then begin
|
||||
x := FBlockSelection.StartBytePos;
|
||||
while (x<length(ALine)) and (ALine[x] in [' ',#9]) do
|
||||
inc(x);
|
||||
x := CountLeadWhiteSpace(PChar(ALine)) + 1;
|
||||
FBlockSelection.StartLineBytePos := Point(x,MinMax(Value.y, 1, FTheLinesView.Count));
|
||||
while (x2 > x) and (ALine[X2-1] in [' ',#9]) do
|
||||
dec(x2);
|
||||
@ -7476,7 +7474,9 @@ begin
|
||||
Temp := Clipboard.AsText;
|
||||
Helper := SelText;
|
||||
if (Temp <> '') and (not (Temp[Length(Temp)] in [#10,#13, #9, #32])) and
|
||||
(not (Helper[1] in [#10,#13, #9, #32]))
|
||||
not( (Helper[1] in [#10,#13, #9, #32]) and
|
||||
( (Length(Helper) = 1) or (not IsCombiningCodePoint(PChar(Helper)+1)))
|
||||
)
|
||||
then
|
||||
Temp := Temp + ' ';
|
||||
Clipboard.AsText := Temp + Helper;
|
||||
@ -9010,6 +9010,8 @@ begin
|
||||
// scan over whitespaces
|
||||
while (p^ in [#9, #32]) do
|
||||
inc(p);
|
||||
if IsCombiningCodePoint(p) then
|
||||
dec(p);
|
||||
i := LogicalToPhysicalCol(PrevLine, iLine, p-@PrevLine[1]+1) - CaretX;
|
||||
end;
|
||||
end;
|
||||
@ -9321,7 +9323,7 @@ begin
|
||||
j := 0;
|
||||
for i := 1 to FBlockTabIndent do begin
|
||||
i2 := fTabWidth;
|
||||
while (i2 > 0) and (Line[j] = #32) do begin
|
||||
while (i2 > 0) and IsSpaceChar(Line+j) do begin
|
||||
dec(i2);
|
||||
inc(j);
|
||||
end;
|
||||
@ -9537,9 +9539,7 @@ begin
|
||||
s := FTheLinesView[CaretXY.Y - 1];
|
||||
|
||||
// search first non blank char pos
|
||||
FirstNonBlank := 1;
|
||||
while (FirstNonBlank <= length(s)) and (s[FirstNonBlank] in [#32, #9]) do
|
||||
inc(FirstNonBlank);
|
||||
FirstNonBlank := CountLeadWhiteSpace(PChar(s)) + 1;
|
||||
if FirstNonBlank > length(s) then
|
||||
FirstNonBlank := -1;
|
||||
end else
|
||||
|
@ -543,15 +543,11 @@ function TSynEditMarkupFoldColors.GetFirstCharacterColumn(pIndex: Integer
|
||||
): TColumnCacheEntry;
|
||||
var
|
||||
l: String;
|
||||
s, p: Integer;
|
||||
p: Integer;
|
||||
begin
|
||||
l := SynEdit.Lines[pIndex];
|
||||
s := length(l);
|
||||
p := 1;
|
||||
while (p <= s)
|
||||
//and (l[p] in [#9, #32, '/']) do inc(p);
|
||||
and (l[p] in [#9, #32]) do inc(p);
|
||||
if p > s then
|
||||
p := CountLeadWhiteSpace(PChar(l)) + 1;
|
||||
if p > length(l) then
|
||||
exit(high(Result));
|
||||
Result := SynEdit.LogicalToPhysicalPos(Point(p, toPos(pIndex))).x;
|
||||
end;
|
||||
|
@ -27,7 +27,7 @@ interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Graphics, Controls,
|
||||
SynEditMarkup, SynEditTypes, SynEditMiscClasses;
|
||||
SynEditMarkup, SynEditTypes, SynEditMiscClasses, SynEditMiscProcs;
|
||||
|
||||
type
|
||||
|
||||
@ -87,9 +87,10 @@ end;
|
||||
function TSynEditMarkupSpecialChar.IsSpecial(pos: Integer): Boolean;
|
||||
begin
|
||||
if (pos < 1) or (pos > Length(FCurLine)) then exit(False);
|
||||
Result := ( (vscSpace in FVisibleSpecialChars) and (FCurLine[pos] in [' ']) ) or
|
||||
( (FVisibleSpecialChars*[vscTabAtFirst, vscTabAtLast] <> []) and (FCurLine[pos] in [#9]) )
|
||||
;
|
||||
Result := ( ( (vscSpace in FVisibleSpecialChars) and (FCurLine[pos] in [' ']) ) or
|
||||
( (FVisibleSpecialChars*[vscTabAtFirst, vscTabAtLast] <> []) and (FCurLine[pos] in [#9]) )
|
||||
) and
|
||||
(not IsCombiningCodePoint(PChar(FCurLine)+pos));
|
||||
end;
|
||||
|
||||
constructor TSynEditMarkupSpecialChar.Create(ASynEdit : TSynEditBase);
|
||||
|
@ -82,6 +82,9 @@ function ToPos(AIdx: Integer): Integer; inline;
|
||||
function YToIdx(APointWithYPos: TPoint): TPoint; inline;
|
||||
function YToPos(APointWithYIdx: TPoint): TPoint; inline;
|
||||
|
||||
function IsCombiningCodePoint(const AChar: PChar): Boolean;
|
||||
function IsSpaceChar(AText: PChar): Boolean; inline;
|
||||
function CountLeadSpace(AText: PChar): integer; inline;
|
||||
function CountLeadWhiteSpace(AText: PChar): integer; inline;
|
||||
function CountBackwardWhiteSpace(AText: PChar; AStart: Integer): integer; inline;
|
||||
function CountLeadWhiteSpace(AText: PChar; out AnHasTab: boolean): integer; inline;
|
||||
@ -111,6 +114,38 @@ begin
|
||||
inc(Result.Y);
|
||||
end;
|
||||
|
||||
function IsCombiningCodePoint(const AChar: PChar): Boolean;
|
||||
begin
|
||||
Result := (
|
||||
( (AChar[0] = #$CC) ) or // Combining Diacritical Marks (belongs to previos char) 0300-036F
|
||||
( (AChar[0] = #$CD) and (AChar[1] in [#$80..#$AF]) ) or // Combining Diacritical Marks
|
||||
( (AChar[0] = #$D8) and (AChar[1] in [#$90..#$9A]) ) or // Arabic 0610 (d890)..061A (d89a)
|
||||
( (AChar[0] = #$D9) and (AChar[1] in [#$8b..#$9f, #$B0]) ) or // Arabic 064B (d98b)..065F (d99f) // 0670 (d9b0)
|
||||
( (AChar[0] = #$DB) and (AChar[1] in [#$96..#$9C, #$9F..#$A4, #$A7..#$A8, #$AA..#$AD]) ) or // Arabic 06D6 (db96).. .. ..06EA (dbaa)
|
||||
( (AChar[0] = #$E0) and (AChar[1] = #$A3) and (AChar[2] in [#$A4..#$BE]) ) or // Arabic 08E4 (e0a3a4) ..08FE (e0a3be)
|
||||
( (AChar[0] = #$E1) and (AChar[1] = #$B7) ) or // Combining Diacritical Marks Supplement 1DC0-1DFF
|
||||
( (AChar[0] = #$E2) and (AChar[1] = #$83) and (AChar[2] in [#$90..#$FF]) ) or // Combining Diacritical Marks for Symbols 20D0-20FF
|
||||
( (AChar[0] = #$EF) and (AChar[1] = #$B8) and (AChar[2] in [#$A0..#$AF]) ) // Combining half Marks FE20-FE2F
|
||||
);
|
||||
end;
|
||||
|
||||
function IsSpaceChar(AText: PChar): Boolean;
|
||||
begin
|
||||
Result := (AText^ = ' ') and not IsCombiningCodePoint(AText);
|
||||
end;
|
||||
|
||||
function CountLeadSpace(AText: PChar): integer;
|
||||
var
|
||||
Run : PChar;
|
||||
begin
|
||||
Run := AText;
|
||||
while (Run^ in [' ']) do
|
||||
Inc(Run);
|
||||
Result := Run - AText;
|
||||
if (Result > 0) and IsCombiningCodePoint(Run) then
|
||||
dec(Result);
|
||||
end;
|
||||
|
||||
function CountLeadWhiteSpace(AText: PChar): integer;
|
||||
var
|
||||
Run : PChar;
|
||||
@ -119,6 +154,8 @@ begin
|
||||
while (Run^ in [' ', #9]) do
|
||||
Inc(Run);
|
||||
Result := Run - AText;
|
||||
if (Result > 0) and IsCombiningCodePoint(Run) then
|
||||
dec(Result);
|
||||
end;
|
||||
|
||||
function CountBackwardWhiteSpace(AText: PChar; AStart: Integer): integer;
|
||||
@ -142,6 +179,8 @@ begin
|
||||
while (Run^ in [' ', #9]) do
|
||||
Inc(Run);
|
||||
Result := Run - AText;
|
||||
if (Result > 0) and IsCombiningCodePoint(Run) then
|
||||
dec(Result);
|
||||
end;
|
||||
|
||||
{* fontstyle utilities *}
|
||||
|
@ -206,7 +206,6 @@ type
|
||||
procedure UndoEditLinesDelete(LogY, ACount: Integer);
|
||||
procedure IncreaseTextChangeStamp;
|
||||
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
|
||||
function LogicPosIsCombining(const AChar: PChar): Boolean; inline;
|
||||
|
||||
function GetDisplayView: TLazSynDisplayView; override;
|
||||
|
||||
@ -979,7 +978,7 @@ begin
|
||||
#$80..#$BF:
|
||||
PWidths^ := 0;
|
||||
else
|
||||
if LogicPosIsCombining(Line) then
|
||||
if IsCombiningCodePoint(Line) then
|
||||
PWidths^ := 0
|
||||
else
|
||||
PWidths^ := 1;
|
||||
@ -1012,21 +1011,6 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
function TSynEditStringList.LogicPosIsCombining(const AChar: PChar): Boolean;
|
||||
begin
|
||||
Result := (
|
||||
( (AChar[0] = #$CC) ) or // Combining Diacritical Marks (belongs to previos char) 0300-036F
|
||||
( (AChar[0] = #$CD) and (AChar[1] in [#$80..#$AF]) ) or // Combining Diacritical Marks
|
||||
( (AChar[0] = #$D8) and (AChar[1] in [#$90..#$9A]) ) or // Arabic 0610 (d890)..061A (d89a)
|
||||
( (AChar[0] = #$D9) and (AChar[1] in [#$8b..#$9f, #$B0]) ) or // Arabic 064B (d98b)..065F (d99f) // 0670 (d9b0)
|
||||
( (AChar[0] = #$DB) and (AChar[1] in [#$96..#$9C, #$9F..#$A4, #$A7..#$A8, #$AA..#$AD]) ) or // Arabic 06D6 (db96).. .. ..06EA (dbaa)
|
||||
( (AChar[0] = #$E0) and (AChar[1] = #$A3) and (AChar[2] in [#$A4..#$BE]) ) or // Arabic 08E4 (e0a3a4) ..08FE (e0a3be)
|
||||
( (AChar[0] = #$E1) and (AChar[1] = #$B7) ) or // Combining Diacritical Marks Supplement 1DC0-1DFF
|
||||
( (AChar[0] = #$E2) and (AChar[1] = #$83) and (AChar[2] in [#$90..#$FF]) ) or // Combining Diacritical Marks for Symbols 20D0-20FF
|
||||
( (AChar[0] = #$EF) and (AChar[1] = #$B8) and (AChar[2] in [#$A0..#$AF]) ) // Combining half Marks FE20-FE2F
|
||||
);
|
||||
end;
|
||||
|
||||
function TSynEditStringList.GetDisplayView: TLazSynDisplayView;
|
||||
begin
|
||||
Result := FDisplayView;
|
||||
@ -1240,7 +1224,7 @@ begin
|
||||
while (Result < l) and (ACount > 0) do begin
|
||||
inc(Result);
|
||||
if (ALine[Result] in [#0..#127, #192..#255]) and
|
||||
( (lpStopAtCodePoint in AFlags) or (not LogicPosIsCombining(@ALine[Result])) )
|
||||
( (lpStopAtCodePoint in AFlags) or (not IsCombiningCodePoint(@ALine[Result])) )
|
||||
then
|
||||
dec(ACount);
|
||||
end;
|
||||
@ -1250,7 +1234,7 @@ begin
|
||||
if (Result <= l) then
|
||||
while (Result > 1) and
|
||||
( (not(ALine[Result] in [#0..#127, #192..#255])) or
|
||||
( (not(lpStopAtCodePoint in AFlags)) and LogicPosIsCombining(@ALine[Result]) )
|
||||
( (not(lpStopAtCodePoint in AFlags)) and IsCombiningCodePoint(@ALine[Result]) )
|
||||
)
|
||||
do
|
||||
dec(Result);
|
||||
@ -1259,7 +1243,7 @@ begin
|
||||
dec(Result);
|
||||
if (Result > l) or (Result = 1) or
|
||||
( (ALine[Result] in [#0..#127, #192..#255]) and
|
||||
( (lpStopAtCodePoint in AFlags) or (not LogicPosIsCombining(@ALine[Result])) )
|
||||
( (lpStopAtCodePoint in AFlags) or (not IsCombiningCodePoint(@ALine[Result])) )
|
||||
)
|
||||
then
|
||||
inc(ACount);
|
||||
@ -1278,7 +1262,7 @@ begin
|
||||
if Result then
|
||||
Result := (ALogicalPos = 1) or
|
||||
(lpStopAtCodePoint in AFlags) or
|
||||
(not LogicPosIsCombining(@ALine[ALogicalPos]));
|
||||
(not IsCombiningCodePoint(@ALine[ALogicalPos]));
|
||||
end;
|
||||
|
||||
function TSynEditStringList.LogicPosAdjustToChar(const ALine: String; ALogicalPos: integer;
|
||||
@ -1292,7 +1276,7 @@ begin
|
||||
while (Result <= length(ALine)) and
|
||||
( (not(ALine[Result] in [#0..#127, #192..#255])) or
|
||||
((Result <> 1) and
|
||||
(not(lpStopAtCodePoint in AFlags)) and LogicPosIsCombining(@ALine[Result])
|
||||
(not(lpStopAtCodePoint in AFlags)) and IsCombiningCodePoint(@ALine[Result])
|
||||
)
|
||||
)
|
||||
do
|
||||
@ -1305,7 +1289,7 @@ begin
|
||||
|
||||
while (Result > 1) and
|
||||
( (not(ALine[Result] in [#0..#127, #192..#255])) or
|
||||
( (not(lpStopAtCodePoint in AFlags)) and LogicPosIsCombining(@ALine[Result]) )
|
||||
( (not(lpStopAtCodePoint in AFlags)) and IsCombiningCodePoint(@ALine[Result]) )
|
||||
)
|
||||
do
|
||||
dec(Result);
|
||||
|
Loading…
Reference in New Issue
Block a user