Now, I believe your question is totally ["open" and "opinion based"] on one side, and ["why is this code not working" without showing the code] on the other side.. but I want to try pointing some problem with the idea of "improvement" you have now.
Q2: How can I unify the code that generate the "templated blocks" both for "Generation" and "Update"
I'm strongly convinced that you should not, at least not now. Here's why:
- 'generate' and 'update' are happening in different directions; first is t4template->content, second is content->t4template
- those two directions form different functionality
- at least one of these directions requires complex logic not present in the other one
- 'generate' is based on T4 Engine, while 'update' will probably not be able to use it at all
- ..and probably many other reasons, but that's enough
Q3: Later on, How can i make it work on Non-Code files too
T4 Engine has no idea that what you generate now is a C++ file. T4 works only on a layer of "text files". If the process you have works now, you should be able to "generate" any text file already right now. The "update" part is a bit more tricky, because it depends on how you implemented it. If you assumed/used any correlaction to C++ syntax, you've got a problem. (guess why T4 Templates are called 'text templating engine', agnostic to the actual generated code language) If you kept it clean and worked as if on a free-form text file, then you're already safe to work on, well, free-form text files.
Q1: How can I recognize location/blocks in a generated file without "littering" the file with "comment"/"unimportant" text?
Well, basically, you can't and/or shouldn't. Consider a smart idea of keeping a hidden database that remembers text locations for every file. For every comment that you would put in the file, you put a row in the database, saying file: BAR\FOO.CPP | FROM: line 120 char 1 | TO: line 131 char 15 | XXX: yyy | ZZZ: aaa
. That's almost no difference to having comments in the file, all information is preserved, and the file is clean now, right?
Nope. And that's because you want to detect what has changed. Let's take a highly contrived example, here's the generated file with such invisible markers that are managed by database. Each @
character denotes a marker, be it start/stop/metainfo nevermind:
class FooBar : public @BaseClass@
{
public:
@void Blargh(Whizz& output);@
@int GetAge() const;@
private:
int @shoeSize@;
@
};
Those @
are of course invisible, it's just an information held elsewhere, the user sees a clean file. Now, he edits it to this:
class FooBar : public BaseClass
{
public:
template<T>
void Yeeek(T& output);
int GetAge() const;
private:
int shoeSize;
};
Please note how "template" was added and method renamed to "Yeeek". There were some markers out there, I didn't show them intentionally, just look on the "template<>" line. What if it was accidentally placed a line or a byte too far or too early, so one marker too many was skipped or included? Now the detector and updater may accidentally skip "template<>", and it will be totally happy to just rename the method. This is not a problem with the detector or updater. This is a problem of markers not being visible, so the user was not able to see where should he place his edit.
That's probably the most important point. But, let's see something more algorithmic/technical. Let's try an even simpler edit. User edits the file to:
class FooBarize : publ@ic BaseCl@ass
{
int goat;
@ string cheese; @
p@ublic: @
void Blargh(Whizz& output);
i@nt GetA@ge() const;
p@rivate:
int shoeSize;
};
I overlaid those invisible markes from 'the external database of markers' back onto this edited file. What has happened? Simple. User has added two lines more in an odd place (he doesnt see the markes, right?), and the database remembers old places (i.e. 'line:char', but could be 'byte', or really whatever). Now of course, database may (and should!) also remember old shape of the file, so it can see that i.e. the first @
was after ":public" and the process can try to map it onto the new file.. but then, you already have a highly complex problem, and this edit was trivial. Of course, you can require the user to enter some information on how to update the markers.. but hey, he don't see them, how can he do it? And since we wanted to hide the markers from him, we probably don't want to ask him about updating them as well..
How about editing the file to:
struct FooBar : One,Two,Three,Four
{
void OhNoes();
};
I didn't care to overlay the markers, because it's utter nonsense. Now, how to map it back to the template? Is OhNoes
mappable to GetAge
(const
removed) or to Blargh
(parameters removed)? How the template base class should be updated? Which one of the new bases is the true base? Or maybe all of them? Neither you nor I can decide it, even with our combined human intelligence, not mentioning an automated process.
Of course, you can leave it as a corner case, you can emit an error to the user and inform them that their edit went to far and is unanalyzable and so on. But The complexity of reverse-mapping a change back to the model text is still there.
What I want to show you by these contrived examples is, that if you want to detect and map changes back to the original template, you should keep these markers in the generated content. Having these markers in the code allows you quickly and reliably detect:
- which sections changed? (-> content between markers has changed)
- which sections were offsetted by edits? (->markers are now at different position than before)
- were any sections deleted? (-> both markers and content between removed)
- (..)
It also allows the user to see which parts are special so he can place his edits in a reasonable way, which allows you to ignore and not support more corner cases than in the "invisible markers" case.
Finally, let's take a read-world example which you already know. T4 Template. All those ugly <%!@!#^$^!%@
littering your precious template text. Couldn't they be removed? Couldn't these be kept in a separate file that describes the transformation? Or at least at the beginning or end of the file? Yes, it could. But it would make the editing a real pain - we're back to 'invisible markers' problem: each your edit to the content may require you to manually update locations of some invisible markers.
Keep the markers in the generated content.
Keep your users aware of the generation and detection and special regions.
If it's too complex for them, change the users to a more technical group, or train your userbase to be more technical. Or prevent them from editing the file. Given them some partial access so they can edit a part of the file, as an excerpt, not as a whole file. Limit their editing power to absolute minimum. Maybe it will allow you to limit the number of visible markers, maybe even down to zero, maybe at the cost of splitting and downsizing editable fragments.