-
Notifications
You must be signed in to change notification settings - Fork 10
/
pretty_printer.pl
315 lines (246 loc) · 18.3 KB
/
pretty_printer.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
% First saved: 12/03/2011
% Last saved: 12/03/2011
%
% State:
% matrices.pl required!
% Doing:
%
% Todo
%
% NOTES:
%%%% Notes %%%%
%%%%%%%%%%%%%%%
/*
Pretty-printer for prolog. Written for LPA Win-Prolog 4.900
but should probably work with most Edinburgh-compatible
Prologs with a minimum amount of fuss.
Data to be output should be given in the form of a table,
ie, a nested list, each of its elements an n-element list.
The top-goal is not definitve and can be redefined to suit your
needs (for example, you may want to add a separate grid/3 call
to surround the title with a different border, or add a
print_rows/4 call to print a subtitle etc.
*/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Swi Compatibility %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- set_prolog_flag(backquoted_string,true).
% Swi LPA backtic string compatibility.
:- style_check(-singleton).
% Stop Swi warning on singleton vars.
:- style_check(-discontiguous).
% Stop Swi warning on discontiguous clauses.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Pretty-printer %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%pp_style/4 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* pp_style(+Style, +Header, +Body, +Footer). */
% "Style" being the characters to output as borders
pp_style('Simple',[+,-,+,+],[+,'|',+],[+,-,+,+]).
pp_style('Box drawings', [╔,═,╦,╗],[║,║,║],[╚,═,╩,╝]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%pretty_print/6 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* pretty_print(+Title, +Data, +Margin, +Header, +Body, +Footer) */
% Top-level goal for the printer
% Margin: tabs from the start of the screen
% Padding: space to the end of a column (from the end of the datum)
pretty_print(Title, Data, Margin, Header, Body, Footer):-
append([Title], Data, Full),
column_lengths(Full, Column_lengths),
% ^ The full length of a column takes the title into account!
map(pad, 3, Column_lengths, Padded_lengths),
% ^ grid col. lengths take separators into account
tab(Margin),
grid(Header, Padded_lengths, Header_row),
write(Header_row),nl,
% ^ Header
print_rows([Title], Margin, Column_lengths, Body),
tab(Margin),
% ^ Title
write(Header_row),nl,
print_rows(Data, Margin, Column_lengths, Body),
% ^ Data
tab(Margin),
grid(Footer, Padded_lengths, Footer_row),
write(Footer_row),nl.
% ^ Footer
% | ?- pretty_print([[`Name`, `Type`, `Mana_cost`]], [[abc,12,1234],[abcd,3,12345]],
% 5, [+,-,+,+], ['|','|','|'], [+,-,-,+]).
%%%%%%%%%%%%%%pad/3 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%
/* pad(+Number, +Addend, +Result) */
% Adds a number to another and returns the result. Duh.
pad(A, Pad, Incr):-
Incr is A + Pad.
%%%%%%%%%%%%%%map/4 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%
/* map(+Functor, Arg, List_1, List_2) */
% Maps the elements of a list to a predicate's arguments.
% This version takes three arguments.
% Based on an example from the Win-LPA documentation
%%%%%%%%%%%%%%map/4 (0) 12/03/11
map(_Pred, _A, [], []).
%%%%%%%%%%%%%%map/4 (1) 12/03/11
map(Pred, A, [X|Y], [X1|Y1]) :-
% Pred(A, X, X1), %Swi, 18/06/11
Map =.. [Pred, A, X, X1],
% ^ constructs the term Pred(A, X, X1)
Map,
map(Pred, A, Y, Y1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%column_lengths/2 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* column_lengths(+Data, -Column_lengths) */
% Measures the length of the elements of in each "column" of a "table"
% (ie, list of n-element lists).
% To feed into grid/5 (Lengths = Tabs)
column_lengths(Data, Col_lengths):-
type(Data, 6), % data is a list
columns(Data, Columns),
max_lengths(Columns, [], Col_lengths).
% each Col_lengths element must correspond to a Columns element,
% eg: [[abc,a,bc], [ab,a,b], [abcd,ab,abc]], [3,2,4]
%%%%%%%%%%%%%%max_lengths/3 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%
/* max_lengths(+Columns, [], -Max) */
% Finds the longest element in a column-list.
%%%%%%%%%%%%%%max_lengths/3 (0) 12/03/11
max_lengths([], Max, Max).
%%%%%%%%%%%%%%max_lengths/3 (1) 12/03/11
max_lengths([Column | Rest], Temp, Max):-
findall(Length,
(member(Element, Column),
len(Element, Length)),
Lengths),
sort(Lengths, Sorted),
reverse(Sorted, [Longest | _Rest]),
append(Temp, [Longest], New_temp),
max_lengths(Rest, New_temp, Max).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%print_rows/4 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* print_rows(+Table, +Margin, +Column_lengths, +Formatting) */
% Prints rows of data from a table-list. Each row is an n-element
% list, member of the table-list.
%%%% Notes %%%%
%%%%%%%%%%%%%%%
/*
Table:
data to print; a square matrix, in list form, ie a
list of n-element lists, eg:
[[abc, defg, h] [1, 2345, 67] [Monday, Tuesday, Wednesday]]
Any deviation from the "square table" pattern will cause
this to fail disracefully and it has a tendency to go infinite,
so don't push it. Particularly, key-value pairs are not
supported currently and large, complex data in tuples is
not well accepted.
Margin:
How far to start the printing from the left side of the console
Column_lengths:
Data will be output in columns of a maximum length determined
by this argument (which can be instantiated by a call to
column_lengths/2)
Fomratting:
[Left_border, Separator, Right_border]
Where:
Left_border: symbol to print at the start of each row
Separator: symbol to print at the end of each datum in a row
Right_border: symbol to print at the end of each row
*/
%%%%%%%%%%%%%%print_rows/4 (0) 12/03/11
% Print each row of data
print_rows([], _Margin, _Column_lengths, [_L, _S, _R]).
% Data : list of Datum; Datum : list of atoms.
%%%%%%%%%%%%%%print_rows/4 (1) 12/03/11
print_rows([Row | Data], Margin, Column_lengths, [L, S, R]):-
tab(Margin),
write(L), %write(` `),
print_datum(Row, S, Column_lengths),
%write(` `),
write(R), nl,
print_rows(Data, Margin, Column_lengths, [L, S, R]).
%%%%%%%%%%%%%%print_rows/3 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%
/* print_row(+Data, +Separator, +Column_lengths) */
% Prints each datum in a row of data
%%%%%%%%%%%%%%print_rows/3 (0) 12/03/11
print_datum([], _Separator, _Column_lengths).
%%%%%%%%%%%%%%print_rows/3 (1) 12/03/11
% One last datum remaining
print_datum([Datum | []], Separator, [Column_length | Lengths]):-
write(` `),
write(Datum),
write(` `),
len(Datum, Length),
Padding is Column_length - Length + 1,
tab(Padding),
print_datum([], Separator, Lengths).
%%%%%%%%%%%%%%print_rows/4 (1) 12/03/11
print_datum([Datum | Data], Separator, [Column_length | Lengths]):-
write(` `),
write(Datum),
write(` `),
len(Datum, Length),
Padding is Column_length - Length + 1,
tab(Padding),
write(Separator),
print_datum(Data, Separator, Lengths).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%grid/3 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* grid(+Borders, +Tabs, -Output) */
% Composes a line of symbols to be used as a header or row
% for a pretty-printed table
%%%% Notes %%%%
%%%%%%%%%%%%%%%
/*
Borders:
[Left_border, Line, Separator, Right_border]
Where:
Left_border: the symbol to print at the start of the grid line
Line: the symbol to print across the top of each column of the
table
Separator: the symbol to print between columns
Right_border: the symbol to print at the end of the grid line
Tabs:
Length of each column in the table (they don't have to be equal)
Output:
The completed line, ready for pretty-printing (or any printing)
*/
%%%%%%%%%%%%%%grid/3 (1) 12/03/11
grid([L_char, Cntr_char, Separator, R_char], [Tab | Tabs], Row):-
grid(Cntr_char, Separator, Tab, [Tab | Tabs], [], Row_1),
append([L_char], Row_1, Temp),
append(Temp, [R_char], List),
atom_to_list(Row, List), !. %Green cut
%%%%%%%%%%%%%%grid/6 12/03/11
%%%%%%%%%%%%%%%%%%%%%%%
/* grid(+Line, +Separator, +Tab, +Tabs, [], -Output) */
%%%%%%%%%%%%%%grid/6 (0) 12/03/11
grid(_Cntr_char, _Separator, 0, [], Row, Row).
%%%%%%%%%%%%%%grid/6 (1) 12/03/11
% One last tab left
grid(Cntr_char, Separator, 0, [Next_tab | []], Temp, Row):-
Temp \= [],
grid(Cntr_char, Separator, Next_tab, [], Temp, Row).
%%%%%%%%%%%%%%grid/6 (2) 12/03/11
% Add a column separator
grid(Cntr_char, Separator, 0, [_Tab | [Next_tab | Tabs]], Temp, Row):-
Temp \= [],
append(Temp, [Separator], New_temp),
grid(Cntr_char, Separator, Next_tab, [_| Tabs], New_temp, Row).
%%%%%%%%%%%%%%grid/6 (3) 12/03/11
% Write a cell's top character.
grid(Character, Separator, Tab, Tabs, Temp, Row):-
append(Temp, [Character], New_temp),
New_tab is Tab - 1,
grid(Character, Separator, New_tab, Tabs, New_temp, Row).
%%%% Notes %%%%
%%%%%%%%%%%%%%%
/*
Test with:
grid([╔, ═ , ╦, ╗], [2,3,3,4,3,2], Row_1),
write(Row_1), nl,
grid([╠, ═ , ╬, ╣], [2,3,3,4,3,2], Row_2),
write(Row_2), nl,
grid([╚, ═ , ╩, ╝], [2,3,3,4,3,2], Row_3),
write(Row_3), nl, nl.
*/