// GEDPARA.SR	Paragraph 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
	cpmin
	cpmax
	readsel
	stcompare
	cpadjust2
	cppara
	parabounds
	cpparabounds
	paracp
	paraspec
	gotparaspec
	specstate
	nextspecstate
	gcspecs
	freespec
	ckspecs
	cpadjustlist
	parsespec
	unparsespec
	putscrwd
	getscrwd
	finishchanges
	codechange
	changeformata
	receivechange
	setparaspec
	setparacp
	invalidateband
	invalidatedisplay
	compatible
	subspec
	deletesubspec
	insertsubspec
	mergespecs
	discardspecs
	acquirespecs
	replacespec
	forgetspec
	uadjust
	paradetails
	specdetails
	dupspec
	selectsel
	macpara
	compactspec
	makeroominspec
	bubblesegs
	wholeparas
	lastparacp
	discardpages
	wholepages
	inheap // ** take out calls when thoroughly debugged
	cpc
	]

// Incoming statics

external
	[
	rgdlfirst
	rgdllast
	rgmaxdl
	macww
	rgdoc
	vdoc
	vcp
	vchremain
	rgmaccp
	rgcpfdispl
	rgcplast
	vxleftmarg
	vxrightmarg
	cpscrt
	vdlhint
	vpara
	rgpara
	currentspec
	rgdirty
	vdeltacp
	selarg
	rgprogram
	fdebug
	otherspec
	]

// Outgoing procedures

external
	[
	fdeletea
	finserta
	finsertk
	finsertstring
	finsertparastring
	splitpara
	mergeparas
	copyparas
	deleteparas
	insertparas
	]

// Outgoing statics
external
	[
	vcpfinsert
	]

// Local statics

static	[
	vgrew
	vcpfinsert
	]

let fdeletea(doc, cp1, cp2) = valof
[
if cpc(cp1, cp2) gr 0 then resultis cp1
let page1, page2 = nil, nil
if wholepages(doc, cp1, cp2, lv page1, lv page2) then
	discardpages(doc, page1, page2)
let para1 = cppara(doc, cp1)
let para2 = cppara(doc, cp2)
if wholeparas(doc, cp1, cp2) then
	[ // delete an integral number of paragraphs
	cp1 = deleteparas(doc, para1, para2)
	if fdebug then ckspecs() // **
	resultis cp1
	]
if para1 ne para2 then errhlt("XXD")
deletesubspec(doc, para1, cp1, cp2) // delete a subparagraph
deletea(doc, cp1, cp2)
if fdebug then ckspecs() // **
resultis cp1
]

and finserta(docdest, cpdest, doc, cp1, cp2) = valof
[
vgrew = false
if cpc(cp1, cp2) gr 0 then
	[
	vcpfinsert = cpdest ;
	resultis cpdest;
	]
let para1 = cppara(doc, cp1)
let para2 = cppara(doc, cp2)
if wholeparas(doc, cp1, cp2) then
	[ // paste an integral number of paragraphs
	if rgprogram ! docdest then errhlt("PIP")
	let para = splitpara(docdest, cpdest, false)
	if vgrew & doc eq docdest & cpc(cp1+1, cpdest) gr 0 then
		[
		para1 = para1 + 1
		para2 = para2 + 1
		]
	resultis insertparas(docdest, para, doc, para1, para2)
	]
if para1 ne para2 then errhlt("XXI")
if cpc(cpdest,lastparacp(docdest)) ge 0 do splitpara(docdest,cpdest,true)
insertsubspec(docdest, cpdest, doc, cp1, cp2)
inserta(docdest, cpdest, doc, cp1, cp2)
vcpfinsert = cpdest + cp2 + 1 - cp1
if fdebug then ckspecs() // **
resultis cpdest
]

and finsertk(doc, cp, nchars) = valof
[
// Note -- setpcsiz may call this with nchars ls 0????
let para = cppara(doc, cp)
if para eq macpara(doc)-2 then splitpara(doc, cp, true)
unless nchars do resultis cp
let spec, siz, looks, changes, rcp, r = nil, nil, nil, nil, nil, nil
paradetails(doc, para, lv spec, cp-1)
spec >> SPEC.dirty = true
if r ge siz-2 & siz ge 3 then r = siz-3 // keep hdr ptr same
for i = r+1 to siz-1 do changes!i = changes!i + nchars
if rcp eq -1 & siz eq 2 then // special case -- empty paragraph
	[
	makeroominspec(doc, para, spec, 2)
	paradetails(doc, para, lv spec)
	spec >> SPEC.siz = bubblesegs(siz, 1, 1, changes, looks)
	changes ! 1 = nchars
	]
resultis cp
]

and finsertstring(doc, cp, string) = valof
[
let siz = stsize(string)
cp = finsertk(doc, cp, siz)
insertstring(doc, cp, string)
vcpfinsert = cp + siz
if fdebug then ckspecs()
resultis cp
]

