Преглед изворни кода

Squashed 'src/ted2go/' changes from e12c273c9..89ba48bbc

89ba48bbc Fixed macos shortcut.
b18f4f99c Cleanup.
0369efc2e Macos - changed hotkey for Replace action to Alt+F.
7fbbcba98 Show hints by timer - not immediately. Find / Replace panel - added switcher to replace mode ("R"-button).
7d5911c61 Improved store / restore docs sizes.
7d6ea026a Removed Escape hotkey from UpdateModuledDialog. Icons color set to 'text-default'.
43b68de56 Fixed crash on app closing if you close it quickly after start.
91e7eb658 Save all opened files when updating modules.
f504e83b0 Added item "Goto declaration" into editor menu. Also fixed mouse right-click behaviour.
a3d7adac7 Fixed code map - clicking outside of content height have no effect now.
0b235e7b1 Kills app being debugged before building.
ca1aa63c6 Cleanups.
4546d13cc Fixed endless loop in "Find previous" logic when there is only one result exists.
519444f57 Merge branch 'master' into dev
1401da023 Hide completion by Home / End keys. Lock build file by double-click on tab. Add custom style for locked tabs.
1c87db340 Replaced all TextField with TextFieldExt and made it cursor blinked-beam).
01904c8bb Menus and hints now fitted into window bounds.
f08ebf866 Improved usings-filter in completion.
ff7a807ae Added option for surround selection with "" () [].
3209b0726 Added "Find/Replace in selection" feature.
3fdf4e672 Fixes in completion (and jump to ident).
14c4b1b47 Completion by tab - now do replace (was insert) whole ident under cursor.
45932f508 Added surround selected text with " ( [ instead of replacing.
7c8a7b0c0 Combined Help & Docs tabs. Ctrl+F1 - search in docs.
c8dbc573f Comment / Uncomment selected block by single-quote char.
c36898745 Fixed draggable tabs for themes with TabButton.states{} section. Added close icon into find / replace panel.
831256462 Added store/restore cursor position (and selection) in state.json for opened textual docs.
c3c6d590e Added option to auto-pair quotes and brackets.
2d2d91d2f Fixed tab size for whitespaces marks.
a9451ab52 Completion - now show members from 'monkey..' namespace even if it didn't explicitly included. Update modules dialog - assigned Enter and Escape hotkeys.
1463772a7 Changed shortcuts for navigate left / right.
998c32bcc Finished draggable tabs!
5d6a45252 Merge branch 'dev' into draggable_tabs
52444a3ff Fixed (reverted) macos shortcuts.
51ccbd94a (wip) draggable tabs in mainwindow.
1f4c07e3a Now show extensions in SOURCE tree.
7a00d131f Completion - now Self inside of extensions shows us public and protected members of its parent class. And show static members only inside of functions.
7a3d937cb Merge branch 'master' into dev
3948c934e Merge branch 'master' into dev
2dfef57dc Fixed views sizes in Prefs dialog.
40e2e9f46 Totally new Find / Replace, docked at the editor bottom.
1e967a4ff Fixed completion  - was broken for global vars; and exclude constructors from list.
eb3ccdbd5 Move cursor to screen center when jump to line.
f05b5c9e0 Some tweaks with system cursor.
91fc440c3 Change cursor to beam inside of code view.
39437dbe9 Now saving opened files for current built project only.
d90d1f7e7 Editor - change cursor for 'overwrite' mode (block / beam), and now each document has its own overwrite mode. Fixed shortcuts for macos.
613bd16c2 Now make selection for comment/uncomment block. Added keyword DebugStop. Increased first-char priority in completion list.
0522bbec9 Improved open doc - now just-opened doc's tab is visible!
35d66df09 Project view - run .exe /.bat / .sh files with 'okay' prompt.
a9b3b963c Editor - now can goto extension members by F2 / F12. and show help in status bar by F1. Project browser - can select item and delete it by Delete key.
e97e7019b Fixed auto-show popup sub-menus.
344301458 Merge branch 'master' into dev
43551d722 Added support for extensions in auto-completion! (can't jump to ext members yet)
937dbc2a3 Fixed autocompletion for 'Super' keyword.

git-subtree-dir: src/ted2go
git-subtree-split: 89ba48bbc95be59a0e4e236c1c8f939fbb6284e4
Mark Sibly пре 8 година
родитељ
комит
dd14ca9610
48 измењених фајлова са 2614 додато и 1026 уклоњено
  1. 417 179
      MainWindow.monkey2
  2. 7 4
      Prefs.monkey2
  3. 37 28
      ProcessReader.monkey2
  4. 8 2
      Ted2.monkey2
  5. 25 17
      action/BuildActions.monkey2
  6. 157 200
      action/FindActions.monkey2
  7. 2 2
      action/ViewActions.monkey2
  8. 13 15
      assets/aboutTed2Go.html
  9. 19 7
      assets/themes/ted2-default.json
  10. 1 1
      dialog/EditProductDialog.monkey2
  11. 7 6
      dialog/FindDialog.monkey2
  12. 14 8
      dialog/FindInFilesDialog.monkey2
  13. 30 23
      dialog/PrefsDialog.monkey2
  14. 2 0
      dialog/UpdateModulesDialog.monkey2
  15. 123 58
      document/CodeDocument.monkey2
  16. 32 7
      document/DocumentManager.monkey2
  17. 0 2
      document/SceneDocument.monkey2
  18. 53 14
      eventfilter/Monkey2KeyEventFilter.monkey2
  19. 61 11
      parser/CodeItem.monkey2
  20. 275 204
      parser/Monkey2Parser.monkey2
  21. 26 41
      parser/Parser.monkey2
  22. 23 4
      parser/ParserPlugin.monkey2
  23. 1 1
      syntax/Monkey2Keywords.monkey2
  24. 17 3
      testing/ParserTests.monkey2
  25. 3 0
      testing/test.bat
  26. 15 0
      utils/JsonUtils.monkey2
  27. 34 0
      utils/Utils.monkey2
  28. 31 23
      view/AutocompleteView.monkey2
  29. 4 1
      view/CodeMapView.monkey2
  30. 199 26
      view/CodeTextView.monkey2
  31. 23 9
      view/CodeTreeView.monkey2
  32. 7 3
      view/DebugView.monkey2
  33. 18 0
      view/DockingViewExt.monkey2
  34. 11 7
      view/FileBrowserExt.monkey2
  35. 241 0
      view/FindReplaceView.monkey2
  36. 3 3
      view/HelpTreeView.monkey2
  37. 42 19
      view/HintView.monkey2
  38. 6 6
      view/IRCView.monkey2
  39. 35 26
      view/MenuExt.monkey2
  40. 18 1
      view/ProjectBrowserView.monkey2
  41. 77 30
      view/ProjectView.monkey2
  42. 22 0
      view/SpacerView.monkey2
  43. 2 1
      view/StatusBarView.monkey2
  44. 393 30
      view/TabViewExt.monkey2
  45. 36 0
      view/TextFieldExt.monkey2
  46. 4 4
      view/ToolBarViewExt.monkey2
  47. 8 0
      view/TreeViewExt.monkey2
  48. 32 0
      view/ViewExtensions.monkey2

+ 417 - 179
MainWindow.monkey2

@@ -19,7 +19,7 @@ Global MainWindow:MainWindowInstance
 Class MainWindowInstance Extends Window
 	
 	Field SizeChanged:Void()
-	Field Rendered:Void()
+	Field Rendered:Void( canvas:Canvas )
 	
 	Method New( title:String,rect:Recti,flags:WindowFlags,jobj:JsonObject )
 		Super.New( title,rect,flags )
@@ -30,11 +30,9 @@ Class MainWindowInstance Extends Window
 		
 		LiveTemplates.Load()
 		
-		_docsTabView=New TabViewExt( TabViewFlags.DraggableTabs|TabViewFlags.ClosableTabs )
+		_tabsWrap=New DraggableTabs
 		
-		_browsersTabView=New TabView( TabViewFlags.DraggableTabs )
-		_browsersTabView.Style=GetStyle( "ProjectTabView" )
-		_consolesTabView=New TabView( TabViewFlags.DraggableTabs )
+		_docsTabView=New TabViewExt( TabViewFlags.DraggableTabs|TabViewFlags.ClosableTabs )
 		
 		_recentFilesMenu=New MenuExt( "Recent files" )
 		_recentProjectsMenu=New MenuExt( "Recent projects" )
@@ -48,6 +46,17 @@ Class MainWindowInstance Extends Window
 			
 			UpdateKeyView()
 			CodeDocument.HideAutocomplete()
+			
+			Local doc:=Cast<CodeTextView>( _docsManager.CurrentTextView )
+			Local mode:=doc ? doc.OverwriteMode Else False
+			OverwriteTextMode=mode
+			
+			_findReplaceView.CodeView=Cast<CodeTextView>( _docsManager.CurrentTextView )
+		End
+		
+		_docsManager.DocumentDoubleClicked+=Lambda( doc:Ted2Document )
+		
+			_buildActions.LockBuildFile()
 		End
 		
 		App.FileDropped+=Lambda( path:String )
@@ -89,7 +98,7 @@ Class MainWindowInstance Extends Window
 		
 		Local label:=New Label( "Filter:" )
 		bar.AddView( label,"left" )
-		Local editFilter:=New TextField()
+		Local editFilter:=New TextFieldExt
 		editFilter.Style=GetStyle( "TextFieldBordered" )
 		editFilter.CursorType=CursorType.Line
 		editFilter.CursorBlinkRate=2.5
@@ -146,7 +155,7 @@ Class MainWindowInstance Extends Window
 		'Help tab
 		
 		_helpView=New HtmlViewExt
-		_helpConsole=New DockingView
+		_docsConsole=New DockingView
 		bar=New ToolBarExt
 		bar.MaxSize=New Vec2i( 300,30 )
 		bar.AddIconicButton(
@@ -171,23 +180,37 @@ Class MainWindowInstance Extends Window
 		bar.AddSeparator()
 		bar.AddSeparator()
 		label=New Label
-		bar.AddView( label,"left" )
+		
+		bar.ContentView=label
 		
 		_helpView.Navigated+=Lambda( url:String )
 			
 			label.Text=url
 		End
 		
-		_helpConsole.AddView( bar,"top" )
-		_helpConsole.ContentView=_helpView
+		_helpTree=New HelpTreeView( _helpView )
+		_docsConsole.AddView( _helpTree,"right",200,True )
+		
+		_docsConsole.AddView( bar,"top" )
+		_docsConsole.ContentView=_helpView
+		
+		_helpSwitcher=New ToolButtonExt( New Action( "<" ) )
+		bar.AddView( New SpacerView( 6,0 ),"right" ) ' right offset
+		bar.AddView( _helpSwitcher,"right" )
+		_helpSwitcher.Clicked=Lambda()
+		
+			_helpTree.Visible=Not _helpTree.Visible
+			_helpSwitcher.Text=_helpTree.Visible ? ">" Else "<"
+			_helpSwitcher.Hint=_helpTree.Visible ? "Hide docs index" Else "Show docs index"
+		End
+		_helpTree.Visible=False
+		_helpSwitcher.Clicked() 'show at startup
 		
 		_helpView.Navigate( AboutPagePath )
 		
-		_helpTree=New HelpTreeView( _helpView )
 		
 		_debugView=New DebugView( _docsManager,_outputConsole )
 		
-		
 		_buildActions=New BuildActions( _docsManager,_buildConsole,_debugView )
 		_buildActions.ErrorsOccured+=Lambda( errors:BuildError[] )
 			ShowBuildConsole( True )
@@ -302,10 +325,9 @@ Class MainWindowInstance Extends Window
 		'
 		_findMenu=New MenuExt( "Find" )
 		_findMenu.AddAction( _findActions.find )
+		_findMenu.AddAction( _findActions.replace )
 		_findMenu.AddAction( _findActions.findNext )
 		_findMenu.AddAction( _findActions.findPrevious )
-		'_findMenu.AddAction( _findActions.replace )
-		'_findMenu.AddAction( _findActions.replaceAll )
 		_findMenu.AddSeparator()
 		_findMenu.AddAction( _findActions.findInFiles )
 		
@@ -393,10 +415,10 @@ Class MainWindowInstance Extends Window
 		_menuBar.AddMenu( _helpMenu )
 		
 		
-		_browsersTabView.AddTab( "Project",_projectView,True )
-		_browsersTabView.AddTab( "Source",_docBrowser,False )
-		_browsersTabView.AddTab( "Debug",_debugView,False )
-		_browsersTabView.AddTab( "Help",_helpTree,False )
+		'_browsersTabView.AddTab( "Project",_projectView,True )
+		'_browsersTabView.AddTab( "Source",_docBrowser,False )
+		'_browsersTabView.AddTab( "Debug",_debugView,False )
+		'_browsersTabView.AddTab( "Help",_helpTree,False )
 		
 		_buildErrorsList=New ListViewExt
 		_buildErrorsList.Visible=False
@@ -409,14 +431,6 @@ Class MainWindowInstance Extends Window
 		_buildConsoleView.AddView( _buildErrorsList,"right","400",True )
 		_buildConsoleView.ContentView=_buildConsole
 		
-		_consolesTabView.AddTab( "Build",_buildConsoleView,True )
-		_consolesTabView.AddTab( "Output",_outputConsoleView,False )
-		_consolesTabView.AddTab( "Docs",_helpConsole,False )
-		_consolesTabView.AddTab( "Find",_findConsole,False )
-		_consolesTabView.AddTab( "Chat",_ircView,False )
-		
-		_consolesTabView.CurrentChanged+=OnChatClicked
-		
 		_statusBar=New StatusBarView
 		
 		_contentView=New DockingView
@@ -450,34 +464,49 @@ Class MainWindowInstance Extends Window
 		
 	End
 	
-	Method ArrangeElements()
+	Method GainFocus()
 		
-		_contentView.RemoveView( _toolBar )
-		_contentView.RemoveView( _statusBar )
-		_contentView.RemoveView( _browsersTabView )
-		_contentView.RemoveView( _consolesTabView )
+		'Local event:=New WindowEvent( EventType.WindowGainedFocus,Self )
+		'OnWindowEvent( event )
 		
-		If Prefs.MainToolBarVisible
-			_toolBar=GetMainToolBar()
-			_contentView.AddView( _toolBar,"top" )
-		Endif
+		'SendWindowEvent( event )
+		'SDL_RaiseWindow( SDLWindow )
+	End
+	
+	Method HideFindPanel:Bool()
 		
-		_contentView.AddView( _statusBar,"bottom" )
+		If Not _findReplaceView.Visible Return False
 		
-		Local location:=Prefs.MainProjectTabsRight ? "right" Else "left"
+		_findReplaceView.CodeView=Null
+		_findReplaceView.Visible=False
+		UpdateKeyView()
 		
-		Local size:=_browsersTabView.Rect.Width
-		If size=0 Then size=300
-		_contentView.AddView( _browsersTabView,location,size,True )
+		Return True
+	End
+	
+	Method ShowFind( what:String="" )
 		
-		size=_consolesTabView.Rect.Height
-		If size=0 Then size=150
-		_contentView.AddView( _consolesTabView,"bottom",size,True )
+		_findReplaceView.CodeView=Cast<CodeTextView>( _docsManager.CurrentTextView )
 		
-		_contentView.ContentView=_docsTabView
+		Local arr:=what.Split( "~n" )
+		If arr.Length>1
+			what=""
+		Endif
 		
+		If _findReplaceView.Visible And Not what
+			what=_findReplaceView.FindText
+		Endif
+		_findReplaceView.Visible=True
+		_findReplaceView.FindText=what
+		_findReplaceView.Mode=FindReplaceView.Kind.Find
+		_findReplaceView.Activate()
 	End
 	
+	Method ShowReplace( what:String="" )
+		
+		ShowFind( what )
+		_findReplaceView.Mode=FindReplaceView.Kind.Replace
+	End
 	
 	Method OnFind()
 		_findActions.find.Trigger()
@@ -495,9 +524,10 @@ Class MainWindowInstance Extends Window
 	
 		If _buildConsole.Running
 			_buildConsole.Terminate()
-			HideStatusBarProgress()
-			RestoreConsoleVisibility()
 		Endif
+		_debugView.KillApp()
+		HideStatusBarProgress()
+		RestoreConsoleVisibility()
 		If _outputConsole.Running
 			_outputConsole.Terminate()
 		Endif
@@ -520,6 +550,14 @@ Class MainWindowInstance Extends Window
 		
 		If value=_ovdMode Return
 		_ovdMode=value
+		
+		Local doc:=Cast<CodeTextView>( _docsManager.CurrentTextView )
+		If doc
+			doc.OverwriteMode=_ovdMode
+		Else
+			_ovdMode=False
+		Endif
+		
 		SetStatusBarInsertMode( Not _ovdMode )
 	End
 	
@@ -561,9 +599,16 @@ Class MainWindowInstance Extends Window
 		SaveState()
 		_enableSaving=False
 		OnForceStop() ' kill build process if started
-		ProcessReader.StopAll()
 		If _ircView Then _ircView.Quit("Closing Ted2Go")
 		
+		' waiting for started processes if any
+		ParsersManager.DisableAll()
+		Local future:=New Future<Bool>
+		New Fiber( Lambda()
+			ProcessReader.WaitingForStopAll( future )
+		End )
+		future.Get()
+		
 		App.Terminate()
 	End
 
@@ -626,19 +671,19 @@ Class MainWindowInstance Extends Window
 	
 	Method StoreConsoleVisibility()
 	
-		If Prefs.SiblyMode return
+		'If Prefs.SiblyMode return
 		
-		_storedConsoleVisible=_consolesTabView.Visible
-		_consoleVisibleCounter=0
+		'_storedConsoleVisible=_consolesTabView.Visible
+		'_consoleVisibleCounter=0
 	End
 	
 	Method RestoreConsoleVisibility()
 	
-		If Prefs.SiblyMode Return
+		'If Prefs.SiblyMode Return
 	
-		If _consoleVisibleCounter > 0 Return
-		_consolesTabView.Visible=_storedConsoleVisible
-		RequestRender()
+		'If _consoleVisibleCounter > 0 Return
+		'_consolesTabView.Visible=_storedConsoleVisible
+		'RequestRender()
 	End
 	
 	Method IsTmpPath:Bool( path:String )
@@ -684,6 +729,35 @@ Class MainWindowInstance Extends Window
 	
 	Private
 	
+	Method GetFindDock:DockingView()
+		
+		If _findReplaceView Return _findReplaceView
+		
+		_findReplaceView=New FindReplaceView( _findActions )
+		
+		_findReplaceView.RequestedFind+=Lambda( opt:FindOptions )
+			
+			_findActions.options=opt
+			If opt.goNext
+				_findActions.findNext.Triggered()
+			Else
+				_findActions.findPrevious.Triggered()
+			Endif
+		End
+		
+		_findReplaceView.RequestedReplace+=Lambda( opt:FindOptions )
+		
+			_findActions.options=opt
+			If opt.all
+				_findActions.replaceAll.Triggered()
+			Else
+				_findActions.replaceNext.Triggered()
+			Endif
+		End
+		
+		Return _findReplaceView
+	End
+	
 	Method GetMainToolBar:ToolBarExt()
 		
 		If _toolBar Return _toolBar
@@ -704,22 +778,16 @@ Class MainWindowInstance Extends Window
 		Local cutTitle:=GetActionTextWithShortcut( _editActions.cut )
 		Local copyTitle:=GetActionTextWithShortcut( _editActions.copy )
 		Local pasteTitle:=GetActionTextWithShortcut( _editActions.paste )
+		Local goBackTitle:=GetActionTextWithShortcut( _viewActions.goBack )
+		Local goForwTitle:=GetActionTextWithShortcut( _viewActions.goForward )
 		
 		_toolBar=New ToolBarExt
 		_toolBar.Style=GetStyle( "MainToolBar" )
 		_toolBar.MaxSize=New Vec2i( 10000,40 )
 		
-		Local goBack:=Lambda()
-			Navigator.TryBack()
-		End
-		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/back.png" ),goBack,"Go back (Alt+Left)" )
-		
-		Local goForw:=Lambda()
-			Navigator.TryForward()
-		End
-		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/forward.png" ),goForw,"Go forward (Alt+Right)" )
+		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/back.png" ),_viewActions.goBack.Triggered,goBackTitle )
+		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/forward.png" ),_viewActions.goForward.Triggered,goForwTitle )
 		_toolBar.AddSeparator()
-		
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/new_file.png" ),_fileActions.new_.Triggered,newTitle )
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/open_file.png" ),_fileActions.open.Triggered,openTitle )
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/open_project.png" ),_projectView.openProject.Triggered,"Open project..." )
@@ -776,32 +844,54 @@ Class MainWindowInstance Extends Window
 	Public
 	
 	Method ShowProjectView()
-		_browsersTabView.CurrentView=_projectView
+		
+		_tabsWrap.tabs["Project"].Activate()
 	End
 	
 	Method ShowDebugView()
-		_browsersTabView.CurrentView=_debugView
+		
+		_tabsWrap.tabs["Debug"].Activate()
 	End
 	
 	Method ShowBuildConsole( vis:Bool=True )
 		
-		If vis _consolesTabView.Visible=True
-		_consolesTabView.CurrentView=_buildConsoleView
+		Local tab:=_tabsWrap.tabs["Build"]
+		tab.Activate()
+		If vis tab.ParentDock.Visible=True
 	End
 	
 	Method ShowOutputConsole( vis:Bool=True )
-		If vis _consolesTabView.Visible=True
-		_consolesTabView.CurrentView=_outputConsoleView
+		
+		Local tab:=_tabsWrap.tabs["Output"]
+		tab.Activate()
+		If vis tab.ParentDock.Visible=True
 	End
 	
 	Method ShowHelpView()
-		_consolesTabView.Visible=True
-		_consolesTabView.CurrentView=_helpConsole
+		
+		Local tab:=_tabsWrap.tabs["Docs"]
+		tab.Activate()
+		tab.ParentDock.Visible=True
 	End
 	
 	Method ShowFindResults()
-		_consolesTabView.Visible=True
-		_consolesTabView.CurrentView=_findConsole
+		
+		Local tab:=_tabsWrap.tabs["Find"]
+		tab.Activate()
+		tab.ParentDock.Visible=True
+	End
+	
+	Method ShowFindInDocs()
+		
+		Local doc:=Cast<CodeDocumentView>( _docsManager.CurrentTextView )
+		If Not doc Return
+		
+		Local ident:=doc.WordAtCursor
+		Print "ident: "+ident
+		_helpTree.QuickHelp( ident )
+		_helpTree.Visible=False
+		_helpSwitcher.Clicked()
+		_tabsWrap.tabs["Docs"].Activate()
 	End
 	
 	Method ShowQuickHelp()
@@ -809,7 +899,7 @@ Class MainWindowInstance Extends Window
 		Local doc:=Cast<CodeDocumentView>( _docsManager.CurrentTextView )
 		If Not doc Return
 		
-		Local ident:=doc.FullIdentAtCursor()
+		Local ident:=doc.FullIdentAtCursor
 		
 		If Not ident Return
 		
@@ -855,24 +945,26 @@ Class MainWindowInstance Extends Window
 			Else
 				Local nmspace:=item.Namespac
 				If parentIdent Then nmspace+="."+parentIdent
-				ShowStatusBarText( "("+item.KindStr+") "+item.Text+"    |  "+nmspace+"  |  "+StripDir( item.FilePath )+"  |  line "+(item.ScopeStartPos.x+1) )
+				Local ext:=item.IsExtension ? "(ext) " Else ""
+				ShowStatusBarText( ext+"("+item.KindStr+") "+item.Text+"    |  "+nmspace+"  |  "+StripDir( item.FilePath )+"  |  line "+(item.ScopeStartPos.x+1) )
 			Endif
 			
 			_helpIdent=ident
 			
-		Elseif KeywordsManager.Get( doc.FileType ).Contains( ident )
+		ElseIf KeywordsManager.Get( doc.FileType ).Contains( ident )
 			
 			ShowStatusBarText( "(keyword) "+ident )
 		
 		Else
 			
-			_helpTree.QuickHelp( ident )
-				
+			ShowFindInDocs()
+			
 		Endif
 		
 	End
 	
-	Method ShowHelp( url:String  )
+	Method ShowHelp( url:String )
+		
 		ShowHelpView()
 		_helpView.Navigate( url )
 		_helpView.Scroll=New Vec2i( 0,0 )
@@ -885,6 +977,8 @@ Class MainWindowInstance Extends Window
 		
 		If Not _editorMenu
 			_editorMenu=New MenuExt
+			_editorMenu.AddAction( _viewActions.gotoDeclaration )
+			_editorMenu.AddSeparator()
 			_editorMenu.AddAction( _editActions.cut )
 			_editorMenu.AddAction( _editActions.copy )
 			_editorMenu.AddAction( _editActions.paste )
@@ -933,6 +1027,7 @@ Class MainWindowInstance Extends Window
 		UpdateWindow( False )
 		
 		tv.GotoPosition( pos )
+		tv.MakeKeyView()
 	End
 	
 	Method GotoDeclaration()
@@ -941,6 +1036,7 @@ Class MainWindowInstance Extends Window
 		If Not doc Return
 		
 		doc.GotoDeclaration()
+		doc.TextView.MakeKeyView()
 	End
 	
 	Method GotoLine()
@@ -960,7 +1056,6 @@ Class MainWindowInstance Extends Window
 		
 	End
 	
-	
 	Method SaveState()
 	
 		If Not _enableSaving Return
@@ -969,18 +1064,13 @@ Class MainWindowInstance Extends Window
 		
 		jobj["windowRect"]=ToJson( Frame )
 		
-		Local vis:Bool
-		vis=_browsersTabView.Visible
-		jobj["browserVisible"]=New JsonBool( vis )
-		jobj["browserTab"]=New JsonString( GetBrowsersTabAsString() )
-		If vis Then _browsersSize=Int( _contentView.GetViewSize( _browsersTabView ) )
-		If _browsersSize > 0 Then jobj["browserSize"]=New JsonNumber( _browsersSize )
+		SaveTabsState( jobj )
 		
-		vis=_consolesTabView.Visible
-		jobj["consoleVisible"]=New JsonBool( vis )
-		jobj["consoleTab"]=New JsonString( GetConsolesTabAsString() )
-		If vis Then _consolesSize=Int( _contentView.GetViewSize( _consolesTabView ) ) 
-		If _consolesSize > 0 Then jobj["consoleSize"]=New JsonNumber( _consolesSize )
+		Local jdocs:=New JsonObject
+		jobj["docsTab"]=jdocs
+		
+		jdocs["indexerVisible"]=New JsonBool( _helpTree.Visible )
+		jdocs["indexerSize"]=New JsonString( _docsConsole.GetViewSize( _helpTree ) )
 		
 		Local recent:=New JsonArray
 		For Local path:=Eachin _recentFiles
@@ -1053,8 +1143,7 @@ Class MainWindowInstance Extends Window
 		
 		UpdateIrcIcon()
 		
-		Rendered()
-		Rendered=Null
+		Rendered( canvas )
 	End
 	
 	Method OnInit()
@@ -1133,11 +1222,13 @@ Class MainWindowInstance Extends Window
 		
 	End
 	
-	Method OnChatClicked()
+	Method OnChatTabActiveChanged()
+		
+		Local tab:=_tabsWrap.tabs["Chat"]
 		
-		If _consolesTabView.CurrentView<>_ircView Then Return
+		If Not tab.IsActive Return
 		
-		_consolesTabView.SetTabIcon( _ircView, Null )
+		tab.Icon=Null
 		
 		_ircNotifyIcon=0
 		
@@ -1147,7 +1238,7 @@ Class MainWindowInstance Extends Window
 	
 	Method OnChatMessage( message:IRCMessage, container:IRCMessageContainer, server:IRCServer )
 		
-		If message.type<>"PRIVMSG" Or _consolesTabView.CurrentView=_ircView Then Return
+		If message.type<>"PRIVMSG" Or _tabsWrap.tabs["Chat"].IsActive Return
 		
 		'Show notice icon
 		If message.text.Contains(server.nickname) Then
@@ -1161,7 +1252,8 @@ Class MainWindowInstance Extends Window
 				mentionStr+=message.fromUser+" in "
 				mentionStr+=container.name
 				
-				ShowHint( mentionStr, New Vec2i( 0, -GetStyle( "Hint" ).Font.Height*4 ), _consolesTabView, 20000 )
+				Local dock:=_tabsWrap.tabs["Chat"].ParentDock '_tabsWrap.docks["bottom"]
+				ShowHint( mentionStr, New Vec2i( 0, -GetStyle( "Hint" ).Font.Height*4 ), dock, 20000 )
 				
 			Endif
 			
@@ -1174,6 +1266,7 @@ Class MainWindowInstance Extends Window
 	End
 	
 	Method UpdateIrcIcon()
+		
 		If _ircNotifyIcon<=0 Then Return
 		
 		Local time:Int=Int(Millisecs()*0.0025)
@@ -1181,36 +1274,164 @@ Class MainWindowInstance Extends Window
 		If time=_ircIconBlink Then Return
 		_ircIconBlink=time
 		
+		Local tab:=_tabsWrap.tabs["Chat"]
+		
 		If time Mod 2 Then
 			Select _ircNotifyIcon
 				
 				Case 1
-					_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/notice.png" ) )
+					tab.Icon=App.Theme.OpenImage( "irc/notice.png" )
 					
 				Case 2
-					_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/important.png" ) )
+					tab.Icon=App.Theme.OpenImage( "irc/important.png" )
 			End
 		Else
-			_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/blink.png" ) )
+			tab.Icon=App.Theme.OpenImage( "irc/blink.png" )
 		Endif
 		
 	End
 	
-	Method LoadState( jobj:JsonObject )
+	Method InitTabs()
+		
+		If Not _tabsWrap.tabs.Empty Return
+		
+		_tabsWrap.AddTab( "Project",_projectView )
+		_tabsWrap.AddTab( "Debug",_debugView )
+		_tabsWrap.AddTab( "Source",_docBrowser )
+		_tabsWrap.AddTab( "Build",_buildConsoleView )
+		_tabsWrap.AddTab( "Output",_outputConsoleView )
+		_tabsWrap.AddTab( "Docs",_docsConsole )
+		_tabsWrap.AddTab( "Find",_findConsole )
+		_tabsWrap.AddTab( "Chat",_ircView )
+		
+		_tabsWrap.tabs["Chat"].ActiveChanged+=OnChatTabActiveChanged
+	End
 	
-		If jobj.Contains( "browserSize" )
-			_browsersSize=Int( jobj.GetNumber( "browserSize" ) )
-			_contentView.SetViewSize( _browsersTabView,_browsersSize )
+	Method ArrangeElements()
+		
+		InitTabs()
+		
+		_contentView.RemoveView( _toolBar )
+		_contentView.RemoveView( _statusBar )
+		_contentView.RemoveView( _findReplaceView )
+		
+		_tabsWrap.DetachFromParent()
+		
+		If Prefs.MainToolBarVisible
+			_toolBar=GetMainToolBar()
+			_contentView.AddView( _toolBar,"top" )
 		Endif
-		If jobj.Contains( "browserVisible" ) _browsersTabView.Visible=jobj.GetBool( "browserVisible" )
-		If jobj.Contains( "browserTab" ) SetBrowsersTabByString( jobj.GetString( "browserTab" ) )
 		
-		If jobj.Contains( "consoleSize" )
-			_consolesSize=Int( jobj.GetNumber( "consoleSize" ) )
-			_contentView.SetViewSize( _consolesTabView,_consolesSize )
+		_contentView.AddView( _statusBar,"bottom" )
+		
+		_tabsWrap.AttachToParent( _contentView )
+		
+		Local d:=GetFindDock()
+		d.Visible=False
+		_contentView.AddView( d,"bottom" )
+		
+		_contentView.ContentView=_docsTabView
+		
+		
+	End
+	
+	Method LoadTabsState( jobj:JsonObject )
+		
+		Global places:=New StringMap<StringStack>
+		' defaults
+		Local s:=""
+		places["left"]=New StringStack
+		s="Project,Source,Debug,Help"
+		places["right"]=New StringStack( s.Split( "," ) )
+		s="Build,Output,Docs,Find,Chat"
+		places["bottom"]=New StringStack( s.Split( "," ) )
+		
+		Global actives:=New StringMap<String>
+		' defaults
+		actives["left"]="Project"
+		actives["right"]="Project"
+		actives["bottom"]="Docs"
+		
+		Local edges:=DraggableTabs.Edges
+		
+		' put views
+		For Local edge:=Eachin edges
+			Local val:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Tabs" )
+			If val And val<>JsonValue.NullValue
+				For Local v:=Eachin val.ToArray().All()
+					Local key:=v.ToString()
+					' remove from defaults
+					For Local e:=Eachin edges
+						places[e].Remove( key )
+					Next
+					'
+					Local tab:=_tabsWrap.tabs[key]
+					If tab Then _tabsWrap.docks[edge].AddTab( tab )
+				Next
+			Endif
+		Next
+		
+		' put default if any
+		For Local edge:=Eachin edges
+			For Local name:=Eachin places[edge]
+				Local tab:=_tabsWrap.tabs[name]
+				If tab Then _tabsWrap.docks[edge].AddTab( tab )
+			Next
+		Next
+		
+		For Local edge:=Eachin edges
+			' set active
+			Local val:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Active" )
+			If val
+				actives[edge]=val.ToString()
+			Endif
+			Local tab:=_tabsWrap.tabs[actives[edge]]
+			If tab Then tab.Activate()
+			' set sizes
+			Local sz:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Size" )
+			If sz
+				_tabsWrap.sizes[edge]=sz.ToString()
+			Endif
+			Local dock:=_tabsWrap.docks[edge]
+			_contentView.SetViewSize( dock,_tabsWrap.sizes[edge] )
+			' set visibility
+			Local vis:=Json_FindValue( jobj.Data,"tabsDocks/"+edge+"Visible" )
+			If vis
+				dock.Visible=vis.ToBool()
+			Endif
+			dock.Visible=dock.Visible And (dock.NumTabs>0)
+		Next
+		
+	End
+	
+	Method SaveTabsState( jobj:JsonObject )
+	
+		Local jj:=New JsonObject
+		jobj["tabsDocks"]=jj
+		
+		Local edges:=DraggableTabs.Edges
+		
+		For Local edge:=Eachin edges
+			Local dock:=_tabsWrap.docks[edge]
+			jj[edge+"Tabs"]=JsonArray.Create( dock.TabsNames )
+			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 LoadState( jobj:JsonObject )
+	
+		LoadTabsState( jobj )
+		
+		If jobj.Contains( "docsTab" )
+			Local jdocs:=jobj.GetObject( "docsTab" )
+			Local size:=jdocs.GetString( "indexerSize" )
+			_docsConsole.SetViewSize( _helpTree,size )
+			Local vis:=jdocs.GetBool( "indexerVisible" )
+			_helpTree.Visible=Not vis
+			_helpSwitcher.Clicked()
 		Endif
-		If jobj.Contains( "consoleVisible" ) _consolesTabView.Visible=jobj.GetBool( "consoleVisible" )
-		If jobj.Contains( "consoleTab" ) SetConsolesTabByString( jobj.GetString( "consoleTab" ) )
 		
 		If jobj.Contains( "recentFiles" )
 			For Local file:=Eachin jobj.GetArray( "recentFiles" )
@@ -1245,7 +1466,7 @@ Class MainWindowInstance Extends Window
 		_docsManager.LoadState( jobj )
 		_buildActions.LoadState( jobj )
 		_projectView.LoadState( jobj )
-		
+		 
 		If Not _projectView.OpenProjects _projectView.OpenProject( CurrentDir() )
 		
 		UpdateRecentFilesMenu()
@@ -1262,15 +1483,33 @@ Class MainWindowInstance Extends Window
 	
 		Select event.Type
 		Case EventType.KeyDown
+			
 			Select event.Key
 			Case Key.Escape
+				
+				' hide find / replace panel
+				If HideFindPanel()
+					Return
+				Endif
+				
+				Local dock:TabViewExt
+				' show / hide left & right docks
 				If event.Modifiers & Modifier.Shift
-					_browsersTabView.Visible=Not _browsersTabView.Visible
-				Else
-					_consolesTabView.Visible=Not _consolesTabView.Visible
+					
+					dock=_tabsWrap.docks["left"]
+					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					
+					dock=_tabsWrap.docks["right"]
+					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					
+				Else ' bottom dock
+					
+					dock=_tabsWrap.docks["bottom"]
+					If dock.NumTabs>0 Then dock.Visible=Not dock.Visible
+					
 					_consoleVisibleCounter+=1
 				Endif
-			Case Key.Keypad1
+				
 			End
 		End
 	End
@@ -1317,18 +1556,19 @@ Class MainWindowInstance Extends Window
 	Field _outputConsole:ConsoleExt
 	Field _outputConsoleView:DockingView
 	Field _helpView:HtmlViewExt
-	Field _helpConsole:DockingView
+	Field _docsConsole:DockingView
 	Field _findConsole:TreeViewExt
 	
 	Field _projectView:ProjectView
 	Field _docBrowser:DockingView
 	Field _debugView:DebugView
 	Field _helpTree:HelpTreeView
+	Field _helpSwitcher:ToolButtonExt
 	
 	'Field _ircTabView:TabView
 	Field _docsTabView:TabViewExt
-	Field _consolesTabView:TabView
-	Field _browsersTabView:TabView
+	Field _consolesTabView2:TabView
+	Field _browsersTabView2:TabView
 	
 	Field _ircNotifyIcon:Int
 	Field _ircIconBlink:Int
@@ -1352,9 +1592,7 @@ Class MainWindowInstance Extends Window
 	Field _themeScale:=1.0
 	
 	Field _contentView:DockingView
-	Field _contentLeftView:DockingView
-	Field _contentRightView:DockingView
-
+	
 	Field _recentFiles:=New StringStack
 	Field _recentProjects:=New StringStack
 	
@@ -1368,8 +1606,8 @@ Class MainWindowInstance Extends Window
 	Field _isTerminating:Bool
 	Field _enableSaving:Bool
 	Field _resized:Bool
-	Field _browsersSize:=0,_consolesSize:=0
-
+	Field _findReplaceView:FindReplaceView
+	Field _tabsWrap:=New DraggableTabs
 	
 	Method ToJson:JsonValue( rect:Recti )
 		Return New JsonArray( New JsonValue[]( New JsonNumber( rect.min.x ),New JsonNumber( rect.min.y ),New JsonNumber( rect.max.x ),New JsonNumber( rect.max.y ) ) )
@@ -1547,75 +1785,75 @@ Class MainWindowInstance Extends Window
 		
 		App.Idle+=OnAppIdle
 		
-		GCCollect()	'thrash that GC!
 	End
 	
-	Method GetConsolesTabAsString:String()
+End
+
+
+Private
+
+Class DraggableTabs
+	
+	Const Edges:=New String[]( "left","right","bottom" )
+	
+	Field tabs:=New StringMap<TabButtonExt>
+	Field docks:=New StringMap<TabViewExt>
+	Field sizes:=New StringMap<String>
+	
+	Method New()
 		
-		Select _consolesTabView.CurrentView
-			Case _outputConsoleView
-				Return "output"
-			Case _buildConsoleView
-				Return "build"
-			Case _helpConsole
-				Return "docs"
-			Case _findConsole
-				Return "find"
-		End
-		Return ""
+		sizes["left"]="300"
+		sizes["right"]="300"
+		sizes["bottom"]="250"
+		
+		_docksArray=New TabViewExt[Edges.Length]
+		Local i:=0
+		For Local edge:=Eachin Edges
+			docks[edge]=New TabViewExt
+			_docksArray[i]=docks[edge]
+			i+=1
+		Next
 	End
 	
-	Method SetConsolesTabByString( value:String )
+	Method AttachToParent( view:DockingView )
 		
-		Local view:View
-		Select value
-			Case "output"
-				view=_outputConsoleView
-			Case "build"
-				view=_buildConsoleView
-			Case "docs"
-				view=_helpConsole
-			Case "find"
-				view=_findConsole
-		End
-		If view Then _consolesTabView.CurrentView=view
+		For Local edge:=Eachin Edges
+			view.AddView( docks[edge],edge,sizes[edge],True )
+		Next
+		_parent=view
 	End
 	
-	Method GetBrowsersTabAsString:String()
+	Method DetachFromParent()
+		
+		If Not _parent Return
+		
+		For Local edge:=Eachin Edges
+			_parent.RemoveView( docks[edge] )
+		Next
+	End
 	
-		Select _browsersTabView.CurrentView
-			Case _projectView
-				Return "project"
-			Case _docBrowser
-				Return "source"
-			Case _debugView
-				Return "debug"
-			Case _helpTree
-				Return "help"
-		End
-		Return ""
+	Method AddTab( name:String,view:View )
+		
+		tabs[name]=TabViewExt.CreateDraggableTab( name,view,_docksArray )
 	End
 	
-	Method SetBrowsersTabByString( value:String )
+	Method GetDockSize:String( dock:TabViewExt )
+		
+		Return _parent.GetViewSize( dock )
+	End
 	
-		Local view:View
-		Select value
-			Case "project"
-				view=_projectView
-			Case "source"
-				view=_docBrowser
-			Case "debug"
-				view=_debugView
-			Case "help"
-				view=_helpTree
-		End
-		If view Then _browsersTabView.CurrentView=view
+	Property AllDocks:TabViewExt[]()
+		Return _docksArray
 	End
+	
+	Private
+	
+	Field _docksArray:TabViewExt[]
+	Field _parent:DockingView
+	
 End
 
 
-Private
-
 Function OnCreatePlugins()
 	
 	#rem

+ 7 - 4
Prefs.monkey2

@@ -18,7 +18,6 @@ Class PrefsInstance
 	Field AcUseLiveTemplates:=True
 	'
 	Field MainToolBarVisible:=True
-	Field MainProjectTabsRight:=True
 	Field MainProjectIcons:=True
 	'
 	Field IrcNickname:String
@@ -35,6 +34,8 @@ Class PrefsInstance
 	Field EditorShowEvery10LineNumber:=True
 	Field EditorCodeMapVisible:=True
 	Field EditorAutoIndent:=True
+	Field EditorAutoPairs:=True
+	Field EditorSurroundSelection:=True
 	'
 	Field SourceSortByType:=True
 	Field SourceShowInherited:=False
@@ -69,7 +70,6 @@ Class PrefsInstance
 			
 			Local j2:=json["main"].ToObject()
 			MainToolBarVisible=Json_GetBool( j2,"toolBarVisible",MainToolBarVisible )
-			MainProjectTabsRight=Json_GetBool( j2,"tabsRight",MainProjectTabsRight )
 			MainProjectIcons=Json_GetBool( j2,"projectIcons",MainProjectIcons )
       
 		Endif
@@ -100,6 +100,8 @@ Class PrefsInstance
 			EditorShowEvery10LineNumber=Json_GetBool( j2,"showEvery10",EditorShowEvery10LineNumber )
 			EditorCodeMapVisible=Json_GetBool( j2,"codeMapVisible",EditorCodeMapVisible )
 			EditorAutoIndent=Json_GetBool( j2,"autoIndent",EditorAutoIndent )
+			EditorAutoPairs=Json_GetBool( j2,"autoPairs",EditorAutoPairs )
+			EditorSurroundSelection=Json_GetBool( j2,"surroundSelection",EditorSurroundSelection )
 			
 		Endif
 		
@@ -123,7 +125,6 @@ Class PrefsInstance
 		Local j:=New JsonObject
 		json["main"]=j
 		j["toolBarVisible"]=New JsonBool( MainToolBarVisible )
-		j["tabsRight"]=New JsonBool( MainProjectTabsRight )
 		j["projectIcons"]=New JsonBool( MainProjectIcons )
 		
 		j=New JsonObject
@@ -156,13 +157,15 @@ Class PrefsInstance
 		j["showEvery10"]=New JsonBool( EditorShowEvery10LineNumber )
 		j["codeMapVisible"]=New JsonBool( EditorCodeMapVisible )
 		j["autoIndent"]=New JsonBool( EditorAutoIndent )
+		j["autoPairs"]=New JsonBool( EditorAutoPairs )
+		j["surroundSelection"]=New JsonBool( EditorSurroundSelection )
 		
 		j=New JsonObject
 		json["source"]=j
 		j["sortByType"]=New JsonBool( SourceSortByType )
 		j["showInherited"]=New JsonBool( SourceShowInherited )
 		
-		If SiblyMode json["siblyMode"]=JsonBool.TrueValue
+		If "SiblyMode" json["siblyMode"]=JsonBool.TrueValue
 		
 	End
 	

+ 37 - 28
ProcessReader.monkey2

@@ -39,7 +39,7 @@ Class ProcessReader
 	
 	#rem monkeydoc Obtain a reader instance.
 	#end
-	Function Obtain:ProcessReader( tag:String="" )
+	Function Obtain:ProcessReader( tag:String )
 	
 		Local r:ProcessReader
 		If _recycled.Empty
@@ -47,10 +47,11 @@ Class ProcessReader
 		Else
 			r=_recycled[0]
 			_recycled.Remove( r )
+			r.Finished=Null
+			r.PortionRead=Null
+			r.Error=Null
+			r._running=False
 		Endif
-		r.Finished=Null
-		r.PortionRead=Null
-		r.Error=Null
 		r.Tag=tag
 		_items.Add( r )
 		Return r
@@ -67,14 +68,26 @@ Class ProcessReader
 	
 	#rem monkeydoc Stops all obtained readers if them are running and not recycled.
 	#end
-	Function StopAll()
-	
+	Function WaitingForStopAll( wait:Future<Bool> )
+		
+		_stopSize=0
+		_stopCounter=0
+		
 		For Local r:=Eachin _items
-			r.Stop()
+			If r.IsRunning
+				_stopSize+=1
+				r.Finished+=Lambda( s:String,c:Int )
+					_stopCounter+=1
+					If _stopCounter=_stopSize Then wait.Set( True )
+				End
+			Endif
 		Next
+		If _stopSize=0
+			wait.Set( True )
+			Return
+		Endif
 	End
 	
-	
 	#rem monkeydoc Async reading of process. You should to subscribe on (at least) Finished event to get result.
 	This method can be used without creation of new Fiber.
 	If started while process already running - nothing happen.
@@ -104,8 +117,14 @@ Class ProcessReader
 	#rem monkeydoc Terminate process execution.
 	#end
 	Method Stop()
-	
-		If Not _procOpen Return
+		
+		If Not _procOpen
+			If _stdoutWaiting
+				_stdoutWaiting.Set( False )
+				_stdoutWaiting=Null
+			Endif
+			Return
+		Endif
 		
 		_process.Terminate()
 		_running=False
@@ -113,7 +132,7 @@ Class ProcessReader
 	
 	#rem monkeydoc Is reading currently in progress.
 	#end
-	Method IsRunning:Bool()
+	Property IsRunning:Bool()
 	
 		Return _running
 	End
@@ -132,6 +151,7 @@ Class ProcessReader
 	Field _stdoutOpen:Bool,_procOpen:Bool
 	Global _items:=New Stack<ProcessReader>
 	Global _recycled:=New Stack<ProcessReader>
+	Global _stopSize:Int,_stopCounter:Int
 	
 	Method RunInternal:String( cmd:String )
 	
@@ -155,13 +175,13 @@ Class ProcessReader
 		Local process:=New Process
 	
 		process.Finished=Lambda()
-			
+			'Print "proc.finished: "+Tag
 			_procOpen=False
 			UpdateRunning()
 		End
 		
 		process.StdoutReady=Lambda()
-		
+			'Print "proc.stdoutReady: "+Tag
 			Local stdout:=process.ReadStdout()
 			
 			If stdout
@@ -177,7 +197,6 @@ Class ProcessReader
 		If Not process.Start( cmd ) Return False
 		
 		_process=process
-		
 		_running=True
 		_procOpen=True
 		_stdoutOpen=True
@@ -192,25 +211,15 @@ Class ProcessReader
 	
 		_running=False
 		
-		If _stdoutWaiting Then _stdoutWaiting.Set( True )
-		
 		Local code:=_process.ExitCode
 		
 		Finished( _output,code )
 		If code<>0 Then Error( code )
 		
+		If _stdoutWaiting
+			_stdoutWaiting.Set( True )
+			_stdoutWaiting=Null
+		Endif
 	End
 	
 End
-
-
-Private
-
-' Extends ProcessReader - to get access to protected New()
-Class ProcessBridge Extends ProcessReader
-
-	Function Create:ProcessReader()
-		
-		Return New ProcessReader
-	End
-End

+ 8 - 2
Ted2.monkey2

@@ -105,12 +105,18 @@
 #Import "view/ScrollableViewExt"
 #Import "view/BuildErrorListViewItem"
 #Import "view/TextFieldExt"
+#Import "view/SpacerView"
+#Import "view/FindReplaceView"
+#Import "view/ViewExtensions"
+#Import "view/DockingViewExt"
 
 #Import "Plugin"
 #Import "ThemeImages"
 #Import "Prefs"
 #Import "ProcessReader"
 #Import "LiveTemplates"
+#Import "SystemCursor"
+#Import "DraggableTabs"
 #Import "MainWindow"
 
 
@@ -124,7 +130,7 @@ Using tinyxml2..
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
-Global AppTitle:="Ted2Go v2.5"
+Global AppTitle:="Ted2Go v2.6"
 
 
 Function Main()
@@ -209,7 +215,7 @@ Function SetupMonkeyRootPath:String( rootPath:String,searchMode:Bool )
 		' search for choosen-by-requester folder
 		While Not found
 	
-			Local ok:=Confirm( "Initializing","Error initializing - can't find working dir!~nDo you want to specify Monkey2 root folder now?" )
+			Local ok:=Confirm( "Initializing","Monkey2 root directory isn't set.~nTo continue, you should to specify it." )
 			If Not ok
 				Return ""
 			End

+ 25 - 17
action/BuildActions.monkey2

@@ -99,7 +99,6 @@ Class BuildActions Implements IModuleBuilder
 #Endif
 		semant.Triggered=OnSemant
 		
-		
 		buildSettings=New Action( "Product settings..." )
 		buildSettings.Triggered=OnBuildFileSettings
 		
@@ -108,7 +107,7 @@ Class BuildActions Implements IModuleBuilder
 		nextError.HotKey=Key.F4
 		
 		lockBuildFile=New Action( "Lock build file" )
-		lockBuildFile.Triggered=OnLockBuildFile
+		lockBuildFile.Triggered=LockBuildFile
 		lockBuildFile.HotKey=Key.L
 		lockBuildFile.HotKeyModifiers=Modifier.Menu
 		
@@ -207,7 +206,8 @@ Class BuildActions Implements IModuleBuilder
 	
 	Method LockBuildFile()
 		
-		OnLockBuildFile()
+		Local doc:=Cast<CodeDocument>( _docs.CurrentDocument )
+		OnLockBuildFile( doc )
 	End
 	
 	Method SaveState( jobj:JsonObject )
@@ -224,7 +224,7 @@ Class BuildActions Implements IModuleBuilder
 		If jobj.Contains( "lockedDocument" )
 			Local path:=jobj["lockedDocument"].ToString()
 			_locked=Cast<CodeDocument>( _docs.FindDocument( path ) )
-			If _locked _locked.State="+"
+			If _locked Then SetLockedState( _locked,True )
 		Endif
 		
 		If jobj.Contains( "buildConfig" )
@@ -321,12 +321,12 @@ Class BuildActions Implements IModuleBuilder
 		Local doc:=Cast<CodeDocument>( _docs.OpenDocument( err.path,True ) )
 		If Not doc Return
 	
-		Local tv := doc.TextView
+		Local tv := doc.CodeView
 		If Not tv Return
 	
 		MainWindow.UpdateWindow( False )
 	
-		tv.GotoLine( err.line )
+		tv.GotoPosition( New Vec2i( err.line,0 ) )
 	End
 	
 	
@@ -361,9 +361,13 @@ Class BuildActions Implements IModuleBuilder
 		Return _locked
 	End
 	
-	Method SaveAll:Bool()
-	
+	Method SaveAll:Bool( buildFile:String )
+		
+		Local proj:=ProjectView.FindProjectByFile( buildFile )
+		
 		For Local doc:=Eachin _docs.OpenDocuments
+			' save docs only for built project
+			If proj And Not doc.Path.StartsWith( proj ) Continue
 			If Not doc.Save() Return False
 		Next
 		
@@ -381,7 +385,7 @@ Class BuildActions Implements IModuleBuilder
 
 	End
 
-	Method BuildMx2:Bool( cmd:String,progressText:String,action:String="build",showElapsedTime:Bool=False )
+	Method BuildMx2:Bool( cmd:String,progressText:String,action:String="build",buildFile:String="",showElapsedTime:Bool=False )
 	
 		ClearErrors()
 		
@@ -391,7 +395,7 @@ Class BuildActions Implements IModuleBuilder
 		
 		MainWindow.ShowBuildConsole()
 		
-		If Not SaveAll() Return False
+		If Not SaveAll( buildFile ) Return False
 		
 		_timing=Millisecs()
 		
@@ -500,7 +504,7 @@ Class BuildActions Implements IModuleBuilder
 	
 	Method MakeDocs:Bool()
 	
-		Return BuildMx2( MainWindow.Mx2ccPath+" makedocs","Rebuilding documentation...","build",True )
+		Return BuildMx2( MainWindow.Mx2ccPath+" makedocs","Rebuilding documentation...","build","",True )
 	End
 	
 	Method BuildApp:Bool( config:String,target:String,sourceAction:String )
@@ -526,7 +530,7 @@ Class BuildActions Implements IModuleBuilder
 		Local title := sourceAction="build" ? "Building" Else (sourceAction="run" ? "Running" Else "Checking")
 		Local msg:=title+" ~ "+target+" ~ "+config+" ~ "+StripDir( buildDoc.Path )
 		
-		If Not BuildMx2( cmd,msg,sourceAction,True ) Return False
+		If Not BuildMx2( cmd,msg,sourceAction,buildDoc.Path,True ) Return False
 		
 		_console.Write("~nDone.")
 		
@@ -606,13 +610,11 @@ Class BuildActions Implements IModuleBuilder
 		GotoError( _errors.First )
 	End
 	
-	Method OnLockBuildFile()
+	Method OnLockBuildFile( doc:CodeDocument )
 	
-		Local doc:=Cast<CodeDocument>( _docs.CurrentDocument )
-		
 		If Not doc Return
 		
-		If _locked _locked.State=""
+		If _locked Then SetLockedState( _locked,False )
 		
 		If doc=_locked
 			_locked=Null
@@ -620,8 +622,14 @@ Class BuildActions Implements IModuleBuilder
 		Endif
 		
 		_locked=doc
-		_locked.State="+"
+		SetLockedState( _locked,True )
+	End
+	
+	Method SetLockedState( doc:CodeDocument,locked:Bool )
 		
+		doc.State=locked ? "+" Else ""
+		Local tab:=_docs.FindTab( doc.View )
+		If tab Then tab.SetLockedState( locked )
 	End
 	
 	Method OnBuildFileSettings()

+ 157 - 200
action/FindActions.monkey2

@@ -8,25 +8,25 @@ Class FindActions
 	Field findNext:Action
 	field findPrevious:Action
 	Field replace:Action
+	Field replaceNext:Action
 	Field replaceAll:Action
 	Field findInFiles:Action
 	Field findAllInFiles:Action
 	
+	Field options:FindOptions
+	
 	Method New( docs:DocumentManager,projView:ProjectView,findConsole:TreeViewExt )
 		
 		_docs=docs
 		_findConsole=findConsole
-		_projView=projView
 		
-		find=New Action( "Find / Replace..." )
+		find=New Action( "Find..." )
 		find.Triggered=OnFind
 		find.HotKey=Key.F
 		find.HotKeyModifiers=Modifier.Menu
 		
 		findNext=New Action( "Find next" )
-		findNext.Triggered=Lambda()
-			OnFindNext()
-		End
+		findNext.Triggered=OnFindNext
 		findNext.HotKey=Key.F3
 		
 		findPrevious=New Action( "Find previous" )
@@ -34,15 +34,25 @@ Class FindActions
 		findPrevious.HotKey=Key.F3
 		findPrevious.HotKeyModifiers=Modifier.Shift
 		
-		replace=New Action( "Replace" )
+		replace=New Action( "Replace..." )
 		replace.Triggered=OnReplace
+		#If __TARGET__="macos"
+		replace.HotKey=Key.F
+		replace.HotKeyModifiers=Modifier.Alt|Modifier.Menu
+		#Else
+		replace.HotKey=Key.H
+		replace.HotKeyModifiers=Modifier.Menu
+		#Endif
+		replaceNext=New Action( "Replace next" )
+		replaceNext.Triggered=OnReplaceNext
 		
 		replaceAll=New Action( "Replace all" )
 		replaceAll.Triggered=OnReplaceAll
 		
 		findInFiles=New Action( "Find in files..." )
 		findInFiles.Triggered=Lambda()
-			OnFindInFiles()
+			Local proj:=projView.FindProjectByFile( docs.CurrentDocument.Path )
+			OnFindInFiles( "",proj )
 		End
 		findInFiles.HotKey=Key.F
 		findInFiles.HotKeyModifiers=Modifier.Menu|Modifier.Shift
@@ -62,11 +72,12 @@ Class FindActions
 		replace.Enabled=tv
 		replaceAll.Enabled=tv
 	End
-	
+	#Rem
 	Method FindByTextChanged( entireProject:Bool )
 		
 		If Not entireProject Then OnFindNext( False )
 	End
+	#End
 	
 	Method FindInFiles( folder:String )
 	
@@ -85,225 +96,133 @@ Class FindActions
 	Field _findInFilesDialog:FindInFilesDialog
 	Field _findConsole:TreeViewExt
 	Field _cursorPos:=0
-	Field _projView:ProjectView
 	
 	Method OnFind()
 		
+		Local s:=GetInitialText()
+		MainWindow.ShowFind( s )
+	End
+	
+	Method GetInitialText:String()
+		
 		Local tv:=_docs.CurrentTextView
-		If tv <> Null
-			_cursorPos=Min( tv.Cursor,tv.Anchor )
-			Local s:=""
-			If tv.Cursor <> tv.Anchor
-				Local min:=Min( tv.Cursor,tv.Anchor )
-				Local max:=Max( tv.Cursor,tv.Anchor )
-				s=tv.Text.Slice( min,max )
-			Endif
-			_findDialog.SetInitialText( s )
-		Endif
+		If Not tv Return ""
+		
+		_cursorPos=Min( tv.Cursor,tv.Anchor )
 		
-		_findDialog.Show()
+		If tv.CanCopy And Not Prefs.SiblyMode
+			Local min:=Min( tv.Cursor,tv.Anchor )
+			Local max:=Max( tv.Cursor,tv.Anchor )
+			Return tv.Text.Slice( min,max )
+		Endif
+		Return ""
 	End
 	
-	Method OnFindInFiles( folder:String=Null )
-	
-		Local tv:=_docs.CurrentTextView
-		If tv <> Null
-			If tv.Cursor <> tv.Anchor
-				Local min:=Min( tv.Cursor,tv.Anchor )
-				Local max:=Max( tv.Cursor,tv.Anchor )
-				Local s:=tv.Text.Slice( min,max )
-				_findInFilesDialog.SetInitialText( s )
+	Method GetRange:Vec2i( tv:TextView )
+		
+		If options.selectionOnly
+			Local code:=Cast<CodeTextView>( tv )
+			If code And code.HasExtraSelection
+				Return New Vec2i( code.ExtraSelectionStart,code.ExtraSelectionEnd )
 			Endif
 		Endif
 		
-		_findInFilesDialog.CustomFolder=folder
-		_findInFilesDialog.Show()
+		Return New Vec2i( 0,tv.Text.Length )
 	End
 	
-	Field _storedTextView:TextView
-	Field _storedWhat:String
-	Field _storedCaseSens:Bool
-	Field _storedEntireProject:Bool
-	Field _results:Stack<FileJumpData>
-	Field _resultIndex:Int=-1
-	Field _storedChanges:=0,_changesCounter:=0
-	Field _storedLastCursor:=-1
+	Method OnFindInFiles( folder:String=Null,selProj:String=Null )
 	
-	Method OnTextChanged()
-		
-		_changesCounter+=1
+		Local s:=GetInitialText()
+		If s Then _findInFilesDialog.SetInitialText( s )
+		_findInFilesDialog.SetSelectedProject( selProj )
+		_findInFilesDialog.CustomFolder=folder
+		_findInFilesDialog.Show()
 	End
 	
-	Method OnCursorChanged()
+	Method OnFindNext()
 		
-		Local tv:=_docs.CurrentTextView
-		If tv
-			_cursorPos=Min( tv.Cursor,tv.Anchor )
-		Endif
-	End
-	
-	Method OnFindNext( changeCursorPos:Bool=True )
-	
 		Local tv:=_docs.CurrentTextView
 		If Not tv Return
 		
-		Local doc:=_docs.CurrentDocument
+		If Not options Return
 		
-		tv.Document.TextChanged-=OnTextChanged
-		tv.Document.TextChanged+=OnTextChanged
-		
-		tv.CursorMoved-=OnCursorChanged
-		tv.CursorMoved+=OnCursorChanged
+		Local doc:=_docs.CurrentDocument
 		
-		Local what:=_findDialog.FindText
+		Local what:=options.findText
 		If Not what Return
 		
-		Local sens:=_findDialog.CaseSensitive
+		Local text:=tv.Text
+		Local sens:=options.caseSensitive
 		
 		If Not sens
 			what=what.ToLower()
+			text=text.ToLower()
 		Endif
 		
-		Local entire:=_findDialog.EntireProject
-		
-		' when typing request word we should everytime find from current cursor
-		Local cursor:=_cursorPos
-		If changeCursorPos
-			cursor=Min( tv.Anchor,tv.Cursor )
-			_cursorPos=cursor
-		Endif
-		
-		Local theSame:=(what=_storedWhat And sens=_storedCaseSens And entire=_storedEntireProject)
-		theSame = theSame And _storedChanges=_changesCounter
+		Local range:=GetRange( tv )
 		
-		If Not entire Then theSame=theSame And tv=_storedTextView
+		Local cursor:=Max( tv.Anchor,tv.Cursor )
 		
-		_storedWhat=what
-		_storedTextView=tv
-		_storedCaseSens=sens
-		_storedEntireProject=entire
-		_storedChanges=_changesCounter
+		If cursor<range.x Or cursor>range.y Then cursor=range.x
 		
-		If Not theSame Then _results=Null
+		Local i:=text.Find( what,cursor )
 		
-		If Not _results
-			
-			_resultIndex=-1
-			_storedLastCursor=-1
-			
-			' start new search
-			If entire
-				
-				New Fiber( Lambda()
-				
-					Local proj:=""
-					For Local p:=Eachin _projView.OpenProjects
-						If doc.Path.Contains( p )
-							proj=p
-							Exit
-						Endif
-					End
-					Local map:=FindInProject( what,proj,sens )
-					If map
-						CreateResultTree( _findConsole.RootNode,map,what,proj )
-						MainWindow.ShowFindResults()
-					Endif
-					
-					If Not map.Empty
-						
-						_results=New Stack<FileJumpData>
-						
-						' make current opened document as a first results
-						Local curPath:=_docs.CurrentDocument ? _docs.CurrentDocument.Path Else ""
-						If curPath
-							Local vals:=map[curPath]
-							If vals
-								_results.AddAll( vals )
-								map.Remove( curPath )
-							Endif
-						Endif
-						
-						For Local items:=Eachin map.Values
-							_results.AddAll( items )
-						End
-						
-					Endif
-					
-					Jump( NXT )
-				End )
-				
-				Return
-				
-			Else
-				
-				_results=FindInFile( doc.Path,what,sens,tv.Document )
-				
-			Endif
+		If i=-1 Or i+what.Length>range.y
+			If Not options.wrapAround Return
 			
+			i=text.Find( what,range.x )
+			If i=-1 Or i+what.Length>range.y Return
 		Endif
 		
-		Jump( NXT )
+		tv.SelectText( i,i+what.Length )
 		
 	End
 	
-	Method Jump( nxtOrPrev:Int )
+	Method OnFindPrevious()
 		
-		If Not _results Or _results.Length=0 Return
+		Local tv:=_docs.CurrentTextView
+		If Not tv Return
 		
-		If nxtOrPrev=NXT
-			_resultIndex=(_resultIndex+1) Mod _results.Length
-		Else
-			_resultIndex-=1
-			If _resultIndex<0 Then _resultIndex=_results.Length-1
-		Endif
+		If Not options Return
 		
-		Local jump:=_results[_resultIndex]
+		Local doc:=_docs.CurrentDocument
 		
-		If _storedEntireProject
-			MainWindow.OpenDocument( jump.path )
-		Endif
-	
-		Local tv:=_docs.CurrentTextView
-		If tv
-			Local i:=FixResultIndexByCursor( _docs.CurrentDocument,_resultIndex,nxtOrPrev )
-			If i<>_resultIndex
-				_resultIndex=i
-				jump=_results[_resultIndex]
-			Endif
-			tv.SelectText( jump.pos,jump.pos+jump.len )
-			_storedLastCursor=Min( tv.Cursor,tv.Anchor )
+		Local what:=options.findText
+		If Not what Return
+		
+		Local text:=tv.Text
+		Local sens:=options.caseSensitive
+		
+		If Not sens
+			what=what.ToLower()
+			text=text.ToLower()
 		Endif
-	
-	End
-	
-	Method FixResultIndexByCursor:Int( doc:Ted2Document,index:Int,nxtOrPrev:Int )
 		
-		Local tv:=doc.TextView
-		Local theSameDoc:=(tv=_storedTextView)
-		Local cursor:=Min( tv.Cursor,tv.Anchor )
-		Local findFromCursor:=(theSameDoc And cursor<>_storedLastCursor)
+		Local range:=GetRange( tv )
 		
-		If Not findFromCursor Return index
+		Local i:=text.Find( what,range.x )
+		If i=-1 Or i+what.Length>range.y Return
 		
-		' take the first result accordingly to cursor
-		If nxtOrPrev=NXT
-			For Local i:=0 Until _results.Length
-				Local jump:=_results[i]
-				If jump.path=doc.Path And jump.pos>=cursor Return i
-			Next
-			Return 0
+		Local cursor:=Min( tv.Anchor,tv.Cursor )
+		
+		If cursor<range.x Or cursor>range.y Then cursor=range.y
+		
+		If i>=cursor
+			If Not options.wrapAround Return
+			Repeat
+				Local n:=text.Find( what,i+what.Length )
+				If n=-1 Or n>=range.y Exit
+				i=n
+			Forever
 		Else
-			For Local i:=_results.Length-1 To 0 Step -1
-				Local jump:=_results[i]
-				If jump.path=doc.Path And jump.pos<=cursor Return i
-			Next
-			Return _results.Length-1
-		Endif
-	End
-	
-	Method OnFindPrevious()
+			Repeat
+				Local n:=text.Find( what,i+what.Length )
+				If n=-1 Or n>=cursor Exit
+				i=n
+			Forever
+		End
 		
-		Jump( PREV )
+		tv.SelectText( i,i+what.Length )
 	End
 	
 	Method OnFindAllInFiles()
@@ -394,6 +313,7 @@ Class FindActions
 		Return result
 	End
 	
+	#Rem
 	Method FindInFile:Stack<FileJumpData>( filePath:String,what:String,caseSensitive:Bool,doc:TextDocument=Null )
 	
 		Local len:=what.Length
@@ -427,6 +347,7 @@ Class FindActions
 
 		Return result
 	End
+	#End
 	
 	Method CreateResultTree( root:TreeView.Node,map:StringMap<Stack<FileJumpData>>,what:String,projectPath:String )
 		
@@ -456,26 +377,40 @@ Class FindActions
 	End
 	
 	Method OnReplace()
+		
+		Local s:=GetInitialText()
+		MainWindow.ShowReplace( s )
+	End
+	
+	Method OnReplaceNext()
 	
 		Local tv:=_docs.CurrentTextView
 		If Not tv Return
 		
-		Local text:=_findDialog.FindText
-		If Not text Return
-		
 		Local min:=Min( tv.Anchor,tv.Cursor )
 		Local max:=Max( tv.Anchor,tv.Cursor )
 		
-		Local tvtext:=tv.Text.Slice( min,max )
+		Local text:=tv.Text.Slice( min,max )
+		Local what:=options.findText
+		
+		If Not text Return
 
-		If Not _findDialog.CaseSensitive
-			tvtext=tvtext.ToLower()
+		If Not options.caseSensitive
 			text=text.ToLower()
+			what=what.ToLower()
 		Endif
 		
-		If tvtext<>text Return
+		If text<>what Return
+		
+		Local with:=options.replaceText
 		
-		tv.ReplaceText( _findDialog.ReplaceText )
+		tv.ReplaceText( with )
+		
+		' temp solution
+		If options.selectionOnly
+			Local code:=Cast<CodeTextView>( tv )
+			If code Then code.ExtraSelectionEnd+=(with.Length-what.Length)
+		Endif
 		
 		OnFindNext()
 
@@ -486,35 +421,57 @@ Class FindActions
 		Local tv:=_docs.CurrentTextView
 		If Not tv Return
 		
-		Local text:=_findDialog.FindText
-		If Not text Return
+		Local what:=options.findText
+		If Not what Return
 		
-		Local rtext:=_findDialog.ReplaceText
+		Local with:=options.replaceText
 		
-		Local tvtext:=tv.Text
+		Local text:=tv.Text
 
-		If Not _findDialog.CaseSensitive
-			tvtext=tvtext.ToLower()
+		If Not options.caseSensitive
 			text=text.ToLower()
+			what=what.ToLower()
 		Endif
 		
 		Local anchor:=tv.Anchor
 		Local cursor:=tv.Cursor
 		
-		Local i:=0,t:=0
+		Local range:=GetRange( tv )
+		
+		Local lenWhat:=what.Length
+		Local lenWith:=with.Length
+		
+		Local i:=range.x,t:=0
 		Repeat
 		
-			i=tvtext.Find( text,i )
-			If i=-1 Exit
+			i=text.Find( what,i )
+			If i=-1 Or i+lenWhat>range.y Exit
 			
-			tv.SelectText( i+t,i+text.Length+t )
-			tv.ReplaceText( rtext )
+			tv.SelectText( i+t,i+lenWhat+t )
+			tv.ReplaceText( with )
 			
-			t+=rtext.Length-text.Length
-			i+=text.Length
+			' select last replacement
+			cursor=tv.Cursor
+			anchor=tv.Cursor-lenWith
+			
+			Local dlen:=lenWith-lenWhat
+			
+			' temp solution
+			If options.selectionOnly
+				Local code:=Cast<CodeTextView>( tv )
+				If code Then code.ExtraSelectionEnd+=dlen
+			Endif
+			
+			t+=dlen
+			i+=lenWhat
 			
 		Forever
 		
+'		If options.selectionOnly
+'			anchor=range.x
+'			cursor=range.x
+'		Endif
+		
 		tv.SelectText( anchor,cursor )
 		
 	End

+ 2 - 2
action/ViewActions.monkey2

@@ -18,12 +18,12 @@ Class ViewActions
 		goBack=New Action( "Go back" )
 		goBack.Triggered=OnGoBack
 		goBack.HotKey=Key.Left
-		goBack.HotKeyModifiers=Modifier.Alt
+		goBack.HotKeyModifiers=Modifier.Alt|Modifier.Menu
 		
 		goForward=New Action( "Go forward" )
 		goForward.Triggered=OnGoForward
 		goForward.HotKey=Key.Right
-		goForward.HotKeyModifiers=Modifier.Alt
+		goForward.HotKeyModifiers=Modifier.Alt|Modifier.Menu
 		
 		comment=New Action( "Comment block" )
 		comment.Triggered=OnComment

+ 13 - 15
assets/aboutTed2Go.html

@@ -44,9 +44,7 @@ a:hover{
 
 <body>
 
-<h2>Ted2Go is a fork of an official Ted2 IDE.</h2>
-
-<a href="https://github.com/engor/Ted2Go">Sources on Github</a> | <a href="https://trello.com/b/6FHUXCBF/ted2go">Todo on Trello</a> | <a href="http://monkeycoder.co.nz/forums/topic/ted2go-fork/">Discuss on Forum</a> | <a href="https://paypal.me/engor/10">Donate</a><br>
+<center><a href="https://github.com/engor/Ted2Go">Sources on Github</a> | <a href="https://trello.com/b/6FHUXCBF/ted2go">Todo on Trello</a> | <a href="http://monkeycoder.co.nz/forums/topic/ted2go-fork/">Discuss on Forum</a> | <a href="https://paypal.me/engor/10">Donate</a><br></center>
 
 <h3>Features</h3>
 
@@ -99,22 +97,22 @@ Allow you to find in whole project.
 <h3>Shortcuts</h3>
 <ul>
 <li>F1 - show help for ident under cursor;</li>
-<li>F12 - goto ident declaration;</li>
-<li>Alt+Left / Alt+Right - go back / go forward through navigation stack;</li>
-<li>Ctrl+' - comment selected lines (macos: Ctrl+\);</li>
-<li>Ctrl+Shift+' - uncomment selected lines (macos: Ctrl+Shift+\);</li>
-<li>Ctrl+E - delete whole line under cursor (on windows).</li>
+<li>F2/F12 - goto ident declaration;</li>
+<li>Ctrl+Alt+Left / Ctrl+Alt+Right - go back / go forward through navigation stack;</li>
+<li>Ctrl+' (or just ' for selection) - comment selected lines (macos: Ctrl+\);</li>
+<li>Ctrl+Shift+' (or just ' for selection) - uncomment selected lines (macos: Ctrl+Shift+\);</li>
+<li>Ctrl+E - delete whole line under cursor (macos: Ctrl+Backspace).</li>
 <li>Ctrl+Shift+F - open "Find in files" dialog.</li>
 <li>Shift+F5 - stop current process (cancel building, etc).</li>
-<li>Esc - show/hide console tabs.</li>
-<li>Shift+Esc - show/hide project tabs.</li>
+<li>Esc - show/hide bottom tabs.</li>
+<li>Shift+Esc - show/hide left&right tabs.</li>
 </ul>
 
 
-<h3>Author</h3>
+<h3>Authors</h3>
 
-<p>By Evgeniy Goroshkin (nerobot/engor).<br>
-Welcome to say me thanks with <a href="https://paypal.me/engor/10">PayPal donation</a>.<br>
+<p>Maintained by Evgeniy Goroshkin (nerobot/engor) and Mark Sibly.<br>
+Welcome to say thanks to Evgeniy with <a href="https://paypal.me/engor/10">PayPal donation</a>.<br>
 Enjoy coding!</p>
 
 
@@ -124,9 +122,9 @@ Enjoy coding!</p>
 ToolBar icons were taken from <a href="https://icons8.com/icon/new-icons/win8">icons8.com</a>.</p>
 
 
-<h3>Special Thanks</h3>
+<h3>Special thanks</h3>
 
-<p>Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
+<p>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>
 

+ 19 - 7
assets/themes/ted2-default.json

@@ -6,6 +6,7 @@
 		"transparent": "#0000",
 		"textview-cursor-line":"#2000",
 		"textview-whitespaces":"#2aaa",
+		"textview-extra-selection":"#5555",
 		"statusbar": "content",
 		"statusbar-active": "#CA5100",
 		"menu-shortcut":"text-background",
@@ -76,7 +77,7 @@
 
 		"ColoredToolButton":{
 			"extends":"ToolButton",
-			"iconColor":"#6A92CF"
+			"iconColor":"text-default"
 		},
 
 		"TabViewArrowPrev":{
@@ -127,12 +128,7 @@
 		"CompletionDialogContent":{
 			"padding":[ 1 ]
 		},
-		
-		"ProjectTabView":{
-			"extends":"TabView",
-			"backgroundColor":"content"
-		},
-		
+				
 		"TextFieldBordered":{
 			"extends":"TextField",
 			"border":[ 1 ],
@@ -184,6 +180,22 @@
 					"backgroundColor":"active"
 				}
 			}
+		},
+
+		"FindReplaceView":{
+			"extends":"DockingView",
+			"padding":[ 0,4,0,2 ]
+		},
+
+		"TabsDropArea":{
+			"extends":"Label",
+			"backgroundColor":"#5009"
+		},
+		
+		"TabButtonLocked":{
+			"extends":"TabButton",
+			"borderColor":"#fa22",
+			"border":[ 0,0,0,1 ]
 		}
 	}
 }

