Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
85153a606e

+ 70 - 121
MainWindow.monkey2

@@ -11,8 +11,6 @@ Namespace ted2go
 
 #Import "assets/fonts/@/fonts"
 
-#Import "assets/themes/irc/@/themes/irc"
-
 
 Global MainWindow:MainWindowInstance
 
@@ -68,29 +66,21 @@ Class MainWindowInstance Extends Window
 			
 			OnFileDropped( path )
 		End
-
+		
 		_docsManager.DocumentAdded+=Lambda( doc:Ted2Document )
 			AddRecentFile( doc.Path )
+			
+			Local codeDoc:=Cast<CodeDocument>( doc )
+			If codeDoc Then codeDoc.AnalyzeIndentation()
+			
 			SaveState()
 		End
-
+		
 		_docsManager.DocumentRemoved+=Lambda( doc:Ted2Document )
 			If IsTmpPath( doc.Path ) DeleteFile( doc.Path )
 			SaveState()
 		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
 		
 		_buildConsole=New ConsoleExt
@@ -243,6 +233,7 @@ Class MainWindowInstance Extends Window
 		_findActions=New FindActions( _docsManager,_projectView,_findConsole )
 		_helpActions=New HelpActions
 		_viewActions=New ViewActions( _docsManager )
+		_tabActions=New TabActions( _tabsWrap.AllDocks )
 		
 		_tabMenu=New Menu
 		_tabMenu.AddAction( _fileActions.close )
@@ -363,6 +354,10 @@ Class MainWindowInstance Extends Window
 		_gotoMenu.AddAction( _viewActions.goBack )
 		_gotoMenu.AddAction( _viewActions.goForward )
 		
+		'View menu
+		'
+		_viewMenu=New MenuExt( "View" )
+		TabActions.CreateMenu( _viewMenu )
 		'Build menu
 		'
 		_forceStop=New Action( "Force Stop" )
@@ -435,6 +430,7 @@ Class MainWindowInstance Extends Window
 		_menuBar.AddMenu( _editMenu )
 		_menuBar.AddMenu( _findMenu )
 		_menuBar.AddMenu( _gotoMenu )
+		_menuBar.AddMenu( _viewMenu )
 		_menuBar.AddMenu( _buildMenu )
 		_menuBar.AddMenu( _windowMenu )
 		_menuBar.AddMenu( _helpMenu )
@@ -443,7 +439,7 @@ Class MainWindowInstance Extends Window
 		_buildConsoleView=New DockingView
 		_buildConsoleView.ContentView=_buildConsole
 		
-		_statusBar=New StatusBarView
+		_statusBar=New StatusBarView( "Stop process ("+_forceStop.HotKeyText+")" )
 		
 		_contentView=New DockingView
 		_contentView.AddView( _menuBar,"top" )
@@ -469,12 +465,16 @@ Class MainWindowInstance Extends Window
 	End
 	
 	Field PrefsChanged:Void()
+	
 	Method OnPrefsChanged()
 		
 		ArrangeElements()
-		PrefsChanged()
 		
-		SetupChatTab()
+		For Local doc:=Eachin _docsManager.OpenDocuments
+			doc.TextView?.TabStop=Prefs.EditorTabSize
+		Next
+		
+		PrefsChanged()
 		
 		_projectView.SingleClickExpanding=Prefs.MainProjectSingleClickExpanding
 	End
@@ -623,7 +623,6 @@ Class MainWindowInstance Extends Window
 		SaveState()
 		_enableSaving=False
 		OnForceStop() ' kill build process if started
-		If _ircView Then _ircView.Quit("Closing Ted2Go")
 		
 		' waiting for started processes if any
 		ParsersManager.DisableAll()
@@ -1223,6 +1222,9 @@ Class MainWindowInstance Extends Window
 		jobj["windowRect"]=ToJson( _storedSize )
 		jobj["windowState"]=New JsonNumber( Int(state) )
 		
+		SaveUndockTabsState( jobj )
+		If _isTerminating UndockWindow.RestoreUndock()
+			
 		SaveTabsState( jobj )
 		
 		Local jdocs:=New JsonObject
@@ -1298,9 +1300,8 @@ Class MainWindowInstance Extends Window
 			SizeChanged()
 		Endif
 		
-		UpdateIrcIcon()
-		
 		Rendered( canvas )
+		
 	End
 	
 	Method OnInit()
@@ -1361,93 +1362,6 @@ Class MainWindowInstance Extends Window
 		_resized=True
 	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()
 		
 		If Not _tabsWrap.tabs.Empty Return
@@ -1459,9 +1373,7 @@ Class MainWindowInstance Extends Window
 		_tabsWrap.AddTab( "Output",_outputConsoleView )
 		_tabsWrap.AddTab( "Docs",_docsConsole )
 		_tabsWrap.AddTab( "Find",_findConsole )
