// GEDSPEC.SR Paragraph spec editing get "BRAVO.DF" get "CHAR.DF" get "GINN.DF" // Incoming procedures external [ getint binsearcha getvch putvch mapscrcp errhlt stcopy stnum stappend stsize insertstring deletea inserta move movec enww min max readsel stcompare cpadjust2 cppara parabounds cpparabounds paracp paraspec gotparaspec ckspecs parsespec unparsespec compatible replacespec nulltrailer uadjust paradetails specdetails cpc makespec ] // Incoming statics external [ rgdlfirst rgdllast rgmaxdl macww rgdoc vdoc vcp vchremain rgmaccp rgcpfdispl rgcplast vxleftmarg vxrightmarg cpscrt vdlhint vpara rgpara vlookmod vlookbold vlookctrl vlookjust vlookul currentspec otherspec mphd rgdirty vdeltacp ] // Outgoing procedures external [ subspec deletesubspec insertsubspec mergespecs dupspec compactspec ] // Outgoing statics // Local statics let subspec(doc, para, cp1, cp2) = valof [ // Make a spec for span cp1:cp2 in doc's para // The span should not include the trailer of the paragraph // First convert cp's to relative // Find the spec entries that correspond // Make the new spec with just enough room + 2 // Copy the paragraph-wide format information // Copy the format changes, adjusting relative cp's accordingly // The new spec is dirty and has a null trailer // The text is at least a carriage return // The new spec is returned let spec,siz,looks,changes,rcp1,r1,rcp2,r2 = nil,nil,nil,nil,nil,nil,nil,nil paradetails(doc, para, lv spec, cp1, cp2) if rcp2 ls rcp1 then r2 = r1 - 1 let newsiz = r2+1-r1 + 2 let newspec = makespec(newsiz+2) paradetails(doc, para, lv spec) let newlooks, newchanges = nil,nil initspec(newspec, newsiz, spec, lv newlooks, lv newchanges) copychanges(newsiz-2,newlooks,newchanges,0,looks,changes,r1,-rcp1) newchanges ! 0 = 0 let tsiz = max(cp2+1-cp1, 0) newchanges ! (newsiz-2) = tsiz newchanges ! (newsiz-1) = tsiz + 2 resultis newspec ] and mergespecs(doc1, para1, doc2, para2) = valof [ // Merge two paragraphs currentspec = paraspec(doc1, para1) otherspec = paraspec(doc2, para2) resultis mergetwospecs(false) ] and deletesubspec(doc, para, cp1, cp2) be [ // Remove spec information about span cp1:cp2 in doc's para // The span should not include the terminal cr of the paragraph let tex, b, e = nil, nil, nil parabounds(doc, para, lv tex, lv b, lv e) replacespec(doc, para, mergesubspecs(doc, tex, cp1-1, doc, cp2+1, b-1)) ] and insertsubspec(docdest, cpdest, doc, cp1, cp2) be [ // Insert doc(cp1:cp2) format into docdest spec at cp // cp1 and cp2 are both in para let tex, b, e = nil, nil, nil let paradest = cpparabounds(docdest, cpdest, lv tex, lv b, lv e) replacespec(docdest, paradest, mergesubspecs( docdest, tex, cpdest-1, doc, cp1, cp2, docdest, cpdest, b-1 )) ] and mergesubspecs(doc, cp1, cp2, bdoc, bcp1, bcp2, cdoc, ccp1, ccp2; numargs N) = valof [ // Merge N subparagraphs into a new paragraph // statics are used because they are updated by enphp let spec = subspec(doc, cppara(doc, cp1), cp1, cp2) for i = 3 to N-3 by 3 do [ let otherdoc = (lv doc)!i let othercp1 = (lv cp1)!i let othercp2 = (lv cp2)!i if cpc(othercp1, othercp2) gr 0 then loop currentspec = spec otherspec = subspec(otherdoc, cppara(otherdoc, othercp1), othercp1, othercp2) spec = mergetwospecs(true) ] resultis spec ] and mergetwospecs(release) = valof [ // Make a spec that combines currentspec with otherspec // First make the new spec with just enough room + 2 // Copy the paragraph-wide format information from the 1st paragraph // Copy the format changes, adjusting relative cp's accordingly // Compact the new spec // The new spec is dirty and has a null trailer let siz1,looks1,changes1 = nil,nil,nil specdetails(currentspec, lv siz1) let siz2,looks2,changes2 = nil,nil,nil specdetails(otherspec, lv siz2) let len1 = changes1 ! (siz1-2) let newsiz = siz1 + siz2 - 2 let newspec = makespec(newsiz+2) specdetails(currentspec, lv siz1) specdetails(otherspec, lv siz2) let newlooks, newchanges = nil, nil initspec(newspec, newsiz, currentspec, lv newlooks, lv newchanges) copychanges(siz1-2, newlooks,newchanges,0, looks1,changes1,0, 0) copychanges(siz2-1, newlooks,newchanges,siz1-2, looks2,changes2,0, len1) newchanges ! (newsiz-1) = newchanges ! (newsiz-2) + 2 compactspec(newspec) if release then [ currentspec >> SPEC.doc = abandon otherspec >> SPEC.doc = abandon ] currentspec = 0 otherspec = 0 resultis newspec ] and initspec(spec, siz, oldspec, plooks, pchanges) be [ // Fill in the paragraph-wide info fields of a new spec similar to an old spec >> SPEC.dirty = true spec >> SPEC.trailerlength = 2 spec >> SPEC.siz = siz move(oldspec+firstformat, spec+firstformat, formatl) @plooks = spec + specbase @pchanges = @plooks + spec >> LIST.max ] and copychanges(hmany, looks, changes, r1, oldlooks, oldchanges, oldr, delta) be [ // Copy intra-paragraph format changes from an old to a new place // Relative cp's must be adjusted by delta let inc = looks eq oldlooks & r1 gr oldr? -1, 1 let i = inc gr 0? 0, hmany-1 for j = 1 to hmany do [ looks ! (r1+i) = oldlooks ! (oldr+i) changes ! (r1+i) = max(0, oldchanges ! (oldr+i) + delta) i = i + inc ] ] and compactspec(spec) be [ let siz, looks, changes = nil, nil, nil specdetails(spec, lv siz) let dest = 0 let src = 0 let hi = changes ! (siz-2) [ if changes ! src ge hi then break while changes ! src eq changes ! (src+1) do src = src + 1 if dest eq 0 % looks ! src ne looks ! (dest-1) then [ looks ! dest = looks ! src changes ! dest = changes ! src dest = dest + 1 ] src = src + 1 ] repeat changes ! dest = hi looks ! dest = 0 dest = dest + 1 changes ! dest = changes ! (siz-1) looks ! dest = 0 spec >> SPEC.siz = dest+1 spec >> SPEC.dirty = true ] and dupspec(doc, para) = valof [ let spec = gotparaspec(doc, para) if not spec % spec << odd then resultis spec let lim = spec >> SPEC.max let newspec = makespec(lim) let spec = gotparaspec(doc, para) let link = newspec >> SPEC.link move(spec, newspec, 2*lim + specbase) newspec >> SPEC.link = link resultis newspec ]