+ 1 - 1
dialog/EditProductDialog.monkey2

@@ -21,7 +21,7 @@ Class ProductVar
 		Select type
 		Case "string"
 		
-			Local view:=New TextField( value )
+			Local view:=New TextFieldExt( value )
 			
 			view.TextChanged+=Lambda()
 				value=view.Text

+ 7 - 6
dialog/FindDialog.monkey2

@@ -6,21 +6,22 @@ Class FindDialog Extends DialogExt
 
 	Method New( actions:FindActions )
 	
-		_findField=New TextField
+		_findField=New TextFieldExt
 		
-		_replaceField=New TextField
+		_replaceField=New TextFieldExt
 		
 		_findField.Entered+=Lambda()
 			actions.findNext.Trigger()
 		End
 		_findField.TextChanged+=Lambda(  )
-			
+			#Rem
 			Local t:=_findField.Text
 			If t.Length > 1
-				If Not Prefs.SiblyMode			
+				If Not Prefs.SiblyMode
 					actions.FindByTextChanged( EntireProject )
 				Endif
 			Endif
+			#End
 		End
 
 		_findField.Tabbed+=_replaceField.MakeKeyView
@@ -102,8 +103,8 @@ Endif
 	
 	Private
 	
-	Field _findField:TextField
-	Field _replaceField:TextField
+	Field _findField:TextFieldExt
+	Field _replaceField:TextFieldExt
 	Field _caseSensitive:CheckButton
 	Field _entireProject:CheckButton
 