-		_tabsWrap.AddTab( "Chat",_ircView )
 		
-		_tabsWrap.tabs["Chat"].ActiveChanged+=OnChatTabActiveChanged
 	End
 	
 	Method ArrangeElements()
@@ -1503,7 +1415,7 @@ Class MainWindowInstance Extends Window
 		places["left"]=New StringStack( s.Split( "," ) )
 		s="Project,Debug"
 		places["right"]=New StringStack( s.Split( "," ) )
-		s="Build,Output,Docs,Find,Chat"
+		s="Build,Output,Docs,Find"
 		places["bottom"]=New StringStack( s.Split( "," ) )
 		
 		Global actives:=New StringMap<String>
@@ -1517,6 +1429,7 @@ Class MainWindowInstance Extends Window
 		' put views
 		For Local edge:=Eachin edges
 			Local val:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Tabs" )
+			Local vistabs:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"TabsVisible" )
 			If val And val<>JsonValue.NullValue
 				For Local v:=Eachin val.ToArray().All()
 					Local key:=v.ToString()
@@ -1526,7 +1439,16 @@ Class MainWindowInstance Extends Window
 					Next
 					'
 					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
 			Endif
 		Next
@@ -1574,16 +1496,45 @@ Class MainWindowInstance Extends Window
 		For Local edge:=Eachin edges
 			Local dock:=_tabsWrap.docks[edge]
 			jj[edge+"Tabs"]=JsonArray.FromStrings( dock.TabsNames )
+			jj[edge+"TabsVisible"]=JsonArray.FromStrings( dock.TabsVisible )
 			jj[edge+"Active"]=New JsonString( dock.ActiveName )
 			jj[edge+"Visible"]=New JsonBool( dock.Visible )
 			jj[edge+"Size"]=New JsonString( _tabsWrap.GetDockSize( dock ) )
 		Next
 	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 )
 		
 		LoadTabsState( jobj )
 		
+		LoadUndockTabsState( jobj )
+		
 		If jobj.Contains( "docsTab" )
 			Local jdocs:=jobj.GetObject( "docsTab" )
 			Local size:=jdocs.GetString( "indexerSize" )
@@ -1677,15 +1628,15 @@ Class MainWindowInstance Extends Window
 				If event.Modifiers & Modifier.Shift
 					
 					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"]
-					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
 					
 					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
 				Endif
@@ -1728,8 +1679,8 @@ Class MainWindowInstance Extends Window
 	Field _buildActions:BuildActions
 	Field _helpActions:HelpActions
 	Field _viewActions:ViewActions
+	Field _tabActions:TabActions
 	
-	Field _ircView:IRCView
 	Field _buildConsole:ConsoleExt
 	Field _buildConsoleView:DockingView
 	Field _outputConsole:ConsoleExt
@@ -1744,14 +1695,10 @@ Class MainWindowInstance Extends Window
 	Field _helpTree:HelpTreeView
 	Field _helpSwitcher:ToolButtonExt
 	
-	'Field _ircTabView:TabView
 	Field _docsTabView:TabViewExt
 	Field _consolesTabView2:TabView
 	Field _browsersTabView2:TabView
 	
-	Field _ircNotifyIcon:Int
-	Field _ircIconBlink:Int
-	
 	Field _forceStop:Action
 
 	Field _tabMenu:Menu
@@ -1760,6 +1707,7 @@ Class MainWindowInstance Extends Window
 	Field _editMenu:MenuExt
 	Field _findMenu:MenuExt
 	Field _gotoMenu:MenuExt
+	Field _viewMenu:MenuExt
 	Field _buildMenu:MenuExt
 	Field _windowMenu:MenuExt
 	Field _helpMenu:MenuExt
@@ -2033,6 +1981,7 @@ Class DraggableTabs
 	Method AddTab( name:String,view:View )
 		
 		tabs[name]=TabViewExt.CreateDraggableTab( name,view,_docksArray )
+		tabs[name].Undockable=True
 	End
 	
 	Method GetDockSize:String( dock:TabViewExt )

+ 11 - 27
Prefs.monkey2

@@ -10,10 +10,10 @@ Class PrefsInstance
 	Field AcKeywordsOnly:=False
 	Field AcShowAfter:=2
 	Field AcUseTab:=True
-	Field AcUseEnter:=False
+	Field AcUseEnter:=True
 	Field AcUseSpace:=False
 	Field AcUseDot:=False
-	Field AcNewLineByEnter:=True
+	Field AcNewLineByEnter:=False
 	Field AcStrongFirstChar:=True
 	Field AcUseLiveTemplates:=True
 	'
@@ -22,12 +22,6 @@ Class PrefsInstance
 	Field MainProjectSingleClickExpanding:=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 EditorGutterVisible:=True
 	Field EditorShowWhiteSpaces:=False
