瀏覽代碼

Squashed 'src/ted2go/' changes from ae66ba141..f6f785a72

f6f785a72 Merge branch 'dev'
89d79d526 Fixex completion list size for small theme scale.
6a9953dc9 Disabled autocompletion inside of commented blocks.
226cc2721 Improved keywords capitalizer.
e5b0c2649 Cleanups in process reader.
052f0d732 Cleanups.
9ba996d41 Fixed app crashes (it was error in process reader).
59ef941f5 (wip)
31a4cf3ce Some doc parsing changes.
197a7e386 (wip) parsing doc.
40d3b91a8 no message

git-subtree-dir: src/ted2go
git-subtree-split: f6f785a7290fcf41519f0fb0c1ffbf54a2637d9d
Mark Sibly 8 年之前
父節點
當前提交
b120f075dd

+ 13 - 16
MainWindow.monkey2

@@ -414,12 +414,6 @@ Class MainWindowInstance Extends Window
 		_menuBar.AddMenu( _windowMenu )
 		_menuBar.AddMenu( _helpMenu )
 		
-		
-		'_browsersTabView.AddTab( "Project",_projectView,True )
-		'_browsersTabView.AddTab( "Source",_docBrowser,False )
-		'_browsersTabView.AddTab( "Debug",_debugView,False )
-		'_browsersTabView.AddTab( "Help",_helpTree,False )
-		
 		_buildErrorsList=New ListViewExt
 		_buildErrorsList.Visible=False
 		_buildErrorsList.OnItemChoosen+=Lambda()
@@ -1462,18 +1456,21 @@ Class MainWindowInstance Extends Window
 			_mx2cc=_mx2ccDir+StripDir( _mx2cc )
 		Endif
 		
-		
-		_docsManager.LoadState( jobj )
-		_buildActions.LoadState( jobj )
-		_projectView.LoadState( jobj )
+		App.Idle+=Lambda() 'delay execution
+			
+			_docsManager.LoadState( jobj )
+			_buildActions.LoadState( jobj )
+			_projectView.LoadState( jobj )
 		 
-		If Not _projectView.OpenProjects _projectView.OpenProject( CurrentDir() )
-		
-		UpdateRecentFilesMenu()
-		UpdateRecentProjectsMenu()
-		UpdateCloseProjectMenu()
+			If Not _projectView.OpenProjects _projectView.OpenProject( CurrentDir() )
+			
+			UpdateRecentFilesMenu()
+			UpdateRecentProjectsMenu()
+			UpdateCloseProjectMenu()
 
-		DeleteTmps()
+			DeleteTmps()
+			
+		End
 	End
 	
 	

+ 18 - 32
ProcessReader.monkey2

@@ -39,34 +39,20 @@ Class ProcessReader
 	
 	#rem monkeydoc Obtain a reader instance.
 	#end
-	Function Obtain:ProcessReader( tag:String )
-	
-		Local r:=New ProcessReader
-'		If _recycled.Empty
-'			r=New ProcessReader
-'		Else
-'			r=_recycled[0]
-'			_recycled.Remove( r )
-'			r.Finished=Null
-'			r.PortionRead=Null
-'			r.Error=Null
-'			r._running=False
-'		Endif
-		r.Tag=tag
-		_items.Add( r )
-		Return r
+	Method New( tag:String="" )
+	
+		Tag=tag
+		_items.Add( Self )
 	End
 	
-	#rem monkeydoc Recycle a reader instance. So we can get it again using Obtain.
-	#end
-	Function Recycle( r:ProcessReader )
+	Function StopAll()
 	
-		_items.Remove( r )
-		'r.Stop()
-		'_recycled.Add( r )
+		For Local r:=Eachin _items
+			r.Stop()
+		Next
 	End
 	
-	#rem monkeydoc Stops all obtained readers if them are running and not recycled.
+	#rem monkeydoc
 	#end
 	Function WaitingForStopAll( wait:Future<Bool> )
 		
@@ -121,13 +107,13 @@ Class ProcessReader
 		If Not _procOpen
 '			If _stdoutWaiting
 '				_stdoutWaiting.Set( False )
-'				_stdoutWaiting=Null
 '			Endif
 			Return
 		Endif
 		
 		_process.Terminate()
-		_running=False
+		
+		OnStop()
 	End
 	
 	#rem monkeydoc Is reading currently in progress.
@@ -137,10 +123,6 @@ Class ProcessReader
 		Return _running
 	End
 	
-	Protected
-	
-	Method New()
-	End
 	
 	Private
 	
@@ -150,7 +132,6 @@ Class ProcessReader
 	Field _stdoutWaiting:Future<Bool>
 	Field _stdoutOpen:Bool,_procOpen:Bool
 	Global _items:=New Stack<ProcessReader>
-	Global _recycled:=New Stack<ProcessReader>
 	Global _stopSize:Int,_stopCounter:Int
 	
 	Method RunInternal:String( cmd:String )
@@ -209,7 +190,7 @@ Class ProcessReader
 	
 		If Not _running Or _procOpen Or _stdoutOpen Return
 	
-		_running=False
+		OnStop()
 		
 		Local code:=_process.ExitCode
 		
@@ -218,8 +199,13 @@ Class ProcessReader
 		
 		If _stdoutWaiting
 			_stdoutWaiting.Set( True )
-			_stdoutWaiting=Null
 		Endif
 	End
 	
+	Method OnStop()
+		
+		_running=False
+		_items.Remove( Self )
+	End
+	
 End

+ 2 - 1
Ted2.monkey2

