PageRenderTime 84ms CodeModel.GetById 13ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/components/synedit/syneditmarkupbracket.pp

http://github.com/graemeg/lazarus
Pascal | 281 lines | 214 code | 34 blank | 33 comment | 27 complexity | bb3e69b52493d0963b05fa2af88fc774 MD5 | raw file
  1{-------------------------------------------------------------------------------
  2The contents of this file are subject to the Mozilla Public License
  3Version 1.1 (the "License"); you may not use this file except in compliance
  4with the License. You may obtain a copy of the License at
  5http://www.mozilla.org/MPL/
  6
  7Software distributed under the License is distributed on an "AS IS" basis,
  8WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  9the specific language governing rights and limitations under the License.
 10
 11Alternatively, the contents of this file may be used under the terms of the
 12GNU General Public License Version 2 or later (the "GPL"), in which case
 13the provisions of the GPL are applicable instead of those above.
 14If you wish to allow use of your version of this file only under the terms
 15of the GPL and not to allow others to use your version of this file
 16under the MPL, indicate your decision by deleting the provisions above and
 17replace them with the notice and other provisions required by the GPL.
 18If you do not delete the provisions above, a recipient may use your version
 19of this file under either the MPL or the GPL.
 20
 21-------------------------------------------------------------------------------}
 22unit SynEditMarkupBracket;
 23
 24{$mode objfpc}{$H+}
 25
 26interface
 27
 28uses
 29  Classes, SysUtils, Graphics, SynEditMarkup, SynEditMiscClasses, Controls, LCLProc;
 30
 31type
 32  TSynEditBracketHighlightStyle = (
 33    sbhsLeftOfCursor,
 34    sbhsRightOfCursor,
 35    sbhsBoth
 36  );
 37  { TSynEditMarkupBracket }
 38
 39  TSynEditMarkupBracket = class(TSynEditMarkup)
 40  private
 41    // Physical Position
 42    FBracketHighlightPos: TPoint;
 43    FBracketHighlightAntiPos: TPoint;
 44    FHighlightStyle: TSynEditBracketHighlightStyle;
 45    FNeedInvalidate: Boolean;
 46    procedure SetHighlightStyle(const AValue: TSynEditBracketHighlightStyle);
 47  protected
 48    procedure FindMatchingBracketPair(LogCaret: TPoint;
 49      var StartBracket, EndBracket: TPoint);
 50    procedure DoCaretChanged(Sender: TObject); override;
 51    procedure DoTopLineChanged(OldTopLine : Integer); override;
 52    procedure DoLinesInWindoChanged(OldLinesInWindow : Integer); override;
 53    procedure DoTextChanged(StartLine, EndLine, ACountDiff: Integer); override;
 54    procedure DoMarkupChanged(AMarkup: TSynSelectedColor); override;
 55    procedure DoEnabledChanged(Sender: TObject); override;
 56    procedure DoVisibleChanged(AVisible: Boolean); override;
 57  public
 58    constructor Create(ASynEdit: TSynEditBase);
 59    procedure DecPaintLock; override;
 60
 61    function GetMarkupAttributeAtRowCol(const aRow: Integer;
 62                                        const aStartCol: TLazSynDisplayTokenBound;
 63                                        const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor; override;
 64    procedure GetNextMarkupColAfterRowCol(const aRow: Integer;
 65                                         const aStartCol: TLazSynDisplayTokenBound;
 66                                         const AnRtlInfo: TLazSynDisplayRtlInfo;
 67                                         out   ANextPhys, ANextLog: Integer); override;
 68
 69    procedure InvalidateBracketHighlight;
 70    property HighlightStyle: TSynEditBracketHighlightStyle read FHighlightStyle write SetHighlightStyle;
 71  end;
 72
 73implementation
 74uses
 75  SynEdit;
 76
 77{ TSynEditMarkupBracket }
 78
 79constructor TSynEditMarkupBracket.Create(ASynEdit : TSynEditBase);
 80begin
 81  inherited Create(ASynEdit);
 82  FBracketHighlightPos.Y := -1;
 83  FBracketHighlightAntiPos.Y := -1;
 84  FHighlightStyle := sbhsBoth;
 85  MarkupInfo.Foreground := clNone;
 86  MarkupInfo.Background := clNone;
 87  MarkupInfo.Style := [fsBold];
 88  MarkupInfo.StyleMask := [];
 89end;
 90
 91procedure TSynEditMarkupBracket.DecPaintLock;
 92begin
 93  inherited DecPaintLock;
 94  if (FPaintLock = 0) and FNeedInvalidate then
 95    InvalidateBracketHighlight;
 96end;
 97
 98procedure TSynEditMarkupBracket.SetHighlightStyle(
 99  const AValue: TSynEditBracketHighlightStyle);
100begin
101  if FHighlightStyle <> AValue then
102  begin
103    FHighlightStyle := AValue;
104    InvalidateBracketHighlight;
105  end;
106end;
107
108procedure TSynEditMarkupBracket.FindMatchingBracketPair(LogCaret: TPoint; var StartBracket,
109  EndBracket: TPoint);
110const
111  Brackets: set of Char = ['(',')','{','}','[',']', '''', '"' ];
112var
113  StartLine: string;
114  x: Integer;
115begin
116  StartBracket.Y := -1;
117  EndBracket.Y := -1;
118  if (LogCaret.Y < 1) or (LogCaret.Y > Lines.Count) or (LogCaret.X < 1) then
119    Exit;
120
121  StartLine := Lines[LogCaret.Y - 1];
122
123  // check for bracket, left of cursor
124  if (HighlightStyle in [sbhsLeftOfCursor, sbhsBoth]) and (LogCaret.x > 1) then
125  begin
126    x := Lines.LogicPosAddChars(StartLine, LogCaret.x, -1);
127    if (x <= length(StartLine)) and (StartLine[x] in Brackets) then
128    begin
129      StartBracket := LogCaret;
130      StartBracket.x := x;
131      EndBracket := TCustomSynEdit(SynEdit).FindMatchingBracketLogical(StartBracket, False, False, False, False);
132      if EndBracket.y < 0 then
133        StartBracket.y := -1;
134      Exit;
135    end;
136  end;
137
138  // check for bracket after caret
139  if (HighlightStyle in [sbhsRightOfCursor, sbhsBoth]) then
140  begin
141    x := LogCaret.x ;
142    if (x <= length(StartLine)) and (StartLine[x] in Brackets) then
143    begin
144      StartBracket := LogCaret;
145      EndBracket := TCustomSynEdit(SynEdit).FindMatchingBracketLogical(LogCaret, False, False, False, False);
146      if EndBracket.y < 0 then
147        StartBracket.y := -1;
148    end;
149  end;
150end;
151
152procedure TSynEditMarkupBracket.DoCaretChanged(Sender: TObject);
153begin
154  InvalidateBracketHighlight;
155end;
156
157procedure TSynEditMarkupBracket.DoTopLineChanged(OldTopLine: Integer);
158begin
159  InvalidateBracketHighlight;
160end;
161
162procedure TSynEditMarkupBracket.DoLinesInWindoChanged(OldLinesInWindow: Integer);
163begin
164  InvalidateBracketHighlight;
165end;
166
167procedure TSynEditMarkupBracket.DoTextChanged(StartLine, EndLine,
168  ACountDiff: Integer);
169begin
170  InvalidateBracketHighlight;
171end;
172
173procedure TSynEditMarkupBracket.DoMarkupChanged(AMarkup: TSynSelectedColor);
174begin
175  InvalidateBracketHighlight;
176end;
177
178procedure TSynEditMarkupBracket.DoEnabledChanged(Sender: TObject);
179begin
180  InvalidateBracketHighlight;
181end;
182
183procedure TSynEditMarkupBracket.DoVisibleChanged(AVisible: Boolean);
184begin
185  inherited DoVisibleChanged(AVisible);
186  if SynEdit.IsVisible then
187    InvalidateBracketHighlight;
188end;
189
190procedure TSynEditMarkupBracket.InvalidateBracketHighlight;
191var
192  NewPos, NewAntiPos, SwapPos : TPoint;
193begin
194  FNeedInvalidate := True;
195  if (Caret = nil) or (not SynEdit.HandleAllocated) or (FPaintLock > 0) or
196     (not SynEdit.IsVisible)
197  then
198    exit;
199
200  FNeedInvalidate := False;
201  NewPos.Y:=-1;
202  NewAntiPos.Y:=-1;
203  if eoBracketHighlight in TCustomSynEdit(SynEdit).Options
204  then FindMatchingBracketPair(Caret.LineBytePos, NewPos, NewAntiPos);
205
206  // Always keep ordered
207  if (NewAntiPos.Y > 0)
208  and ((NewAntiPos.Y < NewPos.Y) or ((NewAntiPos.Y = NewPos.Y) and (NewAntiPos.X < NewPos.X)))
209  then begin
210    SwapPos    := NewAntiPos;
211    NewAntiPos := NewPos;
212    NewPos     := SwapPos;
213  end;
214
215  // invalidate old bracket highlighting, if changed
216  if (FBracketHighlightPos.Y > 0)
217  and ((FBracketHighlightPos.Y <> NewPos.Y) or (FBracketHighlightPos.X <> NewPos.X))
218  then begin
219    //DebugLn('TCustomSynEdit.InvalidateBracketHighlight A Y=',dbgs(FBracketHighlightPos));
220    InvalidateSynLines(FBracketHighlightPos.Y,FBracketHighlightPos.Y);
221  end;
222
223  if (FBracketHighlightAntiPos.Y > 0)
224  and (FBracketHighlightPos.Y <> FBracketHighlightAntiPos.Y)
225  and ((FBracketHighlightAntiPos.Y <> NewAntiPos.Y) or (FBracketHighlightAntiPos.X <> NewAntiPos.X))
226  then
227    InvalidateSynLines(FBracketHighlightAntiPos.Y,FBracketHighlightAntiPos.Y);
228
229  // invalidate new bracket highlighting, if changed
230  if NewPos.Y>0 then begin
231    //DebugLn('TCustomSynEdit.InvalidateBracketHighlight C Y=',dbgs(NewPos.Y),' X=',dbgs(NewPos.X),' Y=',dbgs(NewAntiPos.Y),' X=',dbgs(NewAntiPos.X));
232    if ((FBracketHighlightPos.Y <> NewPos.Y) or (FBracketHighlightPos.X <> NewPos.X))
233    then InvalidateSynLines(NewPos.Y, NewPos.Y);
234
235    if ((NewPos.Y <> NewAntiPos.Y)
236        or ((FBracketHighlightPos.Y = NewPos.Y) and (FBracketHighlightPos.X = NewPos.X))
237       )
238    and ((FBracketHighlightAntiPos.Y <> NewAntiPos.Y) or (FBracketHighlightAntiPos.X <> NewAntiPos.X))
239    then InvalidateSynLines(NewAntiPos.Y, NewAntiPos.Y);
240  end;
241  FBracketHighlightPos     := NewPos;
242  FBracketHighlightAntiPos := NewAntiPos;
243//  DebugLn('TCustomSynEdit.InvalidateBracketHighlight C P=',dbgs(NewPos),' A=',dbgs(NewAntiPos), ' LP=',dbgs(fLogicalPos),' LA',dbgs(fLogicalAntiPos));
244end;
245
246function TSynEditMarkupBracket.GetMarkupAttributeAtRowCol(const aRow: Integer;
247  const aStartCol: TLazSynDisplayTokenBound; const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor;
248begin
249  Result := nil;
250  if ((FBracketHighlightPos.y = aRow) and  (FBracketHighlightPos.x = aStartCol.Logical))
251  or ((FBracketHighlightAntiPos.y = aRow) and  (FBracketHighlightAntiPos.x = aStartCol.Logical))
252  then begin
253    Result := MarkupInfo;
254    MarkupInfo.SetFrameBoundsLog(aStartCol.Logical, aStartCol.Logical + 1); // bracket is alvays 1 byte
255  end;
256end;
257
258procedure TSynEditMarkupBracket.GetNextMarkupColAfterRowCol(const aRow: Integer;
259  const aStartCol: TLazSynDisplayTokenBound; const AnRtlInfo: TLazSynDisplayRtlInfo; out ANextPhys,
260  ANextLog: Integer);
261begin
262  ANextLog := -1;
263  ANextPhys := -1;
264  if (FBracketHighlightPos.y = aRow) then begin
265    if  (FBracketHighlightPos.x > aStartCol.Logical )
266    then ANextLog := FBracketHighlightPos.x
267    else if  (FBracketHighlightPos.x + 1 > aStartCol.Logical )
268    then ANextLog := FBracketHighlightPos.x + 1; // end of bracket
269  end;
270  if (FBracketHighlightAntiPos.y = aRow) then begin
271    if  (FBracketHighlightAntiPos.x > aStartCol.Logical )
272    and ((FBracketHighlightAntiPos.x < ANextLog) or (ANextLog < 0))
273    then ANextLog := FBracketHighlightAntiPos.x
274    else if  (FBracketHighlightAntiPos.x + 1 > aStartCol.Logical )
275    and ((FBracketHighlightAntiPos.x + 1 < ANextLog) or (ANextLog < 0))
276    then ANextLog := FBracketHighlightAntiPos.x + 1;
277  end
278end;
279
280end.
281