Prechádzať zdrojové kódy

Squashed 'src/ted2go/' changes from 795d6240..43463bbc

43463bbc Merge branch 'dev'
0aa04b88 Updated 3d template file.
2c72b18b Added patron info (#115)
9f8950c9 Changed SourceCodePro.ttf to SourceCodePro.otf due to missing 'missing' glyph.
30b71654 Merge branch 'dev'
a5e6ac96 Improved removing whitespaced trailings.
bd606b5e Added "Remove lines trailing" feature (enabled by default).
fde8e555 Bump app version.
814ecffd Improved support of array type in code completion and code tree view.
1bf57792 Now storing latest opened tab in prefs dialog.
c14b7280 Added "Rename folder", and open a *folder* by "open file on desktop".
a80fe7e2 Updated special thanks.
d40bf4d4 Added shortcut (Ctrl+Shift+D) for duplicate line or selection (#90)
e32dfab7 Added some preprocessor directives.
799ef412 Improved "fix indentation" logic.
8b747870 Added shortcut text for "Stop process" button in status bar.
652924fa Completion list - some colors added into theme file (#103)
7ab83d27 Removed IRC stuff (#105)
ab276f07 Improved "spaces as tabs" convertion. (#98)
2476c50b More work on tabulation.
2d7a16b6 New feature - using spaces as tabs! (almost done)
64219e7c Disabled tabs undocking until there is no support for multi-window apps.
8fb4bf2d Merge branch 'master' into dev
a21bf249 Themes fixes by Hezkore.
cad986d0 Fix wrong View size afer restart and reload Undock Window (#112)
3599a22a Merge branch 'v2.8.1' into dev
86369138 Fixed tabs moving after drag-n-drop them.
c67124bc Undock tabs v2 (#109)
b82b1c29 View Mod (#108)
ba39705c Fixed text.
8e6d4cf4 Fixed #101 - make locked latest file just opened by double-click (via extension association).
052102d7 Updated mojo3d app template.
846935d1 Added ".glb" support to ted2go.
1267a050 Fixed SceneDocument to work with new mojo3d.
4d2d9577 Added a record to console about building cancellation.
720be2dc Close pop-up parameter hints by Escape.
d580b2ae Fixed #92 - minor focus issue.
da00ab0b Added jumping to error line right from Console view.

git-subtree-dir: src/ted2go
git-subtree-split: 43463bbcb22a7ad759e82972a9bacd317d3bcc86
Mark Sibly 7 rokov pred
rodič
commit
85153a606e

+ 70 - 121
MainWindow.monkey2

@@ -11,8 +11,6 @@ Namespace ted2go
 
 
 #Import "assets/fonts/@/fonts"
 #Import "assets/fonts/@/fonts"
 
 
-#Import "assets/themes/irc/@/themes/irc"
-
 
 
 Global MainWindow:MainWindowInstance
 Global MainWindow:MainWindowInstance
 
 
@@ -68,29 +66,21 @@ Class MainWindowInstance Extends Window
 			
 			
 			OnFileDropped( path )
 			OnFileDropped( path )
 		End
 		End
-
+		
 		_docsManager.DocumentAdded+=Lambda( doc:Ted2Document )
 		_docsManager.DocumentAdded+=Lambda( doc:Ted2Document )
 			AddRecentFile( doc.Path )
 			AddRecentFile( doc.Path )
+			
+			Local codeDoc:=Cast<CodeDocument>( doc )
+			If codeDoc Then codeDoc.AnalyzeIndentation()
+			
 			SaveState()
 			SaveState()
 		End
 		End
-
+		
 		_docsManager.DocumentRemoved+=Lambda( doc:Ted2Document )
 		_docsManager.DocumentRemoved+=Lambda( doc:Ted2Document )
 			If IsTmpPath( doc.Path ) DeleteFile( doc.Path )
 			If IsTmpPath( doc.Path ) DeleteFile( doc.Path )
 			SaveState()
 			SaveState()
 		End
 		End
 		
 		
-		'IRC tab
-		
-		_ircView=New IRCView
-		_ircView.introScreen.Text="Hang out with other Monkey 2 users"
-		_ircView.introScreen.OnNickChange+=Lambda( nick:String )
-			Prefs.IrcNickname=nick
-		End
-		
-		SetupChatTab()
-		
-		If Prefs.IrcConnect Then _ircView.introScreen.Connect()
-		
 		'Build tab
 		'Build tab
 		
 		
 		_buildConsole=New ConsoleExt
 		_buildConsole=New ConsoleExt
@@ -243,6 +233,7 @@ Class MainWindowInstance Extends Window
 		_findActions=New FindActions( _docsManager,_projectView,_findConsole )
 		_findActions=New FindActions( _docsManager,_projectView,_findConsole )
 		_helpActions=New HelpActions
 		_helpActions=New HelpActions
 		_viewActions=New ViewActions( _docsManager )
 		_viewActions=New ViewActions( _docsManager )
+		_tabActions=New TabActions( _tabsWrap.AllDocks )
 		
 		
 		_tabMenu=New Menu
 		_tabMenu=New Menu
 		_tabMenu.AddAction( _fileActions.close )
 		_tabMenu.AddAction( _fileActions.close )
@@ -363,6 +354,10 @@ Class MainWindowInstance Extends Window
 		_gotoMenu.AddAction( _viewActions.goBack )
 		_gotoMenu.AddAction( _viewActions.goBack )
 		_gotoMenu.AddAction( _viewActions.goForward )
 		_gotoMenu.AddAction( _viewActions.goForward )
 		
 		
+		'View menu
+		'
+		_viewMenu=New MenuExt( "View" )
+		TabActions.CreateMenu( _viewMenu )
 		'Build menu
 		'Build menu
 		'
 		'
 		_forceStop=New Action( "Force Stop" )
 		_forceStop=New Action( "Force Stop" )
@@ -435,6 +430,7 @@ Class MainWindowInstance Extends Window
 		_menuBar.AddMenu( _editMenu )
 		_menuBar.AddMenu( _editMenu )
 		_menuBar.AddMenu( _findMenu )
 		_menuBar.AddMenu( _findMenu )
 		_menuBar.AddMenu( _gotoMenu )
 		_menuBar.AddMenu( _gotoMenu )
+		_menuBar.AddMenu( _viewMenu )
 		_menuBar.AddMenu( _buildMenu )
 		_menuBar.AddMenu( _buildMenu )
 		_menuBar.AddMenu( _windowMenu )
 		_menuBar.AddMenu( _windowMenu )
 		_menuBar.AddMenu( _helpMenu )
 		_menuBar.AddMenu( _helpMenu )
@@ -443,7 +439,7 @@ Class MainWindowInstance Extends Window
 		_buildConsoleView=New DockingView
 		_buildConsoleView=New DockingView
 		_buildConsoleView.ContentView=_buildConsole
 		_buildConsoleView.ContentView=_buildConsole
 		
 		
-		_statusBar=New StatusBarView
+		_statusBar=New StatusBarView( "Stop process ("+_forceStop.HotKeyText+")" )
 		
 		
 		_contentView=New DockingView
 		_contentView=New DockingView
 		_contentView.AddView( _menuBar,"top" )
 		_contentView.AddView( _menuBar,"top" )
@@ -469,12 +465,16 @@ Class MainWindowInstance Extends Window
 	End
 	End
 	
 	
 	Field PrefsChanged:Void()
 	Field PrefsChanged:Void()
+	
 	Method OnPrefsChanged()
 	Method OnPrefsChanged()
 		
 		
 		ArrangeElements()
 		ArrangeElements()
-		PrefsChanged()
 		
 		
-		SetupChatTab()
+		For Local doc:=Eachin _docsManager.OpenDocuments
+			doc.TextView?.TabStop=Prefs.EditorTabSize
+		Next
+		
+		PrefsChanged()
 		
 		
 		_projectView.SingleClickExpanding=Prefs.MainProjectSingleClickExpanding
 		_projectView.SingleClickExpanding=Prefs.MainProjectSingleClickExpanding
 	End
 	End
@@ -623,7 +623,6 @@ Class MainWindowInstance Extends Window
 		SaveState()
 		SaveState()
 		_enableSaving=False
 		_enableSaving=False
 		OnForceStop() ' kill build process if started
 		OnForceStop() ' kill build process if started
-		If _ircView Then _ircView.Quit("Closing Ted2Go")
 		
 		
 		' waiting for started processes if any
 		' waiting for started processes if any
 		ParsersManager.DisableAll()
 		ParsersManager.DisableAll()
@@ -1223,6 +1222,9 @@ Class MainWindowInstance Extends Window
 		jobj["windowRect"]=ToJson( _storedSize )
 		jobj["windowRect"]=ToJson( _storedSize )
 		jobj["windowState"]=New JsonNumber( Int(state) )
 		jobj["windowState"]=New JsonNumber( Int(state) )
 		
 		
+		SaveUndockTabsState( jobj )
+		If _isTerminating UndockWindow.RestoreUndock()
+			
 		SaveTabsState( jobj )
 		SaveTabsState( jobj )
 		
 		
 		Local jdocs:=New JsonObject
 		Local jdocs:=New JsonObject
@@ -1298,9 +1300,8 @@ Class MainWindowInstance Extends Window
 			SizeChanged()
 			SizeChanged()
 		Endif
 		Endif
 		
 		
-		UpdateIrcIcon()
-		
 		Rendered( canvas )
 		Rendered( canvas )
+		
 	End
 	End
 	
 	
 	Method OnInit()
 	Method OnInit()
@@ -1361,93 +1362,6 @@ Class MainWindowInstance Extends Window
 		_resized=True
 		_resized=True
 	End
 	End
 	
 	
-	Method SetupChatTab()
-		
-		If Not _ircView Return
-		
-		_ircView.ircHandler.OnMessage+=Self.OnChatMessage
-		
-		Local intro:=_ircView.introScreen
-		
-		If intro.IsConnected Return
-		
-		Local nick:=Prefs.IrcNickname
-		Local server:=Prefs.IrcServer
-		Local port:=Prefs.IrcPort
-		Local rooms:=Prefs.IrcRooms
-		intro.AddOnlyServer( nick,server,server,port,rooms )
-		
-	End
-	
-	Method OnChatTabActiveChanged()
-		
-		Local tab:=_tabsWrap.tabs["Chat"]
-		
-		If Not tab.IsActive Return
-		
-		tab.Icon=Null
-		
-		_ircNotifyIcon=0
-		
-		HideHint()
-		
-	End
-	
-	Method OnChatMessage( message:IRCMessage, container:IRCMessageContainer, server:IRCServer )
-		
-		If message.type<>"PRIVMSG" Or _tabsWrap.tabs["Chat"].IsActive Return
-		
-		'Show notice icon
-		If message.text.Contains(server.nickname) Then
-			
-			If _ircNotifyIcon<=1 Then
-				
-				_ircNotifyIcon=2
-				
-				Local mentionStr:String
-				mentionStr=server.nickname+" was mentioned by "
-				mentionStr+=message.fromUser+" in "
-				mentionStr+=container.name
-				
-				Local dock:=_tabsWrap.tabs["Chat"].CurrentHolder '_tabsWrap.docks["bottom"]
-				ShowHint( mentionStr, New Vec2i( 0, -GetStyle( "Hint" ).Font.Height*4 ), dock, 20000 )
-				
-			Endif
-			
-		Else
-			
-			If _ircNotifyIcon<=0 Then _ircNotifyIcon=1
-			
-		Endif
-		
-	End
-	
-	Method UpdateIrcIcon()
-		
-		If _ircNotifyIcon<=0 Then Return
-		
-		Local time:Int=Int(Millisecs()*0.0025)
-		
-		If time=_ircIconBlink Then Return
-		_ircIconBlink=time
-		
-		Local tab:=_tabsWrap.tabs["Chat"]
-		
-		If time Mod 2 Then
-			Select _ircNotifyIcon
-				
-				Case 1
-					tab.Icon=App.Theme.OpenImage( "irc/notice.png" )
-					
-				Case 2
-					tab.Icon=App.Theme.OpenImage( "irc/important.png" )
-			End
-		Else
-			tab.Icon=App.Theme.OpenImage( "irc/blink.png" )
-		Endif
-		
-	End
-	
 	Method InitTabs()
 	Method InitTabs()
 		
 		
 		If Not _tabsWrap.tabs.Empty Return
 		If Not _tabsWrap.tabs.Empty Return
@@ -1459,9 +1373,7 @@ Class MainWindowInstance Extends Window
 		_tabsWrap.AddTab( "Output",_outputConsoleView )
 		_tabsWrap.AddTab( "Output",_outputConsoleView )
 		_tabsWrap.AddTab( "Docs",_docsConsole )
 		_tabsWrap.AddTab( "Docs",_docsConsole )
 		_tabsWrap.AddTab( "Find",_findConsole )
 		_tabsWrap.AddTab( "Find",_findConsole )
-		_tabsWrap.AddTab( "Chat",_ircView )
 		
 		
-		_tabsWrap.tabs["Chat"].ActiveChanged+=OnChatTabActiveChanged
 	End
 	End
 	
 	
 	Method ArrangeElements()
 	Method ArrangeElements()
@@ -1503,7 +1415,7 @@ Class MainWindowInstance Extends Window
 		places["left"]=New StringStack( s.Split( "," ) )
 		places["left"]=New StringStack( s.Split( "," ) )
 		s="Project,Debug"
 		s="Project,Debug"
 		places["right"]=New StringStack( s.Split( "," ) )
 		places["right"]=New StringStack( s.Split( "," ) )
-		s="Build,Output,Docs,Find,Chat"
+		s="Build,Output,Docs,Find"
 		places["bottom"]=New StringStack( s.Split( "," ) )
 		places["bottom"]=New StringStack( s.Split( "," ) )
 		
 		
 		Global actives:=New StringMap<String>
 		Global actives:=New StringMap<String>
@@ -1517,6 +1429,7 @@ Class MainWindowInstance Extends Window
 		' put views
 		' put views
 		For Local edge:=Eachin edges
 		For Local edge:=Eachin edges
 			Local val:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Tabs" )
 			Local val:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Tabs" )
+			Local vistabs:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"TabsVisible" )
 			If val And val<>JsonValue.NullValue
 			If val And val<>JsonValue.NullValue
 				For Local v:=Eachin val.ToArray().All()
 				For Local v:=Eachin val.ToArray().All()
 					Local key:=v.ToString()
 					Local key:=v.ToString()
@@ -1526,7 +1439,16 @@ Class MainWindowInstance Extends Window
 					Next
 					Next
 					'
 					'
 					Local tab:=_tabsWrap.tabs[key]
 					Local tab:=_tabsWrap.tabs[key]
-					If tab Then _tabsWrap.docks[edge].AddTab( tab )
+					If tab Then 
+						_tabsWrap.docks[edge].AddTab( tab )
+						'set view visible
+						If vistabs And vistabs<>JsonValue.NullValue
+							For Local vt:=Eachin vistabs.ToArray().All()
+								If key=vt.ToString() Then tab.Visible=True; Exit
+								tab.Visible=False
+							Next
+						End
+					End
 				Next
 				Next
 			Endif
 			Endif
 		Next
 		Next
@@ -1574,16 +1496,45 @@ Class MainWindowInstance Extends Window
 		For Local edge:=Eachin edges
 		For Local edge:=Eachin edges
 			Local dock:=_tabsWrap.docks[edge]
 			Local dock:=_tabsWrap.docks[edge]
 			jj[edge+"Tabs"]=JsonArray.FromStrings( dock.TabsNames )
 			jj[edge+"Tabs"]=JsonArray.FromStrings( dock.TabsNames )
+			jj[edge+"TabsVisible"]=JsonArray.FromStrings( dock.TabsVisible )
 			jj[edge+"Active"]=New JsonString( dock.ActiveName )
 			jj[edge+"Active"]=New JsonString( dock.ActiveName )
 			jj[edge+"Visible"]=New JsonBool( dock.Visible )
 			jj[edge+"Visible"]=New JsonBool( dock.Visible )
 			jj[edge+"Size"]=New JsonString( _tabsWrap.GetDockSize( dock ) )
 			jj[edge+"Size"]=New JsonString( _tabsWrap.GetDockSize( dock ) )
 		Next
 		Next
 	End
 	End
 	
 	
+	Method LoadUndockTabsState( jobj:JsonObject ) 
+				
+		Local edges:=DraggableTabs.Edges	
+		For Local edge:=Eachin edges
+			Local dock:=_tabsWrap.docks[edge]
+			For Local i:=Eachin dock.TabsNames
+				Local val:=Json_FindValue( jobj.Data,"undockTabs/"+i )
+				If val
+					Local _undockWindow:=UndockWindow.NewUndock( _tabsWrap.tabs[i] )
+					_undockWindow.SetUndockFrame( ToRecti( val ) )
+				End
+			Next
+		Next
+	End
+		
+	Method SaveUndockTabsState( jobj:JsonObject )
+		
+		If( UndockWindow._undockWindows.Length )	
+			Local jj:=New JsonObject
+			jobj["undockTabs"]=jj
+			For Local i:=Eachin UndockWindow._undockWindows
+				If i._visible jj[i.Title]=ToJson( i.Frame )
+			Next
+		End
+	End
+	
 	Method LoadState( jobj:JsonObject )
 	Method LoadState( jobj:JsonObject )
 		
 		
 		LoadTabsState( jobj )
 		LoadTabsState( jobj )
 		
 		
+		LoadUndockTabsState( jobj )
+		
 		If jobj.Contains( "docsTab" )
 		If jobj.Contains( "docsTab" )
 			Local jdocs:=jobj.GetObject( "docsTab" )
 			Local jdocs:=jobj.GetObject( "docsTab" )
 			Local size:=jdocs.GetString( "indexerSize" )
 			Local size:=jdocs.GetString( "indexerSize" )
@@ -1677,15 +1628,15 @@ Class MainWindowInstance Extends Window
 				If event.Modifiers & Modifier.Shift
 				If event.Modifiers & Modifier.Shift
 					
 					
 					dock=_tabsWrap.docks["left"]
 					dock=_tabsWrap.docks["left"]
-					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					If dock.NumTabs>0 And dock.VisibleTabs Then dock.Visible=Not dock.Visible
 					
 					
 					dock=_tabsWrap.docks["right"]
 					dock=_tabsWrap.docks["right"]
-					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					If dock.NumTabs>0 And dock.VisibleTabs Then dock.Visible=Not dock.Visible
 					
 					
 				Else ' bottom dock
 				Else ' bottom dock
 					
 					
 					dock=_tabsWrap.docks["bottom"]
 					dock=_tabsWrap.docks["bottom"]
-					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					If dock.NumTabs>0 And dock.VisibleTabs Then dock.Visible=Not dock.Visible
 					
 					
 					_consoleVisibleCounter+=1
 					_consoleVisibleCounter+=1
 				Endif
 				Endif
@@ -1728,8 +1679,8 @@ Class MainWindowInstance Extends Window
 	Field _buildActions:BuildActions
 	Field _buildActions:BuildActions
 	Field _helpActions:HelpActions
 	Field _helpActions:HelpActions
 	Field _viewActions:ViewActions
 	Field _viewActions:ViewActions
+	Field _tabActions:TabActions
 	
 	
-	Field _ircView:IRCView
 	Field _buildConsole:ConsoleExt
 	Field _buildConsole:ConsoleExt
 	Field _buildConsoleView:DockingView
 	Field _buildConsoleView:DockingView
 	Field _outputConsole:ConsoleExt
 	Field _outputConsole:ConsoleExt
@@ -1744,14 +1695,10 @@ Class MainWindowInstance Extends Window
 	Field _helpTree:HelpTreeView
 	Field _helpTree:HelpTreeView
 	Field _helpSwitcher:ToolButtonExt
 	Field _helpSwitcher:ToolButtonExt
 	
 	
-	'Field _ircTabView:TabView
 	Field _docsTabView:TabViewExt
 	Field _docsTabView:TabViewExt
 	Field _consolesTabView2:TabView
 	Field _consolesTabView2:TabView
 	Field _browsersTabView2:TabView
 	Field _browsersTabView2:TabView
 	
 	
-	Field _ircNotifyIcon:Int
-	Field _ircIconBlink:Int
-	
 	Field _forceStop:Action
 	Field _forceStop:Action
 
 
 	Field _tabMenu:Menu
 	Field _tabMenu:Menu
@@ -1760,6 +1707,7 @@ Class MainWindowInstance Extends Window
 	Field _editMenu:MenuExt
 	Field _editMenu:MenuExt
 	Field _findMenu:MenuExt
 	Field _findMenu:MenuExt
 	Field _gotoMenu:MenuExt
 	Field _gotoMenu:MenuExt
+	Field _viewMenu:MenuExt
 	Field _buildMenu:MenuExt
 	Field _buildMenu:MenuExt
 	Field _windowMenu:MenuExt
 	Field _windowMenu:MenuExt
 	Field _helpMenu:MenuExt
 	Field _helpMenu:MenuExt
@@ -2033,6 +1981,7 @@ Class DraggableTabs
 	Method AddTab( name:String,view:View )
 	Method AddTab( name:String,view:View )
 		
 		
 		tabs[name]=TabViewExt.CreateDraggableTab( name,view,_docksArray )
 		tabs[name]=TabViewExt.CreateDraggableTab( name,view,_docksArray )
+		tabs[name].Undockable=True
 	End
 	End
 	
 	
 	Method GetDockSize:String( dock:TabViewExt )
 	Method GetDockSize:String( dock:TabViewExt )

+ 11 - 27
Prefs.monkey2

@@ -10,10 +10,10 @@ Class PrefsInstance
 	Field AcKeywordsOnly:=False
 	Field AcKeywordsOnly:=False
 	Field AcShowAfter:=2
 	Field AcShowAfter:=2
 	Field AcUseTab:=True
 	Field AcUseTab:=True
-	Field AcUseEnter:=False
+	Field AcUseEnter:=True
 	Field AcUseSpace:=False
 	Field AcUseSpace:=False
 	Field AcUseDot:=False
 	Field AcUseDot:=False
-	Field AcNewLineByEnter:=True
+	Field AcNewLineByEnter:=False
 	Field AcStrongFirstChar:=True
 	Field AcStrongFirstChar:=True
 	Field AcUseLiveTemplates:=True
 	Field AcUseLiveTemplates:=True
 	'
 	'
@@ -22,12 +22,6 @@ Class PrefsInstance
 	Field MainProjectSingleClickExpanding:=False
 	Field MainProjectSingleClickExpanding:=False
 	Field MainPlaceDocsAtBegin:=False
 	Field MainPlaceDocsAtBegin:=False
 	'
 	'
-	Field IrcNickname:String
-	Field IrcServer:="irc.freenode.net"
-	Field IrcPort:=6667
-	Field IrcRooms:="#monkey2" '#mojox#mojo2d
-	Field IrcConnect:Bool=False
-	'
 	Field EditorToolBarVisible:=False
 	Field EditorToolBarVisible:=False
 	Field EditorGutterVisible:=True
 	Field EditorGutterVisible:=True
 	Field EditorShowWhiteSpaces:=False
 	Field EditorShowWhiteSpaces:=False
@@ -39,6 +33,9 @@ Class PrefsInstance
 	Field EditorAutoPairs:=True
 	Field EditorAutoPairs:=True
 	Field EditorSurroundSelection:=True
 	Field EditorSurroundSelection:=True
 	Field EditorShowParamsHint:=True
 	Field EditorShowParamsHint:=True
+	Field EditorUseSpacesAsTabs:=False
+	Field EditorTabSize:=4
+	Field EditorRemoveLinesTrailing:=False
 	'
 	'
 	Field SourceSortByType:=True
 	Field SourceSortByType:=True
 	Field SourceShowInherited:=False
 	Field SourceShowInherited:=False
@@ -58,17 +55,6 @@ Class PrefsInstance
 	
 	
 	Method LoadState( json:JsonObject )
 	Method LoadState( json:JsonObject )
 		
 		
-		If json.Contains( "irc" )
-			
-			Local j2:=json["irc"].ToObject()
-			IrcNickname=Json_GetString( j2,"nickname",IrcNickname )
-			IrcServer=Json_GetString( j2,"server",IrcServer )
-			IrcPort=Json_GetInt( j2,"port",IrcPort )
-			IrcRooms=Json_GetString( j2,"rooms",IrcRooms )
-			IrcConnect=Json_GetBool( j2,"connect",IrcConnect )
-			
-		Endif
-		
 		If json.Contains( "main" )
 		If json.Contains( "main" )
 			
 			
 			Local j2:=json["main"].ToObject()
 			Local j2:=json["main"].ToObject()
@@ -108,6 +94,9 @@ Class PrefsInstance
 			EditorAutoPairs=Json_GetBool( j2,"autoPairs",EditorAutoPairs )
 			EditorAutoPairs=Json_GetBool( j2,"autoPairs",EditorAutoPairs )
 			EditorSurroundSelection=Json_GetBool( j2,"surroundSelection",EditorSurroundSelection )
 			EditorSurroundSelection=Json_GetBool( j2,"surroundSelection",EditorSurroundSelection )
 			EditorShowParamsHint=Json_GetBool( j2,"showParamsHint",EditorShowParamsHint )
 			EditorShowParamsHint=Json_GetBool( j2,"showParamsHint",EditorShowParamsHint )
+			EditorUseSpacesAsTabs=Json_GetBool( j2,"useSpacesAsTabs",EditorUseSpacesAsTabs )
+			EditorTabSize=Json_GetInt( j2,"tabSize",EditorTabSize )
+			EditorRemoveLinesTrailing=Json_GetBool( j2,"removeLinesTrailing",EditorRemoveLinesTrailing )
 			
 			
 		Endif
 		Endif
 		
 		
@@ -135,14 +124,6 @@ Class PrefsInstance
 		j["singleClickExpanding"]=New JsonBool( MainProjectSingleClickExpanding )
 		j["singleClickExpanding"]=New JsonBool( MainProjectSingleClickExpanding )
 		j["placeDocsAtBegin"]=New JsonBool( MainPlaceDocsAtBegin )
 		j["placeDocsAtBegin"]=New JsonBool( MainPlaceDocsAtBegin )
 		
 		
-		j=New JsonObject
-		json["irc"]=j
-		j["nickname"]=New JsonString( IrcNickname )
-		j["server"]=New JsonString( IrcServer )
-		j["port"]=New JsonNumber( IrcPort )
-		j["rooms"]=New JsonString( IrcRooms )
-		j["connect"]=New JsonBool( IrcConnect )
-		
 		j=New JsonObject
 		j=New JsonObject
 		json["completion"]=j
 		json["completion"]=j
 		j["enabled"]=New JsonBool( AcEnabled )
 		j["enabled"]=New JsonBool( AcEnabled )
@@ -168,6 +149,9 @@ Class PrefsInstance
 		j["autoPairs"]=New JsonBool( EditorAutoPairs )
 		j["autoPairs"]=New JsonBool( EditorAutoPairs )
 		j["surroundSelection"]=New JsonBool( EditorSurroundSelection )
 		j["surroundSelection"]=New JsonBool( EditorSurroundSelection )
 		j["showParamsHint"]=New JsonBool( EditorShowParamsHint )
 		j["showParamsHint"]=New JsonBool( EditorShowParamsHint )
+		j["useSpacesAsTabs"]=New JsonBool( EditorUseSpacesAsTabs )
+		j["tabSize"]=New JsonNumber( EditorTabSize )
+		j["removeLinesTrailing"]=New JsonBool( EditorRemoveLinesTrailing )
 		
 		
 		j=New JsonObject
 		j=New JsonObject
 		json["source"]=j
 		json["source"]=j

+ 1 - 0
README.md

@@ -18,6 +18,7 @@ Discuss on [forum page](http://monkeycoder.co.nz/forums/topic/ted2go-fork/).
 Support me if you like this project:
 Support me if you like this project:
 * [PayPal](https://paypal.me/engor)
 * [PayPal](https://paypal.me/engor)
 * Payed downloading [from itch.io](https://nerobot.itch.io/ted2go)
 * Payed downloading [from itch.io](https://nerobot.itch.io/ted2go)
+* Become a patron [on Patreon.com](https://www.patreon.com/nerobot)
 
 
 ## Notes for contributors
 ## Notes for contributors
 Please, take a look at code style. It based on original Ted2.
 Please, take a look at code style. It based on original Ted2.

+ 4 - 1
Ted2.monkey2

@@ -32,6 +32,7 @@
 #Import "action/FindActions"
 #Import "action/FindActions"
 #Import "action/ViewActions"
 #Import "action/ViewActions"
 #Import "action/WindowActions"
 #Import "action/WindowActions"
+#Import "action/TabActions"
 
 
 #Import "dialog/FindDialog"
 #Import "dialog/FindDialog"
 #Import "dialog/PrefsDialog"
 #Import "dialog/PrefsDialog"
@@ -80,6 +81,7 @@
 
 
 #Import "utils/JsonUtils"
 #Import "utils/JsonUtils"
 #Import "utils/Utils"
 #Import "utils/Utils"
+#Import "utils/TextUtils"
 
 
 #Import "view/IRCView"
 #Import "view/IRCView"
 #Import "view/CodeMapView"
 #Import "view/CodeMapView"
@@ -114,6 +116,7 @@
 #Import "view/ViewExtensions"
 #Import "view/ViewExtensions"
 #Import "view/DockingViewExt"
 #Import "view/DockingViewExt"
 #Import "view/DraggableViewListener"
 #Import "view/DraggableViewListener"
+#Import "view/Undock"
 
 
 #Import "Tree"
 #Import "Tree"
 #Import "Tuple"
 #Import "Tuple"
@@ -135,7 +138,7 @@ Using sdl2..
 
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
 
-Global AppTitle:="Ted2Go v2.8.1"
+Global AppTitle:="Ted2Go v2.9"
 
 
 
 
 Function Main()
 Function Main()

+ 12 - 0
action/FileActions.monkey2

@@ -343,6 +343,8 @@ Class FileActions
 		
 		
 		_prefsDialog=New PrefsDialog
 		_prefsDialog=New PrefsDialog
 		
 		
+		' not good place for subscribing, but it's simplier than proper one...
+		'
 		_prefsDialog.Apply+=Lambda()
 		_prefsDialog.Apply+=Lambda()
 		
 		
 			For Local d:=Eachin _docs.OpenDocuments
 			For Local d:=Eachin _docs.OpenDocuments
@@ -353,6 +355,16 @@ Class FileActions
 			MainWindow.OnPrefsChanged()
 			MainWindow.OnPrefsChanged()
 		End
 		End
 		
 		
+		' analyze opened docs to show prompt "fix indentation?"
+		'
+		_prefsDialog.TabulationChanged+=Lambda()
+			
+			For Local d:=Eachin _docs.OpenDocuments
+				Local codeDoc:=Cast<CodeDocument>( d )
+				If codeDoc Then codeDoc.AnalyzeIndentation()
+			Next
+		End
+		
 		_prefsDialog.ShowModal()
 		_prefsDialog.ShowModal()
 	End
 	End
 	
 	

+ 78 - 0
action/TabActions.monkey2

@@ -0,0 +1,78 @@
+Namespace ted2go
+
+
+Class TabActions
+	
+	Global tabs:TabViewExt[]
+	
+	Method New( _tabs:TabViewExt[] )
+		
+		tabs=_tabs
+	End
+	
+	Function SwitchView( tabName:String )
+		
+			For Local i:=Eachin tabs
+				Local _docks:=i.Tabs
+				For Local _tabb:=Eachin _docks	
+					If _tabb.Text=tabName Then
+						If _tabb.Visible
+							_tabb.Visible=False
+							_tabb.View.Visible=False
+							'make first tab as current
+							For Local firstCurrent:=Eachin _docks
+								If firstCurrent.Visible Then firstCurrent.CurrentHolder.MakeCurrent( firstCurrent.Text ); Exit
+							Next	
+						Else
+							If( _tabb.View )
+								_tabb.Visible=True
+								_tabb.View.Visible=True
+								_tabb.CurrentHolder.MakeCurrent( _tabb.Text )
+							End
+						End
+						_tabb.CurrentHolder.Visible=_tabb.CurrentHolder.VisibleTabs
+					End
+					
+				Next
+			Next
+	End
+	
+	Function CreateMenu( view:MenuExt )
+		
+		Local keynr:Int
+		Local tabNames:=New String[]( "Project","Debug","Source","Build","Output","Docs","Find","Chat" )	
+		For Local a:=Eachin tabNames
+			Local key:=Cast<Key>( 49+keynr )
+			Local i:=view.AddAction( a )
+			i.HotKey=key
+			i.HotKeyModifiers=Modifier.Alt
+			i.Triggered=Lambda()
+				SwitchView( a )	
+			End
+			keynr+=1
+		Next
+		view.AddSeparator()
+		'reset all tabs
+		Local _reset:=view.AddAction( "Reset" )
+		_reset.Triggered=Lambda()
+			Reset()	
+		End
+	End
+	
+	Function Reset()
+		
+		For Local i:=Eachin tabs
+			Local _docks:=i.Tabs
+			For Local _tabb:=Eachin _docks	
+					If _tabb.View
+						_tabb.Visible=True
+						_tabb.View.Visible=True
+						_tabb.CurrentHolder.MakeCurrent( _tabb.Text )
+						_tabb.CurrentHolder.Visible=_tabb.CurrentHolder.VisibleTabs
+					End
+			Next
+		Next
+		'Undock Reset
+		UndockWindow.RestoreUndock()
+	End
+End

+ 1 - 1
assets/aboutTed2Go.html

@@ -124,7 +124,7 @@ ToolBar icons were taken from <a href="https://icons8.com/icon/new-icons/win8">i
 
 
 <h3>Special thanks</h3>
 <h3>Special thanks</h3>
 
 
-<p>Rajasekaran Senthil Kumaran, abakobo, Peter Rigby, Dmitry Fadeev, James Boyd, Sam Fisher, Matthew Bowen, Mark Mcvittie, Simon Armstrong, Rudy van Etten, Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
+<p>Dominique MIS, Rajasekaran Senthil Kumaran, abakobo, Peter Rigby, Dmitry Fadeev, James Boyd, Sam Fisher, Matthew Bowen, Mark Mcvittie, Simon Armstrong, Rudy van Etten, Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
 
 
 </body>
 </body>
 
 

BIN
assets/fonts/SourceCodePro-Medium.otf


+ 19 - 23
assets/newfiles/Simple_Mojo3d_App.monkey2

@@ -8,63 +8,59 @@ Using std..
 Using mojo..
 Using mojo..
 Using mojo3d..
 Using mojo3d..
 
 
+
 Class MyWindow Extends Window
 Class MyWindow Extends Window
 	
 	
 	Field _scene:Scene
 	Field _scene:Scene
-	
 	Field _camera:Camera
 	Field _camera:Camera
-	
 	Field _light:Light
 	Field _light:Light
-	
 	Field _ground:Model
 	Field _ground:Model
-	
 	Field _donut:Model
 	Field _donut:Model
 	
 	
+	
 	Method New( title:String="Simple mojo3d app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
 	Method New( title:String="Simple mojo3d app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
-
+		
 		Super.New( title,width,height,flags )
 		Super.New( title,width,height,flags )
+	End
+	
+	Method OnCreateWindow() Override
 		
 		
 		'create (current) scene
 		'create (current) scene
-		'
 		_scene=New Scene
 		_scene=New Scene
-		_scene.ShadowAlpha=.75
+		_scene.ClearColor = New Color( 0.2, 0.6, 1.0 )
+		_scene.AmbientLight = _scene.ClearColor * 0.25
+		_scene.FogColor = _scene.ClearColor
+		_scene.FogFar = 1.0
+		_scene.FogFar = 200.0
 		
 		
 		'create camera
 		'create camera
-		'
 		_camera=New Camera( Self )
 		_camera=New Camera( Self )
 		_camera.AddComponent<FlyBehaviour>()
 		_camera.AddComponent<FlyBehaviour>()
-		_camera.Move( 0,10,-5 )
+		_camera.Move( 0,2.5,-5 )
 		
 		
 		'create light
 		'create light
-		'
 		_light=New Light
 		_light=New Light
 		_light.CastsShadow=True
 		_light.CastsShadow=True
-		_light.RotateX( 90 )
+		_light.Rotate( 45, 45, 0 )
 		
 		
 		'create ground
 		'create ground
-		'
-		Local groundBox:=New Boxf( -50,-1,-50,50,0,50 )
-		Local groundMaterial:=New PbrMaterial( Color.Green )
+		Local groundBox:=New Boxf( -100,-1,-100,100,0,100 )
+		Local groundMaterial:=New PbrMaterial( Color.Lime )
 		_ground=Model.CreateBox( groundBox,1,1,1,groundMaterial )
 		_ground=Model.CreateBox( groundBox,1,1,1,groundMaterial )
 		_ground.CastsShadow=False
 		_ground.CastsShadow=False
 		
 		
-		'create dount
-		'		
-		Local donutMaterial:=New PbrMaterial( Color.Brown )
+		'create donut
+		Local donutMaterial:=New PbrMaterial( Color.Red, 0.05, 0.2 )
 		_donut=Model.CreateTorus( 2,.5,48,24,donutMaterial )
 		_donut=Model.CreateTorus( 2,.5,48,24,donutMaterial )
-		_donut.Move( 0,10,0 )
+		_donut.Move( 0,2.5,0 )
 	End
 	End
 	
 	
 	Method OnRender( canvas:Canvas ) Override
 	Method OnRender( canvas:Canvas ) Override
-	
-		RequestRender()
 		
 		
+		RequestRender()
 		_donut.Rotate( .2,.4,.6 )
 		_donut.Rotate( .2,.4,.6 )
-
 		_scene.Update()
 		_scene.Update()
-		
 		_camera.Render( canvas )
 		_camera.Render( canvas )
-		
 		canvas.DrawText( "FPS="+App.FPS,0,0 )
 		canvas.DrawText( "FPS="+App.FPS,0,0 )
 	End
 	End
 	
 	

BIN
assets/themes/irc/blink.png


BIN
assets/themes/irc/important.png


BIN
assets/themes/irc/notice.png


+ 4 - 1
assets/themes/ted2-default.json

@@ -13,7 +13,10 @@
 		"codemap-background": "transparent",
 		"codemap-background": "transparent",
 		"codemap-selection": "#48000000",
 		"codemap-selection": "#48000000",
 		"params-hint-common": "textview-color1",
 		"params-hint-common": "textview-color1",
-		"params-hint-selected": "textview-color4"
+		"params-hint-selected": "textview-color4",
+		"completion-list-selected": "content",
+		"completion-list-marked-bg": "#0fff",
+		"completion-list-marked-text": "textview-color4"
 	},
 	},
 
 
 	"fonts":{
 	"fonts":{

+ 7 - 7
assets/themes/theme-hollow.json

@@ -8,9 +8,9 @@
 		"normal":"Roboto-Medium.ttf,16",
 		"normal":"Roboto-Medium.ttf,16",
 		"fixedWidth":"RobotoMono-Medium.ttf,19",
 		"fixedWidth":"RobotoMono-Medium.ttf,19",
 		"small":"Roboto-Medium.ttf,14",
 		"small":"Roboto-Medium.ttf,14",
-		"editor":"MesloLGSDZ-Bold.ttf,19"
+		"editor":"SourceCodePro-Medium.otf,19"
 	},
 	},
-
+	
 	"colors":{
 	"colors":{
 
 
 		"border": "#121111",
 		"border": "#121111",
@@ -36,12 +36,12 @@
 		"textview-whitespaces":"bright",
 		"textview-whitespaces":"bright",
 
 
 		"textview-color0":"#FF00FF", 	//When is this used?
 		"textview-color0":"#FF00FF", 	//When is this used?
-		"textview-color1": "#EBDAB4",	//identifiers
-		"textview-color2": "#FB4934",	//keywords
-		"textview-color3": "#B8BB26",	//strings
-		"textview-color4": "#B087D2",	//numbers
+		"textview-color1": "#FFFBF2",	//identifiers
+		"textview-color2": "#FA3E28",	//keywords
+		"textview-color3": "#C4C722",	//strings
+		"textview-color4": "#B77FE5",	//numbers
 		"textview-color5": "#6F665E",	//comment
 		"textview-color5": "#6F665E",	//comment
-		"textview-color6": "#FABD2F",	//preproc
+		"textview-color6": "#FDBD28",	//preproc
 		"textview-color7": "#8EC07C",
 		"textview-color7": "#8EC07C",
 		
 		
 		"windowClearColor":"darkest",
 		"windowClearColor":"darkest",

+ 2 - 2
assets/themes/theme-prime-base.json

@@ -7,9 +7,9 @@
 		"normal":"Roboto-Medium.ttf,16",
 		"normal":"Roboto-Medium.ttf,16",
 		"fixedWidth":"RobotoMono-Medium.ttf,18",
 		"fixedWidth":"RobotoMono-Medium.ttf,18",
 		"small":"Roboto-Medium.ttf,13",
 		"small":"Roboto-Medium.ttf,13",
-		"editor":"MesloLGSDZ-Bold.ttf,18"
+		"editor":"SourceCodePro-Medium.otf,19"
 	},
 	},
-
+	
 	"colors":{
 	"colors":{
 
 
 		// "accent": "",
 		// "accent": "",

+ 41 - 41
dialog/PrefsDialog.monkey2

@@ -5,6 +5,7 @@ Namespace ted2go
 Class PrefsDialog Extends DialogExt
 Class PrefsDialog Extends DialogExt
 
 
 	Field Apply:Void()
 	Field Apply:Void()
+	Field TabulationChanged:Void()
 	
 	
 	Method New()
 	Method New()
 		
 		
@@ -28,11 +29,6 @@ Class PrefsDialog Extends DialogExt
 		docker=GetCompletionDock()
 		docker=GetCompletionDock()
 		tabView.AddTab( "AutoComplete",docker )
 		tabView.AddTab( "AutoComplete",docker )
 		
 		
-		' Chat
-		'
-		docker=GetChatDock()
-		tabView.AddTab( "IRC chat",docker )
-		
 		' Live Templates
 		' Live Templates
 		'
 		'
 		docker=GetLiveTemplatesDock()
 		docker=GetLiveTemplatesDock()
@@ -49,7 +45,14 @@ Class PrefsDialog Extends DialogExt
 		
 		
 		_acShowAfter.Activated+=_acShowAfter.MakeKeyView
 		_acShowAfter.Activated+=_acShowAfter.MakeKeyView
 		
 		
-		Deactivated+=MainWindow.UpdateKeyView
+		Deactivated+=Lambda()
+			MainWindow.UpdateKeyView()
+			_lastTab=tabView.CurrentIndex
+		End
+		
+		OnShow+=Lambda()
+			tabView.CurrentIndex=_lastTab
+		End
 		
 		
 		MinSize=New Vec2i( 550,500 )
 		MinSize=New Vec2i( 550,500 )
 		MaxSize=New Vec2i( 550,600 )
 		MaxSize=New Vec2i( 550,600 )
@@ -80,6 +83,9 @@ Class PrefsDialog Extends DialogExt
 	Field _editorAutoPairs:CheckButton
 	Field _editorAutoPairs:CheckButton
 	Field _editorSurround:CheckButton
 	Field _editorSurround:CheckButton
 	Field _editorShowParamsHint:CheckButton
 	Field _editorShowParamsHint:CheckButton
+	Field _editorUseSpacesAsTabs:CheckButton
+	Field _editorTabSize:TextFieldExt
+	Field _editorRemoveLinesTrailing:CheckButton
 	
 	
 	Field _mainToolBarVisible:CheckButton
 	Field _mainToolBarVisible:CheckButton
 	Field _mainProjectIcons:CheckButton
 	Field _mainProjectIcons:CheckButton
@@ -97,6 +103,9 @@ Class PrefsDialog Extends DialogExt
 	Field _codeView:Ted2CodeTextView
 	Field _codeView:Ted2CodeTextView
 	Field _treeView:TreeViewExt
 	Field _treeView:TreeViewExt
 	
 	
+	Global _lastTab:Int
+	
+	
 	Method OnApply()
 	Method OnApply()
 	
 	
 		Prefs.AcEnabled=_acEnabled.Checked
 		Prefs.AcEnabled=_acEnabled.Checked
@@ -125,23 +134,25 @@ Class PrefsDialog Extends DialogExt
 		Prefs.EditorAutoPairs=_editorAutoPairs.Checked
 		Prefs.EditorAutoPairs=_editorAutoPairs.Checked
 		Prefs.EditorSurroundSelection=_editorSurround.Checked
 		Prefs.EditorSurroundSelection=_editorSurround.Checked
 		Prefs.EditorShowParamsHint=_editorShowParamsHint.Checked
 		Prefs.EditorShowParamsHint=_editorShowParamsHint.Checked
+		Local useSpaces:=Prefs.EditorUseSpacesAsTabs ' store
+		Prefs.EditorUseSpacesAsTabs=_editorUseSpacesAsTabs.Checked
+		size=_editorTabSize.Text.Trim()
+		If Not size Then size="4" 'default
+		Prefs.EditorTabSize=Clamp( Int(size),1,16 )
+		Prefs.EditorRemoveLinesTrailing=_editorRemoveLinesTrailing.Checked
 		
 		
 		Prefs.MainToolBarVisible=_mainToolBarVisible.Checked
 		Prefs.MainToolBarVisible=_mainToolBarVisible.Checked
 		Prefs.MainProjectIcons=_mainProjectIcons.Checked
 		Prefs.MainProjectIcons=_mainProjectIcons.Checked
 		Prefs.MainProjectSingleClickExpanding=_mainProjectSingleClickExpanding.Checked
 		Prefs.MainProjectSingleClickExpanding=_mainProjectSingleClickExpanding.Checked
 		Prefs.MainPlaceDocsAtBegin=_mainPlaceDocsAtBegin.Checked
 		Prefs.MainPlaceDocsAtBegin=_mainPlaceDocsAtBegin.Checked
 		
 		
-		Prefs.IrcNickname=_chatNick.Text
-		Prefs.IrcServer=_chatServer.Text
-		Prefs.IrcPort=Int(_chatPort.Text)
-		Prefs.IrcRooms=_chatRooms.Text
-		Prefs.IrcConnect=_chatAutoConnect.Checked
-		
 		App.ThemeChanged()
 		App.ThemeChanged()
 		
 		
 		Hide()
 		Hide()
 		Apply()
 		Apply()
 		
 		
+		If Prefs.EditorUseSpacesAsTabs<>useSpaces Then TabulationChanged()
+		
 		Prefs.SaveLocalState()
 		Prefs.SaveLocalState()
 		
 		
 		LiveTemplates.Save()
 		LiveTemplates.Save()
@@ -188,7 +199,7 @@ Class PrefsDialog Extends DialogExt
 		
 		
 		Local docker:=New DockingView
 		Local docker:=New DockingView
 		Local monkeyPathDock:=New DockingView
 		Local monkeyPathDock:=New DockingView
-		monkeyPathDock.AddView( New Label( "Monkey2 root folder" ),"left" )
+		monkeyPathDock.AddView( New Label( "Monkey2 root folder:" ),"left" )
 		monkeyPathDock.AddView( _monkeyRootPath,"left" )
 		monkeyPathDock.AddView( _monkeyRootPath,"left" )
 		monkeyPathDock.AddView( btnChooseMonkeyPath,"left" )
 		monkeyPathDock.AddView( btnChooseMonkeyPath,"left" )
 		
 		
@@ -234,6 +245,13 @@ Class PrefsDialog Extends DialogExt
 		_editorShowParamsHint=New CheckButton( "Show parameters hint" )
 		_editorShowParamsHint=New CheckButton( "Show parameters hint" )
 		_editorShowParamsHint.Checked=Prefs.EditorShowParamsHint
 		_editorShowParamsHint.Checked=Prefs.EditorShowParamsHint
 		
 		
+		_editorUseSpacesAsTabs=New CheckButton( "Use spaces" )
+		_editorUseSpacesAsTabs.Checked=Prefs.EditorUseSpacesAsTabs
+		_editorTabSize=New TextFieldExt( ""+Prefs.EditorTabSize )
+		
+		_editorRemoveLinesTrailing=New CheckButton( "Remove whitespaced trailings on saving" )
+		_editorRemoveLinesTrailing.Checked=Prefs.EditorRemoveLinesTrailing
+		
 		Local path:=Prefs.EditorFontPath
 		Local path:=Prefs.EditorFontPath
 		If Not path Then path=_defaultFont
 		If Not path Then path=_defaultFont
 		_editorFontPath=New TextFieldExt( "" )
 		_editorFontPath=New TextFieldExt( "" )
@@ -269,12 +287,18 @@ Class PrefsDialog Extends DialogExt
 		Local btnResetFont:=New PushButton( resetFont )
 		Local btnResetFont:=New PushButton( resetFont )
 		
 		
 		Local font:=New DockingView
 		Local font:=New DockingView
-		font.AddView( New Label( "Font" ),"left" )
+		font.AddView( New Label( "Font:" ),"left" )
 		font.AddView( _editorFontPath,"left" )
 		font.AddView( _editorFontPath,"left" )
 		font.AddView( _editorFontSize,"left","45" )
 		font.AddView( _editorFontSize,"left","45" )
 		font.AddView( btnChooseFont,"left" )
 		font.AddView( btnChooseFont,"left" )
 		font.AddView( btnResetFont,"left" )
 		font.AddView( btnResetFont,"left" )
 		
 		
+		Local tabs:=New DockingView
+		tabs.AddView( New Label( "Tab size:" ),"left" )
+		_editorTabSize.MaxSize=New Vec2i( 100,100 )
+		tabs.AddView( _editorTabSize,"left" )
+		tabs.AddView( _editorUseSpacesAsTabs,"left" )
+		
 		Local docker:=New DockingView
 		Local docker:=New DockingView
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( _editorToolBarVisible,"top" )
 		docker.AddView( _editorToolBarVisible,"top" )
@@ -287,8 +311,11 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( _editorAutoPairs,"top" )
 		docker.AddView( _editorAutoPairs,"top" )
 		docker.AddView( _editorSurround,"top" )
 		docker.AddView( _editorSurround,"top" )
 		docker.AddView( _editorShowParamsHint,"top" )
 		docker.AddView( _editorShowParamsHint,"top" )
+		docker.AddView( _editorRemoveLinesTrailing,"top" )
+		docker.AddView( tabs,"top" )
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( New Label( " " ),"top" )
 		
 		
+		
 		Return docker
 		Return docker
 	End
 	End
 	
 	
@@ -340,33 +367,6 @@ Class PrefsDialog Extends DialogExt
 		Return docker
 		Return docker
 	End
 	End
 	
 	
-	Method GetChatDock:DockingView()
-		
-		Local chatTable:=New TableView( 2,6 )
-		_chatNick=New TextFieldExt( Prefs.IrcNickname )
-		_chatServer=New TextFieldExt( Prefs.IrcServer )
-		_chatPort=New TextFieldExt( ""+Prefs.IrcPort )
-		_chatRooms=New TextFieldExt( Prefs.IrcRooms )
-		_chatAutoConnect=New CheckButton( "Auto connect at start" )
-		_chatAutoConnect.Checked=Prefs.IrcConnect
-		chatTable[0,0]=New Label( "Nickname" )
-		chatTable[1,0]=_chatNick
-		chatTable[0,1]=New Label( "Server" )
-		chatTable[1,1]=_chatServer
-		chatTable[0,2]=New Label( "Port" )
-		chatTable[1,2]=_chatPort
-		chatTable[0,3]=New Label( "Rooms" )
-		chatTable[1,3]=_chatRooms
-		chatTable[0,4]=_chatAutoConnect
-		chatTable[0,5]=New Label( "" ) 'bottom padding hack
-		
-		Local docker:=New DockingView
-		docker.AddView( New Label( " " ),"top" )
-		docker.AddView( chatTable,"top" )
-		
-		Return docker
-	End
-	
 	Method GetLiveTemplatesDock:DockingView()
 	Method GetLiveTemplatesDock:DockingView()
 	
 	
 		Local treeDock:=New DockingView
 		Local treeDock:=New DockingView

+ 219 - 61
document/CodeDocument.monkey2

@@ -157,7 +157,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				Local indent:=Utils.GetIndent( s )
 				Local indent:=Utils.GetIndent( s )
 				Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 				Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 				If indent > 0 Then s=s.Slice(indent)
 				If indent > 0 Then s=s.Slice(indent)
-				Local x:=RenderStyle.Font.TextWidth( indentStr )*TabStop
+				indentStr=indentStr.Replace( "~t"," ".Dup(Prefs.EditorTabSize) )
+				Local x:=RenderStyle.Font.TextWidth( indentStr )
 				Local w:=RenderStyle.Font.TextWidth( s )
 				Local w:=RenderStyle.Font.TextWidth( s )
 				DrawCurvedLine( canvas,x,x+w,(err.line+1)*LineHeight )
 				DrawCurvedLine( canvas,x,x+w,(err.line+1)*LineHeight )
 			Next
 			Next
@@ -198,6 +199,53 @@ Class CodeDocumentView Extends Ted2CodeTextView
 '					Endif
 '					Endif
 '				#Endif
 '				#Endif
 				
 				
+				Case Key.D
+					
+					Local ok:=ctrl
+					#If __TARGET__="macos"
+					ok=ok And shift
+					#Endif
+					
+					If ok ' duplicate line or selection
+						
+						Local cur:=Cursor,anc:=Anchor
+						If cur=anc ' duplicate whole line
+							
+							Local pos:=PosInLineAtCursor
+							Local line:=Document.FindLine( cur )
+							Local s:=LineTextAtCursor
+							Local ends:=Document.EndOfLine( line )
+							ReplaceText( ends,ends,"~n"+s )
+							pos=pos+StartOfLineAtCursor
+							SelectText( pos,pos )
+							
+						Else ' duplicate selection
+							
+							Local min:=Min( Cursor,Anchor )
+							Local max:=Max( Cursor,Anchor )
+							Local selLen:=max-min
+							Local s:=SelectedText
+							Local atEnd:=(max=Document.EndOfLine( Document.FindLine( max ) ))
+							If atEnd
+								Local minLine:=Document.FindLine( min )
+								Local s0:=Document.GetLine( minLine )
+								Local pos:=min-Document.StartOfLine( minLine )
+								Local indent:=Min( GetIndent( s0 ),pos )
+								Local indentStr:=(indent>0) ? s0.Slice( 0,indent ) Else ""
+								s="~n"+indentStr+s
+								selLen+=indentStr.Length
+							Endif
+							SelectText( max,max )
+							ReplaceText( s )
+							Local pos:=max+Int(atEnd)
+							SelectText( pos,pos+selLen )
+							
+						Endif
+						
+						Return
+						
+					Endif
+					
 				Case Key.Space
 				Case Key.Space
 					If ctrl
 					If ctrl
 						Return
 						Return
@@ -219,21 +267,40 @@ Class CodeDocumentView Extends Ted2CodeTextView
 						
 						
 					Else
 					Else
 						
 						
-'						#If __TARGET__="macos"
-'						If menu
-'							DeleteToBegin()
-'						Elseif ctrl
-'							DeleteWordBeforeCursor()
-'						Endif
-'						#Else
-'						If ctrl
-'							If shift
-'								DeleteToBegin()
-'							Else
-'								DeleteWordBeforeCursor()
-'							Endif
-'						Endif
-'						#Endif
+						' remove all indent spaces by single press of Backspace
+						If Cursor=Anchor And Prefs.EditorUseSpacesAsTabs
+							
+							Local color:=Document.Colors[Cursor]
+							
+							' skip comments and strings areas
+							If color<>Highlighter.COLOR_COMMENT And color<>Highlighter.COLOR_STRING
+								
+								Local posInLine:=PosInLineAtCursor
+								Local line:=LineTextAtCursor
+								
+								' check for spaces only, tab will be removed by super class
+								If posInLine>0 And line[posInLine-1]=Chars.SPACE
+								
+									Local pos:=GetPosInLineAtCursorCheckingTabSize()
+									Local canRemoveCount:=(pos Mod Prefs.EditorTabSize)
+									If canRemoveCount=0 Then canRemoveCount=Prefs.EditorTabSize
+									Local i:=posInLine-1,counter:=canRemoveCount
+									
+									While counter>0
+										If line[i]<>Chars.SPACE Exit
+										counter-=1
+										i-=1
+									Wend
+									If counter>1 Then counter+=1 ' don't remove space nearest to another char (is it correct?)
+									canRemoveCount-=counter
+									SelectText( Cursor,Cursor-canRemoveCount )
+									
+								Endif
+								
+							Endif
+							
+						Endif
+						
 						
 						
 					Endif
 					Endif
 				
 				
@@ -313,7 +380,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 			
 			
 			
 				Case Key.Enter,Key.KeypadEnter 'auto indent
 				Case Key.Enter,Key.KeypadEnter 'auto indent
-			
+					
 					Local line:=CursorLine
 					Local line:=CursorLine
 					Local text:=Document.GetLine( line )
 					Local text:=Document.GetLine( line )
 					Local indent:=GetIndent( text )
 					Local indent:=GetIndent( text )
@@ -322,19 +389,23 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					'in this case GetLine return 2 lines, and if they empty
 					'in this case GetLine return 2 lines, and if they empty
 					'then we get double indent
 					'then we get double indent
 					'need to fix inside mojox
 					'need to fix inside mojox
-			
+					
 					Local beforeIndent:=(posInLine<=indent)
 					Local beforeIndent:=(posInLine<=indent)
-			
+					
 					If indent > posInLine Then indent=posInLine
 					If indent > posInLine Then indent=posInLine
-			
+					
 					Local s:=(indent ? text.Slice( 0,indent ) Else "")
 					Local s:=(indent ? text.Slice( 0,indent ) Else "")
-			
+					
+					If Prefs.EditorUseSpacesAsTabs
+						s=s.Replace( "~t",TabStr )
+					Endif
+					
 					' auto indentation
 					' auto indentation
 					If Prefs.EditorAutoIndent And Not beforeIndent
 					If Prefs.EditorAutoIndent And Not beforeIndent
 						text=text.Trim().ToLower()
 						text=text.Trim().ToLower()
 						If text.StartsWith( "if" )
 						If text.StartsWith( "if" )
 							If Not Utils.BatchContains( text,_arrIf,True )
 							If Not Utils.BatchContains( text,_arrIf,True )
-								s="~t"+s
+								s=TabStr+s
 							Endif
 							Endif
 						Elseif Utils.BatchStartsWith( text,_arrAddonIndents,True )
 						Elseif Utils.BatchStartsWith( text,_arrAddonIndents,True )
 							
 							
@@ -345,7 +416,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 								If scope And scope.Kind=CodeItemKind.Interface_
 								If scope And scope.Kind=CodeItemKind.Interface_
 									' nothing
 									' nothing
 								Else
 								Else
-									s="~t"+s
+									s=TabStr+s
 								Endif
 								Endif
 							Endif
 							Endif
 						Endif
 						Endif
@@ -414,68 +485,82 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 			
 						' live templates by tab!
 						' live templates by tab!
 						Local ident:=IdentBeforeCursor()
 						Local ident:=IdentBeforeCursor()
-						If InsertLiveTemplate( ident ) Return
+						If InsertLiveTemplate( ident ) Return ' exit method
+						
+					Endif
+					
+					If Cursor = Anchor And Not shift
+						
+						' usual tab behaviour - insert tab or spaced-equivalent-of-tab
+						InsertTabulation()
+						
+					Else ' tab/untab selection
 						
 						
-						' usual tab behaviour
-						If Not shift
-							ReplaceText( "~t" )
-						Else
-							If Cursor > 0 And Document.Text[Cursor-1]=Chars.TAB
-								SelectText( Cursor-1,Cursor )
-								ReplaceText( "" )
-							Endif
-						Endif
-			
-					Else 'block tab/untab
-			
 						Local minPos:=Min( Cursor,Anchor )
 						Local minPos:=Min( Cursor,Anchor )
 						Local maxPos:=Max( Cursor,Anchor )
 						Local maxPos:=Max( Cursor,Anchor )
 						Local min:=Document.FindLine( minPos )
 						Local min:=Document.FindLine( minPos )
 						Local max:=Document.FindLine( maxPos )
 						Local max:=Document.FindLine( maxPos )
-			
+						
 						' if we are at the beginning of bottom line - skip it
 						' if we are at the beginning of bottom line - skip it
 						Local strt:=Document.StartOfLine( max )
 						Local strt:=Document.StartOfLine( max )
 						If maxPos = strt
 						If maxPos = strt
 							max-=1
 							max-=1
 						Endif
 						Endif
-			
+						
 						Local lines:=New StringStack
 						Local lines:=New StringStack
-			
+						
 						For Local i:=min To max
 						For Local i:=min To max
 							lines.Push( Document.GetLine( i ) )
 							lines.Push( Document.GetLine( i ) )
 						Next
 						Next
-			
+						
 						Local go:=True
 						Local go:=True
 						Local shiftFirst:=0,shiftLast:=0
 						Local shiftFirst:=0,shiftLast:=0
-			
+						Local tabStr:=TabStr
+						
 						If shift
 						If shift
-			
+							
 							Local changes:=0
 							Local changes:=0
 							For Local i:=0 Until lines.Length
 							For Local i:=0 Until lines.Length
-								If lines[i].StartsWith( "~t" )
+								
+								If lines[i].StartsWith( tabStr ) ' try to remove tab or spaces
+								
+									lines[i]=lines[i].Slice( tabStr.Length )+"~n"
+									changes+=1
+									If i=0 Then shiftFirst=-tabStr.Length
+									If i=lines.Length-1 Then shiftLast=-tabStr.Length
+								
+								Elseif tabStr<>"~t" And lines[i].StartsWith( "~t" ) ' for spaces-mode also try to remove tabs (mixed indentation)
+								
 									lines[i]=lines[i].Slice( 1 )+"~n"
 									lines[i]=lines[i].Slice( 1 )+"~n"
 									changes+=1
 									changes+=1
 									If i=0 Then shiftFirst=-1
 									If i=0 Then shiftFirst=-1
-									if i=lines.Length-1 Then shiftLast=-1
+									If i=lines.Length-1 Then shiftLast=-1
+								
 								Else
 								Else
+								
 									lines[i]+="~n"
 									lines[i]+="~n"
+								
 								Endif
 								Endif
 							Next
 							Next
 			
 			
 							go=(changes > 0)
 							go=(changes > 0)
+							
 						Else
 						Else
-							shiftFirst=1
-							shiftLast=1
+							
+							shiftFirst=tabStr.Length
+							shiftLast=tabStr.Length
 							For Local i:=0 Until lines.Length
 							For Local i:=0 Until lines.Length
-								lines[i]="~t"+lines[i]+"~n"
+								lines[i]=tabStr+lines[i]+"~n"
 							Next
 							Next
+							
 						Endif
 						Endif
 			
 			
 						If go
 						If go
+							
 							Local minStart:=Document.StartOfLine( min )
 							Local minStart:=Document.StartOfLine( min )
 							Local maxStart:=Document.StartOfLine( max )
 							Local maxStart:=Document.StartOfLine( max )
 							Local maxEnd:=Document.EndOfLine( max )
 							Local maxEnd:=Document.EndOfLine( max )
-			
+							
 							Local p1:=minPos+shiftFirst 'absolute pos
 							Local p1:=minPos+shiftFirst 'absolute pos
 							Local p2:=maxPos-maxStart+shiftLast 'pos in line
 							Local p2:=maxPos-maxStart+shiftLast 'pos in line
 							SelectText( minStart,maxEnd+1 )
 							SelectText( minStart,maxEnd+1 )
@@ -485,7 +570,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 							p1=Max( p1,Document.StartOfLine( min ) )
 							p1=Max( p1,Document.StartOfLine( min ) )
 							SelectText( p1,p2 )
 							SelectText( p1,p2 )
 						Endif
 						Endif
-			
+						
 					Endif
 					Endif
 					
 					
 					CheckFormat( event )
 					CheckFormat( event )
@@ -711,7 +796,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Local indent:=Utils.GetIndent( s )
 					Local indent:=Utils.GetIndent( s )
 					Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 					Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 					If indent > 0 Then s=s.Slice(indent)
 					If indent > 0 Then s=s.Slice(indent)
-					Local x:=RenderStyle.Font.TextWidth( indentStr )*TabStop
+					indentStr=indentStr.Replace( "~t"," ".Dup(Prefs.EditorTabSize) )
+					Local x:=RenderStyle.Font.TextWidth( indentStr )
 					Local w:=RenderStyle.Font.TextWidth( s )
 					Local w:=RenderStyle.Font.TextWidth( s )
 					If event.Location.x >= x And event.Location.x <= x+w
 					If event.Location.x >= x And event.Location.x <= x+w
 						Local s:=_doc.GetStringError( line )
 						Local s:=_doc.GetStringError( line )
@@ -793,7 +879,7 @@ Class CodeDocument Extends Ted2Document
 		
 		
 		' Editor
 		' Editor
 		_codeView=New CodeDocumentView( Self )
 		_codeView=New CodeDocumentView( Self )
-		_codeView.LineChanged += OnLineChanged
+		_codeView.LineNumChanged += OnLineChanged
 		
 		
 		_doc=_codeView.Document
 		_doc=_codeView.Document
 		
 		
@@ -844,10 +930,41 @@ Class CodeDocument Extends Ted2Document
 			MainWindow.GotoCodePosition( nav.filePath,nav.pos )
 			MainWindow.GotoCodePosition( nav.filePath,nav.pos )
 		End
 		End
 		
 		
-		' update 
-'		Monkey2Parser.OnDoneParseModules+=Lambda( deltaMs:Int )
-'			UpdateCodeTree()
-'		End
+		' fix indentation panel
+		'
+		_fixIndentView=New DockingView
+		_fixIndentHint=New Label
+		_fixIndentButton=New Button( "Yes" )
+		_fixIndentButton.Clicked=Lambda()
+			' store cursor position
+			Local line:=_codeView.LineNumAtCursor
+			Local posInLine:=_codeView.PosInLineAtCursor
+			Local scroll:=_codeView.Scroll
+			' get fixed text
+			Local text:=IndentationHelper.FixIndentation( _codeView.Document )
+			' replacing allow us to use undo
+			_codeView.SelectAll()
+			_codeView.ReplaceText( text )
+			' restore cursor
+			Local cursor:=_codeView.Document.StartOfLine( line )+posInLine
+			_codeView.SelectText( cursor,cursor )
+			_codeView.Scroll=scroll
+			' 
+			_fixIndentView.Visible=False
+		End
+		Local fixIndentCancel:=New Button( "No" )
+		fixIndentCancel.Clicked=Lambda()
+			
+			_fixIndentView.Visible=False
+		End
+		_fixIndentView.AddView( New Label( " " ),"right" )
+		_fixIndentView.AddView( fixIndentCancel,"right" )
+		_fixIndentView.AddView( New Label( " " ),"right" )
+		_fixIndentView.AddView( _fixIndentButton,"right" )
+		_fixIndentView.AddView( New Label( " " ),"right" )
+		_fixIndentView.AddView( _fixIndentHint,"right" )
+		_fixIndentView.Visible=False
+		_content.AddView( _fixIndentView,"bottom" )
 		
 		
 		ArrangeElements()
 		ArrangeElements()
 	End
 	End
@@ -903,7 +1020,6 @@ Class CodeDocument Extends Ted2Document
 		_browserView.AddView( bar,"top" )
 		_browserView.AddView( bar,"top" )
 		
 		
 		
 		
-		
 		_treeView=New CodeTreeView
 		_treeView=New CodeTreeView
 		_browserView.ContentView=_treeView
 		_browserView.ContentView=_treeView
 		
 		
@@ -922,6 +1038,37 @@ Class CodeDocument Extends Ted2Document
 		Return _browserView
 		Return _browserView
 	End
 	End
 	
 	
+	Method AnalyzeIndentation()
+		
+		Local text:=_codeView.Text
+		If Not text Return
+		
+		Local useSpaces:=Prefs.EditorUseSpacesAsTabs
+		Local hint:=""
+		Local type:=IndentationHelper.AnalyzeIndentation( text )
+		
+		Select type
+			Case IndentationHelper.Type.Spaces
+				If Not useSpaces Then hint="There is a spaced indentation found."
+				
+			Case IndentationHelper.Type.Tabs
+				If useSpaces Then hint="There is a tabbed indentation found."
+				
+			Case IndentationHelper.Type.Mixed
+				hint="There is a mixed indentation found."
+				
+		End
+		
+		If hint
+			Local quest:=Prefs.EditorUseSpacesAsTabs ? "Replace with spaces?" Else "Replace with tabs?"
+			_fixIndentHint.Text=hint+" "+quest
+			_fixIndentView.Visible=True
+		Else
+			_fixIndentView.Visible=False
+		Endif
+		
+	End
+	
 	' not multipurpose method, need to move into plugin
 	' not multipurpose method, need to move into plugin
 	Method PrepareForInsert:String( ident:String,text:String,addSpace:Bool,textLine:String,cursorPosInLine:Int,item:CodeItem )
 	Method PrepareForInsert:String( ident:String,text:String,addSpace:Bool,textLine:String,cursorPosInLine:Int,item:CodeItem )
 		
 		
@@ -1135,7 +1282,7 @@ Class CodeDocument Extends Ted2Document
 	
 	
 	Method ShowAutocomplete( ident:String="",byCtrlSpace:Bool=False )
 	Method ShowAutocomplete( ident:String="",byCtrlSpace:Bool=False )
 		
 		
-		If ident = "" Then ident=_codeView.IdentBeforeCursor()
+		If Not ident Then ident=_codeView.IdentBeforeCursor()
 		
 		
 		Print "ident: "+ident
 		Print "ident: "+ident
 		
 		
@@ -1241,6 +1388,9 @@ Class CodeDocument Extends Ted2Document
 	Field _codeView:CodeDocumentView
 	Field _codeView:CodeDocumentView
 	Field _treeView:CodeTreeView
 	Field _treeView:CodeTreeView
 	Field _browserView:DockingView
 	Field _browserView:DockingView
+	Field _fixIndentView:DockingView
+	Field _fixIndentHint:Label
+	Field _fixIndentButton:Button
 	
 	
 	Field _errors:=New Stack<BuildError>
 	Field _errors:=New Stack<BuildError>
 	Field _errMap:=New IntMap<String>
 	Field _errMap:=New IntMap<String>
@@ -1367,7 +1517,15 @@ Class CodeDocument Extends Ted2Document
 	
 	
 		'ResetErrors()
 		'ResetErrors()
 		
 		
-		Local text:=_doc.Text
+		Local text:=""
+		
+		If Prefs.EditorRemoveLinesTrailing
+			Local linesChanged:=0
+			text=RemoveWhitespacedTrailings( _doc,Varptr linesChanged )
+			If linesChanged>0 Then _codeView.SetTextSilent( text ) ' set text saving cursor/anchor/scroll
+		Else
+			text=_doc.Text
+		Endif
 		
 		
 		Local ok:=stringio.SaveString( text,Path )
 		Local ok:=stringio.SaveString( text,Path )
 	
 	
@@ -1562,8 +1720,8 @@ Class CodeDocument Extends Ted2Document
 						j-=1
 						j-=1
 					Wend
 					Wend
 					j+=1
 					j+=1
-					Local pair:=GetIndentBeforePos_Mx2( line,j,True )
-					Local ident:=pair.Item1
+					Local info:=GetIndentBeforePos_Mx2( line,j,True )
+					Local ident:=info.ident
 					'Print "ident: "+ident'+", paramIndex: "+paramIndex+", isNew: "+isNew
 					'Print "ident: "+ident'+", paramIndex: "+paramIndex+", isNew: "+isNew
 					If ident
 					If ident
 						part=New ParamsPart
 						part=New ParamsPart
@@ -1573,7 +1731,7 @@ Class CodeDocument Extends Ted2Document
 						part.ranges.Add( New Vec2i( i,0 ) )
 						part.ranges.Add( New Vec2i( i,0 ) )
 						
 						
 						' check for 'New' keyword
 						' check for 'New' keyword
-						j=pair.Item2-1 'where ident starts
+						j=info.pos-1 'where ident starts
 						While j>=0 And line[j]<=32
 						While j>=0 And line[j]<=32
 							j-=1
 							j-=1
 						Wend
 						Wend

+ 3 - 27
document/Monkey2Document.monkey2

@@ -354,35 +354,11 @@ Class Monkey2DocumentView Extends Ted2TextView
 			Local ident:=IdentNearestCursor()
 			Local ident:=IdentNearestCursor()
 				
 				
 			If ident MainWindow.ShowQuickHelp( ident )
 			If ident MainWindow.ShowQuickHelp( ident )
-				
-		Case Key.F2
 			
 			
-			New Fiber( Lambda()
-				
-				Local cmd:="~q"+MainWindow.Mx2ccPath+"~q makeapp -parse -geninfo ~q"+_doc.Path+"~q"
-					
-				Local str:=LoadString( "process::"+cmd )
-				Local i:=str.Find( "{" )
-				If i=-1 Return
-				str=str.Slice( i )
-					
-				Local jobj:=JsonObject.Parse( str )
-				If Not jobj Return
-					
-				Local jsonTree:=New JsonTreeView( jobj )
-					
-				Local dialog:=New Dialog( "ParseInfo",jsonTree )
-				dialog.AddAction( "Close" ).Triggered=dialog.Close
-				dialog.MinSize=New Vec2i( 512,600 )
-					
-				dialog.Open()
-				
-			End )
-				
 		Case Key.Tab,Key.Enter
 		Case Key.Tab,Key.Enter
 			
 			
 			If _typing Capitalize( False )
 			If _typing Capitalize( False )
-				
+			
 		Case Key.Left
 		Case Key.Left
 			
 			
 			If _typing
 			If _typing
@@ -392,7 +368,7 @@ Class Monkey2DocumentView Extends Ted2TextView
 					Capitalize( True )
 					Capitalize( True )
 				Endif
 				Endif
 			Endif
 			Endif
-				
+			
 		Case Key.Right
 		Case Key.Right
 			
 			
 			If _typing
 			If _typing
@@ -402,7 +378,7 @@ Class Monkey2DocumentView Extends Ted2TextView
 					Capitalize( True )
 					Capitalize( True )
 				Endif
 				Endif
 			Endif
 			Endif
-				
+			
 		Case Key.Up,Key.Down
 		Case Key.Up,Key.Down
 			
 			
 			Capitalize( True )	'in cased we missed anything...
 			Capitalize( True )	'in cased we missed anything...

+ 1 - 1
document/SceneDocument.monkey2

@@ -109,7 +109,7 @@ Class SceneDocument Extends Ted2Document
 		_camera.Near=.01
 		_camera.Near=.01
 		_camera.Far=10
 		_camera.Far=10
 		_camera.MoveZ( -2.5 )
 		_camera.MoveZ( -2.5 )
-			
+		
 		_light=New Light
 		_light=New Light
 		_light.RotateX( Pi/2 )
 		_light.RotateX( Pi/2 )
 		
 		

+ 27 - 0
eventfilter/Monkey2KeyEventFilter.monkey2

@@ -31,6 +31,33 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 					MainWindow.GotoDeclaration()
 					MainWindow.GotoDeclaration()
 					event.Eat()
 					event.Eat()
 				
 				
+				Case Key.F10
+				
+					Print "works"
+					Local doc:=MainWindow.DocsManager.CurrentDocument
+					If Not doc Return
+					
+					New Fiber( Lambda()
+						
+						Local cmd:="~q"+MainWindow.Mx2ccPath+"~q makeapp -parse -geninfo ~q"+doc.Path+"~q"
+						
+						Local str:=LoadString( "process::"+cmd )
+						Local i:=str.Find( "{" )
+						If i=-1 Return
+						str=str.Slice( i )
+						
+						Local jobj:=JsonObject.Parse( str )
+						If Not jobj Return
+						
+						Local jsonTree:=New JsonTreeView( jobj )
+						
+						Local dialog:=New Dialog( "ParseInfo",jsonTree )
+						dialog.AddAction( "Close" ).Triggered=dialog.Close
+						dialog.MinSize=New Vec2i( 512,600 )
+						
+						dialog.Open()
+						
+					End )
 			End
 			End
 			
 			
 			
 			

+ 2 - 0
parser/CodeItem.monkey2

@@ -427,6 +427,7 @@ Struct CodeType
 	Field expr:String
 	Field expr:String
 	Field args:CodeType[]
 	Field args:CodeType[]
 	Field isPointer:Bool
 	Field isPointer:Bool
+	Field isArray:Bool
 	
 	
 	Property ident:String()
 	Property ident:String()
 		Return _ident
 		Return _ident
@@ -458,6 +459,7 @@ Struct CodeType
 		Endif
 		Endif
 		
 		
 		If isPointer Then _str+=" Ptr"
 		If isPointer Then _str+=" Ptr"
+		If isArray Then _str+="[]"
 		
 		
 		Return _str
 		Return _str
 	End
 	End

+ 28 - 28
parser/Monkey2Parser.monkey2

@@ -855,6 +855,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 	
 	
 	Method ParseModules()
 	Method ParseModules()
 		
 		
+		'Return
+		
 		Local dd:=LoadDir( _modsPath )
 		Local dd:=LoadDir( _modsPath )
 		
 		
 		' pop up some modules to parse them first
 		' pop up some modules to parse them first
@@ -911,6 +913,10 @@ Class Monkey2Parser Extends CodeParserPlugin
 					Local t:=ParseMember( jobj )
 					Local t:=ParseMember( jobj )
 					t.kind=kind2
 					t.kind=kind2
 					Return t
 					Return t
+				Default
+					If init.Contains( "type" )
+						Return ParseType( init["type"].ToObject() )
+					Endif
 				End
 				End
 			Endif
 			Endif
 			' not found
 			' not found
@@ -924,6 +930,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Local t:=New CodeType
 				Local t:=New CodeType
 				t.kind=kind
 				t.kind=kind
 				t.ident=type["ident"].ToString()
 				t.ident=type["ident"].ToString()
+				t.isArray=type.Contains( "is-array" )
 				Return t
 				Return t
 				
 				
 			Case "functype"
 			Case "functype"
@@ -1043,12 +1050,25 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return result
 		Return result
 	End
 	End
 	
 	
-	Method GetJobjType:Map<String,JsonValue>( jobj:Map<String,JsonValue> )
+	Method ProcessArrayType( child:StringMap<JsonValue>,parent:StringMap<JsonValue> )
+		
+		If parent.Contains( "kind" ) And parent["kind"].ToString()="arraytype"
+			child["is-array"]=New JsonBool( True )
+		Endif
+	End
+	
+	Method GetJobjType:StringMap<JsonValue>( jobj:Map<String,JsonValue> )
 		
 		
 		Local type:Map<String,JsonValue> = Null
 		Local type:Map<String,JsonValue> = Null
 		
 		
 		If jobj.Contains( "type" )
 		If jobj.Contains( "type" )
 			type=jobj["type"].ToObject()
 			type=jobj["type"].ToObject()
+			ProcessArrayType( type,type )
+			While type.Contains( "type" )
+				Local t:=type
+				type=type["type"].ToObject()
+				ProcessArrayType( type,t )
+			Wend
 		Elseif jobj.Contains( "getFunc" )
 		Elseif jobj.Contains( "getFunc" )
 			type=jobj["getFunc"].ToObject()["type"].ToObject()
 			type=jobj["getFunc"].ToObject()["type"].ToObject()
 			' properties have retType
 			' properties have retType
@@ -1057,9 +1077,13 @@ Class Monkey2Parser Extends CodeParserPlugin
 			Endif
 			Endif
 		Elseif jobj.Contains( "init" )
 		Elseif jobj.Contains( "init" )
 			Local init:=jobj["init"].ToObject()
 			Local init:=jobj["init"].ToObject()
-			if init.Contains( "type" )
-				type=init["type"].ToObject()
-			Endif
+			Local t:=init
+			While t.Contains( "type" )
+				Local par:=type
+				t=t["type"].ToObject()
+				type=t
+				If par Then ProcessArrayType( type,par )
+			Wend
 		Endif
 		Endif
 		
 		
 		Return type
 		Return type
@@ -1338,30 +1362,6 @@ Class Monkey2Parser Extends CodeParserPlugin
 End
 End
 
 
 
 
-Struct Chars
-	
-	Const SINGLE_QUOTE:="'"[0] '39
-	Const DOUBLE_QUOTE:="~q"[0] '34
-	Const COMMA:=","[0] '44
-	Const SEMICOLON:=";"[0]
-	Const DOT:="."[0] '46
-	Const EQUALS:="="[0] '61
-	Const LESS_BRACKET:="<"[0] '60
-	Const MORE_BRACKET:=">"[0] '62
-	Const OPENED_SQUARE_BRACKET:="["[0] '91
-	Const CLOSED_SQUARE_BRACKET:="]"[0] '93
-	Const OPENED_ROUND_BRACKET:="("[0] '40
-	Const CLOSED_ROUND_BRACKET:=")"[0] '41
-	Const DIGIT_0:="0"[0] '48
-	Const DIGIT_9:="9"[0] '57
-	Const AT:="@"[0] '64
-	Const GRID:="#"[0] '35
-	Const TAB:="~t"[0] '9
-	Const SPACE:=" "[0] '32
-	
-End
-
-
 Class NSpace
 Class NSpace
 	
 	
 	Field parent:NSpace
 	Field parent:NSpace

+ 2 - 2
testing/ParserTests.monkey2

@@ -64,8 +64,8 @@ End
 Global boo:=True
 Global boo:=True
 
 
 Global multi:="Hello,
 Global multi:="Hello,
-               multiline
-               world!"
+				multiline
+				world!"
 
 
 Global vector:Vec2f
 Global vector:Vec2f
 Global globList:List<String>
 Global globList:List<String>

+ 65 - 0
utils/TextUtils.monkey2

@@ -0,0 +1,65 @@
+
+Namespace ted2go
+
+
+Class TextUtils Final
+	
+	Function GetSpacesForTabEquivalent:String()
+	
+		If Prefs.EditorTabSize<>_storedTabSize
+			_storedTabSize=Prefs.EditorTabSize
+			_spacesForTab=" ".Dup( _storedTabSize )
+		Endif
+	
+		Return _spacesForTab
+	End
+	
+	Function GetPosInLineCheckingTabSize:Int( line:String,posInLine:Int,tabSize:Int )
+	
+		Local pos:=0
+		For Local i:=0 Until posInLine
+			If line[i]=Chars.TAB
+				Local offset:=(pos Mod tabSize)
+				pos+=tabSize-offset
+			Else
+				pos+=1
+			Endif
+		Next
+	
+		Return pos
+	End
+	
+	
+	Private
+	
+	Global _storedTabSize:=0,_spacesForTab:String
+	
+	Method New()
+	End
+	
+End
+
+
+Struct Chars
+	
+	Const SINGLE_QUOTE:="'"[0] '39
+	Const DOUBLE_QUOTE:="~q"[0] '34
+	Const COMMA:=","[0] '44
+	Const SEMICOLON:=";"[0]
+	Const DOT:="."[0] '46
+	Const EQUALS:="="[0] '61
+	Const LESS_BRACKET:="<"[0] '60
+	Const MORE_BRACKET:=">"[0] '62
+	Const OPENED_SQUARE_BRACKET:="["[0] '91
+	Const CLOSED_SQUARE_BRACKET:="]"[0] '93
+	Const OPENED_ROUND_BRACKET:="("[0] '40
+	Const CLOSED_ROUND_BRACKET:=")"[0] '41
+	Const DIGIT_0:="0"[0] '48
+	Const DIGIT_9:="9"[0] '57
+	Const AT:="@"[0] '64
+	Const GRID:="#"[0] '35
+	Const TAB:="~t"[0] '9
+	Const SPACE:=" "[0] '32
+	Const NEW_LINE:="~n"[0] '10
+	
+End

+ 67 - 4
utils/Utils.monkey2

@@ -37,7 +37,7 @@ Function GetCaseSensitivePath:String( path:String )
 #Endif
 #Endif
 End
 End
 
 
-Class Utils
+Class Utils Final
 	
 	
 	Function ArrayContains<T>:Bool( arr:T[],value:T )
 	Function ArrayContains<T>:Bool( arr:T[],value:T )
 		If Not arr Return False
 		If Not arr Return False
@@ -63,13 +63,23 @@ Class Utils
 	End
 	End
 	
 	
 	Function GetIndent:Int( line:String )
 	Function GetIndent:Int( line:String )
+		
 		Local len:=line.Length,n:=0
 		Local len:=line.Length,n:=0
-		While n < len And line[n] <= 32
+		While n < len And line[n] <= Chars.SPACE
 			n+=1
 			n+=1
 		Wend
 		Wend
 		Return n
 		Return n
 	End
 	End
+	
+	Function GetIndentAsSpaces:Int( line:String )
 		
 		
+		Local len:=line.Length,n:=0
+		While n < len And line[n] <= Chars.SPACE
+			n+=(line[n]=Chars.TAB) ? Prefs.EditorTabSize Else 1
+		Wend
+		Return n
+	End
+	
 	Function GetIndentStr:String( line:String )
 	Function GetIndentStr:String( line:String )
 		Local n:=GetIndent( line )
 		Local n:=GetIndent( line )
 		Return  (n > 0) ? line.Slice( 0,n ) Else ""
 		Return  (n > 0) ? line.Slice( 0,n ) Else ""
@@ -172,6 +182,9 @@ Class Utils
 	
 	
 	Private
 	Private
 	
 	
+	Global _storedTabSize:=0,_spacesForTab:String
+	
+	
 	Method New()
 	Method New()
 	End
 	End
 	
 	
@@ -341,14 +354,40 @@ Function StripStarting:String( text:String,starts:String )
 	Return text.StartsWith( starts ) ? text.Slice( starts.Length ) Else text
 	Return text.StartsWith( starts ) ? text.Slice( starts.Length ) Else text
 End
 End
 
 
+' 
+Struct IdentInfo
+	
+	Field pos:Int
+	Field ident:String
+	Field isArray:Bool
+	
+End
+
 #Rem monkeydocs Return ident and position in line where ident starts
 #Rem monkeydocs Return ident and position in line where ident starts
 #End
 #End
-Function GetIndentBeforePos_Mx2:Tuple2<String,Int>( line:String,pos:Int,withDots:Bool )
+Function GetIndentBeforePos_Mx2:IdentInfo( line:String,pos:Int,withDots:Bool )
 	
 	
 	Local n:=pos-1
 	Local n:=pos-1
 	
 	
 	While n >= 0
 	While n >= 0
 	
 	
+		' array syntax: a[i]
+		If line[n]=Chars.CLOSED_SQUARE_BRACKET
+			Local cnt:=1
+			n-=1
+			While n >= 0
+				If line[n]=Chars.CLOSED_SQUARE_BRACKET
+					cnt+=1
+				Elseif line[n]=Chars.OPENED_SQUARE_BRACKET
+					cnt-=1
+					If cnt=0 Exit
+				Endif
+				n-=1
+			Wend
+			n-=1
+			If n<0 Exit
+		Endif
+		
 		Local more:=(line[n]=Chars.MORE_BRACKET)
 		Local more:=(line[n]=Chars.MORE_BRACKET)
 	
 	
 		If line[n] = Chars.DOT Or more ' . | ?. | ->
 		If line[n] = Chars.DOT Or more ' . | ?. | ->
@@ -369,11 +408,35 @@ Function GetIndentBeforePos_Mx2:Tuple2<String,Int>( line:String,pos:Int,withDots
 	
 	
 	Local s:=""
 	Local s:=""
 	Local starts:=-1
 	Local starts:=-1
+	Local arr:=False
 	If n < pos
 	If n < pos
 		starts=n
 		starts=n
 		s=line.Slice( n,pos ).Replace( "?.","." ).Replace( "->","." )
 		s=line.Slice( n,pos ).Replace( "?.","." ).Replace( "->","." )
+		Local i:=s.FindLast( "." )
+		arr=(i>0 And s[i-1]=Chars.CLOSED_SQUARE_BRACKET) ' [i].
+		If s.Find( "[" )<>-1
+			n=0
+			Local s2:="",cnt:=0
+			While n<s.Length
+				If s[n]=Chars.OPENED_SQUARE_BRACKET
+					cnt+=1
+				Elseif s[n]=Chars.CLOSED_SQUARE_BRACKET
+					cnt-=1
+				Elseif cnt=0
+					s2+=String.FromChar( s[n] )
+				Endif
+				n+=1
+			Wend
+			s=s2
+		Endif
 	Endif
 	Endif
-	Return New Tuple2<String,Int>( s,starts )
+	
+	Local info:=New IdentInfo
+	info.ident=s
+	info.pos=starts
+	info.isArray=arr
+	
+	Return info
 End
 End
 
 
 Function IsPosInsideOfQuotes_Mx2:Bool( text:String,pos:Int )
 Function IsPosInsideOfQuotes_Mx2:Bool( text:String,pos:Int )

+ 18 - 5
view/AutocompleteView.monkey2

@@ -28,12 +28,23 @@ Class AutocompleteListView Extends ListViewExt
 	Field word:String 'word to select
 	Field word:String 'word to select
 	
 	
 	Method New( lineHeight:Int,maxLines:Int )
 	Method New( lineHeight:Int,maxLines:Int )
+		
 		Super.New( lineHeight,maxLines )
 		Super.New( lineHeight,maxLines )
+		
+		OnThemeChanged()
 	End
 	End
 	
 	
 	
 	
 	Protected
 	Protected
 	
 	
+	Method OnThemeChanged() Override
+		
+		Super.OnThemeChanged()
+		_selColor=App.Theme.GetColor( "completion-list-selected" )
+		_markedBgColor=App.Theme.GetColor( "completion-list-marked-bg" )
+		_markedTextColor=App.Theme.GetColor( "completion-list-marked-text" )
+	End
+	
 	Method DrawItem( item:ListViewItem,canvas:Canvas,x:Float,y:Float,handleX:Float=0,handleY:Float=0 ) Override
 	Method DrawItem( item:ListViewItem,canvas:Canvas,x:Float,y:Float,handleX:Float=0,handleY:Float=0 ) Override
 		
 		
 		canvas.Color=App.Theme.DefaultStyle.TextColor
 		canvas.Color=App.Theme.DefaultStyle.TextColor
@@ -62,19 +73,21 @@ Class AutocompleteListView Extends ListViewExt
 				index+=1
 				index+=1
 				ch = index>=len ? -1 Else word[index]
 				ch = index>=len ? -1 Else word[index]
 				clr=canvas.Color
 				clr=canvas.Color
-				canvas.Color=_selColor
+				canvas.Color=_markedBgColor
 				canvas.DrawRect( x,y-LineHeight*handleY,w,LineHeight )
 				canvas.DrawRect( x,y-LineHeight*handleY,w,LineHeight )
+				canvas.Color=_markedTextColor
+				canvas.DrawText( s,x,y,handleX,handleY )
 				canvas.Color=clr
 				canvas.Color=clr
+			Else
+				canvas.DrawText( s,x,y,handleX,handleY )
 			Endif
 			Endif
-			canvas.DrawText( s,x,y,handleX,handleY )
 			x+=w
 			x+=w
 		Next
 		Next
 	End
 	End
 	
 	
-	
 	Private
 	Private
 	
 	
-	Field _selColor:=New Color( .8,.8,.8,.1 )
+	Field _markedBgColor:Color,_markedTextColor:Color
 	
 	
 End
 End
 
 
@@ -514,7 +527,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		Next
 		Next
 		'preprocessor
 		'preprocessor
 		'need to load it like keywords
 		'need to load it like keywords
-		Local s:="#If ,#Rem,#End,#Endif,#Else,#Else If ,#Import ,monkeydoc,__TARGET__,__MOBILE_TARGET__,__DESKTOP_TARGET__,__HOSTOS__,__ARCH__,#Reflect "
+		Local s:="#If ,#Rem,#End,#Endif,#Else,#Else If ,#Import ,#Reflect ,monkeydoc,__TARGET__,__MOBILE_TARGET__,__DESKTOP_TARGET__,__WEB_TARGET__,__HOSTOS__,__ARCH__,__DEBUG__,__RELEASE__,__CONFIG__,__MAKEDOCS__"
 		Local arr:=s.Split( "," )
 		Local arr:=s.Split( "," )
 		For Local i:=Eachin arr
 		For Local i:=Eachin arr
 			list.Add( New ListViewItem( i ) )
 			list.Add( New ListViewItem( i ) )

+ 328 - 33
view/CodeTextView.monkey2

@@ -8,7 +8,7 @@ Class CodeTextView Extends TextView
 	Field Keywords:IKeywords
 	Field Keywords:IKeywords
 	Field Highlighter:Highlighter
 	Field Highlighter:Highlighter
 	
 	
-	Field LineChanged:Void( prevLine:Int,newLine:Int )
+	Field LineNumChanged:Void( prevLine:Int,newLine:Int )
 	Field TextChanged:Void()
 	Field TextChanged:Void()
 	
 	
 	Method New()
 	Method New()
@@ -21,6 +21,12 @@ Class CodeTextView Extends TextView
 		CursorMoved += OnCursorMoved
 		CursorMoved += OnCursorMoved
 		Document.TextChanged += TextChanged
 		Document.TextChanged += TextChanged
 		
 		
+		TabStop=Prefs.EditorTabSize
+		
+'		LineNumChanged+=Lambda( prevLine:Int,newLine:Int )
+'		
+'		End
+		
 		
 		
 '		Document.LinesModified += Lambda( first:Int,removed:Int,inserted:Int )
 '		Document.LinesModified += Lambda( first:Int,removed:Int,inserted:Int )
 '			
 '			
@@ -203,8 +209,8 @@ Class CodeTextView Extends TextView
 	
 	
 	Method IdentBeforeCursor:String( withDots:Bool=True )
 	Method IdentBeforeCursor:String( withDots:Bool=True )
 		
 		
-		Local pair:=GetIndentBeforePos_Mx2( LineTextAtCursor,PosInLineAtCursor,withDots )
-		Return pair.Item1
+		Local info:=GetIndentBeforePos_Mx2( LineTextAtCursor,PosInLineAtCursor,withDots )
+		Return info.ident
 	End
 	End
 	
 	
 	Property WordAtCursor:String()
 	Property WordAtCursor:String()
@@ -394,6 +400,22 @@ Class CodeTextView Extends TextView
 		Return _extraSelStart>=0
 		Return _extraSelStart>=0
 	End
 	End
 	
 	
+	Method SetTextSilent( text:String )
+		
+		Local curLine:=LineNumAtCursor
+		Local ancLine:=LineNumAtAnchor
+		Local curPos:=PosInLineAtCursor
+		Local ancPos:=PosInLineAtAnchor
+		Local scroll:=Scroll
+		
+		Text=text
+		
+		SelectText( Document.StartOfLine( ancLine )+ancPos,Document.StartOfLine( curLine )+curPos )
+		Scroll=scroll
+		
+	End
+	
+	
 	Protected
 	Protected
 	
 	
 	Method CheckFormat( event:KeyEvent )
 	Method CheckFormat( event:KeyEvent )
@@ -536,6 +558,30 @@ Class CodeTextView Extends TextView
 		SelectText( Cursor,Anchor )
 		SelectText( Cursor,Anchor )
 	End
 	End
 	
 	
+	Method GetPosInLineAtCursorCheckingTabSize:Int()
+	
+		Return TextUtils.GetPosInLineCheckingTabSize( LineTextAtCursor,PosInLineAtCursor,TabStop )
+	End
+	
+	Method InsertTabulation()
+		
+		Local useSpaces:=Prefs.EditorUseSpacesAsTabs
+		Local tabSize:=Prefs.EditorTabSize
+		
+		If useSpaces ' use spaces
+			
+			Local pos:=GetPosInLineAtCursorCheckingTabSize()
+			Local chars:=(pos Mod tabSize)
+			ReplaceText( " ".Dup( tabSize-chars ) )
+			
+		Else ' use tabs
+			
+			ReplaceText( "~t" )
+			
+		Endif
+		
+	End
+	
 	Method SmartCopySelected()
 	Method SmartCopySelected()
 	
 	
 		' here we strip indents from all lines - the same as in first-line indent
 		' here we strip indents from all lines - the same as in first-line indent
@@ -699,50 +745,55 @@ Class CodeTextView Extends TextView
 		Super.OnRenderContent( canvas,clip )
 		Super.OnRenderContent( canvas,clip )
 	End
 	End
 	
 	
+	Property TabStr:String()
+		
+		Return Prefs.EditorUseSpacesAsTabs ? TextUtils.GetSpacesForTabEquivalent() Else "~t"
+	End
+	
 	Method OnRenderLine( canvas:Canvas,line:Int ) Override
 	Method OnRenderLine( canvas:Canvas,line:Int ) Override
 		
 		
 		Super.OnRenderLine( canvas,line )
 		Super.OnRenderLine( canvas,line )
 	
 	
 		' draw whitespaces
 		' draw whitespaces
+		'
 		If Not _showWhiteSpaces Return
 		If Not _showWhiteSpaces Return
 	
 	
 		Local text:=Document.Text
 		Local text:=Document.Text
-		Local colors:=Document.Colors
-		Local r:Recti
 		Local start:=Document.StartOfLine( line )
 		Local start:=Document.StartOfLine( line )
+		Local ending:=Document.EndOfLine( line )
+		Local right:=0
+		Local lineStr:=Document.GetLine( line )
+		
+		canvas.Color=_whitespacesColor
 		
 		
 		For Local word:=Eachin WordIterator.ForLine( Self,line )
 		For Local word:=Eachin WordIterator.ForLine( Self,line )
 			
 			
-			If text[word.Index]=9 ' tab
-				
-				Local ind:=word.Index-1
-				Local cnt:=0
-				' ckeck tab width
-				While ind>=start
-					If text[ind]=9 Exit
-					cnt+=1
-					ind-=1
-				Wend
-				
-				cnt = cnt Mod TabStop
-				
-				canvas.Color=_whitespacesColor
-				
-				Local len:=word.Length
-				
-				r=word.Rect
-				Local x0:=r.Left,y0:=r.Top+1,y1:=y0+r.Height
+			Local atEnd:=(word.Index+word.Length=ending)
+			
+			If text[word.Index]=Chars.TAB Or (text[word.Index]=Chars.SPACE And (word.Length>=TabStop Or atEnd)) ' indent chars
 				
 				
-				Local xx:=x0 + (cnt=0 ? _tabw Else Float(TabStop-cnt)/Float(TabStop)*_tabw)
+				Local wordStr:=text.Slice( word.Index,word.Index+word.Length )
+				wordStr=wordStr.Replace( "~t",TextUtils.GetSpacesForTabEquivalent() )
 				
 				
-				Local after:=word.Index+len
-				If after < text.Length And text[after] > 32 Then len-=1
+				Local i1:=word.Index-start
+				Local i2:=i1+word.Length
+				i1=TextUtils.GetPosInLineCheckingTabSize( lineStr,i1,TabStop )
+				i2=TextUtils.GetPosInLineCheckingTabSize( lineStr,i2,TabStop )
+				If atEnd Then i2+=1
 				
 				
-				For Local i:=0 Until len
-					canvas.DrawLine( xx,y0,xx,y1 )
-					xx+=_tabw
+				Local r:=word.Rect
+				Local x0:=right,y0:=r.Top+1,y1:=y0+r.Height
+				For Local i:=i1+1 Until i2
+					If i Mod TabStop = 0
+						Local dx:=Float(i-i1)*_charw
+						canvas.DrawLine( x0+dx,y0,x0+dx,y1 )
+					Endif
 				Next
 				Next
+				
 			Endif
 			Endif
+			
+			right=word.Rect.Right
+			
 		Next
 		Next
 	
 	
 	End
 	End
@@ -752,7 +803,8 @@ Class CodeTextView Extends TextView
 		Super.OnValidateStyle()
 		Super.OnValidateStyle()
 		
 		
 		Local style:=RenderStyle
 		Local style:=RenderStyle
-		_tabw=style.Font.TextWidth( "X" )*TabStop
+		_charw=style.Font.TextWidth( "X" )
+		_tabw=_charw*TabStop
 	End
 	End
 	
 	
 	
 	
@@ -761,7 +813,7 @@ Class CodeTextView Extends TextView
 	Field _line:Int
 	Field _line:Int
 	Field _whitespacesColor:Color
 	Field _whitespacesColor:Color
 	Field _showWhiteSpaces:Bool
 	Field _showWhiteSpaces:Bool
-	Field _tabw:Int
+	Field _tabw:Int,_charw:Int
 	Field _overwriteMode:Bool
 	Field _overwriteMode:Bool
 	Field _extraSelStart:Int=-1,_extraSelEnd:Int
 	Field _extraSelStart:Int=-1,_extraSelEnd:Int
 	Field _extraSelColor:Color=Color.DarkGrey
 	Field _extraSelColor:Color=Color.DarkGrey
@@ -774,7 +826,7 @@ Class CodeTextView Extends TextView
 		If line <> _line
 		If line <> _line
 			If _typing Then FormatLine( _line )
 			If _typing Then FormatLine( _line )
 			
 			
-			LineChanged( _line,line )
+			LineNumChanged( _line,line )
 			_line=line
 			_line=line
 		Endif
 		Endif
 		
 		
@@ -828,3 +880,246 @@ Function FixNumpadKeys:Key( event:KeyEvent )
 	Endif
 	Endif
 	Return key
 	Return key
 End
 End
+
+
+Function RemoveWhitespacedTrailings:String( doc:TextDocument,linesChanged:Int Ptr )
+	
+	Local text:=doc.Text
+	Local numLines:=doc.NumLines
+	Local result:=""
+	Local index:=0,changes:=0
+	
+	For Local line:=0 Until numLines
+		
+		Local start:=doc.StartOfLine( line )
+		Local ends:=doc.EndOfLine( line )
+		Local i:=ends-1
+		
+		Local color:=doc.Colors[i]
+		If color=Highlighter.COLOR_STRING Or color=Highlighter.COLOR_COMMENT Continue
+		
+		While i>=start And text[i]<=Chars.SPACE
+			i-=1
+		Wend
+		i+=1
+		
+		If i=ends Continue ' have no trailing
+		If i=start Continue ' skip whole-whitespaced line
+		
+		If i>index 
+			result+=text.Slice( index,i )
+			changes+=1
+		Endif
+		index=ends ' skip trailing part of text
+		
+	Next
+	
+	If changes=0
+		result=text
+	Elseif index<text.Length-1
+		result+=text.Slice( index,text.Length )
+	Endif
+	
+	linesChanged[0]=changes
+	Return result
+End
+
+
+Class IndentationHelper Final
+	
+	Enum Type
+		Spaces,
+		Tabs,
+		Mixed,
+		None
+	End
+		
+	Function AnalyzeIndentation:Type( text:String )
+		
+		Local len:=text.Length
+		Local start:=-1,k:=0,spacesCount:=0,tabsCount:=0
+		
+		Local tabAsSpacesStr:=TextUtils.GetSpacesForTabEquivalent()
+		
+		Local lines:=New StringStack( text.Split( "~n" ) )
+		
+		For Local line:=Eachin lines
+			
+			Local lineLen:=line.Length
+			
+			For Local k:=0 Until lineLen
+				
+				Local char:=line[k]
+				Local atEnd:=(k=lineLen-1)
+				
+				If atEnd Then k+=1
+				
+				If char>Chars.SPACE Or atEnd ' end of indentation
+					
+					If k>0
+						Local indentStr:=line.Slice( 0,k )
+						
+						Local spaces:=(indentStr.Find( tabAsSpacesStr )<>-1)
+						Local tabs:=(indentStr.Find( "~t" )<>-1)
+						
+						spacesCount+=Int(spaces)
+						tabsCount+=Int(tabs)
+						
+						If spacesCount>0 And tabsCount>0 Return Type.Mixed
+						
+					Endif
+					
+					Exit
+					
+				Endif
+			Next
+		Next
+		
+		If spacesCount>0
+			Return Type.Spaces
+		Elseif tabsCount>0
+			Return Type.Tabs
+		Endif
+		
+		Return Type.None
+	End
+	
+	Function FixIndentation:String( document:TextDocument )
+		
+		Local text:=document.Text
+		Local useSpaces:=Prefs.EditorUseSpacesAsTabs
+		Local tabSize:=Prefs.EditorTabSize
+		Local tabAsSpacesStr:=TextUtils.GetSpacesForTabEquivalent()
+		Local minIndent:=useSpaces ? 1 Else 2 ' minimum 1 tab or 2 spaces
+		
+		' will work with single lines
+		Local lines:=New StringStack( text.Split( "~n" ) )
+		
+		For Local lineIndex:=0 Until lines.Length
+			
+			Local line:=lines[lineIndex]
+			
+			Local lineLen:=line.Length
+			If lineLen=0 Continue
+			
+			' trim endings of lines
+			Local s:=line.TrimEnd()
+			If s ' don't trim whitespaced lines
+				line=s
+				lines[lineIndex]=line
+			Endif
+			
+			Local start:=document.StartOfLine( lineIndex )
+			Local lineStr:="" ' our new content of line 
+			Local indentStart:=-1,textStart:=0
+			Local replaced:=0
+			
+			' processing each line
+			For Local k:=0 Until lineLen
+				
+				Local char:=line[k]
+				Local atEnd:=(k=lineLen-1)
+				Local isText:=(char>Chars.SPACE)
+				
+				If isText Or atEnd' end of indentation
+					
+					Local color:=document.Colors[start+k-1]
+					
+					' skip comments and strings areas - checking of colors isn't good but works
+					Local skip:=(color=Highlighter.COLOR_COMMENT Or color=Highlighter.COLOR_STRING)
+					
+					If atEnd
+						If indentStart=-1 Then indentStart=k ' if there is the only tab in line
+						If Not isText Then k+=1
+					Endif
+					
+					' indentation found
+					If Not skip And indentStart<>-1 And k-indentStart>=minIndent
+						
+						replaced+=1
+						
+						' if there is a part of text before indent
+						If textStart<>-1
+							lineStr+=line.Slice( textStart,indentStart )
+							textStart=k
+						Endif
+						' processing indent depending on "tabs or spaces" option
+						Local indentStr:=line.Slice( indentStart,k )
+						
+						' tabs --> spaces
+						If useSpaces
+							
+							' the first tab can be 1 to 4 spaces
+							If indentStr[0]=Chars.TAB
+								Local pos:=TextUtils.GetPosInLineCheckingTabSize( line,indentStart,Prefs.EditorTabSize )
+								Local chars:=(pos Mod tabSize)
+								Local spaces:=" ".Dup( tabSize-chars )
+								If indentStr.Length=1
+									' single tab - just convert into spaces
+									indentStr=spaces
+								Else
+									' convert first part + add (4*tabsCount) spaces
+									indentStr=spaces+indentStr.Slice( 1 ).Replace( "~t",tabAsSpacesStr )
+								Endif
+							Else
+								' starts with not a tab - don't know what to do exactly
+								' so convert all tabs into spaces equivalent
+								indentStr=indentStr.Replace( "~t",tabAsSpacesStr )
+							Endif
+							
+						Else ' spaces --> tabs
+							
+							indentStr=indentStr.Replace( "~t",tabAsSpacesStr ) ' avoid mixing of tabs and spaces
+							Local size:=indentStr.Length
+							Local cnt:=size/tabSize
+							Local md:=size Mod tabSize
+							indentStr=""
+							If md>1 ' convert 2+ spaces into tab
+								cnt+=1
+							Elseif md>0 ' left 1 space as is at the beginning of indent
+								indentStr+=" "
+							Endif
+							If cnt>0 ' our tabs 'replacement'
+								indentStr+="~t".Dup( cnt )
+							Endif
+							
+						Endif
+						
+						lineStr+=indentStr
+						
+					Endif
+					
+					If atEnd And (isText Or skip)
+						
+						If replaced=0 ' if do nothing with line
+							lineStr=line
+						Elseif textStart<>-1 ' if there is a last part of line
+							lineStr+=line.Slice( textStart,k+1 )
+							textStart=0
+						Endif
+						
+					Endif
+					
+					indentStart=-1
+					
+				Elseif indentStart=-1
+					
+					indentStart=k ' store the nearest like-a-space position of indent
+					
+				Endif
+			Next
+			
+			lines[lineIndex]=lineStr ' apply resulting string
+			
+		Next
+		
+		Return lines.Join( "~n" )
+	End
+	
+	
+	Private
+	
+	Method New()
+	End
+	
+End

+ 4 - 5
view/ListViewExt.monkey2

@@ -53,9 +53,6 @@ Class ListViewExt Extends ScrollableView
 		_lineHeightEtalon=lineHeight
 		_lineHeightEtalon=lineHeight
 		_maxLines=maxLines
 		_maxLines=maxLines
 		
 		
-		_selColor=App.Theme.GetColor( "content" )
-		_hoverColor=App.Theme.GetColor( "knob" )
-		
 		OnThemeChanged()
 		OnThemeChanged()
 	End
 	End
 	
 	
@@ -173,9 +170,12 @@ Class ListViewExt Extends ScrollableView
 	
 	
 	Protected
 	Protected
 	
 	
+	Field _selColor:Color
+	
 	Method OnThemeChanged() Override
 	Method OnThemeChanged() Override
 	
 	
 		_lineH=_lineHeightEtalon*App.Theme.Scale.y
 		_lineH=_lineHeightEtalon*App.Theme.Scale.y
+		_selColor=App.Theme.GetColor( "content" )
 	End
 	End
 	
 	
 	Method SelectPrevInternal( ensureVis:Bool )
 	Method SelectPrevInternal( ensureVis:Bool )
@@ -246,7 +246,7 @@ Class ListViewExt Extends ScrollableView
 			Endif
 			Endif
 			k+=1
 			k+=1
 		Next
 		Next
-			
+		
 	End
 	End
 	
 	
 	Method OnMeasureContent:Vec2i() Override
 	Method OnMeasureContent:Vec2i() Override
@@ -332,7 +332,6 @@ Class ListViewExt Extends ScrollableView
 	Field _visibleCount:Int
 	Field _visibleCount:Int
 	Field _maxLines:Int
 	Field _maxLines:Int
 	Field _selIndex:Int
 	Field _selIndex:Int
-	Field _selColor:Color,_hoverColor:Color
 	Field _width:Int,_height:Int
 	Field _width:Int,_height:Int
 	Field _moveCyclic:Bool
 	Field _moveCyclic:Bool
 	Field _dh:Float
 	Field _dh:Float

+ 32 - 8
view/ProjectView.monkey2

@@ -387,8 +387,6 @@ Class ProjectView Extends ScrollView
 					d.ShowModal()
 					d.ShowModal()
 				End
 				End
 				
 				
-				menu.AddSeparator()
-				
 				menu.AddAction( "New file" ).Triggered=Lambda()
 				menu.AddAction( "New file" ).Triggered=Lambda()
 					
 					
 					Local file:=RequestString( "New file name:" )
 					Local file:=RequestString( "New file name:" )
@@ -421,6 +419,34 @@ Class ProjectView Extends ScrollView
 					browser.Refresh( node )
 					browser.Refresh( node )
 				End
 				End
 				
 				
+				menu.AddSeparator()
+				
+				menu.AddAction( "Rename folder" ).Triggered=Lambda()
+				
+					Local oldName:=StripDir( path )
+					Local name:=RequestString( "Enter new name:","Ranaming '"+oldName+"'",oldName )
+					If Not name Or name=oldName Return
+					
+					Local i:=path.Slice( 0,path.Length-1 ).FindLast( "/" )
+					If i<>-1
+						
+						Local newPath:=path.Slice( 0,i+1 )+name
+						
+						If DirectoryExists( newPath )
+							Alert( "Folder already exists! Path: '"+newPath+"'" )
+							Return
+						Endif
+						
+						Local ok:=(libc.rename( path,newPath )=0)
+						If ok
+							browser.Refresh( node.Parent )
+							Return
+						Endif
+					
+						Alert( "Failed to rename folder: '"+path+"'" )
+					Endif
+				End
+				
 				menu.AddAction( "Delete" ).Triggered=Lambda()
 				menu.AddAction( "Delete" ).Triggered=Lambda()
 					
 					
 					DeleteItem( browser,path,node )
 					DeleteItem( browser,path,node )
@@ -508,12 +534,12 @@ Class ProjectView Extends ScrollView
 				
 				
 				menu.AddAction( "Open on Desktop" ).Triggered=Lambda()
 				menu.AddAction( "Open on Desktop" ).Triggered=Lambda()
 					
 					
-					requesters.OpenUrl( path )
+					requesters.OpenUrl( ExtractDir( path ) )
 				End
 				End
 				
 				
 				menu.AddSeparator()
 				menu.AddSeparator()
 				
 				
-				menu.AddAction( "Rename" ).Triggered=Lambda()
+				menu.AddAction( "Rename file" ).Triggered=Lambda()
 					
 					
 					Local oldName:=StripDir( path )
 					Local oldName:=StripDir( path )
 					Local name:=RequestString( "Enter new name:","Ranaming '"+oldName+"'",oldName )
 					Local name:=RequestString( "Enter new name:","Ranaming '"+oldName+"'",oldName )
@@ -526,10 +552,8 @@ Class ProjectView Extends ScrollView
 						Return
 						Return
 					Endif
 					Endif
 					
 					
-					If CopyFile( path,newPath )
-						
-						DeleteFile( path )
-						
+					Local ok:=(libc.rename( path,newPath )=0)
+					If ok
 						browser.Refresh( node.Parent )
 						browser.Refresh( node.Parent )
 						Return
 						Return
 					Endif
 					Endif

+ 2 - 2
view/StatusBarView.monkey2

@@ -6,7 +6,7 @@ Class StatusBarView Extends DockingView
 	
 	
 	Field Cancelled:Void()
 	Field Cancelled:Void()
 	
 	
-	Method New()
+	Method New( stopProcessHint:String="Stop process" )
 		
 		
 		Style=GetStyle( "StatusBar" )
 		Style=GetStyle( "StatusBar" )
 		
 		
@@ -37,7 +37,7 @@ Class StatusBarView Extends DockingView
 		act.Triggered=OnCancel
 		act.Triggered=OnCancel
 		
 		
 		_progressCancel=New ToolButtonExt( act,"" )
 		_progressCancel=New ToolButtonExt( act,"" )
-		_progressCancel.Hint="Stop process"
+		_progressCancel.Hint=stopProcessHint
 		_progressCancel.Style=GetStyle( "StatusBarButton" )
 		_progressCancel.Style=GetStyle( "StatusBarButton" )
 		AddView( _progressCancel,"right" )
 		AddView( _progressCancel,"right" )
 		
 		

+ 33 - 1
view/TabViewExt.monkey2

@@ -176,6 +176,30 @@ Class TabViewExt Extends DockingView Implements IDraggableHolder
 		Return _tabs.Length
 		Return _tabs.Length
 	End
 	End
 	
 	
+	#rem monkeydoc Number of visible tabs
+	#end
+	Property VisibleTabs:Int()
+		
+		Local num:Int
+		For Local t:=Eachin _tabs
+			If t.Visible num+=1
+		Next
+		Return num
+	End
+	
+	#rem monkeydoc Give string array of Visible tab names
+	#end
+	Property TabsVisible:String[]()
+		
+		Local arr:=New String[NumTabs]
+		For Local i:=0 Until _tabs.Length
+			If _tabs[i].Visible
+				arr[i]=_tabs[i].Text
+			End
+		Next
+		Return arr
+	End
+	
 	#rem monkeydoc The current index.
 	#rem monkeydoc The current index.
 	#end
 	#end
 	Property CurrentIndex:Int()
 	Property CurrentIndex:Int()
@@ -270,7 +294,7 @@ Class TabViewExt Extends DockingView Implements IDraggableHolder
 		tab.RightClicked=Lambda()
 		tab.RightClicked=Lambda()
 		
 		
 			MakeCurrent( tab,True )
 			MakeCurrent( tab,True )
-			
+			'If tab.Undockable Then UndockWindow.NewUndock( tab )
 			RightClicked()
 			RightClicked()
 		End
 		End
 		
 		
@@ -570,6 +594,13 @@ Class TabButtonExt Extends TabButton Implements IDraggableItem<TabViewExt>
 		Return _parentDock.ActiveName=Text
 		Return _parentDock.ActiveName=Text
 	End
 	End
 	
 	
+	'undockable?
+	Property Undockable:Bool()
+		Return _undockable
+	Setter( value:Bool )
+		_undockable=value
+	End
+	
 	Method SetLockedState( locked:Bool )
 	Method SetLockedState( locked:Bool )
 		
 		
 		_locked=locked
 		_locked=locked
@@ -607,6 +638,7 @@ Class TabButtonExt Extends TabButton Implements IDraggableItem<TabViewExt>
 	Field _possibleParentDocks:TabViewExt[]
 	Field _possibleParentDocks:TabViewExt[]
 	Field _locked:Bool
 	Field _locked:Bool
 	Field _closable:Bool
 	Field _closable:Bool
+	Field _undockable:Bool
 End
 End
 
 
 
 

+ 88 - 0
view/Undock.monkey2

@@ -0,0 +1,88 @@
+Namespace ted2go
+
+Class UndockWindow Extends Window
+		
+		Field _storeView:View
+		Field _storeTabbutton:TabButtonExt
+		Field _storeIndex:Int
+		Field _visible:Int
+		
+		Global _undockWindows:=New Stack<UndockWindow>
+		
+		Method New()
+		
+			Super.New( "Undock Window", MainWindow.Width/2, MainWindow.Height/2, WindowFlags.Resizable | WindowFlags.HighDPI | WindowFlags.Center )
+			Self.UpdateWindow( True )
+			_undockWindows.Push( Self )
+		End
+		
+		Function NewUndock:UndockWindow( _tabbutton:TabButtonExt )
+			
+			Local _window:UndockWindow
+		
+			For Local dw:=Eachin _undockWindows
+				If(dw.Title=_tabbutton.Text)_window=dw;Exit
+			Next
+				
+			If Not (_window) _window=New UndockWindow
+			
+			_tabbutton.CurrentHolder.MakeCurrent( _tabbutton.Text )
+			_window.Title=_tabbutton.Text
+			_tabbutton.Visible=False
+		
+			_window._storeTabbutton=_tabbutton
+			_window._storeView=_tabbutton.CurrentHolder.CurrentView
+			_window._storeIndex=_tabbutton.CurrentHolder.CurrentIndex
+		
+			_tabbutton.CurrentHolder.SetTabView( _window._storeIndex, Null )
+			If Not _tabbutton.CurrentHolder.VisibleTabs _tabbutton.CurrentHolder.Visible=False
+		
+			For Local mk:=Eachin _tabbutton.CurrentHolder.Tabs
+				If mk.Visible _tabbutton.CurrentHolder.MakeCurrent( mk.Text )
+			Next
+		
+			_window.ContentView=_window._storeView
+			_window._visible=True
+			_window.Activated()
+			Return _window
+		End
+			
+		Method SetUndockFrame( _frame:Recti )
+			
+			SDL_SetWindowPosition( Self.Window.SDLWindow, _frame.X, _frame.Y )
+			SDL_SetWindowSize( Self.Window.SDLWindow, _frame.Width, _frame.Height )
+			Self.Restore()
+			Local event:=New WindowEvent( EventType.WindowMoved, Self )
+			SendWindowEvent( event )
+		End
+		
+		Method OnWindowEvent( event:WindowEvent ) Override
+		
+			Select event.Type
+				Case EventType.WindowClose
+					CloseWindow()
+				Default
+					Super.OnWindowEvent( event )
+			End
+		End
+		
+		Method CloseWindow()
+			
+			Local view:=ContentView
+			ContentView=Null
+			_storeTabbutton.CurrentHolder.SetTabView( _storeIndex, view )
+			_storeTabbutton.Visible=True
+			If Not _storeTabbutton.CurrentHolder.Visible _storeTabbutton.CurrentHolder.Visible=True
+			SDL_HideWindow( Self.Window.SDLWindow )
+			Self._visible=False
+		End
+		
+		Function RestoreUndock()
+
+			For Local i:=Eachin _undockWindows
+				i.CloseWindow()
+				_undockWindows.RemoveEach( i )
+			Next
+			If _undockWindows.Length RestoreUndock()		
+		End	
+End