@@ -39,6 +33,9 @@ Class PrefsInstance
 	Field EditorAutoPairs:=True
 	Field EditorSurroundSelection:=True
 	Field EditorShowParamsHint:=True
+	Field EditorUseSpacesAsTabs:=False
+	Field EditorTabSize:=4
+	Field EditorRemoveLinesTrailing:=False
 	'
 	Field SourceSortByType:=True
 	Field SourceShowInherited:=False
@@ -58,17 +55,6 @@ Class PrefsInstance
 	
 	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" )
 			
 			Local j2:=json["main"].ToObject()
@@ -108,6 +94,9 @@ Class PrefsInstance
 			EditorAutoPairs=Json_GetBool( j2,"autoPairs",EditorAutoPairs )
 			EditorSurroundSelection=Json_GetBool( j2,"surroundSelection",EditorSurroundSelection )
 			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
 		
@@ -135,14 +124,6 @@ Class PrefsInstance
 		j["singleClickExpanding"]=New JsonBool( MainProjectSingleClickExpanding )
 		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
 		json["completion"]=j
 		j["enabled"]=New JsonBool( AcEnabled )
@@ -168,6 +149,9 @@ Class PrefsInstance
 		j["autoPairs"]=New JsonBool( EditorAutoPairs )
 		j["surroundSelection"]=New JsonBool( EditorSurroundSelection )
 		j["showParamsHint"]=New JsonBool( EditorShowParamsHint )