@@ -110,6 +110,7 @@
 #Import "view/ViewExtensions"
 #Import "view/DockingViewExt"
 
+#Import "Tuple"
 #Import "Plugin"
 #Import "ThemeImages"
 #Import "Prefs"
@@ -129,7 +130,7 @@ Using tinyxml2..
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
-Global AppTitle:="Ted2Go v2.6"
+Global AppTitle:="Ted2Go v2.7"
 
 
 Function Main()

+ 99 - 0
Tuple.monkey2

@@ -0,0 +1,99 @@
+
+Namespace ted2go
+
+
+Class Tuple Abstract
+
+End
+
+'---------------------------
+' Tuple 2
+'---------------------------
+
+Class Tuple2<T1,T2> Extends Tuple Final
+	
+	Method New( item1:T1,item2:T2 )
+		
+		_i1=item1
+		_i2=item2
+	End
+	
+	Property Item1:T1()
+		Return _i1
+	End
+	
+	Property Item2:T2()
+		Return _i2
+	End
+	
+	Private
+	
+	Field _i1:T1,_i2:T2
+End
+
+
+'---------------------------
+' Tuple 3
+'---------------------------
+
+Class Tuple3<T1,T2,T3> Extends Tuple Final
+	
+	Method New( item1:T1,item2:T2,item3:T3 )
+		
+		_i1=item1
+		_i2=item2
+		_i3=item3
+	End
+	
+	Property Item1:T1()
+		Return _i1
+	End
+	
+	Property Item2:T2()
+		Return _i2
+	End
+	
+	Property Item3:T3()
+		Return _i3
+	End
+	
+	Private
+	
+	Field _i1:T1,_i2:T2,_i3:T3
+End
+
+
+'---------------------------
+' Tuple 4
+'---------------------------
+
+Class Tuple4<T1,T2,T3,T4> Extends Tuple Final
+	
+	Method New( item1:T1,item2:T2,item3:T3,item4:T4 )
+		
+		_i1=item1
+		_i2=item2
+		_i3=item3
+		_i4=item4
+	End
+	
+	Property Item1:T1()
+		Return _i1
+	End
+	
+	Property Item2:T2()
+		Return _i2
+	End
+	
+	Property Item3:T3()
+		Return _i3
+	End
+	
+	Property Item4:T4()
+		Return _i4
+	End
+	
+	Private
+	
+	Field _i1:T1,_i2:T2,_i3:T3,_i4:T4
+End

+ 96 - 57
document/CodeDocument.monkey2

@@ -120,6 +120,11 @@ Class CodeDocumentView Extends Ted2CodeTextView
 
 	Protected
 	
+	Method OnThemeChanged() Override
+		
+		_doc.HideAutocomplete()
+	End
+	
 	Method OnRenderContent( canvas:Canvas ) Override
 	
 		Local color:=canvas.Color
@@ -194,6 +199,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				End
 			Endif
 			
+			CheckFormat( event,key )
+			
 			Select key
 			
 				Case Key.Space
@@ -293,8 +300,6 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 				Case Key.Enter,Key.KeypadEnter 'auto indent
 			
-					If _typing Then DoFormat( False )
-			
 					Local line:=CursorLine
 					Local text:=Document.GetLine( line )
 					Local indent:=GetIndent( text )
@@ -471,11 +476,6 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Return
 			
 			
-				Case Key.Up,Key.Down
-			
-					DoFormat( True )
-			
-			
 				Case Key.V
 			
 					If CanPaste And ctrl
@@ -505,6 +505,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 		Case EventType.KeyChar
 			
+			CheckFormat( event,event.Key )
+			
 			If event.Key = Key.Space And ctrl
 				If _doc.CanShowAutocomplete()
 					Local ident:=IdentBeforeCursor()
@@ -1065,7 +1067,9 @@ Class CodeDocument Extends Ted2Document
 	End
 	
 	Method GotoDeclaration()
-	
+		
+		If Not _parsingEnabled Return
+		
 		Local ident:=_codeView.FullIdentAtCursor
 		Local line:=TextDocument.FindLine( _codeView.Cursor )
 		Local item:=_parser.ItemAtScope( ident,Path,line )
@@ -1101,6 +1105,11 @@ Class CodeDocument Extends Ted2Document
 		If Not Prefs.AcEnabled Return False
 		
 		Local line:=TextDocument.FindLine( _codeView.Cursor )
+		
+		' is inside of comment?
+		Local state:=TextDocument.LineState( line )
+		If state & 255 <> 255 Return False
+		
 		Local text:=TextDocument.GetLine( line )
 		Local posInLine:=_codeView.Cursor-TextDocument.StartOfLine( line )
 		
@@ -1114,40 +1123,38 @@ Class CodeDocument Extends Ted2Document
 		If ident = "" Then ident=_codeView.IdentBeforeCursor()
 		
 		'show
-		Local line:=TextDocument.FindLine( _codeView.Cursor )
+		Local lineNum:=TextDocument.FindLine( _codeView.Cursor )
+		Local lineStr:=TextDocument.GetLine( lineNum )
+		Local posInLine:=_codeView.Cursor-TextDocument.StartOfLine( lineNum )
 		
 		If byCtrlSpace And AutoComplete.IsOpened
 			AutoComplete.DisableUsingsFilter=Not AutoComplete.DisableUsingsFilter
 		Endif
 		
-		AutoComplete.Show( ident,Path,FileExtension,line )
+		AutoComplete.Show( ident,Path,FileExtension,lineNum,lineStr,posInLine )
 		
 		If Not AutoComplete.IsOpened Return
 		
 		Local frame:=AutoComplete.Frame
 		
