Recent

Author Topic: Problem: How to conditionally mark multiple strings in a SynEdit  (Read 9328 times)

carlejt

  • New Member
  • *
  • Posts: 39
Hello

How to conditionally mark one or more strings in a SynEdit component?

The root of my problem (SynEdit): How to mark (with a red frame) a string on the line L between columns A and B when the cursor (text) is over the string "hello".

Thanks.


carlejt

  • New Member
  • *
  • Posts: 39
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #2 on: June 30, 2012, 06:11:13 pm »
Thanks for replying

yes, as to the mark.

But, My problem is: How to conditionally mark multiple strings in a SynEdit?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #3 on: June 30, 2012, 07:38:36 pm »
You mean in your own application, rather than in the IDE?

SynEdit has 2 concepts of getting highlight info.

1) The highlighter (I already pointed you to the tutorial in another post: http://wiki.lazarus.freepascal.org/SynEdit_Highlighter).
This is for text structure.

2) TSynEditMarkup
Can do anything.

unit SynEditMarkupHighAll
* TSynEditMarkupHighlightAll
  can highlight all occurrences of a given word
* TSynEditMarkupHighlightAllCaret
   the word under caret

One instance is present in each SynEdit
Code: [Select]
  TSynEditMarkupHighlightAllCaret(SynEdit1.MarkupByClass[TSynEditMarkupHighlightAllCaret]).MarkupInfo.FrameColor := clRed;

There are others, just look at the uses clause, top of the SynEdit unit.


You can write your own, but there is no documentation at all.

For sample (including how to subclass SynEdit, so you can add it), see unit SourceSynEditor (folder ide) TIDESynEditor and TSynEditMarkupGutterMark

carlejt

  • New Member
  • *
  • Posts: 39
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #4 on: July 01, 2012, 04:15:39 am »
Hi Martin, thanks for replying

My application is small, consists only of: Form1 with SynEdit1.

And my problem is: In SynEdit1, How to mark (with a red frame) a string on the line L between columns A and B when the cursor (text) is over the string "hello".

the solution to this problem would be helpful.

Thanks

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #5 on: July 01, 2012, 12:30:41 pm »
Ok, let's see if I understand

The word "hello" (or whatever the trigger) is not the sahe as Line L columns a and b?

columns a and b means from x=1 to x=b, or means 2 individual blocks?

Code: Text  [Select][+][-]
  1.   some text with hello in it
  2.   line L foo |column a - end column| mroe text foo bar |column b| abc
  3.  

Code: Text  [Select][+][-]
  1.   some text with hello in it
  2.   line L foo |HIGHLIGHT ME| abc
  3.  

If you do not neede the block selection at that time, you can use the  selection.
Code: [Select]
  options2 := options2 + [eoPersistentBlock]; // keep selection if caret moves]
  SelectedColor.FrameColor := ecRed;
  SelectedColor.FrameEdges := ...;
  BlockBegin := point(L,x1);
  BlockEnd := point(L,x2); 

If using the block is not an option(it is a bit of a hack) then you must subclass SynEdit (see SourceSynEditor)

You can add additional TSynEditMarkupSelection in

Code: [Select]
  constructor TYourSynedit.Create(AOwner....)
....
   inherited;/ must be first

  FMyBlock := TSynEditSelection.Create(ViewedTextBuffer, FAlse);  // set to True, to keep moving with text on edit
  FMyBlock.InvalidateLinesMethod := @InvalidateLines;

  fMyMarkup := TSynEditMarkupSelection.Create(self, FMyBlock);
  MarkupMgr.AddMarkUp(fMyMarkup);


You only need to free FMyBlock, the markup will be destroyed automatically

FMyBlock has start and end-point....

fMyMarkup  has MarkupColor (includes frame),

carlejt

  • New Member
  • *
  • Posts: 39
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #6 on: July 01, 2012, 04:29:52 pm »
Hello Martin fr, Thanks for responding

Excuse me, I will explain:

I want that when the cursor is on the line L and column C is marked the string of the line L+1 between columns C+2 and C+6.

Note: That process must always run.

Thanks

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #7 on: July 01, 2012, 04:40:49 pm »
Yes, so either use the selection, or create the markup, as I have indicated.


