Jump to content

pyscripter

Members
  • Content Count

    785
  • Joined

  • Last visited

  • Days Won

    42

Posts posted by pyscripter


  1. No.  It is (was) a stand-alone free and open source C/C++ IDE, working with the GNU compiler toolset built with Delphi and quite popular at its prime.  There is a fork that includes a form designer for WxWidgets GUI applications. 

     

    Does anyone recall the short-lived commercial C++ wxWidgets (then called WxWindows) Borland IDE (unrelated to Dev-C++)?  I can't even remember what it was called. 


  2. 5 hours ago, A.M. Hoornweg said:

    Okay, that makes sense; so if I use tAggregatedObject then I can use the "AS" keyword to freely switch between the inner and the outer interface (see example 1) whereas in tContainedObject that isn't possible (it would only let me switch from the outer to the inner interface, right?) .

    Yes


  3. 1 hour ago, A.M. Hoornweg said:

    And the controller explicitly manages the inner object's lifetime, not through reference counting.

    Exactly.  If you are familiar with Excel automation think about the Applications and the Workbooks collection.  The second exists only as part of the first.  The second could be implemented as a TContainedObject.

     

    What TAggregatedObject and TContainedObject have in common:

    • They have no separate reference counting
    • They should be created and destroyed by the Controller.

    How do they differ? (from the source code)

    • TAggregatedObject simply reflects QueryInterface calls to its controller.  From such an aggregated object, one can  obtain any interface that the controller supports, and  only interfaces that the controller supports.  This is  useful for implementing a controller class that uses one
        or more internal objects to implement the interfaces declared  on the controller class.  Aggregation promotes implementation  sharing across the object hierarchy.
    • TContainedObject is an aggregated object that isolates  QueryInterface on the aggregate from the controller.    TContainedObject will return only interfaces that the  contained object itself implements, not interfaces  that the controller implements.

  4. If you are switching from another version of Synedit to Synedit-2 you need to uninstall the current version, remove all compiled packages and install from scratch.  As mentioned above I am not sure which is the earliest version supported (same about the Turbo Synedit), however I am quite sure Delphi 10.2 should be good.


  5. 2 minutes ago, dummzeuch said:

    Judging from the VERxxx constants in the package source, SynEdit2 supports Delphi 2006 and up, correct? Could you please add that to the project description? @pyscripter

    To be frank I am not sure.  Like the Turbo branch it is aimed at the most recent versions of Delphi.  The code uses generics and unicode, so that I suppose determines the minimum version.   


  6. 26 minutes ago, Darian Miller said:

    I'm currently in the same situation of looking at the SynEdit-2 vs SynEdit.  I originally picked SynEdit-2 by Pyscripter due to his changes, but am now using the github/SynEdit version due to Gutter.ShowModification support.

    Unfortunately SynEdit's ShowModification is half-baked and does not work well when you undo.   This is why it has not been ported to SynEdit-2.  Proper support requires some work in the undo/redo system.


  7. I will start with a bit of history.

    • The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, a great programmer.  The key feature of the editor was fast syntax highlighting.  This was more than 20 years ago.
    • After a split of the community the SynEdit project was formed maintaining some of the key features of mwEdit.
    • Over the years some of the best Delphi programmers contributed to the project.  The list includes for example Gerald Nunn, Eric Grange, Jordan Russell and many many others.
    • Flavio Etrusco added word wrap and Maël Hörz added unicode support (but in a rather idiosyncratic way).
    • However the project management was very weak and the code gradually became very hard to maintain and improve.  It aimed to support very old Delphi versions including Kylix and the code became full of IFDEFs and patches without an overall coherence.
    • An early fork of Synedit is part of Lazarus but the two development efforts have diverged a great deal.
    • When Embarcadero introduced the GetIt package manager they asked Roman Kassebaum to produce a version of SynEdit for GetIt.  Roman did a general code cleanup removing support for early Delphi versions and Kylix (Turbo fork(s)).
    • I have added support for code folding (the first major new feature for years) to both the Turbo fork and the main Synedit repository.
    • However the Turbo fork(s) were not actively supported or developed beyond recompiling for new Delphi versions and the main Synedit branch was too hard to work with, hence the creation of SynEdit-2 as a fork of Turbo SynEdit.

    Main new features in SynEdit-2:

    • Replaced SynRegExpr with the built-in RegularExpressions
    • Move/Copy Line(s) Up/Down commands as in VS Code
    • Delete Line command should work with multi-line selection
    • Handle triple and quadruple clicks for selection
    • Triple click and drag should select lines 
    • Double click and drag should select whole words 
    • Support OLE Drag & Drop 

    What are the key features missing in Synedit:

    • Better Unicode handling:
      • Better support for wide characters e.g. Chinese ideograms (爾雅爾雅爾雅爾雅)
      • Support for surrogate pairs (two widechars correspond to one glyph)
      • Combining characters (e.g. Åström ḱṷṓn)
    • Multi-cursor and multi-selection editing as in VS Code.

    When these features get implemented I think SynEdit will become comparable to some of the best editors around. But both of them require major rewriting of the code.  Work on the second is well advanced and the unicode work is in the planning stage.

     

    Of course it is your choice as to which version of SynEdit to use, but if anyone wants to contribute to the development you are very welcome.

     

     

    • Like 6
    • Thanks 2

  8. 5 hours ago, Dmitry Arefiev said:

    Thanks a lot !
    The proposed here changes will be in 10.4 Update 1 with some modifications. Mostly due to new cross-platform AtomicCmpExchange128 for 64bit platforms.

    This is worth a certain degree of celebration.   I cannot remember Embarcadero/Inprice/Borland etc. being so responsive ever. It also demonstrates the power of the collective efforts of the community to make Delphi better.

    • Like 1

  9. 56 minutes ago, Stefan Glienke said:

    Ugh  - just stop it please

    That is so nice...

     

    Thanks for spotting the typo anyway.    With the typo fixed the following test code:

     

    procedure Test();
    begin
      try
        var Bob := TSmartPointer.Wrap(TTalking.Create('Bob'));
        Bob.Talk;
        var John := TSmartPointer.Wrap(TTalking.Create('John'));
        John.Talk;
        John := Bob;
        John.Talk;
      finally
        WriteLn('Do more stuff');
      end;
    end;

    produces

     

    Bob is talking
    John is talking
    Release 0
    John is gone
    Bob is talking
    Release 1
    Release 0
    Bob is gone
    Do more stuff

    with no AV or memory leak.


  10. 7 hours ago, Stefan Glienke said:

    hardly - its approx 25% to 50% slower

    True.  Spring4D is the best!  And for what it is (not) worth, I have voted for RSP-27375.

     

    Here is another one (more complex but still compact) which I think is comparable and similar in approach to Spring4D, based on a Stackoverflow question.  I am adding it here for the completeness of the discussion.

     

    type
    TInjectType<T> = record
    public
      VMT: pointer;
      unknown: IInterface;
      RefCount: integer;
      AValue: T;
    end;
    
    TInject<T> = class
    public type
      TInjectType = TInjectType<T>;
      PInjectType = ^TInjectType;
    end;
    
    PInjectObjectType = TInject<TObject>.PInjectType;
    
    TSmartPointer = class
      class function Wrap<T: class>(const AValue: T): TFunc<T>; static;
    end;
    
    function Trick_Release(const obj:  PInjectObjectType): Integer; stdcall; forward;
    function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall; forward;
    function Invoke(const obj:  PInjectObjectType): TObject; forward;
    
    const
      PSEUDO_VMT: array [0 .. 3] of pointer = (nil, @Trick_AddRef, @Trick_Release, @Invoke);
    
    function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall;
    begin
      Result:= AtomicIncrement(Obj^.RefCount);
    end;
    
    function Trick_Release(const obj:  PInjectObjectType): Integer; stdcall;
    begin
      Result:= AtomicDecrement(Obj^.RefCount);
      WriteLn('Release '+IntToStr(Obj.RefCount));
      if Result = 0 then begin
        obj^.AValue.Free;
        FreeMem(obj);
      end;
    end;
    
    function Invoke(const obj:  PInjectObjectType): TObject;
    begin
      Result:= obj^.AValue;
    end;
    
    class function TSmartPointer.Wrap<T>(const AValue: T): TFunc<T>;
    var
      p: PInjectObjectType;
    begin
      P:= GetMemory(SizeOf(TInjectType<T>));
      p.RefCount:= 1;
      pointer(p.unknown):= p;
      p.VMT:= @PSEUDO_VMT;
      p.AValue:= AValue;
      pointer(Result):= pointer(TFunc<T>(p));
    end;

    Note: typo corrected (see below).


  11. Minimalist implementation of SmartPointers based on a old post by Barry Kelly  comparable to the Spring4D one in performance.

     

    type
      TObjectHandle<T: class> = class(TInterfacedObject, TFunc<T>)
      private
        FValue:  T;
      public
        constructor  Create(AValue:  T);
        destructor  Destroy;  override;
        function  Invoke:  T;
      end;
    
      TSmartPointer = record
        class function Make<T: class>(AValue: T): TFunc<T>; static;
      end;
    
    constructor  TObjectHandle<T>.Create(AValue:  T);
    begin
      FValue  :=  AValue;
    end;
    
    destructor  TObjectHandle<T>.Destroy;
    begin
      FValue.Free;
    end;
    
    function  TObjectHandle<T>.Invoke:  T;
    begin
      Result  :=  FValue;
    end;
    
    
    { TSmartPointer }
    
    class function TSmartPointer.Make<T>(AValue: T): TFunc<T>;
    begin
      Result := TObjectHandle<T>.Create(AValue);
    end;

    Used as in:

     

     var Bob := TSmartPointer.Make(TTalking.Create('Bob'))();
    or
     var Bob := TSmartPointer.Make(TTalking.Create('Bob'));

     

    • Like 1

  12. @Anders Melander The general rule that has always applied is that managed types (strings, interfaces, records with managed fields, dynamic arrays, etc,) are finalized at the end of the scope in which they are introduced.  This included temp variables.

    The newly introduced managed records breaks this rule.  Whether you like it better or not, it is inconsistent.

     

    And a local block does not solve the problem.  The temp managed record will still self-destruct at the end of the statement it is used. 


  13. 17 minutes ago, Anders Melander said:

    I actually prefer that finalization style over the way interfaces etc. are finalized. At least this is by design while the old style seems more like a side effect of an implementation detail.

     

    I've always had a problem with this:

    
    var
      Foo: IUnknown;
    begin
      Foo := TInterfacedObject.Create as IUnknown;
      ...some code here...
      Foo := nil; // This doesn't destroy the object
      ...more code here...
    end; // but this does

    I've not tried it but from the comment by Chee Wee Chua on RSP-28520 is seems I could solve it with a managed record inside a local block.

    Your example is not correct:

     

    Try:

    program Scope;
    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils,
      System.Classes;
    
    type
      TTestScope = class(TInterfacedObject)
         destructor Destroy; override;
      end;
    
    { TTestScope }
    destructor TTestScope.Destroy;
    begin
      WriteLn('Gone');
      inherited;
    end;
    
    procedure Test;
    var
      Foo: IUnknown;
    begin
      Foo := TTestScope.Create as IUnknown;
      WriteLn('Do stuff');
      Foo := nil; // This does destroy the object
      WriteLn('Do more stuff');
    end;
    
    begin
      Test();
      ReadLn;
    end.

    Output:

     

    Do stuff
    Gone
    Do more stuff

     

     

    • Like 3
×