-		Local w:=frame.Width
+		Local w:=frame.Width+ScaledVal( 18 ) 'hack: 18px for scroll
 		Local h:=frame.Height
 		
 		Local cursorRect:=_codeView.CursorRect
 		Local scroll:=_codeView.Scroll
 		Local tvFrame:=_codeView.RenderRect
 		Local yy:=tvFrame.Top+cursorRect.Top-scroll.y
-		yy+=30 'magic offset :)
+		yy+=ScaledVal( 26 ) 'magic offset :)
 		Local xx:=tvFrame.Left+cursorRect.Left-scroll.x'+100
-		xx+=46 'magic
+		xx+=ScaledVal( 46 ) 'magic
 		frame.Left=xx
 		frame.Right=frame.Left+w
 		frame.Top=yy
 		frame.Bottom=frame.Top+h
 		' fit dialog into window
 		If frame.Bottom > MainWindow.RenderRect.Bottom
-			
-			Local dy:=frame.Bottom-MainWindow.RenderRect.Bottom-128
-			frame.Top+=dy
-			frame.Bottom+=dy
-			frame.Left+=50
-			frame.Right+=50
+			Local dy:=frame.Bottom-MainWindow.RenderRect.Bottom-ScaledVal( 128 )
+			frame.MoveBy( ScaledVal( 50 ),dy )
 		Endif
 		AutoComplete.Frame=frame
 		
@@ -1208,6 +1215,7 @@ Class CodeDocument Extends Ted2Document
 	Field _parser:ICodeParser
 	Field _prevLine:=-1
 	Field _prevScope:CodeItem
+	Field _parsingEnabled:Bool
 	
 	Field _toolBar:ToolBarExt
 	Field _content:DockingView
@@ -1302,12 +1310,15 @@ Class CodeDocument Extends Ted2Document
 	
 	Method OnLoad:Bool() Override
 	
-		_parser=ParsersManager.Get( FileExtension )
-	
 		Local text:=stringio.LoadString( Path )
 		
 		_doc.Text=text
 		
+		_parser=ParsersManager.Get( FileExtension )
+		_parsingEnabled=Not ParsersManager.IsFake( _parser )
+		
+		ParsingDoc() 'start parsing right after loading, not by timer
+		
 		Return True
 	End
 	
@@ -1333,7 +1344,11 @@ Class CodeDocument Extends Ted2Document
 	End
 	
 	Method OnLineChanged:Void( prevLine:Int,newLine:Int )
-	
+		
+		If AutoComplete.IsOpened Then AutoComplete.Hide()
+		
+		If Not _parsingEnabled Return
+		
 		Local scope:=_parser.GetScope( Path,_codeView.LineNumAtCursor+1 )	
 		If scope And scope <> _prevScope
 			Local classs := (_prevScope And scope.IsLikeClass And scope = _prevScope.Parent)
@@ -1343,7 +1358,6 @@ Class CodeDocument Extends Ted2Document
 			_prevScope = scope
 		Endif
 		
-		If AutoComplete.IsOpened Then AutoComplete.Hide()
 	End
 	
 	Method UpdateCodeTree()
@@ -1351,7 +1365,55 @@ Class CodeDocument Extends Ted2Document
 		_treeView.Fill( FileExtension,Path )
 	End
 	
-	Method BgParsing( pathOnDisk:String )
+	Field _timeTextChanged:=0
+	Field _timeDocParsed:=0
+	Method ParsingOnTextChanged()
+		
+		If Not _parsingEnabled Return
+		
+		_timeTextChanged=Millisecs()
+		
+		If Not _timer Then _timer=New Timer( 1,Lambda()
+		
+			If _parsing Return
+			
+			Local msec:=Millisecs()
+			If msec<_timeDocParsed+1000 Return
+			If _timeTextChanged=0 Or msec<_timeTextChanged+1000 Return
+			_timeTextChanged=0
+			
+			ParsingDoc()
+		
+		End )
+		
+	End
+	
+	Method ParsingDoc()
+		
+		If _parsing Return
+		
+		_parsing=True
+		
+		New Fiber( Lambda()
+		
+			Local tmp:=MainWindow.AllocTmpPath( "_mx2cc_parse_",".monkey2" )
+			Local file:=StripDir( Path )
+			
+			SaveString( _doc.Text,tmp )
+			
+			ParsingFile( tmp )
+		
+			DeleteFile( tmp )
+			
+			_parsing=False
+			
+			_timeDocParsed=Millisecs()
+			
+		End )
+		
+	End
+	
+	Method ParsingFile( pathOnDisk:String )
 		
 		If MainWindow.IsTerminating Return
 		
@@ -1363,6 +1425,10 @@ Class CodeDocument Extends Ted2Document
 		
 		If errors
 			
+			If errors="#"
+				Return
+			Endif
+			
 			Local arr:=errors.Split( "~n" )
 			For Local s:=Eachin arr
 				Local i:=s.Find( "] : Error : " )
@@ -1396,38 +1462,7 @@ Class CodeDocument Extends Ted2Document
 		' -----------------------------------
 		' catch for parsing
 		
-		If FileExtension <> ".monkey2" Return
-
-		
-		If _timer _timer.Cancel()
-		
-		_timer=New Timer( 0.5,Lambda()
-		
-			If _parsing Return
-			
-			_parsing=True
-			
-			New Fiber( Lambda()
-			
-				Local tmp:=MainWindow.AllocTmpPath( "_mx2cc_parse_",".monkey2" )
-				Local file:=StripDir( Path )
-				'Print "parsing:"+file+" ("+tmp+")"
-				
-				SaveString( _doc.Text,tmp )
-			
-				BgParsing( tmp )
-				
-				'Print "finished:"+file
-				
-				DeleteFile( tmp )
-				
-				_timer.Cancel()
-				
-				_timer=Null
-				_parsing=False
-				
-			End )
-		End )
+		ParsingOnTextChanged()
 		
 	End
 	