+ 14 - 8
dialog/FindInFilesDialog.monkey2

@@ -6,27 +6,27 @@ Class FindInFilesDialog Extends DialogExt
 	
 	Method New( actions:FindActions,projView:ProjectView )
 		
-		_findField=New TextField
+		_findField=New TextFieldExt
 		
 		_findField.Entered+=Lambda()
 			actions.findNext.Trigger()
 		End
 		
 		_projList=New ListView
-		_projList.MaxSize=New Vec2i( 500,120 )
-		_filterField=New TextField( Prefs.FindFilesFilter )
+		_projList.MaxSize=New Vec2i( 400,120 )
+		_filterField=New TextFieldExt( Prefs.FindFilesFilter )
 		
 		_caseSensitive=New CheckButton( "Case sensitive" )
 		_caseSensitive.Layout="float"
 		
-		Local table:=New TableView( 2,3 )
+		Local table:=New TableView( 2,4 )
 		table[0,0]=New Label( "Find" )
 		table[1,0]=_findField
 		table[0,1]=New Label( "Where" )
 		table[1,1]=_projList
 		table[0,2]=New Label( "Filter" )
 		table[1,2]=_filterField
-		table.Layout="float"
+		table[0,3]=New SpacerView( 0,8 )
 		
 		_docker=New DockingView
 		_docker.AddView( table,"top" )
