From 400f05dee00db13cb43036eccb1508fe58bf7208 Mon Sep 17 00:00:00 2001 From: martin Date: Wed, 14 Dec 2011 02:53:19 +0000 Subject: [PATCH] SynEdit: refactor painting git-svn-id: trunk@34165 - --- .gitattributes | 1 + components/synedit/allsynedit.pas | 2 +- components/synedit/lazsynedittext.pas | 1072 +++++++++++++++++ components/synedit/synbeautifier.pas | 2 +- components/synedit/synedit.pp | 108 +- components/synedit/syneditfoldedview.pp | 46 +- components/synedit/syneditmarks.pp | 2 +- components/synedit/syneditmarkup.pp | 2 +- .../synedit/syneditmarkupctrlmouselink.pp | 2 +- components/synedit/syneditmiscclasses.pp | 2 +- components/synedit/syneditpointclasses.pas | 2 +- components/synedit/synedittextbase.pas | 868 ------------- components/synedit/synedittextbuffer.pp | 89 +- .../synedit/synedittextdoublewidthchars.pas | 2 +- components/synedit/synedittexttabexpander.pas | 2 +- components/synedit/synedittexttrimmer.pas | 72 +- components/synedit/synedittypes.pp | 3 + components/synedit/syngutterlinenumber.pp | 2 +- components/synedit/syngutterlineoverview.pp | 2 +- components/synedit/synpluginsyncroedit.pp | 2 +- .../synedit/synpluginsyncronizededitbase.pp | 4 +- components/synedit/synplugintemplateedit.pp | 2 +- ide/sourceeditor.pp | 2 +- ide/sourcesyneditor.pas | 2 +- 24 files changed, 1346 insertions(+), 947 deletions(-) create mode 100644 components/synedit/lazsynedittext.pas diff --git a/.gitattributes b/.gitattributes index b1ff8f4510..61e83031f7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2322,6 +2322,7 @@ components/synedit/languages/synmacrorecorder.pt_BR.po svneol=native#text/plain components/synedit/languages/synmacrorecorder.ru.po svneol=native#text/plain components/synedit/languages/synmacrorecorder.uk.po svneol=native#text/plain components/synedit/languages/synmacrorecorder.zh_CN.po svneol=native#text/utf8 +components/synedit/lazsynedittext.pas svneol=native#text/pascal components/synedit/synbeautifier.pas svneol=native#text/plain components/synedit/syncompletion.pas svneol=native#text/pascal components/synedit/syndesignstringconstants.pas svneol=native#text/plain diff --git a/components/synedit/allsynedit.pas b/components/synedit/allsynedit.pas index a6ddcdd460..8e283b99de 100644 --- a/components/synedit/allsynedit.pas +++ b/components/synedit/allsynedit.pas @@ -25,7 +25,7 @@ uses SynMacroRecorder, SynMemo, SynPluginSyncroEdit, SynPluginSyncronizedEditBase, SynPluginTemplateEdit, SynPropertyEditObjectList, SynRegExpr, SynTextDrawer, SynEditMarkupGutterMark, SynHighlighterBat, SynHighlighterIni, SynEditMarkupSpecialChar, - LazarusPackageIntf; + LazSynEditText, LazarusPackageIntf; implementation diff --git a/components/synedit/lazsynedittext.pas b/components/synedit/lazsynedittext.pas new file mode 100644 index 0000000000..13ad54e46f --- /dev/null +++ b/components/synedit/lazsynedittext.pas @@ -0,0 +1,1072 @@ +{------------------------------------------------------------------------------- +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 LazSynEditText; + +{$I synedit.inc} +{$IFOPT C+} + {$DEFINE AssertSynMemIndex} + {$DEFINE SynAssert} +{$ENDIF} +{$IFDEF SynAssert} + {$DEFINE AssertSynMemIndex} +{$ENDIF} + +interface + +uses + Classes, SysUtils, Graphics, LCLProc, SynEditTypes, SynEditMiscProcs, + SynEditHighlighter, SynEditKeyCmds, SynEditTextBase; + +type + TSynEditStrings = class; + + TStringListLineCountEvent = procedure(Sender: TSynEditStrings; + Index, Count: Integer) of object; + TStringListLineEditEvent = procedure(Sender: TSynEditStrings; + LinePos, BytePos, Count, LineBrkCnt: Integer; + Text: String) of object; + + TSynEditNotifyReason = ( // TStringListLineCountEvent + senrLineCount, // Lines Inserted or Deleted (if not empty, they will trigger senrLineChange too) + senrLineChange, // Lines modified (also triggered by senrEditAction) + senrHighlightChanged, // used by Highlighter (invalidate and fold checks needed) + // TStringListLineEditEvent + senrEditAction, // EditInsert, EditDelete, EditLineBreak, ... + // TNotifyEvent + senrCleared, + senrUndoRedoAdded, + senrModifiedChanged, // The modified flag was changed + // Paintlocks are managed by SynEdit, but need distribution to shared edits + senrIncOwnedPaintLock, // Inform other SynEdits (ForeignPaintLock) + senrDecOwnedPaintLock, + senrIncPaintLock, // Actual PaintLock + senrDecPaintLock, + senrAfterIncPaintLock, // For plugins, etc... + senrBeforeDecPaintLock, + senrTextBufferChanging, // About to change + senrTextBufferChanged + ); + + TPhysicalCharWidths = Array of Shortint; + TPhysicalCharWidth = ShortInt; + PPhysicalCharWidth = ^TPhysicalCharWidth; + + { TSynLogicalPhysicalConvertor } +const + SYN_LP_MIN_ALLOC = 1024; // Keep at least n*SizeOf(TPhysicalCharWidths) allocated +type + TSynLogicalPhysicalConvertor = class + private + FLines: TSynEditStrings; + FCurrentWidths: TPhysicalCharWidths; + FCurrentWidthsLen, FCurrentWidthsAlloc: Integer; + FCurrentLine: Integer; + FTextChangeStamp, FViewChangeStamp: Int64; + // TODOtab-width + procedure PrepareWidthsForLine(AIndex: Integer; AForce: Boolean = False); + public + constructor Create(ALines: TSynEditStrings); + destructor Destroy; override; + // Line is 0-based // Column is 1-based + function PhysicalToLogical(AIndex, AColumn: Integer): Integer; + function PhysicalToLogical(AIndex, AColumn: Integer; out AColOffset: Integer): Integer; + // ACharPos 1=before 1st char + function LogicalToPhysical(AIndex, ABytePos: Integer): Integer; + function LogicalToPhysical(AIndex, ABytePos: Integer; var AColOffset: Integer): Integer; + end; + + (* + TLazSynDisplayView: + - Represents the visible text + e.g. excludes folds, maps wrapped lines, ... + + TSynEditStrings: + - Represents the entire text, + inluding temporary chars or text that may not be displayed. + Temporary chars (e.g. trailing spaces) may not be accesibl via SynEdit.Lines + - Can be Edited + *) + + { TLazSynDisplayView } + + TLazSynDisplayView = class + private + FNextView: TLazSynDisplayView; + public + constructor Create; + property NextView: TLazSynDisplayView read FNextView write FNextView; + public + procedure InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); virtual; + procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); virtual; + procedure FinishHighlighterTokens; virtual; + function GetNextHighlighterToken(out ATokenStart: PChar; out ATokenLength: integer; + out ATokenAttr: TSynHighlighterAttributes + ): Boolean; virtual; + function GetDrawDividerInfo: TSynDividerDrawConfigSetting; virtual; + // todo: gutter info + end; + + { TLazSynDisplayViewEx } + + TLazSynDisplayViewEx = class(TLazSynDisplayView) + private + FInitialized: boolean; + FCurrentTokenHighlighter: TSynCustomHighlighter; + FCurrentTokenLine: TLineIdx; + procedure SetCurrentTokenLine(AValue: TLineIdx); + protected + property Initialized: boolean read FInitialized; + property CurrentTokenHighlighter: TSynCustomHighlighter read FCurrentTokenHighlighter; + property CurrentTokenLine: TLineIdx read FCurrentTokenLine write SetCurrentTokenLine; + public + constructor Create; + procedure InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); override; + procedure FinishHighlighterTokens; override; + end; + + { TSynEditStrings } + + TSynEditStrings = class(TSynEditStringsBase) + private + FSenderUpdateCount: Integer; + FLogPhysConvertor :TSynLogicalPhysicalConvertor; + protected + FIsUtf8: Boolean; + function GetIsUtf8 : Boolean; virtual; + procedure SetIsUtf8(const AValue : Boolean); virtual; + + function GetExpandedString(Index: integer): string; virtual; abstract; + function GetLengthOfLongestLine: integer; virtual; abstract; + procedure SetTextStr(const Value: string); override; + function GetTextChangeStamp: int64; virtual; abstract; + function GetViewChangeStamp: int64; virtual; + + function GetIsInEditAction: Boolean; virtual; abstract; + procedure IncIsInEditAction; virtual; abstract; + procedure DecIsInEditAction; virtual; abstract; + function GetUndoList: TSynEditUndoList; virtual; abstract; + function GetRedoList: TSynEditUndoList; virtual; abstract; + function GetCurUndoList: TSynEditUndoList; virtual; abstract; + procedure SetIsUndoing(const AValue: Boolean); virtual; abstract; + function GetIsUndoing: Boolean; virtual; abstract; + procedure SetIsRedoing(const AValue: Boolean); virtual; abstract; + function GetIsRedoing: Boolean; virtual; abstract; + procedure IgnoreSendNotification(AReason: TSynEditNotifyReason; + ReEnable: Boolean); virtual; abstract; + + procedure SetUpdateState(Updating: Boolean); override; + procedure SetUpdateState(Updating: Boolean; Sender: TObject); virtual; abstract; + + procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); virtual; abstract; + + function GetDisplayView: TLazSynDisplayView; virtual; + public + constructor Create; + destructor Destroy; override; + procedure BeginUpdate(Sender: TObject); overload; + procedure EndUpdate(Sender: TObject); overload; + function IsUpdating: Boolean; + + // Currently Lines are physical + procedure DeleteLines(Index, NumLines: integer); virtual; abstract; + procedure InsertLines(Index, NumLines: integer); virtual; abstract; + procedure InsertStrings(Index: integer; NewStrings: TStrings); virtual; abstract; + + procedure AddGenericHandler(AReason: TSynEditNotifyReason; + AHandler: TMethod); virtual; abstract; + procedure AddChangeHandler(AReason: TSynEditNotifyReason; + AHandler: TStringListLineCountEvent); + procedure AddNotifyHandler(AReason: TSynEditNotifyReason; + AHandler: TNotifyEvent); + + procedure RemoveGenericHandler(AReason: TSynEditNotifyReason; + AHandler: TMethod); virtual; abstract; + procedure RemoveChangeHandler(AReason: TSynEditNotifyReason; + AHandler: TStringListLineCountEvent); + procedure RemoveNotifyHandler(AReason: TSynEditNotifyReason; + AHandler: TNotifyEvent); + + procedure AddEditHandler(AHandler: TStringListLineEditEvent); + procedure RemoveEditHandler(AHandler: TStringListLineEditEvent); + procedure SendHighlightChanged(aIndex, aCount: Integer); override; + procedure SendNotification(AReason: TSynEditNotifyReason; + ASender: TSynEditStrings; aIndex, aCount: Integer; + aBytePos: Integer = -1; aLen: Integer = 0; + aTxt: String = ''); virtual; abstract; + procedure SendNotification(AReason: TSynEditNotifyReason; + ASender: TObject); virtual; abstract; + procedure FlushNotificationCache; virtual; abstract; + public + function GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; + function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; + // Byte to Char + function LogicalToPhysicalPos(const p: TPoint): TPoint; + function LogicalToPhysicalCol(const Line: String; + Index, LogicalPos: integer): integer; virtual; + // Char to Byte + function PhysicalToLogicalPos(const p: TPoint): TPoint; + function PhysicalToLogicalCol(const Line: string; + Index, PhysicalPos: integer): integer; virtual; + property LogPhysConvertor :TSynLogicalPhysicalConvertor read FLogPhysConvertor; + public + // Currently Lines are physical + procedure EditInsert(LogX, LogY: Integer; AText: String); virtual; abstract; + function EditDelete(LogX, LogY, ByteLen: Integer): String; virtual; abstract; + procedure EditLineBreak(LogX, LogY: Integer); virtual; abstract; + procedure EditLineJoin(LogY: Integer; FillText: String = ''); virtual; abstract; + procedure EditLinesInsert(LogY, ACount: Integer; AText: String = ''); virtual; abstract; + procedure EditLinesDelete(LogY, ACount: Integer); virtual; abstract; + procedure EditUndo(Item: TSynEditUndoItem); virtual; abstract; + procedure EditRedo(Item: TSynEditUndoItem); virtual; abstract; + property IsInEditAction: Boolean read GetIsInEditAction; + property UndoList: TSynEditUndoList read GetUndoList; + property RedoList: TSynEditUndoList read GetRedoList; + property CurUndoList: TSynEditUndoList read GetCurUndoList; // Re or Undo (Redo while undoing) + property IsUndoing: Boolean read GetIsUndoing write SetIsUndoing; + property IsRedoing: Boolean read GetIsRedoing write SetIsRedoing; + public + property TextChangeStamp: int64 read GetTextChangeStamp; + property ViewChangeStamp: int64 read GetViewChangeStamp; // tabs-size, trailing-spaces, ... + property ExpandedStrings[Index: integer]: string read GetExpandedString; + property LengthOfLongestLine: integer read GetLengthOfLongestLine; + property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8; + public + property DisplayView: TLazSynDisplayView read GetDisplayView; + end; + + { TSynEditStringsLinked } + + TSynEditStringsLinked = class(TSynEditStrings) + private + procedure SetSynStrings(AValue: TSynEditStrings); + protected + fSynStrings: TSynEditStrings; + + function GetIsUtf8 : Boolean; override; + procedure SetIsUtf8(const AValue : Boolean); override; + function GetTextChangeStamp: int64; override; + function GetViewChangeStamp: int64; override; + + function GetRange(Index: Pointer): TSynManagedStorageMem; override; + procedure PutRange(Index: Pointer; const ARange: TSynManagedStorageMem); override; + + function GetExpandedString(Index: integer): string; override; + function GetLengthOfLongestLine: integer; override; + + procedure IgnoreSendNotification(AReason: TSynEditNotifyReason; + IncIgnore: Boolean); override; + function GetIsInEditAction: Boolean; override; + procedure IncIsInEditAction; override; + procedure DecIsInEditAction; override; + function GetUndoList: TSynEditUndoList; override; + function GetRedoList: TSynEditUndoList; override; + function GetCurUndoList: TSynEditUndoList; override; + procedure SetIsUndoing(const AValue: Boolean); override; + function GetIsUndoing: Boolean; override; + procedure SetIsRedoing(const AValue: Boolean); override; + function GetIsRedoing: Boolean; 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; Sender: TObject); override; + procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override; + + function GetDisplayView: TLazSynDisplayView; 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; + function GetPChar(ALineIndex: Integer; out ALen: Integer): PChar; override; // experimental + + procedure AddGenericHandler(AReason: TSynEditNotifyReason; + AHandler: TMethod); override; + procedure RemoveGenericHandler(AReason: TSynEditNotifyReason; + AHandler: TMethod); override; + procedure SendNotification(AReason: TSynEditNotifyReason; + ASender: TSynEditStrings; aIndex, aCount: Integer; + aBytePos: Integer = -1; aLen: Integer = 0; + aTxt: String = ''); override; + procedure SendNotification(AReason: TSynEditNotifyReason; + ASender: TObject); override; + procedure FlushNotificationCache; override; + + //function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; override; + property NextLines: TSynEditStrings read fSynStrings write SetSynStrings; + public + // LogX, LogY are 1-based + procedure EditInsert(LogX, LogY: Integer; AText: String); override; + function EditDelete(LogX, LogY, ByteLen: Integer): String; override; + procedure EditLineBreak(LogX, LogY: Integer); override; + procedure EditLineJoin(LogY: Integer; FillText: String = ''); override; + procedure EditLinesInsert(LogY, ACount: Integer; AText: String = ''); override; + procedure EditLinesDelete(LogY, ACount: Integer); override; + procedure EditUndo(Item: TSynEditUndoItem); override; + procedure EditRedo(Item: TSynEditUndoItem); override; + end; + + +implementation + +{ TLazSynDisplayViewEx } + +procedure TLazSynDisplayViewEx.SetCurrentTokenLine(AValue: TLineIdx); +begin + {$IFDEF SynAssert} + if not Initialized then + raise Exception.Create('uninitialized SetCurrentTokenLine'); + {$ENDIF} + FCurrentTokenLine := AValue; +end; + +constructor TLazSynDisplayViewEx.Create; +begin + inherited Create; + FInitialized := False; +end; + +procedure TLazSynDisplayViewEx.InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); +begin + {$IFDEF SynAssert} + if FInitialized then + raise Exception.Create('Nested InitHighlighterTokensForLine'); + {$ENDIF} + FCurrentTokenHighlighter := AHighlighter; + FCurrentTokenLine := -1; + FInitialized := True; + inherited; +end; + +procedure TLazSynDisplayViewEx.FinishHighlighterTokens; +begin + FCurrentTokenHighlighter := nil; + FInitialized := False; + inherited; +end; + +{ TLazSynDisplayView } + +constructor TLazSynDisplayView.Create; +begin + FNextView := nil; +end; + +procedure TLazSynDisplayView.InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); +begin + if assigned(FNextView) then + FNextView.InitHighlighterTokens(AHighlighter); +end; + +procedure TLazSynDisplayView.SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); +begin + if assigned(FNextView) then + FNextView.SetHighlighterTokensLine(ALine, ARealLine); +end; + +procedure TLazSynDisplayView.FinishHighlighterTokens; +begin + if assigned(FNextView) then + FNextView.FinishHighlighterTokens; +end; + +function TLazSynDisplayView.GetNextHighlighterToken(out ATokenStart: PChar; out + ATokenLength: integer; out ATokenAttr: TSynHighlighterAttributes): Boolean; +begin + if assigned(FNextView) then + Result := FNextView.GetNextHighlighterToken(ATokenStart, ATokenLength, ATokenAttr) + else + Result := False; +end; + +function TLazSynDisplayView.GetDrawDividerInfo: TSynDividerDrawConfigSetting; +begin + if assigned(FNextView) then + Result := FNextView.GetDrawDividerInfo + else + Result.Color := clNone; +end; + +{ TSynLogicalPhysicalConvertor } + +procedure TSynLogicalPhysicalConvertor.PrepareWidthsForLine(AIndex: Integer; + AForce: Boolean); +var + LineLen: Integer; + Line: PChar; +//const dbg_cnt: integer = 0; +begin + if (not AForce) and (FCurrentLine = AIndex) and + (FLines.TextChangeStamp = FTextChangeStamp) and (FLines.ViewChangeStamp = FViewChangeStamp) + then begin + //debugln(['**************** RE-USING widths: ', AIndex,' (',dbgs(Pointer(self)),')']); + //dbg_cnt := dbg_cnt + 1; + exit; + end; + + if (AIndex < 0) or (AIndex >= FLines.Count) then begin + FCurrentWidthsLen := 0; + FViewChangeStamp := FLines.ViewChangeStamp; + FTextChangeStamp := FLines.TextChangeStamp; + exit; + end; + + Line := FLines.GetPChar(AIndex, LineLen); + if LineLen > FCurrentWidthsAlloc then begin + //debugln(['**************** COMPUTING widths (grow): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]); + SetLength(FCurrentWidths, LineLen); + FCurrentWidthsAlloc := LineLen; + end + else if FCurrentWidthsAlloc > Max(Max(LineLen, FCurrentWidthsLen)*4, SYN_LP_MIN_ALLOC) then begin + //debugln(['**************** COMPUTING widths (shrink): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]); + FCurrentWidthsAlloc := Max(Max(LineLen, FCurrentWidthsLen), SYN_LP_MIN_ALLOC) ; + SetLength(FCurrentWidths, FCurrentWidthsAlloc); + //end + //else begin + // debugln(['**************** COMPUTING widths: ', AIndex,' (',dbgs(Pointer(self)),') alloc=',FCurrentWidthsAlloc]); + end; + //debugln(['**************** NEW for index:: ', AIndex,' (',dbgs(Pointer(self)),') after index: ', FCurrentLine, ' used ', dbg_cnt,' times // old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen, ' viewchg:',dbgs(not(FViewChangeStamp=FLines.ViewChangeStamp)),' txtchg:',dbgs(not(FTextChangeStamp=FLines.TextChangeStamp))]); dbg_cnt := 0; + + FCurrentWidthsLen := LineLen; + if LineLen > 0 then + FLines.DoGetPhysicalCharWidths(Line, LineLen, AIndex, @FCurrentWidths[0]); + FViewChangeStamp := FLines.ViewChangeStamp; + FTextChangeStamp := FLines.TextChangeStamp; + FCurrentLine := AIndex; +end; + +constructor TSynLogicalPhysicalConvertor.Create(ALines: TSynEditStrings); +begin + FLines := ALines; + FCurrentLine := -1; + FCurrentWidths := nil; + FCurrentWidthsLen := 0; + FCurrentWidthsAlloc := 0; +end; + +destructor TSynLogicalPhysicalConvertor.Destroy; +begin + SetLength(FCurrentWidths, 0); + inherited Destroy; +end; + +function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex, + AColumn: Integer): Integer; +var + ColOffs: Integer; +begin + Result := PhysicalToLogical(AIndex, AColumn, ColOffs); +end; + +function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex, AColumn: Integer; + out AColOffset: Integer): Integer; +var + BytePos, ScreenPos, ScreenPosOld: integer; +begin + PrepareWidthsForLine(AIndex); + + ScreenPos := 1; + BytePos := 0; + while BytePos < FCurrentWidthsLen do begin + ScreenPosOld := ScreenPos; + ScreenPos := ScreenPos + FCurrentWidths[BytePos]; + inc(BytePos); + if ScreenPos > AColumn then begin + AColOffset := AColumn - ScreenPosOld; + exit(BytePos); + end; + end; + + // Column at/past end of line + AColOffset := 0; + Result := BytePos + 1 + AColumn - ScreenPos; +end; + +function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex, + ABytePos: Integer): Integer; +var + ColOffs: Integer; +begin + ColOffs := 0; + Result := LogicalToPhysical(AIndex, ABytePos, ColOffs); +end; + +function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex, ABytePos: Integer; + var AColOffset: Integer): Integer; +var + i: integer; + CharWidths: TPhysicalCharWidths; +begin + {$IFDEF AssertSynMemIndex} + if (ABytePos <= 0) then + raise Exception.Create(Format('Bad Bytpos for PhystoLogical BytePos=%d ColOffs= %d idx= %d',[ABytePos, AColOffset, AIndex])); + {$ENDIF} + if (ABytePos = 0) or ((ABytePos = 1) and (AColOffset=0)) then + exit(ABytePos); + PrepareWidthsForLine(AIndex); + + dec(ABytePos); + if ABytePos >= FCurrentWidthsLen then begin + Result := 1 + ABytePos - FCurrentWidthsLen; + ABytePos := FCurrentWidthsLen; + AColOffset := 0; + end + else begin + AColOffset := Min(AColOffset, FCurrentWidths[ABytePos]-1); + Result := 1 + AColOffset; + end; + + for i := 0 to ABytePos - 1 do + Result := Result + FCurrentWidths[i]; +end; + +{ TSynEditStrings } + +constructor TSynEditStrings.Create; +begin + FLogPhysConvertor := TSynLogicalPhysicalConvertor.Create(self); + inherited Create; + IsUtf8 := True; +end; + +destructor TSynEditStrings.Destroy; +begin + FreeAndNil(FLogPhysConvertor); + inherited Destroy; +end; + +procedure TSynEditStrings.BeginUpdate(Sender: TObject); +begin + if FSenderUpdateCount = 0 then + SetUpdateState(true, Sender); + inc(FSenderUpdateCount); +end; + +procedure TSynEditStrings.EndUpdate(Sender: TObject); +begin + If FSenderUpdateCount>0 then + Dec(FSenderUpdateCount); + if FSenderUpdateCount=0 then + SetUpdateState(False, Sender); +end; + +function TSynEditStrings.IsUpdating: Boolean; +begin + Result := (FSenderUpdateCount > 0) or (UpdateCount > 0); +end; + +procedure TSynEditStrings.AddChangeHandler(AReason: TSynEditNotifyReason; + AHandler: TStringListLineCountEvent); +begin + AddGenericHandler(AReason, TMethod(AHandler)); +end; + +procedure TSynEditStrings.AddNotifyHandler(AReason: TSynEditNotifyReason; + AHandler: TNotifyEvent); +begin + AddGenericHandler(AReason, TMethod(AHandler)); +end; + +procedure TSynEditStrings.RemoveChangeHandler(AReason: TSynEditNotifyReason; + AHandler: TStringListLineCountEvent); +begin + RemoveGenericHandler(AReason, TMethod(AHandler)); +end; + +procedure TSynEditStrings.RemoveNotifyHandler(AReason: TSynEditNotifyReason; + AHandler: TNotifyEvent); +begin + RemoveGenericHandler(AReason, TMethod(AHandler)); +end; + +procedure TSynEditStrings.AddEditHandler(AHandler: TStringListLineEditEvent); +begin + AddGenericHandler(senrEditAction, TMethod(AHandler)); +end; + +procedure TSynEditStrings.RemoveEditHandler(AHandler: TStringListLineEditEvent); +begin + RemoveGenericHandler(senrEditAction, TMethod(AHandler)); +end; + +procedure TSynEditStrings.SendHighlightChanged(aIndex, aCount: Integer); +begin + SendNotification(senrHighlightChanged, Self, aIndex, aCount); +end; + +function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; +var + s: string; +begin + s := Strings[Index]; + Result := GetPhysicalCharWidths(PChar(s), length(s), Index); +end; + +function TSynEditStrings.GetPhysicalCharWidths(Line: PChar; LineLen, + Index: Integer): TPhysicalCharWidths; +begin + SetLength(Result, LineLen); + if LineLen = 0 then + exit; + DoGetPhysicalCharWidths(Line, LineLen, Index, @Result[0]); +end; + +function TSynEditStrings.GetDisplayView: TLazSynDisplayView; +begin + Result := nil; +end; + +function TSynEditStrings.GetIsUtf8 : Boolean; +begin + Result := FIsUtf8; +end; + +procedure TSynEditStrings.SetIsUtf8(const AValue : Boolean); +begin + FIsUtf8 := AValue; +end; + +procedure TSynEditStrings.SetTextStr(const Value : string); +var + StartPos: PChar; + p: PChar; + Last: PChar; + sl: TStringList; + s: string; +begin + if Value='' then begin + Clear; + exit; + end; + BeginUpdate; + sl:=TStringList.Create; + try + Clear; + p:=PChar(Value); + StartPos:=p; + Last:=p+length(Value); + while p'' then + System.Move(StartPos^,s[1],length(s)); + sl.Add(s); + if (p[1] in [#10,#13]) and (p[1]<>p^) then + inc(p); + inc(p); + StartPos:=p; + end; + end; + if StartPos'' then + System.Move(StartPos^,s[1],length(s)); + sl.Add(s); + end; + AddStrings(sl); + finally + sl.Free; + EndUpdate; + end; +end; + +function TSynEditStrings.GetViewChangeStamp: int64; +begin + Result := 0; +end; + +procedure TSynEditStrings.SetUpdateState(Updating: Boolean); +begin + // Update/check "FSenderUpdateCount", to avoid extra locking/unlocking + if Updating then + BeginUpdate(nil) + else + EndUpdate(nil); +end; + +function TSynEditStrings.LogicalToPhysicalPos(const p : TPoint) : TPoint; +begin + Result := p; + Result.X := FLogPhysConvertor.LogicalToPhysical(p.y - 1, p.x); +// if Result.Y - 1 < Count then +// Result.X:=LogicalToPhysicalCol(self[Result.Y - 1], Result.Y, Result.X); +end; + +function TSynEditStrings.LogicalToPhysicalCol(const Line : String; + Index, LogicalPos: integer) : integer; +var + i, ByteLen: integer; + CharWidths: TPhysicalCharWidths; +begin + CharWidths := GetPhysicalCharWidths(Pchar(Line), length(Line), Index); + ByteLen := length(Line); + dec(LogicalPos); + + if LogicalPos > ByteLen then begin + Result := 1 + LogicalPos - ByteLen; + LogicalPos := ByteLen; + end + else + Result := 1; + + for i := 0 to LogicalPos - 1 do + Result := Result + CharWidths[i]; +end; + +function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint; +begin + Result := p; + Result.X := FLogPhysConvertor.PhysicalToLogical(p.y - 1, p.x); +// if (Result.Y>=1) and (Result.Y <= Count) then +// Result.X:=PhysicalToLogicalCol(self[Result.Y - 1], Result.Y - 1, Result.X); +end; + +function TSynEditStrings.PhysicalToLogicalCol(const Line : string; + Index, PhysicalPos : integer) : integer; +var + BytePos, ByteLen: integer; + ScreenPos: integer; + CharWidths: TPhysicalCharWidths; +begin + CharWidths := GetPhysicalCharWidths(PChar(Line), length(Line), Index); + ByteLen := Length(Line); + ScreenPos := 1; + BytePos := 0; + + while BytePos < ByteLen do begin + if ScreenPos + CharWidths[BytePos] > PhysicalPos then + exit(BytePos+1); + ScreenPos := ScreenPos + CharWidths[BytePos]; + inc(BytePos); + end; + + Result := BytePos + 1 + PhysicalPos - ScreenPos; +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; + +function TSynEditStringsLinked.GetPChar(ALineIndex: Integer; out ALen: Integer): PChar; +begin + Result := fSynStrings.GetPChar(ALineIndex, ALen); +end; + +procedure TSynEditStringsLinked.SetIsUndoing(const AValue: Boolean); +begin + fSynStrings.IsUndoing := AValue; +end; + +function TSynEditStringsLinked.GetIsUndoing: Boolean; +begin + Result := fSynStrings.IsUndoing; +end; + +procedure TSynEditStringsLinked.SetIsRedoing(const AValue: Boolean); +begin + fSynStrings.IsRedoing := AValue; +end; + +function TSynEditStringsLinked.GetIsRedoing: Boolean; +begin + Result := fSynStrings.IsRedoing; +end; + +procedure TSynEditStringsLinked.SetSynStrings(AValue: TSynEditStrings); +begin + if fSynStrings = AValue then Exit; + fSynStrings := AValue; + if DisplayView <> nil then begin + if fSynStrings = nil + then DisplayView.NextView := nil + else DisplayView.NextView := fSynStrings.DisplayView; + end; +end; + +function TSynEditStringsLinked.GetIsUtf8: Boolean; +begin + Result := FSynStrings.IsUtf8; +end; + +procedure TSynEditStringsLinked.SetIsUtf8(const AValue: Boolean); +begin + FSynStrings.IsUtf8 := AValue; +end; + +function TSynEditStringsLinked.GetTextChangeStamp: int64; +begin + Result := fSynStrings.GetTextChangeStamp; +end; + +function TSynEditStringsLinked.GetViewChangeStamp: int64; +begin + Result := fSynStrings.GetViewChangeStamp; +end; + +//Ranges +function TSynEditStringsLinked.GetRange(Index: Pointer): TSynManagedStorageMem; +begin + Result:= fSynStrings.Ranges[Index]; +end; + +procedure TSynEditStringsLinked.PutRange(Index: Pointer; const ARange: TSynManagedStorageMem); +begin + fSynStrings.Ranges[Index] := ARange; +end; + +function TSynEditStringsLinked.GetExpandedString(Index: integer): string; +begin + Result:= fSynStrings.GetExpandedString(Index); +end; + +function TSynEditStringsLinked.GetLengthOfLongestLine: integer; +begin + Result:= fSynStrings.GetLengthOfLongestLine; +end; + +function TSynEditStringsLinked.GetRedoList: TSynEditUndoList; +begin + Result := fSynStrings.GetRedoList; +end; + +function TSynEditStringsLinked.GetUndoList: TSynEditUndoList; +begin + Result := fSynStrings.GetUndoList; +end; + +function TSynEditStringsLinked.GetCurUndoList: TSynEditUndoList; +begin + Result := fSynStrings.GetCurUndoList; +end; + +procedure TSynEditStringsLinked.AddGenericHandler(AReason: TSynEditNotifyReason; AHandler: TMethod); +begin + fSynStrings.AddGenericHandler(AReason, AHandler); +end; + +procedure TSynEditStringsLinked.RemoveGenericHandler(AReason: TSynEditNotifyReason; AHandler: TMethod); +begin + fSynStrings.RemoveGenericHandler(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; + +//function TSynEditStringsLinked.GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; +//begin +// Result := fSynStrings.GetPhysicalCharWidths(Line, LineLen, Index); +//end; + +procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean; Sender: TObject); +begin + // Update/check "FSenderUpdateCount" in linked lists too (avoid extra locking/unlocking) + if Updating then + fSynStrings.BeginUpdate(Sender) + else + fSynStrings.EndUpdate(Sender); +end; + +procedure TSynEditStringsLinked.DoGetPhysicalCharWidths(Line: PChar; + LineLen, Index: Integer; PWidths: PPhysicalCharWidth); +begin + fSynStrings.DoGetPhysicalCharWidths(Line, LineLen, Index, PWidths); +end; + +function TSynEditStringsLinked.GetDisplayView: TLazSynDisplayView; +begin + Result := fSynStrings.GetDisplayView; +end; + +procedure TSynEditStringsLinked.EditInsert(LogX, LogY: Integer; AText: String); +begin + fSynStrings.EditInsert(LogX, LogY, AText); +end; + +function TSynEditStringsLinked.EditDelete(LogX, LogY, ByteLen: Integer): String; +begin + Result := fSynStrings.EditDelete(LogX, LogY, ByteLen); +end; + +procedure TSynEditStringsLinked.EditLineBreak(LogX, LogY: Integer); +begin + fSynStrings.EditLineBreak(LogX, LogY); +end; + +procedure TSynEditStringsLinked.EditLineJoin(LogY: Integer; + FillText: String = ''); +begin + fSynStrings.EditLineJoin(LogY, FillText); +end; + +procedure TSynEditStringsLinked.EditLinesInsert(LogY, ACount: Integer; AText: String = ''); +begin + fSynStrings.EditLinesInsert(LogY, ACount, AText); +end; + +procedure TSynEditStringsLinked.EditLinesDelete(LogY, ACount: Integer); +begin + fSynStrings.EditLinesDelete(LogY, ACount); +end; + +procedure TSynEditStringsLinked.EditUndo(Item: TSynEditUndoItem); +begin + fSynStrings.EditUndo(Item); +end; + +procedure TSynEditStringsLinked.EditRedo(Item: TSynEditUndoItem); +begin + fSynStrings.EditRedo(Item); +end; + +procedure TSynEditStringsLinked.SendNotification(AReason: TSynEditNotifyReason; + ASender: TSynEditStrings; aIndex, aCount: Integer; + aBytePos: Integer = -1; aLen: Integer = 0; aTxt: String = ''); +begin + fSynStrings.SendNotification(AReason, ASender, aIndex, aCount, aBytePos, aLen, aTxt); +end; + +procedure TSynEditStringsLinked.SendNotification(AReason: TSynEditNotifyReason; + ASender: TObject); +begin + fSynStrings.SendNotification(AReason, ASender); +end; + +procedure TSynEditStringsLinked.FlushNotificationCache; +begin + fSynStrings.FlushNotificationCache; +end; + +procedure TSynEditStringsLinked.IgnoreSendNotification(AReason: TSynEditNotifyReason; + IncIgnore: Boolean); +begin + fSynStrings.IgnoreSendNotification(AReason, IncIgnore); +end; + +function TSynEditStringsLinked.GetIsInEditAction: Boolean; +begin + Result := fSynStrings.GetIsInEditAction; +end; + +procedure TSynEditStringsLinked.IncIsInEditAction; +begin + fSynStrings.IncIsInEditAction; +end; + +procedure TSynEditStringsLinked.DecIsInEditAction; +begin + fSynStrings.DecIsInEditAction; +end; + +end. + diff --git a/components/synedit/synbeautifier.pas b/components/synedit/synbeautifier.pas index 860f8dbe04..51896ea667 100644 --- a/components/synedit/synbeautifier.pas +++ b/components/synedit/synbeautifier.pas @@ -40,7 +40,7 @@ unit SynBeautifier; interface uses - Classes, SysUtils, LCLProc, SynEditMiscClasses, SynEditTextBase, SynEditPointClasses, + Classes, SysUtils, LCLProc, SynEditMiscClasses, LazSynEditText, SynEditPointClasses, SynEditKeyCmds; type diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index 54bbb3dd15..3cc65962f9 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -72,15 +72,18 @@ uses {$ENDIF} SynEditTypes, SynEditSearch, SynEditKeyCmds, SynEditMouseCmds, SynEditMiscProcs, SynEditPointClasses, SynBeautifier, SynEditMarks, + // Markup SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket, SynEditMarkupWordGroup, SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection, SynEditMarkupSpecialChar, - SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView, SynEditTextTabExpander, - SynEditTextDoubleWidthChars, + // Lines + SynEditTextBase, LazSynEditText, SynEditTextBuffer, SynEditLines, + SynEditTextTrimmer, SynEditTextTabExpander, SynEditTextDoubleWidthChars, + SynEditFoldedView, + // Gutter SynGutterBase, SynGutter, SynGutterCodeFolding, SynGutterChanges, SynGutterLineNumber, SynGutterMarks, SynGutterLineOverview, - SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer, - SynEditLines, + SynEditMiscClasses, SynEditHighlighter, SynTextDrawer, LResources, Clipbrd {$IFDEF SYN_COMPILER_4_UP} , StdActns @@ -413,6 +416,7 @@ type FLines: TSynEditStrings; // The real (un-mapped) line-buffer FStrings: TStrings; // External TStrings based interface to the Textbuffer FTopLinesView: TSynEditStrings; // The linesview that holds the real line-buffer/FLines + FDisplayView: TLazSynDisplayView; fExtraCharSpacing: integer; fLinesInWindow: Integer;// MG: fully visible lines in window @@ -1720,14 +1724,18 @@ begin // ftab, currently has LengthOfLongestLine, therefore must be after DoubleWidthChar FTabbedLinesView := TSynEditStringTabExpander.Create(FDoubleWidthChrLinesView); - FFoldedLinesView := TSynEditFoldedView.Create(FTabbedLinesView, fCaret); - FFoldedLinesView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged; - FFoldedLinesView.OnLineInvalidate := {$IFDEF FPC}@{$ENDIF}InvalidateGutterLines; - // Pointer to the First/Lowest View // TODO: this should be Folded... FTheLinesView := FTabbedLinesView; FTopLinesView := FTrimmedLinesView; + + FFoldedLinesView := TSynEditFoldedView.Create(FTheLinesView, fCaret); + FFoldedLinesView.OnFoldChanged := {$IFDEF FPC}@{$ENDIF}FoldChanged; + FFoldedLinesView.OnLineInvalidate := {$IFDEF FPC}@{$ENDIF}InvalidateGutterLines; + FFoldedLinesView.DisplayView.NextView := FTheLinesView.DisplayView; + + FDisplayView := FFoldedLinesView.DisplayView; + // External Accessor FStrings := TSynEditLines.Create(TSynEditStringList(FLines), {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved); @@ -3370,7 +3378,7 @@ end; procedure TCustomSynEdit.PaintTextLines(AClip: TRect; FirstLine, LastLine, FirstCol, LastCol: integer); -// FirstLine, LastLine are based 1 +// FirstLine, LastLine are based 0 // FirstCol, LastCol are screen based 1 without scrolling (physical position). // i.e. the real screen position is fTextOffset+Pred(FirstCol)*CharWidth var @@ -3863,6 +3871,7 @@ var function CharToByteLen(aCharLen: Integer) : Integer; begin if not UseUTF8 then exit(aCharLen); + // tabs and double-width chars are padded with spaces Result := UTF8CharToByteIndex(sToken, nTokenByteLen, aCharLen); if Result < 0 then begin debugln('ERROR: Could not convert CharLen (',dbgs(aCharLen),') to byteLen (maybe invalid UTF8?)',' len ',dbgs(nTokenByteLen),' Line ',dbgs(CurLine),' PhysPos ',dbgs(CurPhysPos)); @@ -4000,27 +4009,22 @@ var attr: TSynHighlighterAttributes; ypos: Integer; DividerInfo: TSynDividerDrawConfigSetting; - cl: Integer; + TV, cl: Integer; begin // Initialize rcLine for drawing. Note that Top and Bottom are updated // inside the loop. Get only the starting point for this. rcLine := AClip; rcLine.Bottom := FirstLine * fTextHeight; - // Make sure the token accumulator string doesn't get reassigned to often. - if Assigned(fHighlighter) then begin - TokenAccu.MaxLen := Max(128, fCharsInWindow * 4); - SetTokenAccuLength; - end; + + TV := TopView - 1; // Now loop through all the lines. The indices are valid for Lines. CurLine := FirstLine-1; while CurLine clNone) and (nRightEdge > TextLeftPixelOffset(False) - 1) then - begin - ypos := rcToken.Bottom - 1; - cl := DividerInfo.Color; - if cl = clDefault then - cl := fRightEdgeColor; - fTextDrawer.DrawLine(nRightEdge, ypos, TextLeftPixelOffset(False) - 1, ypos, cl); - dec(rcToken.Bottom); - end; - // 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.StartAtLineIndex(CurTextIndex); - // 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 - // is ignored as well. - //debugln('>>>> PaintLines Line=',dbgs(CurLine),' rect=',dbgs(rcToken)); - while not fHighlighter.GetEol do begin - fHighlighter.GetTokenEx(sToken,nTokenLen); - attr := fHighlighter.GetTokenAttribute; - // Add Markup to the token and append it to the TokenAccu - // record. This will paint any chars already stored if there is - // a (visible) change in the attributes. - DrawHiLightMarkupToken(attr,sToken,nTokenLen); - // Let the highlighter scan the next token. - fHighlighter.Next; - end; + FDisplayView.SetHighlighterTokensLine(TV + CurLine, CurTextIndex); + CharWidths := FTheLinesView.GetPhysicalCharWidths(CurTextIndex); + fMarkupManager.PrepareMarkupForRow(CurTextIndex+1); + + DividerInfo := FDisplayView.GetDrawDividerInfo; + if (DividerInfo.Color <> clNone) and (nRightEdge > TextLeftPixelOffset(False) - 1) then + begin + ypos := rcToken.Bottom - 1; + cl := DividerInfo.Color; + if cl = clDefault then + cl := fRightEdgeColor; + fTextDrawer.DrawLine(nRightEdge, ypos, TextLeftPixelOffset(False) - 1, ypos, cl); + dec(rcToken.Bottom); end; + + while FDisplayView.GetNextHighlighterToken(sToken, nTokenLen, attr) do begin + DrawHiLightMarkupToken(attr,sToken,nTokenLen); + end; + // Draw anything that's left in the TokenAccu record. Fill to the end // of the invalid area with the correct colors. PaintHighlightToken(TRUE); @@ -4091,11 +4079,8 @@ begin //DebugLn(['TCustomSynEdit.PaintTextLines ',dbgs(AClip)]); CurLine:=-1; - FillChar(TokenAccu,SizeOf(TokenAccu),0); //DebugLn('TCustomSynEdit.PaintTextLines ',DbgSName(Self),' TopLine=',dbgs(TopLine),' AClip=',dbgs(AClip)); colEditorBG := Color; - if Assigned(fHighlighter) then - fHighlighter.CurrentLines := FTheLinesView; // If the right edge is visible and in the invalid area, prepare to paint it. // Do this first to realize the pen when getting the dc variable. bDoRightEdge := FALSE; @@ -4126,12 +4111,24 @@ begin // necessary information about the selected area: is there any visible // selected area, and what are its lines / columns? // Moved to two local procedures to make it easier to read. + + FillChar(TokenAccu,SizeOf(TokenAccu),0); + if Assigned(fHighlighter) then begin + fHighlighter.CurrentLines := FTheLinesView; + // Make sure the token accumulator string doesn't get reassigned to often. + TokenAccu.MaxLen := Max(128, fCharsInWindow * 4); + SetTokenAccuLength; + end; + + FDisplayView.InitHighlighterTokens(FHighlighter); fTextDrawer.Style := Font.Style; fTextDrawer.BeginDrawing(dc); try PaintLines; finally fTextDrawer.EndDrawing; + FDisplayView.FinishHighlighterTokens; + ReAllocMem(TokenAccu.p,0); end; end; @@ -4151,7 +4148,6 @@ begin end; fMarkupManager.EndMarkup; - ReAllocMem(TokenAccu.p,0); end; procedure TCustomSynEdit.StartPaintBuffer(const ClipRect: TRect); diff --git a/components/synedit/syneditfoldedview.pp b/components/synedit/syneditfoldedview.pp index 3f2fcaf876..79176e2110 100644 --- a/components/synedit/syneditfoldedview.pp +++ b/components/synedit/syneditfoldedview.pp @@ -46,7 +46,7 @@ interface uses LCLProc, Graphics, - Classes, SysUtils, SynEditTextBase, SynEditTypes, SynEditMiscClasses, + Classes, SysUtils, LazSynEditText, SynEditTypes, SynEditMiscClasses, SynEditMiscProcs, SynEditPointClasses, SynEditHighlighter, SynEditHighlighterFoldBase; @@ -317,6 +317,19 @@ type property FoldsAvailable: Boolean read GetFoldsAvailable; end; + TSynEditFoldedView = class; + + { TLazSynDisplayFold } + + TLazSynDisplayFold = class(TLazSynDisplayView) + private + FFoldView: TSynEditFoldedView; + public + constructor Create(AFoldView: TSynEditFoldedView); + procedure InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); override; + procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); override; + end; + { TSynTextFoldedView *Line = Line (0-based) on Screen (except TopLine which should be TopViewPos) *ViewPos = Line (1-based) in the array of viewable/visible lines @@ -325,7 +338,7 @@ type { TSynEditFoldedView } - TSynEditFoldedView = class // TODO: class(TSynEditStringsLinked) + TSynEditFoldedView = class private fCaret: TSynEditCaret; FBlockSelection: TSynEditSelection; @@ -343,8 +356,10 @@ type fNeedFixFrom, fNeedFixMinEnd : Integer; fNeedCaretCheck : Boolean; FInTopLineChanged: Boolean; + FDisplayView: TLazSynDisplayFold; function GetCount : integer; + function GetDisplayView: TLazSynDisplayView; function GetFoldClasifications(index : Integer): TFoldNodeClassifications; function GetHighLighter: TSynCustomHighlighter; function GetLines(index : Integer) : String; @@ -488,6 +503,8 @@ type property HighLighter: TSynCustomHighlighter read GetHighLighter write SetHighLighter; property FoldProvider: TSynEditFoldProvider read FFoldProvider; + + property DisplayView: TLazSynDisplayView read GetDisplayView; end; implementation @@ -626,6 +643,24 @@ begin NumEncode86Values[NumEncode86Chars[i]] := i - 1; end; +{ TLazSynDisplayFold } + +constructor TLazSynDisplayFold.Create(AFoldView: TSynEditFoldedView); +begin + inherited Create; + FFoldView := AFoldView; +end; + +procedure TLazSynDisplayFold.InitHighlighterTokens(AHighlighter: TSynCustomHighlighter); +begin + inherited InitHighlighterTokens(AHighlighter); +end; + +procedure TLazSynDisplayFold.SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); +begin + inherited SetHighlighterTokensLine(FFoldView.ViewPosToTextIndex(ALine + 1), ARealLine); +end; + { TSynEditFoldExportStream } constructor TSynEditFoldExportStream.Create; @@ -2828,6 +2863,7 @@ begin fCaret.AddChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged); fFoldTree := TSynTextFoldAVLTree.Create; FFoldProvider := TSynEditFoldProvider.Create(aTextView, fFoldTree); + FDisplayView := TLazSynDisplayFold.Create(Self); FMarkupInfoFoldedCode := TSynSelectedColor.Create; FMarkupInfoFoldedCode.Background := clNone; @@ -2845,6 +2881,7 @@ begin fLines.RemoveNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}LinesCleared); fLines.RemoveEditHandler({$IFDEF FPC}@{$ENDIF}LineEdited); fCaret.RemoveChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged); + FreeAndNil(FDisplayView); fFoldTree.Free; fTextIndexList := nil; fFoldTypeList := nil; @@ -2984,6 +3021,11 @@ begin Result := fLines.Count - fFoldTree.FindLastFold.FoldedBefore; end; +function TSynEditFoldedView.GetDisplayView: TLazSynDisplayView; +begin + Result := FDisplayView; +end; + function TSynEditFoldedView.GetFoldClasifications(index : Integer): TFoldNodeClassifications; begin if (index < -1) or (index > fLinesInWindow + 1) then exit([]); diff --git a/components/synedit/syneditmarks.pp b/components/synedit/syneditmarks.pp index 2923c4dff5..0967c08744 100644 --- a/components/synedit/syneditmarks.pp +++ b/components/synedit/syneditmarks.pp @@ -11,7 +11,7 @@ unit SynEditMarks; interface uses - Classes, Controls, SysUtils, math, SynEditMiscClasses, SynEditTextBase, LCLProc; + Classes, Controls, SysUtils, math, SynEditMiscClasses, LazSynEditText, LCLProc; type diff --git a/components/synedit/syneditmarkup.pp b/components/synedit/syneditmarkup.pp index 82e17fe150..a7e722ccf1 100644 --- a/components/synedit/syneditmarkup.pp +++ b/components/synedit/syneditmarkup.pp @@ -26,7 +26,7 @@ unit SynEditMarkup; interface uses - Classes, SysUtils, Graphics, SynEditTypes, SynEditTextBase, SynEditPointClasses, + Classes, SysUtils, Graphics, SynEditTypes, LazSynEditText, SynEditPointClasses, SynEditMiscClasses, SynEditMiscProcs, Controls, SynEditHighlighter, LCLProc; type diff --git a/components/synedit/syneditmarkupctrlmouselink.pp b/components/synedit/syneditmarkupctrlmouselink.pp index 3f8cc04e0e..524a276320 100644 --- a/components/synedit/syneditmarkupctrlmouselink.pp +++ b/components/synedit/syneditmarkupctrlmouselink.pp @@ -27,7 +27,7 @@ interface uses Classes, SysUtils, Graphics, SynEditMarkup, SynEditMiscClasses, - SynEditMouseCmds, SynEditTextBase, Controls, LCLProc; + SynEditMouseCmds, LazSynEditText, Controls, LCLProc; type diff --git a/components/synedit/syneditmiscclasses.pp b/components/synedit/syneditmiscclasses.pp index c74be4119b..41ddf4baba 100644 --- a/components/synedit/syneditmiscclasses.pp +++ b/components/synedit/syneditmiscclasses.pp @@ -44,7 +44,7 @@ interface uses LCLIntf, LCLType, LCLProc, Classes, Graphics, Controls, SysUtils, Clipbrd, - SynEditMiscProcs, SynEditTypes, SynEditTextBase, SynEditPointClasses; + SynEditMiscProcs, SynEditTypes, LazSynEditText, SynEditPointClasses; type diff --git a/components/synedit/syneditpointclasses.pas b/components/synedit/syneditpointclasses.pas index 9188917568..038f4e45ad 100644 --- a/components/synedit/syneditpointclasses.pas +++ b/components/synedit/syneditpointclasses.pas @@ -40,7 +40,7 @@ uses {$IFDEF SYN_MBCSSUPPORT} Imm, {$ENDIF} - SynEditTextBase, SynEditTypes, SynEditMiscProcs;//, SynEditTextBuffer; + LazSynEditText, SynEditTypes, SynEditMiscProcs;//, SynEditTextBuffer; type diff --git a/components/synedit/synedittextbase.pas b/components/synedit/synedittextbase.pas index f9e58aafe2..09372e3aca 100644 --- a/components/synedit/synedittextbase.pas +++ b/components/synedit/synedittextbase.pas @@ -36,38 +36,6 @@ uses Classes, SysUtils, LCLProc, SynEditMiscProcs, SynEditKeyCmds; type - TSynEditStrings = class; - - TStringListLineCountEvent = procedure(Sender: TSynEditStrings; - Index, Count: Integer) of object; - TStringListLineEditEvent = procedure(Sender: TSynEditStrings; - LinePos, BytePos, Count, LineBrkCnt: Integer; - Text: String) of object; - - TSynEditNotifyReason = ( // TStringListLineCountEvent - senrLineCount, // Lines Inserted or Deleted (if not empty, they will trigger senrLineChange too) - senrLineChange, // Lines modified (also triggered by senrEditAction) - senrHighlightChanged, // used by Highlighter (invalidate and fold checks needed) - // TStringListLineEditEvent - senrEditAction, // EditInsert, EditDelete, EditLineBreak, ... - // TNotifyEvent - senrCleared, - senrUndoRedoAdded, - senrModifiedChanged, // The modified flag was changed - // Paintlocks are managed by SynEdit, but need distribution to shared edits - senrIncOwnedPaintLock, // Inform other SynEdits (ForeignPaintLock) - senrDecOwnedPaintLock, - senrIncPaintLock, // Actual PaintLock - senrDecPaintLock, - senrAfterIncPaintLock, // For plugins, etc... - senrBeforeDecPaintLock, - senrTextBufferChanging, // About to change - senrTextBufferChanged - ); - - TPhysicalCharWidths = Array of Shortint; - TPhysicalCharWidth = ShortInt; - PPhysicalCharWidth = ^TPhysicalCharWidth; TSynEditUndoList = class; TSynEditUndoItem = class; @@ -136,30 +104,6 @@ type read GetStorageMems write SetStorageMems; default; end; - { TSynLogicalPhysicalConvertor } -const - SYN_LP_MIN_ALLOC = 1024; // Keep at least n*SizeOf(TPhysicalCharWidths) allocated -type - TSynLogicalPhysicalConvertor = class - private - FLines: TSynEditStrings; - FCurrentWidths: TPhysicalCharWidths; - FCurrentWidthsLen, FCurrentWidthsAlloc: Integer; - FCurrentLine: Integer; - FTextChangeStamp, FViewChangeStamp: Int64; - // TODOtab-width - procedure PrepareWidthsForLine(AIndex: Integer; AForce: Boolean = False); - public - constructor Create(ALines: TSynEditStrings); - destructor Destroy; override; - // Line is 0-based // Column is 1-based - function PhysicalToLogical(AIndex, AColumn: Integer): Integer; - function PhysicalToLogical(AIndex, AColumn: Integer; out AColOffset: Integer): Integer; - // ACharPos 1=before 1st char - function LogicalToPhysical(AIndex, ABytePos: Integer): Integer; - function LogicalToPhysical(AIndex, ABytePos: Integer; var AColOffset: Integer): Integer; - end; - { TSynEditStringsBase } TSynEditStringsBase = class(TStrings) @@ -173,190 +117,6 @@ type property Ranges[Index: Pointer]: TSynManagedStorageMem read GetRange write PutRange; end; - { TSynEditStrings } - - TSynEditStrings = class(TSynEditStringsBase) - private - FSenderUpdateCount: Integer; - FLogPhysConvertor :TSynLogicalPhysicalConvertor; - protected - FIsUtf8: Boolean; - function GetIsUtf8 : Boolean; virtual; - procedure SetIsUtf8(const AValue : Boolean); virtual; - - function GetExpandedString(Index: integer): string; virtual; abstract; - function GetLengthOfLongestLine: integer; virtual; abstract; - procedure SetTextStr(const Value: string); override; - function GetTextChangeStamp: int64; virtual; abstract; - function GetViewChangeStamp: int64; virtual; - - function GetIsInEditAction: Boolean; virtual; abstract; - procedure IncIsInEditAction; virtual; abstract; - procedure DecIsInEditAction; virtual; abstract; - function GetUndoList: TSynEditUndoList; virtual; abstract; - function GetRedoList: TSynEditUndoList; virtual; abstract; - function GetCurUndoList: TSynEditUndoList; virtual; abstract; - procedure SetIsUndoing(const AValue: Boolean); virtual; abstract; - function GetIsUndoing: Boolean; virtual; abstract; - procedure SetIsRedoing(const AValue: Boolean); virtual; abstract; - function GetIsRedoing: Boolean; virtual; abstract; - procedure IgnoreSendNotification(AReason: TSynEditNotifyReason; - ReEnable: Boolean); virtual; abstract; - - procedure SetUpdateState(Updating: Boolean); override; - procedure SetUpdateState(Updating: Boolean; Sender: TObject); virtual; abstract; - - procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); virtual; abstract; - public - constructor Create; - destructor Destroy; override; - procedure BeginUpdate(Sender: TObject); overload; - procedure EndUpdate(Sender: TObject); overload; - function IsUpdating: Boolean; - procedure DeleteLines(Index, NumLines: integer); virtual; abstract; - procedure InsertLines(Index, NumLines: integer); virtual; abstract; - procedure InsertStrings(Index: integer; NewStrings: TStrings); virtual; abstract; - - procedure AddGenericHandler(AReason: TSynEditNotifyReason; - AHandler: TMethod); virtual; abstract; - procedure AddChangeHandler(AReason: TSynEditNotifyReason; - AHandler: TStringListLineCountEvent); - procedure AddNotifyHandler(AReason: TSynEditNotifyReason; - AHandler: TNotifyEvent); - - procedure RemoveGenericHandler(AReason: TSynEditNotifyReason; - AHandler: TMethod); virtual; abstract; - procedure RemoveChangeHandler(AReason: TSynEditNotifyReason; - AHandler: TStringListLineCountEvent); - procedure RemoveNotifyHandler(AReason: TSynEditNotifyReason; - AHandler: TNotifyEvent); - - procedure AddEditHandler(AHandler: TStringListLineEditEvent); - procedure RemoveEditHandler(AHandler: TStringListLineEditEvent); - procedure SendHighlightChanged(aIndex, aCount: Integer); override; - procedure SendNotification(AReason: TSynEditNotifyReason; - ASender: TSynEditStrings; aIndex, aCount: Integer; - aBytePos: Integer = -1; aLen: Integer = 0; - aTxt: String = ''); virtual; abstract; - procedure SendNotification(AReason: TSynEditNotifyReason; - ASender: TObject); virtual; abstract; - procedure FlushNotificationCache; virtual; abstract; - public - function GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; - function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; - // Byte to Char - function LogicalToPhysicalPos(const p: TPoint): TPoint; - function LogicalToPhysicalCol(const Line: String; - Index, LogicalPos: integer): integer; virtual; - // Char to Byte - function PhysicalToLogicalPos(const p: TPoint): TPoint; - function PhysicalToLogicalCol(const Line: string; - Index, PhysicalPos: integer): integer; virtual; - property LogPhysConvertor :TSynLogicalPhysicalConvertor read FLogPhysConvertor; - public - procedure EditInsert(LogX, LogY: Integer; AText: String); virtual; abstract; - function EditDelete(LogX, LogY, ByteLen: Integer): String; virtual; abstract; - procedure EditLineBreak(LogX, LogY: Integer); virtual; abstract; - procedure EditLineJoin(LogY: Integer; FillText: String = ''); virtual; abstract; - procedure EditLinesInsert(LogY, ACount: Integer; AText: String = ''); virtual; abstract; - procedure EditLinesDelete(LogY, ACount: Integer); virtual; abstract; - procedure EditUndo(Item: TSynEditUndoItem); virtual; abstract; - procedure EditRedo(Item: TSynEditUndoItem); virtual; abstract; - property IsInEditAction: Boolean read GetIsInEditAction; - property UndoList: TSynEditUndoList read GetUndoList; - property RedoList: TSynEditUndoList read GetRedoList; - property CurUndoList: TSynEditUndoList read GetCurUndoList; // Re or Undo (Redo while undoing) - property IsUndoing: Boolean read GetIsUndoing write SetIsUndoing; - property IsRedoing: Boolean read GetIsRedoing write SetIsRedoing; - public - property TextChangeStamp: int64 read GetTextChangeStamp; - property ViewChangeStamp: int64 read GetViewChangeStamp; // tabs-size, trailing-spaces, ... - property ExpandedStrings[Index: integer]: string read GetExpandedString; - property LengthOfLongestLine: integer read GetLengthOfLongestLine; - property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8; - end; - - { TSynEditStringsLinked } - - TSynEditStringsLinked = class(TSynEditStrings) - protected - fSynStrings: TSynEditStrings; - - function GetIsUtf8 : Boolean; override; - procedure SetIsUtf8(const AValue : Boolean); override; - function GetTextChangeStamp: int64; override; - function GetViewChangeStamp: int64; override; - - function GetRange(Index: Pointer): TSynManagedStorageMem; override; - procedure PutRange(Index: Pointer; const ARange: TSynManagedStorageMem); override; - - function GetExpandedString(Index: integer): string; override; - function GetLengthOfLongestLine: integer; override; - - procedure IgnoreSendNotification(AReason: TSynEditNotifyReason; - IncIgnore: Boolean); override; - function GetIsInEditAction: Boolean; override; - procedure IncIsInEditAction; override; - procedure DecIsInEditAction; override; - function GetUndoList: TSynEditUndoList; override; - function GetRedoList: TSynEditUndoList; override; - function GetCurUndoList: TSynEditUndoList; override; - procedure SetIsUndoing(const AValue: Boolean); override; - function GetIsUndoing: Boolean; override; - procedure SetIsRedoing(const AValue: Boolean); override; - function GetIsRedoing: Boolean; 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; Sender: TObject); override; - procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); 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; - function GetPChar(ALineIndex: Integer; out ALen: Integer): PChar; override; // experimental - - procedure AddGenericHandler(AReason: TSynEditNotifyReason; - AHandler: TMethod); override; - procedure RemoveGenericHandler(AReason: TSynEditNotifyReason; - AHandler: TMethod); override; - procedure SendNotification(AReason: TSynEditNotifyReason; - ASender: TSynEditStrings; aIndex, aCount: Integer; - aBytePos: Integer = -1; aLen: Integer = 0; - aTxt: String = ''); override; - procedure SendNotification(AReason: TSynEditNotifyReason; - ASender: TObject); override; - procedure FlushNotificationCache; override; - - //function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; override; - property NextLines: TSynEditStrings read fSynStrings write fSynStrings; - public - // LogX, LogY are 1-based - procedure EditInsert(LogX, LogY: Integer; AText: String); override; - function EditDelete(LogX, LogY, ByteLen: Integer): String; override; - procedure EditLineBreak(LogX, LogY: Integer); override; - procedure EditLineJoin(LogY: Integer; FillText: String = ''); override; - procedure EditLinesInsert(LogY, ACount: Integer; AText: String = ''); override; - procedure EditLinesDelete(LogY, ACount: Integer); override; - procedure EditUndo(Item: TSynEditUndoItem); override; - procedure EditRedo(Item: TSynEditUndoItem); override; - end; - { TSynEditUndoItem } TSynEditUndoItem = class(TObject) @@ -477,139 +237,6 @@ begin raise ESynEditStorageMem.CreateFmt(SListIndexOutOfBounds, [Index]); end; -{ TSynLogicalPhysicalConvertor } - -procedure TSynLogicalPhysicalConvertor.PrepareWidthsForLine(AIndex: Integer; - AForce: Boolean); -var - LineLen: Integer; - Line: PChar; -//const dbg_cnt: integer = 0; -begin - if (not AForce) and (FCurrentLine = AIndex) and - (FLines.TextChangeStamp = FTextChangeStamp) and (FLines.ViewChangeStamp = FViewChangeStamp) - then begin - //debugln(['**************** RE-USING widths: ', AIndex,' (',dbgs(Pointer(self)),')']); - //dbg_cnt := dbg_cnt + 1; - exit; - end; - - if (AIndex < 0) or (AIndex >= FLines.Count) then begin - FCurrentWidthsLen := 0; - FViewChangeStamp := FLines.ViewChangeStamp; - FTextChangeStamp := FLines.TextChangeStamp; - exit; - end; - - Line := FLines.GetPChar(AIndex, LineLen); - if LineLen > FCurrentWidthsAlloc then begin - //debugln(['**************** COMPUTING widths (grow): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]); - SetLength(FCurrentWidths, LineLen); - FCurrentWidthsAlloc := LineLen; - end - else if FCurrentWidthsAlloc > Max(Max(LineLen, FCurrentWidthsLen)*4, SYN_LP_MIN_ALLOC) then begin - //debugln(['**************** COMPUTING widths (shrink): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]); - FCurrentWidthsAlloc := Max(Max(LineLen, FCurrentWidthsLen), SYN_LP_MIN_ALLOC) ; - SetLength(FCurrentWidths, FCurrentWidthsAlloc); - //end - //else begin - // debugln(['**************** COMPUTING widths: ', AIndex,' (',dbgs(Pointer(self)),') alloc=',FCurrentWidthsAlloc]); - end; - //debugln(['**************** NEW for index:: ', AIndex,' (',dbgs(Pointer(self)),') after index: ', FCurrentLine, ' used ', dbg_cnt,' times // old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen, ' viewchg:',dbgs(not(FViewChangeStamp=FLines.ViewChangeStamp)),' txtchg:',dbgs(not(FTextChangeStamp=FLines.TextChangeStamp))]); dbg_cnt := 0; - - FCurrentWidthsLen := LineLen; - if LineLen > 0 then - FLines.DoGetPhysicalCharWidths(Line, LineLen, AIndex, @FCurrentWidths[0]); - FViewChangeStamp := FLines.ViewChangeStamp; - FTextChangeStamp := FLines.TextChangeStamp; - FCurrentLine := AIndex; -end; - -constructor TSynLogicalPhysicalConvertor.Create(ALines: TSynEditStrings); -begin - FLines := ALines; - FCurrentLine := -1; - FCurrentWidths := nil; - FCurrentWidthsLen := 0; - FCurrentWidthsAlloc := 0; -end; - -destructor TSynLogicalPhysicalConvertor.Destroy; -begin - SetLength(FCurrentWidths, 0); - inherited Destroy; -end; - -function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex, - AColumn: Integer): Integer; -var - ColOffs: Integer; -begin - Result := PhysicalToLogical(AIndex, AColumn, ColOffs); -end; - -function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex, AColumn: Integer; - out AColOffset: Integer): Integer; -var - BytePos, ScreenPos, ScreenPosOld: integer; -begin - PrepareWidthsForLine(AIndex); - - ScreenPos := 1; - BytePos := 0; - while BytePos < FCurrentWidthsLen do begin - ScreenPosOld := ScreenPos; - ScreenPos := ScreenPos + FCurrentWidths[BytePos]; - inc(BytePos); - if ScreenPos > AColumn then begin - AColOffset := AColumn - ScreenPosOld; - exit(BytePos); - end; - end; - - // Column at/past end of line - AColOffset := 0; - Result := BytePos + 1 + AColumn - ScreenPos; -end; - -function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex, - ABytePos: Integer): Integer; -var - ColOffs: Integer; -begin - ColOffs := 0; - Result := LogicalToPhysical(AIndex, ABytePos, ColOffs); -end; - -function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex, ABytePos: Integer; - var AColOffset: Integer): Integer; -var - i: integer; - CharWidths: TPhysicalCharWidths; -begin - {$IFDEF AssertSynMemIndex} - if (ABytePos <= 0) then - raise Exception.Create(Format('Bad Bytpos for PhystoLogical BytePos=%d ColOffs= %d idx= %d',[ABytePos, AColOffset, AIndex])); - {$ENDIF} - if (ABytePos = 0) or ((ABytePos = 1) and (AColOffset=0)) then - exit(ABytePos); - PrepareWidthsForLine(AIndex); - - dec(ABytePos); - if ABytePos >= FCurrentWidthsLen then begin - Result := 1 + ABytePos - FCurrentWidthsLen; - ABytePos := FCurrentWidthsLen; - AColOffset := 0; - end - else begin - AColOffset := Min(AColOffset, FCurrentWidths[ABytePos]-1); - Result := 1 + AColOffset; - end; - - for i := 0 to ABytePos - 1 do - Result := Result + FCurrentWidths[i]; -end; - { TSynEditStringsBase } function TSynEditStringsBase.GetPChar(ALineIndex: Integer): PChar; @@ -619,501 +246,6 @@ begin Result := GetPChar(ALineIndex, l); end; -{ TSynEditStrings } - -constructor TSynEditStrings.Create; -begin - FLogPhysConvertor := TSynLogicalPhysicalConvertor.Create(self); - inherited Create; - IsUtf8 := True; -end; - -destructor TSynEditStrings.Destroy; -begin - FreeAndNil(FLogPhysConvertor); - inherited Destroy; -end; - -procedure TSynEditStrings.BeginUpdate(Sender: TObject); -begin - if FSenderUpdateCount = 0 then - SetUpdateState(true, Sender); - inc(FSenderUpdateCount); -end; - -procedure TSynEditStrings.EndUpdate(Sender: TObject); -begin - If FSenderUpdateCount>0 then - Dec(FSenderUpdateCount); - if FSenderUpdateCount=0 then - SetUpdateState(False, Sender); -end; - -function TSynEditStrings.IsUpdating: Boolean; -begin - Result := (FSenderUpdateCount > 0) or (UpdateCount > 0); -end; - -procedure TSynEditStrings.AddChangeHandler(AReason: TSynEditNotifyReason; - AHandler: TStringListLineCountEvent); -begin - AddGenericHandler(AReason, TMethod(AHandler)); -end; - -procedure TSynEditStrings.AddNotifyHandler(AReason: TSynEditNotifyReason; - AHandler: TNotifyEvent); -begin - AddGenericHandler(AReason, TMethod(AHandler)); -end; - -procedure TSynEditStrings.RemoveChangeHandler(AReason: TSynEditNotifyReason; - AHandler: TStringListLineCountEvent); -begin - RemoveGenericHandler(AReason, TMethod(AHandler)); -end; - -procedure TSynEditStrings.RemoveNotifyHandler(AReason: TSynEditNotifyReason; - AHandler: TNotifyEvent); -begin - RemoveGenericHandler(AReason, TMethod(AHandler)); -end; - -procedure TSynEditStrings.AddEditHandler(AHandler: TStringListLineEditEvent); -begin - AddGenericHandler(senrEditAction, TMethod(AHandler)); -end; - -procedure TSynEditStrings.RemoveEditHandler(AHandler: TStringListLineEditEvent); -begin - RemoveGenericHandler(senrEditAction, TMethod(AHandler)); -end; - -procedure TSynEditStrings.SendHighlightChanged(aIndex, aCount: Integer); -begin - SendNotification(senrHighlightChanged, Self, aIndex, aCount); -end; - -function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; -var - s: string; -begin - s := Strings[Index]; - Result := GetPhysicalCharWidths(PChar(s), length(s), Index); -end; - -function TSynEditStrings.GetPhysicalCharWidths(Line: PChar; LineLen, - Index: Integer): TPhysicalCharWidths; -begin - SetLength(Result, LineLen); - if LineLen = 0 then - exit; - DoGetPhysicalCharWidths(Line, LineLen, Index, @Result[0]); -end; - -function TSynEditStrings.GetIsUtf8 : Boolean; -begin - Result := FIsUtf8; -end; - -procedure TSynEditStrings.SetIsUtf8(const AValue : Boolean); -begin - FIsUtf8 := AValue; -end; - -procedure TSynEditStrings.SetTextStr(const Value : string); -var - StartPos: PChar; - p: PChar; - Last: PChar; - sl: TStringList; - s: string; -begin - if Value='' then begin - Clear; - exit; - end; - BeginUpdate; - sl:=TStringList.Create; - try - Clear; - p:=PChar(Value); - StartPos:=p; - Last:=p+length(Value); - while p'' then - System.Move(StartPos^,s[1],length(s)); - sl.Add(s); - if (p[1] in [#10,#13]) and (p[1]<>p^) then - inc(p); - inc(p); - StartPos:=p; - end; - end; - if StartPos'' then - System.Move(StartPos^,s[1],length(s)); - sl.Add(s); - end; - AddStrings(sl); - finally - sl.Free; - EndUpdate; - end; -end; - -function TSynEditStrings.GetViewChangeStamp: int64; -begin - Result := 0; -end; - -procedure TSynEditStrings.SetUpdateState(Updating: Boolean); -begin - // Update/check "FSenderUpdateCount", to avoid extra locking/unlocking - if Updating then - BeginUpdate(nil) - else - EndUpdate(nil); -end; - -function TSynEditStrings.LogicalToPhysicalPos(const p : TPoint) : TPoint; -begin - Result := p; - Result.X := FLogPhysConvertor.LogicalToPhysical(p.y - 1, p.x); -// if Result.Y - 1 < Count then -// Result.X:=LogicalToPhysicalCol(self[Result.Y - 1], Result.Y, Result.X); -end; - -function TSynEditStrings.LogicalToPhysicalCol(const Line : String; - Index, LogicalPos: integer) : integer; -var - i, ByteLen: integer; - CharWidths: TPhysicalCharWidths; -begin - CharWidths := GetPhysicalCharWidths(Pchar(Line), length(Line), Index); - ByteLen := length(Line); - dec(LogicalPos); - - if LogicalPos > ByteLen then begin - Result := 1 + LogicalPos - ByteLen; - LogicalPos := ByteLen; - end - else - Result := 1; - - for i := 0 to LogicalPos - 1 do - Result := Result + CharWidths[i]; -end; - -function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint; -begin - Result := p; - Result.X := FLogPhysConvertor.PhysicalToLogical(p.y - 1, p.x); -// if (Result.Y>=1) and (Result.Y <= Count) then -// Result.X:=PhysicalToLogicalCol(self[Result.Y - 1], Result.Y - 1, Result.X); -end; - -function TSynEditStrings.PhysicalToLogicalCol(const Line : string; - Index, PhysicalPos : integer) : integer; -var - BytePos, ByteLen: integer; - ScreenPos: integer; - CharWidths: TPhysicalCharWidths; -begin - CharWidths := GetPhysicalCharWidths(PChar(Line), length(Line), Index); - ByteLen := Length(Line); - ScreenPos := 1; - BytePos := 0; - - while BytePos < ByteLen do begin - if ScreenPos + CharWidths[BytePos] > PhysicalPos then - exit(BytePos+1); - ScreenPos := ScreenPos + CharWidths[BytePos]; - inc(BytePos); - end; - - Result := BytePos + 1 + PhysicalPos - ScreenPos; -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; - -function TSynEditStringsLinked.GetPChar(ALineIndex: Integer; out ALen: Integer): PChar; -begin - Result := fSynStrings.GetPChar(ALineIndex, ALen); -end; - -procedure TSynEditStringsLinked.SetIsUndoing(const AValue: Boolean); -begin - fSynStrings.IsUndoing := AValue; -end; - -function TSynEditStringsLinked.GetIsUndoing: Boolean; -begin - Result := fSynStrings.IsUndoing; -end; - -procedure TSynEditStringsLinked.SetIsRedoing(const AValue: Boolean); -begin - fSynStrings.IsRedoing := AValue; -end; - -function TSynEditStringsLinked.GetIsRedoing: Boolean; -begin - Result := fSynStrings.IsRedoing; -end; - -function TSynEditStringsLinked.GetIsUtf8: Boolean; -begin - Result := FSynStrings.IsUtf8; -end; - -procedure TSynEditStringsLinked.SetIsUtf8(const AValue: Boolean); -begin - FSynStrings.IsUtf8 := AValue; -end; - -function TSynEditStringsLinked.GetTextChangeStamp: int64; -begin - Result := fSynStrings.GetTextChangeStamp; -end; - -function TSynEditStringsLinked.GetViewChangeStamp: int64; -begin - Result := fSynStrings.GetViewChangeStamp; -end; - -//Ranges -function TSynEditStringsLinked.GetRange(Index: Pointer): TSynManagedStorageMem; -begin - Result:= fSynStrings.Ranges[Index]; -end; - -procedure TSynEditStringsLinked.PutRange(Index: Pointer; const ARange: TSynManagedStorageMem); -begin - fSynStrings.Ranges[Index] := ARange; -end; - -function TSynEditStringsLinked.GetExpandedString(Index: integer): string; -begin - Result:= fSynStrings.GetExpandedString(Index); -end; - -function TSynEditStringsLinked.GetLengthOfLongestLine: integer; -begin - Result:= fSynStrings.GetLengthOfLongestLine; -end; - -function TSynEditStringsLinked.GetRedoList: TSynEditUndoList; -begin - Result := fSynStrings.GetRedoList; -end; - -function TSynEditStringsLinked.GetUndoList: TSynEditUndoList; -begin - Result := fSynStrings.GetUndoList; -end; - -function TSynEditStringsLinked.GetCurUndoList: TSynEditUndoList; -begin - Result := fSynStrings.GetCurUndoList; -end; - -procedure TSynEditStringsLinked.AddGenericHandler(AReason: TSynEditNotifyReason; AHandler: TMethod); -begin - fSynStrings.AddGenericHandler(AReason, AHandler); -end; - -procedure TSynEditStringsLinked.RemoveGenericHandler(AReason: TSynEditNotifyReason; AHandler: TMethod); -begin - fSynStrings.RemoveGenericHandler(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; - -//function TSynEditStringsLinked.GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; -//begin -// Result := fSynStrings.GetPhysicalCharWidths(Line, LineLen, Index); -//end; - -procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean; Sender: TObject); -begin - // Update/check "FSenderUpdateCount" in linked lists too (avoid extra locking/unlocking) - if Updating then - fSynStrings.BeginUpdate(Sender) - else - fSynStrings.EndUpdate(Sender); -end; - -procedure TSynEditStringsLinked.DoGetPhysicalCharWidths(Line: PChar; - LineLen, Index: Integer; PWidths: PPhysicalCharWidth); -begin - fSynStrings.DoGetPhysicalCharWidths(Line, LineLen, Index, PWidths); -end; - -procedure TSynEditStringsLinked.EditInsert(LogX, LogY: Integer; AText: String); -begin - fSynStrings.EditInsert(LogX, LogY, AText); -end; - -function TSynEditStringsLinked.EditDelete(LogX, LogY, ByteLen: Integer): String; -begin - Result := fSynStrings.EditDelete(LogX, LogY, ByteLen); -end; - -procedure TSynEditStringsLinked.EditLineBreak(LogX, LogY: Integer); -begin - fSynStrings.EditLineBreak(LogX, LogY); -end; - -procedure TSynEditStringsLinked.EditLineJoin(LogY: Integer; - FillText: String = ''); -begin - fSynStrings.EditLineJoin(LogY, FillText); -end; - -procedure TSynEditStringsLinked.EditLinesInsert(LogY, ACount: Integer; AText: String = ''); -begin - fSynStrings.EditLinesInsert(LogY, ACount, AText); -end; - -procedure TSynEditStringsLinked.EditLinesDelete(LogY, ACount: Integer); -begin - fSynStrings.EditLinesDelete(LogY, ACount); -end; - -procedure TSynEditStringsLinked.EditUndo(Item: TSynEditUndoItem); -begin - fSynStrings.EditUndo(Item); -end; - -procedure TSynEditStringsLinked.EditRedo(Item: TSynEditUndoItem); -begin - fSynStrings.EditRedo(Item); -end; - -procedure TSynEditStringsLinked.SendNotification(AReason: TSynEditNotifyReason; - ASender: TSynEditStrings; aIndex, aCount: Integer; - aBytePos: Integer = -1; aLen: Integer = 0; aTxt: String = ''); -begin - fSynStrings.SendNotification(AReason, ASender, aIndex, aCount, aBytePos, aLen, aTxt); -end; - -procedure TSynEditStringsLinked.SendNotification(AReason: TSynEditNotifyReason; - ASender: TObject); -begin - fSynStrings.SendNotification(AReason, ASender); -end; - -procedure TSynEditStringsLinked.FlushNotificationCache; -begin - fSynStrings.FlushNotificationCache; -end; - -procedure TSynEditStringsLinked.IgnoreSendNotification(AReason: TSynEditNotifyReason; - IncIgnore: Boolean); -begin - fSynStrings.IgnoreSendNotification(AReason, IncIgnore); -end; - -function TSynEditStringsLinked.GetIsInEditAction: Boolean; -begin - Result := fSynStrings.GetIsInEditAction; -end; - -procedure TSynEditStringsLinked.IncIsInEditAction; -begin - fSynStrings.IncIsInEditAction; -end; - -procedure TSynEditStringsLinked.DecIsInEditAction; -begin - fSynStrings.DecIsInEditAction; -end; - { TSynEditUndoList } constructor TSynEditUndoList.Create; diff --git a/components/synedit/synedittextbuffer.pp b/components/synedit/synedittextbuffer.pp index fed68a0e44..7218580dca 100644 --- a/components/synedit/synedittextbuffer.pp +++ b/components/synedit/synedittextbuffer.pp @@ -39,11 +39,16 @@ unit SynEditTextBuffer; {$I synedit.inc} +{$IFOPT C+} + {$DEFINE SynAssert} +{$ENDIF} + interface uses - Classes, SysUtils, LCLProc, LCLIntf, LCLType, - SynEditTextBase, SynEditMiscProcs, SynEditMiscClasses; + Classes, SysUtils, Graphics, LCLProc, LCLIntf, LCLType, + SynEditTypes, LazSynEditText, SynEditTextBase, SynEditMiscProcs, SynEditMiscClasses, + SynEditHighlighter; type TSynEditFlagsClass = class end; // For Register @@ -103,11 +108,29 @@ type property Flags[Index: Integer]: TSynEditStringFlags read GetFlags write SetFlags; end; + TSynEditStringList = class; + + { TLazSynDisplayBuffer } + + TLazSynDisplayBuffer = class(TLazSynDisplayViewEx) + private + FBuffer: TSynEditStringList; + FAtLineStart: Boolean; + public + constructor Create(ABuffer: TSynEditStringList); + procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); override; + function GetNextHighlighterToken(out ATokenStart: PChar; out ATokenLength: integer; + out ATokenAttr: TSynHighlighterAttributes + ): Boolean; override; + function GetDrawDividerInfo: TSynDividerDrawConfigSetting; override; + end; + { TSynEditStringList } TSynEditStringList = class(TSynEditStrings) private FList: TSynEditStringMemory; + FDisplayView: TLazSynDisplayBuffer; FAttachedSynEditList: TFPList; FNotifyLists: Array [TSynEditNotifyReason] of TSynMethodList; @@ -170,6 +193,8 @@ type procedure UndoEditLinesDelete(LogY, ACount: Integer); procedure IncreaseTextChangeStamp; procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override; + + function GetDisplayView: TLazSynDisplayView; override; public constructor Create; destructor Destroy; override; @@ -312,8 +337,59 @@ type function PerformUndo(Caller: TObject): Boolean; override; end; +{ TLazSynDisplayBuffer } + +constructor TLazSynDisplayBuffer.Create(ABuffer: TSynEditStringList); +begin + inherited Create; + FBuffer := ABuffer; +end; + +procedure TLazSynDisplayBuffer.SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); +begin + CurrentTokenLine := ALine; + ARealLine := ALine; + FAtLineStart := True; +end; + +function TLazSynDisplayBuffer.GetNextHighlighterToken(out ATokenStart: PChar; out + ATokenLength: integer; out ATokenAttr: TSynHighlighterAttributes): Boolean; +begin + Result := False; + if not Initialized then exit; + + if CurrentTokenHighlighter = nil then begin + Result := FAtLineStart; + if not Result then exit; + ATokenStart := FBuffer.GetPChar(CurrentTokenLine, ATokenLength); + ATokenAttr := nil; + FAtLineStart := False; + end + else begin + if FAtLineStart then + CurrentTokenHighlighter.StartAtLineIndex(CurrentTokenLine); + FAtLineStart := False; + + Result := not CurrentTokenHighlighter.GetEol; + if not Result then exit; + + CurrentTokenHighlighter.GetTokenEx(ATokenStart, ATokenLength); + ATokenAttr := CurrentTokenHighlighter.GetTokenAttribute; + CurrentTokenHighlighter.Next; + end; +end; + +function TLazSynDisplayBuffer.GetDrawDividerInfo: TSynDividerDrawConfigSetting; +begin + if CurrentTokenHighlighter <> nil then + Result := CurrentTokenHighlighter.DrawDivider[CurrentTokenLine] + else + Result.Color := clNone; +end; + { TSynEditUndoTxtInsert } - function TSynEditUndoTxtInsert.DebugString: String; + +function TSynEditUndoTxtInsert.DebugString: String; begin Result := 'X='+dbgs(FPosX) + ' Y='+ dbgs(FPosY) + ' len=' + dbgs(FLen); end; @@ -452,6 +528,7 @@ var r: TSynEditNotifyReason; begin fList := TSynEditStringMemory.Create; + FDisplayView := TLazSynDisplayBuffer.Create(Self); FAttachedSynEditList := TFPList.Create; FUndoList := TSynEditUndoList.Create; @@ -495,6 +572,7 @@ begin FreeAndNil(FRedoList); FreeAndNil(FAttachedSynEditList); + FreeAndNil(FDisplayView); FreeAndNil(fList); end; @@ -748,6 +826,11 @@ begin end; end; +function TSynEditStringList.GetDisplayView: TLazSynDisplayView; +begin + Result := FDisplayView; +end; + procedure TSynEditStringList.AttachSynEdit(AEdit: TSynEditBase); begin if FAttachedSynEditList.IndexOf(AEdit) < 0 then diff --git a/components/synedit/synedittextdoublewidthchars.pas b/components/synedit/synedittextdoublewidthchars.pas index 7017db4b12..2f39fa243f 100644 --- a/components/synedit/synedittextdoublewidthchars.pas +++ b/components/synedit/synedittextdoublewidthchars.pas @@ -33,7 +33,7 @@ unit SynEditTextDoubleWidthChars; interface uses - Classes, SysUtils, SynEditTextBase; + Classes, SysUtils, LazSynEditText; type diff --git a/components/synedit/synedittexttabexpander.pas b/components/synedit/synedittexttabexpander.pas index 3df352b5ef..1428d2bac7 100644 --- a/components/synedit/synedittexttabexpander.pas +++ b/components/synedit/synedittexttabexpander.pas @@ -26,7 +26,7 @@ unit SynEditTextTabExpander; interface uses - LCLProc, Classes, SysUtils, SynEditTextBase; + LCLProc, Classes, SysUtils, LazSynEditText, SynEditTextBase; type diff --git a/components/synedit/synedittexttrimmer.pas b/components/synedit/synedittexttrimmer.pas index 6326bb661a..57c6ebac24 100644 --- a/components/synedit/synedittexttrimmer.pas +++ b/components/synedit/synedittexttrimmer.pas @@ -28,7 +28,7 @@ interface uses LCLProc, - Classes, SysUtils, SynEditTextBase, + Classes, SysUtils, LazSynEditText, SynEditTextBase, SynEditTypes, SynEditHighlighter, SynEditPointClasses, SynEditMiscProcs; type @@ -36,6 +36,24 @@ type TSynEditStringTrimmingType = (settLeaveLine, settEditLine, settMoveCaret, settIgnoreAll); + TSynEditStringTrimmingList = class; + + { TLazSynDisplayTrim } + + TLazSynDisplayTrim = class(TLazSynDisplayViewEx) + private + FTrimer: TSynEditStringTrimmingList; + FTempLineStringForPChar: String; + FAtLineStart: Boolean; + public + constructor Create(ATrimer: TSynEditStringTrimmingList); + procedure FinishHighlighterTokens; override; + procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); override; + function GetNextHighlighterToken(out ATokenStart: PChar; out ATokenLength: integer; + out ATokenAttr: TSynHighlighterAttributes + ): Boolean; override; + end; + { TSynEditStringTrimmingList } TSynEditStringTrimmingList = class(TSynEditStringsLinked) @@ -53,6 +71,7 @@ type FLineEdited: Boolean; FTempLineStringForPChar: String; // experimental; used by GetPChar; FViewChangeStamp: int64; + FDisplayView: TLazSynDisplayTrim; procedure DoCaretChanged(Sender : TObject); procedure ListCleared(Sender: TObject); Procedure LinesChanged(Sender: TSynEditStrings; AIndex, ACount : Integer); @@ -79,6 +98,7 @@ type procedure Put(Index: integer; const S: string); override; procedure PutObject(Index: integer; AObject: TObject); override; function GetPCharSpaces(ALineIndex: Integer; out ALen: Integer): PChar; // experimental + function GetDisplayView: TLazSynDisplayView; override; public constructor Create(ASynStringSource: TSynEditStrings; ACaret: TSynEditCaret); destructor Destroy; override; @@ -184,6 +204,48 @@ type function PerformUndo(Caller: TObject): Boolean; override; end; +{ TLazSynDisplayTrim } + +constructor TLazSynDisplayTrim.Create(ATrimer: TSynEditStringTrimmingList); +begin + inherited Create; + FTrimer := ATrimer; +end; + +procedure TLazSynDisplayTrim.FinishHighlighterTokens; +begin + inherited FinishHighlighterTokens; + FTempLineStringForPChar := ''; +end; + +procedure TLazSynDisplayTrim.SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); +begin + CurrentTokenLine := ALine; + FAtLineStart := True; + inherited SetHighlighterTokensLine(ALine, ARealLine); +end; + +function TLazSynDisplayTrim.GetNextHighlighterToken(out ATokenStart: PChar; out + ATokenLength: integer; out ATokenAttr: TSynHighlighterAttributes): Boolean; +begin + Result := False; + if not Initialized then exit; + + if (CurrentTokenHighlighter = nil) and (FTrimer.Spaces(CurrentTokenLine) <> '') then begin + Result := FAtLineStart; + if not Result then exit; + + FTempLineStringForPChar := FTrimer[CurrentTokenLine]; + ATokenStart := PChar(FTempLineStringForPChar); + ATokenLength := length(FTempLineStringForPChar); + ATokenAttr := nil; + FAtLineStart := False; + end; + + // highlighter currently includes trimed spaces + Result := inherited GetNextHighlighterToken(ATokenStart, ATokenLength, ATokenAttr); +end; + { TSynEditUndoTrimMoveTo } function TSynEditUndoTrimMoveTo.DebugString: String; @@ -344,6 +406,8 @@ begin fCaret := ACaret; fCaret.AddChangeHandler(@DoCaretChanged); fLockList := TStringList.Create; + FDisplayView := TLazSynDisplayTrim.Create(Self); + FDisplayView.NextView := ASynStringSource.DisplayView; fLineIndex:= -1; fSpaces := ''; fEnabled:=false; @@ -363,6 +427,7 @@ begin fSynStrings.RemoveChangeHandler(senrLineChange, {$IFDEF FPC}@{$ENDIF}LinesChanged); fSynStrings.RemoveNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}ListCleared); fCaret.RemoveChangeHandler(@DoCaretChanged); + FreeAndNil(FDisplayView); FreeAndNil(fLockList); inherited Destroy; end; @@ -740,6 +805,11 @@ begin Result := PChar(FTempLineStringForPChar); end; +function TSynEditStringTrimmingList.GetDisplayView: TLazSynDisplayView; +begin + Result := FDisplayView; +end; + function TSynEditStringTrimmingList.GetPChar(ALineIndex: Integer; out ALen: Integer): PChar; begin Result := inherited GetPChar(ALineIndex, ALen); diff --git a/components/synedit/synedittypes.pp b/components/synedit/synedittypes.pp index 9092240118..6fda0fc279 100644 --- a/components/synedit/synedittypes.pp +++ b/components/synedit/synedittypes.pp @@ -55,6 +55,9 @@ type TSynIdentChars = set of char; + TLinePos = type integer; // 1..high(Integer); + TLineIdx = type integer; // 0..high(Integer); + {$IFDEF SYN_LAZARUS} // NOTE: the note below is not valid for the LCL which uses UTF-8 {$ELSE} diff --git a/components/synedit/syngutterlinenumber.pp b/components/synedit/syngutterlinenumber.pp index 5a81362b57..8d8d10565c 100644 --- a/components/synedit/syngutterlinenumber.pp +++ b/components/synedit/syngutterlinenumber.pp @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Graphics, LCLType, LCLIntf, SynGutterBase, - SynEditMiscProcs, SynTextDrawer, SynEditMouseCmds, SynEditTextBuffer, SynEditTextBase; + SynEditMiscProcs, SynTextDrawer, SynEditMouseCmds, SynEditTextBuffer, LazSynEditText; type diff --git a/components/synedit/syngutterlineoverview.pp b/components/synedit/syngutterlineoverview.pp index e8b67b93ae..8a5b2578dd 100644 --- a/components/synedit/syngutterlineoverview.pp +++ b/components/synedit/syngutterlineoverview.pp @@ -28,7 +28,7 @@ interface uses Classes, Graphics, Controls, LCLProc, LCLType, LCLIntf, FPCanvas, sysutils, math, - SynGutterBase, SynEditTypes, SynEditTextBase, SynEditTextBuffer, SynEditMarks, + SynGutterBase, SynEditTypes, LazSynEditText, SynEditTextBuffer, SynEditMarks, SynEditMiscClasses; type diff --git a/components/synedit/synpluginsyncroedit.pp b/components/synedit/synpluginsyncroedit.pp index 1bd5189f99..e833963cd1 100644 --- a/components/synedit/synpluginsyncroedit.pp +++ b/components/synedit/synpluginsyncroedit.pp @@ -27,7 +27,7 @@ interface uses Classes, Controls, SysUtils, math, LCLProc, Forms, Graphics, SynEditMiscClasses, - LCLType, SynEdit, SynPluginSyncronizedEditBase, SynEditTextBase, SynEditMiscProcs, + LCLType, SynEdit, SynPluginSyncronizedEditBase, LazSynEditText, SynEditMiscProcs, SynEditMouseCmds, SynEditKeyCmds, SynEditTypes, LCLIntf; type diff --git a/components/synedit/synpluginsyncronizededitbase.pp b/components/synedit/synpluginsyncronizededitbase.pp index fca9d2ac5d..3e64995c7b 100644 --- a/components/synedit/synpluginsyncronizededitbase.pp +++ b/components/synedit/synpluginsyncronizededitbase.pp @@ -26,8 +26,8 @@ unit SynPluginSyncronizedEditBase; interface uses - Classes, SysUtils, math, Graphics, LCLProc, - SynEditMiscClasses, SynEdit, SynEditMarkup, SynEditMiscProcs, SynEditTextBase, + Classes, SysUtils, math, Graphics, LCLProc, SynEditTextBase, + SynEditMiscClasses, SynEdit, SynEditMarkup, SynEditMiscProcs, LazSynEditText, SynEditTextTrimmer, SynEditKeyCmds; type diff --git a/components/synedit/synplugintemplateedit.pp b/components/synedit/synplugintemplateedit.pp index 85e3a31c85..d045a634fc 100644 --- a/components/synedit/synplugintemplateedit.pp +++ b/components/synedit/synplugintemplateedit.pp @@ -28,7 +28,7 @@ interface uses Classes, SysUtils, math, Graphics, LCLType, SynEditMiscClasses, SynPluginSyncronizedEditBase, SynEditKeyCmds, SynEdit, SynEditMiscProcs, - SynEditTextBase, LCLProc; + LazSynEditText, LCLProc; type diff --git a/ide/sourceeditor.pp b/ide/sourceeditor.pp index 1bfbda6306..d71351fc1e 100644 --- a/ide/sourceeditor.pp +++ b/ide/sourceeditor.pp @@ -51,7 +51,7 @@ uses SynEditLines, SynEditStrConst, SynEditTypes, SynEdit, SynRegExpr, SynEditHighlighter, SynEditAutoComplete, SynEditKeyCmds, SynCompletion, SynEditMiscClasses, SynEditMarkupHighAll, SynEditMarks, - SynBeautifier, SynEditTextBase, + SynBeautifier, SynEditTextBase, LazSynEditText, SynPluginSyncronizedEditBase, SourceSynEditor, // Intf SrcEditorIntf, MenuIntf, LazIDEIntf, PackageIntf, IDEHelpIntf, IDEImagesIntf, diff --git a/ide/sourcesyneditor.pas b/ide/sourcesyneditor.pas index 9e08061bf6..de0981bc8a 100644 --- a/ide/sourcesyneditor.pas +++ b/ide/sourcesyneditor.pas @@ -41,7 +41,7 @@ uses SynEdit, SynEditMiscClasses, SynGutter, SynGutterBase, SynEditMarks, SynGutterLineNumber, SynGutterCodeFolding, SynGutterMarks, SynGutterChanges, SynGutterLineOverview, SynEditMarkup, SynEditMarkupGutterMark, - SynEditTextBuffer, SynEditFoldedView, SynTextDrawer, SynEditTextBase, + SynEditTextBuffer, SynEditFoldedView, SynTextDrawer, SynEditTextBase, LazSynEditText, SynPluginTemplateEdit, SynPluginSyncroEdit, SynEditHighlighter, SynEditHighlighterFoldBase, SynHighlighterPas;