@@ -1466,7 +1501,7 @@ Class CodeDocument Extends Ted2Document
 		Local event:=New KeyEvent( EventType.KeyDown,_codeView,Key.Tab,Key.Tab,Modifier.None,"~t" )
 		_codeView.OnKeyEvent( event )
 	End
-				
+	
 End
 
 
@@ -1719,3 +1754,7 @@ Class NavCode
 	
 End
 
+Function ScaledVal:Int( val:Int )
+	
+	Return val*App.Theme.Scale.x
+End

+ 7 - 0
parser/CodeItem.monkey2

@@ -34,10 +34,17 @@ End
 
 Class CodeItem
 	
+	Field nspace:NSpace
+	
 	Method New( ident:String )
 		_ident=ident
 	End
 	
+	Method OnRemoved()
+		
+		If nspace Then nspace.items.Remove( Self )
+	End
+	
 	Property Ident:String()
 		Return _ident
 	Setter( value:String )

+ 268 - 26
parser/Monkey2Parser.monkey2

@@ -121,6 +121,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 		' start parsing process
 		Local str:=StartParsing( pathOnDisk,isModule )
 		
+		If Not str Return "#" 'special kind of error
+		
 '		If Not isModule
 '			Print "-----"
 '			Print str
@@ -133,7 +135,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		' return errors
 		If hasErrors Return (i > 0) ? str.Slice( 0,i ) Else str
-		If i=-1 Return "" ' not a valid json
+		If i=-1 Return "#" ' not a valid json
 		
 		'----------
 		
@@ -153,8 +155,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 			Items.AddAll( items )
 			
 			For Local i:=Eachin items
-				i.Namespac=nspace
 				i.IsModuleMember=isModule
+				NSpace.AddItem( nspace,i )
 			Next
 			'Print "file parsed: "+filePath+", items.count: "+items.Count()
 		Endif
@@ -351,9 +353,14 @@ Class Monkey2Parser Extends CodeParserPlugin
 	
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 		
-		Local result:=New Stack<CodeItem>
-		GetItemsInternal( ident,filePath,docLine,result,_lastUsingsFilter,1 )
-		Return (Not result.Empty) ? result[0] Else Null
+		Local opts:=New ParserRequestOptions
+		opts.results=New Stack<CodeItem>
+		opts.ident=ident
+		opts.filePath=filePath
+		opts.docLineNum=docLine
+		opts.usingsFilter=_lastUsingsFilter
+		GetItemsInternal( opts,1 )
+		Return (Not opts.results.Empty) ? opts.results[0] Else Null
 	End
 	
 	Method RefineRawType( item:CodeItem )
@@ -367,9 +374,9 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return Null
 	End
 	
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( options:ParserRequestOptions )
 		
-		GetItemsInternal( ident,filePath,docLine,target,usingsFilter,-1 )
+		GetItemsInternal( options )
 	End
 	
 	
@@ -388,7 +395,14 @@ Class Monkey2Parser Extends CodeParserPlugin
 		_types=New String[](".monkey2")
 	End
 	
-	Method GetItemsInternal( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null,resultLimit:Int=-1 )
+	Method GetItemsInternal( options:ParserRequestOptions,resultLimit:Int=-1 )
+		
+		Local ident:=options.ident
+		Local filePath:=options.filePath
+		Local docLineNum:=options.docLineNum
+		Local docLineStr:=options.docLineStr
+		Local target:=options.results
+		Local usingsFilter:=options.usingsFilter
 		
 		_lastUsingsFilter=usingsFilter
 		
@@ -399,7 +413,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Local onlyOne:=(idents.Length=1)
 	
 		'check current scope
-		Local rootScope:=GetScope( filePath,docLine )
+		Local rootScope:=GetScope( filePath,docLineNum )
 		Local scope:=rootScope
 		
 		'If scope Print scope.Text
@@ -414,7 +428,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Local items:=New Stack<CodeItem>
 		Local fullyMatched:CodeItem=Null
 		
-		'Print "idents: "+firstIdent+" - "+lastIdent
+		'Print "idents: "+firstIdent+" - "+lastIdent+" - "+ident
 		
 		If isSelf Or isSuper
 			
@@ -445,7 +459,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 							Continue
 						Endif
 						' additional checking for the first ident
-						If IsLocalMember( i ) And i.ScopeStartPos.x > docLine
+						If IsLocalMember( i ) And i.ScopeStartPos.x > docLineNum
 							'Print "cont3: "+i.Ident
 							Continue
 						Endif
@@ -492,7 +506,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 			item=_aliases[firstIdent]
 			If item
 				
-				If CheckUsingsFilter( item,usingsFilter )
+				If CheckUsingsFilter( item.Namespac,usingsFilter )
 					target.Add( item )
 					If resultLimit>0 And target.Length=resultLimit Return
 				Endif
@@ -501,7 +515,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				
 				For Local i:=Eachin Items
 					
-					If Not CheckUsingsFilter( i,usingsFilter )
+					If Not CheckUsingsFilter( i.Namespac,usingsFilter )
 						'Print "skip 1 "+i.Ident
 						Continue
 					Endif
@@ -517,7 +531,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 						Continue
 					Endif
 					