@@ -35,7 +35,7 @@ Class FindInFilesDialog Extends DialogExt
 		
 		Title="Find in files"
 		
-		_docker.MinSize=New Vec2i( 512,200 )
+		_docker.MinSize=New Vec2i( 440,230 )
 		
 		ContentView=_docker
 		
@@ -66,6 +66,7 @@ Class FindInFilesDialog Extends DialogExt
 			For Local p:=Eachin projs
 				Local it:=_projList.AddItem( p )
 				If Not sel Then sel=it
+				If p=_selProj Then sel=it
 			Next
 			_projList.Selected=sel
 			
@@ -112,14 +113,19 @@ Class FindInFilesDialog Extends DialogExt
 		_findField.SelectAll()
 	End
 	
+	Method SetSelectedProject( proj:String )
+	
+		_selProj=proj
+	End
 	
 	Private
 	
-	Field _findField:TextField
-	Field _filterField:TextField
+	Field _findField:TextFieldExt
+	Field _filterField:TextFieldExt
 	Field _caseSensitive:CheckButton
 	Field _projList:ListView
 	Field _docker:DockingView
 	Field _customFolder:String
+	Field _selProj:String
 	
 End

+ 30 - 23
dialog/PrefsDialog.monkey2

@@ -47,7 +47,8 @@ Class PrefsDialog Extends DialogExt
 		
 		Deactivated+=MainWindow.UpdateKeyView
 		
-		MinSize=New Vec2i( 300,500 )
+		MinSize=New Vec2i( 550,500 )
+		MaxSize=New Vec2i( 550,600 )
 	End
 	
 	
@@ -61,28 +62,29 @@ Class PrefsDialog Extends DialogExt
 	Field _acUseDot:CheckButton
 	Field _acNewLineByEnter:CheckButton
 	Field _acKeywordsOnly:CheckButton
-	Field _acShowAfter:TextField
+	Field _acShowAfter:TextFieldExt
 	Field _acUseLiveTemplates:CheckButton
 	
 	Field _editorToolBarVisible:CheckButton
 	Field _editorGutterVisible:CheckButton
 	Field _editorShowWhiteSpaces:CheckButton
-	Field _editorFontPath:TextField
-	Field _editorFontSize:TextField
+	Field _editorFontPath:TextFieldExt
+	Field _editorFontSize:TextFieldExt
 	Field _editorShowEvery10LineNumber:CheckButton
 	Field _editorCodeMapVisible:CheckButton
 	Field _editorAutoIndent:CheckButton
+	Field _editorAutoPairs:CheckButton
+	Field _editorSurround:CheckButton
 	
 	Field _mainToolBarVisible:CheckButton
-	Field _mainProjectTabsRight:CheckButton
 	Field _mainProjectIcons:CheckButton
 	
-	Field _monkeyRootPath:TextField
+	Field _monkeyRootPath:TextFieldExt
 	
-	Field _chatNick:TextField
-	Field _chatServer:TextField
-	Field _chatPort:TextField
-	Field _chatRooms:TextField
+	Field _chatNick:TextFieldExt
+	Field _chatServer:TextFieldExt
+	Field _chatPort:TextFieldExt
+	Field _chatRooms:TextFieldExt
 	Field _chatAutoConnect:CheckButton
 	
 	Field _codeView:Ted2CodeTextView
@@ -113,9 +115,10 @@ Class PrefsDialog Extends DialogExt
 		Prefs.EditorShowEvery10LineNumber=_editorShowEvery10LineNumber.Checked
 		Prefs.EditorCodeMapVisible=_editorCodeMapVisible.Checked
 		Prefs.EditorAutoIndent=_editorAutoIndent.Checked
+		Prefs.EditorAutoPairs=_editorAutoPairs.Checked
+		Prefs.EditorSurroundSelection=_editorSurround.Checked
 		
 		Prefs.MainToolBarVisible=_mainToolBarVisible.Checked
-		Prefs.MainProjectTabsRight=_mainProjectTabsRight.Checked
 		Prefs.MainProjectIcons=_mainProjectIcons.Checked
 		
 		Prefs.IrcNickname=_chatNick.Text
@@ -139,13 +142,10 @@ Class PrefsDialog Extends DialogExt
 		_mainToolBarVisible=New CheckButton( "ToolBar visible" )
 		_mainToolBarVisible.Checked=Prefs.MainToolBarVisible
 		
-		_mainProjectTabsRight=New CheckButton( "Project tabs on the right side" )
-		_mainProjectTabsRight.Checked=Prefs.MainProjectTabsRight
-		
 		_mainProjectIcons=New CheckButton( "Project file type icons" )
 		_mainProjectIcons.Checked=Prefs.MainProjectIcons
 		
-		_monkeyRootPath=New TextField( Prefs.MonkeyRootPath )
+		_monkeyRootPath=New TextFieldExt( Prefs.MonkeyRootPath )
 		_monkeyRootPath.Enabled=False
 		Local chooseMonkeyPath:=New Action( "..." )
 		chooseMonkeyPath.Triggered+=Lambda()
@@ -180,7 +180,6 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( monkeyPathDock,"top" )
 		
 		docker.AddView( New Label( " " ),"top" )
-		docker.AddView( _mainProjectTabsRight,"top" )
 		docker.AddView( _mainProjectIcons,"top" )
 		docker.AddView( _mainToolBarVisible,"top" )
 		docker.AddView( New Label( " " ),"top" )
@@ -208,15 +207,21 @@ Class PrefsDialog Extends DialogExt
 		_editorAutoIndent=New CheckButton( "Auto indentation" )
 		_editorAutoIndent.Checked=Prefs.EditorAutoIndent
 		
+		_editorAutoPairs=New CheckButton( "Auto pair quotes and brackets: ~q~q, (), []" )
+		_editorAutoPairs.Checked=Prefs.EditorAutoPairs
+		
+		_editorSurround=New CheckButton( "Surround selected text with ~q~q, (), []" )
+		_editorSurround.Checked=Prefs.EditorSurroundSelection
+		
 		Local path:=Prefs.EditorFontPath
 		If Not path Then path=_defaultFont
-		_editorFontPath=New TextField( "" )
+		_editorFontPath=New TextFieldExt( "" )
 		_editorFontPath.TextChanged+=Lambda()
 		
 			Local enabled:=(_editorFontPath.Text<>_defaultFont)
 			_editorFontSize.Enabled=enabled
 		End
-		_editorFontSize=New TextField( ""+Prefs.EditorFontSize )
+		_editorFontSize=New TextFieldExt( ""+Prefs.EditorFontSize )
 		_editorFontPath.Text=path
 		_editorFontPath.ReadOnly=True
 		
@@ -258,6 +263,8 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( _editorShowEvery10LineNumber,"top" )
 		docker.AddView( _editorCodeMapVisible,"top" )
 		docker.AddView( _editorAutoIndent,"top" )
+		docker.AddView( _editorAutoPairs,"top" )
+		docker.AddView( _editorSurround,"top" )
 		docker.AddView( New Label( " " ),"top" )
 		
 		Return docker
@@ -265,7 +272,7 @@ Class PrefsDialog Extends DialogExt
 	
 	Method GetCompletionDock:DockingView()
 		
-		_acShowAfter=New TextField( ""+Prefs.AcShowAfter )
+		_acShowAfter=New TextFieldExt( ""+Prefs.AcShowAfter )
 		
 		Local after:=New DockingView
 		after.AddView( New Label( "Show after" ),"left" )
@@ -314,10 +321,10 @@ Class PrefsDialog Extends DialogExt
 	Method GetChatDock:DockingView()
 		
 		Local chatTable:=New TableView( 2,6 )
-		_chatNick=New TextField( Prefs.IrcNickname )
-		_chatServer=New TextField( Prefs.IrcServer )
-		_chatPort=New TextField( ""+Prefs.IrcPort )
-		_chatRooms=New TextField( Prefs.IrcRooms )
+		_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" )

+ 2 - 0
dialog/UpdateModulesDialog.monkey2

@@ -112,6 +112,8 @@ Class UpdateModulesDialog Extends DialogExt
 		
 		ContentView=dock
 		
+		SetKeyAction( Key.Enter,actUpdate )
+		SetKeyAction( Key.Escape,actCancel )
 	End
 	
 	Property SelectedModules:String()

+ 123 - 58
document/CodeDocument.monkey2

@@ -35,8 +35,6 @@ Class CodeDocumentView Extends Ted2CodeTextView
 	
 		_doc=doc
 		
-		Document=_doc.TextDocument
-		
 		ContentView.Style.Border=New Recti( -4,-4,4,4 )
 		
 		'very important to set FileType for init
@@ -62,7 +60,16 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Local bySpace:=result.bySpace
 					
 					text=_doc.PrepareForInsert( ident,text,Not bySpace,LineTextAtCursor,PosInLineAtCursor,item )
-					SelectText( Cursor,Cursor-AutoComplete.LastIdentPart.Length )
+					Local i1:=Cursor-AutoComplete.LastIdentPart.Length
+					Local i2:=Cursor
+					If result.byTab
+						Local i:=Cursor
+						While i<Text.Length And IsIdent( Text[i] )
+							i+=1
+						Wend
+						i2=i
+					Endif
+					SelectText( i1,i2 )
 					ReplaceText( text )
 				Endif
 			Endif
@@ -190,7 +197,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			Select key
 			
 				Case Key.Space
-					If event.Modifiers & Modifier.Control
+					If ctrl
 						Return
 					'Else
 					'	if AutoComplete.IsOpened And Prefs.AcUseSpace Return
@@ -199,6 +206,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				Case Key.Backspace
 					
 					If AutoComplete.IsOpened
+						
 						Local ident:=IdentBeforeCursor()
 						ident=ident.Slice( 0,ident.Length-1 )
 						If ident.Length > 0
@@ -329,16 +337,16 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Return
 			
 				#If __TARGET__="macos"
-				Case Key.Left 'smart Home behaviour
+				Case Key.A 'smart Home behaviour
 			
-					If event.Modifiers & Modifier.Menu
+					If ctrl
 						SmartHome( shift )
 						Return
 					Endif
 			
-				Case Key.Right
+				Case Key.E
 			
-					If event.Modifiers & Modifier.Menu
+					If ctrl
 						SmartEnd( shift )
 						Return
 					Endif
@@ -476,39 +484,8 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Endif
 			
 			
-				Case Key.Insert
-			
-					If CanPaste And shift
-						SmartPaste()
-						Return
-					Endif
-			
-				Case Key.KeyDelete
-			
-					If shift
-						OnCut()
-						Return
-					Endif
-			
 				#If __TARGET__="macos"
-				'smart Home behaviour
-				Case Key.Left
-			
-					If event.Modifiers & Modifier.Menu
-						SmartHome( True )
-			
-						Return
-					Endif
-			
-			
-				Case Key.Right
-			
-					If event.Modifiers & Modifier.Menu
-						SmartHome( False )
-			
-						Return
-					Endif
-			
+				
 				Case Key.Z
 			
 					If event.Modifiers & Modifier.Menu
@@ -525,10 +502,10 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 			End
 			
-				
+			
 		Case EventType.KeyChar
 			
-			If event.Key = Key.Space And event.Modifiers & Modifier.Control
+			If event.Key = Key.Space And ctrl
 				If _doc.CanShowAutocomplete()
 					Local ident:=IdentBeforeCursor()
 					If ident Then _doc.ShowAutocomplete( ident,True )
@@ -536,6 +513,89 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				Return
 			Endif
 			
+			If CanCopy And Prefs.EditorSurroundSelection
+				' surround selection 
+				Local txt:=event.Text
+				
+				Local k1:=(txt="~q")
+				Local k2:=(txt="(")
+				Local k3:=(txt="[")
+				
+				If k1 Or k2 Or k3
+					Local ins:=k1 ? "~q" Else (k2 ? ")" Else "]")
+					Local i1:=Min( Anchor,Cursor )
+					Local i2:=Max( Anchor,Cursor )
+					ReplaceText( txt + Text.Slice( i1,i2 ) + ins )
+					Return
+				Endif
+				
+			Endif
+			
+			' try to auto-pair chars
+			If Prefs.EditorAutoPairs
+				
+				Local txt:=event.Text
+				
+				Local k1:=(txt="~q")
+				Local k2:=(txt="(")
+				Local k3:=(txt="[")
+				Local k21:=(txt=")")
+				Local k31:=(txt="]")
+				
+				If k1 Or k2 Or k3 Or k21 Or k31
+					
+					Local s:=LineTextAtCursor
+					Local p:=PosInLineAtAnchor
+					
+					' skip if this char is already right after cursor
+					If p<s.Length
+						If (k1 And s[p]=Chars.DOUBLE_QUOTE) Or (k21 And s[p]=Chars.CLOSED_ROUND_BRACKET) Or (k31 And s[p]=Chars.CLOSED_SQUARE_BRACKET)
+							SelectText( Cursor+1,Cursor+1 )
+							Return
+						Endif
+					Endif
+					
+					' just insert our char
+					ReplaceText( txt )
+					
+					If k21 Or k31 Return
+					
+					Local skip:=False
+					If k1
+						skip=_doc.Parser.IsPosInsideOfQuotes( s,p )
+					ElseIf k2
+						'skip=p<s.Length And s[p]=Chars.CLOSED_ROUND_BRACKET
+						skip=Not IsCursorAtTheEndOfLine
+					Elseif k3
+						skip=p<s.Length And s[p]=Chars.CLOSED_SQUARE_BRACKET
+					Endif
+					If Not skip ' auto-pair it
+						Local ins:=k1 ? "~q" Else (k2 ? ")" Else "]")
+						ReplaceText( ins )
+						SelectText( Cursor-1,Cursor-1 )
+					Endif
+					
+					Return
+					
+				Else
+'					
+'					
+'					Local skip:=False
+'					If k21
+'						skip=p<s.Length And s[p]=Chars.CLOSED_ROUND_BRACKET
+'					If k3
+'						skip=p<s.Length And s[p]=Chars.CLOSED_SQUARE_BRACKET
+'					Endif
+'					If Not skip ' auto-pair it
+'						Local ins:=k1 ? "~q" Else (k2 ? ")" Else "]")
+'						ReplaceText( ins )
+'						SelectText( Cursor-1,Cursor-1 )
+'					Endif
+					
+				Endif
+			
+			Endif
+			
 		End
 		
 		Super.OnKeyEvent( event )
@@ -579,7 +639,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 		Endif
 		
 		' text overwrite mode
-		If event.Key=Key.Insert And Not (shift Or ctrl Or alt)
+		If event.Type=EventType.KeyDown And event.Key=Key.Insert And Not (shift Or ctrl Or alt)
 			
 			MainWindow.OverwriteTextMode=Not MainWindow.OverwriteTextMode
 		Endif
@@ -703,8 +763,11 @@ Class CodeDocumentView Extends Ted2CodeTextView
 	Method DeleteLineAtCursor()
 		
 		Local line:=Document.FindLine( Cursor )
+		Local pos:=Cursor
 		SelectText( Document.StartOfLine( line ),Document.EndOfLine( line )+1 )
 		ReplaceText( "" )
+		pos=Min( pos,Document.EndOfLine( line ) )
+		SelectText( pos,pos )
 	End
 	
 End
@@ -716,7 +779,13 @@ Class CodeDocument Extends Ted2Document
 		
 		Super.New( path )
 	
-		_doc=New TextDocument
+		_view=New DockingView
+		
+		' Editor
+		_codeView=New CodeDocumentView( Self )
+		_codeView.LineChanged += OnLineChanged
+		
+		_doc=_codeView.Document
 		
 		_doc.LinesModified+=Lambda( first:Int,removed:Int,inserted:Int )
 		
@@ -734,18 +803,12 @@ Class CodeDocument Extends Ted2Document
 				put+=1
 			Next
 			_errors.Resize( put )
-			
+		
 			' also move debug line
 			If _debugLine>=first
 				_debugLine+=(inserted-removed)
 			Endif
 		End
-
-		_view=New DockingView
-		
-		' Editor
-		_codeView=New CodeDocumentView( Self )
-		_codeView.LineChanged += OnLineChanged
 		
 		_doc.TextChanged+=Lambda()
 			Dirty=True
@@ -1003,12 +1066,11 @@ Class CodeDocument Extends Ted2Document
 	
 	Method GotoDeclaration()
 	
-		Local ident:=_codeView.FullIdentAtCursor()
+		Local ident:=_codeView.FullIdentAtCursor
 		Local line:=TextDocument.FindLine( _codeView.Cursor )
 		Local item:=_parser.ItemAtScope( ident,Path,line )
-		Print "go decl: "+ident
+		
 		If item
-			Print "item found"
 			Local pos:=item.ScopeStartPos
 			JumpToPosition( item.FilePath,pos )
 		Endif
@@ -1017,7 +1079,10 @@ Class CodeDocument Extends Ted2Document
 	Method JumpToPosition( filePath:String,pos:Vec2i )
 		
 		Local cur:=_codeView.CursorPos
-		If pos=cur Return
+		If pos=cur
+			_codeView.MakeKeyView()
+			Return
+		Endif
 		
 		' store navOp
 		Local nav:=New NavCode
@@ -1104,13 +1169,13 @@ Class CodeDocument Extends Ted2Document
 	
 	Method Comment()
 	
-		Local event:=New KeyEvent( EventType.KeyDown,_codeView,Key.Apostrophe,Key.Apostrophe,Modifier.Control,"" )
+		Local event:=New KeyEvent( EventType.KeyChar,_codeView,Key.Apostrophe,Key.Apostrophe,Modifier.Control,"'" )
 		_codeView.OnKeyEvent( event )
 	End
 	
 	Method Uncomment()
 	
-		Local event:=New KeyEvent( EventType.KeyDown,_codeView,Key.Apostrophe,Key.Apostrophe,Modifier.Control|Modifier.Shift,"" )
+		Local event:=New KeyEvent( EventType.KeyChar,_codeView,Key.Apostrophe,Key.Apostrophe,Modifier.Control|Modifier.Shift,"'" )
 		_codeView.OnKeyEvent( event )
 	End
 	
@@ -1336,7 +1401,7 @@ Class CodeDocument Extends Ted2Document
 		
 		If _timer _timer.Cancel()
 		
