Setters.txt 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. MODULE TextSetters;
  2. (* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Text/Mod/Setters.odc *)
  3. (* DO NOT EDIT *)
  4. (* correct NextPage postcond in docu *)
  5. (* make s.r, s.rd reducible? *)
  6. (* paraShutoff needs to be controlled by an approx flag to certain ops (later ...?) *)
  7. IMPORT
  8. Fonts, Ports, Printers, Stores, Models, Views, Properties,
  9. TextModels, TextRulers;
  10. CONST
  11. (** Pref.opts, options of setter-aware views; 0 overrides 1 **)
  12. lineBreak* = 0; wordJoin* = 1; wordPart* = 2; flexWidth* = 3;
  13. tab = TextModels.tab; line = TextModels.line; para = TextModels.para;
  14. zwspace = TextModels.zwspace; nbspace = TextModels.nbspace;
  15. hyphen = TextModels.hyphen; nbhyphen = TextModels.nbhyphen;
  16. digitspace = TextModels.digitspace;
  17. softhyphen = TextModels.softhyphen;
  18. mm = Ports.mm;
  19. minTabWidth = 2 * Ports.point; stdTabWidth = 4 * mm;
  20. leftLineGap = 2 * Ports.point; rightLineGap = 3 * Ports.point;
  21. adjustMask = {TextRulers.leftAdjust, TextRulers.rightAdjust};
  22. centered = {}; leftFlush = {TextRulers.leftAdjust}; rightFlush = {TextRulers.rightAdjust};
  23. blocked = adjustMask;
  24. boxCacheLen = 64;
  25. seqCacheLen = 16;
  26. paraShutoff = MAX(INTEGER); (* longest stretch read backwards to find start of paragraph *)
  27. (* unsafe: disabled *)
  28. cachedRulers = FALSE; (* caching ruler objects trades speed against GC effectiveness *)
  29. periodInWords = FALSE;
  30. colonInWords = FALSE;
  31. minVersion = 0; maxVersion = 0; maxStdVersion = 0;
  32. TYPE
  33. Pref* = RECORD (Properties.Preference)
  34. opts*: SET;
  35. endW*: INTEGER; (** preset (to width of view) **)
  36. dsc*: INTEGER (** preset (to dominating line descender) **)
  37. END;
  38. Reader* = POINTER TO ABSTRACT RECORD
  39. r-: TextModels.Reader; (** look-ahead state **)
  40. (** unit **)
  41. string*: ARRAY 64 OF CHAR; (** single chars in string[0] **)
  42. view*: Views.View;
  43. (** unit props **)
  44. textOpts*: SET;
  45. mask*: CHAR;
  46. setterOpts*: SET;
  47. w*, endW*, h*, dsc*: INTEGER;
  48. attr*: TextModels.Attributes;
  49. (** reading state **)
  50. eot*: BOOLEAN;
  51. pos*: INTEGER;
  52. x*: INTEGER; (** to be advanced by client! **)
  53. adjStart*: INTEGER;
  54. spaces*: INTEGER;
  55. tabIndex*: INTEGER; (** tabs being processed; initially -1 **)
  56. tabType*: SET; (** type of tab being processed; initially {} **)
  57. (** line props **)
  58. vw*: INTEGER;
  59. hideMarks*: BOOLEAN;
  60. ruler*: TextRulers.Ruler;
  61. rpos*: INTEGER
  62. END;
  63. Setter* = POINTER TO ABSTRACT RECORD (Stores.Store)
  64. text-: TextModels.Model; (** connected iff text # NIL **)
  65. defRuler-: TextRulers.Ruler;
  66. vw-: INTEGER;
  67. hideMarks-: BOOLEAN
  68. END;
  69. LineBox* = RECORD
  70. len*: INTEGER;
  71. ruler*: TextRulers.Ruler;
  72. rpos*: INTEGER;
  73. left*, right*, asc*, dsc*: INTEGER;
  74. rbox*, bop*, adj*, eot*: BOOLEAN; (** adj => adjW > 0; adj & blocked => spaces > 0 **)
  75. views*: BOOLEAN;
  76. skipOff*: INTEGER; (** chars in [skipOff, len) take endW **)
  77. adjOff*: INTEGER; (** offset of last block in box - adjust only this block **)
  78. spaces*: INTEGER; (** valid, > 0 if adj & blocked **)
  79. adjW*: INTEGER; (** valid if adj - to be distributed over spaces **)
  80. tabW*: ARRAY TextRulers.maxTabs OF INTEGER (** delta width of tabs (<= 0) **)
  81. END;
  82. Directory* = POINTER TO ABSTRACT RECORD END;
  83. Worder = RECORD
  84. box: LineBox; next: INTEGER;
  85. i: INTEGER
  86. END;
  87. StdReader = POINTER TO RECORD (Reader) END;
  88. StdSetter = POINTER TO RECORD (Setter)
  89. rd: Reader; (* subject to reduction? *)
  90. r: TextModels.Reader; (* subject to reduction? *)
  91. ruler: TextRulers.Ruler;
  92. rpos: INTEGER;
  93. key: INTEGER
  94. END;
  95. StdDirectory = POINTER TO RECORD (Directory) END;
  96. VAR
  97. dir-, stdDir-: Directory;
  98. nextKey: INTEGER;
  99. boxIndex, seqIndex: INTEGER;
  100. boxCache: ARRAY boxCacheLen OF RECORD
  101. key: INTEGER; (* valid iff key > 0 *)
  102. start: INTEGER;
  103. line: LineBox (* inv ruler = NIL *)
  104. END;
  105. seqCache: ARRAY seqCacheLen OF RECORD
  106. key: INTEGER; (* valid iff key > 0 *)
  107. start, pos: INTEGER (* sequence [start, end), end >= pos *)
  108. END;
  109. (** Reader **)
  110. PROCEDURE (rd: Reader) Set* (
  111. old: TextModels.Reader;
  112. text: TextModels.Model; x, pos: INTEGER;
  113. ruler: TextRulers.Ruler; rpos: INTEGER; vw: INTEGER; hideMarks: BOOLEAN
  114. ), NEW, EXTENSIBLE;
  115. BEGIN
  116. ASSERT(text # NIL, 20);
  117. ASSERT(ruler # NIL, 22);
  118. rd.r := text.NewReader(old); rd.r.SetPos(pos); rd.r.Read;
  119. rd.string[0] := 0X; rd.view := NIL;
  120. rd.textOpts := {};
  121. rd.setterOpts := {}; rd.w := 0; rd.endW := 0; rd.h := 0; rd.dsc := 0;
  122. rd.attr := NIL;
  123. rd.eot := FALSE; rd.pos := pos; rd.x := x;
  124. rd.tabIndex := -1; rd.tabType := {};
  125. rd.adjStart := pos; rd.spaces := 0;
  126. rd.ruler := ruler; rd.rpos := rpos; rd.vw := vw; rd.hideMarks := hideMarks
  127. END Set;
  128. PROCEDURE (rd: Reader) Read*, NEW, EXTENSIBLE;
  129. (** pre: rd set **)
  130. (** post: rd.pos = rd.pos' + Length(rd.string) **)
  131. BEGIN
  132. rd.string[0] := rd.r.char; rd.string[1] := 0X;
  133. rd.view := rd.r.view;
  134. rd.textOpts := {};
  135. rd.setterOpts := {};
  136. rd.w := rd.r.w; rd.endW := rd.w; rd.h := rd.r.h; rd.dsc := 0;
  137. rd.attr := rd.r.attr;
  138. rd.eot := rd.r.eot;
  139. INC(rd.pos);
  140. rd.r.Read
  141. END Read;
  142. PROCEDURE (rd: Reader) AdjustWidth* (start, pos: INTEGER; IN box: LineBox;
  143. VAR w: INTEGER
  144. ), NEW, ABSTRACT;
  145. PROCEDURE (rd: Reader) SplitWidth* (w: INTEGER): INTEGER, NEW, ABSTRACT;
  146. (** Setter **)
  147. PROCEDURE (s: Setter) CopyFrom- (source: Stores.Store), EXTENSIBLE;
  148. BEGIN
  149. WITH source: Setter DO
  150. s.text := source.text; s.defRuler := source.defRuler;
  151. s.vw := source.vw; s.hideMarks := source.hideMarks
  152. END
  153. END CopyFrom;
  154. PROCEDURE (s: Setter) Internalize- (VAR rd: Stores.Reader), EXTENSIBLE;
  155. VAR thisVersion: INTEGER;
  156. BEGIN
  157. s.Internalize^(rd);
  158. IF rd.cancelled THEN RETURN END;
  159. rd.ReadVersion(minVersion, maxVersion, thisVersion)
  160. END Internalize;
  161. PROCEDURE (s: Setter) Externalize- (VAR wr: Stores.Writer), EXTENSIBLE;
  162. BEGIN
  163. s.Externalize^(wr);
  164. wr.WriteVersion(maxVersion)
  165. END Externalize;
  166. PROCEDURE (s: Setter) ConnectTo* (text: TextModels.Model;
  167. defRuler: TextRulers.Ruler; vw: INTEGER; hideMarks: BOOLEAN
  168. ), NEW, EXTENSIBLE;
  169. BEGIN
  170. IF text # NIL THEN
  171. s.text := text; s.defRuler := defRuler; s.vw := vw; s.hideMarks := hideMarks
  172. ELSE
  173. s.text := NIL; s.defRuler := NIL
  174. END
  175. END ConnectTo;
  176. PROCEDURE (s: Setter) ThisPage* (pageH: INTEGER; pageNo: INTEGER): INTEGER, NEW, ABSTRACT;
  177. (** pre: connected, 0 <= pageNo **)
  178. (** post: (result = -1) & (pageNo >= maxPageNo) OR (result = pageStart(pageNo)) **)
  179. PROCEDURE (s: Setter) NextPage* (pageH: INTEGER; start: INTEGER): INTEGER, NEW, ABSTRACT;
  180. (** pre: connected, ThisPage(pageH, pageNo) = start [with pageNo = NumberOfPageAt(start)] **)
  181. (** post: (result = start) & last-page(start) OR result = next-pageStart(start) **)
  182. PROCEDURE (s: Setter) ThisSequence* (pos: INTEGER): INTEGER, NEW, ABSTRACT;
  183. (** pre: connected, 0 <= pos <= s.text.Length() **)
  184. (** post: (result = 0) OR (char(result - 1) IN {line, para}) **)
  185. PROCEDURE (s: Setter) NextSequence* (start: INTEGER): INTEGER, NEW, ABSTRACT;
  186. (** pre: connected, ThisSequence(start) = start **)
  187. (** post: (result = start) & last-line(start) OR (ThisSequence(t, result - 1) = start) **)
  188. PROCEDURE (s: Setter) PreviousSequence* (start: INTEGER): INTEGER, NEW, ABSTRACT;
  189. (** pre: connected, ThisSequence(t, start) = start **)
  190. (** post: (result = 0) & (start = 0) OR (result = ThisSequence(t, start - 1)) **)
  191. PROCEDURE (s: Setter) ThisLine* (pos: INTEGER): INTEGER, NEW, ABSTRACT;
  192. (** pre: connected, 0 <= pos <= s.text.Length() **)
  193. (** post: result <= pos, (pos < NextLine(result)) OR last-line(result) **)
  194. PROCEDURE (s: Setter) NextLine* (start: INTEGER): INTEGER, NEW, ABSTRACT;
  195. (** pre: connected, ThisLine(start) = start **)
  196. (** post: (result = 0) & (start = 0) OR
  197. (result = start) & last-line(start) OR
  198. (ThisLine(result - 1) = start) **)
  199. PROCEDURE (s: Setter) PreviousLine* (start: INTEGER): INTEGER, NEW, ABSTRACT;
  200. (** pre: connected, ThisLine(start) = start **)
  201. (** post: (result = 0) & (start = 0) OR (result = ThisLine(start - 1)) **)
  202. PROCEDURE (s: Setter) GetWord* (pos: INTEGER; OUT beg, end: INTEGER), NEW, ABSTRACT;
  203. (** pre: connected, 0 <= pos <= s.text.Length() **)
  204. (** post: c set, beg <= pos <= end **)
  205. PROCEDURE (s: Setter) GetLine* (start: INTEGER; OUT box: LineBox), NEW, ABSTRACT;
  206. (** pre: connected, ThisLine(start) = start, 0 <= start <= s.text.Length() **)
  207. (** post: (c, box) set (=> box.ruler # NIL), (box.len > 0) OR box.eot,
  208. 0 <= box.left <= box.right <= ruler.right **)
  209. PROCEDURE (s: Setter) GetBox* (start, end, maxW, maxH: INTEGER;
  210. OUT w, h: INTEGER
  211. ), NEW, ABSTRACT;
  212. (** pre: connected, ThisLine(start) = start, 0 <= start <= end <= s.text.Length() **)
  213. (** post: c set, maxW > undefined => w <= maxW, maxH > undefined => h <= maxH **)
  214. PROCEDURE (s: Setter) NewReader* (old: Reader): Reader, NEW, ABSTRACT;
  215. (** pre: connected **)
  216. PROCEDURE (s: Setter) GridOffset* (dsc: INTEGER; IN box: LineBox): INTEGER, NEW, ABSTRACT;
  217. (** pre: connected, dsc >= 0: dsc is descender of previous line; dsc = -1 for first line **)
  218. (** post: dsc + GridOffset(dsc, box) + box.asc = k*ruler.grid (k >= 0) >= ruler.asc + ruler.grid **)
  219. (** Directory **)
  220. PROCEDURE (d: Directory) New* (): Setter, NEW, ABSTRACT;
  221. (* line box cache *)
  222. PROCEDURE InitCache;
  223. VAR i: INTEGER;
  224. BEGIN
  225. nextKey := 1; boxIndex := 0; seqIndex := 0;
  226. i := 0; WHILE i < boxCacheLen DO boxCache[i].key := -1; INC(i) END;
  227. i := 0; WHILE i < seqCacheLen DO seqCache[i].key := -1; INC(i) END
  228. END InitCache;
  229. PROCEDURE ClearCache (key: INTEGER);
  230. VAR i, j: INTEGER;
  231. BEGIN
  232. i := 0; j := boxIndex;
  233. WHILE i < boxCacheLen DO
  234. IF boxCache[i].key = key THEN boxCache[i].key := -1; j := i END;
  235. INC(i)
  236. END;
  237. boxIndex := j;
  238. i := 0; j := seqIndex;
  239. WHILE i < seqCacheLen DO
  240. IF seqCache[i].key = key THEN seqCache[i].key := -1; j := i END;
  241. INC(i)
  242. END;
  243. seqIndex := j
  244. END ClearCache;
  245. PROCEDURE CacheIndex (key, start: INTEGER): INTEGER;
  246. VAR i: INTEGER;
  247. BEGIN
  248. RETURN -1;
  249. i := 0;
  250. WHILE (i < boxCacheLen) & ~((boxCache[i].key = key) & (boxCache[i].start = start)) DO
  251. INC(i)
  252. END;
  253. IF i = boxCacheLen THEN i := -1 END;
  254. RETURN i
  255. END CacheIndex;
  256. PROCEDURE GetFromCache (s: StdSetter; i: INTEGER; VAR l: LineBox);
  257. BEGIN
  258. l := boxCache[i].line;
  259. IF ~cachedRulers THEN
  260. IF l.rpos >= 0 THEN
  261. s.r := s.text.NewReader(s.r); s.r.SetPos(l.rpos); s.r.Read;
  262. l.ruler := s.r.view(TextRulers.Ruler)
  263. ELSE l.ruler := s.defRuler
  264. END
  265. END
  266. END GetFromCache;
  267. PROCEDURE AddToCache (key, start: INTEGER; VAR l: LineBox);
  268. VAR i: INTEGER;
  269. BEGIN
  270. i := boxIndex; boxIndex := (i + 1) MOD boxCacheLen;
  271. boxCache[i].key := key; boxCache[i].start := start; boxCache[i].line := l;
  272. IF ~cachedRulers THEN
  273. boxCache[i].line.ruler := NIL
  274. END
  275. END AddToCache;
  276. PROCEDURE CachedSeqStart (key, pos: INTEGER): INTEGER;
  277. VAR start: INTEGER; i: INTEGER;
  278. BEGIN
  279. i := 0;
  280. WHILE (i < seqCacheLen)
  281. & ~((seqCache[i].key = key) & (seqCache[i].start <= pos) & (pos <= seqCache[i].pos)) DO
  282. INC(i)
  283. END;
  284. IF i < seqCacheLen THEN start := seqCache[i].start ELSE start := -1 END;
  285. RETURN start
  286. END CachedSeqStart;
  287. PROCEDURE AddSeqStartToCache (key, pos, start: INTEGER);
  288. VAR i: INTEGER;
  289. BEGIN
  290. i := 0;
  291. WHILE (i < seqCacheLen) & ~((seqCache[i].key = key) & (seqCache[i].start = start)) DO
  292. INC(i)
  293. END;
  294. IF i < seqCacheLen THEN
  295. IF seqCache[i].pos < pos THEN seqCache[i].pos := pos END
  296. ELSE
  297. i := seqIndex; seqIndex := (i + 1) MOD seqCacheLen;
  298. seqCache[i].key := key; seqCache[i].pos := pos; seqCache[i].start := start
  299. END
  300. END AddSeqStartToCache;
  301. (* StdReader *)
  302. (*
  303. PROCEDURE WordPart (ch, ch1: CHAR): BOOLEAN;
  304. (* needs more work ... put elsewhere? *)
  305. BEGIN
  306. CASE ORD(ch) OF
  307. ORD("0") .. ORD("9"), ORD("A") .. ORD("Z"), ORD("a") .. ORD("z"),
  308. ORD(digitspace), ORD(nbspace), ORD(nbhyphen), ORD("_"),
  309. 0C0H .. 0C6H, 0E0H .. 0E6H, (* ~ A *)
  310. 0C7H, 0E7H, (* ~ C *)
  311. 0C8H .. 0CBH, 0E8H .. 0EBH, (* ~ E *)
  312. 0CCH .. 0CFH, 0ECH .. 0EFH, (* ~ I *)
  313. 0D1H, 0F1H, (* ~ N *)
  314. 0D2H .. 0D6H, 0D8H, 0F2H .. 0F6H, 0F8H, (* ~ O *)
  315. 0D9H .. 0DCH, 0F9H .. 0FCH, (* ~ U *)
  316. 0DDH, 0FDH, 0FFH, (* ~ Y *)
  317. 0DFH: (* ~ ss *)
  318. RETURN TRUE
  319. | ORD("."), ORD(":"):
  320. IF (ch = ".") & periodInWords OR (ch = ":") & colonInWords THEN
  321. CASE ch1 OF
  322. 0X, TextModels.viewcode, tab, line, para, " ":
  323. RETURN FALSE
  324. ELSE RETURN TRUE
  325. END
  326. ELSE RETURN FALSE
  327. END
  328. ELSE RETURN FALSE
  329. END
  330. END WordPart;
  331. *)
  332. PROCEDURE WordPart (ch, ch1: CHAR): BOOLEAN;
  333. (* Same as .net function System.Char.IsLetterOrDigit(ch)
  334. + digit space, nonbreaking space, nonbreaking hyphen, & underscore
  335. ch1 unused *)
  336. VAR low: INTEGER;
  337. BEGIN
  338. low := ORD(ch) MOD 256;
  339. CASE ORD(ch) DIV 256 OF
  340. | 001H, 015H, 034H..04CH, 04EH..09EH, 0A0H..0A3H, 0ACH..0D6H, 0F9H, 0FCH: RETURN TRUE
  341. | 000H: CASE low OF
  342. | 030H..039H, 041H..05AH, 061H..07AH, 0AAH, 0B5H, 0BAH, 0C0H..0D6H, 0D8H..0F6H, 0F8H..0FFH,
  343. ORD(digitspace), ORD(nbspace), ORD(nbhyphen), ORD("_"): RETURN TRUE
  344. ELSE
  345. END
  346. | 002H: CASE low OF
  347. | 000H..041H, 050H..0C1H, 0C6H..0D1H, 0E0H..0E4H, 0EEH: RETURN TRUE
  348. ELSE
  349. END
  350. | 003H: CASE low OF
  351. | 07AH, 086H, 088H..08AH, 08CH, 08EH..0A1H, 0A3H..0CEH, 0D0H..0F5H, 0F7H..0FFH: RETURN TRUE
  352. ELSE
  353. END
  354. | 004H: CASE low OF
  355. | 000H..081H, 08AH..0CEH, 0D0H..0F9H: RETURN TRUE
  356. ELSE
  357. END
  358. | 005H: CASE low OF
  359. | 000H..00FH, 031H..056H, 059H, 061H..087H, 0D0H..0EAH, 0F0H..0F2H: RETURN TRUE
  360. ELSE
  361. END
  362. | 006H: CASE low OF
  363. | 021H..03AH, 040H..04AH, 060H..069H, 06EH..06FH, 071H..0D3H, 0D5H, 0E5H..0E6H, 0EEH..0FCH, 0FFH: RETURN TRUE
  364. ELSE
  365. END
  366. | 007H: CASE low OF
  367. | 010H, 012H..02FH, 04DH..06DH, 080H..0A5H, 0B1H: RETURN TRUE
  368. ELSE
  369. END
  370. | 009H: CASE low OF
  371. | 004H..039H, 03DH, 050H, 058H..061H, 066H..06FH, 07DH, 085H..08CH, 08FH..090H, 093H..0A8H, 0AAH..0B0H, 0B2H, 0B6H..0B9H, 0BDH, 0CEH, 0DCH..0DDH, 0DFH..0E1H, 0E6H..0F1H: RETURN TRUE
  372. ELSE
  373. END
  374. | 00AH: CASE low OF
  375. | 005H..00AH, 00FH..010H, 013H..028H, 02AH..030H, 032H..033H, 035H..036H, 038H..039H, 059H..05CH, 05EH, 066H..06FH, 072H..074H, 085H..08DH, 08FH..091H, 093H..0A8H, 0AAH..0B0H, 0B2H..0B3H, 0B5H..0B9H, 0BDH, 0D0H, 0E0H..0E1H, 0E6H..0EFH: RETURN TRUE
  376. ELSE
  377. END
  378. | 00BH: CASE low OF
  379. | 005H..00CH, 00FH..010H, 013H..028H, 02AH..030H, 032H..033H, 035H..039H, 03DH, 05CH..05DH, 05FH..061H, 066H..06FH, 071H, 083H, 085H..08AH, 08EH..090H, 092H..095H, 099H..09AH, 09CH, 09EH..09FH, 0A3H..0A4H, 0A8H..0AAH, 0AEH..0B9H, 0E6H..0EFH: RETURN TRUE
  380. ELSE
  381. END
  382. | 00CH: CASE low OF
  383. | 005H..00CH, 00EH..010H, 012H..028H, 02AH..033H, 035H..039H, 060H..061H, 066H..06FH, 085H..08CH, 08EH..090H, 092H..0A8H, 0AAH..0B3H, 0B5H..0B9H, 0BDH, 0DEH, 0E0H..0E1H, 0E6H..0EFH: RETURN TRUE
  384. ELSE
  385. END
  386. | 00DH: CASE low OF
  387. | 005H..00CH, 00EH..010H, 012H..028H, 02AH..039H, 060H..061H, 066H..06FH, 085H..096H, 09AH..0B1H, 0B3H..0BBH, 0BDH, 0C0H..0C6H: RETURN TRUE
  388. ELSE
  389. END
  390. | 00EH: CASE low OF
  391. | 001H..030H, 032H..033H, 040H..046H, 050H..059H, 081H..082H, 084H, 087H..088H, 08AH, 08DH, 094H..097H, 099H..09FH, 0A1H..0A3H, 0A5H, 0A7H, 0AAH..0ABH, 0ADH..0B0H, 0B2H..0B3H, 0BDH, 0C0H..0C4H, 0C6H, 0D0H..0D9H, 0DCH..0DDH: RETURN TRUE
  392. ELSE
  393. END
  394. | 00FH: CASE low OF
  395. | 000H, 020H..029H, 040H..047H, 049H..06AH, 088H..08BH: RETURN TRUE
  396. ELSE
  397. END
  398. | 010H: CASE low OF
  399. | 000H..021H, 023H..027H, 029H..02AH, 040H..049H, 050H..055H, 0A0H..0C5H, 0D0H..0FAH, 0FCH: RETURN TRUE
  400. ELSE
  401. END
  402. | 011H: CASE low OF
  403. | 000H..059H, 05FH..0A2H, 0A8H..0F9H: RETURN TRUE
  404. ELSE
  405. END
  406. | 012H: CASE low OF
  407. | 000H..048H, 04AH..04DH, 050H..056H, 058H, 05AH..05DH, 060H..088H, 08AH..08DH, 090H..0B0H, 0B2H..0B5H, 0B8H..0BEH, 0C0H, 0C2H..0C5H, 0C8H..0D6H, 0D8H..0FFH: RETURN TRUE
  408. ELSE
  409. END
  410. | 013H: CASE low OF
  411. | 000H..010H, 012H..015H, 018H..05AH, 080H..08FH, 0A0H..0F4H: RETURN TRUE
  412. ELSE
  413. END
  414. | 014H: IF low >= 001H THEN RETURN TRUE END
  415. | 016H: CASE low OF
  416. | 000H..06CH, 06FH..076H, 081H..09AH, 0A0H..0EAH: RETURN TRUE
  417. ELSE
  418. END
  419. | 017H: CASE low OF
  420. | 000H..00CH, 00EH..011H, 020H..031H, 040H..051H, 060H..06CH, 06EH..070H, 080H..0B3H, 0D7H, 0DCH, 0E0H..0E9H: RETURN TRUE
  421. ELSE
  422. END
  423. | 018H: CASE low OF
  424. | 010H..019H, 020H..077H, 080H..0A8H: RETURN TRUE
  425. ELSE
  426. END
  427. | 019H: CASE low OF
  428. | 000H..01CH, 046H..06DH, 070H..074H, 080H..0A9H, 0C1H..0C7H, 0D0H..0D9H: RETURN TRUE
  429. ELSE
  430. END
  431. | 01AH: IF low < 017H THEN RETURN TRUE END
  432. | 01DH: IF low < 0C0H THEN RETURN TRUE END
  433. | 01EH: CASE low OF
  434. | 000H..09BH, 0A0H..0F9H: RETURN TRUE
  435. ELSE
  436. END
  437. | 01FH: CASE low OF
  438. | 000H..015H, 018H..01DH, 020H..045H, 048H..04DH, 050H..057H, 059H, 05BH, 05DH, 05FH..07DH, 080H..0B4H, 0B6H..0BCH, 0BEH, 0C2H..0C4H, 0C6H..0CCH, 0D0H..0D3H, 0D6H..0DBH, 0E0H..0ECH, 0F2H..0F4H, 0F6H..0FCH: RETURN TRUE
  439. ELSE
  440. END
  441. | 020H: CASE low OF
  442. | 071H, 07FH, 090H..094H: RETURN TRUE
  443. ELSE
  444. END
  445. | 021H: CASE low OF
  446. | 002H, 007H, 00AH..013H, 015H, 019H..01DH, 024H, 026H, 028H, 02AH..02DH, 02FH..031H, 033H..039H, 03CH..03FH, 045H..049H: RETURN TRUE
  447. ELSE
  448. END
  449. | 02CH: CASE low OF
  450. | 000H..02EH, 030H..05EH, 080H..0E4H: RETURN TRUE
  451. ELSE
  452. END
  453. | 02DH: CASE low OF
  454. | 000H..025H, 030H..065H, 06FH, 080H..096H, 0A0H..0A6H, 0A8H..0AEH, 0B0H..0B6H, 0B8H..0BEH, 0C0H..0C6H, 0C8H..0CEH, 0D0H..0D6H, 0D8H..0DEH: RETURN TRUE
  455. ELSE
  456. END
  457. | 030H: CASE low OF
  458. | 005H..006H, 031H..035H, 03BH..03CH, 041H..096H, 09DH..09FH, 0A1H..0FAH, 0FCH..0FFH: RETURN TRUE
  459. ELSE
  460. END
  461. | 031H: CASE low OF
  462. | 005H..02CH, 031H..08EH, 0A0H..0B7H, 0F0H..0FFH: RETURN TRUE
  463. ELSE
  464. END
  465. | 04DH: IF low < 0B6H THEN RETURN TRUE END
  466. | 09FH: IF low < 0BCH THEN RETURN TRUE END
  467. | 0A4H: IF low < 08DH THEN RETURN TRUE END
  468. | 0A8H: CASE low OF
  469. | 000H..001H, 003H..005H, 007H..00AH, 00CH..022H: RETURN TRUE
  470. ELSE
  471. END
  472. | 0D7H: IF low < 0A4H THEN RETURN TRUE END
  473. | 0FAH: CASE low OF
  474. | 000H..02DH, 030H..06AH, 070H..0D9H: RETURN TRUE
  475. ELSE
  476. END
  477. | 0FBH: CASE low OF
  478. | 000H..006H, 013H..017H, 01DH, 01FH..028H, 02AH..036H, 038H..03CH, 03EH, 040H..041H, 043H..044H, 046H..0B1H, 0D3H..0FFH: RETURN TRUE
  479. ELSE
  480. END
  481. | 0FDH: CASE low OF
  482. | 000H..03DH, 050H..08FH, 092H..0C7H, 0F0H..0FBH: RETURN TRUE
  483. ELSE
  484. END
  485. | 0FEH: CASE low OF
  486. | 070H..074H, 076H..0FCH: RETURN TRUE
  487. ELSE
  488. END
  489. | 0FFH: CASE low OF
  490. | 010H..019H, 021H..03AH, 041H..05AH, 066H..0BEH, 0C2H..0C7H, 0CAH..0CFH, 0D2H..0D7H, 0DAH..0DCH: RETURN TRUE
  491. ELSE
  492. END
  493. ELSE
  494. END;
  495. RETURN FALSE
  496. END WordPart;
  497. (*
  498. PROCEDURE ExtendToEOL (x, right: INTEGER): INTEGER;
  499. BEGIN
  500. IF right - x > 5 * mm THEN RETURN right - x ELSE RETURN 5 * mm END
  501. END ExtendToEOL;
  502. *)
  503. PROCEDURE Right (ra: TextRulers.Attributes; vw: INTEGER): INTEGER;
  504. BEGIN
  505. IF TextRulers.rightFixed IN ra.opts THEN
  506. RETURN ra.right
  507. ELSE
  508. RETURN vw
  509. END
  510. END Right;
  511. PROCEDURE GetViewPref (rd: StdReader);
  512. CONST maxH = 1600 * Ports.point;
  513. VAR ra: TextRulers.Attributes; tp: TextModels.Pref; sp: Pref;
  514. BEGIN
  515. ra := rd.ruler.style.attr;
  516. tp.opts := {}; Views.HandlePropMsg(rd.view, tp);
  517. rd.textOpts := tp.opts; rd.mask := tp.mask;
  518. sp.opts := {}; sp.dsc := ra.dsc; sp.endW := rd.w; Views.HandlePropMsg(rd.view, sp);
  519. rd.setterOpts := sp.opts; rd.dsc := sp.dsc; rd.endW := sp.endW;
  520. IF rd.w >= 10000 * mm THEN rd.w := 10000 * mm END;
  521. IF (TextModels.hideable IN tp.opts) & rd.hideMarks THEN
  522. rd.h := 0; sp.dsc := 0;
  523. (*
  524. rd.w := 0;
  525. *)
  526. IF ~( (rd.view IS TextRulers.Ruler)
  527. OR (TextModels.maskChar IN rd.textOpts) & (rd.mask = para) ) THEN
  528. rd.w := 0
  529. END
  530. (**)
  531. ELSIF rd.h > maxH THEN rd.h := maxH
  532. END;
  533. IF TextModels.maskChar IN rd.textOpts THEN
  534. rd.string[0] := rd.mask; rd.string[1] := 0X
  535. ELSE rd.string[0] := TextModels.viewcode
  536. END
  537. END GetViewPref;
  538. PROCEDURE GatherString (rd: StdReader);
  539. VAR i, len: INTEGER; ch: CHAR;
  540. BEGIN
  541. i := 1; len := LEN(rd.string) - 1; ch := rd.r.char;
  542. WHILE (i < len)
  543. & (rd.r.view = NIL) & (rd.r.attr = rd.attr)
  544. & ( (" " < ch) & (ch <= "~") & (ch # "-")
  545. OR (ch = digitspace)
  546. OR (ch >= nbspace) & (ch < 100X) & (ch # softhyphen)
  547. )
  548. DO (* rd.r.char > " " => ~rd.eot *)
  549. rd.string[i] := ch; INC(i);
  550. rd.eot := rd.r.eot;
  551. rd.r.Read; ch := rd.r.char; INC(rd.pos)
  552. END;
  553. rd.string[i] := 0X; rd.setterOpts := {wordJoin};
  554. IF i = 1 THEN
  555. IF WordPart(rd.string[0], 0X) THEN INCL(rd.setterOpts, wordPart) END
  556. END;
  557. rd.w := rd.attr.font.StringWidth(rd.string); rd.endW := rd.w
  558. END GatherString;
  559. PROCEDURE SpecialChar (rd: StdReader);
  560. VAR ra: TextRulers.Attributes; i, tabs, spaceW, dW: INTEGER; type: SET;
  561. BEGIN
  562. ra := rd.ruler.style.attr;
  563. CASE ORD(rd.string[0]) OF
  564. ORD(tab):
  565. rd.textOpts := {TextModels.hideable};
  566. rd.endW := minTabWidth;
  567. rd.adjStart := rd.pos; rd.spaces := 0;
  568. (*
  569. i := 0; WHILE (i < ra.tabs.len) & (ra.tabs.tab[i].stop < rd.x + minTabWidth) DO INC(i) END;
  570. *)
  571. i := rd.tabIndex + 1;
  572. IF i < ra.tabs.len THEN
  573. type := ra.tabs.tab[i].type;
  574. rd.w := MAX(minTabWidth, ra.tabs.tab[i].stop - rd.x);
  575. IF TextRulers.barTab IN type THEN
  576. IF TextRulers.rightTab IN type THEN
  577. rd.w := MAX(minTabWidth, rd.w - leftLineGap)
  578. ELSIF ~(TextRulers.centerTab IN type) THEN
  579. INC(rd.w, rightLineGap)
  580. END
  581. END;
  582. rd.tabIndex := i; rd.tabType := type
  583. ELSE (* for "reasonable" fonts: round to closest multiple of spaces of this font *)
  584. spaceW := rd.attr.font.SStringWidth(" ");
  585. IF (1 <= spaceW) & (spaceW <= stdTabWidth) THEN
  586. rd.w := (stdTabWidth + spaceW DIV 2) DIV spaceW * spaceW
  587. ELSE
  588. rd.w := stdTabWidth
  589. END;
  590. rd.tabIndex := TextRulers.maxTabs; rd.tabType := {}
  591. END
  592. | ORD(line):
  593. rd.setterOpts := {lineBreak}; rd.w := 0; rd.endW := 0
  594. | ORD(para):
  595. (*
  596. IF rd.hideMarks THEN
  597. rd.w := 0; rd.h := 0; rd.dsc := 0
  598. ELSE
  599. rd.w := ExtendToEOL(rd.x, Right(ra, rd.vw)) + 1
  600. END;
  601. INC(rd.h, ra.lead);
  602. rd.textOpts := {TextModels.hideable};
  603. rd.endW := rd.w
  604. *)
  605. (*
  606. rd.setterOpts := {lineBreak};
  607. *)
  608. IF rd.hideMarks THEN rd.h := 0; rd.dsc := 0 END;
  609. INC(rd.h, ra.lead); rd.textOpts := {TextModels.hideable};
  610. IF (rd.view = NIL) OR ~(rd.view IS TextRulers.Ruler) THEN
  611. rd.w := 10000 * Ports.mm (* ExtendToEOL(rd.x, Right(ra, rd.vw)) + 1 *)
  612. END;
  613. rd.endW := rd.w
  614. (**)
  615. | ORD(" "):
  616. rd.setterOpts := {flexWidth};
  617. rd.w := rd.attr.font.StringWidth(rd.string); rd.endW := 0; INC(rd.spaces)
  618. | ORD(zwspace):
  619. rd.w := 0; rd.endW := 0
  620. | ORD(digitspace):
  621. rd.setterOpts := {wordPart};
  622. rd.w := rd.attr.font.StringWidth("0"); rd.endW := rd.w
  623. | ORD("-"):
  624. rd.setterOpts := {};
  625. rd.w := rd.attr.font.StringWidth("-"); rd.endW := rd.w
  626. | ORD(hyphen):
  627. rd.setterOpts := {};
  628. rd.string[0] := "-" (*softhyphen*);
  629. rd.w := rd.attr.font.StringWidth("-" (*softhyphen*)); rd.endW := rd.w
  630. | ORD(nbhyphen):
  631. rd.setterOpts := {wordJoin, wordPart};
  632. rd.string[0] := "-" (*softhyphen*);
  633. rd.w := rd.attr.font.StringWidth("-" (*softhyphen*)); rd.endW := rd.w
  634. | ORD(softhyphen):
  635. rd.setterOpts := {wordPart}; rd.textOpts := {TextModels.hideable};
  636. rd.string[0] := "-";
  637. rd.endW := rd.attr.font.StringWidth("-" (*softhyphen*));
  638. IF rd.hideMarks THEN rd.w := 0 ELSE rd.w := rd.endW END
  639. ELSE
  640. rd.setterOpts := {wordJoin};
  641. IF WordPart(rd.string[0], rd.r.char) THEN INCL(rd.setterOpts, wordPart) END;
  642. rd.w := rd.attr.font.StringWidth(rd.string); rd.endW := rd.w
  643. END
  644. END SpecialChar;
  645. (*
  646. PROCEDURE LongChar (rd: StdReader);
  647. VAR ra: TextRulers.Attributes;
  648. BEGIN
  649. ra := rd.ruler.style.attr;
  650. rd.setterOpts := {wordJoin, wordPart};
  651. rd.w := rd.attr.font.StringWidth(rd.string); rd.endW := rd.w
  652. END LongChar;
  653. *)
  654. PROCEDURE (rd: StdReader) Read;
  655. (* pre: connected *)
  656. VAR ra: TextRulers.Attributes; asc, dsc, w: INTEGER; ch: CHAR;
  657. BEGIN
  658. rd.Read^;
  659. IF ~rd.eot THEN
  660. IF rd.view = NIL THEN
  661. rd.attr.font.GetBounds(asc, dsc, w);
  662. rd.h := asc + dsc; rd.dsc := dsc
  663. ELSE
  664. GetViewPref(rd)
  665. END;
  666. IF (rd.view = NIL) OR (TextModels.maskChar IN rd.textOpts) THEN
  667. ch := rd.string[0];
  668. IF (rd.view = NIL)
  669. & ( (" " < ch) & (ch < "~") & (ch # "-")
  670. OR (ch = digitspace)
  671. OR (ch >= nbspace) & (ch # softhyphen)
  672. )
  673. THEN
  674. GatherString(rd)
  675. ELSE
  676. SpecialChar(rd)
  677. END
  678. END
  679. ELSE
  680. ra := rd.ruler.style.attr;
  681. rd.w := 0; rd.endW := 0; rd.h := ra.asc + ra.dsc; rd.dsc := ra.dsc
  682. END
  683. END Read;
  684. PROCEDURE (rd: StdReader) AdjustWidth (start, pos: INTEGER; IN box: LineBox; VAR w: INTEGER);
  685. VAR i: INTEGER; form: SET;
  686. BEGIN
  687. IF box.adj & (pos >= start + box.adjOff) THEN
  688. form := box.ruler.style.attr.opts * adjustMask;
  689. IF (form = blocked) & (rd.string[0] = " ") THEN
  690. INC(w, box.adjW DIV box.spaces)
  691. ELSIF (form # blocked) & (rd.string[0] = tab) THEN
  692. INC(w, box.adjW) (* is this correct ??? *)
  693. END
  694. END;
  695. i := rd.tabIndex; (* rd.string[0] = tab => i >= 0 *)
  696. IF (rd.string[0] = tab) & (i < box.ruler.style.attr.tabs.len) THEN
  697. w := box.tabW[i]
  698. END
  699. END AdjustWidth;
  700. PROCEDURE (rd: StdReader) SplitWidth (w: INTEGER): INTEGER;
  701. BEGIN
  702. IF (rd.string[1] = 0X) & (rd.view = NIL) THEN
  703. RETURN (w + 1) DIV 2
  704. ELSE RETURN w
  705. END
  706. END SplitWidth;
  707. (* Worder *)
  708. PROCEDURE SetWorder (VAR w: Worder; s: StdSetter; pos: INTEGER; OUT start: INTEGER);
  709. CONST wordCutoff = LEN(s.rd.string);
  710. BEGIN
  711. start := s.ThisSequence(pos);
  712. IF pos - start >= wordCutoff THEN
  713. start := pos; WHILE pos - start < wordCutoff DO start := s.PreviousLine(start) END
  714. END;
  715. s.GetLine(start, w.box); w.next := start + w.box.len;
  716. s.rd.Set(s.r, s.text, w.box.left, start, w.box.ruler, w.box.rpos, s.vw, s.hideMarks);
  717. w.i := 0; s.rd.string[0] := 0X
  718. END SetWorder;
  719. PROCEDURE StepWorder (VAR w: Worder; s: StdSetter; VAR part: BOOLEAN);
  720. VAR rd: Reader;
  721. BEGIN
  722. rd := s.rd;
  723. IF rd.string[w.i] = 0X THEN
  724. IF rd.pos < w.next THEN
  725. rd.Read; w.i := 0
  726. ELSE
  727. IF ~w.box.eot THEN
  728. s.GetLine(w.next, w.box);
  729. s.rd.Set(s.r, s.text, w.box.left, w.next, w.box.ruler, w.box.rpos, s.vw, s.hideMarks);
  730. rd.Read; w.i := 0;
  731. INC(w.next, w.box.len)
  732. ELSE
  733. rd.string[0] := 0X
  734. END
  735. END
  736. END;
  737. IF rd.string[0] = 0X THEN (* end of text *)
  738. part := TRUE
  739. ELSIF rd.string[1] = 0X THEN (* special character *)
  740. part := wordPart IN rd.setterOpts; INC(w.i)
  741. ELSE (* gathered sString *)
  742. part := WordPart(rd.string[w.i], rd.string[w.i + 1]); INC(w.i)
  743. END
  744. END StepWorder;
  745. (* StdSetter *)
  746. PROCEDURE (s: StdSetter) CopyFrom (source: Stores.Store);
  747. BEGIN
  748. s.CopyFrom^(source);
  749. WITH source: StdSetter DO
  750. s.ruler := source.ruler; s.rpos := source.rpos; s.key := source.key;
  751. s.rd := NIL; s.r := NIL
  752. END
  753. END CopyFrom;
  754. PROCEDURE (s: StdSetter) Externalize (VAR wr: Stores.Writer);
  755. BEGIN
  756. s.Externalize^(wr);
  757. wr.WriteVersion(maxStdVersion)
  758. END Externalize;
  759. PROCEDURE (s: StdSetter) Internalize (VAR rd: Stores.Reader);
  760. VAR thisVersion: INTEGER;
  761. BEGIN
  762. s.Internalize^(rd);
  763. IF rd.cancelled THEN RETURN END;
  764. rd.ReadVersion(minVersion, maxStdVersion, thisVersion);
  765. IF rd.cancelled THEN RETURN END;
  766. s.text := NIL; s.defRuler := NIL; s.ruler := NIL; s.rd := NIL; s.r := NIL
  767. END Internalize;
  768. PROCEDURE (s: StdSetter) ConnectTo (text: TextModels.Model;
  769. defRuler: TextRulers.Ruler; vw: INTEGER; hideMarks: BOOLEAN
  770. );
  771. BEGIN
  772. s.ConnectTo^(text, defRuler, vw, hideMarks);
  773. ClearCache(s.key);
  774. IF text # NIL THEN
  775. s.ruler := defRuler; s.rpos := -1; s.key := nextKey; INC(nextKey)
  776. ELSE
  777. s.ruler := NIL
  778. END
  779. END ConnectTo;
  780. PROCEDURE (s: StdSetter) ThisPage (pageH: INTEGER; pageNo: INTEGER): INTEGER;
  781. (* pre: connected, 0 <= pageNo *)
  782. (* post: (result = -1) & (pageNo >= maxPageNo) OR (result = pageStart(pageNo)) *)
  783. VAR start, prev: INTEGER;
  784. BEGIN
  785. ASSERT(s.text # NIL, 20); ASSERT(pageNo >= 0, 21);
  786. start := 0;
  787. WHILE pageNo > 0 DO
  788. prev := start; DEC(pageNo); start := s.NextPage(pageH, start);
  789. IF start = prev THEN start := -1; pageNo := 0 END
  790. END;
  791. RETURN start
  792. END ThisPage;
  793. PROCEDURE (s: StdSetter) NextPage (pageH: INTEGER; start: INTEGER): INTEGER;
  794. (* pre: connected, ThisPage(pageH, x) = start *)
  795. (* post: (result = s.text.Length()) OR result = next-pageStart(start) *)
  796. CONST
  797. noBreakInside = TextRulers.noBreakInside;
  798. pageBreak = TextRulers.pageBreak;
  799. parJoin = TextRulers.parJoin;
  800. regular = 0; protectInside = 1; joinFirst = 2; joinNext = 3; confirmSpace = 4; (* state *)
  801. VAR
  802. box: LineBox; ra: TextRulers.Attributes;
  803. h, asc, dsc, backup, pos, state: INTEGER; isRuler: BOOLEAN;
  804. PROCEDURE FetchNextLine;
  805. BEGIN
  806. s.GetLine(pos, box);
  807. IF box.len > 0 THEN
  808. ra := box.ruler.style.attr; isRuler := box.rpos = pos;
  809. asc := box.asc + s.GridOffset(dsc, box); dsc := box.dsc; h := asc + dsc
  810. END
  811. END FetchNextLine;
  812. PROCEDURE HandleRuler;
  813. CONST norm = 0; nbi = 1; pj = 2;
  814. VAR strength: INTEGER;
  815. BEGIN
  816. IF isRuler & (pos > start) & ~(pageBreak IN ra.opts) THEN
  817. IF parJoin IN ra.opts THEN strength := pj
  818. ELSIF noBreakInside IN ra.opts THEN strength := nbi
  819. ELSE strength := norm
  820. END;
  821. CASE state OF
  822. | regular:
  823. CASE strength OF
  824. | norm:
  825. | nbi: state := protectInside; backup := pos
  826. | pj: state := joinFirst; backup := pos
  827. END
  828. | protectInside:
  829. CASE strength OF
  830. | norm: state := regular
  831. | nbi: backup := pos
  832. | pj: state := joinFirst; backup := pos
  833. END
  834. | joinFirst:
  835. CASE strength OF
  836. | norm: state := confirmSpace
  837. | nbi: state := protectInside
  838. | pj: state := joinNext
  839. END
  840. | joinNext:
  841. CASE strength OF
  842. | norm: state := confirmSpace
  843. | nbi: state := protectInside
  844. | pj:
  845. END
  846. | confirmSpace:
  847. CASE strength OF
  848. | norm: state := regular
  849. | nbi: state := protectInside; backup := pos
  850. | pj: state := joinFirst; backup := pos
  851. END
  852. END
  853. END
  854. END HandleRuler;
  855. PROCEDURE IsEmptyLine (): BOOLEAN;
  856. BEGIN
  857. RETURN (box.right = box.left) OR s.hideMarks & isRuler & ~(pageBreak IN ra.opts)
  858. END IsEmptyLine;
  859. BEGIN
  860. ASSERT(s.text # NIL, 20);
  861. ASSERT(0 <= start, 21); ASSERT(start <= s.text.Length(), 22);
  862. pos := start; dsc := -1;
  863. FetchNextLine;
  864. IF box.len > 0 THEN
  865. state := regular;
  866. REPEAT (* at least one line per page *)
  867. HandleRuler; DEC(pageH, h); INC(pos, box.len);
  868. IF (state = confirmSpace) & ~IsEmptyLine() THEN state := regular END;
  869. FetchNextLine
  870. UNTIL (box.len = 0) OR (pageH - h < 0) OR isRuler & (pageBreak IN ra.opts);
  871. IF ~isRuler OR ~(pageBreak IN ra.opts) THEN
  872. WHILE (box.len > 0) & IsEmptyLine() DO (* skip empty lines at top of page *)
  873. HandleRuler; INC(pos, box.len); FetchNextLine
  874. END
  875. END;
  876. HandleRuler;
  877. IF (state # regular) & ~(isRuler & (pageBreak IN ra.opts) OR (box.len = 0)) THEN pos := backup END
  878. END;
  879. RETURN pos
  880. END NextPage;
  881. PROCEDURE (s: StdSetter) NextSequence (start: INTEGER): INTEGER;
  882. (* pre: connected, ThisSequence(start) = start *)
  883. (* post: (result = start) & last-line(start) OR (ThisSequence(t, result - 1) = start) *)
  884. VAR rd: TextModels.Reader; ch: CHAR;
  885. BEGIN
  886. ASSERT(s.text # NIL, 20);
  887. s.r := s.text.NewReader(s.r); rd := s.r; rd.SetPos(start);
  888. REPEAT rd.ReadChar(ch) UNTIL rd.eot OR (ch = line) OR (ch = para);
  889. IF rd.eot THEN RETURN start ELSE RETURN rd.Pos() END
  890. END NextSequence;
  891. PROCEDURE (s: StdSetter) ThisSequence (pos: INTEGER): INTEGER;
  892. (* pre: connected, 0 <= pos <= t.Length() *)
  893. (* post: (result = 0) OR (char(result - 1) IN {line, para}) *)
  894. VAR rd: TextModels.Reader; start, limit: INTEGER; ch: CHAR;
  895. BEGIN
  896. ASSERT(s.text # NIL, 20); ASSERT(0 <= pos, 21); ASSERT(pos <= s.text.Length(), 22);
  897. IF pos = 0 THEN
  898. RETURN 0
  899. ELSE
  900. start := CachedSeqStart(s.key, pos);
  901. IF start < 0 THEN
  902. s.r := s.text.NewReader(s.r); rd := s.r; rd.SetPos(pos);
  903. limit := paraShutoff;
  904. REPEAT rd.ReadPrevChar(ch); DEC(limit)
  905. UNTIL rd.eot OR (ch = line) OR (ch = para) OR (limit = 0);
  906. IF rd.eot THEN start := 0 ELSE start := rd.Pos() + 1 END;
  907. AddSeqStartToCache(s.key, pos, start)
  908. END;
  909. RETURN start
  910. END
  911. END ThisSequence;
  912. PROCEDURE (s: StdSetter) PreviousSequence (start: INTEGER): INTEGER;
  913. (* pre: connected, ThisSequence(t, start) = start *)
  914. (* post: (result = 0) & (start = 0) OR (result = ThisSequence(t, start - 1)) *)
  915. BEGIN
  916. IF start <= 1 THEN RETURN 0 ELSE RETURN s.ThisSequence(start - 1) END
  917. END PreviousSequence;
  918. PROCEDURE (s: StdSetter) ThisLine (pos: INTEGER): INTEGER;
  919. (* pre: connected *)
  920. VAR start, next: INTEGER;
  921. BEGIN
  922. next := s.ThisSequence(pos);
  923. REPEAT start := next; next := s.NextLine(start) UNTIL (next > pos) OR (next = start);
  924. RETURN start
  925. END ThisLine;
  926. PROCEDURE (s: StdSetter) NextLine (start: INTEGER): INTEGER;
  927. (* pre: connected, ThisLine(start) = start *)
  928. (* post: (result = 0) & (start = 0) OR
  929. (result = start) & last-line(start) OR
  930. (ThisLine(result - 1) = start) *)
  931. VAR box: LineBox; len: INTEGER; i: INTEGER; eot: BOOLEAN;
  932. BEGIN
  933. i := CacheIndex(s.key, start);
  934. IF i >= 0 THEN
  935. len := boxCache[i].line.len; eot := boxCache[i].line.eot
  936. ELSE
  937. s.GetLine(start, box); len := box.len; eot := box.eot
  938. END;
  939. IF ~eot THEN RETURN start + len ELSE RETURN start END
  940. END NextLine;
  941. PROCEDURE (s: StdSetter) PreviousLine (start: INTEGER): INTEGER;
  942. (* pre: connected, ThisLine(start) = start *)
  943. (* post: (result = 0) & (start = 0) OR (result = ThisLine(start - 1)) *)
  944. BEGIN
  945. IF start <= 1 THEN start := 0 ELSE start := s.ThisLine(start - 1) END;
  946. RETURN start
  947. END PreviousLine;
  948. PROCEDURE (s: StdSetter) GetWord (pos: INTEGER; OUT beg, end: INTEGER);
  949. (* pre: connected, 0 <= pos <= s.text.Length() *)
  950. (* post: beg <= pos <= end *)
  951. CONST wordCutoff = LEN(s.rd.string);
  952. VAR w: Worder; part: BOOLEAN;
  953. BEGIN
  954. ASSERT(s.text # NIL, 20); ASSERT(0 <= pos, 21); ASSERT(pos <= s.text.Length(), 22);
  955. SetWorder(w, s, pos, beg); end := beg;
  956. REPEAT
  957. StepWorder(w, s, part); INC(end);
  958. IF ~part THEN beg := end END
  959. UNTIL end >= pos;
  960. DEC(end);
  961. REPEAT
  962. StepWorder(w, s, part); INC(end)
  963. UNTIL ~part OR (s.rd.string[0] = 0X) OR (end - beg > wordCutoff)
  964. END GetWord;
  965. PROCEDURE (s: StdSetter) GetLine (start: INTEGER; OUT box: LineBox);
  966. VAR rd: Reader; ra: TextRulers.Attributes; brk: LineBox;
  967. d, off, right, w: INTEGER; i, tabsN: INTEGER; form: SET; adj: BOOLEAN; ch: CHAR;
  968. PROCEDURE TrueW (VAR b: LineBox; w: INTEGER): INTEGER;
  969. VAR i: INTEGER; type: SET;
  970. BEGIN
  971. i := rd.tabIndex;
  972. IF (0 <= i ) & (i < TextRulers.maxTabs) & (rd.string[0] # tab) THEN
  973. type := rd.tabType * {TextRulers.centerTab, TextRulers.rightTab};
  974. IF type = {TextRulers.centerTab} THEN
  975. DEC(w, b.tabW[i] - MAX(minTabWidth, b.tabW[i] - w DIV 2))
  976. ELSIF type = {TextRulers.rightTab} THEN
  977. DEC(w, b.tabW[i] - MAX(minTabWidth, b.tabW[i] - w))
  978. END
  979. END;
  980. RETURN w
  981. END TrueW;
  982. PROCEDURE Enclose (VAR b: LineBox; w: INTEGER);
  983. VAR off, i, d: INTEGER; type: SET;
  984. BEGIN
  985. b.len := rd.pos - start; INC(b.right, w);
  986. off := rd.attr.offset; i := rd.tabIndex;
  987. IF rd.h - rd.dsc + off > b.asc THEN b.asc := rd.h - rd.dsc + off END;
  988. IF rd.dsc - off > b.dsc THEN b.dsc := rd.dsc - off END;
  989. IF rd.view # NIL THEN b.views := TRUE END;
  990. IF (0 <= i ) & (i < TextRulers.maxTabs) THEN
  991. IF rd.string[0] = tab THEN
  992. b.tabW[i] := w
  993. ELSE
  994. type := rd.tabType * {TextRulers.centerTab, TextRulers.rightTab};
  995. IF type = {TextRulers.centerTab} THEN
  996. d := b.tabW[i] - MAX(minTabWidth, b.tabW[i] - w DIV 2);
  997. DEC(b.tabW[i], d); DEC(b.right, d)
  998. ELSIF type = {TextRulers.rightTab} THEN
  999. d := b.tabW[i] - MAX(minTabWidth, b.tabW[i] - w);
  1000. DEC(b.tabW[i], d); DEC(b.right, d)
  1001. END
  1002. END
  1003. END
  1004. END Enclose;
  1005. BEGIN
  1006. ASSERT(s.text # NIL, 20); ASSERT(0 <= start, 21); ASSERT(start <= s.text.Length(), 22);
  1007. i := CacheIndex(s.key, start);
  1008. IF i >= 0 THEN
  1009. GetFromCache(s, i, box)
  1010. ELSE
  1011. TextRulers.GetValidRuler(s.text, start, s.rpos, s.ruler, s.rpos);
  1012. IF s.rpos > start THEN s.ruler := s.defRuler; s.rpos := -1 END;
  1013. box.ruler := s.ruler; box.rpos := s.rpos;
  1014. ra := s.ruler.style.attr; tabsN := ra.tabs.len; right := Right(ra, s.vw);
  1015. s.r := s.text.NewReader(s.r);
  1016. IF start = 0 THEN s.r.SetPos(start); ch := para
  1017. ELSE s.r.SetPos(start - 1); s.r.ReadChar(ch)
  1018. END;
  1019. s.r.Read;
  1020. (*
  1021. IF s.r.char = para THEN box.rbox := ~s.hideMarks; box.bop := s.hideMarks; box.left := 0
  1022. ELSIF ch = para THEN box.rbox := FALSE; box.bop := TRUE; box.left := ra.first
  1023. ELSE box.rbox := FALSE; box.bop := FALSE; box.left := ra.left
  1024. END;
  1025. *)
  1026. IF s.r.char = para THEN box.rbox := TRUE; box.bop := FALSE; box.left := 0
  1027. ELSIF ch = para THEN box.rbox := FALSE; box.bop := TRUE; box.left := ra.first
  1028. ELSE box.rbox := FALSE; box.bop := FALSE; box.left := ra.left
  1029. END;
  1030. (**)
  1031. box.views := FALSE;
  1032. box.asc := 0; box.dsc := 0; box.right := box.left;
  1033. box.len := 0; box.adjOff := 0; box.spaces := 0;
  1034. brk.right := 0;
  1035. s.rd := s.NewReader(s.rd); rd := s.rd;
  1036. rd.Set(s.r, s.text, box.left, start, box.ruler, box.rpos, s.vw, s.hideMarks);
  1037. rd.Read;
  1038. WHILE ~rd.eot & (box.right + (*rd.w*) TrueW(box, rd.w) <= right)
  1039. & ~(lineBreak IN rd.setterOpts) DO
  1040. IF ~(wordJoin IN rd.setterOpts) & (box.right + rd.endW <= right) THEN
  1041. (*brk := box;*)
  1042. brk.len := box.len; brk.ruler := box.ruler; brk.rpos := box.rpos;
  1043. brk.left := box.left; brk.right := box.right; brk.asc := box.asc; brk.dsc := box.dsc;
  1044. brk.rbox := box.rbox; brk.bop := box.bop; brk.adj := box.adj; brk.eot := box.eot;
  1045. brk.views := box.views; brk.skipOff := box.skipOff; brk.adjOff := box.adjOff;
  1046. brk.spaces := box.spaces; brk.adjW := box.adjW;
  1047. i := 0; WHILE i < tabsN DO brk.tabW[i] := box.tabW[i]; INC(i) END;
  1048. (*---*)
  1049. Enclose(brk, rd.endW);
  1050. brk.eot := rd.r.eot (* rd.r.eot one ahead of rd.eot *)
  1051. END;
  1052. box.adjOff := rd.adjStart - start; box.spaces := rd.spaces;
  1053. Enclose(box, rd.w);
  1054. rd.x := box.right; rd.Read
  1055. END;
  1056. IF (lineBreak IN rd.setterOpts) (* & ~box.rbox *) THEN Enclose(box, 0) END;
  1057. box.eot := rd.eot; adj := FALSE; box.skipOff := box.len;
  1058. IF box.right + rd.w > right THEN (* rd.w > 0 => ~rd.eot & ~(lineBreak IN setterOpts) *)
  1059. IF ~(wordJoin IN rd.setterOpts) & (box.right + rd.endW <= right) THEN
  1060. IF rd.string[0] = " " THEN DEC(box.spaces) END;
  1061. Enclose(box, rd.endW);
  1062. adj := TRUE
  1063. ELSIF brk.right > 0 THEN
  1064. (*box := brk;*)
  1065. box.len := brk.len; box.ruler := brk.ruler; box.rpos := brk.rpos;
  1066. box.left := brk.left; box.right := brk.right; box.asc := brk.asc; box.dsc := brk.dsc;
  1067. box.rbox := brk.rbox; box.bop := brk.bop; box.adj := brk.adj; box.eot := brk.eot;
  1068. box.views := brk.views; box.skipOff := brk.skipOff; box.adjOff := brk.adjOff;
  1069. box.spaces := brk.spaces; box.adjW := brk.adjW;
  1070. i := 0; WHILE i < tabsN DO box.tabW[i] := brk.tabW[i]; INC(i) END;
  1071. (*---*)
  1072. box.skipOff := box.len - 1; adj := TRUE
  1073. ELSIF box.right = box.left THEN
  1074. Enclose(box, rd.w) (* force at least one per line *)
  1075. END
  1076. ELSIF (box.right = box.left) & box.eot THEN
  1077. box.asc := ra.asc; box.dsc := ra.dsc (* force empty line to ruler's default height *)
  1078. END;
  1079. box.adj := FALSE;
  1080. d := right - box.right;
  1081. IF d > 0 THEN
  1082. form := ra.opts * adjustMask;
  1083. IF form = blocked THEN
  1084. IF adj & (box.spaces > 0) THEN
  1085. box.right := right; box.adj := TRUE; box.adjW := d
  1086. END
  1087. ELSIF form = rightFlush THEN
  1088. IF box.adjOff > 0 THEN
  1089. box.adjW := d; box.adj := TRUE
  1090. ELSE
  1091. INC(box.left, d)
  1092. END;
  1093. box.right := right
  1094. ELSIF form = centered THEN
  1095. IF box.adjOff > 0 THEN
  1096. box.adjW := d DIV 2; box.adj := TRUE
  1097. ELSE
  1098. INC(box.left, d DIV 2)
  1099. END;
  1100. INC(box.right, d DIV 2)
  1101. END
  1102. END;
  1103. AddToCache(s.key, start, box)
  1104. END;
  1105. ASSERT(box.eot OR (box.len > 0), 100)
  1106. END GetLine;
  1107. PROCEDURE (s: StdSetter) GetBox (start, end, maxW, maxH: INTEGER; OUT w, h: INTEGER);
  1108. VAR box: LineBox; asc, dsc: INTEGER;
  1109. BEGIN
  1110. ASSERT(s.text # NIL, 20);
  1111. ASSERT(0 <= start, 21);
  1112. ASSERT(start <= end, 22);
  1113. ASSERT(end <= s.text.Length(), 23);
  1114. w := 0; h := 0; dsc := -1;
  1115. IF maxW <= Views.undefined THEN maxW := MAX(INTEGER) END;
  1116. IF maxH <= Views.undefined THEN maxH := MAX(INTEGER) END;
  1117. WHILE (start < end) & (h < maxH) DO
  1118. s.GetLine(start, box);
  1119. IF box.rbox THEN w := MAX(w, Right(box.ruler.style.attr, s.vw))
  1120. ELSE w := MAX(w, box.right)
  1121. END;
  1122. asc := box.asc + s.GridOffset(dsc, box); dsc := box.dsc;
  1123. INC(start, box.len); INC(h, asc + dsc)
  1124. END;
  1125. w := MIN(w, maxW); h := MIN(h, maxH)
  1126. END GetBox;
  1127. PROCEDURE (s: StdSetter) NewReader (old: Reader): Reader;
  1128. (* pre: connected *)
  1129. VAR rd: StdReader;
  1130. BEGIN
  1131. ASSERT(s.text # NIL, 20);
  1132. IF (old # NIL) & (old IS StdReader) THEN RETURN old
  1133. ELSE NEW(rd); RETURN rd
  1134. END
  1135. END NewReader;
  1136. PROCEDURE (s: StdSetter) GridOffset (dsc: INTEGER; IN box: LineBox): INTEGER;
  1137. VAR ra: TextRulers.Attributes; h, h0: INTEGER;
  1138. (* minimal possible line spacing h0, minimal legal line spacing h *)
  1139. BEGIN
  1140. IF ~box.rbox THEN
  1141. ra := box.ruler.style.attr;
  1142. IF dsc < 0 THEN
  1143. RETURN 0 (* no longer try to correct first line's grid position -- should be done when printing... *)
  1144. (*
  1145. h0 := box.asc; h := ra.asc;
  1146. IF h < h0 THEN (* override legal spacing if to small *)
  1147. h := h - (h - h0) DIV ra.grid * ra.grid (* adjust to next larger grid line *)
  1148. END;
  1149. RETURN h - h0
  1150. *)
  1151. ELSE
  1152. h0 := box.asc + dsc; h := ra.asc + ra.dsc;
  1153. IF h < h0 THEN h := h0 END; (* override legal spacing if to small *)
  1154. RETURN - (-h) DIV ra.grid * ra.grid - h0 (* adjust to next larger grid line *)
  1155. END
  1156. ELSE
  1157. RETURN 0
  1158. END
  1159. END GridOffset;
  1160. (* StdDirectory *)
  1161. PROCEDURE (d: StdDirectory) New (): Setter;
  1162. VAR s: StdSetter;
  1163. BEGIN
  1164. NEW(s); s.text := NIL; RETURN s
  1165. END New;
  1166. (** miscellaneous **)
  1167. PROCEDURE Init;
  1168. VAR d: StdDirectory;
  1169. BEGIN
  1170. InitCache;
  1171. NEW(d); dir := d; stdDir := d
  1172. END Init;
  1173. PROCEDURE SetDir* (d: Directory);
  1174. BEGIN
  1175. ASSERT(d # NIL, 20); dir := d
  1176. END SetDir;
  1177. BEGIN
  1178. Init
  1179. END TextSetters.