-					If IsLocalMember( i ) And i.ScopeStartPos.x > docLine
+					If IsLocalMember( i ) And i.ScopeStartPos.x > docLineNum
 						'Print "skip 4 "+i.Ident
 						Continue
 					Endif
@@ -551,6 +565,71 @@ Class Monkey2Parser Extends CodeParserPlugin
 		'If item Print "item: "+item.Scope+", kind: "+item.KindStr
 		'DebugStop()
 		
+		' check namespace qualifier
+		If item = Null
+			
+			Local s:=ident
+			If s.EndsWith( "." ) Then s=s.Slice( 0,s.Length-1 )
+			Local tuple:=NSpace.Find( s,False,usingsFilter )
+			Local ns := tuple ? (tuple.Item1 ? tuple.Item1 Else tuple.Item2) Else Null
+			If ns
+				' check ident after namespace
+				Local needFind:=""
+				Local stripped:=NSpace.StripNSpace( s,ns )
+				If stripped<>s
+					Local i:=stripped.Find( "." )
+					If i>0
+						needFind=stripped.Slice( 0,i )
+					Else
+						needFind=stripped
+					Endif
+				Endif
+				' grab all items from namespace
+				For Local i:=Eachin ns.items
+					If i.Access<>AccessMode.Public_ And i.FilePath<>filePath Continue
+					If needFind And i.Ident<>needFind Continue
+					If needFind
+						item=i
+						Exit
+					Else
+						target.Add( i )
+						If resultLimit>0 And target.Length=resultLimit Return
+					Endif
+				Next
+				' also grab all children namespaces
+				For Local i:=Eachin ns.nspaces
+					' dirty, create fake code items
+					Local code:=New CodeItem( i.name )
+					target.Add( code )
+					' don't check limit here
+					'If resultLimit>0 And target.Length=resultLimit Return
+				Next
+				
+			Elseif onlyOne
+				
+				Local filter:=usingsFilter
+				' don't filter namespaces for 'using xxx.yyy' section
+				If docLineStr.Trim().ToLower().StartsWith( "using " )
+					filter=Null
+				Endif
+				' grab all namespaces by ident
+				For Local n:=Eachin NSpace.ALL.Values.All()
+					Local r:NSpace
+					If n.name.StartsWith( firstIdent )
+						r=n
+					Else
+						r=n.GetNSpace( firstIdent,True,True )
+					Endif
+					If r And CheckUsingsFilter( r.FullName,filter )
+						' dirty, create fake code items
+						Local code:=New CodeItem( r.name )
+						target.Add( code )
+					Endif
+				Next
+				
+			Endif
+		Endif
+		
 		' var1.var2.var3...
 		If Not onlyOne And item <> Null
 			
@@ -620,7 +699,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 						Endif
 						' extensions can be placed in different namespaces
 						If i.IsExtension
-							If Not CheckUsingsFilter( i,usingsFilter )
+							If Not CheckUsingsFilter( i.Namespac,usingsFilter )
 								Continue
 							Endif
 						Endif
@@ -665,7 +744,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		item.IsExtension=True
 		list.Add( item )
 	End
-
+	
 	Method RemoveExtensions( filePath:String )
 		
 		For Local list:=Eachin ExtraItemsMap.Values.All()
@@ -700,13 +779,11 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		If Not _enabled Return ""
 		
-		Local proc:=ProcessReader.Obtain( pathOnDisk )
+		Local proc:=New ProcessReader( pathOnDisk )
 		
 		Local cmd:=_mx2ccPath+" makeapp -parse -geninfo ~q"+pathOnDisk+"~q"
 		Local str:=proc.Run( cmd )
 		
-		ProcessReader.Recycle( proc )
-		
 		Return str
 	End
 	
@@ -933,17 +1010,18 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 	End
 	
-	Method CheckUsingsFilter:Bool( item:CodeItem,usingsFilter:StringStack )
+	Function CheckUsingsFilter:Bool( nspace:String,usingsFilter:StringStack )
 		
 		If Not usingsFilter Or usingsFilter.Empty Return True
+		If Not nspace Return True
 		
 		For Local u:=Eachin usingsFilter
 			If u.EndsWith( ".." )
 				u=u.Slice( 0,u.Length-2 )
-				If item.Namespac=u Return True
-				If item.Namespac.StartsWith( u+"." ) Return True
+				If nspace=u Return True
+				If nspace.StartsWith( u+"." ) Return True
 			Else
-				If item.Namespac = u Return True
+				If nspace=u Return True
 			Endif
 		Next
 		Return False
@@ -1171,6 +1249,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		For Local i:=Eachin list
 			Items.Remove( i )
+			i.OnRemoved()
 		Next
 		
 		ItemsMap.Remove( path )
@@ -1198,13 +1277,178 @@ Struct Chars
 	Const DIGIT_0:=48
 	Const DIGIT_9:=57
 	Const AT:=64
-	Const GRID:=35
+	Const GRID:=35 ' #
 	Const TAB:=9
 	Const SPACE:=32
 	
 End
 
 