In both cases you must react to caret changes, and set the area that should be highlighted (not sure how it will work if there is no text. e.g highlight in an empty line may be tricky...

You can use the OnStatusChanged event.

It triggers on caret changes

carlejt

  • New Member
  • *
  • Posts: 39
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #8 on: July 01, 2012, 05:19:11 pm »
Hello Martin, Thanks for responding

I add the unit SynEditMarkupSelection to uses.

And then the events:

Code: [Select]
TForm1.FormCreate procedure (Sender: TObject);
begin

/ / Create markup?

end;

Code: [Select]
TForm1.SynEdit1StatusChange procedure (Sender: TObject; Changes: TSynStatusChanges);
begin

/ / set selection?

end;

My application is small, consists only of: Form1 with SynEdit1. the solution to this problem would be helpful.

Thanks

Leledumbo

  • Hero Member
  • *****
  • Posts: 8798
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #9 on: July 01, 2012, 05:43:36 pm »
Seems like you didn't read what Martin has written and only look for a straight solution... please try it yourself first.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #10 on: July 01, 2012, 05:56:09 pm »
Problem: You MUST inherit SynEdit It only works by accessing protected fields.

You either create a new component (via package menu) and register your synedit, or you create in in code.

Only works, if there is a line.
For backgroundcolor, line can be empty. Frame has a bug, and does draw incorrect, unless there is text

You still need to do an handler to update the pos, if the caret moves

I do recommend to use the Identifier dictionary (laz trunk, may need package cody installed), you can find stuff from all units, and it does add units to your uses.

Code: [Select]
unit Unit1;
{$mode objfpc}{$H+}

interface
uses
  Classes, SysUtils, FileUtil,  Forms, Controls, Graphics,  Dialogs,
  SynEdit, SynEditPointClasses, SynEditMarkupSelection, SynEditTypes, SynEditMarkup;

type
  { TMySyn }
  TMySyn = class(TSynEdit)
  private
    FMyBlock: TSynEditSelection;
    fMyMarkup: TSynEditMarkupSelection;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  { TForm1 }
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FMySyn: TMySyn;
  end;

var  Form1: TForm1;

implementation

constructor TMySyn.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FMyBlock := TSynEditSelection.Create(ViewedTextBuffer, FAlse); 
  FMyBlock.InvalidateLinesMethod := @InvalidateLines;
  fMyMarkup := TSynEditMarkupSelection.Create(self, FMyBlock);
  TSynEditMarkupManager(MarkupMgr).AddMarkUp(fMyMarkup);
end;

destructor TMySyn.Destroy;
begin
  FreeAndNil(FMyBlock);
  FreeAndNil(fMyMarkup);
  inherited Destroy;
end;

{$R *.lfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMySyn := TMySyn.Create(self);
  FMySyn.Parent:= self;
  FMySyn.Align := alClient;

  with FMySyn do begin
    FMySyn.text := 'ouaueuioeiuueiaoeuouoeauoeua' + LineEnding    +'ouaueuioeiuueiaoeuouoeauoeua' + LineEnding    +'ouaueuioeiuueiaoeuouoeauoeua' + LineEnding    ;
    FMyBlock.StartLineBytePos := Point(5,2);
    FMyBlock.EndLineBytePos := Point(15,2);
    fMyMarkup.Enabled := True;
    fMyMarkup.MarkupInfo.FrameColor := clRed;
    fMyMarkup.MarkupInfo.FrameEdges := sfeAround;
    fMyMarkup.MarkupInfo.FrameStyle := slsSolid;
    //fMyMarkup.MarkupInfo.Background := clSilver;
  end;
end;

end.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #11 on: July 01, 2012, 06:11:43 pm »
Oh and

Positions are in BYTE. (called logical
  1 = in front of first byte
  2 = between 1st and 2nd byte

If you have multibyte chars (e.g accented umlauts, none latin) then byte pos can be in the middle of a char. Such pos MUST NOT be used.

Caret uses screen pos. (called physical). That is different (and it also is not equal to chars)
A tab or some Chinese char (one char) use multiple screen pos.

There is LogicalCaret and PhysicalToLogical.

search it in code. It can be figured out from there

carlejt

  • New Member
  • *
  • Posts: 39
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #12 on: July 01, 2012, 11:45:26 pm »
Martin Br. Thank you very much for all the guidance.

Still i do not know how to create the handler (StatusChange) of FMySyn ...

Thank you very much...

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11036
  • Debugger - SynEdit - and more
    • wiki
Re: Problem: How to conditionally mark multiple strings in a SynEdit
« Reply #13 on: July 02, 2012, 12:30:18 am »
Like every other event ?

FMySynEdit.OnStatusChange := @YourHandler

Use codetools to complete YourHandler (yes it can complete that for you...


 

TinyPortal © 2005-2018