-
Content Count
136 -
Joined
-
Last visited
-
Days Won
3
Everything posted by darnocian
-
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
Ah, yes. I see what you mean. 😉 -
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
Yes, you can do something like the following: begin var ctx := Template.Context; ctx.StartToken := '{{'; ctx.EndToken := '}}'; Assert.IsEqual('hello', Template.Eval(ctx, '{{ if true }}hello{{else}}bye{{end}}')); end; -
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
Yes. I've illustrated option1 to start... as mentioned, I'll follow up on option 2... personally, I don't think there has to be an absolute rule about where presentation logic is... ideally we want it constrained to the presentation layer where possible... going the option2 route can make the template less pleasant to read, and that is sort of what the helper functions are there to do, besides providing additional bridging.... Also note - the option1 route may be faster from a CPU perspective (just mentioning)... anyways, I'll present that example in a few days when I get some time too look at it again. -
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
Let say there is some type stuff looking like follows: type TMenuItem = class; TMenuItemCollection = class private FChildren: TObjectList<TMenuItem>; public constructor Create(); destructor Destroy; override; function AddChild(const AName: string): TMenuItem; property Children: TObjectList<TMenuItem> read FChildren; end; TMenuItem = class(TMenuItemCollection) private FName: string; FLast: boolean; public constructor Create(const AName: string = ''); property Name: string read FName; property Last: boolean read FLast write FLast; end; TMenu = TMenuItem; With traditional recursion, you can do the following: procedure GetHtmlRecursive(const AMenu: TMenu; const ASB: TStringBuilder); forward; overload; procedure GetItemHtmlRecursive(const AMenuItem: TMenuItem; const ASB: TStringBuilder); var LItem: TMenuItem; begin ASB.Append('<li>'); ASB.Append(AMenuItem.Name); if AMenuItem.Children.Count > 0 then begin GetHtmlRecursive(AMenuItem, ASB); end; ASB.Append('</li>'); end; procedure GetHtmlRecursive(const AMenu: TMenu; const ASB: TStringBuilder); overload; var LItem: TMenuItem; begin if AMenu.Children.Count = 0 then exit; ASB.Append('<ol>'); for LItem in AMenu.Children do begin GetItemHtmlRecursive(LItem, ASB); end; ASB.Append('</ol>'); end; function GetHtmlRecursive(const AMenu: TMenu): string; overload; var LSB: TStringBuilder; LItem: TMenuItem; begin if AMenu.Children.Count = 0 then exit(''); LSB := TStringBuilder.Create; try GetHtmlRecursive(AMenu, LSB); exit(LSB.ToString); finally LSB.free; end; end; To test, we can try something like: var lmenu: TMenu; lchild: TMenuItem; lchild2: TMenuItem; lchild3: TMenuItem; begin lmenu := TMenu.Create; try lchild := lmenu.AddChild('a'); lchild2 := lchild.AddChild('a1'); lchild3 := lchild2.AddChild('a1a'); lchild3 := lchild2.AddChild('a1b'); lchild2 := lchild.AddChild('a2'); lchild2 := lchild.AddChild('a3'); lchild := lmenu.AddChild('b'); lchild2 := lchild.AddChild('b1'); lchild2 := lchild.AddChild('b2'); lchild3 := lchild2.AddChild('b2a'); lchild3 := lchild2.AddChild('b2b'); lchild2 := lchild.AddChild('b3'); var lstr := GetHtmlRecursive(lmenu); writeln(lstr); finally lmenu.free; end; end; So the above just demonstrates how a menu could be done via delphi code... So next, we want to try test this from the template... I havn't got to test this for myself with the above code yet, but you should be able to do the following: type TMyTemplateData = record Menu : TMenu; Data : TData; // whatever end; TTemplateUtils = class public class function RenderMenu(const AMenu: TMenu) : string; static; // call the function above, or just move that in here end; var LMyData:TMyTemplateData; LCtx : TTemplateContext; begin LMyData.Menu := ... some setup ..; LMyData.Data := ... some setup ...; LCtx := TTemplateContext.Create; LCtx.Functions.addfunctions(TTemplateUtils); writeln(Template.Eval(LCtx,'Here is my menu:<br><% RenderMenu(Menu) %>', LMyData); end; -
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
recursive functions call themselves and helper functions utilising the normal stack by managing CPU stack registers. It is often easier to do things this way as well, but there is also a scenario where you can have a stack overflow, depending on how much memory is accessible by the stack. From an algorithmic perspective, it is possible to transform functionally recursive functions to utilise a developer managed stacks, which are used to backtrack appropriately. last night, I wrote a quick recursive one that I can share. I'm a bit busy now, so might only get to the 'dev stack' bound one over the weekend or next week. Let me know if you want me to share stuff earlier. -
Sempare Template - How do you do recursive code generation?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
The template engine is primarily focused on rendering output where data is provided by variables passed in. It does support calling functions written in Delphi. I think you could do two ways: have a function that does the recursion and returns the relevant html (so complexity is in the function in delphi). pro: template will appear simpler con: some presentation is offloaded to the function you can pass the menu structure to the template. you could use a stack in the template, which would allow you to process the structure in a recursive way using a stack, rather than relying on function recursion with a function stack. pro: all presentation is in the template con: the template may look a bit more complex I think I prefer option 2. As the template engine will not know offhand how to create a stack, the easiest is to have a structure containing menu and stack which is passed to the template. -
Maybe it is simpler to imagine this way: - downloading the content from websites = scraping - inspecting that content and extracting something meaningful = parsing so when you scrape a website, the two concepts work hand in hand. get the content, extract anything meaningful, identify if there are any links, repeat... parsing isn't an undocumented subject. it is often taught in courses on compiler theory ... but doesn't necessarily have to relate to compilers... also, the way content can be parsed can vary: - you can be formal and parse according to some language's grammatical rule set - you can cheat - if you know something about the content, you could do some pos() + copy() to get what you want out of it - you could even use regular expressions to extract data based on patterns you may be interested in... e.g. emails or urls can be easily identifiable
-
Hi everyone, Following fast on my last post, I thought I'd also share another development I've started - a Console Manager for the Delphi IDE. This is a tool that allows you to spin up a cmd.exe or powershell.exe within a dockable form, localised within the Delphi IDE. Features: - It is aware of the active project, so it will open up in the directory in which the dproj is located. It is still very alpha as in it just streams stdout/stdin, and not totally pleasant on the eye, but ok for an alpha POC. - I've got a little slider that allows you to zoom in/out. - (planning) The ability to have lists of commands / saved environments that could be applied to a newly created session. This is a POC, and still have some more work to do as I want to embrace the new pseudo console api which was introduced with the new Windows Terminal drive along with the VT emulation which would support colour, repositioning of the cursor, etc. I have not released this publicly yet, but attached is a short video demonstrating how it works. If you are interested in accessing it, please send me a mail: conrad.vermeulen@gmail.com. Let me know about what IDEs versions you may be interested in. I think I can do XE8 onwards. I'll provide more information when it is officially released. Regards, Conrad
-
agreed. I think the newer api should be better for doing this sort of thing.
-
I know this topic area isn't supposed to be commercial. Would it be reasonable to charge a small $5-$10 to build and support this? Open to ideas on the matter.
-
Thanks Edwin. I did mention it was a POC... and am aiming for the full 'embedded' experience. 😉 There isn't really a 'directly embedding' option from what I've researched, but open to any input on the matter. Essentially there are 2 ways I've read about: - the legacy apis using the 'old style' win32 apis - what I've essentially seen happen is the guys hide the actual console that is created, and scrape the console buffer, console size and cursor information, and then redraw it. seems convoluted, but I believe this is what the cmd.exe hosting window does. I read this a few days ago, but can't recall the exact source. (and maybe I'm wrong - I'm open to that too) 😉 - the 'new style' using the pseudo terminal apis - as Microsoft has embraced the unix world, the new pseudo terminal apis are aimed at bridging the legacy and unix philosophies... I'm still reading... I started so far creating bindings for some of the missing api functions from windows.pas etc... I'll probably go down the 'new' way to future proof things, but the current version tickles my immediate itch, but I know there is more scratching on its way. If there are simpler approaches, I'm open to hearing about them. There are some 3rd party libs used in other IDEs like WinPty... I have not explored it yet, but also not sure if the additional dependency is really needed, except from a saving time perspective if it proves easy to do and does the job well. i wanted to have a 'list' of consoles, as these windows can go invisible, so something needs to manage them. I wanted to add a menu item in the right-click 'project structure'... but that menu is already so long... But maybe on the main 'Project' menu in the IDE, the item could be for the current project. Although that may require an additional popup to select which terminal. I'm not totally happy with my current UI behaviour in the current implementation as it presents a popup to give the window a name. if I present an option as a menu item, then a may want to have 2 options - start a powershell.exe, start a cmd.exe... the list can just get automatic naming, and people could rename afterwards if they desire.
-
I was not sure if the docking thing would be a hard or not, but decided to give it a shot... and result! Thanks for the feedback.
-
Agreed. I'll keep you posted on the evolution...
-
Trojan:Script/Sabsik.TE.A!ml detected (false positive of course)
darnocian replied to Clément's topic in RTL and Delphi Object Pascal
just a note when signing files - it may be obvious, but also ensure that any relevant metadata in versioninfo matches the digital signature. e.g. don't use an abbreviation in one place and not the other....the AV guys like metadata to match exactly. Most vendors have a url where you can upload a sample for review where upon acceptance the app will be whitelisted. It is annoying to have to do this however. I have the false positives kicking in while I'm writing unit tests from time to time. the test app gets deleted before it has a chance to run. ;( And then making what may be a seemingly irrelevant change gets it to work again. -
I will definitely try to explore the direct docking when I can. I did ask David Millington about some of the features exposed via the ToolsAPI and there are some limitations... I think it would be nice for the console windows to be docked alongside the main console manager window, or possibly have some icons that can represent the preferred docking location (much like the alignment popup for controls in the object inspector). The dockable windows can be created, shown or hidden, but the ToolsAPI doesn't present other features currently. It may just be that I need to play around more as well. I found an ancient reference by Allen Bauer on the topic - it looked like it could have been the original prototype. But I'll see how that goes... The first big step I'd like to make is getting full terminal emulation going properly. Thanks again for your comments.
-
I've just been working on some IDE experts/wizards. It can be a little annoying ensuring a clean shutdown sometimes, and not always easy to identify the root problem. I wish the IDE would allow for a registry config variable for displaying/hiding exceptions on shutdown. It is a bit annoying when 3rd parties behave badly. 😉
-
Debug Configuration Manager for the Delphi IDE
darnocian replied to darnocian's topic in I made this
I've only tested it on 10.4 Sydney so far. Let me know which Delphi versions may be of interested and I can look building for that. I think I have access from XE8 onwards. Regards, Conrad -
Generic event handler for a generic class
darnocian replied to CoMPi74's topic in Algorithms, Data Structures and Class Design
Sorry, I think I was a dufus and didn't pay attention to what i was doing. 😉 Reproducing correctly with event2:TEvent2<T> , the event2 is not exposed as you highlighted... It would be useful to raise the Quality Portal issue so that this type of scenario works... Generics can be really powerful, but unfortunately there are lots of bugs with the implementation. ;( -
Generic event handler for a generic class
darnocian replied to CoMPi74's topic in Algorithms, Data Structures and Class Design
I thought I should try properly to try reproduce as well rather than speculate. 😉 The following worked for me: type TEvent = procedure (avalue:integer)of object; TEvent2<T:record> = procedure (avalue:t) of object; TCustomEdit<T:record> = class(TEdit) private fevent1:tevent; fevent2:TEvent2<integer>; published property event1:tevent read fevent1 write fevent1; property event2:tevent2<integer> read fevent2 write fevent2; end; TEditEx = class(TCustomEdit<integer>) end; ide was fine on my end. -
Generic event handler for a generic class
darnocian replied to CoMPi74's topic in Algorithms, Data Structures and Class Design
I've also had bad experience in the past, and the bug should be re-reported. Does making an 'intermediate' concrete type like the following do anything: TBaseIntEdit = class abstract(TCustomEdit<Integer>); TIntEdit = class(TBaseIntEdit) ... -
Generics compiler Error "Incompatible Types"
darnocian replied to luebbe's topic in Algorithms, Data Structures and Class Design
I think the compiler is getting confused as your generic parameters matches the names of existing types. if you rename the standalone IMyIntf to something else, then the generic type can remain TMyList<IMyIntf>, and similarly for TMyType, the generic types should be ok. alternatively rename the generic parameters, and even placing constraints may be helpful. e.g. TMyList<TIntf: IMyInf> = class ... TMyTypeList<T:class> = class ... -
Parsing Text search expression
darnocian replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I wasn’t sure if you were referring to the test snippets I posted? in the project I made to illustrate writing the custom parsers, I provided alternative TParser implementations - just thought I’d clarify in case of confusion. -
Parsing Text search expression
darnocian replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
He was just meaning that in other languages there are more libraries for parser generation… e.g. originally lex and yacc existed for C. flex and bison were the open source equivalents… I personally like antlr as it supports manny languages as targets. -
Parsing Text search expression
darnocian replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Do you mean lexer & parser generators like lex&yacc/antlr? Antrl3 has some Delphi support, but Antlr4 hasn't been ported yet. FPC has a TP Lex and TP Yacc - the tools are still available, but the documentation seems to have gone offline. I tried that a while back, but there were too much global state for my liking. -
Parsing Text search expression
darnocian replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Lucene is really excellent! I can highly recommend it! I've only used it in Java. I've considered doing a port, but it is a big project to undertake. BTW. There is an older port on sourceforge: https://sourceforge.net/projects/mutis/