Compare commits

..

4 Commits

Author SHA1 Message Date
d8f8d5cc1e docs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2026-07-06 15:32:10 +03:00
5d7bc6ec3d docs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2026-07-06 14:50:01 +03:00
677a639047 ...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2026-07-06 13:11:45 +03:00
26073fb713 added macro else handling + basic testing...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2026-07-06 13:08:25 +03:00
3 changed files with 86 additions and 67 deletions

View File

@ -137,6 +137,8 @@ bot from within pWiki as well as outside.
### now () ### now ()
XXX
``` ```
\@now() \@now()
``` ```
@ -295,8 +297,6 @@ Will render to: `original [ ]`
<source <src>> <source <src>>
... ...
<content/>
...
</source> </source>
``` ```
@ -331,6 +331,53 @@ Arguments:
]]--> ]]-->
### macro (_name_ _src_ _join_ _else_) / else
Define and/or apply a macro.
```
@macro(name=".." src=".." text=".." else="..")
<macro name=".." src="..">
...
<else>
...
</else>
</macro>
```
If `name` is given a _named macro_ is defined. This macro can be later
referenced (used) by name. A named macro can be redefined/overridden.
If `src` is given then expand the macro in applied to (i.e. expanded
in the context of) a page or range of pages and the result is included
in the current page.
This differs frome `@include(..)` in that it does not load the rource
page, it only executes macros in it's context.
Both `name` and `src` are optional.
For a macro to be useful it must have a body (or a `text`/`body` attribute),
either defined as a named macro or in the current macro.
The `<else>` macro (or `else` attribute) is used if the `src` does not match
any pages.
**Example:**
<pwiki-comment>
- [bootstrap pages](/bootstrap/Templates/pages.html)
</pwiki-comment>
<!--[pWiki[
[Templates/pages] / [bootstrap pages](bootstrap/Templates/pages.html):
```
@source(Templates/pages)
```
]]-->
--- ---
@ -363,45 +410,6 @@ macro at the end of the page._
### macro (name src sort) / else ()
Apply macro to source page and include the result.
This is similar to include but does not require a separate page.
Both `name` and `src` are optional.
If `name` is given a _named macro_ is defined. This macro can be later
referenced (used) by name. A named macro can be redefined/overridden.
If `src` is given a macro is applied to a specific page or range of pages
(see: WikiPath).
For a macro to be useful it must have a body (`text`), either defined as
a named macro or in the current macro.
Arguments:
- `name` -- macro name (optional).
- `src` -- path to source page (optional).
- `sort` -- space separated list of methods to use for item sorting
`else` macro is applicable inside `macro`. it is used when the `src` path
of `macro` matches no pages.
**Example:**
<pwiki-comment>
- [bootstrap pages](/bootstrap/Templates/pages.html)
</pwiki-comment>
<!--[pWiki[
[Templates/pages] / [bootstrap pages](bootstrap/Templates/pages.html):
```
@source(Templates/pages)
```
]]-->
<!-- @filter(markdown) --> <!-- @filter(markdown) -->
<!-- vim:set ts=4 sw=4 ft=markdown : --> <!-- vim:set ts=4 sw=4 ft=markdown : -->

View File