+		j["useSpacesAsTabs"]=New JsonBool( EditorUseSpacesAsTabs )
+		j["tabSize"]=New JsonNumber( EditorTabSize )
+		j["removeLinesTrailing"]=New JsonBool( EditorRemoveLinesTrailing )
 		
 		j=New JsonObject
 		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:
 * [PayPal](https://paypal.me/engor)
 * Payed downloading [from itch.io](https://nerobot.itch.io/ted2go)
+* Become a patron [on Patreon.com](https://www.patreon.com/nerobot)
 
 ## Notes for contributors
 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/ViewActions"
 #Import "action/WindowActions"
+#Import "action/TabActions"
 
 #Import "dialog/FindDialog"
 #Import "dialog/PrefsDialog"
@@ -80,6 +81,7 @@
 
 #Import "utils/JsonUtils"
 #Import "utils/Utils"
+#Import "utils/TextUtils"
 
 #Import "view/IRCView"
 #Import "view/CodeMapView"
@@ -114,6 +116,7 @@
 #Import "view/ViewExtensions"
 #Import "view/DockingViewExt"
 #Import "view/DraggableViewListener"
+#Import "view/Undock"
 
 #Import "Tree"
 #Import "Tuple"
@@ -135,7 +138,7 @@ Using sdl2..
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
-Global AppTitle:="Ted2Go v2.8.1"
+Global AppTitle:="Ted2Go v2.9"
 
 
 Function Main()

+ 12 - 0
action/FileActions.monkey2

@@ -343,6 +343,8 @@ Class FileActions
 		
 		_prefsDialog=New PrefsDialog
 		
+		' not good place for subscribing, but it's simplier than proper one...
+		'
 		_prefsDialog.Apply+=Lambda()
 		
 			For Local d:=Eachin _docs.OpenDocuments
@@ -353,6 +355,16 @@ Class FileActions
 			MainWindow.OnPrefsChanged()
 		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()
 	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>
 
-<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>
 

BIN
assets/fonts/SourceCodePro-Medium.otf


+ 19 - 23
assets/newfiles/Simple_Mojo3d_App.monkey2

@@ -8,63 +8,59 @@ Using std..
 Using mojo..
 Using mojo3d..
 
+
 Class MyWindow Extends Window
 	
 	Field _scene:Scene
-	
 	Field _camera:Camera
-	
 	Field _light:Light
-	
 	Field _ground:Model
-	
 	Field _donut:Model
 	
+	
 	Method New( title:String="Simple mojo3d app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
-
+		
 		Super.New( title,width,height,flags )
+	End
+	
+	Method OnCreateWindow() Override
 		
 		'create (current) 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
-		'
 		_camera=New Camera( Self )
 		_camera.AddComponent<FlyBehaviour>()
-		_camera.Move( 0,10,-5 )
+		_camera.Move( 0,2.5,-5 )
 		
 		'create light
-		'
 		_light=New Light
 		_light.CastsShadow=True
-		_light.RotateX( 90 )
+		_light.Rotate( 45, 45, 0 )
 		
 		'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.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.Move( 0,10,0 )
+		_donut.Move( 0,2.5,0 )
 	End
 	
 	Method OnRender( canvas:Canvas ) Override
-	
-		RequestRender()
 		
+		RequestRender()
 		_donut.Rotate( .2,.4,.6 )
-
 		_scene.Update()
-		
 		_camera.Render( canvas )
-		
 		canvas.DrawText( "FPS="+App.FPS,0,0 )
 	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-selection": "#48000000",
 		"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":{

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

@@ -8,9 +8,9 @@
 		"normal":"Roboto-Medium.ttf,16",
 		"fixedWidth":"RobotoMono-Medium.ttf,19",
 		"small":"Roboto-Medium.ttf,14",
-		"editor":"MesloLGSDZ-Bold.ttf,19"
+		"editor":"SourceCodePro-Medium.otf,19"
 	},
-
+	
 	"colors":{
 
 		"border": "#121111",
@@ -36,12 +36,12 @@
 		"textview-whitespaces":"bright",
 
 		"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-color6": "#FABD2F",	//preproc
+		"textview-color6": "#FDBD28",	//preproc
 		"textview-color7": "#8EC07C",
 		
 		"windowClearColor":"darkest",

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

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

+ 41 - 41
dialog/PrefsDialog.monkey2

@@ -5,6 +5,7 @@ Namespace ted2go
 Class PrefsDialog Extends DialogExt
 
 	Field Apply:Void()
+	Field TabulationChanged:Void()
 	
 	Method New()
 		
@@ -28,11 +29,6 @@ Class PrefsDialog Extends DialogExt
 		docker=GetCompletionDock()
 		tabView.AddTab( "AutoComplete",docker )
 		
-		' Chat
-		'
-		docker=GetChatDock()
-		tabView.AddTab( "IRC chat",docker )
-		
 		' Live Templates
 		'
 		docker=GetLiveTemplatesDock()
@@ -49,7 +45,14 @@ Class PrefsDialog Extends DialogExt
 		
 		_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 )
 		MaxSize=New Vec2i( 550,600 )
@@ -80,6 +83,9 @@ Class PrefsDialog Extends DialogExt
 	Field _editorAutoPairs:CheckButton
 	Field _editorSurround:CheckButton
 	Field _editorShowParamsHint:CheckButton
+	Field _editorUseSpacesAsTabs:CheckButton
+	Field _editorTabSize:TextFieldExt
+	Field _editorRemoveLinesTrailing:CheckButton
 	
 	Field _mainToolBarVisible:CheckButton
 	Field _mainProjectIcons:CheckButton
@@ -97,6 +103,9 @@ Class PrefsDialog Extends DialogExt
 	Field _codeView:Ted2CodeTextView
 	Field _treeView:TreeViewExt
 	
+	Global _lastTab:Int
+	
+	
 	Method OnApply()
 	
 		Prefs.AcEnabled=_acEnabled.Checked
@@ -125,23 +134,25 @@ Class PrefsDialog Extends DialogExt
 		Prefs.EditorAutoPairs=_editorAutoPairs.Checked
 		Prefs.EditorSurroundSelection=_editorSurround.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.MainProjectIcons=_mainProjectIcons.Checked
 		Prefs.MainProjectSingleClickExpanding=_mainProjectSingleClickExpanding.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()
 		
 		Hide()
 		Apply()
 		
+		If Prefs.EditorUseSpacesAsTabs<>useSpaces Then TabulationChanged()
+		
 		Prefs.SaveLocalState()
 		
 		LiveTemplates.Save()
@@ -188,7 +199,7 @@ Class PrefsDialog Extends DialogExt
 		
 		Local docker:=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( btnChooseMonkeyPath,"left" )
 		
@@ -234,6 +245,13 @@ Class PrefsDialog Extends DialogExt
 		_editorShowParamsHint=New CheckButton( "Show parameters hint" )
 		_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
 		If Not path Then path=_defaultFont
 		_editorFontPath=New TextFieldExt( "" )
@@ -269,12 +287,18 @@ Class PrefsDialog Extends DialogExt
 		Local btnResetFont:=New PushButton( resetFont )
 		
 		Local font:=New DockingView
-		font.AddView( New Label( "Font" ),"left" )
+		font.AddView( New Label( "Font:" ),"left" )
 		font.AddView( _editorFontPath,"left" )
 		font.AddView( _editorFontSize,"left","45" )
 		font.AddView( btnChooseFont,"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
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( _editorToolBarVisible,"top" )
@@ -287,8 +311,11 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( _editorAutoPairs,"top" )
 		docker.AddView( _editorSurround,"top" )
 		docker.AddView( _editorShowParamsHint,"top" )
+		docker.AddView( _editorRemoveLinesTrailing,"top" )
+		docker.AddView( tabs,"top" )
 		docker.AddView( New Label( " " ),"top" )
 		
+		
 		Return docker
 	End
 	
@@ -340,33 +367,6 @@ Class PrefsDialog Extends DialogExt
 		Return docker
 	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()
 	
 		Local treeDock:=New DockingView

+ 219 - 61
document/CodeDocument.monkey2

@@ -157,7 +157,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				Local indent:=Utils.GetIndent( s )
 				Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 				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 )
 				DrawCurvedLine( canvas,x,x+w,(err.line+1)*LineHeight )
 			Next
@@ -198,6 +199,53 @@ Class CodeDocumentView Extends Ted2CodeTextView
 '					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
 					If ctrl
 						Return
@@ -219,21 +267,40 @@ Class CodeDocumentView Extends Ted2CodeTextView
 						
 					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
 				
@@ -313,7 +380,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 			
 				Case Key.Enter,Key.KeypadEnter 'auto indent
-			
+					
 					Local line:=CursorLine
 					Local text:=Document.GetLine( line )
 					Local indent:=GetIndent( text )
@@ -322,19 +389,23 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					'in this case GetLine return 2 lines, and if they empty
 					'then we get double indent
 					'need to fix inside mojox
-			
+					
 					Local beforeIndent:=(posInLine<=indent)
-			
+					
 					If indent > posInLine Then indent=posInLine
-			
+					
 					Local s:=(indent ? text.Slice( 0,indent ) Else "")
-			
+					
+					If Prefs.EditorUseSpacesAsTabs
+						s=s.Replace( "~t",TabStr )
+					Endif
+					
 					' auto indentation
 					If Prefs.EditorAutoIndent And Not beforeIndent
 						text=text.Trim().ToLower()
 						If text.StartsWith( "if" )
 							If Not Utils.BatchContains( text,_arrIf,True )
-								s="~t"+s
+								s=TabStr+s
 							Endif
 						Elseif Utils.BatchStartsWith( text,_arrAddonIndents,True )
 							
@@ -345,7 +416,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 								If scope And scope.Kind=CodeItemKind.Interface_
 									' nothing
 								Else
-									s="~t"+s
+									s=TabStr+s
 								Endif
 							Endif
 						Endif
@@ -414,68 +485,82 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 						' live templates by tab!
 						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 maxPos:=Max( Cursor,Anchor )
 						Local min:=Document.FindLine( minPos )
 						Local max:=Document.FindLine( maxPos )
-			
+						
 						' if we are at the beginning of bottom line - skip it
 						Local strt:=Document.StartOfLine( max )
 						If maxPos = strt
 							max-=1
 						Endif
-			
+						
 						Local lines:=New StringStack
-			
+						
 						For Local i:=min To max
 							lines.Push( Document.GetLine( i ) )
 						Next
-			
+						
 						Local go:=True
 						Local shiftFirst:=0,shiftLast:=0
-			
+						Local tabStr:=TabStr
+						
 						If shift
-			
+							
 							Local changes:=0
 							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"
 									changes+=1
 									If i=0 Then shiftFirst=-1
-									if i=lines.Length-1 Then shiftLast=-1
+									If i=lines.Length-1 Then shiftLast=-1
+								
 								Else
+								
 									lines[i]+="~n"
+								
 								Endif
 							Next
 			
 							go=(changes > 0)
+							
 						Else
-							shiftFirst=1
-							shiftLast=1
+							
+							shiftFirst=tabStr.Length
+							shiftLast=tabStr.Length
 							For Local i:=0 Until lines.Length
-								lines[i]="~t"+lines[i]+"~n"
+								lines[i]=tabStr+lines[i]+"~n"
 							Next
+							
 						Endif
 			
 						If go
+							
 							Local minStart:=Document.StartOfLine( min )
 							Local maxStart:=Document.StartOfLine( max )
 							Local maxEnd:=Document.EndOfLine( max )
-			
+							
 							Local p1:=minPos+shiftFirst 'absolute pos
 							Local p2:=maxPos-maxStart+shiftLast 'pos in line
 							SelectText( minStart,maxEnd+1 )
@@ -485,7 +570,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 							p1=Max( p1,Document.StartOfLine( min ) )
 							SelectText( p1,p2 )
 						Endif
-			
+						
 					Endif
 					
 					CheckFormat( event )
@@ -711,7 +796,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Local indent:=Utils.GetIndent( s )
 					Local indentStr:=(indent > 0) ? s.Slice( 0, indent ) Else ""
 					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 )
 					If event.Location.x >= x And event.Location.x <= x+w
 						Local s:=_doc.GetStringError( line )
@@ -793,7 +879,7 @@ Class CodeDocument Extends Ted2Document
 		
 		' Editor
 		_codeView=New CodeDocumentView( Self )
-		_codeView.LineChanged += OnLineChanged
+		_codeView.LineNumChanged += OnLineChanged
 		
 		_doc=_codeView.Document
 		
@@ -844,10 +930,41 @@ Class CodeDocument Extends Ted2Document
 			MainWindow.GotoCodePosition( nav.filePath,nav.pos )
 		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()
 	End
@@ -903,7 +1020,6 @@ Class CodeDocument Extends Ted2Document
 		_browserView.AddView( bar,"top" )
 		
 		
-		
 		_treeView=New CodeTreeView
 		_browserView.ContentView=_treeView
 		
@@ -922,6 +1038,37 @@ Class CodeDocument Extends Ted2Document
 		Return _browserView
 	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
 	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 )
 		
-		If ident = "" Then ident=_codeView.IdentBeforeCursor()
+		If Not ident Then ident=_codeView.IdentBeforeCursor()
 		
 		Print "ident: "+ident
 		
@@ -1241,6 +1388,9 @@ Class CodeDocument Extends Ted2Document
 	Field _codeView:CodeDocumentView
 	Field _treeView:CodeTreeView
 	Field _browserView:DockingView
+	Field _fixIndentView:DockingView
+	Field _fixIndentHint:Label
+	Field _fixIndentButton:Button
 	
 	Field _errors:=New Stack<BuildError>
 	Field _errMap:=New IntMap<String>
@@ -1367,7 +1517,15 @@ Class CodeDocument Extends Ted2Document
 	
 		'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 )
 	
@@ -1562,8 +1720,8 @@ Class CodeDocument Extends Ted2Document
 						j-=1
 					Wend
 					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
 					If ident
 						part=New ParamsPart
@@ -1573,7 +1731,7 @@ Class CodeDocument Extends Ted2Document
 						part.ranges.Add( New Vec2i( i,0 ) )
 						
 						' 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
 							j-=1
 						Wend

+ 3 - 27
document/Monkey2Document.monkey2

@@ -354,35 +354,11 @@ Class Monkey2DocumentView Extends Ted2TextView
 			Local ident:=IdentNearestCursor()
 				
 			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
 			
 			If _typing Capitalize( False )
-				
+			
 		Case Key.Left
 			
 			If _typing
@@ -392,7 +368,7 @@ Class Monkey2DocumentView Extends Ted2TextView
 					Capitalize( True )
 				Endif
 			Endif
-				
+			
 		Case Key.Right
 			
 			If _typing
@@ -402,7 +378,7 @@ Class Monkey2DocumentView Extends Ted2TextView
 					Capitalize( True )
 				Endif
 			Endif
-				
+			
 		Case Key.Up,Key.Down
 			
 			Capitalize( True )	'in cased we missed anything...

+ 1 - 1
document/SceneDocument.monkey2

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

+ 27 - 0
eventfilter/Monkey2KeyEventFilter.monkey2

@@ -31,6 +31,33 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 					MainWindow.GotoDeclaration()
 					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
 			
 			

+ 2 - 0
parser/CodeItem.monkey2

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

+ 28 - 28
parser/Monkey2Parser.monkey2

@@ -855,6 +855,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 	
 	Method ParseModules()
 		
+		'Return
+		
 		Local dd:=LoadDir( _modsPath )
 		
 		' pop up some modules to parse them first
@@ -911,6 +913,10 @@ Class Monkey2Parser Extends CodeParserPlugin
 					Local t:=ParseMember( jobj )
 					t.kind=kind2
 					Return t
+				Default
+					If init.Contains( "type" )
+						Return ParseType( init["type"].ToObject() )
+					Endif
 				End
 			Endif
 			' not found
@@ -924,6 +930,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Local t:=New CodeType
 				t.kind=kind
 				t.ident=type["ident"].ToString()
+				t.isArray=type.Contains( "is-array" )
 				Return t
 				
 			Case "functype"
@@ -1043,12 +1050,25 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return result
 	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
 		
 		If jobj.Contains( "type" )
 			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" )
 			type=jobj["getFunc"].ToObject()["type"].ToObject()
 			' properties have retType
@@ -1057,9 +1077,13 @@ Class Monkey2Parser Extends CodeParserPlugin
 			Endif
 		Elseif jobj.Contains( "init" )
 			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
 		
 		Return type
@@ -1338,30 +1362,6 @@ Class Monkey2Parser Extends CodeParserPlugin
 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
 	
 	Field parent:NSpace

+ 2 - 2
testing/ParserTests.monkey2

@@ -64,8 +64,8 @@ End
 Global boo:=True
 
 Global multi:="Hello,
-               multiline
-               world!"
+				multiline
+				world!"
 
 Global vector:Vec2f
 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
 End
 
-Class Utils
+Class Utils Final
 	
 	Function ArrayContains<T>:Bool( arr:T[],value:T )
 		If Not arr Return False
@@ -63,13 +63,23 @@ Class Utils
 	End
 	
 	Function GetIndent:Int( line:String )
+		
 		Local len:=line.Length,n:=0
-		While n < len And line[n] <= 32
+		While n < len And line[n] <= Chars.SPACE
 			n+=1
 		Wend
 		Return n
 	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 )
 		Local n:=GetIndent( line )
 		Return  (n > 0) ? line.Slice( 0,n ) Else ""
@@ -172,6 +182,9 @@ Class Utils
 	
 	Private
 	
+	Global _storedTabSize:=0,_spacesForTab:String
+	
+	
 	Method New()
 	End
 	
@@ -341,14 +354,40 @@ Function StripStarting:String( text:String,starts:String )
 	Return text.StartsWith( starts ) ? text.Slice( starts.Length ) Else text
 End
 
+' 
+Struct IdentInfo
+	
+	Field pos:Int
+	Field ident:String
+	Field isArray:Bool
+	
+End
+
 #Rem monkeydocs Return ident and position in line where ident starts
 #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
 	
 	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)
 	
 		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 starts:=-1