+Class NSpace
+	
+	Field parent:NSpace
+	Field name:String
+	Field items:=New Stack<CodeItem>
+	Field nspaces:=New Stack<NSpace>
+	
+	Property NestedLevel:Int()
+		
+		Local level:=0
+		Local par:=parent
+		While par
+			level+=1
+			par=par.parent
+		Wend
+		Return level
+	End
+	
+	Property FullName:String()
+	
+		Local s:=name
+		Local par:=parent
+		While par
+			s=par.name+"."+s
+			par=par.parent
+		Wend
+		Return s
+	End
+	
+	Method GetNSpace:NSpace( name:String,nested:Bool=False,startsWith:Bool=False )
+		
+		Return GetNSpaceInternal( nspaces,name,nested,startsWith )
+	End
+	
+	Const ALL:=New StringMap<NSpace>
+	Const ALL_PARTS:=New Stack<NSpace>
+	
+	Function StripNSpace:String( str:String,ns:NSpace )
+		
+		Local name:=""
+		While ns
+			name=ns.name+"."+name
+			If str.StartsWith( name ) Return str.Slice( name.Length )
+			ns=ns.parent
+		Wend
+		Return str
+	End
+	
+	Function Find:Tuple2<NSpace,NSpace>( fullNameWithDots:String,wholeMatched:Bool=False,usingsFilter:StringStack=Null )
+		
+		Local parts:=fullNameWithDots.Split( "." )
+		
+		If wholeMatched
+			
+			Local ns:=ALL[parts[0]]
+			If Not ns Return Null
+		
+			For Local i:=1 Until parts.Length
+				ns=ns.GetNSpace( parts[i] )
+				If Not ns Exit
+			Next
+			
+			Return New Tuple2<NSpace,NSpace>( ns,Null )
+			
+		Endif
+		
+		' not whole matched
+		Local list:=New Stack<NSpace>
+		Local name:=parts[0]
+		' find all nspaces by first part
+		For Local n:=Eachin ALL.Values.All()
+			Local r:NSpace
+			If n.name=name
+				r=n
+			Else
+				r=n.GetNSpace( name,True )
+			Endif
+			If r Then list.Add( r )
+		Next
+		If list.Empty Return Null
+		
+		list.Sort( Lambda:Int( n1:NSpace,n2:NSpace )
+			Return n1.NestedLevel<=>n2.NestedLevel
+		End )
+		
+		Local lastNs:NSpace
+		For Local i:=1 Until parts.Length
+			For Local k:=0 Until list.Length
+				Local n:=list[k]
+				If Not n Continue
+				Local r:=n.GetNSpace( parts[i] )
+				If r=Null And lastNs=Null
+					lastNs=n
+				Endif
+				list.Set( k,r ) ' "r" can be null here
+			Next
+		Next
+		
+		Local ns:NSpace
+		For Local n:=Eachin list
+			If n And Monkey2Parser.CheckUsingsFilter( n.FullName,usingsFilter )
+				ns=n
+				Exit
+			Endif
+		Next
+		
+		Return New Tuple2<NSpace,NSpace>( ns,lastNs )
+		
+	End
+	
+	Function AddItem( nspace:String,item:CodeItem )
+	
+		item.Namespac=nspace
+		Local parts:=nspace.Split( "." )
+		' root
+		Local ns:NSpace=Null,prev:NSpace=Null
+		Local sumName:=""
+		' hierarchy
+		For Local part:=Eachin parts
+			sumName+=part
+			If ns=Null
+				' add root part into map
+				ns=GetOrCreate<NSpace>( ALL,part )
+			Else
+				Local i:=prev.GetNSpace( part )
+				If i
+					ns=i
+				Else
+					ns=New NSpace
+					ns.parent=prev
+					prev.nspaces.AddUnique( ns )
+				Endif
+			Endif
+			ns.name=part
+			If sumName=nspace
+				ns.items.Add( item )
+				item.nspace=ns
+				Exit
+			Endif
+			sumName+="."
+			prev=ns
+		Next
+	
+	End
+	
+	
+	Private
+	
+	Method GetNSpaceInternal:NSpace( nspaces:Stack<NSpace>,name:String,nested:Bool=False,startsWith:Bool=False )
+	
+		For Local n:=Eachin nspaces
+			If (startsWith And n.name.StartsWith( name )) Or n.name=name Return n
+		Next
+		If nested
+			For Local n:=Eachin nspaces
+				Local r:=GetNSpaceInternal( n.nspaces,name,True,startsWith )
+				If r Return r
+			Next
+		Endif
+		Return Null
+	End
+	
+End
+
+
 Private
 
 Function GetLiteralType:String( typeIdent:String )
@@ -1273,5 +1517,3 @@ Struct Flags
 	Const DECL_IFACEMEMBER:=$080000
 	
 End
-
-

+ 23 - 5
parser/Parser.monkey2

@@ -12,7 +12,7 @@ Interface ICodeParser
 	Method GetScope:CodeItem( docPath:String,docLine:Int )
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 	
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( options:ParserRequestOptions )
 	Method CheckStartsWith:Bool( ident1:String,ident2:String )
 	
 	Method GetItem:CodeItem( ident:String )
@@ -33,7 +33,7 @@ Class ParsersManager
 		For Local p:=Eachin plugins
 			If p.CheckFileTypeSuitability( fileType ) Then Return p
 		Next
-		Return _empty
+		Return _fake
 	End
 
 	Function DisableAll()
@@ -44,10 +44,15 @@ Class ParsersManager
 		Next
 	End
 	
+	Function IsFake:Bool( parser:ICodeParser )
+		
+		Return parser=_fake
+	End
+	
 	
 	Private
 	
-	Global _empty:=New EmptyParser
+	Global _fake:=New FakeParser
 	
 End
 
@@ -59,9 +64,22 @@ Function StripGenericType:String( ident:String )
 End
 
 
+Class ParserRequestOptions Final
+	
+	Field ident:String
+	Field filePath:String
+	Field docLineNum:Int
+	Field results:Stack<CodeItem>
+	Field usingsFilter:Stack<String>
+	Field docLineStr:String
+	Field docPosInLine:Int
+	
+End
+
+
 Private
 
