'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 5 August 2008 at 8:48:43 am'!

!OldMenuMorph methodsFor: 'modal control' stamp: 'jmv 7/23/2008 12:29'!
invokeModalAt: aPoint in: aWorld allowKeyboard: aBoolean
	"Invoke this menu and don't return until the user has chosen a value.
	See senders of this method for finding out how to use modal menu morphs."
	| w oldFocus |
	oldFocus _ aWorld primaryHand keyboardFocus.
	self popUpAt: aPoint forHand: aWorld primaryHand in: aWorld allowKeyboard: aBoolean.
	self isModalInvokationDone: false.
	w _ aWorld outermostWorldMorph. "containing hand"
	[self isInWorld & self isModalInvokationDone not] whileTrue: [w doOneSubCycle].
	self delete.
	oldFocus ifNotNil: [ aWorld primaryHand newKeyboardFocus: oldFocus ].
	^ self modalSelection! !


!OldMVCMenuMorph methodsFor: 'invoking' stamp: 'jmv 7/23/2008 12:24'!
invokeAt: aPoint in: aWorld allowKeyboard: aBoolean
	"Add this menu to the given world centered at the given point. Wait for the user to make a selection and answer it. The selection value returned is an integer in keeping with PopUpMenu, if the menu is converted from an MVC-style menu."
	"Details: This is invoked synchronously from the caller. In order to keep processing inputs and updating the screen while waiting for the user to respond, this method has its own version of the World's event loop." 
	| w oldFocus |
	self flag: #bob.		"is <aPoint> global or local?"
	self flag: #arNote.	"<aPoint> is local to aWorld"
	oldFocus _ aWorld primaryHand keyboardFocus.
	self popUpAt: aPoint forHand: aWorld primaryHand in: aWorld allowKeyboard: aBoolean.
	done _ false.
	w _ aWorld outermostWorldMorph. "containing hand"
	[self isInWorld & done not] whileTrue: [w doOneSubCycle].
	self delete.
	oldFocus ifNotNil: [ aWorld primaryHand newKeyboardFocus: oldFocus ].
	^ mvcSelection ! !


!ParagraphEditor methodsFor: 'new selection' stamp: 'jmv 7/23/2008 14:04'!
notify: aString at: anInteger in: aStream 
	"The compilation of text failed. The syntax error is noted as the argument, 
	aString. Insert it in the text at starting character position anInteger."

	| pos |
	pos _ self selectionInterval notEmpty
		ifTrue: [
			self startIndex + anInteger - 1 ]
		ifFalse: [anInteger].
	self insertAndSelect: aString at: (pos max: 1)! !


!Parser methodsFor: 'error correction' stamp: 'jmv 7/25/2008 10:39'!
correctSelector: proposedKeyword wordIntervals: spots exprInterval: expInt ifAbort: abortAction
	"Correct the proposedKeyword to some selector symbol, correcting the original text if such action is indicated.  abortAction is invoked if the proposedKeyword couldn't be converted into a valid selector.  Spots is an ordered collection of intervals within the test stream of the for each of the keyword parts."

	| alternatives aStream choice correctSelector lines firstLine |
	"If we can't ask the user, assume that the keyword will be defined later"
	self interactive ifFalse: [ ^ proposedKeyword asSymbol ].

	alternatives _ Symbol possibleSelectorsFor: proposedKeyword.

	aStream _ WriteStream on: (String new: 200).
	aStream nextPutAll: (proposedKeyword contractTo: 35); cr.
	firstLine _ 1.
 	alternatives do:
		[:sel | aStream nextPutAll: (sel contractTo: 35); nextPut: Character cr].
	aStream nextPutAll: 'cancel'.
	lines _ Array with: firstLine with: (alternatives size + firstLine).
	
	choice _ (PopUpMenu labels: aStream contents lines: lines)
		startUpWithCaption: 
'Unknown selector, please 
confirm, correct, or cancel'.

	(choice = 0) | (choice > (lines at: 2))
		ifTrue: [
			requestor selectionInterval isEmpty 
				ifTrue: [ requestor selectFrom: spots first first to: spots last last; select ].
			^ abortAction value ].

	choice = 1 ifTrue: [ ^ proposedKeyword asSymbol ].
	correctSelector _ alternatives at: choice - 1.
	self substituteSelector: correctSelector keywords wordIntervals: spots.
	((proposedKeyword last ~~ $:) and: [correctSelector last == $:]) ifTrue: [
		^ abortAction value].
	^ correctSelector.
! !

