SynEdit: more support for combining codepoints

git-svn-id: trunk@39094 -
This commit is contained in:
martin 2012-10-15 21:54:06 +00:00
parent 946e1acb17
commit caf2837329
2 changed files with 33 additions and 5 deletions

View File

@ -193,6 +193,7 @@ type
procedure UndoEditLinesDelete(LogY, ACount: Integer);
procedure IncreaseTextChangeStamp;
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
function LogicPosIsCombining(const ALine: String; ALogicalPos: integer): Boolean; inline;
function GetDisplayView: TLazSynDisplayView; override;
public
@ -858,6 +859,21 @@ begin
end;
function TSynEditStringList.LogicPosIsCombining(const ALine: String;
ALogicalPos: integer): Boolean;
begin
Result := (ALogicalPos > 1) and (
( (ALine[ALogicalPos] = #$CC) {and (ALine[ALogicalPos+1] in [#$80..#$FF])} ) or // Combining Diacritical Marks (belongs to previos char) 0300-036F
( (ALine[ALogicalPos] = #$CD) and (ALine[ALogicalPos+1] in [#$80..#$AF]) ) or // Combining Diacritical Marks
( (ALine[ALogicalPos] = #$E1) and (ALine[ALogicalPos+1] = #$B7) ) or // Combining Diacritical Marks Supplement 1DC0-1DFF
// (ALine[ALogicalPos+2] in [#$80..#$BF])
( (ALine[ALogicalPos] = #$E2) and (ALine[ALogicalPos+1] = #$83) and
(ALine[ALogicalPos+2] in [#$90..#$FF]) ) or // Combining Diacritical Marks for Symbols 20D0-20FF
( (ALine[ALogicalPos] = #$EF) and (ALine[ALogicalPos+1] = #$B8) and
(ALine[ALogicalPos+2] in [#$A0..#$AF]) ) // Combining half Marks FE20-FE2F
);
end;
function TSynEditStringList.GetDisplayView: TLazSynDisplayView;
begin
Result := FDisplayView;
@ -1051,15 +1067,17 @@ begin
if ACount > 0 then begin;
while (Result < length(ALine)) and (ACount > 0) do begin
inc(Result);
if ALine[Result] in [#0..#127, #192..#255] then
if (ALine[Result] in [#0..#127, #192..#255]) and (not LogicPosIsCombining(ALine, Result)) then
dec(ACount);
end;
while (Result > 1) and not(ALine[Result] in [#0..#127, #192..#255]) do
while (Result > 1) and
( (not(ALine[Result] in [#0..#127, #192..#255])) or LogicPosIsCombining(ALine, Result) )
do
dec(Result);
end else begin
while (Result > 1) and (ACount < 0) do begin
dec(Result);
if ALine[Result] in [#0..#127, #192..#255] then
if (ALine[Result] in [#0..#127, #192..#255]) and (not LogicPosIsCombining(ALine, Result)) then
inc(ACount);
end;
end;
@ -1072,6 +1090,9 @@ begin
Result := False;
if (ALogicalPos < 1) or (ALogicalPos > length(ALine)) then exit;
Result := ALine[ALogicalPos] in [#0..#127, #192..#255];
if Result then
Result := not LogicPosIsCombining(ALine, ALogicalPos);
end;
function TSynEditStringList.LogicPosAdjustToChar(const ALine: String; ALogicalPos: integer;
@ -1082,11 +1103,15 @@ begin
if (ALogicalPos < 1) or (ALogicalPos > length(ALine)) then exit;
if ANext then begin
while (Result < length(ALine)) and not(ALine[Result] in [#0..#127, #192..#255]) do
while (Result < length(ALine)) and
( (not(ALine[Result] in [#0..#127, #192..#255])) or LogicPosIsCombining(ALine, Result) )
do
inc(Result);
end;
while (Result > 1) and not(ALine[Result] in [#0..#127, #192..#255]) do
while (Result > 1) and
( (not(ALine[Result] in [#0..#127, #192..#255])) or LogicPosIsCombining(ALine, Result) )
do
dec(Result);
end;

View File

@ -326,6 +326,7 @@ procedure TTestSynNavigation.TestCaretLeftRight;
'abc def ü'#9'üü xyz', // 7: utf8 multibyte + tabs
'abc あdefあ123', // 8: Double withs
'abc あdef'#9'あ'#9'123', // 9: Double withs + tabs
'Aa'#$CC#$81'B', // 10: a-accent, in 2 (combining) codepoints)
''
]);
end;
@ -577,6 +578,7 @@ begin
TestLeftRight('Umlaut right', 6, 9, ecRight, 10,11, 11,13);
TestLeftRight('Double W right', 8, 5, ecRight, 7, 8, 8, 9);
TestLeftRight('combining right', 10, 2, ecRight, 3, 5, 4, 6);
TestLeftRight('at EOL right', 5, 10, ecRight, 1, 1, 2, 2, True, True, -1 , 6);
@ -618,6 +620,7 @@ begin
TestLeftRight('Umlaut left', 6, 10, ecLeft, 9, 9, 8, 8);
TestLeftRight('Double W left', 8, 7, ecLeft, 5, 5, 4, 4);
TestLeftRight('combining left', 10, 3, ecLeft, 2, 2, 1, 1);
TestLeftRight('at BOL left', 6, 1, ecLeft, 10, 8, 9, 7, True, True, -1 , 5);