SynEdit: Fixing many issues with trailing spaces. Includes bug #12383 "Smart tab un-indent", 12487 "ctrl-t at end of trailing spaces", "special char display of trailing spaces", vertical scrollbar for (many) trailing spaces.

git-svn-id: trunk@17416 -
This commit is contained in:
martin 2008-11-18 00:12:19 +00:00
parent d92cd626a3
commit 34347f789c
9 changed files with 772 additions and 136 deletions

2
.gitattributes vendored
View File

@ -1349,7 +1349,9 @@ components/synedit/syneditplugins.pas svneol=native#text/pascal
components/synedit/syneditregexsearch.pas svneol=native#text/pascal
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/synedittexttrimmer.pas svneol=native#text/plain
components/synedit/synedittypes.pp svneol=native#text/pascal
components/synedit/synexporthtml.pas svneol=native#text/pascal
components/synedit/synhighlighterany.pas svneol=native#text/plain

View File

@ -76,7 +76,7 @@ uses
{$ifdef SYN_LAZARUS}
SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket,
SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection,
SynEditFoldedView,
SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView,
{$ENDIF}
SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer;
@ -227,7 +227,7 @@ type
{$ENDIF}
);
TSynEditorOptions = set of TSynEditorOption;
{$IFDEF SYN_LAZARUS}
TSynEditorOption2 = (
eoCaretSkipsSelection, // Caret skips selection on VK_LEFT/VK_RIGHT
@ -419,6 +419,7 @@ type
fBeautifier: TSynCustomBeautifier;
fExtraCharSpacing: integer;
fTextView : TSynEditFoldedView;
fTrimLines: TStrings; //TSynEditStringTrimmingList;
{$ENDIF}
fLines: TStrings;
fLinesInWindow: Integer;// MG: fully visible lines in window
@ -521,6 +522,7 @@ type
function GetSelectedColor : TSynSelectedColor;
function GetBracketMatchColor : TSynSelectedColor;
function GetMouseLinkColor : TSynSelectedColor;
procedure SetRealLines(const AValue : TStrings);
procedure SetSelectedColor(const AValue : TSynSelectedColor);
procedure SetSpecialLineColors(const AValue : TSpecialLineColorsEvent);
procedure SetSpecialLineMarkup(const AValue : TSpecialLineMarkupEvent);
@ -631,7 +633,9 @@ type
{$ENDIF}
procedure SizeOrFontChanged(bFont: boolean);
procedure StatusChanged(AChanges: TSynStatusChanges);
{$IFNDEF SYN_LAZARUS}
procedure TrimmedSetLine(ALine: integer; ALineText: string);
{$ENDIF}
procedure UndoRedoAdded(Sender: TObject);
procedure UnlockUndo;
procedure UpdateCaret;
@ -851,7 +855,7 @@ type
AOptions: TSynSearchOptions): integer;
{$IFDEF SYN_LAZARUS}
function SearchReplaceEx(const ASearch, AReplace: string;
AOptions: TSynSearchOptions; AStart: TPoint): integer;
AOptions: TSynSearchOptions; AStart: TPoint): integer;
{$ENDIF}
procedure SelectAll;
{$IFDEF SYN_LAZARUS}
@ -905,9 +909,11 @@ 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 SetLines; // No trailing (trimmable) spaces
{$ENDIF}
property RealLines: TStrings read fLines write SetRealLines; // No trailing (trimmable) spaces
property Lines: TStrings read fTrimLines write SetLines;
{$ELSE}
property Lines: TStrings read fLines write SetLines;
{$ENDIF}
property Marks: TSynEditMarkList read fMarkList;
property MaxLeftChar: integer read fMaxLeftChar write SetMaxLeftChar
default 1024;
@ -1461,7 +1467,9 @@ begin
fLines := TSynEditStringList.Create;
{$IFDEF SYN_LAZARUS}
fCaret := TSynEditCaret.Create;
fTextView := TSynEditFoldedView.Create(TSynEditStringList(fLines));
fTrimLines := TSynEditStringTrimmingList.Create(TSynEditStrings(fLines), fCaret);
fTextView := TSynEditFoldedView.Create(TSynEditStringList(fLines),
TSynEditStrings(fTrimLines));
fTextView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged;
{$ENDIF}
// with TSynEditList(fLines) do begin
@ -1481,6 +1489,9 @@ begin
fUndoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded;
fRedoList := TSynEditUndoList.Create;
fRedoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).UndoList := fUndoList;
{$ENDIF}
{$IFDEF SYN_COMPILER_4_UP}
{$IFNDEF SYN_LAZARUS}
// ToDo DoubleBuffered
@ -1518,7 +1529,7 @@ begin
fMarkupManager.AddMarkUp(fMarkupCtrlMouse);
fMarkupManager.AddMarkUp(fMarkupSpecialLine);
fMarkupManager.AddMarkUp(fMarkupSelection);
fMarkupManager.Lines := TSynEditStringList(fLines);
fMarkupManager.Lines := TSynEditStrings(Lines);
fMarkupManager.InvalidateLinesMethod := @InvalidateLines;
Color := clWhite;
@ -1587,6 +1598,7 @@ begin
fTSearch := TSynEditSearch.Create;
fOptions := SYNEDIT_DEFAULT_OPTIONS;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).Enabled := eoTrimTrailingSpaces in fOptions;
fOptions2 := SYNEDIT_DEFAULT_OPTIONS2;
{$ENDIF}
fScrollTimer := TTimer.Create(Self);
@ -1707,6 +1719,7 @@ begin
FreeAndNil(fInternalImage);
FreeAndNil(fFontDummy);
FreeAndNil(fTextView);
FreeAndNil(fTrimLines);
FreeAndNil(fLines);
FreeAndNil(fCaret);
{$ENDIF}
@ -1808,6 +1821,12 @@ begin
Result := fMarkupCtrlMouse.MarkupInfo;
end;
procedure TCustomSynEdit.SetRealLines(const AValue : TStrings);
begin
if HandleAllocated then
fLines.Assign(AValue);
end;
procedure TCustomSynEdit.SetUseIncrementalColor(const AValue : Boolean);
begin
fMarkupSelection.UseIncrementalColor:=AValue;
@ -2061,7 +2080,7 @@ end;
function TCustomSynEdit.SynGetText: string;
begin
Result := Lines.Text;
Result := fLines.Text;
end;
{$IFDEF SYN_LAZARUS}
@ -2080,7 +2099,7 @@ end;
function TCustomSynEdit.RealGetText: TCaption;
begin
if fLines<>nil then
if Lines<>nil then
Result := Lines.Text
else
Result := '';
@ -2780,7 +2799,7 @@ begin
Exclude(fStateFlags, sfDblClicked);
Exclude(fStateFlags, sfPossibleGutterClick);
{$ENDIF}
{$IFDEF SYN_LAZARUS}
if (eoShowCtrlMouseLinks in Options)
and not(wasDragging)
@ -3396,7 +3415,7 @@ var
end;
inc(SrcPos);
end;
#32:
// space
if not Special then begin
@ -3607,7 +3626,7 @@ var
)
// background color must be the same and
// foreground color must be the same or token is only spaces
and ( ((TokenAccu.BG = Background)
and ( ((TokenAccu.BG = Background)
and ((TokenAccu.FG = Foreground)
or (not(eoShowSpecialChars in fOptions) and TokenIsSpaces)))
)
@ -3672,9 +3691,9 @@ var
ExpandSpecialChars(sToken, nTokenByteLen, PhysicalStartPos);
TokenCharLen := UTF8Length(sToken, nTokenByteLen);
// Prepare position for next token
inc(CurPhysPos, TokenCharLen);
inc(CurPhysPos, TokenCharLen);
if CurPhysPos <= FirstCol then exit;
// Remove any Part of the Token that is before FirstCol
if PhysicalStartPos < FirstCol then begin
SubCharLen := FirstCol - PhysicalStartPos;
@ -3699,7 +3718,7 @@ var
exit;
end;
end;
if Assigned(attr) then begin
DefaultFGCol:=attr.Foreground;
DefaultBGCol:=attr.Background;
@ -3725,7 +3744,7 @@ var
debugln('ERROR: Got invalid SubCharLen ',dbgs(SubCharLen),' len ',dbgs(nTokenByteLen),' Line ',dbgs(CurLine),' PhysPos ',dbgs(CurPhysPos));
SubCharLen:=1;
end;
SubTokenByteLen := UTF8CharToByteIndex(sToken,nTokenByteLen,SubCharLen);
if SubTokenByteLen < 0 then begin
debugln('ERROR: Can not find pso in SubToken ',dbgs(SubCharLen),' len ',dbgs(nTokenByteLen),' Line ',dbgs(CurLine),' PhysPos ',dbgs(CurPhysPos));
@ -4963,7 +4982,9 @@ begin
if eoScrollPastEol in Options then
MaxVal := fMaxLeftChar
else
MaxVal := TSynEditStringList(Lines).LengthOfLongestLine;
MaxVal :=
{$IFDEF SYN_LAZARUS}TSynEditStrings{$ELSE}TSynEditStringList{$ENDIF}
(Lines).LengthOfLongestLine;
Value := Min(Value, MaxVal - fCharsInWindow + 1);
{end} //mh 2000-10-19
Value := Max(Value, 1);
@ -5054,17 +5075,16 @@ var
TempString := Copy(Lines[BB.Y - 1], 1, BB.X - 1) +
Copy(Lines[BE.Y - 1], BE.X, MaxInt);
// Delete all lines in the selection range.
{begin} // djlp 2000-09-13
{$IFDEF SYN_LAZARUS}
TSynEditStrings(Lines).DeleteLines(BB.Y-1, BE.Y - BB.Y);
{$ELSE}
TSynEditStringList(Lines).DeleteLines(BB.Y-1, BE.Y - BB.Y);
// for x := BE.Y - 1 downto BB.Y do
// Lines.Delete(x);
{end} // djlp 2000-09-13
// Put the stuff that was outside of selection back in.
// if eoScrollPastEol in Options then //JGF 2000-09-23
if Options * [eoScrollPastEol, eoTrimTrailingSpaces]
= [eoScrollPastEol, eoTrimTrailingSpaces]
then
TempString := TrimRight(TempString);
{$ENDIF}
Lines[BB.Y - 1] := TempString;
end;
UpdateMarks := TRUE;
@ -5100,7 +5120,11 @@ var
Delete(TempString, l, r - l);
{$ENDIF USE_UTF8BIDI_LCL}
{$ENDIF}
{$IFDEF SYN_LAZARUS}
Lines[x] := TempString;
{$ELSE}
TrimmedSetLine(x, TempString);
{$ENDIF}
end;
// Lines never get deleted completely, so keep caret at end.
CaretXY := {$IFDEF SYN_LAZARUS}
@ -5180,18 +5204,27 @@ var
sLeftSide := sLeftSide + StringOfChar(' ', CaretX-1-Length(sLeftSide));
end;
sRightSide := Copy(LineText, CaretX, Length(LineText) - (CaretX - 1));
{$ENDIF}
if eoTrimTrailingSpaces in Options then
sRightSide := TrimRight(sRightSide);
{$ENDIF}
// step1: insert the first line of Value into current line
Start := PChar(Value);
P := GetEOL(Start);
if P^ <> #0 then begin
SetString(Str, Value, P - Start);
{$IFDEF SYN_LAZARUS}
Lines[CaretY - 1] := sLeftSide + Str;
TSynEditStrings(Lines).InsertLines(CaretY, CountLines(P));
{$ELSE}
TrimmedSetLine(CaretY - 1, sLeftSide + Str);
TSynEditStringList(Lines).InsertLines(CaretY, CountLines(P)); // djlp 2000-09-07
{$ENDIF}
end else begin
{$IFDEF SYN_LAZARUS}
Lines[CaretY - 1] := sLeftSide + Value + sRightSide;
{$ELSE}
TrimmedSetLine(CaretY - 1, sLeftSide + Value + sRightSide);
{$ENDIF}
CaretX := LogicalToPhysicalPos(
Point(1 + Length(sLeftSide + Value),CaretY)).X;
end;
@ -5211,18 +5244,10 @@ var
Lines[CaretY - 1] := sRightSide; // djlp 2000-09-07
end else begin
SetString(Str, Start, P - Start); //mh 2000-11-08
{$IFDEF SYN_LAZARUS}
if p^ <> #0 then
TrimmedSetLine(CaretY - 1, Str)
else begin
TrimmedSetLine(CaretY - 1, Str + sRightSide);
end;
{$ELSE}
if p^ <> #0 then
Lines[CaretY - 1] := Str // djlp 2000-09-07
else
Lines[CaretY - 1] := Str + sRightSide // djlp 2000-09-07
{$ENDIF}
end;
{$IFDEF SYN_LAZARUS}
if p^=#0 then
@ -5286,7 +5311,11 @@ var
System.Insert(Str, TempString,
{$IFDEF SYN_LAZARUS}LogicalInsertPos{$ELSE}InsertPos{$ENDIF});
end;
{$IFDEF SYN_LAZARUS}
Lines[CaretY - 1] := TempString;
{$ELSE}
TrimmedSetLine(CaretY - 1, TempString); //JGF 2000-09-23
{$ENDIF}
end;
end;
if ATag <> nil then
@ -5336,11 +5365,17 @@ var
Lines[CaretY - 1] := Str + Lines[CaretY - 1]
else
Lines.Add(Str);
{$IFNDEF SYN_LAZARUS}
if eoTrimTrailingSpaces in Options then
Lines[CaretY - 1] := TrimRight(Lines[CaretY - 1]);
{$ENDIF}
CaretX := 1 + Length(Str);
end else begin
{$IFDEF SYN_LAZARUS}
Lines[CaretY - 1] := Str;
{$ELSE}
TrimmedSetLine(CaretY - 1, Str);
{$ENDIF}
CaretY := CaretY + 1;
Inc(Result);
if P^ = #13 then
@ -5396,6 +5431,7 @@ var
begin
IncPaintLock;
Lines.BeginUpdate;
TSynEditStringTrimmingList(fTrimLines).Lock;
try
BB := BlockBegin;
BE := BlockEnd;
@ -5418,6 +5454,7 @@ begin
EnsureCursorPosVisible;
{$ENDIF}
finally
TSynEditStringTrimmingList(fTrimLines).UnLock;
Lines.EndUpdate;
DecPaintLock;
end;
@ -5431,7 +5468,7 @@ end;
{$IFDEF SYN_LAZARUS}
procedure TCustomSynEdit.RealSetText(const Value: TCaption);
begin
Lines.Text := Value;
Lines.Text := Value; // Do not trim
end;
{$ENDIF}
@ -5634,7 +5671,11 @@ begin
if eoScrollPastEol in Options then
ScrollInfo.nMax := fMaxLeftChar
else
{$IFDEF SYN_LAZARUS}
ScrollInfo.nMax := TSynEditStrings(Lines).LengthOfLongestLine;
{$ELSE}
ScrollInfo.nMax := TSynEditStringList(Lines).LengthOfLongestLine;
{$ENDIF}
{end} //mh 2000-10-19
ScrollInfo.nPage := CharsInWindow;
ScrollInfo.nPos := LeftChar;
@ -5925,8 +5966,8 @@ function TCustomSynEdit.ScanFrom(Index: integer
FixFStart: Integer;
procedure SetCodeFoldAttributes;
begin
TSynEditStringList(Lines).FoldMinLevel[Result-1] := fHighlighter.MinimumCodeFoldBlockLevel;
TSynEditStringList(Lines).FoldEndLevel[Result-1] := fHighlighter.CurrentCodeFoldBlockLevel;
TSynEditStrings(Lines).FoldMinLevel[Result-1] := fHighlighter.MinimumCodeFoldBlockLevel;
TSynEditStrings(Lines).FoldEndLevel[Result-1] := fHighlighter.CurrentCodeFoldBlockLevel;
end;
{$ENDIF}
@ -5946,10 +5987,10 @@ begin
end;
FixFStart := Index;
if Result > 0 then
fHighlighter.SetRange(TSynEditStringList(Lines).Ranges[Result])
fHighlighter.SetRange(TSynEditStrings(Lines).Ranges[Result])
else begin
fHighlighter.ReSetRange;
TSynEditStringList(Lines).Ranges[0] := fHighlighter.GetRange;
TSynEditStrings(Lines).Ranges[0] := fHighlighter.GetRange;
end;
{$ENDIF}
if Index >= Lines.Count - 1 then Exit;
@ -5957,18 +5998,21 @@ begin
fHighlighter.SetLine(Lines[Result], Result);
inc(Result);
fHighlighter.NextToEol;
while (fHighlighter.GetRange <> TSynEditStringList(Lines).Ranges[Result])
{$IFDEF SYN_LAZARUS}
while (fHighlighter.GetRange <> TSynEditStrings(Lines).Ranges[Result])
or (Result<=AtLeastTilIndex)
{$ELSE}
while (fHighlighter.GetRange <> TSynEditStringList(Lines).Ranges[Result])
{$ENDIF}
do begin
//debugln(['TSynCustomHighlighter.ScanFrom WHILE Y=',Result,' Level=',fHighlighter.CurrentCodeFoldBlockLevel,' ScannedLine="',Lines[Result-1],'"']);
TSynEditStringList(Lines).Ranges[Result{$IFNDEF SYN_LAZARUS}-1{$ENDIF}] :=
fHighlighter.GetRange;
{$IFDEF SYN_LAZARUS}
TSynEditStrings(Lines).Ranges[Result] := fHighlighter.GetRange;
SetCodeFoldAttributes;
//if (Result and $fff)=0 then
// debugln('TCustomSynEdit.ScanFrom A Line=', dbgs(Result),' Index=',dbgs(Index),' MinLevel=',dbgs(CodeFoldMinLevel),' EndLevel=',dbgs(CodeFoldEndLevel),' CodeFoldType=',dbgs(ord(CodeFoldType)),' ',dbgs(length(Lines[Result-1])));
{$ELSE}
TSynEditStringList(Lines).Ranges[Result-1] := fHighlighter.GetRange;
{$ENDIF}
fHighlighter.SetLine(Lines[Result], Result);
//debugln(['TSynCustomHighlighter.ScanFrom SetLine Y=',Result,' Level=',fHighlighter.CurrentCodeFoldBlockLevel,' Line="',Lines[Result],'"']);
@ -6557,15 +6601,28 @@ var
begin
Item := fRedoList.PeekItem;
if Item <> nil then begin
{$IFDEF SYN_LAZARUS}
fUndoList.BeginBlock;
OldChangeNumber := Item.fChangeNumber;
{$ELSE}
OldChangeNumber := fUndoList.BlockChangeNumber;
fUndoList.BlockChangeNumber := Item.fChangeNumber;
{$ENDIF}
try
repeat
RedoItem;
Item := fRedoList.PeekItem;
{$IFDEF SYN_LAZARUS}
until (Item = nil) or (Item.fChangeNumber <> OldChangeNumber);
{$ELSE}
until (Item = nil) or (Item.fChangeNumber <> fUndoList.BlockChangeNumber);
{$ENDIF}
finally
{$IFDEF SYN_LAZARUS}
fUndoList.EndBlock;
{$ELSE}
fUndoList.BlockChangeNumber := OldChangeNumber;
{$ENDIF}
end;
end;
end;
@ -6664,6 +6721,9 @@ begin
*)
{end} //mh 2000-11-20
end;
{$IFDEF SYN_LAZARUS}
crTrimSpace: TSynEditStringTrimmingList(fTrimLines).ForceTrim;
{$ENDIF}
crLineBreak:
{begin} //sbs 2000-11-20
// CommandProcessor(ecLineBreak, #13, nil);
@ -6798,15 +6858,28 @@ var
begin
Item := fUndoList.PeekItem;
if Item <> nil then begin
{$IFDEF SYN_LAZARUS}
fRedoList.BeginBlock;
OldChangeNumber := Item.fChangeNumber;
{$ELSE}
OldChangeNumber := fRedoList.BlockChangeNumber;
fRedoList.BlockChangeNumber := Item.fChangeNumber;
{$ENDIF}
try
repeat
UndoItem;
Item := fUndoList.PeekItem;
{$IFDEF SYN_LAZARUS}
until (Item = nil) or (Item.fChangeNumber <> OldChangeNumber);
{$ELSE}
until (Item = nil) or (Item.fChangeNumber <> fRedoList.BlockChangeNumber);
{$ENDIF}
finally
{$IFDEF SYN_LAZARUS}
fRedoList.EndBlock;
{$ELSE}
fRedoList.BlockChangeNumber := OldChangeNumber;
{$ENDIF}
end;
end;
end;
@ -6859,6 +6932,7 @@ begin
{end} //mh 2000-11-20
end;
crDeleteAfterCursor, crDelete, {crDragDropDelete, crSelDelete, } //mh 2000-11-20
{$IFDEF SYN_LAZARUS}crTrimSpace,{$ENDIF}
crSilentDelete, crSilentDeleteAfterCursor: //mh 2000-10-30
begin
// If there's no selection, we have to set
@ -6891,7 +6965,8 @@ begin
TmpPos := Item.fChangeStartPos
else
TmpPos := Item.fChangeEndPos;
if Item.fChangeReason in [crSilentDelete, crSilentDeleteAfterCursor]
if Item.fChangeReason in [crSilentDelete, crSilentDeleteAfterCursor
{$IFDEF SYN_LAZARUS}, crTrimSpace{$ENDIF} ]
then
CaretXY :={$IFDEF SYN_LAZARUS}LogicalToPhysicalPos(TmpPos)
{$ELSE}TmpPos{$ENDIF}
@ -6926,7 +7001,12 @@ begin
end;
CaretXY := {$IFDEF SYN_LAZARUS}PhysStartPos
{$ELSE}Item.fChangeStartPos{$ENDIF};
{$IFDEF SYN_LAZARUS}
if Item.fChangeStr <> '' then
Lines[CaretY - 1] := TmpStr + Item.fChangeStr;
{$ELSE}
TrimmedSetLine(CaretY - 1, TmpStr + Item.fChangeStr);
{$ENDIF}
DoLinesDeleted(CaretY, 1);
end;
crIndent: // remove the column that was inserted
@ -7339,7 +7419,7 @@ begin
{$IFDEF SYN_LAZARUS}
if fHighlighter<>nil then begin
fHighlighter.ResetRange;
TSynEditStringList(Lines).ClearRanges(fHighlighter.GetRange);
TSynEditStrings(Lines).ClearRanges(fHighlighter.GetRange);
fTSearch.IdentChars:=fHighlighter.IdentChars;
end else begin
fTSearch.ResetIdentChars;
@ -7605,6 +7685,10 @@ begin
,' AChar=',AChar,' Data=',DbgS(Data)]);
DumpStack;
{$ENDIF}
{$IFDEF SYN_LAZARUS}
try
BeginUndoBlock;
{$ENDIF}
// first the program event handler gets a chance to process the command
DoOnProcessCommand(Command, AChar, Data);
if Command <> ecNone then begin
@ -7625,6 +7709,11 @@ begin
if Command <> ecNone then
{$ENDIF}
DoOnCommandProcessed(Command, AChar, Data);
{$IFDEF SYN_LAZARUS}
finally
EndUndoBlock;
end;
{$ENDIF}
end;
procedure TCustomSynEdit.ExecuteCommand(Command: TSynEditorCommand;
@ -7723,7 +7812,7 @@ begin
{begin
MoveCaretAndSelectionPhysical(CaretXY,Point(1, CaretY),
Command = ecSelLineStart);
fLastCaretX := fCaretX;
fLastCaretX := CaretX;
end;}
ecLineEnd, ecSelLineEnd:
begin
@ -7838,7 +7927,7 @@ begin
{$IFDEF SYN_LAZARUS}
if fTextView.FoldedAtTextIndex[CaretNew.Y - 1] then begin
CY := FindNextUnfoldedLine(CaretNew.Y, False);
CaretNew := LogicalToPhysicalPos(Point(1 + Length(fLines[CY-1]), CY));
CaretNew := LogicalToPhysicalPos(Point(1 + Length(Lines[CY-1]), CY));
end;
MoveCaretAndSelectionPhysical
{$ELSE}
@ -7890,6 +7979,10 @@ begin
// only move caret one column
Helper := ' ';
CaretX := CaretX - 1;
{$IFDEF SYN_LAZARUS}
// behind EOL, there was no char to delete, this wa a simple cursor move, do not undo
Caret := CaretXY;
{$ENDIF}
end else if CaretX = 1 then begin
// join this line with the last line if possible
if CaretY > 1 then begin
@ -7902,8 +7995,10 @@ begin
{$ENDIF}
Lines.Delete(CaretY);
DoLinesDeleted(CaretY, 1);
{$IFNDEF SYN_LAZARUS}
if eoTrimTrailingSpaces in Options then
Temp := TrimRight(Temp);
{$ENDIF}
LineText := LineText + Temp;
Helper := {$IFDEF SYN_LAZARUS}LineEnding{$ELSE}#13#10{$ENDIF};
end;
@ -7941,7 +8036,7 @@ begin
// ' LogCaretXY.X=',dbgs(LogCaretXY.X),
// ' Temp="',DbgStr(Temp),'" Helper="',DbgStr(Helper),'"');
Temp:=copy(Temp,1,LogSpacePos-1)+copy(Temp,LogCaretXY.X,MaxInt);
TrimmedSetLine(CaretY - 1, Temp);
Lines[CaretY - 1] := Temp;
CaretX := LogicalToPhysicalCol(Temp,LogSpacePos);
{$ELSE}
Helper := Copy(Temp, 1, SpaceCount1 - SpaceCount2);
@ -7968,6 +8063,7 @@ begin
//debugln('ecDeleteLastChar delete char CaretX=',dbgs(CaretX),
// ' Helper="',DbgStr(Helper),'" Temp="',DbgStr(Temp),'"');
{$ENDIF USE_UTF8BIDI_LCL}
Lines[CaretY - 1] := Temp;
{$ELSE}
{$IFDEF SYN_MBCSSUPPORT}
if ByteType(Temp, CaretX - 2) = mbLeadByte then
@ -7976,11 +8072,11 @@ begin
CaretX := CaretX - counter;
Helper := Copy(Temp, CaretX, counter);
Delete(Temp, CaretX, counter);
TrimmedSetLine(CaretY - 1, Temp);
{$ENDIF}
TrimmedSetLine(CaretY - 1, Temp);
end;
end;
if (Caret.X <> CaretX) or (Caret.Y <> CaretY) then begin
{$IFDEF SYN_LAZARUS}
if eoGroupUndo in Options then begin
@ -8035,7 +8131,7 @@ begin
{$ELSE USE_UTF8BIDI_LCL}
System.Delete(Temp, LogCaretXY.X, Counter);
{$ENDIF USE_UTF8BIDI_LCL}
TrimmedSetLine(CaretY - 1, Temp);
Lines[CaretY - 1] := Temp;
{$ELSE}
counter := 1;
{$IFDEF SYN_MBCSSUPPORT}
@ -8051,7 +8147,11 @@ begin
// join line with the line after
if CaretY < Lines.Count then begin
Helper := StringOfChar(' ', CaretX - 1 - Len);
{$IFDEF SYN_LAZARUS}
Lines[CaretY - 1] := Temp + Helper + Lines[CaretY];
{$ELSE}
TrimmedSetLine(CaretY - 1, Temp + Helper + Lines[CaretY]);
{$ENDIF}
Caret := Point(1, CaretY + 1);
Helper := {$IFDEF SYN_LAZARUS}LineEnding{$ELSE}#13#10{$ENDIF};
Lines.Delete(CaretY);
@ -8194,7 +8294,7 @@ begin
// break line in two
SpaceCount1 := LeftSpaces(Temp);
Temp := Copy(LineText, 1, LogCaretXY.X - 1);
TrimmedSetLine(CaretY - 1, Temp);
Lines[CaretY - 1] := Temp;
Delete(Temp2, 1, LogCaretXY.X - 1);
if Assigned(Beautifier) then
SpaceCount1:=Beautifier.GetIndentForLineBreak(Self,LogCaretXY,Temp2);
@ -8215,8 +8315,8 @@ begin
end;
end else begin
// current line is empty (len = 0)
if fLines.Count = 0 then
fLines.Add('');
if Lines.Count = 0 then
Lines.Add('');
// linebreak after end of line
fUndoList.AddChange(crLineBreak,
LogCaretXY, LogCaretXY,
@ -8235,7 +8335,7 @@ begin
end;
Lines.Insert(CaretY, '');
if Command = ecLineBreak then begin
if (SpaceCount2 > 0) and (not (eoScrollPastEol in Options)) then
if (SpaceCount2 > 0) then
Lines[CaretY] := StringOfChar(' ', SpaceCount2);
CaretXY := Point(SpaceCount2 + 1, CaretY + 1);
end;
@ -8342,6 +8442,12 @@ begin
{end} //mh 2000-11-20
end else begin
Temp := LineText;
// Added the check for whether or not we're in insert mode.
// If we are, we append one less space than we would in overwrite mode.
// This is because in overwrite mode we have to put in a final space
// character which will be overwritten with the typed character. If we put the
// extra space in in insert mode, it would be left at the end of the line and
// cause problems unless eoTrimTrailingSpaces is set.
{$IFDEF SYN_LAZARUS}
LogCaretXY:=PhysicalToLogicalPos(CaretXY);
{debugln('ecChar CaretXY=',dbgs(CaretXY),
@ -8371,7 +8477,7 @@ begin
//debugln('ecChar Temp=',DbgStr(Temp),' AChar=',DbgStr(AChar));
CaretX := CaretX + 1;
{$ENDIF}
TrimmedSetLine(CaretY - 1, Temp);
Lines[CaretY - 1] := Temp;
fUndoList.AddChange(crInsert, StartOfBlock,
PhysicalToLogicalPos(CaretXY), '', smNormal);
end else begin
@ -8392,7 +8498,7 @@ begin
Temp:=Temp+StringOfChar(' ', LogCaretXY.X-1-Len)+AChar;
{$ENDIF}
CaretNew := Point((CaretX + 1), CaretY);
TrimmedSetLine(CaretY - 1, Temp);
Lines[CaretY - 1] := Temp;
fUndoList.AddChange(crInsert,
StartOfBlock, PhysicalToLogicalPos(CaretNew),
Helper, smNormal);
@ -8405,12 +8511,6 @@ begin
end;
{$ELSE below for NOT SYN_LAZARUS ----------------------------------}
bChangeScroll := not (eoScrollPastEol in fOptions);
// Added the check for whether or not we're in insert mode.
// If we are, we append one less space than we would in overwrite mode.
// This is because in overwrite mode we have to put in a final space
// character which will be overwritten with the typed character. If we put the
// extra space in in insert mode, it would be left at the end of the line and
// cause problems unless eoTrimTrailingSpaces is set.
try
if bChangeScroll then Include(fOptions, eoScrollPastEol);
StartOfBlock := CaretXY;
@ -8697,7 +8797,7 @@ begin
FindFirstNonWhiteSpaceCharInNextLine;
end else begin
if fHighlighter<>nil then begin
fHighlighter.SetRange(TSynEditStringList(Lines).Ranges[CY - 1]);
fHighlighter.SetRange(TSynEditStrings(Lines).Ranges[CY - 1]);
fHighlighter.SetLine(Line, CY - 1);
while not fHighlighter.GetEol do begin
nTokenPos := fHighlighter.GetTokenPos; // zero-based
@ -8767,7 +8867,7 @@ begin
WhiteChars := [#1..#255] - CurIdentChars;
{$ENDIF}
LineLen := Length(Line);
if CX >{$IFNDEF SYN_LAZARUS}={$ENDIF} LineLen then begin
// find first IdentChar in the next line
if CY < Lines.Count then begin
@ -8900,6 +9000,9 @@ end;
procedure TCustomSynEdit.BeginUndoBlock;
begin
fUndoList.BeginBlock;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).Lock;
{$ENDIF}
end;
{end} //sbs 2000-11-19
@ -8911,6 +9014,11 @@ end;
{begin} //sbs 2000-11-19
procedure TCustomSynEdit.EndUndoBlock;
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;
{$ENDIF}
fUndoList.EndBlock;
end;
{end} //sbs 2000-11-19
@ -8968,7 +9076,7 @@ begin
loop := 0;
while (loop < (p.Y - 1)) and (loop < Lines.Count) do
begin
result := result + llen(lines[loop]);
result := result + llen(Lines[loop]);
inc(loop);
end;
if loop < Lines.Count then
@ -8989,7 +9097,7 @@ begin
loop := 0;
count := 0;
while (loop < Lines.Count) and (count + llen(lines[loop]) < value) do begin
count := count + llen(lines[loop]);
count := count + llen(Lines[loop]);
inc(loop);
end;
{ CaretX := value - count;
@ -9025,7 +9133,7 @@ begin
result := 0;
loop := 0;
while (loop < (p.y - 1)) and (loop < Lines.Count) do begin
Result := result + llen(lines[loop]);
Result := result + llen(Lines[loop]);
inc(loop);
end;
if loop<Lines.Count then
@ -9047,7 +9155,7 @@ begin
loop := 0;
count := 0;
while (loop < Lines.Count) and (count + llen(lines[loop]) < value) do begin
count := count + llen(lines.strings[loop]);
count := count + llen(Lines.strings[loop]);
inc(loop);
end;
p.x := value - count; p.y := loop + 1;
@ -9228,7 +9336,7 @@ begin
Value := MinMax(Value, 1{0}, 256); //lt 2000-10-19
if (Value <> fTabWidth) then begin
fTabWidth := Value;
TSynEditStringList(Lines).TabWidth := Value; //mh 2000-10-19
TSynEditStringList(fLines).TabWidth := Value; //mh 2000-10-19
Invalidate; // to redraw text containing tab chars
end;
end;
@ -9554,6 +9662,9 @@ begin
{$ENDIF}
bSetDrag := (eoDropFiles in fOptions) <> (eoDropFiles in Value);
fOptions := Value;
{$IFDEF SYN_LAZARUS}
TSynEditStringTrimmingList(fTrimLines).Enabled := eoTrimTrailingSpaces in fOptions;
{$ENDIF}
// Reset column position in case Cursor is past EOL.
if not (eoScrollPastEol in fOptions) then
CaretX := CaretX;
@ -10353,7 +10464,7 @@ begin
// calculate line start position
FirstNonBlank:=-1;
if CaretY<=Lines.Count then begin
s:=fLines[CaretXY.Y-1];
s:=Lines[CaretXY.Y-1];
// search first non blank char pos
FirstNonBlank:=1;
@ -10618,7 +10729,7 @@ var
end;
// Init the Highlighter only once per line
if MaxKnownTokenPos < 1 then begin
fHighlighter.SetRange(TSynEditStringList(Lines).Ranges[PosY - 1]);
fHighlighter.SetRange(TSynEditStrings(Lines).Ranges[PosY - 1]);
fHighlighter.SetLine(Line, PosY - 1);
TokenListCnt := 0;
end
@ -10828,7 +10939,11 @@ begin
if Assigned(Highlighter) and (PosY >= 0) and (PosY < Lines.Count) then
begin
Line := Lines[PosY];
{$IFDEF SYN_LAZARUS}
Highlighter.SetRange(TSynEditStrings(Lines).Ranges[PosY]);
{$ELSE}
Highlighter.SetRange(TSynEditStringList(Lines).Ranges[PosY]);
{$ENDIF}
Highlighter.SetLine(Line, PosY);
PosX := XY.X;
if (PosX > 0) and (PosX <= Length(Line)) then begin
@ -10900,7 +11015,7 @@ begin
y:=Line-1;
if y>Lines.Count then y:=Lines.Count;
while y>=1 do begin
s:=fLines[y-1];
s:=Lines[y-1];
FirstNonBlank:=1;
while (FirstNonBlank<=length(s)) and (s[FirstNonBlank] in [' ',#9]) do
inc(FirstNonBlank);
@ -11296,6 +11411,7 @@ begin
end;
{$ENDIF}
{$IFNDEF SYN_LAZARUS}
procedure TCustomSynEdit.TrimmedSetLine(ALine: integer; ALineText: string);
begin
if eoTrimTrailingSpaces in Options then
@ -11303,6 +11419,7 @@ begin
else
Lines[ALine] := ALineText;
end;
{$ENDIF}
{ TSynEditMark }

View File

@ -30,7 +30,7 @@ interface
uses
LCLProc,
Classes, SysUtils, SynEditTextBuffer;
Classes, SysUtils, SynEditTypes, SynEditTextBuffer, SynEditTextBase;
type
@ -162,7 +162,7 @@ type
TSynEditFoldedView = class {TODO: Make a base class, that just maps everything one to one}
private
fLines : TSynEditStringList;
fLines : TSynEditStrings;
fFoldTree : TSynTextFoldAVLTree; // Folds are stored 1-based (the 1st line is 1)
fTopLine : Integer;
fLinesInWindow : Integer; // there may be an additional part visible line
@ -199,7 +199,7 @@ type
Procedure LinesDeletedAtViewPos(AStartPos, ALineCount : Integer;
SkipFixFolding : Boolean = False);
public
constructor Create(aTextBuffer : TSynEditStringList);
constructor Create(aTextBuffer : TSynEditStringList; aTextView : TSynEditStrings);
destructor Destroy; override;
// Converting between Folded and Unfolded Lines/Indexes
@ -1308,13 +1308,13 @@ end;
{ TSynEditFoldedView }
constructor TSynEditFoldedView.Create(aTextBuffer : TSynEditStringList);
constructor TSynEditFoldedView.Create(aTextBuffer : TSynEditStringList; aTextView : TSynEditStrings);
begin
fLines := aTextBuffer;
fLines := aTextView;
fFoldTree := TSynTextFoldAVLTree.Create;
fTopLine := 0;
fLinesInWindow := -1;
fLines.OnLineCountChanged := {$IFDEF FPC}@{$ENDIF}LineCountChanged;
aTextBuffer.OnLineCountChanged := {$IFDEF FPC}@{$ENDIF}LineCountChanged;
end;
destructor TSynEditFoldedView.Destroy;

View File

@ -26,7 +26,7 @@ unit SynEditMarkup;
interface
uses
Classes, SysUtils, Graphics, SynEditTextBuffer, SynEditMiscClasses, Controls, SynEditHighlighter;
Classes, SysUtils, Graphics, SynEditTextBase, SynEditTextBuffer, SynEditMiscClasses, Controls, SynEditHighlighter;
type
@ -38,7 +38,7 @@ type
TSynEditMarkup = class(TObject)
private
fMarkupInfo : TSynSelectedColor;
fLines : TSynEditStringList;
fLines : TSynEditStrings;
fCaret : TPoint;
fTopLine, FLinesInWindow : Integer;
fSynEdit : TCustomControl;
@ -54,7 +54,7 @@ type
procedure MarkupChanged(AMarkup: TObject);
protected
procedure SetInvalidateLinesMethod(const AValue : TInvalidateLines); virtual;
procedure SetLines(const AValue : TSynEditStringList); virtual;
procedure SetLines(const AValue : TSynEditStrings); virtual;
procedure SetTopLine(const AValue : Integer); virtual;
procedure SetLinesInWindow(const AValue : Integer); virtual;
procedure SetCaret(const AValue : TPoint); virtual;
@ -84,7 +84,7 @@ type
property FGColor : TColor read GetFGColor;
property BGColor : TColor read GetBGColor;
property Style : TFontStyles read GetStyle;
property Lines : TSynEditStringList read fLines write SetLines;
property Lines : TSynEditStrings read fLines write SetLines;
property Caret : TPoint read fCaret write SetCaret;
property TopLine : Integer read fTopLine write SetTopLine;
property LinesInWindow : Integer read fLinesInWindow write SetLinesInWindow;
@ -99,7 +99,7 @@ type
protected
procedure SetInvalidateLinesMethod(const AValue : TInvalidateLines); override;
procedure SetLines(const AValue : TSynEditStringList); override;
procedure SetLines(const AValue : TSynEditStrings); override;
procedure SetTopLine(const AValue : Integer); override;
procedure SetLinesInWindow(const AValue : Integer); override;
procedure SetCaret(const AValue : TPoint); override;
@ -161,7 +161,7 @@ begin
DoMarkupChanged(AMarkup as TSynSelectedColor);
end;
procedure TSynEditMarkup.SetLines(const AValue : TSynEditStringList);
procedure TSynEditMarkup.SetLines(const AValue : TSynEditStrings);
begin
if fLines = AValue then exit;
fLines := AValue;
@ -365,7 +365,7 @@ begin
TSynEditMarkup(fMarkUpList[i]).SetInvalidateLinesMethod(AValue);
end;
procedure TSynEditMarkupManager.SetLines(const AValue : TSynEditStringList);
procedure TSynEditMarkupManager.SetLines(const AValue : TSynEditStrings);
var
i : integer;
begin

View File

@ -239,7 +239,7 @@ type
end;
{ TSynInternalImage }
TSynInternalImage = class(TObject)
public
constructor Create(const AName: string; Count: integer);
@ -250,8 +250,8 @@ type
LineHeight: integer; TransparentColor: TColor);
{$ENDIF}
end;
{ TSynEditSearchCustom }
TSynEditSearchCustom = class(TComponent)
@ -420,7 +420,7 @@ procedure TSynGutter.AutoSizeDigitCount(LinesCount: integer);
var
nDigits: integer;
begin
if fVisible and fAutoSize and fShowLineNumbers then begin
if fVisible and fAutoSize and fShowLineNumbers then begin
if fZeroStart then Dec(LinesCount);
nDigits := Max(Length(IntToStr(LinesCount)), fDigitCount);
if fAutoSizeDigitCount <> nDigits then begin
@ -458,7 +458,7 @@ begin
Result := 0;
Exit;
end;
if fShowLineNumbers then
Result := fLeftOffset + fRightOffset + fAutoSizeDigitCount * CharWidth + 2
else

View File

@ -0,0 +1,102 @@
{-------------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
unit SynEditTextBase;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, SynEditTypes;
type
{ TSynEditStrings }
TSynEditStrings = class(TStrings)
protected
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 GetExpandedString(Index: integer): string; virtual; abstract;
function GetLengthOfLongestLine: integer; virtual; abstract;
procedure SetTextStr(const Value: string); override;
public
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;
public
property ExpandedStrings[Index: integer]: string read GetExpandedString;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
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
{ TSynEditStrings }
procedure TSynEditStrings.SetTextStr(const Value : string);
var
StartPos: Integer;
p: Integer;
Len: Integer;
sl: TStringList;
begin
BeginUpdate;
sl:=TStringList.Create;
try
Clear;
p:=1;
StartPos:=p;
Len:=length(Value);
while p<=Len do begin
if not (Value[p] in [#10,#13]) then begin
inc(p);
end else begin
sl.Add(copy(Value,StartPos,p-StartPos));
inc(p);
if (p<=Len) and (Value[p] in [#10,#13]) and (Value[p-1]<>Value[p]) then
inc(p);
StartPos:=p;
end;
end;
if StartPos<=Len then
sl.Add(copy(Value,StartPos,Len-StartPos+1));
AddStrings(sl);
finally
sl.Free;
EndUpdate;
end;
end;
end.

View File

@ -44,7 +44,7 @@ interface
uses
Classes, SysUtils,
{$IFDEF SYN_LAZARUS}
FileUtil, LCLProc, FPCAdds, LCLIntf, LCLType,
FileUtil, LCLProc, FPCAdds, LCLIntf, LCLType, SynEditTextBase,
{$ELSE}
Windows,
{$ENDIF}
@ -52,7 +52,9 @@ uses
type
{begin} //mh 2000-10-10
{$IFNDEF SYN_LAZARUS}
TSynEditRange = pointer;
{$ENDIF}
{begin} //mh 2000-10-19
TSynEditStringFlag = (sfHasTabs, sfHasNoTabs, sfExpandedLengthUnknown);
@ -84,14 +86,18 @@ type
PSynEditStringRecList = ^TSynEditStringRecList;
TSynEditStringRecList = array[0..MaxSynEditStrings - 1] of TSynEditStringRec;
TStringListIndexEvent = procedure(Index: Integer) of object;
TStringListIndexEvent = procedure(Index: Integer) of object;
{$IFDEF SYN_LAZARUS}
TStringListLineCountEvent = procedure(Index, Count: Integer) of object;
{$ENDIF}
{ TSynEditStringList }
{$IFDEF SYN_LAZARUS}
TSynEditStringList = class(TSynEditStrings)
{$ELSE}
TSynEditStringList = class(TStrings)
{$ENDIF}
private
fList: PSynEditStringRecList;
fCount: integer;
@ -111,18 +117,22 @@ type
function ExpandedString(Index: integer): string;
{$IFDEF SYN_LAZARUS}
function ExpandedStringLength(Index: integer): integer;
function GetFoldEndLevel(Index: integer): integer;
function GetFoldMinLevel(Index: integer): integer;
procedure SetFoldEndLevel(Index: integer; const AValue: integer);
procedure SetFoldMinLevel(Index: integer; const AValue: integer);
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;
{$ENDIF}
{$IFNDEF SYN_LAZARUS} // protected in SynLazarus
function GetExpandedString(Index: integer): string;
function GetLengthOfLongestLine: integer;
{$ENDIF}
{end} //mh 2000-10-19
function GetRange(Index: integer): TSynEditRange;
{$IFDEF SYN_LAZARUS}override;{$ENDIF}
procedure Grow;
procedure InsertItem(Index: integer; const S: string);
procedure PutRange(Index: integer; ARange: TSynEditRange);
{$IFDEF SYN_LAZARUS}override;{$ENDIF}
protected
fOnAdded: TStringListIndexEvent;
fOnCleared: TNotifyEvent;
@ -131,6 +141,8 @@ type
fOnPutted: TStringListIndexEvent;
{$IFDEF SYN_LAZARUS}
fOnLineCountChanged : TStringListLineCountEvent;
function GetExpandedString(Index: integer): string; override;
function GetLengthOfLongestLine: integer; override;
{$ENDIF}
function Get(Index: integer): string; override;
function GetCapacity: integer;
@ -143,9 +155,6 @@ type
{$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF} //mh 2000-10-18
procedure SetTabWidth(Value: integer); //mh 2000-10-19
procedure SetUpdateState(Updating: Boolean); override;
{$IFDEF SYN_LAZARUS}
procedure SetTextStr(const Value: string); override;
{$ENDIF}
public
constructor Create;
destructor Destroy; override;
@ -154,14 +163,17 @@ type
procedure Clear; override;
procedure Delete(Index: integer); override;
procedure DeleteLines(Index, NumLines: integer); // DJLP 2000-11-01
{$IFDEF SYN_LAZARUS}override;{$ENDIF}
procedure Exchange(Index1, Index2: integer); override;
procedure Insert(Index: integer; const S: string); override;
procedure InsertLines(Index, NumLines: integer); // DJLP 2000-11-01
{$IFDEF SYN_LAZARUS}override;{$ENDIF}
procedure InsertStrings(Index: integer; NewStrings: TStrings); // DJLP 2000-11-01
{$IFDEF SYN_LAZARUS}override;{$ENDIF}
procedure LoadFromFile(const FileName: string); override;
procedure SaveToFile(const FileName: string); override;
{$IFDEF SYN_LAZARUS}
procedure ClearRanges(ARange: TSynEditRange);
procedure ClearRanges(ARange: TSynEditRange); override;
{$ENDIF}
public
property DosFileFormat: boolean read fDosFileFormat write fDosFileFormat;
@ -199,7 +211,7 @@ type
crDeleteAfterCursor, crDelete, {crSelDelete, crDragDropDelete, } //mh 2000-11-20
crLineBreak, crIndent, crUnindent,
crSilentDelete, crSilentDeleteAfterCursor, //mh 2000-10-30
crNothing);
crNothing {$IFDEF SYN_LAZARUS}, crTrimSpace {$ENDIF});
{ TSynEditUndoItem }
@ -1075,42 +1087,6 @@ begin
end;
end;
{$IFDEF SYN_LAZARUS}
procedure TSynEditStringList.SetTextStr(const Value: string);
var
StartPos: Integer;
p: Integer;
Len: Integer;
sl: TStringList;
begin
BeginUpdate;
sl:=TStringList.Create;
try
Clear;
p:=1;
StartPos:=p;
Len:=length(Value);
while p<=Len do begin
if not (Value[p] in [#10,#13]) then begin
inc(p);
end else begin
sl.Add(copy(Value,StartPos,p-StartPos));
inc(p);
if (p<=Len) and (Value[p] in [#10,#13]) and (Value[p-1]<>Value[p]) then
inc(p);
StartPos:=p;
end;
end;
if StartPos<=Len then
sl.Add(copy(Value,StartPos,Len-StartPos+1));
AddStrings(sl);
finally
sl.Free;
EndUpdate;
end;
end;
{$ENDIF}
{ TSynEditUndoList }
constructor TSynEditUndoList.Create;
@ -1191,8 +1167,8 @@ end;
procedure TSynEditUndoList.EndBlock;
begin
if fBlockCount > 0 then begin
Dec(fBlockCount);
if fBlockCount = 0 then begin
Dec(fBlockCount);
if fBlockCount = 0 then begin
fBlockChangeNumber := 0;
Inc(fNextChangeNumber);
if fNextChangeNumber = 0 then

View File

@ -0,0 +1,435 @@
{-------------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
unit SynEditTextTrimmer;
{$I synedit.inc}
interface
uses
LCLProc,
Classes, SysUtils, SynEditTypes, SynEditTextBase, SynEditTextBuffer, SynEditMiscClasses;
type
{ TSynEditStringTrimmingList }
TSynEditStringTrimmingList = class(TSynEditStrings)
private
fSynStrings: TSynEditStrings;
fCaret: TSynEditCaret;
fUndoList: TSynEditUndoList;
fSpaces: String;
fLineText: String;
fLineIndex: Integer;
fEnabled: Boolean;
fLockCount: Integer;
fLockList : TStringList;
procedure DoCaretChanged(Sender : TObject);
procedure SetEnabled(const AValue : Boolean);
function TrimLine(const S : String; Index: Integer) : String;
function Spaces(Index: Integer) : String;
procedure DoLinesChanged(Index, N: integer);
procedure TrimAfterLock;
protected
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;
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;
property ExpandedStrings[Index: integer]: string read GetExpandedString;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
public
procedure Lock;
procedure UnLock;
procedure ForceTrim; // for redo; redo can not wait for UnLock
property Enabled : Boolean read fEnabled write SetEnabled;
property UndoList: TSynEditUndoList read fUndoList write fUndoList;
end;
implementation
{ TSynEditStringTrimmingList }
constructor TSynEditStringTrimmingList.Create(ASynStringSource : TSynEditStrings; ACaret: TSynEditCaret);
begin
Inherited Create;
fSynStrings := ASynStringSource;
fCaret := ACaret;
fCaret.AddChangeHandler(@DoCaretChanged);
fLockList := TStringList.Create;
fLineIndex:= -1;
fSpaces := '';
fEnabled:=false;
end;
destructor TSynEditStringTrimmingList.Destroy;
begin
fCaret.RemoveChangeHandler(@DoCaretChanged);
FreeAndNil(fLockList);
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;
begin
if (fLineIndex = TSynEditCaret(Sender).LinePos - 1) then exit;
if (length(fSpaces) > 0) and (fLineIndex > 0)
and (fLineIndex <= fSynStrings.Count)
and (fLockCount = 0) then begin
s := fSynStrings[fLineIndex];
fSynStrings[fLineIndex] := s; // trigger OnPutted, so the line gets repainted
fUndoList.AddChange(crTrimSpace, Point(1+length(s), fLineIndex+1),
Point(1+length(s)+length(fSpaces), fLineIndex+1), fSpaces, smNormal);
end;
fLineIndex := TSynEditCaret(Sender).LinePos - 1;
fSpaces := '';
end;
procedure TSynEditStringTrimmingList.SetEnabled(const AValue : Boolean);
begin
if fEnabled = AValue then exit;
fEnabled:=AValue;
fLockList.Clear;
fLockCount:=0;
if fEnabled and (fLineIndex >= 0) and (fLineIndex < fSynStrings.Count) then
fSynStrings[fLineIndex] := TrimLine(fSynStrings[fLineIndex], fLineIndex);
end;
function TSynEditStringTrimmingList.TrimLine(const S: String; Index: Integer): String;
var
l, i:integer;
temp: String;
begin
if not fEnabled then exit(s);
l := length(s);
i := l;
while (i>0) and (s[i] in [#9, ' ']) do dec(i);
temp := copy(s, i+1, l-i);
if i=l then
result := s // No need to make a copy
else
result := copy(s, 1, i);
if fLockCount > 0 then begin
i := fLockList.IndexOfObject(TObject(pointer(Index)));
if i < 0 then
fLockList.AddObject(temp, TObject(pointer(Index)))
else
fLockList[i] := temp;
end
else if (fLineIndex = Index) then begin
fSpaces := temp;
fLineText:=result;
end;
end ;
function TSynEditStringTrimmingList.Spaces(Index : Integer) : String;
var
i : Integer;
begin
if fLockCount > 0 then begin
i := fLockList.IndexOfObject(TObject(Pointer(Index)));
if i < 0 then
result := ''
else
result := fLockList[i];
exit;
end;
if Index <> fLineIndex then exit('');
if (fLineIndex < 0) or (fLineIndex >= fSynStrings.Count)
or (fLineText <> fSynStrings[fLineIndex]) then begin
fSpaces:='';
fLineText:='';
end;
Result:= fSpaces;
end;
procedure TSynEditStringTrimmingList.DoLinesChanged(Index, N : integer);
var
i, j: Integer;
begin
if fLockCount > 0 then begin
for i := fLockList.Count-1 downto 0 do begin
j := Integer(Pointer(fLockList.Objects[i]));
if (j >= Index) and (j < Index - N) then
fLockList.Delete(i)
else if j > Index then
fLockList.Objects[i] := TObject(Pointer(j + N));
end;
end else begin
if (fLineIndex >= Index) and (fLineIndex < Index - N) then
fLineIndex:=-1
else if fLineIndex > Index then
inc(fLineIndex, N);
end;
end;
procedure TSynEditStringTrimmingList.Lock;
begin
if (fLockCount = 0) and (fLineIndex >= 0) then
fLockList.AddObject(Spaces(fLineIndex), TObject(Pointer(fLineIndex)));
inc(fLockCount);
end;
procedure TSynEditStringTrimmingList.UnLock;
var
i, index, llen, slen: Integer;
ltext: String;
begin
dec(fLockCount);
if (fLockCount = 0) then TrimAfterLock;
end;
procedure TSynEditStringTrimmingList.TrimAfterLock;
var
i, index, llen, slen: Integer;
ltext: String;
begin
i := fLockList.IndexOfObject(TObject(Pointer(fLineIndex)));
if i >= 0 then begin
fSpaces:= fLockList[i];
if (fLineIndex >= 0) and (fLineIndex < fSynStrings.Count) then
fLineText := fSynStrings[fLineIndex];
fLockList.Delete(i);
end;
for i := 0 to fLockList.Count-1 do begin
index := Integer(Pointer(fLockList.Objects[i]));
slen := length(fLockList[i]);
if (slen > 0) and (index >= 0) and (index < fSynStrings.Count) then begin
ltext := fSynStrings[index];
llen := length(ltext);
fSynStrings[index] := ltext; // trigger OnPutted, so the line gets repainted
fUndoList.AddChange(crTrimSpace, Point(1+llen, index+1),
Point(1+llen+slen, index+1), fLockList[i], smNormal);
end;
end;
fLockList.Clear;
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
Result:= fSynStrings.ExpandedStrings[Index] + Spaces(Index);
end;
function TSynEditStringTrimmingList.GetLengthOfLongestLine : integer;
var
i: Integer;
begin
Result:= fSynStrings.LengthOfLongestLine;
if (fLineIndex >= 0) and (fLineIndex < Count) then begin
i:= length(ExpandedStrings[fLineIndex]);
if (i > Result) then Result := i;
end;
end;
function TSynEditStringTrimmingList.Get(Index : integer) : string;
begin
Result:= fSynStrings.Strings[Index] + Spaces(Index);
end;
function TSynEditStringTrimmingList.GetObject(Index : integer) : TObject;
begin
Result:= fSynStrings.Objects[Index];
end;
procedure TSynEditStringTrimmingList.Put(Index : integer; const S : string);
begin
fSynStrings.Strings[Index]:= TrimLine(S, Index);
end;
procedure TSynEditStringTrimmingList.PutObject(Index : integer; AObject : TObject);
begin
fSynStrings.Objects[Index]:= AObject;
end;
function TSynEditStringTrimmingList.Add(const S : string) : integer;
var
c : Integer;
begin
c := fSynStrings.Count;
DoLinesChanged(c, 1);
Result := fSynStrings.Add(TrimLine(S, c));
end;
procedure TSynEditStringTrimmingList.AddStrings(AStrings : TStrings);
var
i, c : Integer;
begin
c := fSynStrings.Count;
DoLinesChanged(c, AStrings.Count);
for i := 0 to AStrings.Count-1 do
AStrings[i] := TrimLine(AStrings[i], c + i);
fSynStrings.AddStrings(AStrings);
end;
procedure TSynEditStringTrimmingList.Clear;
begin
fSynStrings.Clear;
fLineIndex:=-1;
end;
procedure TSynEditStringTrimmingList.Delete(Index : integer);
begin
fSynStrings.Delete(Index);
DoLinesChanged(Index, -1);
end;
procedure TSynEditStringTrimmingList.DeleteLines(Index, NumLines : integer);
begin
fSynStrings.DeleteLines(Index, NumLines);
DoLinesChanged(Index, -NumLines);
end;
procedure TSynEditStringTrimmingList.Insert(Index : integer; const S : string);
begin
DoLinesChanged(Index, 1);
fSynStrings.Insert(Index, TrimLine(S, Index));
end;
procedure TSynEditStringTrimmingList.InsertLines(Index, NumLines : integer);
begin
DoLinesChanged(Index, NumLines);
fSynStrings.InsertLines(Index, NumLines);
end;
procedure TSynEditStringTrimmingList.InsertStrings(Index : integer; NewStrings : TStrings);
var
i : Integer;
begin
DoLinesChanged(Index, NewStrings.Count);
for i := 0 to NewStrings.Count-1 do
NewStrings[i] := TrimLine(NewStrings[i], Index+i);
fSynStrings.InsertStrings(Index, NewStrings);
end;
procedure TSynEditStringTrimmingList.Exchange(Index1, Index2 : integer);
begin
fSynStrings.Exchange(Index1, Index2);
if fLineIndex = Index1 then
fLineIndex := Index2
else if fLineIndex = Index2 then
fLineIndex := Index1;
end;
end.

View File

@ -72,6 +72,10 @@ type
ssoRegExpr, ssoRegExprMultiLine{$ENDIF});
TSynSearchOptions = set of TSynSearchOption;
{$IFDEF SYN_LAZARUS}
TSynEditRange = pointer;
{$ENDIF}
implementation
end.