Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XSLT-style templating spec #428

Open
zkat opened this issue Dec 11, 2024 · 10 comments
Open

XSLT-style templating spec #428

zkat opened this issue Dec 11, 2024 · 10 comments

Comments

@zkat
Copy link
Member

zkat commented Dec 11, 2024

We already have the equivalent of JSON Schema/XSD in the KDL Schema spec, but we don't have something that would map to XSLT--that is, a templating language for using KDL to transform input KDL into other KDL documents--or even non-kdl documents?

I'm not really sure how big a task this would be. I've never used XSLT in anger but I imagine there's quite a bit to it.

@imsnif
Copy link
Contributor

imsnif commented Dec 11, 2024

With the disclaimer that I have never used XSLTs...

A big pain point we have in Zellij is the repetition created in our layouts. We have pane_templates and tab_templates etc. but they mostly have to live inside the same file.

A long standing TODO I have is to find some sort of mechanism to solve this but I've mostly been putting this off because I don't want to deal with the usual dependency problems. I think these sorts of capabilities (especially if they'll be built in to the existing SDKs) can take away a lot of this work from me.

@zkat
Copy link
Member Author

zkat commented Dec 11, 2024

@imsnif so, as far as I can tell/imagine, KDL templating would be a lot like your pane_template and tab_template, except it would be "official" and be a little more powerful: it would let you, for example, use KQL selectors to do surgical insertions into more complex templates, for example, rather than limiting you to children. And KQL selectors are about as powerful as CSS selectors (modulo some of the more advanced special CSS selectors, but we should probably add those eventually too). They're mostly the same syntax, too.

And yeah, it would be easy enough to put them in separate files that you pass directly to kdl-rs, and it'll apply the templates to a particular document parse for you, transforming things as needed. And, I would hope, giving you informative errors.

For example:

// my-templates.kdl
$:template match=vertical-sandwich { // KQL selector
    pane split_direction=vertical {
        $:select "[pos = above]"
        $:select "[pos != above][pos != below]"
        $:select "[pos = below]"
    }
}

$:template match=cmd {
    pane command="{$:join $:args ,}"
}

$:template match=watch {
    cmd cargo watch -x $:args
}
// layout.kdl

// This isn't magic. Zellij itself would be responsible for
// loading these files and passing them to kdl-rs
@include "./my-templates.kdl"

vertical-sandwich {
    cmd pos=above fancy-line --color red --width 10
    cmd pos=below htop

    pane split_direction=horizontal {
        watch test
        watch check
    }
}

We could, of course, go further. We could have a whole module system of imports/exports where you can distribute "libraries" of templates and everything. You could also get a lot fancier with how you select arguments and values and interpolate them around. Here's a fun one:

$:template match=group {
    $:select "[]" {
        $:apply $:entries
    }
}

group pos=above {
  cmd foo
  cmd bar
  cmd baz
}
// Expands to:
cmd foo pos=above
cmd bar pos=above
cmd baz pos=above

how does that sound so far?

@emceeaich
Copy link

emceeaich commented Dec 11, 2024

A XSLT-like styling language would, by default, recursively process all nodes (which if empty, would yield nothing) .

So the default behavior of an XSLT processor on:

<foo>
  text1
  <bar>text 2</bar>
 <baz/>
</foo>

would be

  text1
  text2

See: https://www.w3.org/TR/1999/REC-xslt-19991116#built-in-rule

The pattern in XSLT is to define templates for the elements you want to transform (via custom output)

So if your code above would take a KML file, like the one in your example:

group pos=above {
  cmd foo
  cmd bar
  cmd baz
}

and produce, by default

foo
bar
baz 

and, assuming that cmd is contextually the same as an element, then you could extend the implementation by allowing the user to specify templates which match nodes: ie group[pos='above'] in an XPath-y syntax, yielding the expected output.

@zkat
Copy link
Member Author

zkat commented Dec 11, 2024

@emceeaich In my examples, above, the definition for cmd was given:

$:template match=cmd {
    pane command="{$:join $:args ,}"
}

so the final expansion would be:

pane command=foo pos=above
pane command=bar pos=above
pane command=baz pos=above

the pos properties are applied by group itself (with the $:apply node)

@emceeaich
Copy link

emceeaich commented Dec 12, 2024

That makes sense, my example was me thinking in the default behavior of XSLT.

The default behavior in XSLT is to recursively process the tree, applying the default template, unless the stylesheet contains templates that match some expression in the document, if it exists.

@zkat
Copy link
Member Author

zkat commented Dec 12, 2024

yeah. I think in my mind, since KDL isn't a markup language that's intended to be a layer on top of plain text, it makes more sense for us to be more explicit about how the data is passed around and applied. And it'll give us nicer errors to boot, imo.

@zkat
Copy link
Member Author

zkat commented Dec 12, 2024

I guess the catch with this is that you couldn't, for example, use this templating system to generate non-KDL templates. In a way, this is more a "function definition" system than a "templating" system.

@emceeaich
Copy link

Yes, setting the scope of what you expect it to do is the right thing. I do hope you find some of the ideas in XSLT useful.

@imsnif
Copy link
Contributor

imsnif commented Dec 13, 2024

Hey @zkat - thanks for the detailed run-down. This indeed looks really cool. I initially thought this might help with the "magic" part you were referring to in the comments (that's the big pain point in this area as I'm not enthusiastic about implementing dependency resolution and all that is involved there).

Would be cool to also have these features though, but one thing at a time :) I still think this is a super useful addition to KDL.

@zkat
Copy link
Member Author

zkat commented Dec 14, 2024

Yeah I think we could provide some helpers around “including” templates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants