Skip to content
New issue

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

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

Already on GitHub? # to your account

Add internal links to XenAPI reference #6315

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/assets/css/xenapi.css
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,7 @@ th { text-align: left;
margin: 0;
vertical-align: middle;
}

div[id$='_details'] {
cursor: default;
}
146 changes: 146 additions & 0 deletions doc/assets/js/parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@

class Type {};

class Builtin extends Type {
constructor(name) {
super();
this.name = name;
}

static ofString(s) {
const concrete = ['string', 'bool', 'int', 'float', 'void', 'datetime'];
if (!concrete.includes(s))
return null;

return new Builtin(s);
}
};

class Enum extends Type {
constructor(name) {
super();
this.name = name;
}
};

class Ctor extends Type {
constructor(params, name) {
super();
this.params = params;
this.name = name;
}
};

function lex(str) {
if (str.indexOf('$') >= 0)
throw new Error('Not allowed to contain $');

let ts = str.replaceAll('(', ' ( ');
ts = ts.replaceAll(')', ' ) ');
ts = ts.split(' ');
ts = ts.filter(x => x !== '');
ts.push('$');
return ts;
}

class Lexer {
constructor(tokens) {
this.tokens = tokens;
this.pos = 0;
}

shift() {
if (this.pos >= this.tokens.length - 1)
return '$';

return this.tokens[this.pos++];
}

peek() {
const prev = this.pos;
let t = this.shift();
this.pos = prev;
return t;
}

expect(ts) {
if (!Array.isArray(ts))
ts = [ts];

let l = this.shift();
for (const t of ts)
if (l == t) return;

throw new Error(`Expected ${t}, got ${l}`);
}
};

function lbp(t) {
switch (t) {
case '(':
case ')':
case '->':
case '\u2192':
return 0;
case '$':
return -1;
}

return 1;
}

function nud(l, t) {
switch (t) {
case 'enum':
return new Enum(l.shift());

case '(':
let left = parseType(l, 0);
l.expect(['->', '\u2192']);
let right = parseType(l, 0);
l.expect(')');
l.expect('map');
return new Ctor([left, right], 'map');
}

let bty = Builtin.ofString(t);
if (bty != null)
return bty;

const fmt = /^[a-zA-Z_]+$/;
if (fmt.test(t))
return new Ctor([], t);

throw new Error(`No null denotation for ${t}`);
}

function led(l, left, t) {
const known = ['set', 'ref', 'option', 'record'];
if (!known.includes(t))
throw new Error(`Invalid type constructor: ${t}`);

return new Ctor([left], t);
}

function parseType(l, rbp) {
let left = nud(l, l.shift());

while (lbp(l.peek()) > rbp)
left = led(l, left, l.shift());

return left;
}

function parseSingleType(input) {
try {
let lexer = new Lexer(lex(input));
let ty = parseType(lexer, 0);
if (lexer.peek() != '$')
throw new Error('Did not consume entire input');
return ty;
} catch (e) {
}

return null;
}

69 changes: 64 additions & 5 deletions doc/layouts/partials/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,39 @@
{{ $c := .Page.Params.class }}
{{ with index (where $.Site.Data.xenapi "name" $c) 0 }}

<script>

function render(t) {
if (t instanceof Builtin)
return `<span class="ty builtin ${t.name}">${t.name}</span>`;

if (t instanceof Enum)
return `<span class="ty enum"><span class="kw-enum">enum</span> <span class="enum name"><a href="#" onClick="locateEnum('${t.name}')">${t.name}</a></span></span>`;

if (t instanceof Ctor) {
if (t.name == 'map') {
let l = render(t.params[0]);
let r = render(t.params[1]);
return `<span class="ty ctor">(${l} \u2192 ${r}) <span class="ctor name ${t.name}">${t.name}</span></span>`;
}

if (t.params.length == 0)
return `<a href="../${t.name.toLowerCase()}" onClick="event.stopPropagation();">${t.name}</a>`;

let unary = render(t.params[0]);
return `<span class="ty ctor">${unary} <span class="ctor name ${t.name}">${t.name}</span></span>`;
}
}

function renderType(input) {
let ty = parseSingleType(input);
if (ty == null)
return input;

return render(ty);
}
</script>

<script type="text/javascript">
function showhide(obj) {
if (obj.style.display == 'none')
Expand All @@ -16,6 +49,21 @@
obj.style.display = 'none';
}

function toggle(e) {
showhide(e.nextElementSibling);
}

function locateEnum(name) {
event.stopPropagation();
let target = document.querySelector(`#enum_${name}`);
document.querySelector('#enums').scrollIntoView();
let detail = target.querySelector(`#enum_${name}_details`);
detail.style.display = 'inherit';
target.style.transition = '0.1s';
target.style.textShadow = '0px 4px 5px rgba(0, 0, 0, 0.5)';
setTimeout(() => { target.style.textShadow = 'none'; }, 300);
}

function toggle_implicit(button) {
var elements = document.querySelectorAll(".implicit");
for (element of elements)
Expand All @@ -29,7 +77,9 @@
</script>

{{ $style := resources.Get "css/xenapi.css" }}
{{ $parser := resources.Get "js/parse.js" }}
<link rel="stylesheet" href="{{ $style.Permalink }}">
<script src="{{ $parser.Permalink }}"></script>

{{ with .lifecycle }}
<div class="lifecycle">
Expand Down Expand Up @@ -64,11 +114,11 @@ <h2 class="title" onclick="showhide(document.getElementById('class_{{$c}}_detail
</div>

{{ if gt (len .enums) 0 }}
<h3>Enums</h3>
<h3 id="enums">Enums</h3>

{{ range $i, $x := .enums }}
<div id="enum_{{$x.name}}" class="{{ if modBool $i 2 }}field{{ else }}field2{{ end }}" >
<div class="field-name" onclick="showhide(document.getElementById('enum_{{$x.name}}_details'))">{{ $x.name }}</div>
<div class="field-name" onclick="toggle(this)">{{ $x.name }}</div>
<div id="enum_{{$x.name}}_details" style="display: none">

<table class="field-table">
Expand Down Expand Up @@ -146,16 +196,20 @@ <h3 style="padding-right: 0">
{{ end }}
</div>
{{ end }}
<div onclick="showhide(document.getElementById('{{$x.name}}_details'))">
<div onclick="toggle(this)">
<span class="inline-type">{{replace (index $x.result 0) "->" "→"}}</span>
<span class="field-name">{{$x.name}}</span>
{{ $ptypes := slice }}
{{ range $x.params }}
{{ $ptypes = $ptypes | append (replace .type "->" "→") }}
{{ end }}
<span class="inline-params">({{ delimit $ptypes ", " }})</span>
{{ $wrappedTypes := slice }}
{{ range $ptypes }}
{{ $wrappedTypes = $wrappedTypes | append (safeHTML (printf "<span class=\"inline-type\" style=\"margin: 0;\">%s</span>" .)) }}
{{ end }}
<span class="inline-params">({{ delimit $wrappedTypes ", " | safeHTML }})</span>
</div>
<div id="{{$x.name}}_details" style="display: none">
<div id="{{$x.name}}_details" class="details" style="display: none">
<div class="field-description">
{{ $x.description | htmlEscape }}
</div>
Expand Down Expand Up @@ -237,3 +291,8 @@ <h3>Changes</h3>
{{- /* Finished generating the release page content */}}

{{ end }}

<script>
for (let x of document.querySelectorAll('.inline-type'))
x.innerHTML = renderType(x.innerHTML);
</script>
Loading