This is a revised version of my synedit patch which adds support for
"doubleclick" selection of utf-8 text as well as puts all the changes in
{$IFDEF SYN_LAZARUS}.
To sum it up:
1. it inverts parsing logic to use Highlighter.WordBlockChars +
TSynWhiteChars (or TSynWordBlockChars + TSynWhiteChars if there's no
highlighter), thus allowing utf-8 words to be parsed as long as the
block chars don't contain chars > 127.
2. it fixes the doubleclick selection by said logic + fixing final caret
position based on true length of given line if UseUTF8 is true.
Ales
Index: components/synedit/synedittypes.pp
===================================================================
--- components/synedit/synedittypes.pp (revision 13890)
+++ components/synedit/synedittypes.pp (working copy)
@@ -44,6 +44,7 @@
const
TSynSpecialChars = ['À'..'Ö', 'Ø'..'ö', 'ø'..'ÿ'];
TSynValidStringChars = ['_', '0'..'9', 'A'..'Z', 'a'..'z'] + TSynSpecialChars;
+ TSynWhiteChars = [' ', #9];
TSynWordBreakChars = ['.', ',', ';', ':', '"', '''', '!', '?', '[', ']', '(',
')', '{', '}', '^', '-', '=', '+', '*', '/', '\', '|'];
Index: components/synedit/synedit.pp
===================================================================
--- components/synedit/synedit.pp (revision 13890)
+++ components/synedit/synedit.pp (working copy)
@@ -6453,9 +6453,6 @@
Runner: TPoint;
TempString: string;
IdChars: TSynIdentChars;
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- BufChars: array of PChar;
-{$ENDIF}
begin
{ Value is the position of the Carat in bytes }
Value.x := MinMax(Value.x, 1, fMaxLeftChar);
@@ -6463,53 +6460,36 @@
TempString := Lines[Value.Y - 1];
if TempString = '' then exit;
// Click on right side of text
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- UTF8ToArrayOfUTF8Char(PChar(TempString), Length(TempString), BufChars);
- if Length(BufChars) < Value.X then Value.X := Length(BufChars);
-{$ELSE}
if Length(TempString) < Value.X then Value.X := Length(TempString);
-{$ENDIF}
+
Runner := Value;
- if fHighlighter <> nil then
+ if Assigned(fHighlighter) then
+ {$IFDEF SYN_LAZARUS}
+ IdChars := [#1..#255] - (fHighlighter.WordBreakChars + TSynWhiteChars)
+ {$ELSE}
IdChars := fHighlighter.IdentChars
+ {$ENDIF}
else
+ {$IFDEF SYN_LAZARUS}
+ IDchars := [#1..#255] - (TSynWordBreakChars + TSynWhiteChars);
+ {$ELSE}
IDchars := [#33..#255];
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- if not (BufChars[Runner.X - 1]^ in IdChars) then begin
-{$ELSE}
+ {$ENDIF}
if not (TempString[Runner.X] in IdChars) then begin
-{$ENDIF}
// no word under cursor and next char right is not start of a word
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- if (Runner.X > 1) and (not (BufChars[Runner.X - 1]^ in IdChars)) then begin
-{$ELSE}
if (Runner.X > 1) and (not (TempString[Runner.X] in IdChars)) then begin
-{$ENDIF}
// find end of word on the left side
while Runner.X > 1 do begin
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- if (BufChars[Runner.X - 1]^ in IdChars) then break;
-{$ELSE}
if (TempString[Runner.X] in IdChars) then break;
-{$ENDIF}
Dec(Runner.X);
end;
end;
// no word on the left side, so look to the right side
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- if not (BufChars[Runner.X - 1]^ in IdChars) then begin
-{$ELSE}
if not (TempString[Runner.X] in IdChars) then begin
-{$ENDIF}
Runner := Value;
while (Runner.X < fMaxLeftChar)
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- {$IFDEF FPC} and (Runner.X < length(BufChars)){$ENDIF} do begin
- if (BufChars[Runner.X - 1]^ in IdChars) then break;
-{$ELSE}
{$IFDEF FPC} and (Runner.X < length(TempString)){$ENDIF} do begin
if (TempString[Runner.X] in IdChars) then break;
-{$ENDIF}
Inc(Runner.X);
end;
if Runner.X > fMaxLeftChar then
@@ -6518,11 +6498,7 @@
Value := Runner;
end;
while Runner.X > 0 do begin
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- if not (BufChars[Runner.X - 1]^ in IdChars) then break;
-{$ELSE}
if not (TempString[Runner.X] in IdChars) then break;
-{$ENDIF}
Dec(Runner.X);
end;
Inc(Runner.X);
@@ -6530,24 +6506,21 @@
fBlockBegin := Runner;
Runner := Value;
while (Runner.X < fMaxLeftChar)
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- {$IFDEF FPC} and (Runner.X <= length(BufChars)){$ENDIF} do begin
- if not (BufChars[Runner.X - 1]^ in IdChars) then break;
-{$ELSE}
{$IFDEF FPC} and (Runner.X <= length(TempString)){$ENDIF} do begin
if not (TempString[Runner.X] in IdChars) then break;
-{$ENDIF}
Inc(Runner.X);
end;
if Runner.X > fMaxLeftChar then Runner.X := fMaxLeftChar;
fBlockEnd := Runner;
// set caret to the end of selected block
CaretXY := Runner;
+ {$IFDEF SYN_LAZARUS}
+ if UseUTF8 then begin
+ CaretX := CaretX - Max(0, (Length(TempString) - UTF8Length(TempString)));
+ end;
+ {$ENDIF}
InvalidateLine(Value.Y);
StatusChanged([scSelection]);
-{$IFDEF NEW_UTF8_SETWORDBLOCK}
- FreeArrayOfUTF8Char(BufChars);
-{$ENDIF}
end;
{$ENDIF}
@@ -8776,9 +8749,19 @@
// valid line?
if (CY >= 1) and (CY <= Lines.Count) then begin
Line := Lines[CY - 1];
+
+ {$IFDEF SYN_LAZARUS}
+ if Assigned(Highlighter) then
+ CurIdentChars := [#1..#255] - (Highlighter.WordBreakChars + TSynWhiteChars)
+ else
+ CurIdentChars := [#1..#255] - (TSynWordBreakChars + TSynWhiteChars);
+ WhiteChars := TSynWhiteChars + ([#1..#255] - CurIdentChars);
+ {$ELSE}
CurIdentChars:=IdentChars;
WhiteChars := [#1..#255] - CurIdentChars;
+ {$ENDIF}
LineLen := Length(Line);
+
if CX >= LineLen then begin
// find first IdentChar in the next line
if CY < Lines.Count then begin
@@ -8827,8 +8810,17 @@
if (CY >= 1) and (CY <= Lines.Count) then begin
Line := Lines[CY - 1];
CX := Min(CX, Length(Line) + 1);
+
+ {$IFDEF SYN_LAZARUS}
+ if Assigned(Highlighter) then
+ CurIdentChars := [#1..#255] - (Highlighter.WordBreakChars + TSynWhiteChars)
+ else
+ CurIdentChars := [#1..#255] - (TSynWordBreakChars + TSynWhiteChars);
+ WhiteChars := TSynWhiteChars + ([#1..#255] - CurIdentChars);
+ {$ELSE}
CurIdentChars:=IdentChars;
WhiteChars := [#1..#255] - CurIdentChars;
+ {$ENDIF}
//DebugLn(['TCustomSynEdit.PrevWordPos Line="',dbgstr(Line),'" CX=',CX]);
if CX <= 1 then begin
// find last IdentChar in the previous line
@@ -10718,10 +10710,17 @@
Line := Lines[XY.Y - 1];
Len := Length(Line);
if (XY.X >= 1) and (XY.X <= Len + 1) then begin
+ {$IFDEF SYN_LAZARUS}
if Assigned(Highlighter) then
+ IdChars := [#1..#255] - (Highlighter.WordBreakChars + TSynWhiteChars)
+ else
+ IdChars := [#1..#255] - (TSynWordBreakChars + TSynWhiteChars);
+ {$ELSE}
+ if Assigned(Highlighter) then
IdChars := Highlighter.IdentChars
else
IdChars := ['a'..'z', 'A'..'Z'];
+ {$ENDIF}
EndX := XY.X;
while (EndX <= Len) and (Line[EndX] in IdChars) do
Inc(EndX);
@@ -10918,10 +10917,17 @@
Line := Lines[XY.Y - 1];
Len := Length(Line);
if (XY.X >= 1) and (XY.X <= Len + 1) then begin
+ {$IFDEF SYN_LAZARUS}
if Assigned(Highlighter) then
+ IdChars := [#1..#255] - (Highlighter.WordBreakChars + TSynWhiteChars)
+ else
+ IdChars := [#1..#255] - (TSynWordBreakChars + TSynWhiteChars);
+ {$ELSE}
+ if Assigned(Highlighter) then
IdChars := Highlighter.IdentChars
else
IdChars := ['a'..'z', 'A'..'Z'];
+ {$ENDIF}
Stop := XY.X;
while (Stop <= Len) and (Line[Stop] in IdChars) do
Inc(Stop);