-		_timer=New Timer( 1,Lambda()
+		_timer=New Timer( 0.5,Lambda()
 		
 			If _parsing Return
 			

+ 32 - 7
document/DocumentManager.monkey2

@@ -11,6 +11,7 @@ Class DocumentManager
 	
 	Field DocumentAdded:Void( doc:Ted2Document )
 	Field DocumentRemoved:Void( doc:Ted2Document )
+	Field DocumentDoubleClicked:Void( doc:Ted2Document )
 
 	Method New( tabView:TabViewExt,browser:DockingView )
 	
@@ -111,7 +112,10 @@ Class DocumentManager
 		InitDoc( doc )
 	
 		_openDocs.Add( doc )
-		_tabView.AddTab( TabText( doc ),doc.View )
+		Local tab:=_tabView.AddTab( TabText( doc ),doc.View )
+		tab.DoubleClicked+=Lambda()
+			DocumentDoubleClicked( doc )
+		End
 		
 		DocumentAdded( doc )
 		
@@ -183,11 +187,24 @@ Class DocumentManager
 		Return Null
 	End
 	
+	Method FindTab:TabButtonExt( view:View )
+		
+		For Local t:=Eachin _tabView.Tabs
+			If t.View=view Return t
+		Next
+		Return Null
+	End
+	
 	Method SaveState( jobj:JsonObject )
 		
 		Local docs:=New JsonArray
 		For Local doc:=Eachin _openDocs
-			docs.Add( New JsonString( doc.Path ) )
+			Local s:=doc.Path
+			Local tv:=doc.TextView
+			If tv And (tv.Cursor>0 Or tv.Anchor>0)
+				s+=",,,"+tv.Cursor+",,,"+tv.Anchor
+			Endif
+			docs.Add( New JsonString( s ) )
 		Next
 		jobj["openDocuments"]=docs
 		
@@ -195,16 +212,24 @@ Class DocumentManager
 	End
 		
 	Method LoadState( jobj:JsonObject )
-		
+		 
 		If Not jobj.Contains( "openDocuments" ) Return
 		
 		For Local doc:=Eachin jobj.GetArray( "openDocuments" )
-		
-			Local path:=doc.ToString()
+			
+			Local arr:=doc.ToString().Split( ",,," )
+			Local path:=arr[0]
 			If GetFileType( path )<>FileType.File Continue
 			
-			Local tdoc:=OpenDocument( doc.ToString() )
-			If tdoc And MainWindow.IsTmpPath( path ) tdoc.Dirty=True
+			Local tdoc:=OpenDocument( path,True )
+			If tdoc
+				tdoc.Dirty=MainWindow.IsTmpPath( path )
+				If arr.Length>1
+					Local cursor:=Int( arr[1] )
+					Local anchor:=Int( arr[2] )
+					tdoc.TextView.SelectText( anchor,cursor,True )
+				Endif
+			Endif
 		Next
 		
 		Local path:=jobj.GetString( "currentDocument" )

+ 0 - 2
document/SceneDocument.monkey2

@@ -144,8 +144,6 @@ Class SceneDocument Extends Ted2Document
 		
 		If _model _model.Destroy()
 		
-		Print "Loading model:"+Path
-
 		Scene.SetCurrent( _scene )
 		
 		_model=Model.Load( Path )

+ 53 - 14
eventfilter/Monkey2KeyEventFilter.monkey2

@@ -23,7 +23,11 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 				
 				Case Key.F1
 					
-					MainWindow.ShowQuickHelp()
+					If ctrl
+						MainWindow.ShowFindInDocs()
+					Else
+						MainWindow.ShowQuickHelp()
+					Endif
 					event.Eat()
 					
 				Case Key.F2
@@ -31,20 +35,31 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 					MainWindow.GotoDeclaration()
 					event.Eat()
 				
+			End
+			
+			
+		Case EventType.KeyChar
+			
+			Select event.Key
+				
 				Case Key.Apostrophe 'ctrl+' - comment / uncomment block
 				
 					If  shift And ctrl 'uncomment
-						
-						OnCommentUncommentBlock( textView,False )
+				
+						OnCommentUncommentBlock( textView,CommentType.Uncomment )
 						event.Eat()
-						
+				
 					Elseif ctrl 'comment
-					
-						OnCommentUncommentBlock( textView,True )
+				
+						OnCommentUncommentBlock( textView,CommentType.Comment )
 						event.Eat()
-						
-					End
 				
+					Elseif textView.CanCopy 'try to com/uncom selection
+				
+						OnCommentUncommentBlock( textView,CommentType.Inverse )
+						event.Eat()
+				
+					End
 			End
 			
 		End
@@ -61,13 +76,28 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 	 
 	Global _instance:=New Monkey2KeyEventFilter
 
-	Method OnCommentUncommentBlock( textView:TextView,comment:Bool )
+	Method OnCommentUncommentBlock( tv:TextView,type:CommentType )
 		
-		Local doc:=textView.Document
-		Local i1:=Min( textView.Cursor,textView.Anchor )
-		Local i2:=Max( textView.Cursor,textView.Anchor )
+		Local doc:=tv.Document
+		Local i1:=Min( tv.Cursor,tv.Anchor )
+		Local i2:=Max( tv.Cursor,tv.Anchor )
 		Local line1:=doc.FindLine( i1 )
 		Local line2:=doc.FindLine( i2 )
+		
+		If type=CommentType.Inverse
+			Local allCommented:=True
+			For Local line:=line1 To line2
+				Local s:= doc.GetLine( line )
+				If s.Trim()="" Continue
+				If Not s.StartsWith( "'" )
+					allCommented=False
+					Exit
+				Endif
+			Next
+			type=allCommented ? CommentType.Uncomment Else CommentType.Comment
+		Endif
+		
+		Local comment:=(type=CommentType.Comment)
 		Local result:=""
 		Local made:=False
 		For Local line:=line1 To line2
@@ -86,9 +116,18 @@ Class Monkey2KeyEventFilter Extends TextViewKeyEventFilter
 		If made
 			i1=doc.StartOfLine( line1 )
 			i2=doc.EndOfLine( line2 )
-			textView.SelectText( i1,i2 )
-			textView.ReplaceText( result )
+			tv.SelectText( i1,i2 )
+			tv.ReplaceText( result )
+			' select commented / uncommented lines
+			tv.SelectText( i1,i1+result.Length )
 		Endif
 	End
 	
+	
+	Enum CommentType
+		Comment,
+		Uncomment,
+		Inverse
+	End
+	
 End

+ 61 - 11
parser/CodeItem.monkey2

@@ -2,6 +2,36 @@
 Namespace ted2go
 
 
+Enum CodeItemKind
+	Undefine_,
+	Class_,
+	Interface_,
+	Enum_,
+	EnumMember_,
+	Struct_,
+	Field_,
+	Global_,
+	Const_,
+	Method_,
+	Function_,
+	Property_,
+	Param_,
+	Lambda_,
+	Local_,
+	Operator_,
+	Inner_,
+	Alias_,
+	Inherited_
+End
+
+
+Enum AccessMode
+	Private_,
+	Protected_,
+	Public_
+End
+
+
 Class CodeItem
 	
 	Method New( ident:String )
@@ -87,9 +117,9 @@ Class CodeItem
 		
 	End
 	
-	Property Children:List<CodeItem>()
+	Property Children:Stack<CodeItem>()
 		Return _children
-	Setter( value:List<CodeItem> )
+	Setter( value:Stack<CodeItem> )
 		_children=value
 	End
 	
@@ -152,10 +182,11 @@ Class CodeItem
 	End
 	
 	Method SetParent( parent:CodeItem )
-		If Parent <> Null Then Parent.Children.Remove( Self )
+		
+		If Parent Then Parent.Children.Remove( Self )
 		_parent=parent
-		If _parent.Children = Null Then _parent.Children = New List<CodeItem>
-		_parent.Children.AddLast( Self )
+		If Not _parent.Children Then _parent.Children = New Stack<CodeItem>
+		_parent.Children.Add( Self )
 	End
 	
 	Method AddChild( item:CodeItem )
@@ -188,6 +219,12 @@ Class CodeItem
 		Return False
 	End
 	
+	Property IsExtension:Bool()
+		Return _isExtension
+	Setter( value:Bool )
+		_isExtension=value
+	End
+	
 	Method AddSuperType( type:CodeType )
 		If Not _superTypes Then _superTypes=New List<CodeType>
 		_superTypes.AddLast( type )
@@ -261,7 +298,7 @@ Class CodeItem
 	Field _access:=AccessMode.Public_
 	Field _text:String
 	Field _parent:CodeItem
-	Field _children:List<CodeItem>
+	Field _children:Stack<CodeItem>
 	Field _namespace:String
 	Field _filePath:String
 	Field _scopeStartPos:Vec2i=New Vec2i,_scopeEndPos:Vec2i=New Vec2i
@@ -269,6 +306,7 @@ Class CodeItem
 	Field _params:CodeParam[]
 	Field _paramsStr:String
 	Field _isModuleMember:=-1
+	Field _isExtension:Bool
 	
 	
 	Private
@@ -289,8 +327,11 @@ Class CodeItem
 					s+="()"
 				Endif
 		
-			Case CodeItemKind.Class_,CodeItemKind.Interface_,CodeItemKind.Struct_,CodeItemKind.Enum_
-				' nothing
+			Case CodeItemKind.Class_,CodeItemKind.Interface_,CodeItemKind.Struct_,CodeItemKind.Enum_,CodeItemKind.Alias_
+				
+				If _isExtension
+					s+=" (ext)"
+				Endif
 		
 			Case CodeItemKind.Inner_,CodeItemKind.EnumMember_
 				' nothing
@@ -452,7 +493,7 @@ End
 Struct CodeItemsSorter Final
 	
 	
-	Function SortByType( list:List<CodeItem>,inverse:Bool=False,checkIdent:Bool=False )
+	Function SortByType( list:Stack<CodeItem>,inverse:Bool=False,checkIdent:Bool=False )
 		
 		_checkIdent=checkIdent
 		
@@ -475,7 +516,7 @@ Struct CodeItemsSorter Final
 		list.Sort( _sorterByType )
 	End
 	
-	Function SortByPosition( list:List<CodeItem> )
+	Function SortByPosition( list:Stack<CodeItem> )
 	
 		If _sorterByPosition = Null
 			_sorterByPosition=Lambda:Int( lhs:CodeItem,rhs:CodeItem )
@@ -521,6 +562,8 @@ Struct CodeItemsSorter Final
 		Local len:=etalon.Length
 		Local power:=0
 		Local ch:=etalon[0],index:=0
+		Local eqFirstChar:=False
+		
 		For Local i:=0 Until ident.Length
 			Local s:=ident.Slice( i,i+1 )
 			Local eq1:=(s[0]=ch)
@@ -532,6 +575,7 @@ Struct CodeItemsSorter Final
 				index+=1
 				ch = index>=len ? -1 Else etalon[index]
 				If ch=-1 Exit
+				If i=0 Then eqFirstChar=True
 			Endif
 		Next
 		
@@ -539,7 +583,13 @@ Struct CodeItemsSorter Final
 		If Prefs.AcStrongFirstChar
 			Local lower1:=IsLowercacedFirstChar( ident )
 			Local lower2:=IsLowercacedFirstChar( etalon )
-			If lower1 <> lower2 Then power-=10000
+			If lower1 <> lower2 ' if first chars cases aren't equals
+				If Not eqFirstChar ' and letters are different
+					power-=10000
+				Else
+					power-=100
+				Endif
+			Endif
 		End
 		
 		Return power

+ 275 - 204
parser/Monkey2Parser.monkey2

@@ -139,16 +139,16 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		RemovePrevious( filePath )
 
-		Local json:=str.Slice( i )		
+		Local json:=str.Slice( i )
 		Local jobj:=JsonObject.Parse( json )
 		
 		Local nspace:= jobj.Contains( "namespace" ) ? jobj["namespace"].ToString() Else ""
 		
 		
 		If jobj.Contains( "members" )
-			Local items:=New List<CodeItem>
+			Local items:=New Stack<CodeItem>
 			Local members:=jobj["members"].ToArray()
-			ParseJsonMembers( members,Null,filePath,items )
+			ParseJsonMembers( members,Null,filePath,items,nspace )
 			ItemsMap[filePath]=items
 			Items.AddAll( items )
 			
@@ -195,7 +195,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return Null
 	End
 		
-	Method ParseJsonMembers( members:Stack<JsonValue>,parent:CodeItem,filePath:String,resultContainer:List<CodeItem> )
+	Method ParseJsonMembers( members:Stack<JsonValue>,parent:CodeItem,filePath:String,resultContainer:Stack<CodeItem>,namespac:String )
 		
 		For Local val:=Eachin members
 		
@@ -226,6 +226,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 			item.ScopeStartPos=New Vec2i( Int(arr[0])-1,Int(arr[1]) )
 			arr=endPos.Split( ":" )
 			item.ScopeEndPos=New Vec2i( Int(arr[0])-1,Int(arr[1]) )
+			item.Namespac=namespac
 			
 			'Print "parser. add item: "+item.Scope+" "+kind
 			
@@ -233,6 +234,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Local t:=New CodeType
 				t.kind=kind
 				t.ident=ident
+				
+				item.IsExtension=IsExtension( flags )
 			Else
 				Local t:=ParseType( jobj )
 				item.Type=t
@@ -275,15 +278,21 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Next
 			Endif
 			
+			
 			If parent
 				item.SetParent( parent )
+				If parent.IsExtension
+					AddExtensionItem( parent,item )
+				Endif
 			Else
-				resultContainer.Add( item )
+				If Not item.IsExtension
+					resultContainer.Add( item )
+				Endif
 			Endif
 			
 			If jobj.Contains( "members" )
 				Local memb:=jobj["members"].ToArray()
-				ParseJsonMembers( memb,item,filePath,resultContainer )
+				ParseJsonMembers( memb,item,filePath,resultContainer,namespac )
 			Endif
 			
 		Next
@@ -305,6 +314,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		If Not items Return Null
 		
+		' all classes / structs
 		Local result:CodeItem=Null
 		For Local i:=Eachin items
 			If docLine > i.ScopeStartPos.x And docLine < i.ScopeEndPos.x
@@ -312,149 +322,38 @@ Class Monkey2Parser Extends CodeParserPlugin
 				Exit
 			Endif
 		Next
-		If result <> Null
+		
+		If result
+			' try to check is we inside of method/ property / etc
 			Repeat
 				Local i:=GetInnerScope( result,docLine )
 				If i = Null Exit
 				result=i
 			Forever
+			
+		Else
+			' try to find in extension members
+			For Local list:=Eachin ExtraItemsMap.Values.All()
+				For Local i:=Eachin list
+					If i.FilePath<>docPath Continue
+					If docLine > i.ScopeStartPos.x And docLine < i.ScopeEndPos.x
+						result=i
+						Exit
+					Endif
+				Next
+				If result Exit
+			Next
 		End
+		
 		Return result
 		
 	End
 	
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
-	
-		Local idents:=ident.Split( "." )
-	
-		' using lowerCase for keywords
-		Local lastIdent:=idents[idents.Length-1].ToLower()
-		Local onlyOne:=(idents.Length=1)
-	
-		'check current scope
-		Local rootScope:=GetScope( filePath,docLine )
-		Local scope:=rootScope
-			
-		'-----------------------------
-		' what the first ident is?	
-		'-----------------------------
-		Local firstIdent:=idents[0]
-		Local item:CodeItem=Null
-		Local isSelf:=(firstIdent.ToLower()="self")
-		Local isSuper:=(firstIdent.ToLower()="super")
-		Local items:=New List<CodeItem>
-	
-		If isSelf Or isSuper
-	
-			item=scope.NearestClassScope
-	
-		Else ' not 'self' ident
-	
-			' check in 'this' scope
-			While scope <> Null
-	
-				GetAllItems( scope,items )
-	
-				If Not items.Empty
-					For Local i:=Eachin items
-						If i.Ident <> firstIdent Continue
-						If Not CheckAccessInScope( i,scope ) Continue
-						' additional checking for the first ident
-						If IsLocalMember( i ) And i.ScopeStartPos.x > docLine Continue
-						If Not onlyOne
-							item=i
-							Exit
-						Else
-							Return i
-						Endif
-					Next
-				Endif
-				'found item
-				If item <> Null Exit
-	
-				scope=scope.Parent 'if inside of func then go to class' scope
-	
-			Wend
-	
-		Endif
-	
-		' and check in global scope
-		If item = Null Or onlyOne
-			For Local i:=Eachin Items
-				If i.Ident <> firstIdent Continue
-				If Not onlyOne
-					item=i
-					Exit
-				Else
-					Return i
-				Endif
-			Next
-		Endif
-	
-		'If item Print "item: "+item.Scope
-	
-		' var1.var2.var3...
-		If Not onlyOne And item <> Null
-	
-			Local scopeClass:=(rootScope <> Null) ? rootScope.NearestClassScope Else Null
-			Local forceProtected:=(isSelf Or isSuper)
-	
-			' start from the second ident part here
-			For Local k:=1 Until idents.Length
-	
-				Local staticOnly:=(Not isSelf And Not isSuper And (item.Kind = CodeItemKind.Class_ Or item.Kind = CodeItemKind.Struct_))
-	
-				' need to check by ident type
-				Local type:=item.Type.ident
-	
-				Select item.Kind
-	
-					Case CodeItemKind.Class_,CodeItemKind.Struct_,CodeItemKind.Interface_,CodeItemKind.Enum_
-						' don't touch 'item'
-	
-					Default
-						item=Null
-						' is it alias?
-						Local al:=_aliases[type]
-						If al Then type=al.Type.ident
-						'
-						For Local i:=Eachin Items
-							If i.Ident = type
-								item=i
-								Exit
-							Endif
-						Next
-						If item = Null Then Exit
-				End
-	
-	
-				Local identPart:=idents[k]
-				Local last:=(k = idents.Length-1)
-	
-				' extract all items from item
-				items.Clear()
-				GetAllItems( item,items,isSuper )
-	
-				If Not items.Empty
-					For Local i:=Eachin items
-						If i.Ident <> identPart Continue
-						item=i
-						If last
-							If Not staticOnly Or IsStaticMember( i )
-								Return i
-							Endif
-						Else
-							Exit
-						Endif
-					Next
-				Endif
-	
-				If item = Null Then Exit
-			Next
-	
-		Endif
 		
-		Return Null
+		Local result:=New Stack<CodeItem>
+		GetItemsInternal( ident,filePath,docLine,result,_lastUsingsFilter,1 )
+		Return (Not result.Empty) ? result[0] Else Null
 	End
 	
 	Method RefineRawType( item:CodeItem )
@@ -468,40 +367,75 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return Null
 	End
 	
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:List<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
+		
+		GetItemsInternal( ident,filePath,docLine,target,usingsFilter,-1 )
+	End
+	
+	
+	Private
+	
+	Global _instance:=New Monkey2Parser
+	Field _filesTime:=New StringMap<Long>
+	Field _aliases:=New StringMap<CodeItem>
+	Field _modsPath:String,_mx2ccPath:String
+	Field _extensions:=New StringMap<Stack<CodeItem>>
+	Field _lastUsingsFilter:StringStack
+	
+	Method New()
+	
+		Super.New()
+		_types=New String[](".monkey2")
+	End
+	
+	Method GetItemsInternal( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null,resultLimit:Int=-1 )
+		
+		_lastUsingsFilter=usingsFilter
 		
 		Local idents:=ident.Split( "." )
-				
+	
 		' using lowerCase for keywords
 		Local lastIdent:=idents[idents.Length-1].ToLower()
 		Local onlyOne:=(idents.Length=1)
-		
+	
 		'check current scope
 		Local rootScope:=GetScope( filePath,docLine )
 		Local scope:=rootScope
 		
+		'If scope Print scope.Text
+		
 		'-----------------------------
-		' what the first ident is?	
+		' what the first ident is?
 		'-----------------------------
 		Local firstIdent:=idents[0]
 		Local item:CodeItem=Null
 		Local isSelf:=(firstIdent.ToLower()="self")
 		Local isSuper:=(firstIdent.ToLower()="super")
-		Local items:=New List<CodeItem>
+		Local items:=New Stack<CodeItem>
+		Local fullyMatched:CodeItem=Null
 		
-		If isSelf Or isSuper
+		'Print "idents: "+firstIdent+" - "+lastIdent
 		
+		If isSelf Or isSuper
+			
 			If scope Then item=scope.NearestClassScope
 			
 		Else ' not 'self' ident
+			Local staticOnly := (scope And scope.Kind=CodeItemKind.Function_)
 			
 			' check in 'this' scope
 			While scope <> Null
-	
+				
 				GetAllItems( scope,items )
 				
+				'If scope.Parent=Null
+				'	ExtractExtensionItems( scope,items )
+				'Endif
+				
 				If Not items.Empty
+					
 					For Local i:=Eachin items
+						'Print "item at scope: "+i.Text
 						If Not CheckIdent( i.Ident,firstIdent,onlyOne )
 							'Print "cont1: "+i.Ident
 							Continue
@@ -515,14 +449,33 @@ Class Monkey2Parser Extends CodeParserPlugin
 							'Print "cont3: "+i.Ident
 							Continue
 						Endif
+						If i=scope
+							'Print "cont4: "+i.Ident
+							Continue
+						Endif
 						If Not onlyOne
 							item=i
 							Exit
 						Else
-							'RefineRawType( i )
-							target.AddLast( i )
+							If Not staticOnly Or IsStaticMember( i,False )
+								'Print "if 4: "+i.Ident
+								target.Add( i )
+								If i.Ident=firstIdent Then fullyMatched=i
+								If fullyMatched And resultLimit>0 And target.Length=resultLimit Exit
+							Endif
 						Endif
 					Next
+					
+					If fullyMatched
+						If resultLimit>0 And target.Length>=resultLimit
+							target.Slice( 0,resultLimit )
+							target.Remove( fullyMatched )
+							target.Insert( 0,fullyMatched )
+							'Print "matched 1"
+							Return
+						Endif
+					Endif
+					
 				Endif
 				'found item
 				If item <> Null Exit
@@ -530,30 +483,73 @@ Class Monkey2Parser Extends CodeParserPlugin
 				scope=scope.Parent 'if inside of func then go to class' scope
 				
 			Wend
-		
+			
 		Endif
-		
+	
 		' and check in global scope
 		If item = Null Or onlyOne
-			For Local i:=Eachin Items
+			
+			item=_aliases[firstIdent]
+			If item
 				
-				If Not CheckUsingsFilter( i,usingsFilter ) Continue
+				If CheckUsingsFilter( item,usingsFilter )
+					target.Add( item )
+					If resultLimit>0 And target.Length=resultLimit Return
+				Endif
 				
-				'Print "global 1: "+i.Scope
-				If Not CheckIdent( i.Ident,firstIdent,onlyOne ) Continue
-				If Not CheckAccessInGlobal( i,filePath ) Continue
-				If IsLocalMember( i ) And i.ScopeStartPos.x > docLine Continue
-				'Print "global 2"
-				If Not onlyOne
-					item=i
-					Exit
-				Else
-					target.AddLast( i )
+			Else
+				
+				For Local i:=Eachin Items
+					
+					If Not CheckUsingsFilter( i,usingsFilter )
+						'Print "skip 1 "+i.Ident
+						Continue
+					Endif
+					
+					'Print "global 1: "+i.Scope
+					If Not CheckIdent( i.Ident,firstIdent,onlyOne )
+						'Print "skip 2 "+i.Ident
+						Continue
+					Endif
+					
+					If Not CheckAccessInGlobal( i,filePath )
+						'Print "skip 3 "+i.Ident
+						Continue
+					Endif
+					
+					If IsLocalMember( i ) And i.ScopeStartPos.x > docLine
+						'Print "skip 4 "+i.Ident
+						Continue
+					Endif
+					
+					'Print "global 2"
+					If Not onlyOne
+						item=i
+						Exit
+					Else
+						target.Add( i )
+						'Print "from globals: "+i.Ident
+						If i.Ident=firstIdent Then fullyMatched=i
+						If fullyMatched And resultLimit>0 And target.Length=resultLimit Exit
+					Endif
+				Next
+				
+				If fullyMatched
+					If resultLimit>0 And target.Length>=resultLimit
+						target.Slice( 0,resultLimit )
+						target.Remove( fullyMatched )
+						target.Insert( 0,fullyMatched )
+						'Print "matched 2"
+						Return
+					Endif
 				Endif
-			Next
+				
+			Endif
+			
 		Endif
 		
-		'If item Print "item: "+item.Scope
+		'If item Print "item: "+item.Scope+", kind: "+item.KindStr
+		'DebugStop()
 		
 		' var1.var2.var3...
 		If Not onlyOne And item <> Null
@@ -564,10 +560,11 @@ Class Monkey2Parser Extends CodeParserPlugin
 			' start from the second ident part here
 			For Local k:=1 Until idents.Length
 				
-				Local staticOnly:=(Not isSelf And Not isSuper And (item.Kind = CodeItemKind.Class_ Or item.Kind = CodeItemKind.Struct_))
+				Local staticOnly:=(Not isSelf And Not isSuper And (item.Kind = CodeItemKind.Class_ Or item.Kind = CodeItemKind.Struct_ Or item.Kind = CodeItemKind.Alias_))
 				
 				' need to check by ident type
 				Local type:=item.Type.ident
+				Local tmpItem:=item
 				
 				Select item.Kind
 					
@@ -575,10 +572,10 @@ Class Monkey2Parser Extends CodeParserPlugin
 						' don't touch 'item'
 					
 					Default
+						
 						item=Null
 						' is it alias?
-						Local al:=_aliases[type]
-						If al Then type=al.Type.ident
+						type=FixItemType( type )
 						'
 						For Local i:=Eachin Items
 							If i.Ident = type
@@ -589,16 +586,27 @@ Class Monkey2Parser Extends CodeParserPlugin
 						If item = Null Then Exit
 				End
 				
-				
 				Local identPart:=idents[k]
 				Local last:=(k = idents.Length-1)
 				
+				Local extClass:=(item.IsExtension And item.Parent=Null)
+				If extClass
+					' find 'root' class by extension name
+					Local it:=Self[item.Ident]
+					If it Then item=it
+				Endif
+				
 				' extract all items from item
 				items.Clear()
 				GetAllItems( item,items,isSuper )
+				ExtractExtensionItems( tmpItem,items )
 				
 				If Not items.Empty
 					For Local i:=Eachin items
+						
+						' skip constructors
+						If Not (isSelf Or isSuper) And i.Kind=CodeItemKind.Method_ And i.Ident="New" Continue
+						
 						If Not CheckIdent( i.Ident,identPart,last )
 							'Print "continue 1: "+i.Ident
 							Continue
@@ -607,10 +615,20 @@ Class Monkey2Parser Extends CodeParserPlugin
 							'Print "continue 2: "+i.Ident
 							Continue
 						Endif
+						If extClass And i.Access=AccessMode.Private_
+							Continue
+						Endif
+						' extensions can be placed in different namespaces
+						If i.IsExtension
+							If Not CheckUsingsFilter( i,usingsFilter )
+								Continue
+							Endif
+						Endif
 						item=i
 						If last
 							If Not staticOnly Or IsStaticMember( i )
-								target.AddLast( i )
+								target.Add( i )
+								If resultLimit>0 And target.Length=resultLimit Return
 							Endif
 						Else
 							Exit
@@ -624,23 +642,65 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Endif
 	End
 	
+	Method FixItemType:String( typeName:String )
+		
+		Local al:=_aliases[typeName]
+		Return al ? al.Type.ident Else typeName
+	End
 	
-	Private
+	Method AddExtensionItem( parent:CodeItem,item:CodeItem )
 	
-	Global _instance:=New Monkey2Parser
-	Field _filesTime:=New StringMap<Long>
-	Field _aliases:=New StringMap<CodeItem>
-	Field _modsPath:String,_mx2ccPath:String
+		Local key:=parent.Ident
+		Local list:=ExtraItemsMap[key]
+		If Not list
+			list=New Stack<CodeItem>
+			ExtraItemsMap[key]=list
+		Endif
+		For Local i:=Eachin list
+			If i.Text=item.Text
+				list.Remove( i )
+				Exit
+			Endif
+		Next
+		item.IsExtension=True
+		list.Add( item )
+	End
+
+	Method RemoveExtensions( filePath:String )
+		
+		For Local list:=Eachin ExtraItemsMap.Values.All()
+			Local it:=list.All()
+			While Not it.AtEnd
+				Local i:=it.Current
+				If i.FilePath=filePath
+					it.Erase()
+				Else
+					it.Bump()
+				Endif
+			Wend
+		Next
+	End
 	
-	Method New()
+	Method ExtractExtensionItems( item:CodeItem,target:Stack<CodeItem> )
 	
-		Super.New()
-		_types=New String[](".monkey2")
+		If ExtraItemsMap.Empty Return
+		
+		Local type:=item.Type.ident
+		Local list:=ExtraItemsMap[type]
+		If Not list
+			type=item.Ident
+			list=ExtraItemsMap[type]
+		Endif
+		If list
+			AddItems( list,target,True )
+		Endif
 	End
 	
 	Method StartParsing:String( pathOnDisk:String,isModule:Bool )
 		
-		Local proc:=ProcessReader.Obtain()
+		If Not _enabled Return ""
+		
+		Local proc:=ProcessReader.Obtain( pathOnDisk )
 		
 		Local cmd:=_mx2ccPath+" makeapp -parse -geninfo ~q"+pathOnDisk+"~q"
 		Local str:=proc.Run( cmd )
@@ -880,7 +940,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 		For Local u:=Eachin usingsFilter
 			If u.EndsWith( ".." )
 				u=u.Slice( 0,u.Length-2 )
-				If item.Namespac.StartsWith( u ) Return True
+				If item.Namespac=u Return True
+				If item.Namespac.StartsWith( u+"." ) Return True
 			Else
 				If item.Namespac = u Return True
 			Endif
@@ -888,33 +949,39 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return False
 	End
 	
-	Method GetAllItems( item:CodeItem,target:List<CodeItem>,isSuper:Bool=False )
+	Method AddItems( items:Stack<CodeItem>,target:Stack<CodeItem>,checkUnique:Bool )
+		
+		If Not items Return
+		
+		If checkUnique' need to add unique
+			For Local i:=Eachin items
+		
+				Local s:=i.Text
+				Local exists:=False
+				For Local ii:=Eachin target
+					If ii.Text = s
+						exists=True
+						Exit
+					Endif
+				End
+				If Not exists
+					target.Add( i )
+				Endif
+			Next
+		Else
+			target.AddAll( items )
+		Endif
+	End
+	
+	Method GetAllItems( item:CodeItem,target:Stack<CodeItem>,isSuper:Bool=False )
 		
 		Local checkUnique:=Not target.Empty
 		
 		If Not isSuper
 			' add children
-			Local items:=item.Children
-			If items
-				If checkUnique' need to add unique
-					For Local i:=Eachin items
-						
-						Local s:=i.Text
-						Local exists:=False
-						For Local ii:=Eachin target
-							If ii.Text = s
-								exists=True
-								Exit
-							Endif
-						End
-						If Not exists
-							target.AddLast( i )
-						Endif
-					Next
-				Else
-					target.AddAll( items )
-				Endif
-			Endif
+			AddItems( item.Children,target,checkUnique )
+			'
+			'ExtractExtensionItems( item,target )
 		End
 		
 		' add from super classes / ifaces
@@ -935,7 +1002,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 					Exit
 				Endif
 			Next
-			If result <> Null Then GetAllItems( result,target,isSuper )
+			If result <> Null Then GetAllItems( result,target,False )
 		Next
 		
 	End
@@ -981,9 +1048,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 			Return True
 		Endif
 		
-		If forceProtected And a = AccessMode.Protected_
-			Return True
-		Endif
+		If forceProtected And a = AccessMode.Protected_ Return True
 		
 		' not in class, so only public access here
 		If scopeClass = Null
@@ -1026,7 +1091,8 @@ Class Monkey2Parser Extends CodeParserPlugin
 	
 	Method IsStaticMember:Bool( item:CodeItem,checkPublic:Bool=True )
 		
-		If item.Access <> AccessMode.Public_ Return False
+		If checkPublic And item.Access <> AccessMode.Public_ Return False
+		
 		Select item.Kind
 		Case CodeItemKind.Function_,CodeItemKind.Global_,CodeItemKind.Const_,CodeItemKind.Class_,CodeItemKind.Enum_,CodeItemKind.Struct_
 			Return True
@@ -1039,6 +1105,10 @@ Class Monkey2Parser Extends CodeParserPlugin
 		Return (flags & Flags.DECL_OPERATOR)<>0
 	End
 	
+	Function IsExtension:Bool( flags:Int )
+		Return (flags & Flags.DECL_EXTENSION)<>0
+	End
+	
 	Function GetAccess:AccessMode( flags:Int )
 		
 		If flags & Flags.DECL_PRIVATE Return AccessMode.Private_
@@ -1105,6 +1175,7 @@ Class Monkey2Parser Extends CodeParserPlugin
 		
 		ItemsMap.Remove( path )
 		
+		RemoveExtensions( path )
 	End
 	
 	

+ 26 - 41
parser/Parser.monkey2

@@ -2,37 +2,6 @@
 Namespace ted2go
 
 
-Enum CodeItemKind
-	Undefine_,
-	Class_,
-	Interface_,
-	Enum_,
-	EnumMember_,
-	Struct_,
-	Field_,
-	Global_,
-	Const_,
-	Method_,
-	Function_,
-	Property_,
-	Param_,
-	Lambda_,
-	Local_,
-	Operator_,
-	Inner_,
-	Alias_,
-	Inherited_
-End
-
-
-Enum AccessMode
-	Private_,
-	Protected_,
-	Public_
-End
-
-
-
 Interface ICodeParser
 
 	Method RefineRawType( item:CodeItem )
@@ -43,14 +12,17 @@ Interface ICodeParser
 	Method GetScope:CodeItem( docPath:String,docLine:Int )
 	Method ItemAtScope:CodeItem( ident:String,filePath:String,docLine:Int )
 	
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:List<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
 	Method CheckStartsWith:Bool( ident1:String,ident2:String )
 	
 	Method GetItem:CodeItem( ident:String )
 	
-	Property Items:List<CodeItem>()
-	Property ItemsMap:StringMap<List<CodeItem>>()
+	Method SetEnabled( enabled:Bool )
+	
+	Property Items:Stack<CodeItem>()
+	Property ItemsMap:StringMap<Stack<CodeItem>>()
 	Property UsingsMap:StringMap<UsingInfo>()
+	Property ExtraItemsMap:StringMap<Stack<CodeItem>>()
 	
 End
 
@@ -64,6 +36,14 @@ Class ParsersManager
 		Return _empty
 	End
 
+	Function DisableAll()
+		
+		Local plugins:=Plugin.PluginsOfType<CodeParserPlugin>()
+		For Local p:=Eachin plugins
+			p.SetEnabled( False )
+		Next
+	End
+	
 	
 	Private
 	
@@ -83,11 +63,11 @@ Private
 
 Class EmptyParser Implements ICodeParser
 
-	Property Items:List<CodeItem>()
+	Property Items:Stack<CodeItem>()
 		Return _items
 	End
 	
-	Property ItemsMap:StringMap<List<CodeItem>>()
+	Property ItemsMap:StringMap<Stack<CodeItem>>()
 		Return _itemsMap
 	End
 	
@@ -95,6 +75,10 @@ Class EmptyParser Implements ICodeParser
 		Return _usingsMap
 	End
 	
+	Property ExtraItemsMap:StringMap<Stack<CodeItem>>()
+		Return _extraItemsMap
+	End
+	
 	Method ParseFile:String( filePath:String,pathOnDisk:String,isModule:Bool )
 		'do nothing
 		Return Null
@@ -113,7 +97,7 @@ Class EmptyParser Implements ICodeParser
 	End
 	Method RefineRawType( item:CodeItem )
 	End
-	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:List<CodeItem>,usingsFilter:Stack<String> =Null )
+	Method GetItemsForAutocomplete( ident:String,filePath:String,docLine:Int,target:Stack<CodeItem>,usingsFilter:Stack<String> =Null )
 	End
 	Method CheckStartsWith:Bool( ident1:String,ident2:String )
 		Return False
@@ -121,12 +105,13 @@ Class EmptyParser Implements ICodeParser
 	Method GetItem:CodeItem( ident:String )
 		Return Null
 	End
-	
+	Method SetEnabled( enabled:Bool )
+	End
 	
 	Private
 	
-	Field _items:=New List<CodeItem>
-	Field _itemsMap:=New StringMap<List<CodeItem>>
+	Field _items:=New Stack<CodeItem>
+	Field _itemsMap:=New StringMap<Stack<CodeItem>>
 	Field _usingsMap:=New StringMap<UsingInfo>
-	
+	Field _extraItemsMap:=New StringMap<Stack<CodeItem>>
 End

+ 23 - 4
parser/ParserPlugin.monkey2

@@ -8,11 +8,11 @@ Class CodeParserPlugin Extends PluginDependsOnFileType Implements ICodeParser
 		Return "CodeParserPlugin"
 	End
 	
-	Property Items:List<CodeItem>()
+	Property Items:Stack<CodeItem>()
 		Return _items
 	End
 	
-	Property ItemsMap:StringMap<List<CodeItem>>()
+	Property ItemsMap:StringMap<Stack<CodeItem>>()
 		Return _itemsMap
 	End
 	
@@ -20,6 +20,10 @@ Class CodeParserPlugin Extends PluginDependsOnFileType Implements ICodeParser
 		Return _usingsMap
 	End
 	
+	Property ExtraItemsMap:StringMap<Stack<CodeItem>>()
+		Return _extraItemsMap
+	End
+	
 	Method CheckStartsWith:Bool( ident1:String,ident2:String ) Virtual
 	
 		ident1=ident1.ToLower()
@@ -28,9 +32,23 @@ Class CodeParserPlugin Extends PluginDependsOnFileType Implements ICodeParser
 		Return ident1.StartsWith( ident2 )
 	End
 	
+	Method SetEnabled( enabled:Bool )
+		
+		_enabled=enabled
+	End
+	
+	Operator []:CodeItem( ident:String )
+		
+		For Local i:=Eachin _items
+			If i.Ident=ident Return i
+		Next
+		Return Null
+	End
 	
 	Protected
 	
+	Field _enabled:=True
+	
 	Method New()
 		AddPlugin( Self )
 	End
@@ -38,8 +56,9 @@ Class CodeParserPlugin Extends PluginDependsOnFileType Implements ICodeParser
 	
 	Private
 	
-	Field _items:=New List<CodeItem>
-	Field _itemsMap:=New StringMap<List<CodeItem>>
+	Field _items:=New Stack<CodeItem>
+	Field _itemsMap:=New StringMap<Stack<CodeItem>>
 	Field _usingsMap:=New StringMap<UsingInfo>
+	Field _extraItemsMap:=New StringMap<Stack<CodeItem>>
 	
 End

+ 1 - 1
syntax/Monkey2Keywords.monkey2

@@ -38,5 +38,5 @@ Class Monkey2Keywords Extends KeywordsPlugin
 		s+="Typeof;Array"
 		Return s
 	End
-		
+	
 End

+ 17 - 3
testing/ParserTests.monkey2

@@ -1,16 +1,25 @@
 
-Namespace ted2go
+Namespace test2go
 
 
+Struct Vec2i Extension
+	
+	Const One := New Vec2i( 1,1 )
+End
+
 Private
 
+Function vTest( v:Vec2i,e:Entity )
+	
+	v*=Vec2i.One
+End
+
 
 Interface ITest
 
 	Method abs()
-	Property bpp()
+	Property bpp:Bool()
 	
-		
 End
 
 
@@ -76,6 +85,11 @@ Class AAA Extends TestClass
 		'arr2[i].start
 	End
 	
+	Function TestParentFunc()
+		
+		
+	End
+	
 	Method anstrMethod() Abstract
 	
 End

+ 3 - 0
testing/test.bat

@@ -0,0 +1,3 @@
+
+echo 'hello'
+pause

+ 15 - 0
utils/JsonUtils.monkey2

@@ -52,3 +52,18 @@ Function Json_GetInt:Int( json:Map<String,JsonValue>,key:String,def:Int )
 	
 	Return json[key] ? Int(json[key].ToNumber()) Else def
 End
+
+
+Class JsonArray Extension
+	
+	Function Create:JsonArray( values:String[] )
+		
+		Local jvals:=New JsonValue[values.Length]
+		For Local i:=0 Until values.Length
+			jvals[i]=New JsonString( values[i] )
+		Next
+		Return New JsonArray( jvals )
+	End
+	
+End
+

+ 34 - 0
utils/Utils.monkey2

@@ -213,3 +213,37 @@ Function IsIdentStr:Bool( str:String,skipDots:Bool=True )
 	
 	Return True
 End
+
+Function TODO( message:String )
+	
+	Print "Not implemented yet: '"+message+"'"
+	DebugStop()
+	MainWindow.GainFocus()
+End
+
+Function DoInNotMainFiber( work:Void() )
+	
+	If Fiber.Current()=Fiber.Main()
+		New Fiber( work )
+	Else
+		work()
+	End
+End
+
+
+Struct Recti Extension
+	
+	Method MoveTo( x:Int,y:Int )
+		
+		Local size:=Self.Size
+		Self.Origin=New Vec2i( x,y )
+		Self.Size=size
+	End
+	
+	Method MoveBy( dx:Int,dy:Int )
+	
+		Local size:=Self.Size
+		Self.Origin=Self.Origin+New Vec2i( dx,dy )
+		Self.Size=size
+	End
+End

+ 31 - 23
view/AutocompleteView.monkey2

@@ -85,6 +85,7 @@ Struct AutocompleteResult
 	Field text:String
 	Field item:CodeItem
 	Field bySpace:Bool
+	Field byTab:Bool
 	Field isTemplate:Bool
 	
 End
@@ -107,12 +108,12 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 		ContentView=_view
 		
-		_keywords=New StringMap<List<ListViewItem>>
-		_templates=New StringMap<List<ListViewItem>>
+		_keywords=New StringMap<Stack<ListViewItem>>
+		_templates=New StringMap<Stack<ListViewItem>>
 		_parsers=New StringMap<ICodeParser>
 		
 		_view.OnItemChoosen+=Lambda()
-			OnItemChoosen( _view.CurrentItem )
+			OnItemChoosen( _view.CurrentItem,Key.None )
 		End
 		
 		App.KeyEventFilter+=Lambda( event:KeyEvent )
@@ -218,7 +219,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 			Local usings:Stack<String>
 			
-			If onlyOne And Not _disableUsingsFilter
+			If Not _disableUsingsFilter 'And onlyOne
 				
 				usings=New Stack<String>
 				
@@ -244,6 +245,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 					If info.usings Then usings.AddAll( info.usings )
 				Endif
 				
+				If Not usings.Contains( "monkey.." ) Then usings.Add( "monkey.." )
 			Endif
 			
 			_listForExtract.Clear()
@@ -324,12 +326,12 @@ Class AutocompleteDialog Extends NoTitleDialog
 	
 	Field _etalonMaxSize:Vec2i
 	Field _view:AutocompleteListView
-	Field _keywords:StringMap<List<ListViewItem>>
-	Field _templates:StringMap<List<ListViewItem>>
+	Field _keywords:StringMap<Stack<ListViewItem>>
+	Field _templates:StringMap<Stack<ListViewItem>>
 	Field _lastIdentPart:String,_fullIdent:String
 	Field _parsers:StringMap<ICodeParser>
-	Field _listForExtract:=New List<CodeItem>
-	Field _listForExtract2:=New List<CodeItem>
+	Field _listForExtract:=New Stack<CodeItem>
+	Field _listForExtract2:=New Stack<CodeItem>
 	Field _disableUsingsFilter:Bool
 	
 	Method GetParser:ICodeParser( fileType:String )
@@ -337,12 +339,12 @@ Class AutocompleteDialog Extends NoTitleDialog
 		Return _parsers[fileType]
 	End
 	
-	Method GetKeywords:List<ListViewItem>( fileType:String )
+	Method GetKeywords:Stack<ListViewItem>( fileType:String )
 		If _keywords[fileType] = Null Then UpdateKeywords( fileType )
 		Return _keywords[fileType]
 	End
 	
-	Method GetTemplates:List<ListViewItem>( fileType:String )
+	Method GetTemplates:Stack<ListViewItem>( fileType:String )
 		If _templates[fileType] = Null
 			UpdateTemplates( fileType )
 			LiveTemplates.DataChanged+=Lambda( lang:String )
@@ -370,11 +372,16 @@ Class AutocompleteDialog Extends NoTitleDialog
 				Local curItem:=_view.CurrentItem
 				Local templ:=Cast<TemplateListViewItem>( curItem )
 				
-				Select event.Key
+				Local key:=event.Key
+				Select key
+				
 				Case Key.Escape
 					Hide()
 					event.Eat()
-					
+				
+				Case Key.Home,Key.KeyEnd
+					Hide()
+				
 				Case Key.Up
 					_view.SelectPrev()
 					event.Eat()
@@ -394,7 +401,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 				Case Key.Enter,Key.KeypadEnter
 					If Not templ
 						If Prefs.AcUseEnter
-							OnItemChoosen( curItem )
+							OnItemChoosen( curItem,key )
 							If Not Prefs.AcNewLineByEnter Then event.Eat()
 						Else
 							Hide() 'hide by enter
@@ -403,7 +410,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 					
 				Case Key.Tab
 					If Prefs.AcUseTab Or templ
-						OnItemChoosen( curItem )
+						OnItemChoosen( curItem,key )
 						event.Eat()
 					Endif
 					
@@ -411,7 +418,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 					If Not templ
 						Local ctrl:=event.Modifiers & Modifier.Control
 						If Prefs.AcUseSpace And Not ctrl
-							OnItemChoosen( curItem,True )
+							OnItemChoosen( curItem,key )
 							event.Eat()
 						Endif
 					Endif
@@ -419,7 +426,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 				Case Key.Period
 					If Not templ
 						If Prefs.AcUseDot
-							OnItemChoosen( curItem )
+							OnItemChoosen( curItem,key )
 							event.Eat()
 						Endif
 					Endif
@@ -442,7 +449,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 	End
 	
-	Method OnItemChoosen( item:ListViewItem,bySpace:Bool=False )
+	Method OnItemChoosen( item:ListViewItem,key:Key )
 		
 		Local siCode:=Cast<CodeListViewItem>( item )
 		Local siTempl:=Cast<TemplateListViewItem>( item )
@@ -465,7 +472,8 @@ Class AutocompleteDialog Extends NoTitleDialog
 		result.ident=ident
 		result.text=text
 		result.item=code
-		result.bySpace=bySpace
+		result.bySpace=(key=Key.Space)
+		result.byTab=(key=Key.Tab)
 		result.isTemplate=templ
 		OnChoosen( result )
 		Hide()
@@ -475,18 +483,18 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 		'keywords
 		Local kw:=KeywordsManager.Get( fileType )
-		Local list:=New List<ListViewItem>
+		Local list:=New Stack<ListViewItem>
 		Local ic:=CodeItemIcons.GetKeywordsIcon()
 		For Local i:=Eachin kw.Values()
 			Local si:=New ListViewItem( i,ic )
-			list.AddLast( si )
+			list.Add( si )
 		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__"
 		Local arr:=s.Split( "," )
 		For Local i:=Eachin arr
-			list.AddLast( New ListViewItem( i ) )
+			list.Add( New ListViewItem( i ) )
 		Next
 		_keywords[fileType]=list
 	End
@@ -495,11 +503,11 @@ Class AutocompleteDialog Extends NoTitleDialog
 	
 		'live templates
 		Local templates:=LiveTemplates.All( fileType )
-		Local list:=New List<ListViewItem>
+		Local list:=New Stack<ListViewItem>
 		If templates <> Null
 			For Local i:=Eachin templates
 				Local si:=New TemplateListViewItem( i.Key,i.Value )
-				list.AddLast( si )
+				list.Add( si )
 			Next
 			list.Sort( Lambda:Int(l:ListViewItem,r:ListViewItem)
 				Return l.Text<=>r.Text

+ 4 - 1
view/CodeMapView.monkey2

@@ -44,6 +44,8 @@ Class CodeMapView Extends View
 			
 			Case EventType.MouseDown
 				
+				If posY0>ContentHeight Return 'small content height
+				
 				Local top:=_clickedScrollY*(scale-ScrollKoef)
 				Local inside := posY0>=top And posY0<=top+BubbleHeight
 				If Not inside Then ScrollTo( posY )
@@ -154,7 +156,8 @@ Class CodeMapView Extends View
 	Method ScrollTo( posY:Float )
 	
 		Local scrl:=_codeView.Scroll
-		Local percent:=posY/(VisibleHeight-BubbleHeight)
+		Local hg:=Min( VisibleHeight,ContentHeight )
+		Local percent:=posY/(hg-BubbleHeight)
 		Local yy:=_maxOwnerScroll*percent
 		scrl.Y=yy
 		_codeView.Scroll=scrl

+ 199 - 26
view/CodeTextView.monkey2

@@ -20,10 +20,45 @@ Class CodeTextView Extends TextView
 		CursorMoved += OnCursorMoved
 		Document.TextChanged += TextChanged
 		
+'		Document.LinesModified += Lambda( first:Int,removed:Int,inserted:Int )
+'			
+'			If _extraSelStart=-1 Return
+'			If first>=_extraSelEnd Print "ret" ; Return
+'			
+'			Print "LinesModified: "+first+", "+removed+", "+inserted
+'			
+'			If inserted>0
+'				
+'				If first<_extraSelStart
+'					Print "if 1-1"
+'					_extraSelStart+=inserted
+'				Endif
+'				_extraSelEnd+=inserted
+'				
+'			Else
+'				
+'				If first<=_extraSelStart And first+removed>=_extraSelEnd
+'					ResetExtraSelection()
+'					Print "reset"
+'					Return
+'				Endif
+'				
+'				If first<_extraSelStart
+'					Print "if 2-1"
+'					_extraSelStart-=removed
+'					_extraSelEnd-=removed
+'				Else
+'					Print "if 2-2"
+'					_extraSelEnd-=Min( removed,_extraSelEnd-first )
+'				Endif
+'				
+'			Endif
+'		End
+		
 		UpdateThemeColors()
 	End
 	
-	Method IsCursorAtTheEndOfLine:Bool()
+	Property IsCursorAtTheEndOfLine:Bool()
 		
 		Local line:=Document.FindLine( Cursor )
 		Local pos:=Document.EndOfLine( line )
@@ -77,7 +112,31 @@ Class CodeTextView Extends TextView
 		Return ident
 	End
 	
-	Method FullIdentAtCursor:String()
+	Property WordAtCursor:String()
+		
+		Local text:=Text
+		Local cur:=Cursor
+		Local n:=Cursor-1
+		Local line:=Document.FindLine( Cursor )
+		Local start:=Document.StartOfLine( line )
+		Local ends:=Document.EndOfLine( line )
+		
+		While n >= start
+			If Not IsIdent( text[n] ) Exit
+			n-=1
+		Wend
+		Local p1:=n+1
+		n=cur
+		While n < ends And IsIdent( text[n] )
+			n+=1
+		Wend
+		Local p2:=n
+		Local ident:=(p1 < cur Or p2 > cur) ? text.Slice( p1,p2 ) Else ""
+		
+		Return ident
+	End
+		
+	Property FullIdentAtCursor:String()
 		
 		Local text:=Text
 		Local cur:=Cursor
@@ -148,11 +207,12 @@ Class CodeTextView Extends TextView
 	
 		If pos.y = 0
 			GotoLine( pos.x )
-			Return
+		Else
+			Local dest:=Document.StartOfLine( pos.x )+pos.y
+			SelectText( dest,dest )
 		Endif
 		
-		Local dest:=Document.StartOfLine( pos.x )+pos.y
-		SelectText( dest,dest )
+		MakeCentered()
 	End
 	
 	Property LineTextAtCursor:String()
@@ -192,6 +252,48 @@ Class CodeTextView Extends TextView
 		_showWhiteSpaces=value
 	End
 	
+	Property OverwriteMode:Bool()
+	
+		Return _overwriteMode
+	
+	Setter( value:Bool )
+	
+		_overwriteMode=value
+		
+		BlockCursor=_overwriteMode
+	End
+	
+	Method MarkSelectionAsExtraSelection()
+		
+		_extraSelStart=Anchor
+		_extraSelEnd=Cursor
+		RequestRender()
+	End
+	
+	Method ResetExtraSelection()
+		
+		_extraSelStart=-1
+		_extraSelEnd=-1
+		RequestRender()
+	End
+	
+	Property ExtraSelectionStart:Int()
+		Return _extraSelStart
+	Setter( value:Int )
+		_extraSelStart=value
+		RequestRender()
+	End
+	
+	Property ExtraSelectionEnd:Int()
+		Return _extraSelEnd
+	Setter( value:Int )
+		_extraSelEnd=value
+		RequestRender()
+	End
+	
+	Property HasExtraSelection:Bool()
+		Return _extraSelStart>=0
+	End
 	
 	Protected
 	
@@ -206,8 +308,19 @@ Class CodeTextView Extends TextView
 			
 			Case EventType.MouseDown 'prevent selection by dragging with right-button
 				
-				If event.Button = MouseButton.Right Return
-				
+				If event.Button = MouseButton.Right
+					If Not CanCopy
+						Local cur:=CharAtPoint( event.Location )
+						SelectText( cur,cur )
+					Else
+						Local r:=CursorRect | CharRect( Anchor )
+						If Not r.Contains( event.Location )
+							Local cur:=CharAtPoint( event.Location )
+							SelectText( cur,cur )
+						Endif
+					Endif
+					Return
+				Endif
 				
 			Case EventType.MouseUp
 				
@@ -216,11 +329,22 @@ Class CodeTextView Extends TextView
 					MainWindow.ShowEditorMenu( Self )
 					Return
 				Endif
+			
+			Case EventType.MouseEnter
+				
+				Mouse.Cursor=MouseCursor.IBeam
+				
+			Case EventType.MouseLeave
+				
+				Mouse.Cursor=MouseCursor.Arrow
 				
 		End
-
+		
+		' correct click position for beam cursor
+		event=event.Copy( event.Location+New Vec2i( 6,3 ) ) 'magic offset
+		
 		Super.OnContentMouseEvent( event )
-					
+		
 	End
 	
 	Method OnKeyEvent(event:KeyEvent) Override
@@ -235,8 +359,8 @@ Class CodeTextView Extends TextView
 					If _typing Then DoFormat( False )
 				Endif
 				
-				' select next char in override mode
-				If Cursor=Anchor And MainWindow.OverwriteTextMode
+				' select next char in overwrite mode
+				If Cursor=Anchor And _overwriteMode
 				
 					' don't select new-line-char ~n
 					If Cursor < Text.Length And Text[Cursor]<>10
@@ -427,10 +551,32 @@ Class CodeTextView Extends TextView
 	Method UpdateThemeColors() Virtual
 	
 		_whitespacesColor=App.Theme.GetColor( "textview-whitespaces" )
+		_extraSelColor=App.Theme.GetColor( "textview-extra-selection" )
 	End
 	
-	Method OnRenderLine( canvas:Canvas,line:Int ) Override
+	Method OnRenderContent( canvas:Canvas,clip:Recti ) Override
+		
+		' extra selection
+		If _extraSelStart<>-1
+			Local min:=CharRect( Min( _extraSelStart,_extraSelEnd ) )
+			Local max:=CharRect( Max( _extraSelStart,_extraSelEnd ) )
+			
+			canvas.Color=_extraSelColor
+			
+			If min.Y=max.Y
+				canvas.DrawRect( min.Left,min.Top,max.Left-min.Left,min.Height )
+			Else
+				canvas.DrawRect( min.Left,min.Top,(clip.Right-min.Left),min.Height )
+				canvas.DrawRect( 0,min.Bottom,clip.Right,max.Top-min.Bottom )
+				canvas.DrawRect( 0,max.Top,max.Left,max.Height )
+			Endif
+		Endif
+		
+		Super.OnRenderContent( canvas,clip )
+	End
 	
+	Method OnRenderLine( canvas:Canvas,line:Int ) Override
+		
 		Super.OnRenderLine( canvas,line )
 	
 		' draw whitespaces
@@ -439,43 +585,62 @@ Class CodeTextView Extends TextView
 		Local text:=Document.Text
 		Local colors:=Document.Colors
 		Local r:Recti
-	
+		Local start:=Document.StartOfLine( 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 ww:=r.Width/len
-				Local xx:=x0+ww
-	
+				
+				Local xx:=x0 + (cnt=0 ? _tabw Else Float(TabStop-cnt)/Float(TabStop)*_tabw)
+				
 				Local after:=word.Index+len
 				If after < text.Length And text[after] > 32 Then len-=1
-	
+				
 				For Local i:=0 Until len
 					canvas.DrawLine( xx,y0,xx,y1 )
-					xx+=ww
+					xx+=_tabw
 				Next
 			Endif
 		Next
 	
 	End
 	
+	Method OnValidateStyle() Override
+		
+		Super.OnValidateStyle()
+		
+		Local style:=RenderStyle
+		_tabw=style.Font.TextWidth( "X" )*TabStop
+	End
+	
 	
 	Private
 	
 	Field _line:Int
 	Field _whitespacesColor:Color
 	Field _showWhiteSpaces:Bool
-	Field _font:Font
-	Field _charw:Int
-	Field _charh:Int
 	Field _tabw:Int
-	
+	Field _overwriteMode:Bool
+	Field _extraSelStart:Int=-1,_extraSelEnd:Int
+	Field _extraSelColor:Color=Color.DarkGrey
 	
 	Method OnCursorMoved()
 		
@@ -490,5 +655,13 @@ Class CodeTextView Extends TextView
 		
 	End
 	
+End
+
+
+Class MouseEvent Extension
 	
+	Method Copy:MouseEvent( location:Vec2i )
+		
+		Return New MouseEvent( Self.Type,Self.View,location,Self.Button,Self.Wheel,Self.Modifiers,Self.Clicks )
+	End
 End

+ 23 - 9
view/CodeTreeView.monkey2

@@ -25,13 +25,27 @@ Class CodeTreeView Extends TreeViewExt
 		node.Expanded=True
 		node.RemoveAllChildren()
 		
+		_stack.Clear()
+		
+		' extract all items in file
 		Local list:=parser.ItemsMap[path]
-		If list = Null Return
+		If list Then _stack.AddAll( list )
+		
+		' extensions are here too
+		For Local lst:=Eachin parser.ExtraItemsMap.Values.All()
+			For Local i:=Eachin lst
+				If i.FilePath=path
+					If Not _stack.Contains( i.Parent ) Then _stack.Add( i.Parent )
+				Endif
+			Next
+		Next
+		
+		If _stack.Empty Return
 		
 		' sorting
-		SortItems( list )
+		SortItems( _stack )
 		
-		For Local i:=Eachin list
+		For Local i:=Eachin _stack
 			AddTreeItem( i,node,parser )
 		Next
 		
@@ -52,7 +66,7 @@ Class CodeTreeView Extends TreeViewExt
 	Private
 	
 	Field _expander:TreeViewExpander
-	
+	Field _stack:=New Stack<CodeItem>
 	
 	Method FindNode:TreeView.Node( treeNode:TreeView.Node,item:CodeItem )
 	
@@ -80,7 +94,7 @@ Class CodeTreeView Extends TreeViewExt
 		
 		If item.Children = Null And Not ShowInherited Return
 		
-		Local list:=New List<CodeItem>
+		Local list:=New Stack<CodeItem>
 		
 		If item.Children<>Null Then list.AddAll( item.Children )
 		
@@ -92,13 +106,13 @@ Class CodeTreeView Extends TreeViewExt
 			SortItems( list )
 			
 			If ShowInherited
-				Local lst:=New List<CodeItem>
+				Local lst:=New Stack<CodeItem>
 				GetInherited( item,parser,lst )
 				If lst<>Null And Not lst.Empty
 					inherRoot=New CodeItem( "[ Inherited members ]" )
 					inherRoot.Children=lst
 					inherRoot.KindStr="inherited"
-					list.AddFirst( inherRoot )
+					list.Insert( 0,inherRoot )
 					'For Local i:=Eachin lst
 					'	Local children:=i.Children
 					'	
@@ -120,7 +134,7 @@ Class CodeTreeView Extends TreeViewExt
 		
 	End
 	
-	Method SortItems( list:List<CodeItem> )
+	Method SortItems( list:Stack<CodeItem> )
 	
 		If SortByType
 			CodeItemsSorter.SortByType( list,False,True )
@@ -129,7 +143,7 @@ Class CodeTreeView Extends TreeViewExt
 		End
 	End
 	
-	Method GetInherited:List<CodeItem>( item:CodeItem,parser:ICodeParser,result:List<CodeItem> )
+	Method GetInherited:Stack<CodeItem>( item:CodeItem,parser:ICodeParser,result:Stack<CodeItem> )
 	
 		If item.SuperTypesStr=Null Return Null
 	

+ 7 - 3
view/DebugView.monkey2

@@ -35,7 +35,7 @@ Class DebugView Extends DockingView
 		
 		End
 
-		'step over		
+		'step over
 		_step=_toolBar.AddAction( "",icons[3] )
 		_step.Triggered=Lambda()
 			If Not _debugging Return
@@ -177,8 +177,12 @@ Class DebugView Extends DockingView
 		
 		OnStopRunning( "Finished debugging app." )
 	End
-
-
+	
+	Method KillApp()
+		
+		_kill.Trigger()
+	End
+	
 	Private
 	
 	Method OnStopRunning( info:String )

+ 18 - 0
view/DockingViewExt.monkey2

@@ -0,0 +1,18 @@
+
+Namespace ted2go
+
+
+Class DockingViewExt Extends DockingView
+	
+	Field Rendered:Void( canvas:Canvas )
+	
+	Protected
+	
+	Method OnRender( canvas:Canvas ) Override
+		
+		Super.OnRender( canvas )
+		
+		Rendered( canvas )
+	End
+	
+End

+ 11 - 7
view/FileBrowserExt.monkey2

@@ -2,7 +2,7 @@
 Namespace ted2go
 
 
-Class FileBrowserExt Extends TreeView
+Class FileBrowserExt Extends TreeViewExt
 
 	Field FileClicked:Void( path:String )
 
@@ -20,12 +20,12 @@ Class FileBrowserExt Extends TreeView
 		
 		RootPath=rootPath
 
-		NodeClicked=OnNodeClicked
-		NodeRightClicked=OnNodeRightClicked
-		NodeDoubleClicked=OnNodeDoubleClicked
+		NodeClicked+=OnNodeClicked
+		NodeRightClicked+=OnNodeRightClicked
+		NodeDoubleClicked+=OnNodeDoubleClicked
 		
-		NodeExpanded=OnNodeExpanded
-		NodeCollapsed=OnNodeCollapsed
+		NodeExpanded+=OnNodeExpanded
+		NodeCollapsed+=OnNodeCollapsed
 		
 		RootNode=_rootNode
 		
@@ -70,7 +70,7 @@ Class FileBrowserExt Extends TreeView
 		_dirIcon=_fileTypeIcons["._dir"]
 		_fileIcon=_fileTypeIcons["._file"]
 	End
-
+	
 	Private
 	
 	Class Node Extends TreeView.Node
@@ -79,6 +79,10 @@ Class FileBrowserExt Extends TreeView
 			Super.New( "",parent )
 		End
 		
+		Property Path:String()
+			Return _path
+		End
+		
 		Private
 		
 		Field _path:String

+ 241 - 0
view/FindReplaceView.monkey2

@@ -0,0 +1,241 @@
+
+Namespace ted2go
+
+
+Class FindReplaceView Extends DockingView
+	
+	Enum Kind
+		Find,
+		Replace
+	End
+	
+	Field RequestedFind:Void( opt:FindOptions )
+	Field RequestedReplace:Void( opt:FindOptions )
+	
+	Method New( actions:FindActions )
+		
+		Super.New()
+		
+		Style=GetStyle( "FindReplaceView","DockingView" )
+		
+		Local mainDock:=New DockingView
+		
+		' FIND
+		'
+		Local findDock:=New DockingView
+		
+		Local what:=New Label( "Find:" )
+		what.MinSize=New Vec2i( 60,0 )
+		findDock.AddView( what,"left" )
+		
+		_editFind=New TextFieldExt
+		_editFind.MaxSize=New Vec2i( 160,24 )
+		_editFind.Entered+=Lambda()
+			OnFindNext()
+		End
+		findDock.AddView( _editFind,"left" )
+		
+		Local dock:DockingView
+		dock=New DockingView
+		findDock.AddView( dock,"left" )
+		
+		_chbCase=New CheckButton( "Case sens." )
+		_chbSel=New CheckButton( "Sel. text only" )
+		_chbWrap=New CheckButton( "Wrap around" )
+		_chbWrap.Checked=True
+		
+		_chbCase.Clicked+=Lambda()
+			_options.caseSensitive=_chbCase.Checked
+		End
+		
+		_chbSel.Clicked+=Lambda()
+			Local sel:=_chbSel.Checked
+			If Not _tv Or Not _tv.CanCopy Then sel=False ; _chbSel.Checked=False
+			_options.selectionOnly=sel
+			If _tv
+				If sel Then _tv.MarkSelectionAsExtraSelection() Else _tv.ResetExtraSelection()
+			Endif
+		End
+		
+		_chbWrap.Clicked+=Lambda()
+			_options.wrapAround=_chbWrap.Checked
+		End
+		
+		Local act:=New Action( "Next >" )
+		act.Triggered+=Lambda()
+			
+			OnFindNext()
+		End
+		_buttonFindNext=New ToolButtonExt( act,GetActionTextWithShortcut( actions.findNext ) )
+		
+		act=New Action( "< Prev" )
+		act.Triggered+=Lambda()
+			
+			_options.Set( _editFind.Text,"",_chbCase.Checked,_chbWrap.Checked,False,_chbSel.Checked )
+			RequestedFind( _options )
+		End
+		_buttonFindPrev=New ToolButtonExt( act,GetActionTextWithShortcut( actions.findPrevious ) )
+		
+		dock.AddView( New SpacerView( 16,0 ),"left" )
+		dock.AddView( _buttonFindPrev,"left" )
+		dock.AddView( New SpacerView( 5,0 ),"left" )
+		dock.AddView( _buttonFindNext,"left" )
+		dock.AddView( New SpacerView( 5,0 ),"left" )
+		dock.AddView( _chbCase,"left" )
+		dock.AddView( New SpacerView( 5,0 ),"left" )
+		dock.AddView( _chbSel,"left" )
+		dock.AddView( New SpacerView( 5,0 ),"left" )
+		dock.AddView( _chbWrap,"left" )
+		dock.AddView( New SpacerView( 10,0 ),"left" )
+		
+		' replace switcher
+		Local act2:=New Action( "R" )
+		act2.Triggered=Lambda()
+			Mode = (_mode=Kind.Find) ? Kind.Replace Else Kind.Find
+		End
+		Local replSwitcher:=New ToolButtonExt( act2,"Show / hide replace panel" )
+		dock.AddView( replSwitcher,"left" )
+		
+		' don't want to fix padding-right for TabClose style
+		findDock.AddView( New SpacerView( 6,0 ),"right" )
+		
+		Local close:=New Button
+		close.Style=GetStyle( "TabClose" )
+		close.Icon=close.Style.Icons[0]
+		close.Clicked=Lambda()
+			MainWindow.HideFindPanel() 'dirty
+		End
+		
+		findDock.AddView( close,"right" )
+		
+		' REPLACE
+		'
+		_replaceDock=New DockingView
+		
+		Local with:=New Label( "Replace:" )
+		with.MinSize=New Vec2i( 60,0 )
+		_replaceDock.AddView( with,"left" )
+		
+		_editReplace=New TextFieldExt
+		_editReplace.MaxSize=New Vec2i( 160,24 )
+		_replaceDock.AddView( _editReplace,"left" )
+		
+		dock=New DockingView
+		_replaceDock.AddView( dock,"left" )
+		
+		act=New Action( "Replace" )
+		act.Triggered+=Lambda()
+			
+			_options.Set( _editFind.Text,_editReplace.Text,_chbCase.Checked,_chbWrap.Checked,True,_chbSel.Checked )
+			RequestedReplace( _options )
+		End
+		_buttonReplace=New ToolButtonExt( act )
+		
+		act=New Action( "Replace all" )
+		act.Triggered+=Lambda()
+			
+			_options.Set( _editFind.Text,_editReplace.Text,_chbCase.Checked,_chbWrap.Checked,True,_chbSel.Checked,True )
+			RequestedReplace( _options )
+		End
+		_buttonReplaceAll=New ToolButtonExt( act )
+		
+		dock.AddView( New SpacerView( 16,0 ),"left" )
+		dock.AddView( _buttonReplace,"left" )
+		dock.AddView( New SpacerView( 5,0 ),"left" )
+		dock.AddView( _buttonReplaceAll,"left" )
+		
+		mainDock.AddView( findDock,"top" )
+		mainDock.AddView( _replaceDock,"top" )
+		
+		_editFind.NextView=_editReplace
+		_editReplace.NextView=_editFind
+		
+		Self.ContentView=mainDock
+	End
+	
+	Property Mode:Kind()
+		Return _mode
+	Setter( value:Kind )
+		_mode=value
+		_replaceDock.Visible=(_mode=Kind.Replace)
+	End
+	
+	Property FindText:String()
+		Return _editFind.Text
+	Setter( value:String )
+		_editFind.Text=value
+		_editFind.SelectAll()
+	End
+	
+	Property CodeView:CodeTextView()
+		Return _tv
+	Setter( value:CodeTextView )
+		If _tv=value Return
+		If _tv Then _tv.ResetExtraSelection()
+		_tv=value
+		If _tv And _chbSel.Checked
+			If _tv.CanCopy
+				_tv.MarkSelectionAsExtraSelection()
+			Else
+				_chbSel.Checked=False
+			Endif
+		Endif
+	End
+	
+	Method Activate()
+		
+		MainWindow.UpdateWindow( False ) 'hack
+		_editFind.MakeKeyView()
+		_editFind.SelectAll()
+	End
+	
+	
+	Private
+	
+	Field _mode:Kind
+	Field _editFind:TextFieldExt
+	Field _editReplace:TextFieldExt
+	Field _chbCase:CheckButton
+	Field _chbWrap:CheckButton
+	Field _chbSel:CheckButton
+	Field _buttonFindNext:ToolButtonExt
+	Field _buttonFindPrev:ToolButtonExt
+	Field _buttonReplace:ToolButtonExt
+	Field _buttonReplaceAll:ToolButtonExt
+	Field _replaceDock:DockingView
+	Field _tv:CodeTextView
+	
+	Field _options:=New FindOptions
+	
+	Method OnFindNext()
+		
+		_options.Set( _editFind.Text,"",_chbCase.Checked,_chbWrap.Checked,True,_chbSel.Checked )
+		RequestedFind( _options )
+	End
+End
+
+
+Class FindOptions
+
+	Field findText:String
+	Field replaceText:String
+	Field caseSensitive:Bool
+	Field wrapAround:Bool
+	Field goNext:Bool
+	Field all:Bool
+	Field selectionOnly:Bool
+	
+	Method New()
+	End
+	
+	Method Set( find:String,replace:String,caseSens:Bool,wrap:Bool,goNext:Bool,selOnly:Bool,all:Bool=False )
+
+		findText=find
+		replaceText=replace
+		caseSensitive=caseSens
+		wrapAround=wrap
+		selectionOnly=selOnly
+		Self.goNext=goNext
+		Self.all=all
+	End
+End

+ 3 - 3
view/HelpTreeView.monkey2

@@ -61,7 +61,7 @@ Class HelpTreeView Extends TreeViewExt
 		Init()
 	End
 	
-	Property FindField:TextField()
+	Property FindField:TextFieldExt()
 	
 		Return _textField
 	End
@@ -215,7 +215,7 @@ Class HelpTreeView Extends TreeViewExt
 	
 	Method Init()
 
-		_textField=New TextField
+		_textField=New TextFieldExt
 		_textField.Style=GetStyle( "HelpTextField" )
 		
 		_textField.Entered=Lambda()
@@ -246,7 +246,7 @@ Class HelpTreeView Extends TreeViewExt
 				
 	End
 	
-	Field _textField:TextField
+	Field _textField:TextFieldExt
 	
 	Field _matchid:Int
 		

+ 42 - 19
view/HintView.monkey2

@@ -2,23 +2,22 @@
 Namespace ted2go
 
 
-Function ShowHint( hint:String,location:Vec2i,sender:View,duration:Int=3000 )
+Function ShowHint( hint:String,location:Vec2i,sender:View,durationMs:Int=3000 )
 
-	If Not _hint Then InitHint()
+	If Not _hint Then _hint=New HintView
 	
-	location=sender.TransformPointToView( location,MainWindow )
-	location+=10
-	
-	_hint.Show( hint,location )
-	_time=Millisecs()
-	_duration=duration
+	NeedShow( hint,location,sender,durationMs )
 End
 
 Function HideHint()
 
 	If Not _hint Return
 	_hint.Hide()
-	_time=0
+	
+	If _timer
+		_timer.Cancel()
+		_timer=Null
+	Endif
 End
 
 
@@ -26,16 +25,24 @@ Private
 
 Global _hint:HintView
 Global _timer:Timer
-Global _time:Long
-Global _duration:Int
 
-Function InitHint()
+Function NeedShow( hint:String,location:Vec2i,sender:View,duration:Float )
+	
+	_timer=New Timer( 1.8, Lambda()
+		_hint.Show( hint,location,sender )
+		_timer.Cancel()
+		_timer=Null
+		NeedHide( duration )
+	End )
+End
 
-	_hint=New HintView
-	_timer=New Timer( 1, Lambda()
-		If _time > 0 And Millisecs() >= _time+_duration
-			HideHint()
-		End
+Function NeedHide( duration:Float )
+	
+	Local hertz:=1.0/(duration/1000.0)
+	_timer=New Timer( hertz, Lambda()
+		If _hint Then _hint.Hide()
+		_timer.Cancel()
+		_timer=Null
 	End )
 End
 
@@ -51,15 +58,31 @@ Class HintView Extends TextView
 		Gravity=New Vec2f( 0,0 )
 	End
 	
-	Method Show( text:String,location:Vec2i )
+	Method Show( text:String,location:Vec2i,sender:View )
 		
 		Hide()
 		
 		Text=text
 		MainWindow.AddChildView( Self )
-		Offset=location
 		Visible=True
 		
+		Local window:=sender.Window
+		
+		location=sender.TransformPointToView( location,window )
+		Local dy:=New Vec2i( 0,10 )
+		
+		' fit into window area
+		Local size:=MeasureLayoutSize()
+		Local dx:=location.x+size.x-window.Bounds.Right
+		If dx>0
+			location=location-New Vec2i( dx,0 )
+		Endif
+		If location.y+size.y+dy.y>window.Bounds.Bottom
+			location=location-New Vec2i( 0,size.y )
+			dy=-dy
+		Endif
+		Offset=location+dy
+		
 	End
 	
 	Method Hide()

+ 6 - 6
view/IRCView.monkey2

@@ -711,10 +711,10 @@ Class IRCView Extends DockingView
 	Field introScreen:IRCIntroView
 	Field chatScreen:DockingView
 	
-	Field topicField:TextField
+	Field topicField:TextFieldExt
 	Field historyField:TextView
 	Field bottomDocker:DockingView
-	Field inputField:TextField
+	Field inputField:TextFieldExt
 	Field nicknameLabel:Label
 	Field userList:ListView
 	Field serverTree:TreeView
@@ -901,7 +901,7 @@ Class IRCView Extends DockingView
 		End
 		
 		'Topic field
-		topicField=New TextField()
+		topicField=New TextFieldExt
 		topicField.BlockCursor=False
 		topicField.CursorType=CursorType.Line
 		topicField.ReadOnly=True
@@ -925,7 +925,7 @@ Class IRCView Extends DockingView
 		End
 		
 		'User input field
-		inputField=New TextField
+		inputField=New TextFieldExt
 		inputField.BlockCursor=False
 		inputField.CursorType=CursorType.Line
 		inputField.CursorBlinkRate=2.5
@@ -1332,7 +1332,7 @@ Class IRCIntroView Extends DockingView
 	Field servers:=New List<IRCServer>
 	Field roomScroller:ScrollableView
 	Field nickBox:DockingView
-	Field nickField:TextField
+	Field nickField:TextFieldExt
 	Field nickLabel:Label
 	Field checkboxes:=New List<CheckButton>
 	Field connectButton:Button
@@ -1410,7 +1410,7 @@ Class IRCIntroView Extends DockingView
 		nickLabel=New Label("Nickname")
 		nickBox.AddView(nickLabel,"left")
 		
-		nickField=New TextField
+		nickField=New TextFieldExt
 		nickField.BlockCursor=False
 		nickField.TextChanged+=Lambda()
 			OnNickChange(nickField.Text)

+ 35 - 26
view/MenuExt.monkey2

@@ -77,11 +77,7 @@ Class MenuExt Extends DockingView
 		_subs[button]=menu
 		
 		button.Clicked=Lambda()
-			If menu.Visible
-				If Not Prefs.SiblyMode
-					menu.Close()
-				Endif
-			Else
+			If Not menu.Visible
 				Local location:=New Vec2i( button.Bounds.Right,button.Bounds.Top )
 				menu.Open( location,button,Self )
 			Endif
@@ -113,12 +109,23 @@ Class MenuExt Extends DockingView
 		Endif
 		
 		Local window:=view.Window
-		location=view.TransformPointToView( location,window )
 		
 		window.AddChildView( Self )
-		Offset=location
 		Visible=True
 		
+		location=view.TransformPointToView( location,window )
+		
+		' fit into window area
+		Local size:=MeasureLayoutSize()
+		If location.x+size.x>window.Bounds.Right
+			location=location-New Vec2i( size.x,0 )
+		Endif
+		If location.y+size.y>window.Bounds.Bottom
+			location=location-New Vec2i( 0,size.y )
+		Endif
+		
+		Offset=location
+		
 		_owner=owner
 
 		_open.Push( Self )
@@ -155,6 +162,7 @@ Class MenuExt Extends DockingView
 	Global _hovered:View
 	Global _timer:Timer
 	Global _sub:MenuExt
+	Global _seq:Int
 	
 	Global _open:=New Stack<MenuExt>
 	
@@ -185,31 +193,32 @@ Class MenuExt Extends DockingView
 					
 					Local sub:=menu._subs[view]
 					
-					If Not Prefs.SiblyMode
-						If _sub And menu<>_sub
-							_sub.Close()
-							_sub=Null
+					_seq=0
+					_timer=New Timer( 4,Lambda()
+						
+						' close previous
+						If _seq=0
+							If _sub And menu<>_sub
+								_sub.Close()
+								_sub=Null
+							Endif
+							_seq+=1
+							Return
 						Endif
-					Endif
-					
-					If sub
-						_timer=New Timer( 1.8,Lambda()
+						
+						' open submenu
+						If sub
 							Local location:=New Vec2i( view.Bounds.Right,view.Bounds.Top )
 							
-							If Prefs.SiblyMode
-								If _sub And menu<>_sub
-									_sub.Close()
-									_sub=Null
-								Endif
-							Endif
-							
 							If sub.Visible Then sub.Close()
 							sub.Open( location,view,menu )
 							_sub=sub
-							_timer.Cancel()
-							_timer=Null
-						End )
-					Endif
+						Endif
+						
+						_timer.Cancel()
+						_timer=Null
+						
+					End )
 				Endif
 				
 				Return

+ 18 - 1
view/ProjectBrowserView.monkey2

@@ -3,7 +3,8 @@ Namespace ted2go
 
 
 Class ProjectBrowserView Extends FileBrowserExt
-
+	
+	Field RequestedDelete:Void( path:String )
 	
 	Method New( rootPath:String )
 		
@@ -55,6 +56,22 @@ Class ProjectBrowserView Extends FileBrowserExt
 	End
 	
 	
+	Protected
+	
+	Method OnKeyEvent( event:KeyEvent ) Override
+		
+		If Selected And event.Type=EventType.KeyDown And event.Key=Key.KeyDelete
+			
+			Local node:=Cast<FileBrowserExt.Node>( Selected )
+			RequestedDelete( node.Path )
+			event.Eat()
+			Return
+		Endif
+		
+		Super.OnKeyEvent( event )
+	End
+	
+	
 	Private
 	
 	Field _filters:Stack<JsonValue>

+ 77 - 30
view/ProjectView.monkey2

@@ -38,6 +38,18 @@ Class ProjectView Extends ScrollView
 		Return projs.ToArray()
 	End
 	
+	Function FindProjectByFile:String( filePath:String )
+		
+		If Not filePath Return ""
+		
+		For Local p:=Eachin _projects.Keys
+			If filePath.StartsWith( p )
+				Return p
+			Endif
+		End
+		Return ""
+	End
+	
 	Method OpenProject:Bool( dir:String )
 	
 		dir=StripSlashes( dir )
@@ -48,17 +60,16 @@ Class ProjectView Extends ScrollView
 	
 		Local browser:=New ProjectBrowserView( dir )
 		
-		browser.FileClicked+=Lambda( path:String )
+		browser.RequestedDelete+=Lambda( path:String )
 		
-			'OnOpenDocument( path )
-			
+			DeleteItem( browser,path )
 		End
 		
 		If Prefs.SiblyMode
 		
 			browser.FileClicked+=Lambda( path:String )
 			
-				OnOpenDocument( path )
+				OnOpenDocument( path,False )
 			End
 		
 		Else 
@@ -72,7 +83,7 @@ Class ProjectView Extends ScrollView
 		
 		browser.FileRightClicked+=Lambda( path:String )
 		
-			Local menu:=New Menu
+			Local menu:=New MenuExt
 		
 			Select GetFileType( path )
 			Case FileType.Directory
@@ -134,14 +145,7 @@ Class ProjectView Extends ScrollView
 				
 				menu.AddAction( "Delete" ).Triggered=Lambda()
 
-					If Not RequestOkay( "Really delete folder '"+path+"'?" ) Return
-					
-					If DeleteDir( path,True )
-						browser.Refresh()
-						Return
-					Endif
-					
-					Alert( "Failed to delete folder '"+path+"'" )
+					DeleteItem( browser,path )
 				End
 				
 				menu.AddSeparator()
@@ -252,20 +256,8 @@ Class ProjectView Extends ScrollView
 				menu.AddSeparator()
 			
 				menu.AddAction( "Delete" ).Triggered=Lambda()
-				
-					If Not RequestOkay( "Really delete file '"+path+"'?" ) return
-				
-					If DeleteFile( path )
-					
-						Local doc:=_docs.FindDocument( path )
-						
-						If doc doc.Close()
-					
-						browser.Refresh()
-						Return
-					Endif
 					
-					Alert( "Failed to delete file: '"+path+"'" )
+					DeleteItem( browser,path )
 				End
 				
 			Default
@@ -342,9 +334,47 @@ Class ProjectView Extends ScrollView
 	
 	Field _docs:DocumentManager
 	Field _docker:=New DockingView
-	Field _projects:=New StringMap<FileBrowserExt>
+	Global _projects:=New StringMap<FileBrowserExt>
 	Field _builder:IModuleBuilder
-
+	
+	Method DeleteItem( browser:ProjectBrowserView,path:String )
+		
+		Local work:=Lambda()
+			
+			If DirectoryExists( path )
+			
+				If Not RequestOkay( "Really delete folder '"+path+"'?" ) Return
+				
+				If DeleteDir( path,True )
+					browser.Refresh()
+					Return
+				Endif
+				
+				Alert( "Failed to delete folder '"+path+"'" )
+				
+			Else
+				
+				If Not RequestOkay( "Really delete file '"+path+"'?" ) Print "1111" ; Return
+				
+				If DeleteFile( path )
+				
+					Local doc:=_docs.FindDocument( path )
+				
+					If doc doc.Close()
+				
+					browser.Refresh()
+					Return
+				Endif
+				
+				Alert( "Failed to delete file: '"+path+"'" )
+				
+			Endif
+			
+		End
+		
+		New Fiber( work )
+	End
+	
 	Method OnOpenProject()
 	
 		Local dir:=MainWindow.RequestDir( "Select Project Directory...","" )
@@ -353,12 +383,29 @@ Class ProjectView Extends ScrollView
 		OpenProject( dir )
 	End
 	
-	Method OnOpenDocument( path:String )
+	Method OnOpenDocument( path:String,runExec:Bool=True )
 		
 		If GetFileType( path )=FileType.File
-		
+			
 			New Fiber( Lambda()
+				
+				Local ext:=ExtractExt( path )
+				Local exe:=(ext=".exe")
+				If runExec
+					If exe Or ext=".bat" Or ext=".sh"
+						Local s:="Do you want to execute this file?"
+						If Not exe s+="~nPress 'Cancel' to open file in editor."
+						If RequestOkay( s,StripDir( path ) )
+							OpenUrl( path )
+							Return
+						Endif
+					Endif
+				Endif
+				
+				If exe Return 'never open .exe
+				
 				_docs.OpenDocument( path,True )
+				
 			End )
 		
 		Endif

+ 22 - 0
view/SpacerView.monkey2

@@ -0,0 +1,22 @@
+
+Namespace ted2go
+
+
+Class SpacerView Extends View
+	
+	
+	Method New( width:Int,height:Int )
+		
+		Super.New()
+		
+		MinSize=New Vec2i( width,height )
+	End
+	
+	Protected
+	
+	Method OnMeasure:Vec2i() Override
+		
+		Return MinSize
+	End
+	
+End

+ 2 - 1
view/StatusBarView.monkey2

@@ -36,7 +36,8 @@ Class StatusBarView Extends DockingView
 		Local act:=New Action( Null,ThemeImages.Get( "cancel.png" ) )
 		act.Triggered=OnCancel
 		
-		_progressCancel=New ToolButtonExt( act,"" ) '"Stop process" )
+		_progressCancel=New ToolButtonExt( act,"" )
+		_progressCancel.Hint="Stop process"
 		_progressCancel.Style=GetStyle( "StatusBarButton" )
 		AddView( _progressCancel,"right" )
 		

+ 393 - 30
view/TabViewExt.monkey2

@@ -31,7 +31,7 @@ Class ScrollViewTabs Extends ScrollView
 End
 
 
-' full copy of mojox.TextView
+' full copy of mojox.TabView
 ' can't extend it, all I need is private there
 '
 Class TabViewExt Extends DockingView
@@ -62,7 +62,7 @@ Class TabViewExt Extends DockingView
 
 	#rem monkeydoc Creates a new tab view.
 	#end
-	Method New( flags:TabViewFlags=Null )
+	Method New( flags:TabViewFlags=TabViewFlags.DraggableTabs )
 	
 		_flags=flags
 		
@@ -71,28 +71,44 @@ Class TabViewExt Extends DockingView
 		_tabBar=New TabBar
 		
 		' add scrollbar here
-		Local topview:=New DockingView
+		Local headerDock:=New DockingView
+		
+		_prevNextDock=New DockingView
+		_prevNextDock.Visible=False
 		Local nxt:=New PushButton( ">" )
 		nxt.Style=App.Theme.GetStyle( "TabViewArrowNext" )
-		topview.AddView( nxt,"right" )
+		_prevNextDock.AddView( nxt,"right" )
 		
 		Local prev:=New PushButton( "<" )
 		prev.Style=App.Theme.GetStyle( "TabViewArrowPrev" )
-		topview.AddView( prev,"right" )
+		_prevNextDock.AddView( prev,"right" )
+		
+		headerDock.AddView( _prevNextDock,"right" )
 		
 		_scrollView=New ScrollViewTabs( _tabBar )
 		_scrollView.ScrollBarsVisible=False
-		topview.ContentView=_scrollView
-		AddView( topview,"top" )
+		headerDock.ContentView=_scrollView
+		AddView( headerDock,"top" )
 		
 		nxt.Clicked+=Lambda()
 			Local s:=_scrollView.Scroll
-			_scrollView.Scroll=s+New Vec2i( 200,0 )
+			_scrollView.Scroll=s+New Vec2i( 150,0 )
 		End
 		prev.Clicked+=Lambda()
 			Local s:=_scrollView.Scroll
-			_scrollView.Scroll=s-New Vec2i( 200,0 )
+			_scrollView.Scroll=s-New Vec2i( 150,0 )
 		End
+		
+		MinSize=New Vec2i( 50,50 )
+		
+		If Not _listener Then _listener=New DraggableTabsListener
+	End
+	
+	Function CreateDraggableTab:TabButtonExt( text:String,view:View,possibleParents:TabViewExt[],icon:Image=Null,closable:Bool=False )
+		
+		Local tab:=New TabButtonExt( text,icon,view,closable,Null )
+		tab.PossibleParentDocks=possibleParents
+		Return tab
 	End
 	
 	#rem monkeydoc Tab view flags.
@@ -118,7 +134,7 @@ Class TabViewExt Extends DockingView
 		Return -1
 		
 	Setter( currentIndex:Int )
-	
+		
 		MakeCurrent( _tabs[currentIndex],False )
 	End
 	
@@ -153,20 +169,46 @@ Class TabViewExt Extends DockingView
 
 		Return -1
 	End
-
+	
+	Property Tabs:TabButtonExt[]()
+		Return _tabs.ToArray()
+	End
+	
+	Property TabsNames:String[]()
+		
+		Local arr:=New String[NumTabs]
+		For Local i:=0 Until _tabs.Length
+			arr[i]=_tabs[i].Text
+		Next
+		Return arr
+	End
+	
+	Property ActiveName:String()
+		Return _current ? _current.Text Else ""
+	End
+	
 	#rem monkeydoc Adds a tab.
 	#end	
-	Method AddTab:Int( text:String,view:View,makeCurrent:Bool=False )
+	Method AddTab:TabButtonExt( text:String,view:View,makeCurrent:Bool=False )
 	
 		Return AddTab( text,Null,view,makeCurrent )
 	End
 
-	Method AddTab:Int( text:String,icon:Image,view:View,makeCurrent:Bool=False )
+	Method AddTab:TabButtonExt( text:String,icon:Image,view:View,makeCurrent:Bool=False )
+		
+		Local tab:=New TabButtonExt( text,icon,view,_flags & TabViewFlags.ClosableTabs,Self )
+		
+		AddTab( tab,makeCurrent )
+		
+		Return tab
+	End
 	
-		Assert( TabIndex( view )=-1,"View has already been added to TabView" )
+	Method AddTab( tab:TabButtonExt,makeCurrent:Bool=False )
 	
-		Local tab:=New TabButton( text,icon,view,_flags & TabViewFlags.ClosableTabs )
+		Assert( TabIndex( tab.View )=-1,"View has already been added to TabView" )
 		
+		TabButtonExt_Bridge.SetTabParent( tab,Self )
+	
 		tab.Clicked=Lambda()
 		
 			MakeCurrent( tab,True )
@@ -188,9 +230,9 @@ Class TabViewExt Extends DockingView
 			DoubleClicked()
 		End
 		
-		tab.Dragged+=Lambda( v:Vec2i )
+		tab.Dragged=Lambda( v:Vec2i )
 		
-			If Not (_flags & TabViewFlags.DraggableTabs) return
+			If Not (_flags & TabViewFlags.DraggableTabs) Return
 
 			Local mx:=_tabBar.MouseLocation.x
 			If mx<0 Return
@@ -241,21 +283,30 @@ Class TabViewExt Extends DockingView
 		
 		If makeCurrent MakeCurrent( tab,True ) 'CurrentIndex=index
 		
-		Return index
 	End
 	
 	#rem monkeydoc Removes a tab.
 	#end
 	Method RemoveTab( index:Int )
-	
-		If _current=_tabs[index]
+		
+		Local tab:=_tabs[index]
+		If _current=tab
 			_current.Selected=False
 			_current=Null
 			ContentView=Null
 		Endif
 		
-		_tabBar.RemoveView( _tabs[index] )
+		_tabBar.RemoveView( tab )
 		_tabs.Erase( index )
+		
+		tab.Clicked=Null
+		tab.RightClicked=Null
+		tab.DoubleClicked=Null
+		tab.Dragged=Null
+		tab.CloseClicked=Null
+		
+		If index>=NumTabs Then index-=1
+		If index>=0 Then CurrentIndex=index
 	End
 	
 	Method RemoveTab( view:View )
@@ -263,6 +314,11 @@ Class TabViewExt Extends DockingView
 		RemoveTab( TabIndex( view ) )
 	End
 	
+	Method RemoveTab( tab:TabButton )
+	
+		RemoveTab( TabIndex( tab.View ) )
+	End
+	
 	Method SetTabView( index:Int,view:View )
 	
 		_tabs[index].View=view
@@ -304,31 +360,102 @@ Class TabViewExt Extends DockingView
 		EnsureVisibleTab( _current )
 	End
 	
+	Method MakeCurrent( tabCaption:String )
+		
+		For Local t:=Eachin _tabs
+			If t.Text=tabCaption
+				MakeCurrent( t,True )
+				Return
+			Endif
+		Next
+	End
 	
-	Private
+	Method ShowDragPlaceHolder()
+		
+		_dragDropMode=True
+		_curIndex=CurrentIndex
+		_vis=Visible
+		Visible=True
+		If Not _placeHolderTab
+			Local v:=New Label ("[Drop tab here]")
+			v.Style=GetStyle( "TabsDropArea","Label" )
+			v.Layout="fill"
+			v.Gravity=New Vec2f( .5,.5 )
+			_placeHolderTab=AddTab( "[+]",v,True )
+			_placeHolderContent=v
+		Else
+			AddTab( _placeHolderTab,True )
+		Endif
+	End
 	
-	Field _flags:TabViewFlags
+	Method HideDragPlaceHolder()
+		
+		If Not _dragDropMode Return
+		
+		_dragDropMode=False
+		
+		RemoveTab( _placeHolderTab )
+		_placeHolderTab=Null
+'		
+		Visible=(_vis And NumTabs>0)
+		
+		If _curIndex>=0 Then CurrentIndex=_curIndex
+	End
 	
-	Field _tabBar:TabBar
 	
-	Field _tabs:=New Stack<TabButton>
+	Protected
 	
-	Field _current:TabButton
+	Method OnMeasure:Vec2i() Override
+		
+		Local size:=Super.OnMeasure()
+		' show / hide navigation buttons
+		Local ww:=GetTabsWidth()
+		Local vis:=(ww>Frame.Width)
+		_prevNextDock.Visible=vis
+		
+		Return size
+	End
 	
-	Field _scrollView:ScrollView
+	Method OnThemeChanged() Override
+		
+		If _placeHolderContent Then _placeHolderContent.Style=GetStyle( "TabsDropArea","Label" )
+	End
+	
+	
+	Private
 	
+	Field _flags:TabViewFlags
+	Field _tabBar:TabBar
+	Field _tabs:=New Stack<TabButtonExt>
+	Field _current:TabButtonExt
+	Field _scrollView:ScrollView
+	'Field _nxt:PushButton,_prev:PushButton
+	Field _placeHolderTab:TabButtonExt
+	Field _placeHolderContent:View
+	Field _prevNextDock:DockingView
+	Field _curIndex:Int
+	Field _dragDropMode:Bool
+	Field _vis:Bool
+	Global _listener:DraggableTabsListener
 	
-	Method MakeCurrent( tab:TabButton,notify:Bool )
+	Method MakeCurrent( tab:TabButtonExt,notify:Bool )
 	
 		If tab=_current Return
 		
-		If _current _current.Selected=False
+		Local prev:=_current
 		
 		ContentView=tab.View
 		
 		_current=tab
 		
-		If _current _current.Selected=True
+		If prev
+			prev.Selected=False
+			prev.ActiveChanged()
+		Endif
+		If _current
+			_current.Selected=True
+			_current.ActiveChanged()
+		Endif
 		
 		If notify CurrentChanged()
 		
@@ -340,6 +467,8 @@ Class TabViewExt Extends DockingView
 	
 		If Not tab Return
 		
+		MainWindow.UpdateWindow( False )
+		
 		Local scroll:=_scrollView.Scroll
 		Local xx:=GetTabPosX( tab )
 		Local L:=xx-scroll.x
@@ -367,4 +496,238 @@ Class TabViewExt Extends DockingView
 		Return xx
 	End
 	
+	Method GetTabsWidth:Int()
+	
+		Local xx:=0
+		For Local view:=Eachin _tabs
+			xx+=view.Frame.Width
+		Next
+		Return xx
+	End
+	
+End
+
+
+Class TabButtonExt Extends TabButton
+	
+	Field ActiveChanged:Void()
+	
+	Method New( text:String,icon:Image,view:View,closable:Bool,parentDock:TabViewExt )
+		
+		Super.New( text,icon,view,closable )
+		_parentDock=parentDock
+	End
+	
+	Property Detachable:Bool()
+		Return PossibleParentDocks<>Null
+	End
+	
+	Property ParentDock:TabViewExt()
+		Return _parentDock
+	End
+	
+	Property PossibleParentDocks:TabViewExt[]()
+		Return _possibleParentDocks
+	Setter( value:TabViewExt[] )
+		_possibleParentDocks=value
+	End
+	
+	Method Activate()
+		
+		Local dock:=ParentDock
+		If dock Then dock.MakeCurrent( Text )
+	End
+	
+	Method TryDropTo( tabDock:TabViewExt )
+		
+		If Not CanDropTo( tabDock )
+			tabDock=_parentDock
+		Endif
+		
+		_parentDock.Visible=(_parentDock.NumTabs>0)
+		_parentDock=tabDock
+		tabDock.AddTab( Self )
+		tabDock.Visible=True
+		
+		Activate()
+	End
+	
+	Property IsActive:Bool()
+		Return _parentDock.ActiveName=Text
+	End
+	
+	Method SetLockedState( locked:Bool )
+		
+		_locked=locked
+		OnThemeChanged()
+	End
+	
+	
+	Protected
+	
+	Field _parentDock:TabViewExt
+	
+	Method OnThemeChanged() Override
+		
+		Super.OnThemeChanged()
+		Style=GetStyle( _locked ? "TabButtonLocked" Else "TabButton" )
+	End
+	
+	
+	Private
+	
+	Field _possibleParentDocks:TabViewExt[]
+	Field _locked:Bool
+	
+	Method CanDropTo:Bool( tabDock:TabViewExt )
+	
+		If Not tabDock Print "if 1" ; Return False
+		If Not _possibleParentDocks Print "if 1" ; Return False
+	
+		For Local d:=Eachin _possibleParentDocks
+	
+			If d=tabDock Return True
+		Next
+		Print "false"
+		Return False
+	End
+	
+End
+
+
+Private 
+
+Class TabButtonExt_Bridge Extends TabButtonExt Abstract
+
+	Function SetTabParent( tab:TabButtonExt,parent:TabViewExt )
+		
+		tab._parentDock=parent
+	End
+	
+	Private
+	
+	Method New( text:String,icon:Image,view:View,closable:Bool,parentDock:TabViewExt )
+		
+		Super.New( text,icon,view,closable,parentDock )
+	End
+	
+	
+End
+
+
+Class DraggableTabsListener
+	
+	Method New()
+		
+		App.MouseEventFilter+=OnMouseEvent
+	End
+	
+	Private
+	
+	Global _label:Label
+	Global _tab:TabButtonExt
+	Global _pressedPos:Vec2i
+	Global _detached:Bool
+	
+	Function OnMouseEvent( event:MouseEvent )
+	
+		Select event.Type
+			
+			Case EventType.MouseDown
+				
+				_tab=Cast<TabButtonExt>( event.View )
+				If Not _tab Return
+				
+				If Not _tab.Detachable
+					_tab=Null
+					Return
+				Endif
+				
+				_pressedPos=Mouse.Location
+				
+			
+			Case EventType.MouseMove
+			
+				If Not _tab Return
+				
+				If _detached
+					Local r:=_tab.Frame
+					Local sz:=r.Size
+					r.TopLeft=Mouse.Location+New Vec2i( 0,-10 )
+					r.BottomRight=r.TopLeft+sz
+					_tab.Frame=r
+					App.RequestRender()
+					Return
+				Endif
+				
+				Local dy:Float=Abs(Mouse.Y-_pressedPos.y)
+				If dy>10.0*App.Theme.Scale.y
+					Detach()
+				Endif
+				
+				
+			Case EventType.MouseUp
+				
+				If Not _detached 
+					_tab=Null
+					Return
+				Endif
+				
+				MainWindow.RemoveChildView( _tab )
+				
+				Local dock:TabViewExt=Null
+				Local v:=App.ActiveViewAtMouseLocation()
+				While v
+					Local d:=Cast<TabViewExt>( v )
+					If d
+						dock=d
+						Exit
+					Endif
+					v=v.Parent
+				Wend
+				
+				If _tab.PossibleParentDocks
+					For Local d:=Eachin _tab.PossibleParentDocks
+						d.HideDragPlaceHolder()
+					Next
+				Endif
+				
+				_tab.TryDropTo( dock )
+				
+				_tab=Null
+				_detached=False
+			
+		End
+	
+	End
+	
+	Function Detach()
+		
+		_detached=True
+		
+'		If Not _label
+'			_label=New Label
+'			_label.Layout="float"
+'			_label.MaxSize=New Vec2i( 40,100 )
+'			MainWindow.AddChildView( _label )
+'		Endif
+'		_label.Text=_tab.Text
+'		_label.Visible=True
+		'Local size:=_label.MeasureLayoutSize()
+		'_label.Frame=New Recti( Mouse.Location,Mouse.Location+size)
+		
+		_tab.ParentDock.RemoveTab( _tab )
+		MainWindow.AddChildView( _tab )
+		_tab.Selected=True
+		
+		If Not _tab.PossibleParentDocks Return
+		
+		For Local d:=Eachin _tab.PossibleParentDocks
+			d.ShowDragPlaceHolder()
+		Next
+		
+	End
+	
+	
 End
+	

+ 36 - 0
view/TextFieldExt.monkey2

@@ -4,6 +4,25 @@ Namespace ted2go
 
 Class TextFieldExt Extends TextField 'Implements IKeyView
 	
+	Method New()
+		
+		Super.New()
+		CursorBlinkRate=2.5
+		BlockCursor=False
+	End
+	
+	Method New( maxLength:Int )
+		
+		Self.New()
+		MaxLength=maxLength
+	End
+	
+	Method New( text:String,maxLength:Int=80 )
+		
+		Self.New( maxLength )
+		Text=text
+	End
+	
 	Property NextView:TextFieldExt()
 		
 		Return _next
@@ -36,6 +55,15 @@ Class TextFieldExt Extends TextField 'Implements IKeyView
 		MakeKeyView()
 	End
 	
+	Protected
+	
+	Method OnMeasureContent:Vec2i() Override
+		
+		Local size:=Super.OnMeasureContent()
+		size=size+New Vec2i( 0,2 ) ' 2px to fix underline character '_' visibility
+		Return size
+	End
+	
 	Private
 	
 	Field _next:TextFieldExt,_prev:TextFieldExt
@@ -52,6 +80,14 @@ Class TextFieldExt Extends TextField 'Implements IKeyView
 				Return True
 			Endif
 		Endif
+		
+		If event.Key=Key.Enter Or event.Key=Key.KeypadEnter
+			If event.Type=EventType.KeyDown
+				Entered()
+			Endif
+			Return True
+		Endif
+		
 		Return False
 	End
 	

+ 4 - 4
view/ToolBarViewExt.monkey2

@@ -47,10 +47,6 @@ Class ToolButtonExt Extends ToolButton
 		
 		UpdateColors()
 		
-		App.ThemeChanged+=Lambda()
-			UpdateColors()
-		End
-		
 		Clicked+=Lambda()
 			If ToggleMode Then IsToggled=Not IsToggled
 		End
@@ -82,6 +78,10 @@ Class ToolButtonExt Extends ToolButton
 		
 	Protected
 	
+	Method OnThemeChanged() Override
+		UpdateColors()
+	End
+	
 	Method OnMouseEvent( event:MouseEvent ) Override
 		
 		If _hint <> Null

+ 8 - 0
view/TreeViewExt.monkey2

@@ -11,6 +11,12 @@ Class TreeViewExt Extends TreeView
 		
 		NodeClicked+=Lambda( node:TreeView.Node )
 			Selected=node
+			Self.MakeKeyView()
+		End
+		
+		NodeRightClicked+=Lambda( node:TreeView.Node )
+			Selected=node
+			Self.MakeKeyView()
 		End
 		
 		_selColor=App.Theme.GetColor( "panel" )
@@ -29,6 +35,8 @@ Class TreeViewExt Extends TreeView
 		SelectedChanged( _sel )
 		
 		EnsureVisible( _sel )
+		
+		RequestRender()
 	End
 	
 	Method FindSubNode:TreeView.Node( text:String,whereNode:TreeView.Node,recursive:Bool=False )

+ 32 - 0
view/ViewExtensions.monkey2

@@ -0,0 +1,32 @@
+
+Namespace ted2go
+
+
+Class View Extension
+	
+	Method GetStyle:Style( styleName:String,parentStyleName:String )
+		
+		Local st:=Self.GetStyle( styleName )
+		If Not st Then st=Self.GetStyle( parentStyleName )
+		
+		Return st
+	End
+	
+End
+
+Class TextView Extension
+	
+	Method MakeCentered()
+	
+		' scroll to view center
+		Local yy:=CursorRect.Top-Scroll.y
+		Local dy:=yy-Frame.Height*.5
+		Scroll=Scroll+New Vec2i( 0,dy )
+	End
+	
+	Method SelectText( anchor:Int,cursor:Int,makeCentered:Bool )
+	
+		SelectText( anchor,cursor )
+		If makeCentered Then MakeCentered()
+	End
+End