diff --git a/components/synedit/synbeautifier.pas b/components/synedit/synbeautifier.pas index 2accec654d..2f73f9e6fc 100644 --- a/components/synedit/synbeautifier.pas +++ b/components/synedit/synbeautifier.pas @@ -68,7 +68,7 @@ begin Inc(Result); end; 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 Result := 0; end; @@ -98,7 +98,7 @@ begin if SpaceCount2 = SpaceCount1 then SpaceCount2 := 0; // remove visible spaces - LogSpacePos := TSynEdit(Editor).PhysicalToLogicalCol(Line, SpaceCount2 + 1); + LogSpacePos := TSynEdit(Editor).PhysicalToLogicalCol(Line, PhysCaret.y-1, SpaceCount2 + 1); CaretNewX := SpaceCount2 + 1; DelChars := copy(Line, LogSpacePos, PhysCaret.X - LogSpacePos); InsChars := ''; // TODO: if tabs were removed, maybe fill-up with spaces @@ -132,7 +132,8 @@ begin sbitSpace: InsChars := StringOfChar(' ', SpaceCount2); 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: if Line <> '' then InsChars := StringOfChar(' ', SpaceCount2) @@ -140,7 +141,7 @@ begin InsChars := ''; end; Result := InsChars + Line; - CaretNewX := TSynEdit(Editor).LogicalToPhysicalCol(Result, SpaceCount2+1); + CaretNewX := TSynEdit(Editor).LogicalToPhysicalCol(Result, PhysCaret.y - 1, SpaceCount2+1); end; function TSynBeautifier.GetIndentForLine(Editor: TSynEditBase; const Line: string; const PhysCaret: TPoint): Integer; diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index a279699ddf..58c126a878 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -471,7 +471,6 @@ type function GetLineText: string; {$IFDEF SYN_LAZARUS} function GetCharLen(const Line: string; CharStartPos: integer): integer; - function AdjustPhysPosToCharacterStart(Line: integer; PhysPos: integer): integer; function GetLogicalCaretXY: TPoint; procedure SetCFDividerDrawLevel(const AValue: Integer); function GetCFDividerDrawLevel : Integer; @@ -756,18 +755,13 @@ type {$IFDEF SYN_LAZARUS} // Byte to Char function LogicalToPhysicalPos(const p: TPoint): TPoint; - function LogicalToPhysicalCol(const Line: string; - LogicalPos: integer): integer; - function LogicalToPhysicalCol(Line: PChar; LineLen: integer; - LogicalPos, StartBytePos, StartPhysicalPos: integer): integer; + function LogicalToPhysicalCol(const Line: String; Index, LogicalPos + : integer): integer; // Char to Byte function PhysicalToLogicalPos(const p: TPoint): TPoint; function PhysicalToLogicalCol(const Line: string; - PhysicalPos: integer): integer; - function PhysicalToLogicalCol(const Line: string; - PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer; - function PhysicalLineLength(Line: PChar; LineLen: integer; - WithTabs: boolean): integer; + Index, PhysicalPos: integer): integer; + function PhysicalLineLength(Line: String; Index: integer): integer; function ScreenColumnToXValue(Col: integer): integer; // map screen column to screen pixel procedure MoveCaretToVisibleArea; procedure MoveCaretIgnoreEOL(const NewCaret: TPoint); @@ -1817,22 +1811,6 @@ begin Result:=1; 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; begin Result:=PhysicalToLogicalPos(CaretXY); @@ -3685,7 +3663,7 @@ begin if not (eoScrollPastEol in fOptions) then begin {$IFDEF SYN_LAZARUS} Line:=FTheLinesView[Value.Y-1]; - nMaxX := PhysicalLineLength(PChar(Line),length(Line),true)+1; + nMaxX := PhysicalLineLength(Line, Value.Y-1) + 1; {$ELSE} nMaxX := Length(FTheLinesView[Value.Y - 1]) + 1; //abc 2000-09-30 {$ENDIF} @@ -6158,12 +6136,8 @@ begin // join this line with the last line if possible if CaretY > 1 then begin CaretY := CaretY - 1; - {$IFDEF SYN_LAZARUS} - CaretX := LogicalToPhysicalCol(FTheLinesView[CaretY - 1], - Length(FTheLinesView[CaretY - 1]) + 1); - {$ELSE} - CaretX := Length(Lines[CaretY - 1]) + 1; - {$ENDIF} + CaretX := PhysicalLineLength(FTheLinesView[CaretY - 1], + CaretY - 1) + 1; FTheLinesView.Delete(CaretY); DoLinesDeleted(CaretY, 1); {$IFNDEF SYN_LAZARUS} @@ -6194,9 +6168,9 @@ begin Helper := Copy(Temp, CaretX, counter); VDelete(Temp, CaretX, counter, drLTR); {$ELSE USE_UTF8BIDI_LCL} - LogCaretXY.X:=PhysicalToLogicalCol(Temp,CaretX-counter); + LogCaretXY.X:=PhysicalToLogicalCol(Temp, CaretY-1, CaretX-counter); LogCounter:=GetCharLen(Temp,LogCaretXY.X); - CaretX := LogicalToPhysicalCol(Temp,LogCaretXY.X); + CaretX := LogicalToPhysicalCol(Temp, CaretY-1, LogCaretXY.X); Helper := Copy(Temp, LogCaretXY.X, LogCounter); System.Delete(Temp, LogCaretXY.X, LogCounter); //debugln('ecDeleteLastChar delete char CaretX=',dbgs(CaretX), @@ -6263,7 +6237,7 @@ begin {$IFDEF SYN_LAZARUS} Counter:=GetCharLen(Temp,LogCaretXY.X); 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; {$IFDEF USE_UTF8BIDI_LCL} VDelete(Temp, LogCaretXY.X, Counter, drLTR); @@ -6307,7 +6281,7 @@ begin end; ecDeleteWord, ecDeleteEOL: if not ReadOnly then begin - Len := LogicalToPhysicalCol(LineText,Length(LineText)+1)-1; + Len := LogicalToPhysicalCol(LineText, CaretY-1,Length(LineText)+1)-1; Helper := ''; Caret := CaretXY; if Command = ecDeleteWord then begin @@ -8114,17 +8088,17 @@ begin Dec(iLine); if iLine < 0 then break; PrevLine := FTheLinesView[iLine]; - until PhysicalLineLength(PChar(PrevLine),length(PrevLine),true) > OldCaretX - 1; + until PhysicalLineLength(PrevLine, iLine) > OldCaretX - 1; if iLine >= 0 then begin - p := @PrevLine[PhysicalToLogicalCol(PrevLine,OldCaretX)]; + p := @PrevLine[PhysicalToLogicalCol(PrevLine, iLine, OldCaretX)]; // scan over non-whitespaces while not (p^ in [#0, #9, #32]) do inc(p); // scan over whitespaces while (p^ in [#9, #32]) do inc(p); - i := LogicalToPhysicalCol(PrevLine, p-@PrevLine[1]+1) - CaretX; + i := LogicalToPhysicalCol(PrevLine, iLine, p-@PrevLine[1]+1) - CaretX; end; end; end; @@ -9304,28 +9278,18 @@ end; {$ENDIF} {$IFDEF SYN_LAZARUS} -function TCustomSynEdit.LogicalToPhysicalCol(const Line: string; - LogicalPos: integer): integer; +function TCustomSynEdit.LogicalToPhysicalCol(const Line: String; + Index, LogicalPos: integer): integer; +// LogicalPos is 1-based +// Index 0-based LineNumber begin - Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(PChar(Pointer(Line)), - length(Line),LogicalPos,1,1); + Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(Line, Index, + LogicalPos); end; -function TCustomSynEdit.LogicalToPhysicalCol(Line: PChar; LineLen: integer; - LogicalPos, StartBytePos, StartPhysicalPos: integer): integer; -// Note: LogicalPos, StartBytePos, StartPhysicalPos start at 1 +function TCustomSynEdit.PhysicalLineLength(Line: String; Index: integer): integer; begin - Result := TSynEditStrings(FTheLinesView).LogicalToPhysicalCol(Line, LineLen, LogicalPos, - 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); + Result:=LogicalToPhysicalCol(Line, Index, length(Line)+1) - 1 end; function TCustomSynEdit.PhysicalToLogicalPos(const p: TPoint): TPoint; @@ -9334,16 +9298,10 @@ begin end; function TCustomSynEdit.PhysicalToLogicalCol(const Line: string; - PhysicalPos: integer): integer; + Index, PhysicalPos: integer): integer; begin - Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line,PhysicalPos,1,1); -end; - -function TCustomSynEdit.PhysicalToLogicalCol(const Line: string; - PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer; -begin - Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line, PhysicalPos, - StartBytePos, StartPhysicalPos); + Result := TSynEditStrings(FTheLinesView).PhysicalToLogicalCol(Line, Index, + PhysicalPos); end; function TCustomSynEdit.ScreenColumnToXValue(Col : integer) : integer; diff --git a/components/synedit/syneditmiscprocs.pp b/components/synedit/syneditmiscprocs.pp index cf9d4111ae..394924cfd5 100644 --- a/components/synedit/syneditmiscprocs.pp +++ b/components/synedit/syneditmiscprocs.pp @@ -71,41 +71,6 @@ function GetIntArray(Count: Cardinal; InitialValue: integer): PIntArray; 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 function StrScanForCharInSet(const Line: string; Start: 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; AChars: TSynIdentChars): integer; var diff --git a/components/synedit/syneditpointclasses.pas b/components/synedit/syneditpointclasses.pas index 15059e5be5..ebd6b37c7d 100644 --- a/components/synedit/syneditpointclasses.pas +++ b/components/synedit/syneditpointclasses.pas @@ -644,7 +644,8 @@ var else begin TempString := FLines[FCaret.LinePos - 1]; Len := Length(TempString); - LogicalInsertPos := FLines.PhysicalToLogicalCol(TempString,InsertPos); + LogicalInsertPos := FLines.PhysicalToLogicalCol(TempString, + FCaret.LinePos - 1, InsertPos); if Len < LogicalInsertPos then begin TempString := diff --git a/components/synedit/synedittextbase.pas b/components/synedit/synedittextbase.pas index 55b33f9dfb..2352b8c87a 100644 --- a/components/synedit/synedittextbase.pas +++ b/components/synedit/synedittextbase.pas @@ -35,6 +35,8 @@ type Index, Count: Integer) of object; TSynEditNotifyReason = (senrLineCount, senrLineChange); + TPhysicalCharWidths = Array of Shortint; + { TSynEditStrings } TSynEditStrings = class(TStrings) @@ -50,7 +52,6 @@ type function GetExpandedString(Index: integer): string; virtual; abstract; function GetLengthOfLongestLine: integer; virtual; abstract; procedure SetTextStr(const Value: string); override; - public constructor Create; procedure DeleteLines(Index, NumLines: integer); virtual; abstract; @@ -66,20 +67,16 @@ type procedure RemoveChangeHandler(AReason: TSynEditNotifyReason; AHandler: TStringListLineCountEvent); virtual; abstract; public + function GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; + function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; virtual; abstract; // Byte to Char function LogicalToPhysicalPos(const p: TPoint): TPoint; - function LogicalToPhysicalCol(const Line: string; - LogicalPos: integer): integer; - function LogicalToPhysicalCol(Line: PChar; LineLen: integer; - LogicalPos, StartBytePos, - StartPhysicalPos: integer): integer; virtual; + function LogicalToPhysicalCol(const Line: String; + Index, LogicalPos: integer): integer; virtual; // Char to Byte function PhysicalToLogicalPos(const p: TPoint): TPoint; function PhysicalToLogicalCol(const Line: string; - PhysicalPos: integer): integer; - function PhysicalToLogicalCol(const Line: string; - PhysicalPos, StartBytePos, - StartPhysicalPos: integer): integer; virtual; + Index, PhysicalPos: integer): integer; public property ExpandedStrings[Index: integer]: string read GetExpandedString; property LengthOfLongestLine: integer read GetLengthOfLongestLine; @@ -134,6 +131,9 @@ type AHandler: TStringListLineCountEvent); override; procedure RemoveChangeHandler(AReason: TSynEditNotifyReason; AHandler: TStringListLineCountEvent); override; + + function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override; + end; @@ -149,6 +149,11 @@ begin IsUtf8 := True; end; +function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; +begin + Result := GetPhysicalCharWidths(Strings[Index], Index); +end; + function TSynEditStrings.GetIsUtf8 : Boolean; begin Result := FIsUtf8; @@ -197,81 +202,57 @@ function TSynEditStrings.LogicalToPhysicalPos(const p : TPoint) : TPoint; begin Result := p; 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; -function TSynEditStrings.LogicalToPhysicalCol(const Line : string; LogicalPos : integer) : integer; -begin - Result := LogicalToPhysicalCol(PChar(Pointer(Line)),length(Line),LogicalPos,1,1); -end; - -function TSynEditStrings.LogicalToPhysicalCol(Line : PChar; LineLen : integer; LogicalPos, StartBytePos, StartPhysicalPos : integer) : integer; +function TSynEditStrings.LogicalToPhysicalCol(const Line : String; + Index, LogicalPos: integer) : integer; var - BytePos, ByteLen: integer; - ScreenPos: integer; + i, ByteLen: integer; + CharWidths: TPhysicalCharWidths; begin - ByteLen := LineLen; - // map UTF8 - ScreenPos := StartPhysicalPos; - BytePos:= StartBytePos; - while BytePosLogicalPos) and (ScreenPos>StartPhysicalPos) then - dec(ScreenPos); - Result := ScreenPos; + CharWidths := GetPhysicalCharWidths(Line, Index); + ByteLen := length(Line); + dec(LogicalPos); + + if LogicalPos > ByteLen then begin + Result := 1 + LogicalPos - ByteLen; + LogicalPos := ByteLen; + end + else + Result := 1; + + for i := 0 to LogicalPos - 1 do + Result := Result + CharWidths[i]; end; function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint; begin Result := p; 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; -function TSynEditStrings.PhysicalToLogicalCol(const Line : string; PhysicalPos : integer) : integer; -begin - Result:=PhysicalToLogicalCol(Line,PhysicalPos,1,1); -end; - -function TSynEditStrings.PhysicalToLogicalCol(const Line : string; PhysicalPos, StartBytePos, StartPhysicalPos : integer) : integer; +function TSynEditStrings.PhysicalToLogicalCol(const Line : string; + Index, PhysicalPos : integer) : integer; var BytePos, ByteLen: integer; ScreenPos: integer; - PLine: PChar; + CharWidths: TPhysicalCharWidths; begin + CharWidths := GetPhysicalCharWidths(Line, Index); ByteLen := Length(Line); - ScreenPos := StartPhysicalPos; - BytePos := StartBytePos; - PLine := PChar(Line); - // map utf - while ScreenPos < PhysicalPos do begin - if (BytePos <= ByteLen) then begin - inc(ScreenPos); - if IsUTF8 then - inc(BytePos,UTF8CharacterLength(@PLine[BytePos-1])) - else - inc(BytePos); - end else begin - // beyond end of line - inc(BytePos,PhysicalPos-ScreenPos); - break; - end; + ScreenPos := 1; + BytePos := 0; + + while BytePos < ByteLen do begin + if ScreenPos + CharWidths[BytePos] > PhysicalPos then + exit(BytePos+1); + ScreenPos := ScreenPos + CharWidths[BytePos]; + inc(BytePos); end; - if (ScreenPos>PhysicalPos) and (BytePos>1) and (BytePos-2 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 function TSynEditStringList.GetObject(Index: integer): TObject; diff --git a/components/synedit/synedittexttabexpander.pas b/components/synedit/synedittexttabexpander.pas index 3521660da8..b4e1ad35fb 100644 --- a/components/synedit/synedittexttabexpander.pas +++ b/components/synedit/synedittexttabexpander.pas @@ -41,8 +41,6 @@ type TSynEditStringTabExpander = class(TSynEditStringsLinked) private FTabWidth: integer; - FConvertTabsProc: TConvertTabsProcEx; - FSimulateConvertTabsProc: TSimulateConvertTabsProcEx; FIndexOfLongestLine: Integer; function GetLengthOfLine(Index: Integer): integer; procedure SetLengthOfLine(Index: Integer; const AValue: integer); @@ -53,6 +51,7 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked) function GetTabWidth : integer; procedure SetTabWidth(const AValue : integer); function GetExpandedString(Index: integer): string; override; + function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override; function GetLengthOfLongestLine: integer; override; property LengthOfLine[Index: Integer]: integer read GetLengthOfLine write SetLengthOfLine; @@ -61,14 +60,6 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked) destructor Destroy; override; 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 property TabWidth: integer read GetTabWidth write SetTabWidth; end; @@ -76,6 +67,18 @@ TSynEditStringTabExpander = class(TSynEditStringsLinked) 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 } constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings); @@ -117,8 +120,6 @@ begin if FTabWidth = AValue then exit; FTabWidth := AValue; - FConvertTabsProc := GetBestConvertTabsProcEx(fTabWidth); - FSimulateConvertTabsProc := GetBestSimulateConvertTabsProcEx(fTabWidth); FIndexOfLongestLine := -1; for i := 0 to Count - 1 do if not(LengthOfLine[i] >= NoTabLengthOffset) then @@ -136,33 +137,54 @@ end; function TSynEditStringTabExpander.ExpandedString(Index: integer): string; var - HasTabs: boolean; + Line: String; + CharWidths: TPhysicalCharWidths; + i, j, l: Integer; begin - if fSynStrings[Index] = '' then begin - Result := ''; - LengthOfLine[Index] := 0 + NoTabLengthOffset; + Line := fSynStrings[Index]; + if (Line = '') or (not GetHasTabs(PChar(Line))) then begin + Result := Line; + LengthOfLine[Index] := length(Result) + NoTabLengthOffset; end else begin - Result := fConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs); - if HasTabs then - LengthOfLine[Index] := length(Result) - else - LengthOfLine[Index] := length(Result) + NoTabLengthOffset; + CharWidths := GetPhysicalCharWidths(Line, Index); + l := 0; + for i := 0 to length(CharWidths)-1 do + l := l + CharWidths[i]; + 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; function TSynEditStringTabExpander.ExpandedStringLength(Index: integer): Integer; var - HasTabs: boolean; + Line: String; + CharWidths: TPhysicalCharWidths; + i, j, l: Integer; begin - if fSynStrings[Index] = '' then begin + Line := fSynStrings[Index]; + if (Line = '') or (not GetHasTabs(PChar(Line))) then begin Result := 0; - LengthOfLine[Index] := 0 + NoTabLengthOffset; + LengthOfLine[Index] := Length(Line) + NoTabLengthOffset; end else begin - Result := fSimulateConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs); - if HasTabs then - LengthOfLine[Index] := Result - else - LengthOfLine[Index] := Result + NoTabLengthOffset; + CharWidths := GetPhysicalCharWidths(Line, Index); + Result := 0; + for i := 0 to length(CharWidths)-1 do + Result := Result + CharWidths[i]; + + LengthOfLine[Index] := Result; end; end; @@ -177,6 +199,21 @@ begin Result := ''; 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; var i, j, MaxLen: integer; @@ -204,74 +241,5 @@ begin Result := 0; 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 BytePosLogicalPos) 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-2length(s)) or (s[IndentLen] in [#9,' '])) do inc(IndentLen); end; - IndentLen:=AEditor.LogicalToPhysicalCol(s,IndentLen);// consider tabs + IndentLen:=AEditor.LogicalToPhysicalCol(s, p.y - 1, IndentLen);// consider tabs dec(IndentLen); end; p := AEditor.BlockBegin;