+	Local arr:=False
 	If n < pos
 		starts=n
 		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
-	Return New Tuple2<String,Int>( s,starts )
+	
+	Local info:=New IdentInfo
+	info.ident=s
+	info.pos=starts
+	info.isArray=arr
+	
+	Return info
 End
 
 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
 	
 	Method New( lineHeight:Int,maxLines:Int )
+		
 		Super.New( lineHeight,maxLines )
+		
+		OnThemeChanged()
 	End
 	
 	
 	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
 		
 		canvas.Color=App.Theme.DefaultStyle.TextColor
@@ -62,19 +73,21 @@ Class AutocompleteListView Extends ListViewExt
 				index+=1
 				ch = index>=len ? -1 Else word[index]
 				clr=canvas.Color
-				canvas.Color=_selColor
+				canvas.Color=_markedBgColor
 				canvas.DrawRect( x,y-LineHeight*handleY,w,LineHeight )
+				canvas.Color=_markedTextColor
+				canvas.DrawText( s,x,y,handleX,handleY )
 				canvas.Color=clr
+			Else
+				canvas.DrawText( s,x,y,handleX,handleY )
 			Endif
-			canvas.DrawText( s,x,y,handleX,handleY )
 			x+=w
 		Next
 	End
 	
-	
 	Private
 	