-Class EmptyParser Implements ICodeParser
+Class FakeParser Implements ICodeParser
 
 	Property Items:Stack<CodeItem>()
 		Return _items
@@ -97,7 +115,7 @@ Class EmptyParser Implements ICodeParser
 	End
 	Method RefineRawType( item:CodeItem )
 	End
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( options:ParserRequestOptions )
 	End
 	Method CheckStartsWith:Bool( ident1:String,ident2:String )
 		Return False

+ 9 - 2
syntax/CodeFormatter.monkey2

@@ -4,10 +4,13 @@ Namespace ted2go
 
 Interface ICodeFormatter
 
-	Method Format( document:CodeTextView,all:Bool )
+	Method FormatWord( document:CodeTextView,customCursor:Int=-1 )
+	Method FormatLine( document:CodeTextView,line:Int )
 	
 End
+#Rem
 
+#End
 
 'base wrapper for code formatter
 Class CodeFormatterPlugin Extends PluginDependsOnFileType Implements ICodeFormatter
@@ -49,7 +52,11 @@ Private
 
 Class EmptyFormatter Implements ICodeFormatter
 	
-	Method Format( document:CodeTextView,all:Bool )
+	Method FormatWord( document:CodeTextView,customCursor:Int=-1 )
+		'do nothing
+	End
+	
+	Method FormatLine( document:CodeTextView,line:Int )
 		'do nothing
 	End
 	

+ 48 - 13
syntax/Monkey2Formatter.monkey2

@@ -3,7 +3,7 @@ Namespace ted2go
 
 
 Class Monkey2CodeFormatter Extends CodeFormatterPlugin
-
+	
 	Property Name:String() Override
 		Return "Monkey2CodeFormatter"
 	End
@@ -18,10 +18,10 @@ Class Monkey2CodeFormatter Extends CodeFormatterPlugin
 		_types=New String[](".monkey2")
 	End
 	
-	Method Format( view:CodeTextView, all:Bool )
-	
+	Method FormatWord( view:CodeTextView,customCursor:Int=-1 )
+		
 		Local doc:=view.Document
-		Local cursor:=view.Cursor
+		Local cursor:=(customCursor<>-1) ? customCursor Else view.Cursor
 		
 		'ignore comments...
 		'
@@ -30,10 +30,10 @@ Class Monkey2CodeFormatter Extends CodeFormatterPlugin
 		
 		Local text:=doc.Text
 		Local start:=cursor
-		Local term:=all ? text.Length Else start
-
+		Local term:=text.Length
+		
 		'find start of ident
-		'		
+		'
 		While start And IsIdent( text[start-1] )
 			start-=1
 		Wend
@@ -55,7 +55,7 @@ Class Monkey2CodeFormatter Extends CodeFormatterPlugin
 			While i And text[i-1]<=32
 				i-=1
 			Wend
-			If Not i Or text[i-1]<>35 Return
+			If Not i Or text[i-1]<>Chars.GRID Return
 			i-=1
 			While i And text[i-1]<>10
 				i-=1
@@ -63,22 +63,57 @@ Class Monkey2CodeFormatter Extends CodeFormatterPlugin
 			Wend
 			'
 		Endif
-
+		
 		'find end of ident
 		Local ends:=start
 		'
 		While ends<term And IsIdent( text[ends] ) And text[ends]<>10
 			ends+=1
 		Wend
-		If ends=start return
-
+		If ends=start Return
+		
 		Local ident:=text.Slice( start,ends )
-
+		
 		Local kw:=view.Keywords.Get( ident )
 		
 		If Not kw Or kw=ident Return
 		
 		doc.ReplaceText( start,ends,kw )
 	End
-
+	
+	Method FormatLine( view:CodeTextView,line:Int )
+		
+		Local doc:=view.Document
+		
+		'ignore comments...
+		'
+		Local state:=doc.LineState( line )
+		If state & 255 <> 255 Return
+		
+		Local text:=doc.Text
+		Local i:=doc.StartOfLine( line )
+		Local term:=doc.EndOfLine( line )+1 ' grab \n char too
+		
+		Local identStart:=-1
+		
+		While i<term
+			
+			Local isIdent:=IsIdent( text[i] )
+			Local isLastPart:=(i=term-1)
+			If isIdent
+				If identStart=-1 Then identStart=i
+			Endif
+			If (Not isIdent Or isLastPart) And identStart<>-1 ' end of ident
+				Local ident:=text.Slice( identStart,i )
+				Local kw:=view.Keywords.Get( ident )
+				If kw And kw<>ident
+					doc.ReplaceText( identStart,i,kw )
+				Endif
+				identStart=-1
+			Endif
+			i+=1
+		Wend
+		
+	End
+	
 End

+ 15 - 0
testing/ParserTests.monkey2

@@ -4,6 +4,19 @@ Namespace test2go
 
 Private
 
+
+Class TestTheSame
+	
+	Property TestTheSame:TestTheSame()
+		Return Null
+	End
+	
+	Method Test()
+		
+	End
+	
+End
+
 Struct Vec2i Extension
 	
 	Const One := New Vec2i( 1,1 )
@@ -15,6 +28,8 @@ Function vTest( v:Vec2i,e:Entity )
 	
 	Local ok:=RequestOkay()
 	
+	std.filesystem.AppDir()
+	filesystem.AppDir()
 End
 
 

+ 25 - 0
utils/Utils.monkey2

@@ -230,6 +230,31 @@ Function DoInNotMainFiber( work:Void() )
 	End
 End
 
