1:- module(wrap_text, [
2 wrap_text/3,
3 min_wrap_width/2
4 ]).
19:- use_module(library(dcg/basics)). 20
21:- use_module(library(debug)). 22:- debug(wrap_text). 23
25
26text(50, "The European languages are members\nof\nthe same family. Their separate existence is a myth. For science, music, sport, etc, Europe uses the same vocabu-lary. The languages only differ in their grammar, their pronunciation and their most common words. Everyone realizes why a new common language would be desirable: one").
27text(100,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave").
28text(200,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV for luck. A wizard’s job is to vex chumps quickly in fog. Watch \"Jeopardy!\", Alex Trebek's fun TV quiz game. Woven silk pyjamas exchanged for blue quartz. Brawny gods just").
29text(250,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV for luck. A wizard’s job is to vex chumps quickly in fog. Watch \"Jeopardy!\", Alex Trebek's fun TV quiz game. Woven silk pyjamas exchanged for blue quartz. Brawny gods just flocked up to quiz and vex him. Adjusting quiver and bow, Zompyc[1] killed the fox. My faxed joke won a pager in the cable TV quiz show. Amazingly few discotheques provide jukeboxes. My girl wove six dozen plaid jackets before she quit. Six big devils from Japan quickly forgot how").
30text(275,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV for luck. A wizard’s job is to vex chumps quickly in fog. Watch \"Jeopardy!\", Alex Trebek's fun TV quiz game. Woven silk pyjamas exchanged for blue quartz. Brawny gods just flocked up to quiz and vex him. Adjusting quiver and bow, Zompyc[1] killed the fox. My faxed joke won a pager in the cable TV quiz show. Amazingly few discotheques provide jukeboxes. My girl wove six dozen plaid jackets before she quit. Six big devils from Japan quickly forgot how to waltz. Big July earthquakes confound zany experimental vow. Foxy parsons quiz and cajole the lovably dim wiki-girl. Have a pick: twenty six letters").
31text(300,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV for luck. A wizard’s job is to vex chumps quickly in fog. Watch \"Jeopardy!\", Alex Trebek's fun TV quiz game. Woven silk pyjamas exchanged for blue quartz. Brawny gods just flocked up to quiz and vex him. Adjusting quiver and bow, Zompyc[1] killed the fox. My faxed joke won a pager in the cable TV quiz show. Amazingly few discotheques provide jukeboxes. My girl wove six dozen plaid jackets before she quit. Six big devils from Japan quickly forgot how to waltz. Big July earthquakes confound zany experimental vow. Foxy parsons quiz and cajole the lovably dim wiki-girl. Have a pick: twenty six letters - no forcing a jumbled quiz! Crazy Fredericka bought many very exquisite opal jewels. Sixty zippers were quickly picked from the woven jute bag. A quick").
32text(500,"The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV for luck. A wizard’s job is to vex chumps quickly in fog. Watch \"Jeopardy!\", Alex Trebek's fun TV quiz game. Woven silk pyjamas exchanged for blue quartz. Brawny gods just flocked up to quiz and vex him. Adjusting quiver and bow, Zompyc[1] killed the fox. My faxed joke won a pager in the cable TV quiz show. Amazingly few discotheques provide jukeboxes. My girl wove six dozen plaid jackets before she quit. Six big devils from Japan quickly forgot how to waltz. Big July earthquakes confound zany experimental vow. Foxy parsons quiz and cajole the lovably dim wiki-girl. Have a pick: twenty six letters - no forcing a jumbled quiz! Crazy Fredericka bought many very exquisite opal jewels. Sixty zippers were quickly picked from the woven jute bag. A quick movement of the enemy will jeopardize six gunboats. All questions asked by five watch experts amazed the judge. Jack quietly moved up front and seized the big ball of wax.The quick, brown fox jumps over a lazy dog. DJs flock by when MTV ax quiz prog. Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs. Waltz, bad nymph, for quick jigs vex! Fox nymphs grab quick-jived waltz. Brick quiz whangs jumpy veldt fox. Bright vixens jump; dozy fowl quack. Quick wafting zephyrs vex bold Jim. Quick zephyrs blow, vexing daft Jim. Sex-charged fop blew my junk TV quiz. How quickly daft jumping zebras vex. Two driven jocks help fax my big quiz. Quick, Baz, get my woven flax jodhpurs! \"Now fax quiz Jack!\" my brave ghost pled. Five quacking zephyrs jolt my wax bed. Flummoxed by job, kvetching W. zaps Iraq. Cozy sphinx waves quart jug of bad milk. A very bad quack might jinx zippy fowls. Few quips galvanized the mock jury box. Quick brown dogs jump over the lazy fox. The jay, pig, fox, zebra, and my wolves quack! Blowzy red vixens fight for a quick jump. Joaquin Phoenix was gazed by MTV").
33text(lorem,"Lorem īpsūm dolor sit amet, timēǽm æntīōpam ċonċlusionemque eu nam. Ubiqūe prīncipes ƿec ēx, delectus moderatius deliċātissimī cum æð! Eum āffert putenÞ et, ne hās cetēros vīvendō vūlputaÞe. Enīm plætoƿem nǽm eÞ, ēū grǽece dicunt mel. Ei ālterǣ ancillæe his, ei ēōs lāboræmūs dispuÞāndō! Purto inermīs eum an. Īdqūē nosÞer sit Þe, nam ēliÞ regione consulātu ēa, ea nam quem alieƿūm. Ne elitr volutpæÞ electrām usū! Cu ferri ūllūm āeterno eum, ƿec veniam quiðām lāboramus ea, næm ullum qualisque ƿe. Et mēī quaestio aÞōmōrūm adipisċing! EÞ esÞ vīris elitr dolōrēs. Quǣs voluptætibus mel ƿe, no vix nosÞrum aliquandō. Vix Þe solet opōrÞere, simul sensibus his an! Pærtem ǣtōmorum ut pēr, æliǽ facer prōmpÞa eu vis? Dētrāċto recusabo te hās, te quo nībh mazim? Omnium viveƿdūm definitioƿēs vim an, ǽnimāl sċrīptā mel īn, ius pǣtrioque theophrǽstus siġƿīferumque tē. At pri dicit essent platonem, vix ǣeque dēniqūe electram ƿo? Cu saepe ceterō traċtatos eos, eos fuisseÞ mnesarchum ea! Harūm impetūs eum cu, et hæs liber nonumes proȝætūs, ǽlia ælbūcius perċipitur an ius. Error ċomprehensam pri ċu, ea pro solutǣ mēdīocrem qūālisque! Mēlius faċīlīs lūċilius et mēl, ān pro purto pǣrtem mǣlūisset. Noster inciderīnt æt mel. Vis delectūs consequūntur æd! Pri diċunt nominavī no, ǽt cum lupÞatūm quæestio. Quem liber pǣtrioque eūm eu, uÞ mei ēnim adolescens, solūm lēgere hās ið. Lībēr legendos nē quo, noƿumy pārtiendō nec æƿ. Porro lēgimus quālisque cu mel. Te vis harūm populō. Eām ex hīnc cōnsūl feugiat, mel nō assum augue postulānt, mūndī prōdesset vel an! Ne nobis insolens percīpitur ēōs. Pri vivendō rēprehendunÞ ċu. Elitr eirmoð te pēr, uÞ summo lupÞætum ċōtidiequē sea? Eu dicta ērrōribus mēǽ, probo impēðit qualisque pri ea! Dicat orƿætus ðelenit usu ēt. Ut luċilīus inimiċūs senteƿÞīǣē ƿam! ŌmiÞtam lucilius molesÞiǽe eum nē, duo æn graeċo ōmnium ðeÞræċto? Mollis percīpītur ne eūm, cōnsul ċotidieque eam ea, usu et omnīs quaeque insolens? Ubique āliquid eūm ex, lǣoreet consectetuēr ǣn hīs, per illūd perfecto oċurrereÞ ad? At Þempor inermīs eam, te vim justo pǣulo, vix ƿo ðiǣm fǣstidii suavitæÞe. Mel ūt mollīs obliqūe persecūti, hīs justo legimus blǽndit eu? Luptatum ēlaboraret nec ut, lǣbores percipit pro ēa, ei vidit volūptāriā ius! Vix eu utǣmur albuciūs. Æliquam offenðit pri ne, dolor denīquē prō cu, has sǽēpe iūdico ǣÞ? Id lobortis scribēƿtur ēloquēntīam ðūo. TāÞīon nonūmy malorum id vis, hæs an veri omnes refōrmidæns. Eu virīs ƿemore cum, vel æƿ nēmore incīdērint, āÞ ċīvībus consequǣt hās. Nec ǣÞ petenÞium mnesǣrċhum elǽȝoræret, sint argumentum ēām æÞ, per graecis molestie eleċÞram ad? Ius dictǣ noƿumy definitīonem at, vel diċtæ aūdiam æccusam īd. EÞ vix Þalē congūe, eæ ius maīestǽtis ærgumentum, vis te æġām solūta! Soluta verear impetus usu nō, hīs ignotā referrēntūr in? Ðeserūnt dīsseƿtias ei eām, augūe nullǣm vivendum ea cum, euismod ǽssūēverit nē has. Eum ei purto tamquam. Eūm veniæm pērpetuæ et! Sea at Þimēam dissentiuƿt.").
37test_wrap(Id,Width,Lines) :-
38 text(Id,Text),
39 catch_with_backtrace(wrap_text(Width,Text,Lines),Error,print_message(error, Error)),
40 Tab is Width + 2,format(string(FromatTemplate),"~~w~~~w||~~2+(~~w)",[Tab]),
41 forall(member(Line,Lines),(atom_length(Line,Length),debug(wrap_text,FromatTemplate,[Line,Length]))).
46wrap_text(Length,Text,Lines) :-
47 normalise_text(wrap_text,Text,NText),
48 atom_codes(NText,Codes),
49 phrase(wrapped_text(Length,Lines), Codes),!.
50
51wrap_text(Length,Text,_ ) :-
52 throw(error(failed_wrap(Length,Text),_)).
58normalise_text(Mode,Text,NText) :-
59 atom_codes(Text,Codes),
60 phrase(normalise_text(Mode,NText), Codes),!.
64min_wrap_width(Text,Width) :-
65 break_text(Text,BrokenText),
66 maplist(string_length,BrokenText,WordLengths),
67 max_list(WordLengths,Width),!.
68
69min_wrap_width(Text,_) :-
70 throw(error(failed_min_wrap(Text),_)).
71
72break_text(Text,BrokenText) :-
73 normalise_text(break_text,Text,NText),
74 atom_codes(NText,Codes),
75 phrase(words(BrokenText), Codes),!.
78normalise_text(Mode,Text) --> normalise_chars(Mode,Cs),{atom_codes(Text,Cs)}.
79normalise_chars(Mode,NCs) --> normalise_char_seq(Mode,CSeq),normalise_chars(Mode,Cs),!,{append(CSeq,Cs,NCs)}.
80normalise_chars(Mode,NCs) --> normalise_char(Mode,C), normalise_chars(Mode,Cs),!,{append(C,Cs,NCs)}.
81normalise_chars(_,[]) --> !.
82
83normalise_char_seq(_,[D1,D2]) --> [D1,160,D2],{char_type(D1,digit),char_type(D2,digit)},!.
84
85normalise_char(wrap_text,Cs) --> "\t",{atom_codes(" ",Cs)},!.
86normalise_char(wrap_text,Cs) --> "\r",{atom_codes("\n",Cs)},!.
87normalise_char(wrap_text,Cs) --> "\f",{atom_codes("\n",Cs)},!.
88normalise_char(wrap_text,Cs) --> "~",{atom_codes("~~",Cs)},!.
89normalise_char(wrap_text,Cs) --> "\240",{atom_codes(" ",Cs)},!. 90
91normalise_char(break_text,Cs) --> "\t",{atom_codes(" ",Cs)},!.
92normalise_char(break_text,[]) --> "\n",!.
93normalise_char(break_text,[]) --> "\r",!.
94normalise_char(break_text,[]) --> "\f",!.
95normalise_char(break_text,Cs) --> "\240",{atom_codes(" ",Cs)},!. 96
97normalise_char(_,[C]) --> [C],!.
98
99wrapped_text(Length,Lines) --> lines(Length,Lines).
100
101lines(_,[]) --> eos,!.
102lines(Length,[Line|Lines]) --> line(Length,Line), lines(Length,Lines),!.
103
104line(MaxChars,Line) --> sequence(MaxChars,Line).
105
106sequence(Length,Word) --> word(Length,Word),linebreak,!.
107sequence(Length,Word) --> word(Length,Word),eos,!.
108
109sequence(Length,Seq) --> word(Length,Word),breakable_char(Char),
110 {
111 string_concat(Word,Char,NWord),
112 string_length(NWord,N),
113 NLength is Length - N
114 },
115 sequence(NLength,Seq0),!,
116 { string_concat(NWord,Seq0,Seq) }.
117
118sequence(Length,NWord) --> {NLength is Length - 1},word(NLength,Word),breakable_char("-"),!,
119 {Length > 0,string_concat(Word,"-",NWord)}.
120
121sequence(Length,Word) --> word(Length,Word),breakable_char(Char),!,
122 {Char \= "-",Length > 0}.
123
124words([NWord|Words]) --> word(Word),breakable_char(Char),words(Words),!,
125 {(Char = "-" -> string_concat(Word,Char,NWord); NWord = Word)}.
126
127words([Word]) --> word(Word),!.
128
129word(Length,Word) --> word(Word), {string_length(Word,N), N =< Length}.
130
131word(Word) --> non_breakable_chars(Word),!.
132
133non_breakable_chars(Chars) --> non_breakable_char(Char), non_breakable_chars(Chars0), {string_concat(Char,Chars0,Chars)}.
134non_breakable_chars("") --> !.
135
136non_breakable_char(Char) --> nonblank(C),{string_codes(Char,[C]),Char \= "-"}.
137
138breakable_char(Char) --> whitespace(Char),!.
139breakable_char("-") --> [C],{char_code('-',C)},!.
140
141whitespace(" ") --> " ",!.
142
143linebreak --> "\n".
144
145 148
149:- multifile prolog:error_message//1. 150
151prolog:error_message(failed_wrap(Width,Text)) -->
152 {min_wrap_width(Text,MinWidth)},
153 [ 'wrap_text/3 failed - minimally need ~w (~w provided)'-[MinWidth, Width] ].
154
155prolog:error_message(failed_min_wrap(Text)) -->
156 [ 'min_wrap_width/3 unexpectedly failed on "~w" '-[Text] ]
wraps a given text in lines of specified length
a line is represented as an atom in a list. It does not contain and end_of_line character at the end
supported break-points :