mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-22 06:30:40 +01:00
SynEdit, Refactor: Changed Phys/Logical Conversation (tabs, utf8)
git-svn-id: trunk@18603 -
This commit is contained in:
parent
dd08096ff5
commit
01e79b4d74
@ -68,7 +68,7 @@ begin
|
|||||||
Inc(Result);
|
Inc(Result);
|
||||||
end;
|
end;
|
||||||
if Physical and (Result>0) then
|
if Physical and (Result>0) then
|
||||||
Result := TSynEdit(Editor).LogicalToPhysicalCol(Line, Result+1)-1;
|
Result := TSynEdit(Editor).LogicalToPhysicalCol(Line, -1, Result+1)-1; // TODO, Need the real index of the line
|
||||||
end else
|
end else
|
||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
end;
|
||||||
@ -98,7 +98,7 @@ begin
|
|||||||
if SpaceCount2 = SpaceCount1 then
|
if SpaceCount2 = SpaceCount1 then
|
||||||
SpaceCount2 := 0;
|
SpaceCount2 := 0;
|
||||||
// remove visible spaces
|
// remove visible spaces
|
||||||
LogSpacePos := TSynEdit(Editor).PhysicalToLogicalCol(Line, SpaceCount2 + 1);
|
LogSpacePos := TSynEdit(Editor).PhysicalToLogicalCol(Line, PhysCaret.y-1, SpaceCount2 + 1);
|
||||||
CaretNewX := SpaceCount2 + 1;
|
CaretNewX := SpaceCount2 + 1;
|
||||||
DelChars := copy(Line, LogSpacePos, PhysCaret.X - LogSpacePos);
|
DelChars := copy(Line, LogSpacePos, PhysCaret.X - LogSpacePos);
|
||||||
InsChars := ''; // TODO: if tabs were removed, maybe fill-up with spaces
|
InsChars := ''; // TODO: if tabs were removed, maybe fill-up with spaces
|
||||||
@ -132,7 +132,8 @@ begin
|
|||||||
sbitSpace:
|
sbitSpace:
|
||||||
InsChars := StringOfChar(' ', SpaceCount2);
|
InsChars := StringOfChar(' ', SpaceCount2);
|
||||||
sbitCopySpaceTab:
|
sbitCopySpaceTab:
|
||||||
InsChars := copy(Temp, 1, TSynEdit(Editor).PhysicalToLogicalCol(Temp, SpaceCount2+1)-1);
|
InsChars := copy(Temp, 1, TSynEdit(Editor).PhysicalToLogicalCol(Temp,
|
||||||
|
BackCounter, SpaceCount2+1)-1);
|
||||||
sbitPositionCaret:
|
sbitPositionCaret:
|
||||||
if Line <> '' then
|
if Line <> '' then
|
||||||
InsChars := StringOfChar(' ', SpaceCount2)
|
InsChars := StringOfChar(' ', SpaceCount2)
|
||||||
@ -140,7 +141,7 @@ begin
|
|||||||
InsChars := '';
|
InsChars := '';
|
||||||
end;
|
end;
|
||||||
Result := InsChars + Line;
|
Result := InsChars + Line;
|
||||||
CaretNewX := TSynEdit(Editor).LogicalToPhysicalCol(Result, SpaceCount2+1);
|
CaretNewX := TSynEdit(Editor).LogicalToPhysicalCol(Result, PhysCaret.y - 1, SpaceCount2+1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynBeautifier.GetIndentForLine(Editor: TSynEditBase; const Line: string; const PhysCaret: TPoint): Integer;
|
function TSynBeautifier.GetIndentForLine(Editor: TSynEditBase; const Line: string; const PhysCaret: TPoint): Integer;
|
||||||
|
|||||||
@ -471,7 +471,6 @@ type
|
|||||||
function GetLineText: string;
|
function GetLineText: string;
|
||||||
{$IFDEF SYN_LAZARUS}
|
{$IFDEF SYN_LAZARUS}
|
||||||
function GetCharLen(const Line: string; CharStartPos: integer): integer;
|
function GetCharLen(const Line: string; CharStartPos: integer): integer;
|
||||||
function AdjustPhysPosToCharacterStart(Line: integer; PhysPos: integer): integer;
|
|
||||||
function GetLogicalCaretXY: TPoint;
|
function GetLogicalCaretXY: TPoint;
|
||||||
procedure SetCFDividerDrawLevel(const AValue: Integer);
|
procedure SetCFDividerDrawLevel(const AValue: Integer);
|
||||||
function GetCFDividerDrawLevel : Integer;
|
function GetCFDividerDrawLevel : Integer;
|
||||||
@ -756,18 +755,13 @@ type
|
|||||||
{$IFDEF SYN_LAZARUS}
|
{$IFDEF SYN_LAZARUS}
|
||||||
// Byte to Char
|
// Byte to Char
|
||||||
function LogicalToPhysicalPos(const p: TPoint): TPoint;
|
function LogicalToPhysicalPos(const p: TPoint): TPoint;
|
||||||
function LogicalToPhysicalCol(const Line: string;
|
function LogicalToPhysicalCol(const Line: String; Index, LogicalPos
|
||||||
LogicalPos: integer): integer;
|
: integer): integer;
|
||||||
function LogicalToPhysicalCol(Line: PChar; LineLen: integer;
|
|
||||||
LogicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
// Char to Byte
|
// Char to Byte
|
||||||
function PhysicalToLogicalPos(const p: TPoint): TPoint;
|
function PhysicalToLogicalPos(const p: TPoint): TPoint;
|
||||||
function PhysicalToLogicalCol(const Line: string;
|
function PhysicalToLogicalCol(const Line: string;
|
||||||
PhysicalPos: integer): integer;
|
Index, PhysicalPos: integer): integer;
|
||||||
function PhysicalToLogicalCol(const Line: string;
|
function PhysicalLineLength(Line: String; Index: integer): integer;
|
||||||
PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
function PhysicalLineLength(Line: PChar; LineLen: integer;
|
|
||||||
WithTabs: boolean): integer;
|
|
||||||
function ScreenColumnToXValue(Col: integer): integer; // map screen column to screen pixel
|
function ScreenColumnToXValue(Col: integer): integer; // map screen column to screen pixel
|
||||||
procedure MoveCaretToVisibleArea;
|
procedure MoveCaretToVisibleArea;
|
||||||
procedure MoveCaretIgnoreEOL(const NewCaret: TPoint);
|
procedure MoveCaretIgnoreEOL(const NewCaret: TPoint);
|
||||||
@ -1817,22 +1811,6 @@ begin
|
|||||||
Result:=1;
|
Result:=1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomSynEdit.AdjustPhysPosToCharacterStart(Line: integer;
|
|
||||||
PhysPos: integer): integer;
|
|
||||||
var
|
|
||||||
s: string;
|
|
||||||
BytePos: LongInt;
|
|
||||||
begin
|
|
||||||
Result:=PhysPos;
|
|
||||||
if Result<1 then
|
|
||||||
Result:=1
|
|
||||||
else if (Line>=1) and (Line<=FTheLinesView.Count) then begin
|
|
||||||
s:=FTheLinesView[Line-1];
|
|
||||||
BytePos:=PhysicalToLogicalCol(s,Result);
|
|
||||||
Result:=LogicalToPhysicalCol(s,BytePos);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCustomSynEdit.GetLogicalCaretXY: TPoint;
|
function TCustomSynEdit.GetLogicalCaretXY: TPoint;
|
||||||
begin
|
begin
|
||||||
Result:=PhysicalToLogicalPos(CaretXY);
|
Result:=PhysicalToLogicalPos(CaretXY);
|
||||||
@ -3685,7 +3663,7 @@ begin
|
|||||||
if not (eoScrollPastEol in fOptions) then begin
|
if not (eoScrollPastEol in fOptions) then begin
|
||||||
{$IFDEF SYN_LAZARUS}
|
{$IFDEF SYN_LAZARUS}
|
||||||
Line:=FTheLinesView[Value.Y-1];
|
Line:=FTheLinesView[Value.Y-1];
|
||||||
nMaxX := PhysicalLineLength(PChar(Line),length(Line),true)+1;
|
nMaxX := PhysicalLineLength(Line, Value.Y-1) + 1;
|
||||||
{$ELSE}
|
{$ELSE}
|
||||||
nMaxX := Length(FTheLinesView[Value.Y - 1]) + 1; //abc 2000-09-30
|
nMaxX := Length(FTheLinesView[Value.Y - 1]) + 1; //abc 2000-09-30
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -6158,12 +6136,8 @@ begin
|
|||||||
// join this line with the last line if possible
|
// join this line with the last line if possible
|
||||||
if CaretY > 1 then begin
|
if CaretY > 1 then begin
|
||||||
CaretY := CaretY - 1;
|
CaretY := CaretY - 1;
|
||||||
{$IFDEF SYN_LAZARUS}
|
CaretX := PhysicalLineLength(FTheLinesView[CaretY - 1],
|
||||||
CaretX := LogicalToPhysicalCol(FTheLinesView[CaretY - 1],
|
CaretY - 1) + 1;
|
||||||
Length(FTheLinesView[CaretY - 1]) + 1);
|
|
||||||
{$ELSE}
|
|
||||||
CaretX := Length(Lines[CaretY - 1]) + 1;
|
|
||||||
{$ENDIF}
|
|
||||||
FTheLinesView.Delete(CaretY);
|
FTheLinesView.Delete(CaretY);
|
||||||
DoLinesDeleted(CaretY, 1);
|
DoLinesDeleted(CaretY, 1);
|
||||||
{$IFNDEF SYN_LAZARUS}
|
{$IFNDEF SYN_LAZARUS}
|
||||||
@ -6194,9 +6168,9 @@ begin
|
|||||||
Helper := Copy(Temp, CaretX, counter);
|
Helper := Copy(Temp, CaretX, counter);
|
||||||
VDelete(Temp, CaretX, counter, drLTR);
|
VDelete(Temp, CaretX, counter, drLTR);
|
||||||
{$ELSE USE_UTF8BIDI_LCL}
|
{$ELSE USE_UTF8BIDI_LCL}
|
||||||
LogCaretXY.X:=PhysicalToLogicalCol(Temp,CaretX-counter);
|
LogCaretXY.X:=PhysicalToLogicalCol(Temp, CaretY-1, CaretX-counter);
|
||||||
LogCounter:=GetCharLen(Temp,LogCaretXY.X);
|
LogCounter:=GetCharLen(Temp,LogCaretXY.X);
|
||||||
CaretX := LogicalToPhysicalCol(Temp,LogCaretXY.X);
|
CaretX := LogicalToPhysicalCol(Temp, CaretY-1, LogCaretXY.X);
|
||||||
Helper := Copy(Temp, LogCaretXY.X, LogCounter);
|
Helper := Copy(Temp, LogCaretXY.X, LogCounter);
|
||||||
System.Delete(Temp, LogCaretXY.X, LogCounter);
|
System.Delete(Temp, LogCaretXY.X, LogCounter);
|
||||||
//debugln('ecDeleteLastChar delete char CaretX=',dbgs(CaretX),
|
//debugln('ecDeleteLastChar delete char CaretX=',dbgs(CaretX),
|
||||||
@ -6263,7 +6237,7 @@ begin
|
|||||||
{$IFDEF SYN_LAZARUS}
|
{$IFDEF SYN_LAZARUS}
|
||||||
Counter:=GetCharLen(Temp,LogCaretXY.X);
|
Counter:=GetCharLen(Temp,LogCaretXY.X);
|
||||||
Helper := Copy(Temp, LogCaretXY.X, Counter);
|
Helper := Copy(Temp, LogCaretXY.X, Counter);
|
||||||
Caret.X := LogicalToPhysicalCol(Temp,LogCaretXY.X+Counter);
|
Caret.X := LogicalToPhysicalCol(Temp, CaretY-1, LogCaretXY.X+Counter);
|
||||||
Caret.Y := CaretY;
|
Caret.Y := CaretY;
|
||||||
{$IFDEF USE_UTF8BIDI_LCL}
|
{$IFDEF USE_UTF8BIDI_LCL}
|
||||||
VDelete(Temp, LogCaretXY.X, Counter, drLTR);
|
VDelete(Temp, LogCaretXY.X, Counter, drLTR);
|
||||||
@ -6307,7 +6281,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
ecDeleteWord, ecDeleteEOL:
|
ecDeleteWord, ecDeleteEOL:
|
||||||
if not ReadOnly then begin
|
if not ReadOnly then begin
|
||||||
Len := LogicalToPhysicalCol(LineText,Length(LineText)+1)-1;
|
Len := LogicalToPhysicalCol(LineText, CaretY-1,Length(LineText)+1)-1;
|
||||||
Helper := '';
|
Helper := '';
|
||||||
Caret := CaretXY;
|
Caret := CaretXY;
|
||||||
if Command = ecDeleteWord then begin
|
if Command = ecDeleteWord then begin
|
||||||
@ -8114,17 +8088,17 @@ begin
|
|||||||
Dec(iLine);
|
Dec(iLine);
|
||||||
if iLine < 0 then break;
|
if iLine < 0 then break;
|
||||||
PrevLine := FTheLinesView[iLine];
|
PrevLine := FTheLinesView[iLine];
|
||||||
until PhysicalLineLength(PChar(PrevLine),length(PrevLine),true) > OldCaretX - 1;
|
until PhysicalLineLength(PrevLine, iLine) > OldCaretX - 1;
|
||||||
|
|
||||||
if iLine >= 0 then begin
|
if iLine >= 0 then begin
|
||||||
p := @PrevLine[PhysicalToLogicalCol(PrevLine,OldCaretX)];
|
p := @PrevLine[PhysicalToLogicalCol(PrevLine, iLine, OldCaretX)];
|
||||||
// scan over non-whitespaces
|
// scan over non-whitespaces
|
||||||
while not (p^ in [#0, #9, #32]) do
|
while not (p^ in [#0, #9, #32]) do
|
||||||
inc(p);
|
inc(p);
|
||||||
// scan over whitespaces
|
// scan over whitespaces
|
||||||
while (p^ in [#9, #32]) do
|
while (p^ in [#9, #32]) do
|
||||||
inc(p);
|
inc(p);
|
||||||
i := LogicalToPhysicalCol(PrevLine, p-@PrevLine[1]+1) - CaretX;
|
i := LogicalToPhysicalCol(PrevLine, iLine, p-@PrevLine[1]+1) - CaretX;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -9304,28 +9278,18 @@ end;
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
{$IFDEF SYN_LAZARUS}
|
||||||
function TCustomSynEdit.LogicalToPhysicalCol(const Line: string;
|
function TCustomSynEdit.LogicalToPhysicalCol(const Line: String;
|
||||||
LogicalPos: integer): integer;
|
Index, LogicalPos: integer): integer;
|
||||||
|
// LogicalPos is 1-based
|
||||||
|
// Index 0-based LineNumber
|
||||||
begin
|
begin
|
||||||
Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(PChar(Pointer(Line)),
|
Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(Line, Index,
|
||||||
length(Line),LogicalPos,1,1);
|
LogicalPos);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomSynEdit.LogicalToPhysicalCol(Line: PChar; LineLen: integer;
|
function TCustomSynEdit.PhysicalLineLength(Line: String; Index: integer): integer;
|
||||||
LogicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
// Note: LogicalPos, StartBytePos, StartPhysicalPos start at 1
|
|
||||||
begin
|
begin
|
||||||
Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(Line, LineLen, LogicalPos,
|
Result:=LogicalToPhysicalCol(Line, Index, length(Line)+1) - 1
|
||||||
StartBytePos, StartPhysicalPos);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCustomSynEdit.PhysicalLineLength(Line: PChar; LineLen: integer;
|
|
||||||
WithTabs: boolean): integer;
|
|
||||||
begin
|
|
||||||
if WithTabs then
|
|
||||||
Result:=LogicalToPhysicalCol(Line,LineLen,LineLen+1,1,1)-1
|
|
||||||
else
|
|
||||||
Result:=UTF8Length(Line,LineLen);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomSynEdit.PhysicalToLogicalPos(const p: TPoint): TPoint;
|
function TCustomSynEdit.PhysicalToLogicalPos(const p: TPoint): TPoint;
|
||||||
@ -9334,16 +9298,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomSynEdit.PhysicalToLogicalCol(const Line: string;
|
function TCustomSynEdit.PhysicalToLogicalCol(const Line: string;
|
||||||
PhysicalPos: integer): integer;
|
Index, PhysicalPos: integer): integer;
|
||||||
begin
|
begin
|
||||||
Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line,PhysicalPos,1,1);
|
Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line, Index,
|
||||||
end;
|
PhysicalPos);
|
||||||
|
|
||||||
function TCustomSynEdit.PhysicalToLogicalCol(const Line: string;
|
|
||||||
PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
begin
|
|
||||||
Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line, PhysicalPos,
|
|
||||||
StartBytePos, StartPhysicalPos);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomSynEdit.ScreenColumnToXValue(Col : integer) : integer;
|
function TCustomSynEdit.ScreenColumnToXValue(Col : integer) : integer;
|
||||||
|
|||||||
@ -71,41 +71,6 @@ function GetIntArray(Count: Cardinal; InitialValue: integer): PIntArray;
|
|||||||
|
|
||||||
procedure InternalFillRect(dc: HDC; const rcPaint: TRect);
|
procedure InternalFillRect(dc: HDC; const rcPaint: TRect);
|
||||||
|
|
||||||
// Converting tabs to spaces: To use the function several times it's better
|
|
||||||
// to use a function pointer that is set to the fastest conversion function.
|
|
||||||
type
|
|
||||||
TConvertTabsProc = function(const Line: AnsiString;
|
|
||||||
TabWidth: integer): AnsiString;
|
|
||||||
|
|
||||||
function GetBestConvertTabsProc(TabWidth: integer): TConvertTabsProc;
|
|
||||||
// This is the slowest conversion function which can handle TabWidth <> 2^n.
|
|
||||||
function ConvertTabs(const Line: AnsiString; TabWidth: integer): AnsiString;
|
|
||||||
|
|
||||||
{begin} //mh 2000-10-19
|
|
||||||
type
|
|
||||||
TConvertTabsProcEx = function(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): AnsiString;
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
TSimulateConvertTabsProcEx = function(const Line: AnsiString;
|
|
||||||
TabWidth: integer; out HasTabs: boolean): integer;
|
|
||||||
// returns length of converted string
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
function GetBestConvertTabsProcEx(TabWidth: integer): TConvertTabsProcEx;
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function GetBestSimulateConvertTabsProcEx(
|
|
||||||
TabWidth:integer): TSimulateConvertTabsProcEx;
|
|
||||||
{$ENDIF}
|
|
||||||
// This is the slowest conversion function which can handle TabWidth <> 2^n.
|
|
||||||
function ConvertTabsEx(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): AnsiString;
|
|
||||||
{end} //mh 2000-10-19
|
|
||||||
|
|
||||||
function CharIndex2CaretPos(Index, TabWidth: integer;
|
|
||||||
const Line: string): integer;
|
|
||||||
function CaretPos2CharIndex(Position, TabWidth: integer; const Line: string;
|
|
||||||
var InsideTabChar: boolean): integer;
|
|
||||||
|
|
||||||
// search for the first char of set AChars in Line, starting at index Start
|
// search for the first char of set AChars in Line, starting at index Start
|
||||||
function StrScanForCharInSet(const Line: string; Start: integer;
|
function StrScanForCharInSet(const Line: string; Start: integer;
|
||||||
AChars: TSynIdentChars): integer;
|
AChars: TSynIdentChars): integer;
|
||||||
@ -238,391 +203,6 @@ end;
|
|||||||
|
|
||||||
{***}
|
{***}
|
||||||
|
|
||||||
// mh: Please don't change; no stack frame and efficient register use.
|
|
||||||
function GetHasTabs(pLine: PChar; out CharsBefore: integer): boolean;
|
|
||||||
begin
|
|
||||||
CharsBefore := 0;
|
|
||||||
if Assigned(pLine) then begin
|
|
||||||
while (pLine^ <> #0) do begin
|
|
||||||
if (pLine^ = #9) then break;
|
|
||||||
Inc(CharsBefore);
|
|
||||||
Inc(pLine);
|
|
||||||
end;
|
|
||||||
Result := (pLine^ = #9);
|
|
||||||
end else
|
|
||||||
Result := FALSE;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function StringHasTabs(const Line: string; out CharsBefore: integer): boolean;
|
|
||||||
var LineLen: integer;
|
|
||||||
begin
|
|
||||||
LineLen:=length(Line);
|
|
||||||
CharsBefore := 1;
|
|
||||||
while (CharsBefore<=LineLen) and (Line[CharsBefore]<>#9) do
|
|
||||||
inc(CharsBefore);
|
|
||||||
Result:=CharsBefore<=LineLen;
|
|
||||||
dec(CharsBefore);
|
|
||||||
end;
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
{begin} //mh 2000-10-19
|
|
||||||
function ConvertTabs1Ex(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): AnsiString;
|
|
||||||
var
|
|
||||||
pDest: PChar;
|
|
||||||
nBeforeTab: integer;
|
|
||||||
begin
|
|
||||||
Result := Line; // increment reference count only
|
|
||||||
if GetHasTabs(pointer(Line), nBeforeTab) then begin
|
|
||||||
HasTabs := TRUE; //mh 2000-11-08
|
|
||||||
pDest := @Result[nBeforeTab + 1]; // this will make a copy of Line
|
|
||||||
// We have at least one tab in the string, and the tab width is 1.
|
|
||||||
// pDest points to the first tab char. We overwrite all tabs with spaces.
|
|
||||||
repeat
|
|
||||||
if (pDest^ = #9) then pDest^ := ' ';
|
|
||||||
Inc(pDest);
|
|
||||||
until (pDest^ = #0);
|
|
||||||
end else
|
|
||||||
HasTabs := FALSE;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function SimulateConvertTabs1Ex(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): integer;
|
|
||||||
// TabWidth=1
|
|
||||||
var
|
|
||||||
i: integer;
|
|
||||||
begin
|
|
||||||
Result:=length(Line);
|
|
||||||
i:=1;
|
|
||||||
while (i<=Result) and (Line[i]<>#9) do inc(i);
|
|
||||||
HasTabs:=(i<=Result);
|
|
||||||
end;
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
function ConvertTabs1(const Line: AnsiString; TabWidth: integer): AnsiString;
|
|
||||||
var
|
|
||||||
HasTabs: boolean;
|
|
||||||
begin
|
|
||||||
Result := ConvertTabs1Ex(Line, TabWidth, HasTabs);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function ConvertTabs2nEx(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): AnsiString;
|
|
||||||
var
|
|
||||||
i, DestLen, TabCount, TabMask: integer;
|
|
||||||
pSrc, pDest: PChar;
|
|
||||||
begin
|
|
||||||
Result := Line; // increment reference count only
|
|
||||||
if GetHasTabs(pointer(Line), DestLen) then begin
|
|
||||||
HasTabs := TRUE; //mh 2000-11-08
|
|
||||||
pSrc := @Line[1 + DestLen];
|
|
||||||
// We have at least one tab in the string, and the tab width equals 2^n.
|
|
||||||
// pSrc points to the first tab char in Line. We get the number of tabs
|
|
||||||
// and the length of the expanded string now.
|
|
||||||
TabCount := 0;
|
|
||||||
TabMask := (TabWidth - 1) xor $7FFFFFFF;
|
|
||||||
repeat
|
|
||||||
if (pSrc^ = #9) then begin
|
|
||||||
DestLen := (DestLen + TabWidth) and TabMask;
|
|
||||||
Inc(TabCount);
|
|
||||||
end else
|
|
||||||
Inc(DestLen);
|
|
||||||
Inc(pSrc);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
// Set the length of the expanded string.
|
|
||||||
SetLength(Result, DestLen);
|
|
||||||
DestLen := 0;
|
|
||||||
pSrc := PChar(Line);
|
|
||||||
pDest := PChar(Result);
|
|
||||||
// We use another TabMask here to get the difference to 2^n.
|
|
||||||
TabMask := TabWidth - 1;
|
|
||||||
repeat
|
|
||||||
if (pSrc^ = #9) then begin
|
|
||||||
i := TabWidth - (DestLen and TabMask);
|
|
||||||
Inc(DestLen, i);
|
|
||||||
repeat
|
|
||||||
pDest^ := ' ';
|
|
||||||
Inc(pDest);
|
|
||||||
Dec(i);
|
|
||||||
until (i = 0);
|
|
||||||
Dec(TabCount);
|
|
||||||
if (TabCount = 0) then begin
|
|
||||||
repeat
|
|
||||||
Inc(pSrc);
|
|
||||||
pDest^ := pSrc^;
|
|
||||||
Inc(pDest);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
pDest^ := pSrc^;
|
|
||||||
Inc(pDest);
|
|
||||||
Inc(DestLen);
|
|
||||||
end;
|
|
||||||
Inc(pSrc);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
end else
|
|
||||||
HasTabs := FALSE;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function SimulateConvertTabs2nEx(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): integer;
|
|
||||||
var
|
|
||||||
LineLen, DestLen, SrcPos, TabMask: integer;
|
|
||||||
begin
|
|
||||||
LineLen:=length(Line);
|
|
||||||
if StringHasTabs(Line, DestLen) then begin
|
|
||||||
HasTabs := TRUE;
|
|
||||||
SrcPos:=DestLen+1;
|
|
||||||
// We have at least one tab in the string, and the tab width equals 2^n.
|
|
||||||
// pSrc points to the first tab char in Line. We get the number of tabs
|
|
||||||
// and the length of the expanded string now.
|
|
||||||
TabMask := (TabWidth - 1) xor $7FFFFFFF;
|
|
||||||
repeat
|
|
||||||
if (Line[SrcPos] = #9) then
|
|
||||||
DestLen := (DestLen + TabWidth) and TabMask
|
|
||||||
else
|
|
||||||
Inc(DestLen);
|
|
||||||
Inc(SrcPos);
|
|
||||||
until (SrcPos>LineLen);
|
|
||||||
Result:=DestLen;
|
|
||||||
end else begin
|
|
||||||
Result := LineLen;
|
|
||||||
HasTabs := FALSE;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
function ConvertTabs2n(const Line: AnsiString; TabWidth: integer): AnsiString;
|
|
||||||
var
|
|
||||||
HasTabs: boolean;
|
|
||||||
begin
|
|
||||||
Result := ConvertTabs2nEx(Line, TabWidth, HasTabs);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function ConvertTabsEx(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): AnsiString;
|
|
||||||
var
|
|
||||||
i, DestLen, TabCount: integer;
|
|
||||||
pSrc, pDest: PChar;
|
|
||||||
begin
|
|
||||||
Result := Line; // increment reference count only
|
|
||||||
if GetHasTabs(pointer(Line), DestLen) then begin
|
|
||||||
HasTabs := TRUE; //mh 2000-11-08
|
|
||||||
pSrc := @Line[1 + DestLen];
|
|
||||||
// We have at least one tab in the string, and the tab width is greater
|
|
||||||
// than 1. pSrc points to the first tab char in Line. We get the number
|
|
||||||
// of tabs and the length of the expanded string now.
|
|
||||||
TabCount := 0;
|
|
||||||
repeat
|
|
||||||
if (pSrc^ = #9) then begin
|
|
||||||
DestLen := DestLen + TabWidth - DestLen mod TabWidth;
|
|
||||||
Inc(TabCount);
|
|
||||||
end else
|
|
||||||
Inc(DestLen);
|
|
||||||
Inc(pSrc);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
// Set the length of the expanded string.
|
|
||||||
SetLength(Result, DestLen);
|
|
||||||
DestLen := 0;
|
|
||||||
pSrc := PChar(Line);
|
|
||||||
pDest := PChar(Result);
|
|
||||||
repeat
|
|
||||||
if (pSrc^ = #9) then begin
|
|
||||||
i := TabWidth - (DestLen mod TabWidth);
|
|
||||||
Inc(DestLen, i);
|
|
||||||
repeat
|
|
||||||
pDest^ := ' ';
|
|
||||||
Inc(pDest);
|
|
||||||
Dec(i);
|
|
||||||
until (i = 0);
|
|
||||||
Dec(TabCount);
|
|
||||||
if (TabCount = 0) then begin
|
|
||||||
repeat
|
|
||||||
Inc(pSrc);
|
|
||||||
pDest^ := pSrc^;
|
|
||||||
Inc(pDest);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
pDest^ := pSrc^;
|
|
||||||
Inc(pDest);
|
|
||||||
Inc(DestLen);
|
|
||||||
end;
|
|
||||||
Inc(pSrc);
|
|
||||||
until (pSrc^ = #0);
|
|
||||||
end else
|
|
||||||
HasTabs := FALSE;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function SimulateConvertTabsEx(const Line: AnsiString; TabWidth: integer;
|
|
||||||
out HasTabs: boolean): integer;
|
|
||||||
var
|
|
||||||
LineLen, DestLen, SrcPos: integer;
|
|
||||||
begin
|
|
||||||
LineLen:=length(Line);
|
|
||||||
if StringHasTabs(Line, DestLen) then begin
|
|
||||||
HasTabs := TRUE;
|
|
||||||
SrcPos := DestLen+1;
|
|
||||||
// We have at least one tab in the string, and the tab width is greater
|
|
||||||
// than 1. pSrc points to the first tab char in Line. We get the number
|
|
||||||
// of tabs and the length of the expanded string now.
|
|
||||||
repeat
|
|
||||||
if (Line[SrcPos] = #9) then
|
|
||||||
DestLen := DestLen + TabWidth - DestLen mod TabWidth
|
|
||||||
else
|
|
||||||
Inc(DestLen);
|
|
||||||
Inc(SrcPos);
|
|
||||||
until (SrcPos > LineLen);
|
|
||||||
Result:=DestLen;
|
|
||||||
end else begin
|
|
||||||
Result:=LineLen;
|
|
||||||
HasTabs := FALSE;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
function ConvertTabs(const Line: AnsiString; TabWidth: integer): AnsiString;
|
|
||||||
var
|
|
||||||
HasTabs: boolean;
|
|
||||||
begin
|
|
||||||
Result := ConvertTabsEx(Line, TabWidth, HasTabs);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function IsPowerOfTwo(TabWidth: integer): boolean;
|
|
||||||
var
|
|
||||||
nW: integer;
|
|
||||||
begin
|
|
||||||
nW := 2;
|
|
||||||
repeat
|
|
||||||
if (nW >= TabWidth) then break;
|
|
||||||
Inc(nW, nW);
|
|
||||||
until (nW >= $10000); // we don't want 64 kByte spaces...
|
|
||||||
Result := (nW = TabWidth);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function GetBestConvertTabsProc(TabWidth: integer): TConvertTabsProc;
|
|
||||||
begin
|
|
||||||
if (TabWidth < 2) then Result := TConvertTabsProc(@ConvertTabs1)
|
|
||||||
else if IsPowerOfTwo(TabWidth) then
|
|
||||||
Result := TConvertTabsProc(@ConvertTabs2n)
|
|
||||||
else
|
|
||||||
Result := TConvertTabsProc(@ConvertTabs);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function GetBestConvertTabsProcEx(TabWidth: integer): TConvertTabsProcEx;
|
|
||||||
begin
|
|
||||||
if (TabWidth < 2) then
|
|
||||||
Result := TConvertTabsProcEx(@ConvertTabs1Ex)
|
|
||||||
else if IsPowerOfTwo(TabWidth) then
|
|
||||||
Result := TConvertTabsProcEx(@ConvertTabs2nEx)
|
|
||||||
else
|
|
||||||
Result := TConvertTabsProcEx(@ConvertTabsEx);
|
|
||||||
end;
|
|
||||||
{end} //mh 2000-10-19
|
|
||||||
|
|
||||||
{$IFDEF SYN_LAZARUS}
|
|
||||||
function GetBestSimulateConvertTabsProcEx(
|
|
||||||
TabWidth:integer): TSimulateConvertTabsProcEx;
|
|
||||||
begin
|
|
||||||
if (TabWidth < 2) then Result :=
|
|
||||||
TSimulateConvertTabsProcEx(@SimulateConvertTabs1Ex)
|
|
||||||
else if IsPowerOfTwo(TabWidth) then
|
|
||||||
Result := TSimulateConvertTabsProcEx(@SimulateConvertTabs2nEx)
|
|
||||||
else
|
|
||||||
Result := TSimulateConvertTabsProcEx(@SimulateConvertTabsEx);
|
|
||||||
end;
|
|
||||||
{$ENDIF}
|
|
||||||
|
|
||||||
{***}
|
|
||||||
|
|
||||||
function CharIndex2CaretPos(Index, TabWidth: integer;
|
|
||||||
const Line: string): integer;
|
|
||||||
var
|
|
||||||
iChar: integer;
|
|
||||||
pNext: PChar;
|
|
||||||
begin
|
|
||||||
// possible sanity check here: Index := Max(Index, Length(Line));
|
|
||||||
if Index > 1 then begin
|
|
||||||
if (TabWidth <= 1) or not GetHasTabs(pointer(Line), iChar) then
|
|
||||||
Result := Index
|
|
||||||
else begin
|
|
||||||
if iChar + 1 >= Index then
|
|
||||||
Result := Index
|
|
||||||
else begin
|
|
||||||
// iChar is number of chars before first #9
|
|
||||||
Result := iChar;
|
|
||||||
// Index is *not* zero-based
|
|
||||||
Inc(iChar);
|
|
||||||
Dec(Index, iChar);
|
|
||||||
pNext := @Line[iChar];
|
|
||||||
while Index > 0 do begin
|
|
||||||
case pNext^ of
|
|
||||||
#0: break;
|
|
||||||
#9: begin
|
|
||||||
// Result is still zero-based
|
|
||||||
Inc(Result, TabWidth);
|
|
||||||
Dec(Result, Result mod TabWidth);
|
|
||||||
end;
|
|
||||||
else Inc(Result);
|
|
||||||
end;
|
|
||||||
Dec(Index);
|
|
||||||
Inc(pNext);
|
|
||||||
end;
|
|
||||||
// done with zero-based computation
|
|
||||||
Inc(Result);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
Result := 1;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function CaretPos2CharIndex(Position, TabWidth: integer; const Line: string;
|
|
||||||
var InsideTabChar: boolean): integer;
|
|
||||||
var
|
|
||||||
iPos: integer;
|
|
||||||
pNext: PChar;
|
|
||||||
begin
|
|
||||||
InsideTabChar := FALSE;
|
|
||||||
if Position > 1 then begin
|
|
||||||
if (TabWidth <= 1) or not GetHasTabs(pointer(Line), iPos) then
|
|
||||||
Result := Position
|
|
||||||
else begin
|
|
||||||
if iPos + 1 >= Position then
|
|
||||||
Result := Position
|
|
||||||
else begin
|
|
||||||
// iPos is number of chars before first #9
|
|
||||||
Result := iPos + 1;
|
|
||||||
pNext := @Line[Result];
|
|
||||||
// for easier computation go zero-based (mod-operation)
|
|
||||||
Dec(Position);
|
|
||||||
while iPos < Position do begin
|
|
||||||
case pNext^ of
|
|
||||||
#0: break;
|
|
||||||
#9: begin
|
|
||||||
Inc(iPos, TabWidth);
|
|
||||||
Dec(iPos, iPos mod TabWidth);
|
|
||||||
if iPos > Position then begin
|
|
||||||
InsideTabChar := TRUE;
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
else Inc(iPos);
|
|
||||||
end;
|
|
||||||
Inc(Result);
|
|
||||||
Inc(pNext);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
Result := Position;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function StrScanForCharInSet(const Line: string; Start: integer;
|
function StrScanForCharInSet(const Line: string; Start: integer;
|
||||||
AChars: TSynIdentChars): integer;
|
AChars: TSynIdentChars): integer;
|
||||||
var
|
var
|
||||||
|
|||||||
@ -644,7 +644,8 @@ var
|
|||||||
else begin
|
else begin
|
||||||
TempString := FLines[FCaret.LinePos - 1];
|
TempString := FLines[FCaret.LinePos - 1];
|
||||||
Len := Length(TempString);
|
Len := Length(TempString);
|
||||||
LogicalInsertPos := FLines.PhysicalToLogicalCol(TempString,InsertPos);
|
LogicalInsertPos := FLines.PhysicalToLogicalCol(TempString,
|
||||||
|
FCaret.LinePos - 1, InsertPos);
|
||||||
if Len < LogicalInsertPos
|
if Len < LogicalInsertPos
|
||||||
then begin
|
then begin
|
||||||
TempString :=
|
TempString :=
|
||||||
|
|||||||
@ -35,6 +35,8 @@ type
|
|||||||
Index, Count: Integer) of object;
|
Index, Count: Integer) of object;
|
||||||
TSynEditNotifyReason = (senrLineCount, senrLineChange);
|
TSynEditNotifyReason = (senrLineCount, senrLineChange);
|
||||||
|
|
||||||
|
TPhysicalCharWidths = Array of Shortint;
|
||||||
|
|
||||||
{ TSynEditStrings }
|
{ TSynEditStrings }
|
||||||
|
|
||||||
TSynEditStrings = class(TStrings)
|
TSynEditStrings = class(TStrings)
|
||||||
@ -50,7 +52,6 @@ type
|
|||||||
function GetExpandedString(Index: integer): string; virtual; abstract;
|
function GetExpandedString(Index: integer): string; virtual; abstract;
|
||||||
function GetLengthOfLongestLine: integer; virtual; abstract;
|
function GetLengthOfLongestLine: integer; virtual; abstract;
|
||||||
procedure SetTextStr(const Value: string); override;
|
procedure SetTextStr(const Value: string); override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
procedure DeleteLines(Index, NumLines: integer); virtual; abstract;
|
procedure DeleteLines(Index, NumLines: integer); virtual; abstract;
|
||||||
@ -66,20 +67,16 @@ type
|
|||||||
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
||||||
AHandler: TStringListLineCountEvent); virtual; abstract;
|
AHandler: TStringListLineCountEvent); virtual; abstract;
|
||||||
public
|
public
|
||||||
|
function GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths;
|
||||||
|
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; virtual; abstract;
|
||||||
// Byte to Char
|
// Byte to Char
|
||||||
function LogicalToPhysicalPos(const p: TPoint): TPoint;
|
function LogicalToPhysicalPos(const p: TPoint): TPoint;
|
||||||
function LogicalToPhysicalCol(const Line: string;
|
function LogicalToPhysicalCol(const Line: String;
|
||||||
LogicalPos: integer): integer;
|
Index, LogicalPos: integer): integer; virtual;
|
||||||
function LogicalToPhysicalCol(Line: PChar; LineLen: integer;
|
|
||||||
LogicalPos, StartBytePos,
|
|
||||||
StartPhysicalPos: integer): integer; virtual;
|
|
||||||
// Char to Byte
|
// Char to Byte
|
||||||
function PhysicalToLogicalPos(const p: TPoint): TPoint;
|
function PhysicalToLogicalPos(const p: TPoint): TPoint;
|
||||||
function PhysicalToLogicalCol(const Line: string;
|
function PhysicalToLogicalCol(const Line: string;
|
||||||
PhysicalPos: integer): integer;
|
Index, PhysicalPos: integer): integer;
|
||||||
function PhysicalToLogicalCol(const Line: string;
|
|
||||||
PhysicalPos, StartBytePos,
|
|
||||||
StartPhysicalPos: integer): integer; virtual;
|
|
||||||
public
|
public
|
||||||
property ExpandedStrings[Index: integer]: string read GetExpandedString;
|
property ExpandedStrings[Index: integer]: string read GetExpandedString;
|
||||||
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
||||||
@ -134,6 +131,9 @@ type
|
|||||||
AHandler: TStringListLineCountEvent); override;
|
AHandler: TStringListLineCountEvent); override;
|
||||||
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
||||||
AHandler: TStringListLineCountEvent); override;
|
AHandler: TStringListLineCountEvent); override;
|
||||||
|
|
||||||
|
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -149,6 +149,11 @@ begin
|
|||||||
IsUtf8 := True;
|
IsUtf8 := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths;
|
||||||
|
begin
|
||||||
|
Result := GetPhysicalCharWidths(Strings[Index], Index);
|
||||||
|
end;
|
||||||
|
|
||||||
function TSynEditStrings.GetIsUtf8 : Boolean;
|
function TSynEditStrings.GetIsUtf8 : Boolean;
|
||||||
begin
|
begin
|
||||||
Result := FIsUtf8;
|
Result := FIsUtf8;
|
||||||
@ -197,81 +202,57 @@ function TSynEditStrings.LogicalToPhysicalPos(const p : TPoint) : TPoint;
|
|||||||
begin
|
begin
|
||||||
Result := p;
|
Result := p;
|
||||||
if Result.Y - 1 < Count then
|
if Result.Y - 1 < Count then
|
||||||
Result.X:=LogicalToPhysicalCol(self[Result.Y - 1],Result.X);
|
Result.X:=LogicalToPhysicalCol(self[Result.Y - 1], Result.Y, Result.X);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynEditStrings.LogicalToPhysicalCol(const Line : string; LogicalPos : integer) : integer;
|
function TSynEditStrings.LogicalToPhysicalCol(const Line : String;
|
||||||
begin
|
Index, LogicalPos: integer) : integer;
|
||||||
Result := LogicalToPhysicalCol(PChar(Pointer(Line)),length(Line),LogicalPos,1,1);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSynEditStrings.LogicalToPhysicalCol(Line : PChar; LineLen : integer; LogicalPos, StartBytePos, StartPhysicalPos : integer) : integer;
|
|
||||||
var
|
var
|
||||||
BytePos, ByteLen: integer;
|
i, ByteLen: integer;
|
||||||
ScreenPos: integer;
|
CharWidths: TPhysicalCharWidths;
|
||||||
begin
|
begin
|
||||||
ByteLen := LineLen;
|
CharWidths := GetPhysicalCharWidths(Line, Index);
|
||||||
// map UTF8
|
ByteLen := length(Line);
|
||||||
ScreenPos := StartPhysicalPos;
|
dec(LogicalPos);
|
||||||
BytePos:= StartBytePos;
|
|
||||||
while BytePos<LogicalPos do begin
|
if LogicalPos > ByteLen then begin
|
||||||
if (BytePos <= ByteLen) then begin
|
Result := 1 + LogicalPos - ByteLen;
|
||||||
inc(ScreenPos);
|
LogicalPos := ByteLen;
|
||||||
if IsUTF8 then
|
end
|
||||||
inc(BytePos,UTF8CharacterLength(@Line[BytePos-1]))
|
else
|
||||||
else
|
Result := 1;
|
||||||
inc(BytePos);
|
|
||||||
end else begin
|
for i := 0 to LogicalPos - 1 do
|
||||||
// beyond end of line
|
Result := Result + CharWidths[i];
|
||||||
inc(ScreenPos,LogicalPos-BytePos);
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if (BytePos>LogicalPos) and (ScreenPos>StartPhysicalPos) then
|
|
||||||
dec(ScreenPos);
|
|
||||||
Result := ScreenPos;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint;
|
function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint;
|
||||||
begin
|
begin
|
||||||
Result := p;
|
Result := p;
|
||||||
if (Result.Y>=1) and (Result.Y <= Count) then
|
if (Result.Y>=1) and (Result.Y <= Count) then
|
||||||
Result.X:=PhysicalToLogicalCol(self[Result.Y - 1],Result.X,1,1);
|
Result.X:=PhysicalToLogicalCol(self[Result.Y - 1], Result.Y - 1, Result.X);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynEditStrings.PhysicalToLogicalCol(const Line : string; PhysicalPos : integer) : integer;
|
function TSynEditStrings.PhysicalToLogicalCol(const Line : string;
|
||||||
begin
|
Index, PhysicalPos : integer) : integer;
|
||||||
Result:=PhysicalToLogicalCol(Line,PhysicalPos,1,1);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSynEditStrings.PhysicalToLogicalCol(const Line : string; PhysicalPos, StartBytePos, StartPhysicalPos : integer) : integer;
|
|
||||||
var
|
var
|
||||||
BytePos, ByteLen: integer;
|
BytePos, ByteLen: integer;
|
||||||
ScreenPos: integer;
|
ScreenPos: integer;
|
||||||
PLine: PChar;
|
CharWidths: TPhysicalCharWidths;
|
||||||
begin
|
begin
|
||||||
|
CharWidths := GetPhysicalCharWidths(Line, Index);
|
||||||
ByteLen := Length(Line);
|
ByteLen := Length(Line);
|
||||||
ScreenPos := StartPhysicalPos;
|
ScreenPos := 1;
|
||||||
BytePos := StartBytePos;
|
BytePos := 0;
|
||||||
PLine := PChar(Line);
|
|
||||||
// map utf
|
while BytePos < ByteLen do begin
|
||||||
while ScreenPos < PhysicalPos do begin
|
if ScreenPos + CharWidths[BytePos] > PhysicalPos then
|
||||||
if (BytePos <= ByteLen) then begin
|
exit(BytePos+1);
|
||||||
inc(ScreenPos);
|
ScreenPos := ScreenPos + CharWidths[BytePos];
|
||||||
if IsUTF8 then
|
inc(BytePos);
|
||||||
inc(BytePos,UTF8CharacterLength(@PLine[BytePos-1]))
|
|
||||||
else
|
|
||||||
inc(BytePos);
|
|
||||||
end else begin
|
|
||||||
// beyond end of line
|
|
||||||
inc(BytePos,PhysicalPos-ScreenPos);
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
if (ScreenPos>PhysicalPos) and (BytePos>1) and (BytePos-2<ByteLen)
|
|
||||||
and (PLine[BytePos-2]=#9) then
|
Result := BytePos + 1 + PhysicalPos - ScreenPos;
|
||||||
dec(BytePos);
|
|
||||||
Result := BytePos;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TSynEditStringsLinked }
|
{ TSynEditStringsLinked }
|
||||||
@ -415,6 +396,11 @@ begin
|
|||||||
fSynStrings.PutObject(Index, AObject);
|
fSynStrings.PutObject(Index, AObject);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TSynEditStringsLinked.GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths;
|
||||||
|
begin
|
||||||
|
Result := fSynStrings.GetPhysicalCharWidths(Line, Index);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean);
|
procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean);
|
||||||
begin
|
begin
|
||||||
if Updating then
|
if Updating then
|
||||||
|
|||||||
@ -200,6 +200,7 @@ type
|
|||||||
AHandler: TStringListLineCountEvent); override;
|
AHandler: TStringListLineCountEvent); override;
|
||||||
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
|
||||||
AHandler: TStringListLineCountEvent); override;
|
AHandler: TStringListLineCountEvent); override;
|
||||||
|
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
|
||||||
public
|
public
|
||||||
property DosFileFormat: boolean read fDosFileFormat write fDosFileFormat;
|
property DosFileFormat: boolean read fDosFileFormat write fDosFileFormat;
|
||||||
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
||||||
@ -707,6 +708,29 @@ begin
|
|||||||
else
|
else
|
||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Maps the Physical Width (ScreenCells) to each character
|
||||||
|
// Multibyte Chars have thw width on the first byte, and a 0 Width for all other bytes
|
||||||
|
function TSynEditStringList.GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths;
|
||||||
|
var
|
||||||
|
i, j: Integer;
|
||||||
|
begin
|
||||||
|
SetLength(Result, Length(Line));
|
||||||
|
i := 0;
|
||||||
|
j := 0;
|
||||||
|
while i < length(Line) do begin
|
||||||
|
if j > 0 then begin
|
||||||
|
Result[i] := 0;
|
||||||
|
dec(j);
|
||||||
|
end else begin
|
||||||
|
Result[i] := 1;
|
||||||
|
if IsUtf8 then
|
||||||
|
j := UTF8CharacterLength(@Line[i+1]) - 1;
|
||||||
|
end;
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{end} //mh 2000-10-19
|
{end} //mh 2000-10-19
|
||||||
|
|
||||||
function TSynEditStringList.GetObject(Index: integer): TObject;
|
function TSynEditStringList.GetObject(Index: integer): TObject;
|
||||||
|
|||||||
@ -41,8 +41,6 @@ type
|
|||||||
TSynEditStringTabExpander = class(TSynEditStringsLinked)
|
TSynEditStringTabExpander = class(TSynEditStringsLinked)
|
||||||
private
|
private
|
||||||
FTabWidth: integer;
|
FTabWidth: integer;
|
||||||
FConvertTabsProc: TConvertTabsProcEx;
|
|
||||||
FSimulateConvertTabsProc: TSimulateConvertTabsProcEx;
|
|
||||||
FIndexOfLongestLine: Integer;
|
FIndexOfLongestLine: Integer;
|
||||||
function GetLengthOfLine(Index: Integer): integer;
|
function GetLengthOfLine(Index: Integer): integer;
|
||||||
procedure SetLengthOfLine(Index: Integer; const AValue: integer);
|
procedure SetLengthOfLine(Index: Integer; const AValue: integer);
|
||||||
@ -53,6 +51,7 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked)
|
|||||||
function GetTabWidth : integer;
|
function GetTabWidth : integer;
|
||||||
procedure SetTabWidth(const AValue : integer);
|
procedure SetTabWidth(const AValue : integer);
|
||||||
function GetExpandedString(Index: integer): string; override;
|
function GetExpandedString(Index: integer): string; override;
|
||||||
|
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
|
||||||
function GetLengthOfLongestLine: integer; override;
|
function GetLengthOfLongestLine: integer; override;
|
||||||
property LengthOfLine[Index: Integer]: integer
|
property LengthOfLine[Index: Integer]: integer
|
||||||
read GetLengthOfLine write SetLengthOfLine;
|
read GetLengthOfLine write SetLengthOfLine;
|
||||||
@ -61,14 +60,6 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked)
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
||||||
|
|
||||||
// TODO: maybe use inherited for utf8?
|
|
||||||
function LogicalToPhysicalCol(Line: PChar; LineLen: integer;
|
|
||||||
LogicalPos, StartBytePos,
|
|
||||||
StartPhysicalPos: integer): integer; override;
|
|
||||||
function PhysicalToLogicalCol(const Line: string;
|
|
||||||
PhysicalPos, StartBytePos,
|
|
||||||
StartPhysicalPos: integer): integer; override;
|
|
||||||
public
|
public
|
||||||
property TabWidth: integer read GetTabWidth write SetTabWidth;
|
property TabWidth: integer read GetTabWidth write SetTabWidth;
|
||||||
end;
|
end;
|
||||||
@ -76,6 +67,18 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked)
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
function GetHasTabs(pLine: PChar): boolean;
|
||||||
|
begin
|
||||||
|
if Assigned(pLine) then begin
|
||||||
|
while (pLine^ <> #0) do begin
|
||||||
|
if (pLine^ = #9) then break;
|
||||||
|
Inc(pLine);
|
||||||
|
end;
|
||||||
|
Result := (pLine^ = #9);
|
||||||
|
end else
|
||||||
|
Result := FALSE;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TSynEditStringTabExpander }
|
{ TSynEditStringTabExpander }
|
||||||
|
|
||||||
constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings);
|
constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings);
|
||||||
@ -117,8 +120,6 @@ begin
|
|||||||
if FTabWidth = AValue then exit;
|
if FTabWidth = AValue then exit;
|
||||||
|
|
||||||
FTabWidth := AValue;
|
FTabWidth := AValue;
|
||||||
FConvertTabsProc := GetBestConvertTabsProcEx(fTabWidth);
|
|
||||||
FSimulateConvertTabsProc := GetBestSimulateConvertTabsProcEx(fTabWidth);
|
|
||||||
FIndexOfLongestLine := -1;
|
FIndexOfLongestLine := -1;
|
||||||
for i := 0 to Count - 1 do
|
for i := 0 to Count - 1 do
|
||||||
if not(LengthOfLine[i] >= NoTabLengthOffset) then
|
if not(LengthOfLine[i] >= NoTabLengthOffset) then
|
||||||
@ -136,33 +137,54 @@ end;
|
|||||||
|
|
||||||
function TSynEditStringTabExpander.ExpandedString(Index: integer): string;
|
function TSynEditStringTabExpander.ExpandedString(Index: integer): string;
|
||||||
var
|
var
|
||||||
HasTabs: boolean;
|
Line: String;
|
||||||
|
CharWidths: TPhysicalCharWidths;
|
||||||
|
i, j, l: Integer;
|
||||||
begin
|
begin
|
||||||
if fSynStrings[Index] = '' then begin
|
Line := fSynStrings[Index];
|
||||||
Result := '';
|
if (Line = '') or (not GetHasTabs(PChar(Line))) then begin
|
||||||
LengthOfLine[Index] := 0 + NoTabLengthOffset;
|
Result := Line;
|
||||||
|
LengthOfLine[Index] := length(Result) + NoTabLengthOffset;
|
||||||
end else begin
|
end else begin
|
||||||
Result := fConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs);
|
CharWidths := GetPhysicalCharWidths(Line, Index);
|
||||||
if HasTabs then
|
l := 0;
|
||||||
LengthOfLine[Index] := length(Result)
|
for i := 0 to length(CharWidths)-1 do
|
||||||
else
|
l := l + CharWidths[i];
|
||||||
LengthOfLine[Index] := length(Result) + NoTabLengthOffset;
|
SetLength(Result, l);
|
||||||
|
|
||||||
|
l := 1;
|
||||||
|
for i := 1 to length(CharWidths) do begin
|
||||||
|
if Line[i] <> #9 then begin
|
||||||
|
Result[l] := Line[i];
|
||||||
|
inc(l);
|
||||||
|
end else begin
|
||||||
|
for j := 1 to CharWidths[i-1] do begin
|
||||||
|
Result[l] := ' ';
|
||||||
|
inc(l);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
LengthOfLine[Index] := length(Result);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynEditStringTabExpander.ExpandedStringLength(Index: integer): Integer;
|
function TSynEditStringTabExpander.ExpandedStringLength(Index: integer): Integer;
|
||||||
var
|
var
|
||||||
HasTabs: boolean;
|
Line: String;
|
||||||
|
CharWidths: TPhysicalCharWidths;
|
||||||
|
i, j, l: Integer;
|
||||||
begin
|
begin
|
||||||
if fSynStrings[Index] = '' then begin
|
Line := fSynStrings[Index];
|
||||||
|
if (Line = '') or (not GetHasTabs(PChar(Line))) then begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
LengthOfLine[Index] := 0 + NoTabLengthOffset;
|
LengthOfLine[Index] := Length(Line) + NoTabLengthOffset;
|
||||||
end else begin
|
end else begin
|
||||||
Result := fSimulateConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs);
|
CharWidths := GetPhysicalCharWidths(Line, Index);
|
||||||
if HasTabs then
|
Result := 0;
|
||||||
LengthOfLine[Index] := Result
|
for i := 0 to length(CharWidths)-1 do
|
||||||
else
|
Result := Result + CharWidths[i];
|
||||||
LengthOfLine[Index] := Result + NoTabLengthOffset;
|
|
||||||
|
LengthOfLine[Index] := Result;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -177,6 +199,21 @@ begin
|
|||||||
Result := '';
|
Result := '';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TSynEditStringTabExpander.GetPhysicalCharWidths(const Line: String;
|
||||||
|
Index: Integer): TPhysicalCharWidths;
|
||||||
|
var
|
||||||
|
i, p: Integer;
|
||||||
|
begin
|
||||||
|
Result := inherited GetPhysicalCharWidths(Line, Index);
|
||||||
|
p := 0;
|
||||||
|
for i := 0 to length(Line) -1 do begin
|
||||||
|
if Result[i] = 0 then continue;
|
||||||
|
if Line[i+1] = #9 then
|
||||||
|
Result[i] := FTabWidth - p mod FTabWidth;
|
||||||
|
p := p + Result[i];
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
function TSynEditStringTabExpander.GetLengthOfLongestLine: integer;
|
function TSynEditStringTabExpander.GetLengthOfLongestLine: integer;
|
||||||
var
|
var
|
||||||
i, j, MaxLen: integer;
|
i, j, MaxLen: integer;
|
||||||
@ -204,74 +241,5 @@ begin
|
|||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSynEditStringTabExpander.LogicalToPhysicalCol(Line: PChar;
|
|
||||||
LineLen: integer; LogicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
var
|
|
||||||
BytePos, ByteLen: integer;
|
|
||||||
ScreenPos: integer;
|
|
||||||
begin
|
|
||||||
ByteLen := LineLen;
|
|
||||||
// map UTF8 and Tab chars
|
|
||||||
ScreenPos := StartPhysicalPos;
|
|
||||||
BytePos:= StartBytePos;
|
|
||||||
while BytePos<LogicalPos do begin
|
|
||||||
if (BytePos <= ByteLen) then begin
|
|
||||||
if Line[BytePos-1] = #9 then begin
|
|
||||||
inc(ScreenPos, TabWidth - ((ScreenPos-1) mod TabWidth));
|
|
||||||
inc(BytePos);
|
|
||||||
end else begin
|
|
||||||
inc(ScreenPos);
|
|
||||||
if IsUTF8 then
|
|
||||||
inc(BytePos,UTF8CharacterLength(@Line[BytePos-1]))
|
|
||||||
else
|
|
||||||
inc(BytePos);
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
// beyond end of line
|
|
||||||
inc(ScreenPos,LogicalPos-BytePos);
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if (BytePos>LogicalPos) and (ScreenPos>StartPhysicalPos) then
|
|
||||||
dec(ScreenPos);
|
|
||||||
Result := ScreenPos;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSynEditStringTabExpander.PhysicalToLogicalCol(const Line: string;
|
|
||||||
PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer;
|
|
||||||
var
|
|
||||||
BytePos, ByteLen: integer;
|
|
||||||
ScreenPos: integer;
|
|
||||||
PLine: PChar;
|
|
||||||
begin
|
|
||||||
ByteLen := Length(Line);
|
|
||||||
ScreenPos := StartPhysicalPos;
|
|
||||||
BytePos := StartBytePos;
|
|
||||||
PLine := PChar(Line);
|
|
||||||
// map utf and tab chars
|
|
||||||
while ScreenPos < PhysicalPos do begin
|
|
||||||
if (BytePos <= ByteLen) then begin
|
|
||||||
if (PLine[BytePos-1] <> #9) then begin
|
|
||||||
inc(ScreenPos);
|
|
||||||
if IsUTF8 then
|
|
||||||
inc(BytePos,UTF8CharacterLength(@PLine[BytePos-1]))
|
|
||||||
else
|
|
||||||
inc(BytePos);
|
|
||||||
end else begin
|
|
||||||
inc(ScreenPos, TabWidth - ((ScreenPos-1) mod TabWidth));
|
|
||||||
inc(BytePos);
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
// beyond end of line
|
|
||||||
inc(BytePos,PhysicalPos-ScreenPos);
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if (ScreenPos>PhysicalPos) and (BytePos>1) and (BytePos-2<ByteLen)
|
|
||||||
and (PLine[BytePos-2]=#9) then
|
|
||||||
dec(BytePos);
|
|
||||||
Result := BytePos;
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|||||||
@ -109,7 +109,7 @@ begin
|
|||||||
and ((IndentLen>length(s)) or (s[IndentLen] in [#9,' '])) do
|
and ((IndentLen>length(s)) or (s[IndentLen] in [#9,' '])) do
|
||||||
inc(IndentLen);
|
inc(IndentLen);
|
||||||
end;
|
end;
|
||||||
IndentLen:=AEditor.LogicalToPhysicalCol(s,IndentLen);// consider tabs
|
IndentLen:=AEditor.LogicalToPhysicalCol(s, p.y - 1, IndentLen);// consider tabs
|
||||||
dec(IndentLen);
|
dec(IndentLen);
|
||||||
end;
|
end;
|
||||||
p := AEditor.BlockBegin;
|
p := AEditor.BlockBegin;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user