and finsertparastring(doc, para, trailerstring, textstring) = valof
[
insertparas(doc, para, doc, macpara(doc)-2, macpara(doc)-2) // dummy
let cp = paracp(doc, para)
insertstring(doc, cp+1, trailerstring) // after chtrailer
insertstring(doc, cp, textstring)
forgetspec(doc, para)
compactspec(parsespec(doc, para, 0))
vcpfinsert = paracp(doc, para+1)
if fdebug then ckspecs()
resultis cp
]

and splitpara(doc, cp, always) = valof
[
// Make two paragraphs where there is now one
//	But if not "always", don't split at the front
// Force cp out of the trailer
// If at beginning or end of a paragraph, insert an empty paragraph
// Else...
// Insert empty trailer at split point
// Make room in tables for the new paragraph
// Make a spec for it out of the tail of the old paragraph
// Replace the spec of the old paragraph by its head
// Return the number of the new paragraph

let tex, b, e = nil, nil, nil
let para = cpparabounds(doc, cp, lv tex, lv b, lv e)
if rgprogram ! doc then resultis para
cp = cpmin(cp, b)
let newpara = para + 1
test cp eq tex
ifso	[
	if not always then resultis para
	insertparas(doc, para, doc, macpara(doc)-2, macpara(doc)-2)
	]
ifnot	[
	finsertstring(doc, cp, "*032*N")
	b = b + 2
	e = e + 2
	acquirespecs(doc, para, 1)
	setparacp(doc, newpara, cp+2)
	otherspec = subspec(doc, para, cp+2, b-1)
	setparaspec(doc, para, subspec(doc, para, tex, cp-1))
	replacespec(doc, newpara, otherspec)
	otherspec = 0
	]
vgrew = true
resultis newpara
]

and mergeparas(doc, para1, para2) = valof
[
// Make one paragraph where there are now many
// Merge successive paragraphs into the last
// The trailer of each absorbed paragraph is deleted
// Finally, remove the extinct paragraphs from tables
// Return the cp that former para2+1 now begins at

if para1 ge para2 then resultis 0 // result irrelevant
let tex, b, e = nil, nil, nil
for para = para2-1 to para1 by -1 do
	[
	parabounds(doc, para, lv tex, lv b, lv e)
	deletea(doc, b, e)
	setparacp(doc, para2, b)
	paraspec(doc, para) >> SPEC.trailerlength = 0
	replacespec(doc, para2, mergespecs(doc,para, doc,para2))
	forgetspec(doc, para)
	]
discardspecs(doc, para1, para2-1)
setparacp(doc, para1, tex)
resultis b
]

and insertparas(docdest, paradest, doc, para1, para2) = valof
[
// Makes no changes to any document other than a straight text copy
// Returns the number of characters inserted into docdest

let nparas = para2 + 1 - para1
unless nparas gr 0 do resultis 0
let cpdest = paracp(docdest, paradest)
let tex1, b1, e1 = nil, nil, nil
let tex2, b2, e2 = nil, nil, nil
parabounds(doc, para1, lv tex1, lv b1, lv e1)
parabounds(doc, para2, lv tex2, lv b2, lv e2)
let cp1, cp2 = tex1, e2
let nchars = cp2+1-cp1
inserta(docdest, cpdest, doc, cp1, cp2)
if doc eq docdest & cpc(para1+1, paradest) gr 0 then
	[
	para1 = para1 + nparas
	cp1 = cp1 + nchars
	]
acquirespecs(docdest, paradest, nparas)
let cpd = cpdest - cp1
for p = 0 to nparas-1 do
	[
	setparacp(docdest, paradest+p, paracp(doc, para1+p) + cpd)
	setparaspec(docdest, paradest+p, dupspec(doc, para1+p))
	]
setparacp(docdest, paradest, cpdest) // attempt to paste before self
setparacp(docdest, paradest + nparas, cpdest + nchars)
vgrew = true
vcpfinsert = cpdest + nchars
if fdebug then ckspecs() // **
resultis cpdest
]

and deleteparas(doc, para1, para2) = valof
[
let cp1 = paracp(doc, para1)
let cp2 = paracp(doc, para2+1)-1
for para = para1 to para2 do forgetspec(doc, para)
discardspecs(doc, para1, para2)
deletea(doc, cp1, cp2)
if paracp(doc, para1) ne cp1 then errhlt("DPA") // ** para 0 bug?
resultis cp1
]

and uadjust(u, delta,
	pv1, pv2, pv3, pv4, pv5, pv6, pv7, pv8, pv9, pv10, pv11 ;
	numargs N) be
		for i = 0 to N-3 do
			[
			let locn = ((lv pv1) ! i)
			if cpc(@locn, u) ge 0 then
				@locn = @locn + delta
			]