Skip to content
← Back

src/syntax/process/printer/signature_renderer.ghul

1
namespace Syntax.Process.Printer is
2
use Collections.LIST;
3
4
use IoC;
5
6
use Semantic.Symbols.SignaturePart;
7
8
// Lays a SignaturePart tree out against a column budget. WRAPPABLE
9
// parts drive the break points: they render flat when the whole thing
10
// fits, otherwise their items break onto per-item indented lines. A
11
// ONE_OF TYPE_REF expands to a wrappable so a long alternative set
12
// breaks one alternative per line. Everything else is verbatim.
13
//
14
// Shared by the hover pretty-printer (Analysis.SIGNATURE_DOC) and the
15
// narrowing-inlay type renderer, so both wrap identically.
16
class SIGNATURE_RENDERER is
17
// Render a part at `width`.
18
render(part: SignaturePart, width: int) -> string static is
19
let b = DOC_BUILDER();
20
_emit(b, part);
21
return DOC_RENDERER(width).render(b.build());
22
si
23
24
// Render a part whose broken continuation lines hang `base_indent`
25
// columns in from the left, so it sits correctly beneath a prefix
26
// of that width (the `► ` sigil of a narrowing inlay) supplied by
27
// the caller. The first line stays flush left; the caller prepends
28
// its prefix to it.
29
render_nested(part: SignaturePart, base_indent: int, width: int) -> string static is
30
let b = DOC_BUILDER();
31
b.begin_nest(base_indent);
32
_emit(b, part);
33
b.end_nest();
34
return DOC_RENDERER(width).render(b.build());
35
si
36
37
_emit(b: DOC_BUILDER, part: SignaturePart) static is
38
if isa SignaturePart.NIL(part) then
39
return;
40
fi
41
42
if let literal: SignaturePart.LITERAL = part then
43
b.text(literal.text);
44
return;
45
fi
46
47
if let name: SignaturePart.NAME = part then
48
b.text(IoC.CONTAINER.instance.name_display.name_for(name.symbol));
49
return;
50
fi
51
52
if let type_ref: SignaturePart.TYPE_REF = part then
53
if isa Semantic.Types.ONE_OF(type_ref.type) then
54
_emit_wrappable(b, _one_of_wrappable(cast Semantic.Types.ONE_OF(type_ref.type)));
55
else
56
b.text("{type_ref.type}");
57
fi
58
return;
59
fi
60
61
if let sequence: SignaturePart.SEQUENCE = part then
62
for item in sequence.parts do
63
_emit(b, item);
64
od
65
return;
66
fi
67
68
if let wrappable: SignaturePart.WRAPPABLE = part then
69
_emit_wrappable(b, wrappable);
70
return;
71
fi
72
73
if let hanging: SignaturePart.HANGING = part then
74
b.hard_line();
75
b.begin_nest(hanging.indent);
76
b.text(hanging.head);
77
b.begin_nest(hanging.head.length);
78
_emit(b, hanging.body);
79
b.end_nest();
80
b.end_nest();
81
return;
82
fi
83
si
84
85
// Expand a one-of type into a wrappable so a long alternative set
86
// breaks one alternative per line, matching how argument and
87
// generic-argument lists wrap. Flat form reproduces the type's own
88
// `{underlying}{a|b|c}` rendering.
89
_one_of_wrappable(one_of: Semantic.Types.ONE_OF) -> SignaturePart.WRAPPABLE static is
90
let items = LIST[SignaturePart]();
91
92
for subtype in one_of.subtypes do
93
items.add(Semantic.Symbols.PARTS.literal(subtype.name));
94
od
95
96
let close = if one_of.is_optional then "}}?" else "}}" fi;
97
98
return SignaturePart.WRAPPABLE(
99
"{one_of.underlying_type.short_description}{{",
100
"|",
101
true,
102
close,
103
items
104
);
105
si
106
107
// WRAPPABLE lays out as: `open` + GROUP( NEST 4( SOFT_LINE +
108
// items joined by `separator` + LINE-or-SOFT_LINE ) ) + SOFT_LINE
109
// + `close`. Group renders flat when the whole thing fits (SOFT_LINE
110
// drops out, LINE becomes a space after `separator` — so args get
111
// "a, b" while `tight` generics get "T,U"); otherwise breaks with
112
// each item on its own 4-space-indented line and the close returning
113
// to the outer indent.
114
_emit_wrappable(b: DOC_BUILDER, w: SignaturePart.WRAPPABLE) static is
115
b.text(w.open);
116
117
if w.items.count == 0 then
118
b.text(w.close);
119
return;
120
fi
121
122
b.begin_group();
123
b.begin_nest(4);
124
b.soft_line();
125
126
let first mut = true;
127
for item in w.items do
128
if !first then
129
b.text(w.separator);
130
if w.tight then
131
b.soft_line();
132
else
133
b.line();
134
fi
135
fi
136
first = false;
137
_emit(b, item);
138
od
139
140
b.end_nest();
141
b.soft_line();
142
b.end_group();
143
b.text(w.close);
144
si
145
si
146
si