-	Field _selColor:=New Color( .8,.8,.8,.1 )
+	Field _markedBgColor:Color,_markedTextColor:Color
 	
 End
 
@@ -514,7 +527,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		Next
 		'preprocessor
 		'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( "," )
 		For Local i:=Eachin arr
 			list.Add( New ListViewItem( i ) )

+ 328 - 33
view/CodeTextView.monkey2

@@ -8,7 +8,7 @@ Class CodeTextView Extends TextView
 	Field Keywords:IKeywords
 	Field Highlighter:Highlighter
 	
-	Field LineChanged:Void( prevLine:Int,newLine:Int )
+	Field LineNumChanged:Void( prevLine:Int,newLine:Int )
 	Field TextChanged:Void()
 	
 	Method New()
@@ -21,6 +21,12 @@ Class CodeTextView Extends TextView
 		CursorMoved += OnCursorMoved
 		Document.TextChanged += TextChanged
 		
+		TabStop=Prefs.EditorTabSize
+		
+'		LineNumChanged+=Lambda( prevLine:Int,newLine:Int )
+'		
+'		End
+		
 		
 '		Document.LinesModified += Lambda( first:Int,removed:Int,inserted:Int )
 '			
@@ -203,8 +209,8 @@ Class CodeTextView Extends TextView
 	
 	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
 	
 	Property WordAtCursor:String()