+Function GetOrCreate<T>:T( map:StringMap<T>,key:String )
+	
+	Local item:=map[key]
+	If Not item
+		item=New T
+		map[key]=item
+	Endif
+	Return item
+End
+
+'Function SplitToCombinations:String[]( str:String,splitter:String="." )
+'	
+'	
+'End
+
+
+Class Stack<T> Extension
+	
+	Method AddUnique( value:T )
+		
+		If Not Self.Contains( value ) Then Self.Add( value )
+	End
+	
+End
+
 
 Struct Recti Extension
 	

+ 13 - 3
view/AutocompleteView.monkey2

@@ -149,7 +149,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 	End
 	
-	Method Show( ident:String,filePath:String,fileType:String,docLine:Int )
+	Method Show( ident:String,filePath:String,fileType:String,docLineNum:Int,docLineStr:String,docPosInLine:Int )
 		
 		Local dotPos:=ident.FindLast( "." )
 		
@@ -249,7 +249,17 @@ Class AutocompleteDialog Extends NoTitleDialog
 			Endif
 			
 			_listForExtract.Clear()
-			parser.GetItemsForAutocomplete( ident,filePath,docLine,_listForExtract,usings )
+			
+			Global opts:=New ParserRequestOptions
+			opts.ident=ident
+			opts.filePath=filePath
+			opts.docLineNum=docLineNum
+			opts.docLineStr=docLineStr
+			opts.docPosInLine=docPosInLine
+			opts.results=_listForExtract
+			opts.usingsFilter=usings
+			
+			parser.GetItemsForAutocomplete( opts )
 			
 			CodeItemsSorter.SortByType( _listForExtract,True )
 		Endif
@@ -319,7 +329,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 	
 	Method OnThemeChanged() Override
 		
-		_view.MaxSize=_etalonMaxSize*App.Theme.Scale
+		_view.MaxSize=(App.Theme.Scale.x>1) ? _etalonMaxSize*App.Theme.Scale Else _etalonMaxSize
 	End
 	
 	Private

+ 52 - 19
view/CodeTextView.monkey2

@@ -147,9 +147,9 @@ Class CodeTextView Extends TextView
 		
 		While n >= start
 			
-			If text[n] = 46 'dot
+			If text[n] = Chars.DOT 'dot
 				
-			ElseIf Not (IsIdent( text[n] ) Or text[n] = 35) '35 => #
+			ElseIf Not (IsIdent( text[n] ) Or text[n] = Chars.GRID) '#
 				Exit
 			Endif
 			
@@ -297,6 +297,33 @@ Class CodeTextView Extends TextView
 	
 	Protected
 	
+	Method CheckFormat( event:KeyEvent,key:Key )
+		
+		Select event.Type
+		
+			Case EventType.KeyChar
+				
+				If IsIdent( event.Text[0] )
+					_typing=True
+				Else
+					If _typing Then FormatWord()
+				Endif
+		
+			Case EventType.KeyDown
+				
+				Select key
+		
+					Case Key.Tab
+						If _typing Then FormatWord() ' like for Key.Space
+		
+					Case Key.Backspace,Key.KeyDelete,Key.Enter,Key.KeypadEnter
+						_typing=True
+		
+				End
+		
+		End
+	End
+	
 	Method OnContentMouseEvent( event:MouseEvent ) Override
 		
 		Select event.Type
@@ -353,12 +380,6 @@ Class CodeTextView Extends TextView
 			
 			Case EventType.KeyChar
 				
-				If IsIdent( event.Text[0] )
-					_typing=True
-				Else
-					If _typing Then DoFormat( False )
-				Endif
-				
 				' select next char in overwrite mode
 				If Cursor=Anchor And _overwriteMode
 				
@@ -367,6 +388,7 @@ Class CodeTextView Extends TextView
 						SelectText( Cursor,Cursor+1 )
 					Endif
 				Endif
+			
 		End
 		
 		Super.OnKeyEvent( event )
@@ -380,8 +402,6 @@ Class CodeTextView Extends TextView
 	
 	Protected
 	
-	Field _typing:Bool
-	
 	Method OnCut( wholeLine:Bool=False )
 	
 		If wholeLine
@@ -536,12 +556,6 @@ Class CodeTextView Extends TextView
 		Return result
 	End
 	
-	Method DoFormat( all:Bool )
-	
-		_typing=False
-		If Formatter Then Formatter.Format( Self,all )
-	End
-	
 	Method OnThemeChanged() Override
 		
 		Super.OnThemeChanged()
@@ -641,18 +655,37 @@ Class CodeTextView Extends TextView
 	Field _overwriteMode:Bool
 	Field _extraSelStart:Int=-1,_extraSelEnd:Int
 	Field _extraSelColor:Color=Color.DarkGrey
+	Field _storedCursor:Int
+	Field _typing:Bool
 	
 	Method OnCursorMoved()
 		
 		Local line:=Document.FindLine( Cursor )
 		If line <> _line
+			If _typing Then FormatLine( _line )
+			
 			LineChanged( _line,line )
 			_line=line
 		Endif
-				
-		'If Cursor <> Anchor Return
-		'DoFormat( True )
 		
+		_storedCursor=Cursor
+	End
+	
+	Method FormatWord( customCursor:Int=-1 )
+	
+		_typing=False
+		If Formatter
+			Local cur:=(customCursor<>-1) ? customCursor Else _storedCursor
+			Formatter.FormatWord( Self,cur )
+		Endif
+	End
+	
+	Method FormatLine( line:Int )
+	
+		_typing=False
+		If Formatter
+			Formatter.FormatLine( Self,line )
+		Endif
 	End
 	
 End