!Parser methodsFor: 'error correction' stamp: 'jmv 7/23/2008 14:25'!
correctVariable: proposedVariable interval: spot
	"Correct the proposedVariable to a known variable, or declare it as a new
	variable if such action is requested.  We support declaring lowercase
	variables as temps or inst-vars, and uppercase variables as Globals or 
	ClassVars, depending on whether the context is nil (class=UndefinedObject).
	Spot is the interval within the test stream of the variable.
	rr 3/4/2004 10:26 : adds the option to define a new class. "

	| tempIvar labels actions lines alternatives binding choice action start end |
	"Check if this is an i-var, that has been corrected already (ugly)"
	(encoder classEncoding instVarNames includes: proposedVariable) ifTrue: [
		^LiteralVariableNode new 
			name: proposedVariable index: (encoder classEncoding instVarNames indexOf: proposedVariable) - 1 type: 1;
			yourself ].

	"If we can't ask the user for correction, make it undeclared"
	self interactive 
		ifFalse: [ ^encoder undeclared: proposedVariable ].

	"First check to see if the requestor knows anything about the variable"
	tempIvar _ proposedVariable first isLowercase.
	(tempIvar and: [ (binding _ requestor bindingOf: proposedVariable) notNil ])
		ifTrue: [ ^encoder global: binding name: proposedVariable ].

	"Build the menu with alternatives"
	labels _ OrderedCollection new. actions _ OrderedCollection new. lines _ OrderedCollection new.
	alternatives _ encoder possibleVariablesFor: proposedVariable.
	tempIvar 
		ifTrue: [ 
			labels add: 'declare temp'. 
			actions add: [ self declareTempAndPaste: proposedVariable ].
			labels add: 'declare instance'.
			actions add: [ self declareInstVar: proposedVariable ] ]
		ifFalse: [ 
			labels add: 'define new class'.
			actions add: [self defineClass: proposedVariable].
			labels add: 'declare global'.
			actions add: [ self declareGlobal: proposedVariable ].
			encoder classEncoding == UndefinedObject ifFalse: [ 
				labels add: 'declare class variable'.
				actions add: [ self declareClassVar: proposedVariable ] ] ].
	lines add: labels size.
	alternatives do: [ :each | 
		labels add: each.
		actions add: [ 
			self
				substituteWord: each 
				wordInterval: spot 
				offset: 0 
				insideSelection: requestor selectionInterval notEmpty.
			encoder encodeVariable: each ] fixTemps ].
	lines add: labels size.
	labels add: 'cancel'.

	"Display the pop-up menu"
	choice _ (PopUpMenu labelArray: labels asArray lines: lines asArray)
		startUpWithCaption: 'Unknown variable: ', proposedVariable, ' please correct, or cancel:'.
	action _ actions at: choice ifAbsent: [ 
		start _ spot first.
		end _ spot last.
		requestor selectionInterval notEmpty ifTrue: [
			start _ start + requestor startIndex - 1.
			end _ end + requestor startIndex - 1].
		requestor selectFrom: start to: end; select.
		^self fail ].

	"Execute the selected action"
	^action value! !

!Parser methodsFor: 'error correction' stamp: 'jmv 7/23/2008 13:54'!
declareTempAndPaste: name
	| insertion delta theTextString characterBeforeMark |

	theTextString _ requestor text string.
	characterBeforeMark _ theTextString at: tempsMark-1 ifAbsent: [$ ].
	(theTextString at: tempsMark) = $| ifTrue: [
  		"Paste it before the second vertical bar"
		insertion _ name, ' '.
		characterBeforeMark isSeparator ifFalse: [insertion _ ' ', insertion].
		delta _ 0.
	] ifFalse: [
		"No bars - insert some with CR, tab"
		insertion _ '| ' , name , ' |',String cr.
		delta _ 2.	"the bar and CR"
		characterBeforeMark = Character tab ifTrue: [
			insertion _ insertion , String tab.
			delta _ delta + 1.	"the tab"
		].
	].
	tempsMark _ tempsMark +
		(self substituteWord: insertion
			wordInterval: (tempsMark to: tempsMark-1)
			offset: 0
			insideSelection: false) - delta.
	^ encoder bindAndJuggle: name! !

!Parser methodsFor: 'error correction' stamp: 'jmv 7/23/2008 13:51'!
queryUndefined
	| varStart varName labels caption | 
	
	varName _ parseNode key.
	caption _ varName , ' appears to be
undefined at this point.
Proceed anyway?'.
	labels _ 'yes
no'.

	((PopUpMenu labels: labels) startUpWithCaption:
		(caption asText makeBoldFrom: 1 to: varName size)) = 1 
			ifFalse: [
				varStart _ self endOfLastToken + requestorOffset - varName size + 1.
				requestor selectionInterval notEmpty ifTrue: [
					varStart _ varStart + requestor selectionInterval first -1].
				requestor selectFrom: varStart to: varStart + varName size - 1; select.
				^ self fail]! !

!Parser methodsFor: 'error correction' stamp: 'jmv 7/23/2008 13:55'!
substituteSelector: selectorParts wordIntervals: spots
	"Substitute the correctSelector into the (presuamed interactive) receiver."
	| offset |
	offset _ 0.
	selectorParts with: spots do:
		[ :word :interval |
		offset _ self 
			substituteWord: word 
			wordInterval: interval 
			offset: offset 
			insideSelection: requestor selectionInterval notEmpty
		]! !

!Parser methodsFor: 'error correction' stamp: 'jmv 7/23/2008 13:10'!
substituteWord: correctWord wordInterval: spot offset: o insideSelection: aBoolean
	"Substitute the correctSelector into the (presuamed interactive) receiver."
	| selectionOffset |
	selectionOffset _ aBoolean
		ifTrue: [requestor selectionInterval first - 1]
		ifFalse: [0].
	requestor correctFrom: (selectionOffset + spot first + o)
					to: (selectionOffset + spot last + o)
					with: correctWord.
	requestorOffset _ requestorOffset + correctWord size - spot size.
	^ o + correctWord size - spot size! !

Parser removeSelector: #substituteWord:wordInterval:offset:!
