SynEdit: Refactor Line-Viewers, Add LineViewer for tab-expansion

git-svn-id: trunk@18110 -
This commit is contained in:
martin 2009-01-04 18:47:46 +00:00
parent 98372de302
commit 4849ad30c1
9 changed files with 1097 additions and 586 deletions

1
.gitattributes vendored
View File

@ -1428,6 +1428,7 @@ components/synedit/syneditsearch.pp svneol=native#text/pascal
components/synedit/syneditstrconst.pp svneol=native#text/pascal
components/synedit/synedittextbase.pas svneol=native#text/plain
components/synedit/synedittextbuffer.pp svneol=native#text/pascal
components/synedit/synedittexttabexpander.pas svneol=native#text/plain
components/synedit/synedittexttrimmer.pas svneol=native#text/plain
components/synedit/synedittypes.pp svneol=native#text/pascal
components/synedit/synexporthtml.pas svneol=native#text/pascal

View File

@ -77,7 +77,7 @@ uses
{$ifdef SYN_LAZARUS}
SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket,
SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection,
SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView,
SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView, SynEditTextTabExpander,
SynGutter,
{$ENDIF}
SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer;
@ -370,10 +370,12 @@ type
fHighlighterNeedsUpdateEndLine: integer; // 1 based, 0 means invalid
fBeautifier: TSynCustomBeautifier;
fExtraCharSpacing: integer;
fTextView : TSynEditFoldedView;
fTrimLines: TStrings; //TSynEditStringTrimmingList;
{$ENDIF}
fLines: TStrings;
FFoldedLinesView: TSynEditFoldedView;
FTrimmedLinesView: TSynEditStringTrimmingList;
FTabbedLinesView: TSynEditStringTabExpander;
FTheLinesView: TStrings;
fLines: TStrings; // The real (un-mapped) line-buffer
fLinesInWindow: Integer;// MG: fully visible lines in window
fLeftChar: Integer; // first visible screen column
fMaxLeftChar: Integer; // 1024
@ -706,7 +708,7 @@ type
function GetSelStart: integer;
procedure SetSelEnd(const Value: integer);
procedure SetSelStart(const Value: integer);
property TextView : TSynEditFoldedView read fTextView;
property TextView : TSynEditFoldedView read FFoldedLinesView;
property TopView: Integer read GetTopView write SetTopView; // TopLine converted into Visible(View) lines
{$ENDIF}
public
@ -873,8 +875,8 @@ type
property LinesInWindow: Integer read fLinesInWindow; // MG: fully visible lines
property LineText: string read GetLineText write SetLineText;
{$IFDEF SYN_LAZARUS}
property RealLines: TStrings read fLines write SetRealLines; // No trailing (trimmable) spaces
property Lines: TStrings read fTrimLines write SetLines;
property RealLines: TStrings read FLines write SetRealLines; // No trailing (trimmable) spaces
property Lines: TStrings read FTheLinesView write SetLines;
{$ELSE}
property Lines: TStrings read fLines write SetLines;
{$ENDIF}
@ -1247,8 +1249,8 @@ function TCustomSynEdit.ScreenRowToRow(ScreenRow: integer): integer;
// ScreenRow is 0-base
// result is 1-based
begin
Result := fTextView.ScreenLineToTextIndex(ScreenRow)+1;
// DebugLn(['=== SrceenRow TO Row In:',ScreenRow,' out:',Result, ' topline=',TopLine, ' view topline=',fTextView.TopLine]);
Result := FFoldedLinesView.ScreenLineToTextIndex(ScreenRow)+1;
// DebugLn(['=== SrceenRow TO Row In:',ScreenRow,' out:',Result, ' topline=',TopLine, ' view topline=',FFoldedLinesView.TopLine]);
end;
function TCustomSynEdit.RowToScreenRow(PhysicalRow: integer): integer;
@ -1257,7 +1259,7 @@ function TCustomSynEdit.RowToScreenRow(PhysicalRow: integer): integer;
// 0 to LinesInWindow for visible lines (incl last partial visble line)
// and returns LinesInWindow+1 for lines below visible screen
begin
Result := fTextView.TextIndexToScreenLine(PhysicalRow-1);
Result := FFoldedLinesView.TextIndexToScreenLine(PhysicalRow-1);
if Result < -1 then Result := -1;
if Result > LinesInWindow+1 then Result := LinesInWindow+1;
// DebugLn(['=== Row TO ScreenRow In:',PhysicalRow,' out:',Result]);
@ -1396,21 +1398,26 @@ end;
constructor TCustomSynEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{begin} //mh 2000-10-10
// fLines := TSynEditList.Create;
fLines := TSynEditStringList.Create;
{$IFDEF SYN_LAZARUS}
fCaret := TSynEditCaret.Create;
fTrimLines := TSynEditStringTrimmingList.Create(TSynEditStrings(fLines),
fCaret);
fCaret.Lines := TSynEditStrings(fTrimLines);
fTextView := TSynEditFoldedView.Create(TSynEditStringList(fLines),
TSynEditStrings(fTrimLines),
fCaret);
fTextView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged;
{$ENDIF}
// with TSynEditList(fLines) do begin
// Create the lines/views
FTrimmedLinesView := TSynEditStringTrimmingList.Create
(TSynEditStrings(fLines), fCaret);
FTabbedLinesView := TSynEditStringTabExpander.Create
(TSynEditStrings(FTrimmedLinesView));
FFoldedLinesView := TSynEditFoldedView.Create
(TSynEditStrings(FTabbedLinesView), fCaret);
FFoldedLinesView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged;
// Pointer to the First/Lowest View
// TODO: this should be Folded...
FTheLinesView := FTabbedLinesView;
fCaret.Lines := TSynEditStrings(FTheLinesView);
with TSynEditStringList(fLines) do begin
OnAdded := {$IFDEF FPC}@{$ENDIF}ListAdded;
OnChange := {$IFDEF FPC}@{$ENDIF}LinesChanged;
@ -1421,17 +1428,16 @@ begin
OnPutted := {$IFDEF FPC}@{$ENDIF}ListPutted;
// OnScanRanges := {$IFDEF FPC}@{$ENDIF}ListScanRanges;
end;
{end} //mh 2000-10-10
fFontDummy := TFont.Create;
fUndoList := TSynEditUndoList.Create;
fUndoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded;
fRedoList := TSynEditUndoList.Create;
fRedoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).UndoList := fUndoList;
{$ENDIF}
FBlockSelection := TSynEditSelection.Create(TSynEditStrings(FTrimLines));
FTrimmedLinesView.UndoList := fUndoList;
FBlockSelection := TSynEditSelection.Create(TSynEditStrings(FTheLinesView));
FBlockSelection.Caret := FCaret;
FBlockSelection.UndoList := fUndoList;
FBlockSelection.InvalidateLinesMethod := {$IFDEF FPC}@{$ENDIF}InvalidateLines;
@ -1454,7 +1460,7 @@ begin
fBookMarkOpt.OnChange := {$IFDEF FPC}@{$ENDIF}BookMarkOptionsChanged;
// fRightEdge has to be set before FontChanged is called for the first time
fRightEdge := 80;
fGutter := TSynGutter.Create(self, fTextView, fBookMarkOpt, fTextDrawer);
fGutter := TSynGutter.Create(self, FFoldedLinesView, fBookMarkOpt, fTextDrawer);
fGutter.OnChange := {$IFDEF FPC}@{$ENDIF}GutterChanged;
fGutterWidth := fGutter.Width;
fTextOffset := fGutterWidth + 2;
@ -1534,7 +1540,7 @@ begin
fLeftChar := 1;
fTopLine := 1;
{$IFDEF SYN_LAZARUS}
fTextView.TopLine := 1;
FFoldedLinesView.TopLine := 1;
{$ELSE}
fCaretX := 1;
fCaretY := 1;
@ -1543,8 +1549,8 @@ begin
// find / replace
fTSearch := TSynEditSearch.Create;
fOptions := SYNEDIT_DEFAULT_OPTIONS;
FTrimmedLinesView.Enabled := eoTrimTrailingSpaces in fOptions;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).Enabled := eoTrimTrailingSpaces in fOptions;
fOptions2 := SYNEDIT_DEFAULT_OPTIONS2;
{$ENDIF}
fScrollTimer := TTimer.Create(Self);
@ -1602,7 +1608,7 @@ begin
{$ENDIF}
end;
{$IFDEF SYN_LAZARUS}
fTextView.UnLock; // after ScanFrom, but before UpdateCaret
FFoldedLinesView.UnLock; // after ScanFrom, but before UpdateCaret
{$ENDIF}
Dec(fPaintLock);
if (fPaintLock = 0) and HandleAllocated then begin
@ -1649,7 +1655,10 @@ begin
fTextDrawer.Free;
fFontDummy.Free;
fBlockSelection.Free;
FTabbedLinesView.Free;
FTrimmedLinesView.Free;
Lines.Free;
fCaret.Free;
{$ELSE}
fHookedCommandHandlers:=nil;
fPlugins:=nil;
@ -1664,9 +1673,10 @@ begin
FreeAndNil(fGutter);
FreeAndNil(fTextDrawer);
FreeAndNil(fFontDummy);
FreeAndNil(fTextView);
FreeAndNil(FFoldedLinesView);
FreeAndNil(fBlockSelection);
FreeAndNil(fTrimLines);
FreeAndNil(FTabbedLinesView);
FreeAndNil(FTrimmedLinesView);
FreeAndNil(fLines);
FreeAndNil(fCaret);
{$ENDIF}
@ -1799,7 +1809,7 @@ end;
procedure TCustomSynEdit.SetRealLines(const AValue : TStrings);
begin
if HandleAllocated then
fLines.Assign(AValue);
FLines.Assign(AValue);
end;
procedure TCustomSynEdit.SetUseIncrementalColor(const AValue : Boolean);
@ -1839,12 +1849,12 @@ end;
procedure TCustomSynEdit.SetCFDividerDrawLevel(const AValue: Integer);
begin
fTextView.CFDividerDrawLevel := AValue;
FFoldedLinesView.CFDividerDrawLevel := AValue;
end;
function TCustomSynEdit.GetCFDividerDrawLevel : Integer;
begin
Result := fTextView.CFDividerDrawLevel;
Result := FFoldedLinesView.CFDividerDrawLevel;
end;
procedure TCustomSynEdit.SetLogicalCaretXY(const NewLogCaretXY: TPoint);
@ -1953,7 +1963,7 @@ procedure TCustomSynEdit.IncPaintLock;
begin
inc(fPaintLock);
{$IFDEF SYN_LAZARUS}
fTextView.Lock; //DecPaintLock triggers ScanFrom, and folds must wait
FFoldedLinesView.Lock; //DecPaintLock triggers ScanFrom, and folds must wait
{$ENDIF}
end;
@ -2470,7 +2480,7 @@ begin
else
TopView := TopView + fScrollDeltaY;
if fScrollDeltaY > 0
then Y := fTextView.TextIndex[LinesInWindow-1]+1 // scrolling down
then Y := FFoldedLinesView.TextIndex[LinesInWindow-1]+1 // scrolling down
else Y := TopLine; // scrolling up
{$ELSE}
if GetKeyState(VK_SHIFT) < 0 then
@ -2605,7 +2615,7 @@ begin
{$ENDIF}
);
nL2 := Min({$IFDEF SYN_LAZARUS}
(rcClip.Bottom-1) div fTextHeight, fTextView.Count - fTextView.TopLine
(rcClip.Bottom-1) div fTextHeight, FFoldedLinesView.Count - FFoldedLinesView.TopLine
{$ELSE}
TopLine + (rcClip.Bottom + fTextHeight - 1) div fTextHeight, Lines.Count
{$ENDIF}
@ -2648,10 +2658,10 @@ procedure TCustomSynEdit.CodeFoldAction(iLine: integer);
begin
if (iLine<=0) or (iLine>Lines.Count) then exit;
dec(iLine);
//DebugLn(['****** FoldAction at ',iLine,' scrline=',fTextView.TextIndexToScreenLine(iLine), ' type ', SynEditCodeFoldTypeNames[fTextView.FoldType[fTextView.TextIndexToScreenLine(iLine)]], ' view topline=',fTextView.TopLine ]);
case fTextView.FoldType[fTextView.TextIndexToScreenLine(iLine)] of
cfCollapsed : fTextView.UnFoldAtTextIndex(iLine);
cfExpanded : fTextView.FoldAtTextIndex(iLine);
//DebugLn(['****** FoldAction at ',iLine,' scrline=',FFoldedLinesView.TextIndexToScreenLine(iLine), ' type ', SynEditCodeFoldTypeNames[FFoldedLinesView.FoldType[FFoldedLinesView.TextIndexToScreenLine(iLine)]], ' view topline=',FFoldedLinesView.TopLine ]);
case FFoldedLinesView.FoldType[FFoldedLinesView.TextIndexToScreenLine(iLine)] of
cfCollapsed : FFoldedLinesView.UnFoldAtTextIndex(iLine);
cfExpanded : FFoldedLinesView.FoldAtTextIndex(iLine);
end;
end;
@ -2661,19 +2671,19 @@ function TCustomSynEdit.FindNextUnfoldedLine(iLine: integer; Down: boolean
begin
Result:=iLine;
while (Result>0) and (Result<=Lines.Count)
and (fTextView.FoldedAtTextIndex[Result-1]) do
and (FFoldedLinesView.FoldedAtTextIndex[Result-1]) do
if Down then inc(Result) else dec(Result);
end;
procedure TCustomSynEdit.UnfoldAll;
begin
fTextView.UnfoldAll;
FFoldedLinesView.UnfoldAll;
Invalidate;
end;
procedure TCustomSynEdit.FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
begin
fTextView.FoldAll(StartLevel, IgnoreNested);
FFoldedLinesView.FoldAll(StartLevel, IgnoreNested);
Invalidate;
end;
{$ENDIF}
@ -2928,8 +2938,8 @@ var
eolx := rcToken.Left; // remeber end of actual line, so we can decide to draw the right edge
NextPos := Min(LastCol, TokenAccu.PhysicalEndPos+1);
Repeat
MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(fTextView.TextIndex[CurLine]+1, NextPos);
NextPos := fMarkupManager.GetNextMarkupColAfterRowCol(fTextView.TextIndex[CurLine]+1, NextPos);
MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(FFoldedLinesView.TextIndex[CurLine]+1, NextPos);
NextPos := fMarkupManager.GetNextMarkupColAfterRowCol(FFoldedLinesView.TextIndex[CurLine]+1, NextPos);
with fTextDrawer do
if MarkupInfo = nil
@ -3137,7 +3147,7 @@ var
{TODO: cache NextPhysPos, and MarkupInfo between 2 calls }
while (nTokenByteLen > 0) do begin
// Calculate Token Sublen for current Markup
NextPhysPos := fMarkupManager.GetNextMarkupColAfterRowCol(fTextView.TextIndex[CurLine]+1, PhysicalStartPos);
NextPhysPos := fMarkupManager.GetNextMarkupColAfterRowCol(FFoldedLinesView.TextIndex[CurLine]+1, PhysicalStartPos);
if NextPhysPos < 1
then SubCharLen := TokenCharLen
else SubCharLen := NextPhysPos - PhysicalStartPos;
@ -3160,7 +3170,7 @@ var
FG := DefaultFGCol;
FC := DefaultFCCol;
Style := DefaultStyle;
MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(fTextView.TextIndex[CurLine]+1, PhysicalStartPos);
MarkupInfo := fMarkupManager.GetMarkupAttributeAtRowCol(FFoldedLinesView.TextIndex[CurLine]+1, PhysicalStartPos);
if assigned(MarkupInfo)
then MarkupInfo.ModifyColors(FG, BG, FC, Style);
// Deal with equal colors
@ -3222,9 +3232,9 @@ var
LastFSX := -1;
LastFEX := -1;
fMarkupManager.PrepareMarkupForRow(fTextView.TextIndex[CurLine]+1);
fMarkupManager.PrepareMarkupForRow(FFoldedLinesView.TextIndex[CurLine]+1);
// Get the line.
sLine := fTextView[CurLine];
sLine := FFoldedLinesView[CurLine];
// Update the rcLine rect to this line.
rcLine.Top := rcLine.Bottom;
Inc(rcLine.Bottom, fTextHeight);
@ -3240,8 +3250,8 @@ var
// Initialize highlighter with line text and range info. It is
// necessary because we probably did not scan to the end of the last
// line - the internal highlighter range might be wrong.
fHighlighter.SetRange(fTextView.Ranges[CurLine]); //mh 2000-10-10
fHighlighter.SetLine(sLine, fTextView.TextIndex[CurLine]);
fHighlighter.SetRange(FFoldedLinesView.Ranges[CurLine]); //mh 2000-10-10
fHighlighter.SetLine(sLine, FFoldedLinesView.TextIndex[CurLine]);
// Try to concatenate as many tokens as possible to minimize the count
// of ExtTextOut calls necessary. This depends on the selection state
// or the line having special colors. For spaces the foreground color
@ -3262,11 +3272,11 @@ var
// of the invalid area with the correct colors.
PaintHighlightToken(TRUE);
fMarkupManager.FinishMarkupForRow(fTextView.TextIndex[CurLine]+1);
fMarkupManager.FinishMarkupForRow(FFoldedLinesView.TextIndex[CurLine]+1);
// codefold draw splitter line
if Gutter.ShowCodeFolding
and (fTextView.DrawDivider[curLine]) then
and (FFoldedLinesView.DrawDivider[curLine]) then
begin
ypos := rcToken.Bottom - 1;
LCLIntf.MoveToEx(dc, nRightEdge, ypos, nil);
@ -3371,7 +3381,7 @@ begin
// codefold draw splitter line
if Gutter.ShowCodeFolding
and (fTextView.DrawDivider[LastLine]) then
and (FFoldedLinesView.DrawDivider[LastLine]) then
begin
ypos := rcToken.Bottom - 1;
LCLIntf.MoveToEx(dc, nRightEdge, ypos, nil);
@ -4287,7 +4297,7 @@ end;
procedure TCustomSynEdit.SetLines(Value: TStrings);
begin
if HandleAllocated then
Lines.Assign(Value);
FTheLinesView.Assign(Value);
end;
procedure TCustomSynEdit.SetLineText(Value: string);
@ -4331,7 +4341,7 @@ procedure TCustomSynEdit.SetSelTextPrimitive(PasteMode: TSynSelectionMode;
ChangeReason: TSynChangeReason = crInsert);
Begin
IncPaintLock;
TSynEditStringTrimmingList(fTrimLines).Lock;
FTrimmedLinesView.Lock;
try
FBlockSelection.SetSelTextPrimitive(PasteMode, Value, AddToUndoList,
ChangeReason);
@ -4342,7 +4352,7 @@ Begin
Include(fStatusChanges, scCaretX);
EnsureCursorPosVisible;
finally
TSynEditStringTrimmingList(fTrimLines).UnLock;
FTrimmedLinesView.UnLock;
DecPaintLock;
end;
end;
@ -4351,7 +4361,7 @@ procedure TCustomSynEdit.SetSelTextExternal(const Value: string);
begin
// undo entry added
BeginUndoBlock;
TSynEditStringTrimmingList(fTrimLines).Lock;
FTrimmedLinesView.Lock;
try
FBlockSelection.SelText := Value;
// Force caret reset
@ -4361,7 +4371,7 @@ begin
Include(fStatusChanges, scCaretX);
EnsureCursorPosVisible;
finally
TSynEditStringTrimmingList(fTrimLines).UnLock;
FTrimmedLinesView.UnLock;
EndUndoBlock;
end;
end;
@ -4391,20 +4401,20 @@ begin
Value := Min(Value, Lines.Count)
else
{$ifdef SYN_LAZARUS}
Value := Min(Value, fTextView.TextPosAddLines(Lines.Count+1, -fLinesInWindow));
Value := Min(Value, FFoldedLinesView.TextPosAddLines(Lines.Count+1, -fLinesInWindow));
{$ELSE}
Value := Min(Value, Lines.Count + 1 - fLinesInWindow);
{$ENDIF}
Value := Max(Value, 1);
{$IFDEF SYN_LAZARUS}
if fTextView.FoldedAtTextIndex[Value-1] then
if FFoldedLinesView.FoldedAtTextIndex[Value-1] then
Value := FindNextUnfoldedLine(Value, False);
{$ENDIF}
if Value <> fTopLine then begin
{$ifdef SYN_LAZARUS}
OldTopLine:=TopLine;
fTopLine := Value;
fTextView.TopTextIndex := Value-1;
FFoldedLinesView.TopTextIndex := Value-1;
UpdateScrollBars;
Delta := OldTopLine - TopLine;
if (Abs(Delta) < fLinesInWindow) and not (sfPainting in fStateFlags)
@ -4588,7 +4598,7 @@ begin
{$ENDIF}
end;
if fScrollBars in [ssBoth, ssVertical] then begin
nMaxScroll := {$IFDEF SYN_LAZARUS}fTextView.Count+1{$ELSE}Lines.Count{$ENDIF};
nMaxScroll := {$IFDEF SYN_LAZARUS}FFoldedLinesView.Count+1{$ELSE}Lines.Count{$ENDIF};
if (eoScrollPastEof in Options) then
Inc(nMaxScroll, LinesInWindow - 1);
{$IFNDEF SYN_LAZARUS}
@ -4597,7 +4607,7 @@ begin
ScrollInfo.nMax := Max(1, nMaxScroll);
ScrollInfo.nPage := LinesInWindow;
{$IFDEF SYN_LAZARUS}
ScrollInfo.nPos := fTextView.TextIndexToViewPos(TopLine-1);
ScrollInfo.nPos := FFoldedLinesView.TextIndexToViewPos(TopLine-1);
{$ELSE}
ScrollInfo.nPos := TopLine;
{$ENDIF}
@ -4878,7 +4888,7 @@ begin
Result := Index;
{$IFDEF SYN_LAZARUS}
if not assigned(fHighlighter) or (Index > Lines.Count - 1) then begin
fTextView.FixFoldingAtTextIndex(Index);
FFoldedLinesView.FixFoldingAtTextIndex(Index);
fMarkupManager.TextChangedScreen(Max(RowToScreenRow(Index+1), 0), LinesInWindow+1);
Topline := TopLine;
exit;
@ -4892,7 +4902,7 @@ begin
end;
{$ENDIF}
if Index >= Lines.Count - 1 then begin
fTextView.FixFoldingAtTextIndex(Index);
FFoldedLinesView.FixFoldingAtTextIndex(Index);
fMarkupManager.TextChangedScreen(Max(RowToScreenRow(Index+1), 0), LinesInWindow+1);
Topline := TopLine;
Exit;
@ -4938,7 +4948,7 @@ begin
// => update code fold attributes of last scanned line
if (Result>Index+1) and (Result<=Lines.Count) then
SetCodeFoldAttributes;
fTextView.FixFoldingAtTextIndex(FixFStart, Result);
FFoldedLinesView.FixFoldingAtTextIndex(FixFStart, Result);
fMarkupManager.TextChangedScreen(Max(RowToScreenRow(FixFStart+1), 0),
Min(RowToScreenRow(Result), LinesInWindow+1));
Topline := TopLine;
@ -5100,7 +5110,7 @@ var
i: Integer;
begin
TopLine := TopLine;
i := fTextView.CollapsedLineForFoldAtLine(CaretY);
i := FFoldedLinesView.CollapsedLineForFoldAtLine(CaretY);
if i > 0 then
SetCaretXY(Point(1, i))
else
@ -5114,12 +5124,12 @@ end;
procedure TCustomSynEdit.SetTopView(const AValue : Integer);
begin
TopLine := fTextView.ViewPosToTextIndex(AValue)+1;
TopLine := FFoldedLinesView.ViewPosToTextIndex(AValue)+1;
end;
function TCustomSynEdit.GetTopView : Integer;
begin
Result := fTextView.TextIndexToViewPos(TopLine-1);
Result := FFoldedLinesView.TextIndexToViewPos(TopLine-1);
end;
{$ENDIF}
@ -5618,7 +5628,7 @@ begin
{end} //mh 2000-11-20
end;
{$IFDEF SYN_LAZARUS}
crTrimSpace: TSynEditStringTrimmingList(fTrimLines).ForceTrim;
crTrimSpace: FTrimmedLinesView.ForceTrim;
{$ENDIF}
crLineBreak:
{begin} //sbs 2000-11-20
@ -5753,7 +5763,7 @@ begin
{$ENDIF}
finally
// Todo: Decide what do to, If there are any trimable spaces.
TSynEditStringTrimmingList(fTrimLines).ForceTrim;
FTrimmedLinesView.ForceTrim;
fUndoList.UnLock;
{$IFDEF SYN_LAZARUS}
fRedoList.EndBlock;
@ -5843,7 +5853,7 @@ begin
EnsureCursorPosVisible;
end;
crTrimRealSpace:
TSynEditStringTrimmingList(fTrimLines).UndoRealSpaces(Item);
FTrimmedLinesView.UndoRealSpaces(Item);
crLineBreak:
begin
// If there's no selection, we have to set
@ -6431,7 +6441,7 @@ begin
TopLine := CaretY
{$IFDEF SYN_LAZARUS}
else if CaretY > ScreenRowToRow(Max(1, LinesInWindow) - 1) then //mh 2000-10-19
TopLine := fTextView.TextPosAddLines(CaretY, -Max(0, LinesInWindow-1))
TopLine := FFoldedLinesView.TextPosAddLines(CaretY, -Max(0, LinesInWindow-1))
{$ELSE}
else if CaretY > TopLine + Max(1, LinesInWindow) - 1 then //mh 2000-10-19
TopLine := CaretY - (LinesInWindow - 1)
@ -6709,7 +6719,7 @@ begin
ecEditorBottom, ecSelEditorBottom:
begin
{$IFDEF SYN_LAZARUS}
CaretNew := Point(1, fTextView.ViewPosToTextIndex(fTextView.Count)+1);
CaretNew := Point(1, FFoldedLinesView.ViewPosToTextIndex(FFoldedLinesView.Count)+1);
{$ELSE}
CaretNew := Point(1, Lines.Count);
{$ENDIF}
@ -6742,7 +6752,7 @@ begin
Caret := CaretXY;
CaretNew := PrevWordPos;
{$IFDEF SYN_LAZARUS}
if fTextView.FoldedAtTextIndex[CaretNew.Y - 1] then begin
if FFoldedLinesView.FoldedAtTextIndex[CaretNew.Y - 1] then begin
CY := FindNextUnfoldedLine(CaretNew.Y, False);
CaretNew := LogicalToPhysicalPos(Point(1 + Length(Lines[CY-1]), CY));
end;
@ -6761,7 +6771,7 @@ begin
Caret := CaretXY;
CaretNew := NextWordPos;
{$IFDEF SYN_LAZARUS}
if fTextView.FoldedAtTextIndex[CaretNew.Y - 1] then
if FFoldedLinesView.FoldedAtTextIndex[CaretNew.Y - 1] then
CaretNew := Point(1, FindNextUnfoldedLine(CaretNew.Y, True));
MoveCaretAndSelectionPhysical
{$ELSE}
@ -7493,14 +7503,14 @@ begin
UnfoldAll;
EcFoldCurrent:
begin
CY := fTextView.ExpandedLineForBlockAtLine(CaretY);
CY := FFoldedLinesView.ExpandedLineForBlockAtLine(CaretY);
if CY > 0 then begin
fTextView.FoldAtTextIndex(CY-1);
FFoldedLinesView.FoldAtTextIndex(CY-1);
SetCaretXY(Point(1, CY));
end;
end;
EcUnFoldCurrent:
fTextView.UnFoldAtTextIndex(CaretY-1);
FFoldedLinesView.UnFoldAtTextIndex(CaretY-1);
{$ENDIF}
end;
finally
@ -7787,8 +7797,8 @@ begin
fUndoList.BeginBlock;
{$IFDEF SYN_LAZARUS}
IncPaintLock;
fTextView.Lock;
TSynEditStringTrimmingList(fTrimLines).Lock;
FFoldedLinesView.Lock;
FTrimmedLinesView.Lock;
{$ENDIF}
end;
{end} //sbs 2000-11-19
@ -7804,8 +7814,8 @@ begin
{$IFDEF SYN_LAZARUS}
// Write all trimming info to the end of the undo block,
// so it will be undone first, and other UndoItems do see the expected spaces
TSynEditStringTrimmingList(fTrimLines).UnLock;
fTextView.UnLock;
FTrimmedLinesView.UnLock;
FFoldedLinesView.UnLock;
// must be last => May call MoveCaretToVisibleArea, which must only happen
// after unfold
DecPaintLock;
@ -8101,10 +8111,11 @@ end;
procedure TCustomSynEdit.SetTabWidth(Value: integer);
begin
Value := MinMax(Value, 1{0}, 256); //lt 2000-10-19
Value := MinMax(Value, 1{0}, 256);
if (Value <> fTabWidth) then begin
fTabWidth := Value;
TSynEditStringList(fLines).TabWidth := Value; //mh 2000-10-19
FTabbedLinesView.TabWidth := Value;
FBlockSelection.TabWidth := Value;
Invalidate; // to redraw text containing tab chars
end;
end;
@ -8430,9 +8441,7 @@ begin
{$ENDIF}
bSetDrag := (eoDropFiles in fOptions) <> (eoDropFiles in Value);
fOptions := Value;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).Enabled := eoTrimTrailingSpaces in fOptions;
{$ENDIF}
FTrimmedLinesView.Enabled := eoTrimTrailingSpaces in fOptions;
// Reset column position in case Cursor is past EOL.
if not (eoScrollPastEol in fOptions) then
CaretX := CaretX;
@ -8508,7 +8517,7 @@ begin
fCharsInWindow := Max(1,(ClientWidth - fGutterWidth - 2 - ScrollBarWidth)
div fCharWidth);
fLinesInWindow := Max(0,ClientHeight - ScrollBarWidth) div Max(1,fTextHeight);
fTextView.LinesInWindow := fLinesInWindow;
FFoldedLinesView.LinesInWindow := fLinesInWindow;
fMarkupManager.LinesInWindow:= fLinesInWindow;
//DebugLn('TCustomSynEdit.SizeOrFontChanged fLinesInWindow=',dbgs(fLinesInWindow),' ClientHeight=',dbgs(ClientHeight),' ',dbgs(fTextHeight));
@ -8551,7 +8560,7 @@ begin
NewCaret.X:=1
else begin
// move to end of prev line
NewCaret.Y:= fTextView.TextPosAddLines(NewCaret.Y, -1);
NewCaret.Y:= FFoldedLinesView.TextPosAddLines(NewCaret.Y, -1);
s:=Lines[NewCaret.Y-1];
PhysicalLineLen:=LogicalToPhysicalPos(Point(length(s)+1,NewCaret.Y)).X-1;
NewCaret.X:=PhysicalLineLen+1;
@ -8562,7 +8571,7 @@ begin
if NewCaret.X>PhysicalLineLen+1 then begin
// move to start of next line
NewCaret.X:=1;
NewCaret.Y:=fTextView.TextPosAddLines(NewCaret.Y, +1);
NewCaret.Y:=FFoldedLinesView.TextPosAddLines(NewCaret.Y, +1);
end;
end;
@ -8639,7 +8648,7 @@ var
begin
OldCaret:=CaretXY;
NewCaret:=OldCaret;
NewCaret.Y:=fTextView.TextPosAddLines(NewCaret.Y, DY);
NewCaret.Y:=FFoldedLinesView.TextPosAddLines(NewCaret.Y, DY);
if (OldCaret.Y<>NewCaret.Y) and (fLastCaretX>0) and (eoKeepCaretX in Options)
then
NewCaret.X:=fLastCaretX;
@ -8986,7 +8995,7 @@ begin
inc(BB.x, fBlockIndent);
BE.x := x;
end;
TSynEditStringTrimmingList(fTrimLines).ForceTrim; // Otherwise it may reset the block
FTrimmedLinesView.ForceTrim; // Otherwise it may reset the block
SetCaretAndSelection(LogicalToPhysicalPos(BE), BB, BE);
{$ELSE}
SetCaretAndSelection(OrgCaretPos,
@ -9143,7 +9152,7 @@ begin
dec(BB.x, FirstIndent);
dec(BE.x, LastIndent);
end;
TSynEditStringTrimmingList(fTrimLines).ForceTrim; // Otherwise it may reset the block
FTrimmedLinesView.ForceTrim; // Otherwise it may reset the block
SetCaretAndSelection(LogicalToPhysicalPos(BE), BB, BE);
{$ELSE}
if FirstIndent = -1 then

View File

@ -201,7 +201,7 @@ type
function FixFolding(AStart : Integer; AMinEnd : Integer; aFoldTree : TSynTextFoldAVLTree) : Boolean;
procedure DoCaretChanged(Sender : TObject);
Procedure LineCountChanged(AIndex, ACount : Integer);
Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
Procedure LinesInsertedAtTextIndex(AStartIndex, ALineCount : Integer;
SkipFixFolding : Boolean = False);
Procedure LinesInsertedAtViewPos(AStartPos, ALineCount : Integer;
@ -211,7 +211,7 @@ type
Procedure LinesDeletedAtViewPos(AStartPos, ALineCount : Integer;
SkipFixFolding : Boolean = False);
public
constructor Create(aTextBuffer : TSynEditStringList; aTextView : TSynEditStrings; ACaret: TSynEditCaret);
constructor Create(aTextView : TSynEditStrings; ACaret: TSynEditCaret);
destructor Destroy; override;
// Converting between Folded and Unfolded Lines/Indexes
@ -1390,20 +1390,21 @@ end;
{ TSynEditFoldedView }
constructor TSynEditFoldedView.Create(aTextBuffer : TSynEditStringList; aTextView : TSynEditStrings; ACaret: TSynEditCaret);
constructor TSynEditFoldedView.Create(aTextView : TSynEditStrings; ACaret: TSynEditCaret);
begin
fCaret := ACaret;
fCaret.AddChangeHandler(@DoCaretChanged);
fCaret.AddChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged);
fLines := aTextView;
fFoldTree := TSynTextFoldAVLTree.Create;
fTopLine := 0;
fLinesInWindow := -1;
aTextBuffer.OnLineCountChanged := {$IFDEF FPC}@{$ENDIF}LineCountChanged;
fLines.AddChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
end;
destructor TSynEditFoldedView.Destroy;
begin
fCaret.RemoveChangeHandler(@DoCaretChanged);
fLines.RemoveChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
fCaret.RemoveChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged);
fFoldTree.Free;
fTextIndexList := nil;
fFoldTypeList := nil;
@ -1849,7 +1850,7 @@ begin
UnFoldAtTextIndex(i, true);
end;
procedure TSynEditFoldedView.LineCountChanged(AIndex, ACount : Integer);
procedure TSynEditFoldedView.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
begin
// no need for fix folding => synedit will be called, and scanlines will call fixfolding
{TODO: a "need fix folding" flag => to ensure it will be called if synedit doesnt}

View File

@ -84,10 +84,10 @@ function ConvertTabs(const Line: AnsiString; TabWidth: integer): AnsiString;
{begin} //mh 2000-10-19
type
TConvertTabsProcEx = function(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): AnsiString;
out HasTabs: boolean): AnsiString;
{$IFDEF SYN_LAZARUS}
TSimulateConvertTabsProcEx = function(const Line: AnsiString;
TabWidth: integer; var HasTabs: boolean): integer;
TabWidth: integer; out HasTabs: boolean): integer;
// returns length of converted string
{$ENDIF}
@ -98,7 +98,7 @@ function GetBestSimulateConvertTabsProcEx(
{$ENDIF}
// This is the slowest conversion function which can handle TabWidth <> 2^n.
function ConvertTabsEx(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): AnsiString;
out HasTabs: boolean): AnsiString;
{end} //mh 2000-10-19
function CharIndex2CaretPos(Index, TabWidth: integer;
@ -268,7 +268,7 @@ end;
{begin} //mh 2000-10-19
function ConvertTabs1Ex(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): AnsiString;
out HasTabs: boolean): AnsiString;
var
pDest: PChar;
nBeforeTab: integer;
@ -289,7 +289,7 @@ end;
{$IFDEF SYN_LAZARUS}
function SimulateConvertTabs1Ex(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): integer;
out HasTabs: boolean): integer;
// TabWidth=1
var
i: integer;
@ -309,7 +309,7 @@ begin
end;
function ConvertTabs2nEx(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): AnsiString;
out HasTabs: boolean): AnsiString;
var
i, DestLen, TabCount, TabMask: integer;
pSrc, pDest: PChar;
@ -369,7 +369,7 @@ end;
{$IFDEF SYN_LAZARUS}
function SimulateConvertTabs2nEx(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): integer;
out HasTabs: boolean): integer;
var
LineLen, DestLen, SrcPos, TabMask: integer;
begin
@ -404,7 +404,7 @@ begin
end;
function ConvertTabsEx(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): AnsiString;
out HasTabs: boolean): AnsiString;
var
i, DestLen, TabCount: integer;
pSrc, pDest: PChar;
@ -461,7 +461,7 @@ end;
{$IFDEF SYN_LAZARUS}
function SimulateConvertTabsEx(const Line: AnsiString; TabWidth: integer;
var HasTabs: boolean): integer;
out HasTabs: boolean): integer;
var
LineLen, DestLen, SrcPos: integer;
begin