@@ -394,6 +400,22 @@ Class CodeTextView Extends TextView
 		Return _extraSelStart>=0
 	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
 	
 	Method CheckFormat( event:KeyEvent )
@@ -536,6 +558,30 @@ Class CodeTextView Extends TextView
 		SelectText( Cursor,Anchor )
 	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()
 	
 		' 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 )
 	End
 	
+	Property TabStr:String()
+		
+		Return Prefs.EditorUseSpacesAsTabs ? TextUtils.GetSpacesForTabEquivalent() Else "~t"
+	End
+	
 	Method OnRenderLine( canvas:Canvas,line:Int ) Override
 		
 		Super.OnRenderLine( canvas,line )
 	
 		' draw whitespaces
+		'
 		If Not _showWhiteSpaces Return
 	
 		Local text:=Document.Text
-		Local colors:=Document.Colors
-		Local r:Recti
 		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 )
 			
-			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
+				
 			Endif
+			
+			right=word.Rect.Right
+			
 		Next
 	
 	End
@@ -752,7 +803,8 @@ Class CodeTextView Extends TextView
 		Super.OnValidateStyle()
 		
 		Local style:=RenderStyle
-		_tabw=style.Font.TextWidth( "X" )*TabStop
+		_charw=style.Font.TextWidth( "X" )
+		_tabw=_charw*TabStop
 	End
 	
 	