@ -1244,6 +1244,8 @@ module.parser = {
function(st){ function(st){
return ((st ?? state).slots ?? {})[name] }, return ((st ?? state).slots ?? {})[name] },
{slot: name}) }) })), {slot: name}) }) })),
// XXX do not like this name...
content: ['slot'],
// //
@ -1546,16 +1548,13 @@ module.parser = {
// that <store>.match(..) can not know about... // that <store>.match(..) can not know about...
// XXX should we do the same for offset??? // XXX should we do the same for offset???
// //
// XXX BUG: strict does not seem to work: // XXX macro variables...
// @macro(src="./resolved-page" else="no" text="yes" strict)
// -> yes
// should be "no"
// ...this seems to effect non-pattern pages...
// XXX should macro:index be 0 or 1 (current) based??? // XXX should macro:index be 0 or 1 (current) based???
// XXX SORT sorting not implemented yet... // XXX sorting...
// XXX check macro recursion... // XXX check macro recursion...
macro: Macro( macro: Macro(
['name', 'src', 'sort', 'text', 'join', 'else', //['name', 'src', 'sort', 'text', 'join', 'else',
['name', 'src', 'join', 'else',
['strict', 'isolated', 'inheritmacros', 'inheritvars']], ['strict', 'isolated', 'inheritmacros', 'inheritvars']],
lazy( lazy(
function(page, args, body, state){ function(page, args, body, state){
@ -1566,6 +1565,7 @@ module.parser = {
// set macro... // set macro...
if(name && body){ if(name && body){
;(state.macros ??= {})[name] = body ;(state.macros ??= {})[name] = body
// get macro... // get macro...
} else if(name){ } else if(name){
body = (state.macros ?? {})[name] } body = (state.macros ?? {})[name] }
@ -1573,10 +1573,18 @@ module.parser = {
// else... // else...
if(args.src if(args.src
&& !page.get(args.src).exists()){ && !page.get(args.src).exists()){
// <else> .. </else>
for(var elem of body){ for(var elem of body){
if(elem.name == 'else'){ if(elem.name == 'else'){
body = elem.body body = elem.body
return that.expand(page.get(args.src), elem.body, state) } } } return that.expand(page.get(args.src), body, state) } }
// args.else...
return args['else'] ?
that.expand(page.get(args.src), args['else'], state)
: [] }
// join macro???
// XXX
return args.src && body ? return args.src && body ?
// run macro... // run macro...
@ -1584,12 +1592,9 @@ module.parser = {
function(page, body, path, text, state){ function(page, body, path, text, state){
return this.expand(page.get(path), body, state) }) return this.expand(page.get(path), body, state) })
: '' }) })), : '' }) })),
// nesting rules... // nesting rules...
'else': ['macro'], 'else': ['macro'],
join: ['macro'], join: ['macro'],
// XXX do not like this name...
content: ['slot', 'include', 'quote', 'macro'],
}, },
} }

View File

@ -53,6 +53,7 @@ module.exports.P = {
get basepath(){ get basepath(){
return path.dirname(this.path ?? '') }, return path.dirname(this.path ?? '') },
// XXX should this return current path if it does not exixt???
get matched(){ get matched(){
var path_action_pattern = /\/path\/?/ var path_action_pattern = /\/path\/?/
var path = this.path.replace(path_action_pattern, '') var path = this.path.replace(path_action_pattern, '')
@ -74,6 +75,7 @@ module.exports.P = {
:p] :p]
: [] }) : [] })
.flat() } .flat() }
// XXX should this return current path if it does not exixt???
return [this.path] }, return [this.path] },
exists: function(path){ exists: function(path){
var that = this var that = this
@ -287,24 +289,12 @@ test.Setups({
'original overloaded', 'original overloaded',
], ],
} }, } },
/* XXX
include_partial_isolated: function(assert){ include_partial_isolated: function(assert){
return { return {
page: P, page: P,
code:[ code:[
'@include(isolated="partial" /isolated) @slot(slot overloaded)', '@include(isolated="partial" /isolated) @slot(slot overloaded)',
'original overloaded', 'original overloaded', ], } },
],
} },
//*/
/*/ XXX content...
include_content: function(assert, path='/page'){
return {
page: P,
code: [
'<include "'+ path +'">[[ <content/> ]]</include>',
'[[ '+ P.get(path).raw +' ]]', ], } },
//*/
// XXX // XXX
// recursion... // recursion...
@ -330,8 +320,21 @@ test.Setups({
// for inline quoting see: test.Modifiers.quote // for inline quoting see: test.Modifiers.quote
// XXX // XXX
// XXX macro... // macro...
// XXX macro: function(assert, path='/page', res){
return {
page: P,
code: [
'<macro src="'+ path +'">[[ @source(./path) ]]</macro>',
res ?? ('[[ '+ path +' ]]'), ], } },
macro_404: function(assert){
return this.macro(assert, '/not_found', '') },
macro_else: function(assert){
return {
page: P,
code: [
'<macro src="/not_found">[[ @source(./path) ]]<else>ERR</else></macro>',
'ERR', ], } },
// XXX var... // XXX var...
// XXX // XXX
@ -339,6 +342,9 @@ test.Setups({
// XXX arg... // XXX arg...
// XXX // XXX
// XXX filter...
// XXX
}) })