View File

@ -72,6 +72,7 @@ type
FLinesInsertedMethod: TLinesCountChanged;
FEnabled: Boolean;
FSpacesToTabs: Boolean;
FTabWidth: Integer;
FActiveSelectionMode: TSynSelectionMode;
FSelectionMode: TSynSelectionMode;
FStartLinePos: Integer; // 1 based
@ -124,6 +125,8 @@ type
property LinesInsertedMethod: TLinesCountChanged write FLinesInsertedMethod;
property Caret: TSynEditCaret read FCaret write FCaret;
property UndoList: TSynEditUndoList read fUndoList write fUndoList;
// TODO: Move dependend functions to Lines
property TabWidth: integer read FTabWidth write FTabWidth;
end;
{ TSynEditCaret }
@ -568,8 +571,7 @@ var
sLeftSide := sLeftSide
+ CreateTabsAndSpaces(FCaret.CharPos,
FCaret.CharPos-1-PhysicalLineEndPos,
FLines.TabWidth,
FSpacesToTabs);
FTabWidth, FSpacesToTabs);
end;
sRightSide := Copy(FCaret.LineText, LogCaretXY.X,
Length(FCaret.LineText) - (LogCaretXY.X - 1));

View File

@ -21,7 +21,7 @@ of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
unit SynEditTextBase;
{$mode objfpc}{$H+}
{$I synedit.inc}
interface
@ -29,33 +29,124 @@ uses
Classes, SysUtils, LCLProc, SynEditTypes;
type
TSynEditStrings = class;
TStringListLineCountEvent = procedure(Sender: TSynEditStrings;
Index, Count: Integer) of object;
TSynEditNotifyReason = (senrLineCount, senrLineChange);
{ TSynEditStrings }
TSynEditStrings = class(TStrings)
protected
FTabWidth: integer;
FIsUtf8: Boolean;
function GetIsUtf8 : Boolean; virtual;
procedure SetIsUtf8(const AValue : Boolean); virtual;
function GetTabWidth : integer; virtual;
procedure SetTabWidth(const AValue : integer); virtual;
function GetFoldEndLevel(Index: integer): integer; virtual; abstract;
function GetFoldMinLevel(Index: integer): integer; virtual; abstract;
procedure SetFoldEndLevel(Index: integer; const AValue: integer); virtual; abstract;
procedure SetFoldMinLevel(Index: integer; const AValue: integer); virtual; abstract;
function GetRange(Index: integer): TSynEditRange; virtual; abstract;
procedure PutRange(Index: integer; ARange: TSynEditRange); virtual; abstract;
function GetAttribute(const Owner: TClass; const Index: Integer): Pointer; virtual; abstract;
procedure SetAttribute(const Owner: TClass; const Index: Integer; const AValue: Pointer); virtual; abstract;
procedure RegisterAttribute(const Index: TClass; const Size: Word); virtual; abstract;
function GetExpandedString(Index: integer): string; virtual; abstract;
function GetLengthOfLongestLine: integer; virtual; abstract;
procedure SetTextStr(const Value: string); override;
property Attribute[Owner: TClass; Index: Integer]: Pointer
read GetAttribute write SetAttribute;
public
constructor Create;
procedure DeleteLines(Index, NumLines: integer); virtual; abstract;
procedure InsertLines(Index, NumLines: integer); virtual; abstract;
procedure InsertStrings(Index: integer; NewStrings: TStrings); virtual; abstract;
procedure ClearRanges(ARange: TSynEditRange); virtual; abstract;
procedure AddChangeHandler(AReason: TSynEditNotifyReason;
AHandler: TStringListLineCountEvent); virtual; abstract;
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
AHandler: TStringListLineCountEvent); virtual; abstract;
public
// 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;
// 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;
public
property ExpandedStrings[Index: integer]: string read GetExpandedString;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8;
property Ranges[Index: integer]: TSynEditRange read GetRange write PutRange;
property FoldMinLevel[Index: integer]: integer read GetFoldMinLevel
write SetFoldMinLevel;
property FoldEndLevel[Index: integer]: integer read GetFoldEndLevel
write SetFoldEndLevel;
end;
{ TSynEditStringsLinked }
TSynEditStringsLinked = class(TSynEditStrings)
protected
fSynStrings: TSynEditStrings;
function GetIsUtf8 : Boolean; override;
procedure SetIsUtf8(const AValue : Boolean); override;
function GetFoldEndLevel(Index: integer): integer; override;
function GetFoldMinLevel(Index: integer): integer; override;
procedure SetFoldEndLevel(Index: integer; const AValue: integer); override;
procedure SetFoldMinLevel(Index: integer; const AValue: integer); override;
function GetRange(Index: integer): TSynEditRange; override;
procedure PutRange(Index: integer; ARange: TSynEditRange); override;
function GetAttribute(const Owner: TClass; const Index: Integer): Pointer; override;
procedure SetAttribute(const Owner: TClass; const Index: Integer; const AValue: Pointer); override;
// Size: 0 = Bit (TODO); 1..8 Size In Byte "SizeOf()"
procedure RegisterAttribute(const Index: TClass; const Size: Word); override;
protected
function GetCount: integer; override;
function GetCapacity: integer;
{$IFDEF SYN_COMPILER_3_UP} override; {$ELSE} virtual; {$ENDIF}
procedure SetCapacity(NewCapacity: integer);
{$IFDEF SYN_COMPILER_3_UP} override; {$ELSE} virtual; {$ENDIF}
function Get(Index: integer): string; override;
function GetObject(Index: integer): TObject; override;
procedure Put(Index: integer; const S: string); override;
procedure PutObject(Index: integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean); override;
public
constructor Create(ASynStringSource: TSynEditStrings);
function Add(const S: string): integer; override;
procedure AddStrings(AStrings: TStrings); override;
procedure Clear; override;
procedure Delete(Index: integer); override;
procedure DeleteLines(Index, NumLines: integer); override;
procedure Insert(Index: integer; const S: string); override;
procedure InsertLines(Index, NumLines: integer); override;
procedure InsertStrings(Index: integer; NewStrings: TStrings); override;
procedure Exchange(Index1, Index2: integer); override;
procedure ClearRanges(ARange: TSynEditRange); override;
procedure AddChangeHandler(AReason: TSynEditNotifyReason;
AHandler: TStringListLineCountEvent); override;
procedure RemoveChangeHandler(AReason: TSynEditNotifyReason;
AHandler: TStringListLineCountEvent); override;
(* public
// Byte to Char
function LogicalToPhysicalPos(const p: TPoint): TPoint;
function LogicalToPhysicalCol(const Line: string;
@ -68,19 +159,11 @@ type
PhysicalPos: integer): integer;
function PhysicalToLogicalCol(const Line: string;
PhysicalPos, StartBytePos, StartPhysicalPos: integer): integer;
public
property ExpandedStrings[Index: integer]: string read GetExpandedString;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
property TabWidth: integer read GetTabWidth write SetTabWidth;
property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8;
property Ranges[Index: integer]: TSynEditRange read GetRange write PutRange;
property FoldMinLevel[Index: integer]: integer read GetFoldMinLevel
write SetFoldMinLevel;
property FoldEndLevel[Index: integer]: integer read GetFoldEndLevel
write SetFoldEndLevel;
*)
end;
implementation
@ -89,7 +172,6 @@ implementation
constructor TSynEditStrings.Create;
begin
inherited Create;
TabWidth := 8;
IsUtf8 := True;
end;
@ -98,21 +180,11 @@ begin
Result := FIsUtf8;
end;
function TSynEditStrings.GetTabWidth : integer;
begin
Result := FTabWidth;
end;
procedure TSynEditStrings.SetIsUtf8(const AValue : Boolean);
begin
FIsUtf8 := AValue;
end;
procedure TSynEditStrings.SetTabWidth(const AValue : integer);
begin
FTabWidth := AValue;
end;
procedure TSynEditStrings.SetTextStr(const Value : string);
var
StartPos: Integer;
@ -165,21 +237,16 @@ var
ScreenPos: integer;
begin
ByteLen := LineLen;
// map UTF8 and Tab chars
// map UTF8
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(ScreenPos);
if IsUTF8 then
inc(BytePos,UTF8CharacterLength(@Line[BytePos-1]))
else
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);
@ -213,19 +280,14 @@ begin
ScreenPos := StartPhysicalPos;
BytePos := StartBytePos;
PLine := PChar(Line);
// map utf and tab chars
// map utf
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(ScreenPos);
if IsUTF8 then
inc(BytePos,UTF8CharacterLength(@PLine[BytePos-1]))
else
inc(BytePos);
end;
end else begin
// beyond end of line
inc(BytePos,PhysicalPos-ScreenPos);
@ -238,5 +300,175 @@ begin
Result := BytePos;
end;
{ TSynEditStringsLinked }
constructor TSynEditStringsLinked.Create(ASynStringSource: TSynEditStrings);
begin
fSynStrings := ASynStringSource;
Inherited Create;
end;
function TSynEditStringsLinked.Add(const S: string): integer;
begin
Result := fSynStrings.Add(S);
end;
procedure TSynEditStringsLinked.AddStrings(AStrings: TStrings);
begin
fSynStrings.AddStrings(AStrings);
end;
procedure TSynEditStringsLinked.Clear;
begin
fSynStrings.Clear;
end;
procedure TSynEditStringsLinked.Delete(Index: integer);
begin
fSynStrings.Delete(Index);
end;
procedure TSynEditStringsLinked.DeleteLines(Index, NumLines: integer);
begin
fSynStrings.DeleteLines(Index, NumLines);
end;
procedure TSynEditStringsLinked.Insert(Index: integer; const S: string);
begin
fSynStrings.Insert(Index, S);
end;
procedure TSynEditStringsLinked.InsertLines(Index, NumLines: integer);
begin
fSynStrings.InsertLines(Index, NumLines);
end;
procedure TSynEditStringsLinked.InsertStrings(Index: integer; NewStrings: TStrings);
begin
fSynStrings.InsertStrings(Index, NewStrings);
end;
procedure TSynEditStringsLinked.Exchange(Index1, Index2: integer);
begin
fSynStrings.Exchange(Index1, Index2);
end;
function TSynEditStringsLinked.GetIsUtf8: Boolean;
begin
Result := FSynStrings.IsUtf8;
end;
procedure TSynEditStringsLinked.SetIsUtf8(const AValue: Boolean);
begin
FSynStrings.IsUtf8 := AValue;
end;
//Fold
function TSynEditStringsLinked.GetFoldEndLevel(Index: integer): integer;
begin
Result:= fSynStrings.FoldEndLevel[Index];
end;
function TSynEditStringsLinked.GetFoldMinLevel(Index: integer): integer;
begin
Result:= fSynStrings.FoldMinLevel[Index];
end;
procedure TSynEditStringsLinked.SetFoldEndLevel(Index: integer; const AValue: integer);
begin
fSynStrings.FoldEndLevel[Index] := AValue;
end;
procedure TSynEditStringsLinked.SetFoldMinLevel(Index: integer; const AValue: integer);
begin
fSynStrings.FoldMinLevel[Index] := AValue;
end;
//Ranges
function TSynEditStringsLinked.GetRange(Index: integer): TSynEditRange;
begin
Result:= fSynStrings.Ranges[Index];
end;
procedure TSynEditStringsLinked.PutRange(Index: integer; ARange: TSynEditRange);
begin
fSynStrings.Ranges[Index] := ARange;
end;
function TSynEditStringsLinked.GetAttribute(const Owner: TClass; const Index: Integer): Pointer;
begin
Result := fSynStrings.Attribute[Owner, Index];
end;
procedure TSynEditStringsLinked.SetAttribute(const Owner: TClass;
const Index: Integer; const AValue: Pointer);
begin
fSynStrings.Attribute[Owner, Index] := AValue;
end;
procedure TSynEditStringsLinked.RegisterAttribute(const Index: TClass; const Size: Word);
begin
fSynStrings.RegisterAttribute(Index, Size);
end;
procedure TSynEditStringsLinked.ClearRanges(ARange: TSynEditRange);
begin
fSynStrings.ClearRanges(ARange);
end;
procedure TSynEditStringsLinked.AddChangeHandler(AReason: TSynEditNotifyReason; AHandler: TStringListLineCountEvent);
begin
fSynStrings.AddChangeHandler(AReason, AHandler);
end;
procedure TSynEditStringsLinked.RemoveChangeHandler(AReason: TSynEditNotifyReason; AHandler: TStringListLineCountEvent);
begin
fSynStrings.RemoveChangeHandler(AReason, AHandler);
end;
// Count
function TSynEditStringsLinked.GetCount: integer;
begin
Result:= fSynStrings.Count;
end;
function TSynEditStringsLinked.GetCapacity: integer;
begin
Result:= fSynStrings.Capacity;
end;
procedure TSynEditStringsLinked.SetCapacity(NewCapacity: integer);
begin
fSynStrings.Capacity := NewCapacity;
end;
function TSynEditStringsLinked.Get(Index: integer): string;
begin
Result:= fSynStrings.Get(Index);
end;
function TSynEditStringsLinked.GetObject(Index: integer): TObject;
begin
Result:= fSynStrings.GetObject(Index);
end;
procedure TSynEditStringsLinked.Put(Index: integer; const S: string);
begin
fSynStrings.Put(Index, S);
end;
procedure TSynEditStringsLinked.PutObject(Index: integer; AObject: TObject);
begin
fSynStrings.PutObject(Index, AObject);
end;
procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean);
begin
if Updating then
fSynStrings.BeginUpdate
else
fSynStrings.EndUpdate;
end;
end.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,258 @@
unit SynEditTextTabExpander;
{$I synedit.inc}
interface
uses
LCLProc,
Classes, SysUtils, SynEditTypes, SynEditTextBase, SynEditTextBuffer,
SynEditMiscClasses, SynEditMiscProcs;
const
// Offset to add to LengthOfLine, if Line has no tabs.
// (Length will still be valid if tab-width changes)
NoTabLengthOffset = MaxInt div 2;
type
{ TSynEditStringTabExpander }
TSynEditStringTabExpander = class(TSynEditStringsLinked)
private
FTabWidth: integer;
FConvertTabsProc: TConvertTabsProcEx;
FSimulateConvertTabsProc: TSimulateConvertTabsProcEx;
FIndexOfLongestLine: Integer;
function GetLengthOfLine(Index: Integer): integer;
procedure SetLengthOfLine(Index: Integer; const AValue: integer);
Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
function ExpandedString(Index: integer): string;
function ExpandedStringLength(Index: integer): Integer;
protected
function GetTabWidth : integer;
procedure SetTabWidth(const AValue : integer);
function GetExpandedString(Index: integer): string; override;
function GetLengthOfLongestLine: integer; override;
property LengthOfLine[Index: Integer]: integer
read GetLengthOfLine write SetLengthOfLine;
public
constructor Create(ASynStringSource: TSynEditStrings);
destructor Destroy; override;
property ExpandedStrings[Index: integer]: string read GetExpandedString;
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;
implementation
{ TSynEditStringTabExpander }
constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings);
begin
FIndexOfLongestLine := -1;
inherited Create(ASynStringSource);
RegisterAttribute(TSynEditStringTabExpander, SizeOf(Integer));
FTabWidth := 8;
fSynStrings.AddChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
fSynStrings.AddChangeHandler(senrLineChange, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
end;
destructor TSynEditStringTabExpander.Destroy;
begin
fSynStrings.RemoveChangeHandler(senrLineChange, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
fSynStrings.RemoveChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
inherited Destroy;
end;
function TSynEditStringTabExpander.GetLengthOfLine(Index: Integer): integer;
begin
Result := Integer(PtrUInt(Attribute[TSynEditStringTabExpander, Index]));
end;
procedure TSynEditStringTabExpander.SetLengthOfLine(Index: Integer; const AValue: integer);
begin
Attribute[TSynEditStringTabExpander, Index] := Pointer(PtrUInt(AValue));
end;
function TSynEditStringTabExpander.GetTabWidth: integer;
begin
Result := FTabWidth;
end;
procedure TSynEditStringTabExpander.SetTabWidth(const AValue: integer);
var
i: integer;
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
LengthOfLine[i] := -1;
end;
procedure TSynEditStringTabExpander.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer);
var
i: integer;
begin
FIndexOfLongestLine := -1;
for i := AIndex to AIndex + ACount - 1 do
LengthOfLine[i] := -1;
end;
function TSynEditStringTabExpander.ExpandedString(Index: integer): string;
var
HasTabs: boolean;
begin
if fSynStrings[Index] = '' then begin
Result := '';
LengthOfLine[Index] := 0 + NoTabLengthOffset;
end else begin
Result := fConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs);
if HasTabs then
LengthOfLine[Index] := length(Result)
else
LengthOfLine[Index] := length(Result) + NoTabLengthOffset;
end;
end;
function TSynEditStringTabExpander.ExpandedStringLength(Index: integer): Integer;
var
HasTabs: boolean;
begin
if fSynStrings[Index] = '' then begin
Result := 0;
LengthOfLine[Index] := 0 + NoTabLengthOffset;
end else begin
Result := fSimulateConvertTabsProc(fSynStrings[Index], fTabWidth, HasTabs);
if HasTabs then
LengthOfLine[Index] := Result
else
LengthOfLine[Index] := Result + NoTabLengthOffset;
end;
end;
function TSynEditStringTabExpander.GetExpandedString(Index: integer): string;
begin
if (Index >= 0) and (Index < Count) then begin
if LengthOfLine[Index] >= NoTabLengthOffset then
Result := fSynStrings[Index]
else
Result := ExpandedString(Index);
end else
Result := '';
end;
function TSynEditStringTabExpander.GetLengthOfLongestLine: integer;
var
i, j, MaxLen: integer;
begin
if fIndexOfLongestLine < 0 then begin
MaxLen := 0;
if Count > 0 then begin
for i := 0 to Count - 1 do begin
j := LengthOfLine[i];
if j >= NoTabLengthOffset then j := j - NoTabLengthOffset;
if j < 0 then
j := ExpandedStringLength(i);
if j > MaxLen then begin
MaxLen := j;
fIndexOfLongestLine := i;
end;
end;
end;
exit(MaxLen);
end;
if (fIndexOfLongestLine >= 0) and (fIndexOfLongestLine < Count) then begin
Result := LengthOfLine[fIndexOfLongestLine];
if Result >= NoTabLengthOffset then Result := Result - NoTabLengthOffset;
end else
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 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.

View File

@ -35,9 +35,8 @@ type
{ TSynEditStringTrimmingList }
TSynEditStringTrimmingList = class(TSynEditStrings)
TSynEditStringTrimmingList = class(TSynEditStringsLinked)
private
fSynStrings: TSynEditStrings;
fCaret: TSynEditCaret;
fUndoList: TSynEditUndoList;
fSpaces: String;
@ -53,31 +52,12 @@ type
procedure DoLinesChanged(Index, N: integer);
procedure TrimAfterLock;
protected
function GetIsUtf8 : Boolean; override;
procedure SetIsUtf8(const AValue : Boolean); override;
function GetTabWidth : integer; override;
procedure SetTabWidth(const AValue : integer); override;
function GetFoldEndLevel(Index: integer): integer; override;
function GetFoldMinLevel(Index: integer): integer; override;
procedure SetFoldEndLevel(Index: integer; const AValue: integer); override;
procedure SetFoldMinLevel(Index: integer; const AValue: integer); override;
function GetRange(Index: integer): TSynEditRange; override;
procedure PutRange(Index: integer; ARange: TSynEditRange); override;
function GetCount: integer; override;
function GetCapacity: integer;
{$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF}
procedure SetCapacity(NewCapacity: integer);
{$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF}
function GetExpandedString(Index: integer): string; override;
function GetLengthOfLongestLine: integer; override;
function Get(Index: integer): string; override;
function GetObject(Index: integer): TObject; override;
procedure Put(Index: integer; const S: string); override;
procedure PutObject(Index: integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean); override;
public
constructor Create(ASynStringSource: TSynEditStrings; ACaret: TSynEditCaret);
destructor Destroy; override;
@ -91,7 +71,6 @@ type
procedure InsertLines(Index, NumLines: integer); override;
procedure InsertStrings(Index: integer; NewStrings: TStrings); override;
procedure Exchange(Index1, Index2: integer); override;
procedure ClearRanges(ARange: TSynEditRange); override;
property ExpandedStrings[Index: integer]: string read GetExpandedString;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
public
@ -110,14 +89,13 @@ implementation
constructor TSynEditStringTrimmingList.Create(ASynStringSource : TSynEditStrings; ACaret: TSynEditCaret);
begin
fSynStrings := ASynStringSource;
fCaret := ACaret;
fCaret.AddChangeHandler(@DoCaretChanged);
fLockList := TStringList.Create;
fLineIndex:= -1;
fSpaces := '';
fEnabled:=false;
Inherited Create;
Inherited Create(ASynStringSource);
end;
destructor TSynEditStringTrimmingList.Destroy;
@ -127,14 +105,6 @@ begin
inherited Destroy;
end;
procedure TSynEditStringTrimmingList.SetUpdateState(Updating : Boolean);
begin
if Updating then
fSynStrings.BeginUpdate
else
fSynStrings.EndUpdate;
end;
procedure TSynEditStringTrimmingList.DoCaretChanged(Sender : TObject);
var
s: String;
@ -294,84 +264,11 @@ begin
fLockList.Clear;
end;
function TSynEditStringTrimmingList.GetIsUtf8 : Boolean;
begin
Result := FSynStrings.IsUtf8;
end;
procedure TSynEditStringTrimmingList.SetIsUtf8(const AValue : Boolean);
begin
FSynStrings.IsUtf8 := AValue;
end;
function TSynEditStringTrimmingList.GetTabWidth : integer;
begin
Result := FSynStrings.TabWidth;
end;
procedure TSynEditStringTrimmingList.SetTabWidth(const AValue : integer);
begin
FSynStrings.TabWidth := AValue;
end;
procedure TSynEditStringTrimmingList.ForceTrim;
begin
TrimAfterLock;
end;
// Fold
function TSynEditStringTrimmingList.GetFoldEndLevel(Index : integer) : integer;
begin
Result:= fSynStrings.FoldEndLevel[Index];
end;
function TSynEditStringTrimmingList.GetFoldMinLevel(Index : integer) : integer;
begin
Result:= fSynStrings.FoldMinLevel[Index];
end;
procedure TSynEditStringTrimmingList.SetFoldEndLevel(Index : integer; const AValue : integer);
begin
fSynStrings.FoldEndLevel[Index] := AValue;
end;
procedure TSynEditStringTrimmingList.SetFoldMinLevel(Index : integer; const AValue : integer);
begin
fSynStrings.FoldMinLevel[Index] := AValue;
end;
// Range
function TSynEditStringTrimmingList.GetRange(Index : integer) : TSynEditRange;
begin
Result:= fSynStrings.Ranges[Index];
end;
procedure TSynEditStringTrimmingList.PutRange(Index : integer; ARange : TSynEditRange);
begin
fSynStrings.Ranges[Index] := ARange;
end;
procedure TSynEditStringTrimmingList.ClearRanges(ARange : TSynEditRange);
begin
fSynStrings.ClearRanges(ARange);
end;
// Count
function TSynEditStringTrimmingList.GetCount : integer;
begin
Result:= fSynStrings.Count;
end;
function TSynEditStringTrimmingList.GetCapacity : integer;
begin
Result:= fSynStrings.Capacity;
end;
procedure TSynEditStringTrimmingList.SetCapacity(NewCapacity : integer);
begin
fSynStrings.Capacity := NewCapacity;
end;
// Lines
function TSynEditStringTrimmingList.GetExpandedString(Index : integer) : string;
begin