@@ -761,7 +813,7 @@ Class CodeTextView Extends TextView
 	Field _line:Int
 	Field _whitespacesColor:Color
 	Field _showWhiteSpaces:Bool
-	Field _tabw:Int
+	Field _tabw:Int,_charw:Int
 	Field _overwriteMode:Bool
 	Field _extraSelStart:Int=-1,_extraSelEnd:Int
 	Field _extraSelColor:Color=Color.DarkGrey
@@ -774,7 +826,7 @@ Class CodeTextView Extends TextView
 		If line <> _line
 			If _typing Then FormatLine( _line )
 			
-			LineChanged( _line,line )
+			LineNumChanged( _line,line )
 			_line=line
 		Endif
 		
@@ -828,3 +880,246 @@ Function FixNumpadKeys:Key( event:KeyEvent )
 	Endif
 	Return key
 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
 		_maxLines=maxLines
 		
-		_selColor=App.Theme.GetColor( "content" )
-		_hoverColor=App.Theme.GetColor( "knob" )
-		
 		OnThemeChanged()
 	End
 	
@@ -173,9 +170,12 @@ Class ListViewExt Extends ScrollableView
 	
 	Protected
 	
+	Field _selColor:Color
+	
 	Method OnThemeChanged() Override
 	
 		_lineH=_lineHeightEtalon*App.Theme.Scale.y
+		_selColor=App.Theme.GetColor( "content" )
 	End
 	
 	Method SelectPrevInternal( ensureVis:Bool )
@@ -246,7 +246,7 @@ Class ListViewExt Extends ScrollableView
 			Endif
 			k+=1
 		Next
-			
+		
 	End
 	
 	Method OnMeasureContent:Vec2i() Override
@@ -332,7 +332,6 @@ Class ListViewExt Extends ScrollableView
 	Field _visibleCount:Int
 	Field _maxLines:Int
 	Field _selIndex:Int
-	Field _selColor:Color,_hoverColor:Color
 	Field _width:Int,_height:Int
 	Field _moveCyclic:Bool
 	Field _dh:Float

+ 32 - 8
view/ProjectView.monkey2

@@ -387,8 +387,6 @@ Class ProjectView Extends ScrollView
 					d.ShowModal()
 				End
 				
-				menu.AddSeparator()
-				
 				menu.AddAction( "New file" ).Triggered=Lambda()
 					
 					Local file:=RequestString( "New file name:" )
@@ -421,6 +419,34 @@ Class ProjectView Extends ScrollView
 					browser.Refresh( node )
 				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()
 					
 					DeleteItem( browser,path,node )
@@ -508,12 +534,12 @@ Class ProjectView Extends ScrollView
 				
 				menu.AddAction( "Open on Desktop" ).Triggered=Lambda()
 					
-					requesters.OpenUrl( path )
+					requesters.OpenUrl( ExtractDir( path ) )
 				End
 				
 				menu.AddSeparator()
 				
-				menu.AddAction( "Rename" ).Triggered=Lambda()
+				menu.AddAction( "Rename file" ).Triggered=Lambda()
 					
 					Local oldName:=StripDir( path )
 					Local name:=RequestString( "Enter new name:","Ranaming '"+oldName+"'",oldName )
@@ -526,10 +552,8 @@ Class ProjectView Extends ScrollView
 						Return
 					Endif
 					
-					If CopyFile( path,newPath )
-						
-						DeleteFile( path )
-						
+					Local ok:=(libc.rename( path,newPath )=0)
+					If ok
 						browser.Refresh( node.Parent )
 						Return
 					Endif

+ 2 - 2
view/StatusBarView.monkey2

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

+ 33 - 1
view/TabViewExt.monkey2

@@ -176,6 +176,30 @@ Class TabViewExt Extends DockingView Implements IDraggableHolder
 		Return _tabs.Length
 	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.
 	#end
 	Property CurrentIndex:Int()
@@ -270,7 +294,7 @@ Class TabViewExt Extends DockingView Implements IDraggableHolder
 		tab.RightClicked=Lambda()
 		
 			MakeCurrent( tab,True )
-			
+			'If tab.Undockable Then UndockWindow.NewUndock( tab )
 			RightClicked()
 		End
 		
@@ -570,6 +594,13 @@ Class TabButtonExt Extends TabButton Implements IDraggableItem<TabViewExt>
 		Return _parentDock.ActiveName=Text
 	End
 	
+	'undockable?
+	Property Undockable:Bool()
+		Return _undockable
+	Setter( value:Bool )
+		_undockable=value
+	End
+	
 	Method SetLockedState( locked:Bool )
 		
 		_locked=locked
@@ -607,6 +638,7 @@ Class TabButtonExt Extends TabButton Implements IDraggableItem<TabViewExt>
 	Field _possibleParentDocks:TabViewExt[]
 	Field _locked:Bool
 	Field _closable:Bool
+	Field _undockable:Bool
 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