rejectedsoftware / diet-ng Goto Github PK
View Code? Open in Web Editor NEWCompile-time indentation based, XML structured template system
License: MIT License
Compile-time indentation based, XML structured template system
License: MIT License
This explodes all the symbols inside to huge amounts as the file contents become part of the symbol (and all nested symbols). Not sure how much this will reduce the resulting footprints, but definitely worth looking at. At least compiler errors and exception traces will look more reasonable.
When caching views with "versions": {"DietUseCache"}
, the cached view path is prefixed verbatim with _cached_
.
This produces paths like views/_cached_subdirectory/index.dt_[..].d
. Such directory is not created during compilation, thus the file is not written and execution will fail unless the directory was created manually.
Cached views should either be placed alongside their source files, or perhaps within their own sub directory for trivial clearing.
Using diet-ng 1.3.0
Sorry if this is a bit brief. Seems like a straightforward bug though. The following fails to build, apparently due to the id beginning with "0":
select#timezone(name="timezone")
option#0000(value="0000") GMT Casablanca, London, Lisbon, Monrovia
option#0060(value="0060") GMT +1:00 Amsterdam, Berlin, Madrid, Paris, Rome
Part of the error message:
Compiling Diet HTML template event/create.dt...
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/defs.d(34,3): Error: "pieces/timezone.dt(15): Expected identifier but got '0'."
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(1369,13): called from here: enforcep(accept_empty || start != idx, delegate string() => "Expected identifier but got '" ~ s[idx] ~ "'.", loc)
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(1051,26): called from here: skipIdent(input, idx, "-_", loc, false)
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(992,15): called from here: parseTag(input, idx, ret, has_nested, loc)
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(950,38): called from here: parseTagLine(input, loc, has_nested)
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(65,76): called from here: parseDietRaw(f)
/usr/include/dmd/phobos/std/algorithm/iteration.d(597,19): called from here: __lambda2(front(this._input))
/usr/include/dmd/phobos/std/array.d(106,9): called from here: __r6554.front()
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/parser.d(65,81): called from here: array(map(files))
../../.dub/packages/diet-ng-1.3.0/diet-ng/source/diet/html.d(93,90): called from here: parseDiet([InputFile("event/create.dt", ......................
Workaround for now is to simply use:
option(value="0000", id="0000") GMT Casablanca, London, Lisbon, Monrovia
I currently have some types that have nullable values that come from a database.
Let's say it's an id that's either null or not.
Nullable!int othertable_id;
If I want to display an editor to this id, I can do this in diet:
input(type='number', value=othertable_id)
The resulting html code shows value="Nullable.null"
, which works OK for this integer, but is a bit messy (and technically be interpreted as text in some browsers).
Because there isn't a type that evaluates to false or some value, it's hard to do this in one statement. For example:
input(type='number', value=(othertable_id.isNull ? false : othtertable_id)) // error
However, a nice addition to diet would be to treat a Nullable
value that is null
as a "false" in terms of erasing the attribute. I don't think this should impact existing code, since you likely have to sanitize something like this with if statements.
I think this can come in handy in a lot of places, since html has many spots where the absence of an attribute means something different than the presence.
Right now usage of dietTraits requires either different template codepaths (if (dice) compile!TraitsA else compile!TraitsB
) or global variables. This is a bit unfortunate since most mechanisms in the traits could work with a runtime value, e.g. htmlOutputStyle.
Would also be nice for stateful (cache) filters.
Might become a bit tricky with the different contexts (nested templates).
This would enable including and extending external template files.
I can't really continue to work on my website anymore because dmd crashes because it's out of memory. I am only using 38 diet files which are 52kb in total file size and my code is also only about 6.2kloc (counted with dscanner -l, so its about 6200 expressions like function calls, definitions, etc). Though I think this only happens on windows because dmd has no 64 bit version here so the maximum memory it can allocate is 2GB before it crashes. It might also be because of the way how dub compiles the dependencies and the project, but I think the biggest factor is the diet compilation. That takes a lot of time and memory.
Maybe somehow add support for caching the compiled diet files or add runtime compilation? Most of my diet files don't use any D code except for reading out of a file anyway. (I am reading out of a file and embed it into the page because otherwise cache is a problem for me)
../.dub/packages/diet-ng-1.4.3/diet-ng/source/diet/input.d(7,8): Deprecation: module diet.traits
member DietTraitsAttribute
is not visible from module input
Code to replicate this issue: https://github.com/KILLERTKK/vibed-bug
Expected result:
Actual result:
As a user and developer, I find that hand-written CSS and JS, both from files and filters, have a relatively heavy load compared to the already condensed HTML that diet produces. I would like to be able to emit minified CSS and JS to the page. Even something to strip indentation and spaces would contribute a lot.
app-skeleton ~master: building configuration "application"...
| Compiling Diet HTML template error.dt...
| error.dt(4,31): Error: template instance `to!string` template `to` is not defined
| ../../../.dub/packages/diet-ng-1.7.1/diet-ng/source/diet/html.d(221,8): Error: template instance `app.showError.exec!(StreamOutputRange!(InterfaceProxy!(OutputStream), 1024LU))` error instantiating
| ../../http/vibe/http/server.d(345,66): instantiated from here: `compileHTMLDietFileString!(StreamOutputRange!(InterfaceProxy!(OutputStream), 1024LU))`
| source/app.d(12,5): instantiated from here: `render!("error.dt", req, error)`
| Compiling Diet HTML template about.dt...
Visible in Vibe.d's CI and Buildkite builds.
For example with selected
or checked
<input... checked>and
<input... chechbox=false>` will both display the checkbox as "checked".
This is a bit unintuitive as it easily leads to errors as e.g. here in the official Vibe.d examples:
https://github.com/rejectedsoftware/vibe.d/blob/master/examples/web/views/settings.dt#L11
Currently the best workaround is to introduce redundancy:
- if (auth.isAdmin)
input#admin(name="admin", type="checkbox", checked)
- else
input#admin(name="admin", type="checkbox")
Once I have a bit of time, I am happy to submit a PR for this. For now I just put this here in the tracker, so that it's not forgotten.
Currently, if a Diet template begins with extends
, the only thing allowed in the remainder of the template is block
declarations. I don't know how hard / likely it is to implement this, but it would be very nice if certain non-block declarations were permitted, such as D functions or Diet mixins, e.g.:
//- standardpage.dt
html
head
title
block title
body
block body
//- accountcreation.dt
extends standardpage
mixin standardbutton(label, url)
form(method="POST", action=#{url})
button #{label}
block title
|Account creation
block body
h1 Account creation
form(action=#{url})
block formBody
nav
block navBody
//- newaccount.dt
extends accountcreation
block formBody
+standardbutton('New account', "/accounts/new")
+standardbutton('Upgrade old account", "/accounts/upgrade")
The point is that I'd like to declare standardbutton
only for templates that extend accountcreation
. Currently, this isn't allowed, so I have to move the declaration up to the top-level standardpage
template. This pollutes the top-level template with declarations that are only used in a subset of derived templates.
Similarly, it would be nice to allow the same thing for D function declarations as well, so that I can make D functions available to certain subhierarchies of inherited templates.
If you don't define DietUseCache, there's no reason to pre-compute the hash of the required source files.
Only root templates get cached. If my root template is very simple and composed of several other templates then caching is ineffective if any of those change.
It would be nice if each dt file is cached instead during each execution of the include statement.
The current design also makes caching less effective because included templates may change while the parent doesn't. Currently it seems the caching feature doesn't monitor file changes. I end up with 2 cached files but I have about 10 dt files. The two cached files(index.dt and error.dt) essentially do nothing but include the other dt files.
I suggest that in the cached file both the filename, creation time stamp, and file size be included in a meta block(comment at the start would work). These are compared during compilation to determine consistency of the cached files. It is done also at the include level.
Ultimately, a real time caching and synchronization design would be nice. Basically add a real time file monitor for changes and then recompile the changes on the file and re include them. This doesn't seem like it would be that difficult but would require some type of "dll" like way to add and remove the template code.
E.g., if you wrapped all d code in a diet template in a function and used function pointers to point to them(each of the templates in a nested design) and called them in the proper sequence then it should be rather simple to add and remove recompiled templates(handling current connections using the old templates might pose security/usability issue though). (the execution tree would correspond/be derived from to the "include tree")
Then just a way to recompile the templates... shouldn't be too hard since dmd would be required to be available.
This technique scales well with more complex web site designs. It allows one to edit without having to recompile everything.
doctype xml
rss(version= '2.0')
channel
title Blah
description A description
link some.url //"rss.dt(6): Singular HTML element 'link' may not have contents."
ttl 5
include items
This is because diet-ng/source/diet/html.d:292
considers link
to be a singular element for HTML (which it is) but errors when incorrectly for RSS where it isn't.
See also #12
Inhibiting white space using the <
and >
modifiers has no effect for pretty printed output. See also https://forum.rejectedsoftware.com/groups/rejectedsoftware.vibed/thread/42388/
(I think) diet-ng generates "invalid" HTML for attributes equals to true:
https://github.com/rejectedsoftware/diet-ng/blob/master/source/diet/html.d#L183
See:
https://stackoverflow.com/questions/6926442/is-an-xml-attribute-without-a-value-valid
I have code like this that fails to compile:
- if(1) // always do this
someTag
I believe the reason is because the opening curly brace is appended to the line, instead of put on its own line. This means the resulting code looks like this:
if(1) // always do this {
...
}
So essentially, the opening curly brace is missing. The resulting error is super-puzzling: Error: found } instead of statement
.
I'm not sure which is the best option, but this can be fixed trivially by appending a newline before the curly brace. Workaround is to use open/close comment style:
- if(1) /* this works */
someTag
An import or extend treats the file as if it were all the same (Right?) file in terms of generating the AST from the parsed file. In essence, including a file inside a diet template is like you included it in that spot.
However, the engine doesn't really need to reparse these files does it? In fact, it would be nice if it doesn't even need to regenerate the code. I'm imagining that each code might have its own "template" that can be called directly from an including template, just like D modules call other D modules. The savings might be huge. In my project, every single diet template is an extension of a layout template. Imagine if that layout template doesn't even need to be parsed and transpiled every single time it's used.
I'm getting very close to the limit of where my project can be built, and I'm trying to imagine ways I can save on compile time memory usage. This might be one of them. I don't have a concrete plan for how this can happen, but it definitely would be useful to explore these areas.
I've noticed that the diet-ng doesn't output the newline characters after tags.
doctype html
html
body
div something
diet-ng (vibe 0.7.30-beta.1) output:
<!DOCTYPE html><html><body><div>something</div></body></html>
classic diet (vibe 0.7.29) output:
<!DOCTYPE html>
<html>
<body>
<div>something</div>
</body>
</html>
I have no idea if this is actually already supported because the docs are very incomplete, but I'm having a frustrating time trying to figure out how to generate a <meter>
tag whose list of attributes is generated by embedded D code. (It's not just the values of the attributes that are unknown, but whether or not certain attributes even appear in the tag in the first place. The former is easy; the latter I'm having a really hard time with.) Is this even remotely possible, or do I have to generate the tag from D code and inject it into the output?
I found something about &attributes
online in the Jade Template spec, but it seems Diet doesn't support this syntax. If such a thing is not yet supported by Diet, it would be very nice if this feature could be added. Perhaps something along the lines of:
html
body
- auto attrs = [ "min": "0", "max": "100" ];
- if (hasOptimal) attrs["optimal"] = optimalValue;
meter(value=#{value})&attributes(attrs)
Or if this feature already exists in some form, please at least mention it in the docs.
The following code returns this HTML:
- foreach (i; 0..3)
span #{i}
span A
<span>0</span>
<span>1</span>
<span>2</span><span>A</span>
The <span>
tag uses the inline display style, inline tags create a space between other tags if there's a new line after them.
This creates two issues:
There should some syntax for loops that would not create new lines and the bug where for loops don't create new lines should be fixed
html
body
- string val;
- string s = "";
input(value=s) // <-- if i remove the value=s or rename string val up there to something else it compiles
a.dt(5,3): Error: variable val is shadowing variable diet.html.compileHTMLDietFileString!("a.dt", contents, DefaultFilters).exec!(StreamOutputRange!(OutputStream)).exec.val
../../home/webfreak/.dub/packages/diet-ng-1.4.0/diet-ng/source/diet/html.d(116,7): Error: template instance diet.html.compileHTMLDietFileString!("a.dt", contents, DefaultFilters).exec!(StreamOutputRange!(OutputStream)) error instantiating
../../home/webfreak/.dub/packages/vibe-d-0.8.0/vibe-d/http/vibe/http/server.d(243,63): instantiated from here: compileHTMLDietFileString!(StreamOutputRange!(OutputStream))
source/app.d(16,5): instantiated from here: render!"a.dt"
html
body
- struct S { string s; string toString() const { return "s: \"" ~ s ~ '"'; } }
- S str;
a(a=str)
a(a=str.toString)
a(a="" ~ str.toString)
<html>
<body>
<a a="s: """></a><a a="s: """></a><a a="s: """></a>
</body>
</html>
Only the last attribute is correct!
For example this breaks using custom data types like JSON or YAML in attributes
Hello,
I've been diving into Kai Nacke's D Web Development and ran into an error in the filters example in chapter 2. In the merged pull request #1835, the registerDietTextFilter
function was removed along with old diet. Does diet-ng have this functionality or plan to have it?
Best regards,
Jason
As it can be seen on the vibe.d website's about page it's split like:
p With vibe.d we are trying to bring the highest performance possible together with a
| programming interface that is as clean as possible. At the same time the choice of
But still it's written as "aprogramming" instead of "a programming"
See the screenshot for representation in the browser.
I have the following file setup, using diet-ng with vibe.d (WebInterface)(the original diet implementation also has this issue):
layout.dt
provides my page structure.
leftnav.dt
is included by layout.dt
for navigation.
And my pages, which extend layout.dt
and attempt to override a block in leftnav.dt
. I would expect that since the block is included by layout.dt
any file that extends layout.dt
would be able to override it, but my attempts to do so are ignored - the overriding block doesn't make it into the html at all.
If I actually copy the contents of leftnav.dt
into layout.dt
everything works as expected. According to the diet documentation include
is effectively a copy-paste, but it isn't quite working that way.
I could also work around it by passing data to the render function (as adding "active" to the li class is all I really care about here), but would prefer not to do that.
//- layout.dt
doctype html
html(lang="en")
head
block head
title Diet Include Test
body
div
//- I'll want to modify blocks in leftnav in child templates.
include leftnav
div.main
block content
p Content goes here.
//- leftnav.dt
ul
//- These blocks should (but don't) let me adjust each individual item in other templates.
block navIndex
li
a(href="/") Home
block navPage2
li
a(href="/pagetwo") Not Home
//- index.dt
extends layout
//- I expect this block to override the block in layout.dt via the include, but is ignored.
block navIndex
li
a(class="active", href="/") Home Override
block content
h1 Hello!
p "Home" should say "Home Override".
//- pagetwo.dt is much the same as index
extends layout
block head
title Diet Test - Page Two
block navPage2
li
a(class="active", href="/pagetwo") Page Two
block content
h1 The second page.
p "Not Home" should say "Page Two".
Out of bounds error here:
Line 705 in 36cf576
Trigged by forgetting to finish a line! for example:
a(href="../",onclick
Easy fix, just check in the outer if statement that i
is still less than str.length
.
I'll do a PR when I get a chance.
htmlgenerator
has vibe.d
as a dependency in dub.sdl
, but does not import anything from it.
It seems that it can be safely removed.
It seems like compileHTMLDietFile does not support :css & :javascript
Log
▶ dub
object.Exception@../../../../.dub/packages/diet-ng-1.6.0/diet-ng/source/diet/traits.d(172): Unknown filter: javascript
----------------
source/app.d:19 pure @safe void diet.traits.filter!(strip.translateDiet().iterations).filter(const(char[]), immutable(char)[], void delegate(const(char[])) @safe) [0x1001b04ce]
source/app.d:19 @safe void diet.html.compileHTMLDietFileString!("error.dt", diet.html.compileHTMLDietFile!("error.dt", strip.translateDiet().iterations).contents, strip.translateDiet().iterations).exec!(std.stdio.File.LockingTextWriter).exec(ref std.stdio.File.LockingTextWriter) [0x1001b0395]
source/app.d:19 @safe void diet.html.compileHTMLDietFileString!("error.dt", diet.html.compileHTMLDietFile!("error.dt", strip.translateDiet().iterations).contents, strip.translateDiet().iterations).compileHTMLDietFileString!(std.stdio.File.LockingTextWriter).compileHTMLDietFileString(ref std.stdio.File.LockingTextWriter) [0x1001b030c]
source/app.d:19 void strip.translateDiet() [0x1001a7116]
source/app.d:55 _Dmain [0x1001799d8]
Program exited with code 1
Text embedded with |
inside the block of an embedded if statement is treated as additional embedded code.
- int foo = 0;
- if (1 == 1)
| foo = 5; /* this is executed as code */
div foo is #{foo}
With 064187e (current master) outputs:
foo is 5
The |
appears to be appending it's contents verbatim to the parent node. This doesn't make sense where the parent node is embedded code as prefixing with -
is already expected.
in the old vibe.d parser this still worked, now it doesnt:
p.class#id
OS: Windows 7
diet-ng 1.1.0
Using a tag in a template like so:
script(src='Leaflet/leaflet.js')
is generating html like:
<script src="Leaflet/leaflet.js"/>
instead of
<script src="./Leaflet/leaflet.js"> </script>
This is apparently a "known" issue.
Also, the spec for Jade states that using the script tag should generate opening and closing tags.
Is there a way to force the generation of the closing tag?
There should be a mode which doesn't throw exceptions on syntax errors but instead adds error nodes to the tree and attempts to continue parsing. This is useful for external tools and for showing more than one error per file.
I know that this document is incomplete. Hence, this is just an issue to track progress, s.t. it's not forgotten.
The idea is that maybe the spec is generated from a D file with many unittests.
This issue to share my experience of compileHTMLDietFileString() usage for diet templates embedded to code. There are two problems: file name required and incorrect line number when error is found. To fix it I created inlineDiet.d:
module inlineDiet;
struct InlineDiet
{
string file;
int line;
string tpl;
}
template diet(string tpl, string file=__FILE__, int line=__LINE__)
{
enum diet = InlineDiet(file, line, tpl);
}
template compileInline(InlineDiet tpl, ARGS...)
{
import std.array : replicate;
import diet.html;
enum string file = tpl.file~"t";
enum string eTpl = ("\n".replicate(tpl.line-1)~tpl.tpl);
alias compileInline = compileHTMLDietFileString!(file, eTpl, ARGS);
}
I add "t" to the end of current file so if template included from some component.d
it will be visible to diet-ng library as component.dt
file. To fix line number template is prepended by required amount of new line symbols (requirement for correct work: opening quote of template string must be on the same line as diet() template call). So now I can create simple 1-file components like this:
class ManagerMainPage : BasicManagerPage
{
// ...
// controller
override void doContent()
{
client = engine.clients[registrator.getLoggedUser().clientId];
auto page = this;
auto stats = getStats();
output.compileInline!(tpl, page, stats);
}
// view
enum tpl = diet!`
extends manager/page
block content
h2 Manager page
table
tr
td Organization:
td #{page.client.name}
tr
td Users:
td #{stats["users"]}
tr
td Sites:
td #{stats["sites"]}
tr
td Devices:
td #{stats["devices"]}
`;
}
I think it will be useful to add something like inlineDiet.d to library (or modify compileHTMLDietFileString to fix these issues) because every who will use compileHTMLDietFileString() will face same problems.
Live mode outputs strings surrounding all statements. I have some hackish things to fix issues with if statements and return statements.
But two other statements that cannot have output of strings are the break
and continue
statements. If an extra HTML output is done, then the compiler flags that output as an unreachable statement, even though no HTML will ever be inserted there.
Probably should extend the hack to include these statements.
Simple test
// testLayout.dt
doctype 5
html
head
title Test Title
body
block body
link(rel="stylesheet", type="text/css", href="styles/test.css")
h1 Second
// testView.dt
extends testLayout.dt
prepend body
h1 First
append body
h1 Third
I'd expect the "First" heading, then the css link, then "Second" heading, then "Third".
But rather confusingly, what's generated is:
<!DOCTYPE html>
<html>
<head>
<title>Test Title</title>
</head>
<body>
<link rel="stylesheet" type="text/css" href="styles/test.css"/>
<h1>Second</h1>
<h1>First</h1>
<h1>Third</h1>
</body>
</html>
Something seems broken with the appending/prepending.
I had a read of the code, but I don't know it well enough to understand what's going on here.
Reference:
https://pugjs.org/language/inheritance.html#block-append-prepend
I am working on getting something nice together to work with my presentation at dconf, and one of the things I plan to bring up is the slow cycle of modifying a diet template.
In general, any change to a diet template seems to build the entire project again. Which is pretty slow. One of the things PHP and other interpreted languages enjoy is a quick cycle of editing and testing. Obviously, the compiled portion of diet templates (string interpolations and D escapes) needs a recompile, but just changing layout or changing a class should be doable without requiring a recompile
What I'm thinking is that diet's render function could be put in "development" mode, where during compilation, it generates an AA with string lookups to delegates based on the actual D code, and leave everything else to runtime. Then during runtime, the render function actually reads the diet file, and converts it to html at runtime, replacing any D code with the delegate calls (if any delegate call has no equivalent lookup, then it's an error).
For example:
html
body
h3 Hi, #{name} how are you today?
a(href="good") Good
a(href="notgood") Not so good.
Then when you run, if you change it like this, it still works:
html
head
title Simple question
body
h3 Howdy, #{name} what's cookin?
a(href="good") Doin great!
a(href="notgood") Having a bit of a rough patch.
Basically, the #{name}
part will invoke a pre-compiled delegate, but the other parts will be translated at runtime. You can still do this with if/loops, as long as you pass a mechanism to get control back to the interpreter for given branches. e.g.:
html
head
- if (optionA)
title Welcome to this application!
- else
title Welcome to the page #{pagename}
Essentially, the if/else statement can be a delegate which takes 2 delegates to run if the if statement is true or false.
I don't know how possible this is, as I'm not sure how the diet compiler works, but it seems really doable I think.
Obviously in development mode, things are going to be slower. But that's OK because you aren't processing high-volume traffic. It will be quick enough, and quicker than recompiling. Then when you are satisfied with the way things look, you rebuild with development mode off, and it goes back to the fully compiled mode.
Running ./diet-ng-test-library
core.exception.AssertError@source/diet/parser.d(539): unittest failure
----------------
??:? _d_unittestp [0x540c9d]
source/diet/parser.d:540 void diet.parser.__unittest_L518_C1() [0x51ba14]
??:? void diet.parser.__modtest() [0x5395ad]
??:? int core.runtime.runModuleUnitTests().__foreachbody2(object.ModuleInfo*) [0x55e34f]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)).__lambda2(immutable(object.ModuleInfo*)) [0x53fefe]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))).__foreachbody2(ref rt.sections_elf_shared.DSO) [0x547889]
??:? int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref rt.sections_elf_shared.DSO)) [0x547a1c]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))) [0x547815]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)) [0x53fed5]
??:? runModuleUnitTests [0x55e125]
https://ci.dlang.io/blue/organizations/jenkins/dlang-org%2Fphobos/detail/PR-6253/9/pipeline
For a variable of type (string, string)[]
or string[string]
it should be possible to apply all items in the array as attributes for any tag such that the keys (or first items in tuples) are the attribute names and the values (or second items in tuples) are the attribute values.
So for a given variable like this
string[string] myAttrs = ["src": "image.png", "alt": "cool image", "title": "this is a cool image"];
it would be possible to splat it onto some kind of element, let's say a <div>
element, for example with a syntax that could look like this:
div(*myAttrs, extra="attributes here")
resulting in this HTML: (attribute order not guaranteed with AA but should be guaranteed with list of tuples)
<div src="image.png" alt="cool image" title="this is a cool image" extra="attributes here">
This should be generic to work with any input ranges of key/value pairs or 2 item tuples as well as any value types. For attributes that are specified multiple times, or implicitly from other syntax, the same rules as typing out all the attributes now should apply. (e.g. combining .dot
style class names with class attributes)
dlang/phobos#7761 is being held back in buildkite by the released version's dependence on an outdated vibe.
Looking at the way diet parses and processes files, I firmly believe that the cached version is the better version. First off, it's going to use WAY less CTFE, because it simply imports the result. This means both less time and less memory, something which my vibe.d app is straining against currently.
But there is a large problem -- the current model must compile ONCE without any caching for this to work. Essentially, it compiles the file at compile-time, then at runtime, writes the cached result into a specially named file, and then you have to compile again to get a benefit. But this is really a build step, made very awkward by requiring a run of the application once. Not only that, but if you are running against a memory limit, you can't get the faster/less memory build, because you need to build once without it.
With the changes I have in #70, the facilities would be available to do this at runtime BEFORE compilation. In fact, I created a very small utility which does just this. I'm shocked at how quickly this runs and it works perfectly (parses and caches all my 31 diet files in 0.25 seconds). It cuts my compile time from about 38 seconds down to 11 seconds WITHOUT having to run 38 seconds once. If I'm reading my max memory stat correctly (though I'm not 100% sure how /usr/bin/time works), it's using 1GB less memory as well (about 30%). Finally, if we move to this type of compilation mode, there is no need to infiltrate the final executable with build steps.
The code is simple, see here: https://github.com/schveiguy/dietpc. All that remains is to try and make it insertable as a dub step.
I can't do:
div.#{isDone == true ? "active": "inactive";}
div.#{isDone == true ? "active": "inactive";}.selected
div##{isDone == true ? "active": "inactive";}.selected
Will the ## even work?
Or am i doing is wrong?
- auto myClasses = ["foo", "bar"];
div(class="#{myClasses}")
should yield:
<div class="foo bar" />
See also: dlang/ddox#171
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.