Prechádzať zdrojové kódy

Merge commit '25374fc18baa31508f87790e667c222935d76699' into develop

Mark Sibly 8 rokov pred
rodič
commit
cb38033acb
100 zmenil súbory, kde vykonal 1613 pridanie a 323 odobranie
  1. 158 0
      src/ted2go/LiveTemplates.monkey2
  2. 147 35
      src/ted2go/MainWindow.monkey2
  3. 7 0
      src/ted2go/Prefs.monkey2
  4. 8 7
      src/ted2go/Ted2.monkey2
  5. 25 17
      src/ted2go/action/BuildActions.monkey2
  6. 23 21
      src/ted2go/action/FileActions.monkey2
  7. 226 86
      src/ted2go/action/FindActions.monkey2
  8. 10 3
      src/ted2go/action/HelpActions.monkey2
  9. 9 3
      src/ted2go/assets/aboutTed2Go.html
  10. 9 0
      src/ted2go/assets/gen/newClass.txt
  11. 30 0
      src/ted2go/assets/liveTemplates.json
  12. BIN
      src/ted2go/assets/themes/cancel.png
  13. BIN
      src/ted2go/assets/themes/codeicons/alias.png
  14. BIN
      src/ted2go/assets/themes/codeicons/annotation.png
  15. BIN
      src/ted2go/assets/themes/codeicons/code_template.png
  16. BIN
      src/ted2go/assets/themes/codeicons/const.png
  17. BIN
      src/ted2go/assets/themes/codeicons/keyword.png
  18. BIN
      src/ted2go/assets/themes/codeicons/operator.png
  19. BIN
      src/ted2go/assets/themes/codeicons/other.png
  20. BIN
      src/ted2go/assets/themes/codeicons/property.png
  21. BIN
      src/ted2go/assets/themes/codeicons/property_private.png
  22. BIN
      src/ted2go/assets/themes/codeicons/property_protected.png
  23. BIN
      src/ted2go/assets/themes/debug_icons.png
  24. BIN
      src/ted2go/assets/themes/docbar/back.png
  25. BIN
      src/ted2go/assets/themes/docbar/forward.png
  26. BIN
      src/ted2go/assets/themes/docbar/home.png
  27. BIN
      src/ted2go/assets/themes/hollow_assets/checkbox_icons.png
  28. BIN
      src/ted2go/assets/themes/hollow_assets/dialog_skin.png
  29. BIN
      src/ted2go/assets/themes/hollow_assets/progressbar_icons.png
  30. BIN
      src/ted2go/assets/themes/hollow_assets/tabclose_icons.png
  31. BIN
      src/ted2go/assets/themes/hollow_assets/treeview_icons.png
  32. BIN
      src/ted2go/assets/themes/irc/blink.png
  33. BIN
      src/ted2go/assets/themes/irc/important.png
  34. BIN
      src/ted2go/assets/themes/irc/notice.png
  35. BIN
      src/ted2go/assets/themes/outputbar/clean.png
  36. BIN
      src/ted2go/assets/themes/outputbar/wrap.png
  37. BIN
      src/ted2go/assets/themes/prime_assets/checkbox_icons.png
  38. BIN
      src/ted2go/assets/themes/prime_assets/dialog_skin.png
  39. BIN
      src/ted2go/assets/themes/prime_assets/progressbar_icons.png
  40. BIN
      src/ted2go/assets/themes/prime_assets/tabclose_icons.png
  41. BIN
      src/ted2go/assets/themes/prime_assets/treeview_icons.png
  42. BIN
      src/ted2go/assets/themes/progressbar_icons.png
  43. BIN
      src/ted2go/assets/themes/project/package.png
  44. BIN
      src/ted2go/assets/themes/smooth_assets/button_skin.png
  45. BIN
      src/ted2go/assets/themes/smooth_assets/checkbox_icons.png
  46. BIN
      src/ted2go/assets/themes/smooth_assets/dialog_skin.png
  47. BIN
      src/ted2go/assets/themes/smooth_assets/progressbar_icons.png
  48. BIN
      src/ted2go/assets/themes/smooth_assets/tabbutton_selected_skin.png
  49. BIN
      src/ted2go/assets/themes/smooth_assets/tabbutton_skin.png
  50. BIN
      src/ted2go/assets/themes/smooth_assets/tabclose_icons.png
  51. BIN
      src/ted2go/assets/themes/smooth_assets/treeview_icons.png
  52. BIN
      src/ted2go/assets/themes/sourcebar/filter_inherited.png
  53. BIN
      src/ted2go/assets/themes/sourcebar/sort_alpha.png
  54. 25 3
      src/ted2go/assets/themes/ted2-default.json
  55. 7 1
      src/ted2go/assets/themes/theme-hollow.json
  56. 7 1
      src/ted2go/assets/themes/theme-prime-base.json
  57. BIN
      src/ted2go/assets/themes/toolbar/back.png
  58. BIN
      src/ted2go/assets/themes/toolbar/build.png
  59. BIN
      src/ted2go/assets/themes/toolbar/check.png
  60. BIN
      src/ted2go/assets/themes/toolbar/copy.png
  61. BIN
      src/ted2go/assets/themes/toolbar/cut.png
  62. BIN
      src/ted2go/assets/themes/toolbar/debug.png
  63. BIN
      src/ted2go/assets/themes/toolbar/find.png
  64. BIN
      src/ted2go/assets/themes/toolbar/forward.png
  65. BIN
      src/ted2go/assets/themes/toolbar/navigate_back.png
  66. BIN
      src/ted2go/assets/themes/toolbar/navigate_forward.png
  67. BIN
      src/ted2go/assets/themes/toolbar/new_file.png
  68. BIN
      src/ted2go/assets/themes/toolbar/open_file.png
  69. BIN
      src/ted2go/assets/themes/toolbar/open_project.png
  70. BIN
      src/ted2go/assets/themes/toolbar/options.png
  71. BIN
      src/ted2go/assets/themes/toolbar/paste.png
  72. BIN
      src/ted2go/assets/themes/toolbar/paypal.png
  73. BIN
      src/ted2go/assets/themes/toolbar/redo.png
  74. BIN
      src/ted2go/assets/themes/toolbar/run.png
  75. BIN
      src/ted2go/assets/themes/toolbar/save.png
  76. BIN
      src/ted2go/assets/themes/toolbar/save_all.png
  77. BIN
      src/ted2go/assets/themes/toolbar/save_all_dirty.png
  78. BIN
      src/ted2go/assets/themes/toolbar/save_dirty.png
  79. BIN
      src/ted2go/assets/themes/toolbar/undo.png
  80. BIN
      src/ted2go/assets/themes/toolbar/zoom_in.png
  81. BIN
      src/ted2go/assets/themes/toolbar/zoom_out.png
  82. 19 6
      src/ted2go/dialog/FindDialog.monkey2
  83. 186 0
      src/ted2go/dialog/GenerateClassDialog.monkey2
  84. 66 0
      src/ted2go/dialog/LiveTemplatesDialog.monkey2
  85. 186 1
      src/ted2go/dialog/PrefsDialog.monkey2
  86. 0 4
      src/ted2go/dialog/UpdateModulesDialog.monkey2
  87. 54 10
      src/ted2go/document/CodeDocument.monkey2
  88. 5 1
      src/ted2go/product/ModuleManager.monkey2
  89. 10 0
      src/ted2go/utils/JsonUtils.monkey2
  90. 18 0
      src/ted2go/utils/Utils.monkey2
  91. 99 21
      src/ted2go/view/AutocompleteView.monkey2
  92. 21 0
      src/ted2go/view/BuildErrorListViewItem.monkey2
  93. 24 37
      src/ted2go/view/CodeMapView.monkey2
  94. 24 4
      src/ted2go/view/CodeTextView.monkey2
  95. 77 45
      src/ted2go/view/CodeTreeView.monkey2
  96. 9 0
      src/ted2go/view/FileBrowserExt.monkey2
  97. 1 0
      src/ted2go/view/IRCView.monkey2
  98. 36 6
      src/ted2go/view/ListViewExt.monkey2
  99. 38 11
      src/ted2go/view/ProjectView.monkey2
  100. 49 0
      src/ted2go/view/Ted2CodeTextView.monkey2

+ 158 - 0
src/ted2go/LiveTemplates.monkey2

@@ -0,0 +1,158 @@
+
+Namespace ted2go
+
+
+#Import "assets/liveTemplates.json"
+
+Const LiveTemplates:=New LiveTemplatesClass
+
+Class LiveTemplatesClass
+	
+	Field DataChanged:Void( lang:String )
+	
+	Method Load()
+		
+		' merge two files
+		Load( DefaultPath )
+		Load( CustomPath )
+	End
+	
+	Method Save()
+		
+		If Not _dirty Return
+		
+		_dirty=False
+		NotifyDataChanged()
+		
+		Local json:=New JsonObject
+		
+		For Local map:=Eachin _items.All()
+			Local obj:=New JsonObject
+			json[map.Key]=obj
+			For Local i:=Eachin map.Value.All()
+				obj[i.Key]=New JsonString( i.Value )
+			Next
+		Next
+		
+		Local txt:=json.ToJson()
+		SaveString( txt,DefaultPath )
+		SaveString( txt,CustomPath )
+	End
+	
+	Operator []:StringMap<String>( fileType:String )
+	
+		Return _items[fileType]
+	End
+		
+	Operator []:String( fileType:String,name:String )
+	
+		Local map:=_items[fileType]
+		Return map ? map[name] Else Null
+	End
+	
+	Operator []=( fileType:String,name:String,value:String )
+	
+		Local map:=_items[fileType]
+		If map
+			map[name]=value
+			OnChanged( fileType )
+		Endif
+	End
+	
+	Method All:StringMap<StringMap<String>>.Iterator()
+	
+		Return _items.All()
+	End
+	
+	Method All:StringMap<String>.Iterator( fileType:String )
+		
+		Local map:=_items[fileType]
+		Return map ? map.All() Else Null
+	End
+	
+	Method Add( fileType:String,name:String,value:String )
+	
+		Local map:=_items[fileType]
+		If map 
+			map[name]=value
+			OnChanged( fileType )
+		Endif
+	End
+	
+	Method Remove( fileType:String,name:String )
+	
+		Local map:=_items[fileType]
+		If map
+			map.Remove( name )
+			OnChanged( fileType )
+		Endif
+	End
+	
+	
+	Private
+	
+	Field _items:=New StringMap<StringMap<String>>
+	Field _dirty:Bool
+	
+	Property DefaultPath:String()
+		Return "asset::liveTemplates.json"
+	End
+	
+	Property CustomPath:String()
+		Return Prefs.IdeHomeDir+"customTemplates.json"
+	End
+	
+	Method Load( jsonPath:String )
+		
+		If Not FileExists( jsonPath ) Return
+			
+		Local langs:=Json_LoadObject( jsonPath ).All()
+		For Local i:=Eachin langs
+			Local lang:=i.Key
+			Local map:=New StringMap<String>
+			_items[lang]=map
+			Local all:=i.Value.ToObject().All()
+			For Local j:=Eachin all
+				map[j.Key]=j.Value.ToString().Replace( "~r~n","~n" ).Replace( "~r","~n" )
+			Next
+		Next
+		NotifyDataChanged()
+	End
+	
+	Method OnChanged( lang:String )
+		
+		_dirty=True
+	End
+	
+	Method NotifyDataChanged()
+	
+		For Local it:=Eachin All()
+			DataChanged( it.Key )
+		Next
+	End
+	
+End
+
+
+Class TemplateListViewItem Extends ListViewItem
+	
+	Field name:String
+	Field value:String
+	
+	Method New( name:String,value:String )
+		
+		Super.New( GetCaption( name,value ) )
+		
+		Self.name=name
+		Self.value=value
+	End
+	
+	
+	Private
+	
+	Method GetCaption:String( name:String,value:String )
+		
+		Local s:=value.Replace( "~n"," ... " ).Replace( "~t","" ).Replace( "${Cursor}","" )
+		Return name+"   "+s
+	End
+End

+ 147 - 35
src/ted2go/MainWindow.monkey2

@@ -13,6 +13,7 @@ Namespace ted2go
 
 #Import "assets/themes/irc/@/themes/irc"
 
+
 Global MainWindow:MainWindowInstance
 
 Class MainWindowInstance Extends Window
@@ -27,6 +28,8 @@ Class MainWindowInstance Extends Window
 		
 		UpdateToolsPaths()
 		
+		LiveTemplates.Load()
+		
 		_docsTabView=New TabViewExt( TabViewFlags.DraggableTabs|TabViewFlags.ClosableTabs )
 		
 		_browsersTabView=New TabView( TabViewFlags.DraggableTabs )
@@ -41,7 +44,11 @@ Class MainWindowInstance Extends Window
 		
 		_docsManager=New DocumentManager( _docsTabView,_docBrowser )
 
-		_docsManager.CurrentDocumentChanged+=UpdateKeyView
+		_docsManager.CurrentDocumentChanged+=Lambda()
+			
+			UpdateKeyView()
+			CodeDocument.HideAutocomplete()
+		End
 		
 		App.FileDropped+=Lambda( path:String )
 			_docsManager.OpenDocument( path,True )
@@ -79,16 +86,6 @@ Class MainWindowInstance Extends Window
 		Local bar:=New ToolBarExt
 		bar.MaxSize=New Vec2i( 300,30 )
 		
-		bar.AddIconicButton(
-			ThemeImages.Get( "outputbar/clean.png" ),
-			Lambda()
-				_outputConsole.ClearAll()
-			End,
-			"Clear all" )
-		
-		'bar.AddSeparator()
-		'bar.AddSeparator()
-			
 		Local label:=New Label( "Filter:" )
 		bar.AddView( label,"left" )
 		Local editFilter:=New TextField()
@@ -102,6 +99,23 @@ Class MainWindowInstance Extends Window
 			_outputConsole.SetFilter( t )
 		End
 		
+		bar.AddSeparator()
+		
+		bar.AddIconicButton(
+			ThemeImages.Get( "outputbar/clean.png" ),
+			Lambda()
+				_outputConsole.ClearAll()
+			End,
+			"Clear all" )
+		
+		Local it:=bar.AddIconicButton(
+			ThemeImages.Get( "outputbar/wrap.png" ),
+			Lambda()
+				_outputConsole.WordWrap=Not _outputConsole.WordWrap
+			End,
+			"Word wrap" )
+		it.ToggleMode=True
+		
 		_outputConsoleView=New DockingView
 		_outputConsoleView.AddView( bar,"top" )
 		_outputConsoleView.ContentView=_outputConsole
@@ -174,16 +188,23 @@ Class MainWindowInstance Extends Window
 		
 		
 		_buildActions=New BuildActions( _docsManager,_buildConsole,_debugView )
+		_buildActions.ErrorsOccured+=Lambda( errors:BuildError[] )
+			ShowBuildConsole( True )
+			_buildActions.GotoError( errors[0] )
+			
+			_buildErrorsList.Clear()
+			For Local err:=Eachin errors
+				_buildErrorsList.AddItem( New BuildErrorListViewItem( err ) )
+			Next
+			_buildErrorsList.Visible=True
+		End
 		
 		_projectView=New ProjectView( _docsManager,_buildActions )
 		_projectView.ProjectOpened+=Lambda( dir:String )
 			AddRecentProject( dir )
 			SaveState()
 		End
-		_projectView.ProjectClosed+=Lambda( dir:String )
-			UpdateCloseProjectMenu( dir )
-			SaveState()
-		End
+		_projectView.ProjectClosed+=OnProjectClosed
 		
 		_fileActions=New FileActions( _docsManager )
 		_editActions=New EditActions( _docsManager )
@@ -299,7 +320,8 @@ Class MainWindowInstance Extends Window
 		_forceStop.HotKeyModifiers=Modifier.Shift
 		
 		'
-		_buildActions.PreBuild+=OnForceStop
+		_buildActions.PreBuild+=OnPreBuild
+		_buildActions.PreSemant+=OnPreSemant
 		
 		_buildMenu=New MenuExt( "Build" )
 		_buildMenu.AddAction( _buildActions.buildAndRun )
@@ -366,7 +388,18 @@ Class MainWindowInstance Extends Window
 		_browsersTabView.AddTab( "Debug",_debugView,False )
 		_browsersTabView.AddTab( "Help",_helpTree,False )
 		
-		_consolesTabView.AddTab( "Build",_buildConsole,True )
+		_buildErrorsList=New ListViewExt
+		_buildErrorsList.Visible=False
+		_buildErrorsList.OnItemChoosen+=Lambda()
+			Local item:=Cast<BuildErrorListViewItem>( _buildErrorsList.CurrentItem )
+			_buildActions.GotoError( item.error )
+		End
+		
+		_buildConsoleView=New DockingView
+		_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 )
@@ -645,6 +678,7 @@ Class MainWindowInstance Extends Window
 		'
 		Local newTitle:=GetActionTextWithShortcut( _fileActions.new_ )
 		Local openTitle:=GetActionTextWithShortcut( _fileActions.open )
+		Local saveTitle:=GetActionTextWithShortcut( _fileActions.save )
 		Local saveAllTitle:=GetActionTextWithShortcut( _fileActions.saveAll )
 		Local undoTitle:=GetActionTextWithShortcut( _editActions.undo )
 		Local redoTitle:=GetActionTextWithShortcut( _editActions.redo )
@@ -653,15 +687,36 @@ Class MainWindowInstance Extends Window
 		Local checkTitle:=GetActionTextWithShortcut( _buildActions.semant )
 		Local findTitle:=GetActionTextWithShortcut( _findActions.find )
 		Local debugTitle:=GetActionTextWithShortcut( _buildActions.debugApp )
+		Local cutTitle:=GetActionTextWithShortcut( _editActions.cut )
+		Local copyTitle:=GetActionTextWithShortcut( _editActions.copy )
+		Local pasteTitle:=GetActionTextWithShortcut( _editActions.paste )
 		
 		_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.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..." )
-		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/save_all.png" ),_fileActions.saveAll.Triggered,saveAllTitle )
+		Local icons:=New Image[]( ThemeImages.Get( "toolbar/save.png" ),ThemeImages.Get( "toolbar/save_dirty.png" ) )
+		_saveItem=_toolBar.AddIconicButton( icons,_fileActions.save.Triggered,saveTitle )
+		icons=New Image[]( ThemeImages.Get( "toolbar/save_all.png" ),ThemeImages.Get( "toolbar/save_all_dirty.png" ) )
+		_saveAllItem=_toolBar.AddIconicButton( icons,_fileActions.saveAll.Triggered,saveAllTitle )
+		_toolBar.AddSeparator()
+		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/cut.png" ),_editActions.cut.Triggered,cutTitle )
+		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/copy.png" ),_editActions.copy.Triggered,copyTitle )
+		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/paste.png" ),_editActions.paste.Triggered,pasteTitle )
 		_toolBar.AddSeparator()
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/undo.png" ),_editActions.undo.Triggered,undoTitle )
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/redo.png" ),_editActions.redo.Triggered,redoTitle )
@@ -678,17 +733,6 @@ Class MainWindowInstance Extends Window
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/options.png" ),act,"Target settings" )
 		_toolBar.AddSeparator()
 		_toolBar.AddIconicButton( ThemeImages.Get( "toolbar/find.png" ),_findActions.find.Triggered,findTitle )
-		_toolBar.AddSeparator()
-		
-		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)" )
 		
 		Return _toolBar
 	End
@@ -728,7 +772,7 @@ Class MainWindowInstance Extends Window
 	Method ShowBuildConsole( vis:Bool=True )
 		
 		If vis _consolesTabView.Visible=True
-		_consolesTabView.CurrentView=_buildConsole
+		_consolesTabView.CurrentView=_buildConsoleView
 	End
 	
 	Method ShowOutputConsole( vis:Bool=True )
@@ -820,6 +864,21 @@ Class MainWindowInstance Extends Window
 		_helpView.Scroll=New Vec2i( 0,0 )
 	End
 	
+	Method ShowEditorMenu( tv:TextView )
+		
+		If Not tv Then tv=_docsManager.CurrentTextView
+		If Not tv Return
+		
+		If Not _editorMenu
+			_editorMenu=New MenuExt
+			_editorMenu.AddAction( _editActions.cut )
+			_editorMenu.AddAction( _editActions.copy )
+			_editorMenu.AddAction( _editActions.paste )
+		Endif
+		
+		_editorMenu.Open()
+	End
+	
 	Method UpdateHelpTree()
 		_helpTree.Update()
 	End
@@ -994,6 +1053,32 @@ Class MainWindowInstance Extends Window
 		_fileActions.quit.Trigger()
 	End
 	
+	Method OnPreBuild()
+		
+		OnForceStop()
+		_buildErrorsList.Visible=False
+	End
+	
+	Method OnPreSemant()
+	
+		_buildErrorsList.Visible=False
+	End
+	
+	Method OnProjectClosed( dir:String )
+		
+		UpdateCloseProjectMenu( dir )
+		
+		Local list:=New Stack<Ted2Document>
+		' close all related files
+		For Local doc:=Eachin _docsManager.OpenDocuments
+			If doc.Path.StartsWith( dir ) Then list.Add( doc )
+		Next
+		
+		_fileActions.CloseFiles( list.ToArray() )
+		
+		SaveState()
+	End
+	
 	Method OnResized()
 		
 		' just set a flag here.
@@ -1020,21 +1105,41 @@ Class MainWindowInstance Extends Window
 	End
 	
 	Method OnChatClicked()
+		
 		If _consolesTabView.CurrentView<>_ircView Then Return
 		
 		_consolesTabView.SetTabIcon( _ircView, Null )
+		
 		_ircNotifyIcon=0
+		
+		HideHint()
+		
 	End
 	
 	Method OnChatMessage( message:IRCMessage, container:IRCMessageContainer, server:IRCServer )
+		
 		If message.type<>"PRIVMSG" Or _consolesTabView.CurrentView=_ircView Then Return
 		
 		'Show notice icon
 		If message.text.Contains(server.nickname) Then
-			If _ircNotifyIcon<=1 Then _ircNotifyIcon=2
-	
+			
+			If _ircNotifyIcon<=1 Then
+				
+				_ircNotifyIcon=2
+				
+				Local mentionStr:String
+				mentionStr=server.nickname+" was mentioned by "
+				mentionStr+=message.fromUser+" in "
+				mentionStr+=container.name
+				
+				ShowHint( mentionStr, New Vec2i( 0, -GetStyle( "Hint" ).Font.Height*4 ), _consolesTabView, 20000 )
+				
+			Endif
+			
 		Else
+			
 			If _ircNotifyIcon<=0 Then _ircNotifyIcon=1
+			
 		Endif
 		
 	End
@@ -1166,6 +1271,8 @@ Class MainWindowInstance Extends Window
 	Field _modsDir:String
 	
 	Field _toolBar:ToolBarExt
+	Field _saveItem:MultiIconToolButton
+	Field _saveAllItem:MultiIconToolButton
 	Field _docsManager:DocumentManager
 	Field _fileActions:FileActions
 	Field _editActions:EditActions
@@ -1176,6 +1283,8 @@ Class MainWindowInstance Extends Window
 	
 	Field _ircView:IRCView
 	Field _buildConsole:ConsoleExt
+	Field _buildErrorsList:ListViewExt
+	Field _buildConsoleView:DockingView
 	Field _outputConsole:ConsoleExt
 	Field _outputConsoleView:DockingView
 	Field _helpView:HtmlViewExt
@@ -1207,7 +1316,7 @@ Class MainWindowInstance Extends Window
 	Field _windowMenu:MenuExt
 	Field _helpMenu:MenuExt
 	Field _menuBar:MenuBarExt
-	
+	Field _editorMenu:MenuExt
 	Field _themesMenu:MenuExt
 	
 	Field _theme:="default"
@@ -1404,6 +1513,9 @@ Class MainWindowInstance Extends Window
 		
 		_forceStop.Enabled=_buildConsole.Running Or _outputConsole.Running
 	
+		_saveItem.SetIcon( _fileActions.save.Enabled ? 1 Else 0 )
+		_saveAllItem.SetIcon( _fileActions.saveAll.Enabled ? 1 Else 0 )
+		
 		App.Idle+=OnAppIdle
 		
 		GCCollect()	'thrash that GC!
@@ -1414,7 +1526,7 @@ Class MainWindowInstance Extends Window
 		Select _consolesTabView.CurrentView
 			Case _outputConsoleView
 				Return "output"
-			Case _buildConsole
+			Case _buildConsoleView
 				Return "build"
 			Case _helpConsole
 				Return "docs"
@@ -1431,7 +1543,7 @@ Class MainWindowInstance Extends Window
 			Case "output"
 				view=_outputConsoleView
 			Case "build"
-				view=_buildConsole
+				view=_buildConsoleView
 			Case "docs"
 				view=_helpConsole
 			Case "find"

+ 7 - 0
src/ted2go/Prefs.monkey2

@@ -13,6 +13,7 @@ Class Prefs
 	Global AcUseDot:=False
 	Global AcNewLineByEnter:=True
 	Global AcStrongFirstChar:=True
+	Global AcUseLiveTemplates:=True
 	'
 	Global MainToolBarVisible:=True
 	Global MainProjectTabsRight:=True
@@ -37,6 +38,7 @@ Class Prefs
 	Global SourceShowInherited:=False
 	'
 	Global MonkeyRootPath:String
+	Global IdeHomeDir:String
 	
 	Function LoadState( json:JsonObject )
 		
@@ -71,6 +73,7 @@ Class Prefs
 			AcUseSpace=Json_GetBool( j2,"useSpace",AcUseSpace )
 			AcUseDot=Json_GetBool( j2,"useDot",AcUseDot )
 			AcNewLineByEnter=Json_GetBool( j2,"newLineByEnter",AcNewLineByEnter )
+			AcUseLiveTemplates=Json_GetBool( j2,"useLiveTemplates",AcUseLiveTemplates )
 			
 		Endif
 		
@@ -123,6 +126,7 @@ Class Prefs
 		j["useSpace"]=New JsonBool( AcUseSpace )
 		j["useDot"]=New JsonBool( AcUseDot )
 		j["newLineByEnter"]=New JsonBool( AcNewLineByEnter )
+		j["useLiveTemplates"]=New JsonBool( AcUseLiveTemplates )
 		
 		j=New JsonObject
 		json["editor"]=j
@@ -144,6 +148,9 @@ Class Prefs
 	
 	Function LoadLocalState()
 		
+		IdeHomeDir=HomeDir()+"Ted2Go/"
+		CreateDir( IdeHomeDir )
+		
 		Local json:=JsonObject.Load( AppDir()+"state.json" )
 		If Not json Return
 		

+ 8 - 7
src/ted2go/Ted2.monkey2

@@ -34,6 +34,8 @@
 #Import "dialog/NoTitleDialog"
 #Import "dialog/FindInFilesDialog"
 #Import "dialog/UpdateModulesDialog"
+#Import "dialog/GenerateClassDialog"
+#Import "dialog/LiveTemplateDialog"
 
 #Import "document/DocumentManager"
 #Import "document/Ted2Document"
@@ -93,18 +95,22 @@
 #Import "view/ProjectView"
 #Import "view/HelpTreeView"
 #Import "view/Ted2TextView"
+#Import "view/Ted2CodeTextView"
 #Import "view/JsonTreeView"
 #Import "view/XmlTreeView"
 #Import "view/Monkey2TreeView"
 #Import "view/GutterView"
 #Import "view/MenuExt"
 #Import "view/ScrollableViewExt"
+#Import "view/BuildErrorListViewItem"
+#Import "view/TextFieldExt"
 
-#Import "MainWindow"
 #Import "Plugin"
 #Import "ThemeImages"
 #Import "Prefs"
 #Import "ProcessReader"
+#Import "LiveTemplates"
+#Import "MainWindow"
 
 
 Namespace ted2go
@@ -117,7 +123,7 @@ Using tinyxml2..
 
 Const MONKEY2_DOMAIN:="http://monkeycoder.co.nz"
 
-Global AppTitle:="Ted2Go v2.4"
+Global AppTitle:="Ted2Go v2.5"
 
 
 Function Main()
@@ -231,11 +237,6 @@ Function GetActionTextWithShortcut:String( action:Action )
 	Return action.Text+" ("+action.HotKeyText+")"
 End
 
-Function IsFileExists:Bool( path:String )
-	
-	Return GetFileType( path ) = FileType.File
-End
-
 Function Exec( exePath:String,args:String="" )
 
 #If __HOSTOS__="windows"

+ 25 - 17
src/ted2go/action/BuildActions.monkey2

@@ -48,6 +48,8 @@ Class BuildActions Implements IModuleBuilder
 	
 	
 	Field PreBuild:Void()
+	Field PreSemant:Void()
+	Field ErrorsOccured:Void(errors:BuildError[])
 	
 	Method New( docs:DocumentManager,console:ConsoleExt,debugView:DebugView )
 	
@@ -326,6 +328,19 @@ Class BuildActions Implements IModuleBuilder
 		Return result
 	End
 	
+	Method GotoError( err:BuildError )
+	
+		Local doc:=Cast<CodeDocument>( _docs.OpenDocument( err.path,True ) )
+		If Not doc Return
+	
+		Local tv := doc.TextView
+		If Not tv Return
+	
+		MainWindow.UpdateWindow( False )
+	
+		tv.GotoLine( err.line )
+	End
+	
 	
 	Private
 	
@@ -379,19 +394,6 @@ Class BuildActions Implements IModuleBuilder
 
 	End
 
-	Method GotoError( err:BuildError )
-	
-		Local doc:=Cast<CodeDocument>( _docs.OpenDocument( err.path,True ) )
-		If Not doc Return
-		
-		Local tv := doc.TextView
-		If Not tv Return
-		
-		MainWindow.UpdateWindow( False )
-		
-		tv.GotoLine( err.line )
-	End
-	
 	Method BuildMx2:Bool( cmd:String,progressText:String,action:String="build",showElapsedTime:Bool=False )
 	
 		ClearErrors()
@@ -445,10 +447,10 @@ Class BuildActions Implements IModuleBuilder
 						
 						If doc
 							doc.AddError( err )
-							If _errors.Empty 
-								MainWindow.ShowBuildConsole( True )
-								GotoError( err )
-							Endif
+							'If _errors.Empty
+							'	MainWindow.ShowBuildConsole( True )
+							'	GotoError( err )
+							'Endif
 							_errors.Add( err )
 						Endif
 						
@@ -465,6 +467,10 @@ Class BuildActions Implements IModuleBuilder
 		
 		Forever
 		
+		If Not _errors.Empty
+			ErrorsOccured( _errors.ToArray() )
+		Endif
+		
 		MainWindow.HideStatusBarProgress()
 		
 		Local status:=hasErrors ? "{0} failed. See the build console for details." Else (_console.ExitCode=0 ? "{0} finished." Else "{0} cancelled.")
@@ -591,6 +597,8 @@ Class BuildActions Implements IModuleBuilder
 	
 	Method OnSemant()
 	
+		PreSemant()
+		
 		If _console.Running Return
 	
 		BuildApp( _buildConfig,_buildTarget,"semant" )

+ 23 - 21
src/ted2go/action/FileActions.monkey2

@@ -20,7 +20,7 @@ Class FileActions
 	
 		_docs=docs
 		
-		new_=New Action( "New" )
+		new_=New Action( "New file" )
 #if __TARGET__="macos"
 		new_.HotKey=Key.T
 		new_.HotKeyModifiers=Modifier.Menu
@@ -30,7 +30,7 @@ Class FileActions
 #endif
 		new_.Triggered=OnNew
 		
-		open=New Action( "Open" )
+		open=New Action( "Open file" )
 		open.HotKey=Key.O
 		open.HotKeyModifiers=Modifier.Menu
 		open.Triggered=OnOpen
@@ -47,7 +47,9 @@ Class FileActions
 		closeToRight.Triggered=OnCloseToRight
 		
 		closeAll=New Action( "Close all tabs" )
-		closeAll.Triggered=OnCloseAll
+		closeAll.Triggered=Lambda()
+			CloseFiles( _docs.OpenDocuments )
+		End
 		
 		save=New Action( "Save" )
 		save.HotKey=Key.S
@@ -109,6 +111,23 @@ Class FileActions
 		saveAll.Enabled=anyDirty
 	End
 	
+	Method CloseFiles( docs:Ted2Document[] )
+		
+		If Not docs.Length Return
+		
+		_saveAllFlag=False
+		_discardAllFlag=False
+	
+		For Local doc:=Eachin docs
+			If Not CanClose( doc,True ) Return
+		Next
+	
+		For Local doc:=Eachin docs
+			doc.Close()
+		Next
+	
+	End
+	
 	
 	Private
 	
@@ -210,7 +229,7 @@ Class FileActions
 		If Not doc Return
 		
 		doc=CanClose( doc )
-		If Not doc return
+		If Not doc Return
 		
 		doc.Close()
 	End
@@ -264,23 +283,6 @@ Class FileActions
 		
 	End
 	
-	Method OnCloseAll()
-
-		_saveAllFlag=False
-		_discardAllFlag=False
-		
-		Local docs:=_docs.OpenDocuments
-		
-		For Local doc:=Eachin docs
-			If Not CanClose( doc,True ) Return
-		Next
-		
-		For Local doc:=Eachin docs
-			doc.Close()
-		Next
-		
-	End
-	
 	Method OnSave()
 	
 		Local doc:=_docs.CurrentDocument

+ 226 - 86
src/ted2go/action/FindActions.monkey2

@@ -16,8 +16,9 @@ Class FindActions
 		
 		_docs=docs
 		_findConsole=findConsole
+		_projView=projView
 		
-		find=New Action( "Find / Replace" )
+		find=New Action( "Find / Replace..." )
 		find.Triggered=OnFind
 		find.HotKey=Key.F
 		find.HotKeyModifiers=Modifier.Menu
@@ -60,9 +61,9 @@ Class FindActions
 		replaceAll.Enabled=tv
 	End
 	
-	Method FindByTextChanged()
+	Method FindByTextChanged( entireProject:Bool )
 		
-		OnFindNext( False )
+		If Not entireProject Then OnFindNext( False )
 	End
 	
 	
@@ -74,6 +75,7 @@ Class FindActions
 	Field _findInFilesDialog:FindInFilesDialog
 	Field _findConsole:TreeViewExt
 	Field _cursorPos:=0
+	Field _projView:ProjectView
 	
 	Method OnFind()
 		
@@ -106,40 +108,165 @@ Class FindActions
 		Endif
 	End
 	
+	Field _storedTextView:TextView
+	Field _storedWhat:String
+	Field _storedCaseSens:Bool
+	Field _storedEntireProject:Bool
+	Field _results:Stack<FileJumpData>
+	Field _resultIndex:Int=-1
+	
 	Method OnFindNext( changeCursorPos:Bool=True )
 	
-		Local tv:=_docs.CurrentTextView
+		Local doc:=_docs.CurrentDocument
+		If Not doc Return
+		
+		Local tv:=doc.TextView
 		If Not tv Return
 		
-		Local text:=_findDialog.FindText
-		If Not text Return
+		Local what:=_findDialog.FindText
+		If Not what Return
 		
-		Local tvtext:=tv.Text
+		Local sens:=_findDialog.CaseSensitive
+		
+		If Not sens
+			what=what.ToLower()
+		Endif
+		
+		Local entire:=_findDialog.EntireProject
+		
+		' when typing request word we should everytime find from current cursor
 		Local cursor:=_cursorPos
 		If changeCursorPos
 			cursor=Max( tv.Anchor,tv.Cursor )
 			_cursorPos=cursor
 		Endif
 		
-		If Not _findDialog.CaseSensitive
-			tvtext=tvtext.ToLower()
-			text=text.ToLower()
+		Local theSame:=(what=_storedWhat And sens=_storedCaseSens And entire=_storedEntireProject)
+		
+		If Not entire Then theSame=theSame And tv=_storedTextView
+		
+		_storedWhat=what
+		_storedTextView=tv
+		_storedCaseSens=sens
+		_storedEntireProject=entire
+		
+		If Not theSame Then _results=Null
+		
+		If _results
+			' use current search results
+			If Not _results.Empty
+				_resultIndex=(_resultIndex+1) Mod _results.Length
+			Endif
+			
+		Else
+			
+			_resultIndex=-1
+			
+			' start new search
+			If entire
+				
+				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
+					_resultIndex=0
+				Endif
+				
+			Else
+				
+				_results=FindInFile( "",what,sens,tv.Document )
+				
+				If Not _results.Empty
+					' take the first result accordingly to cursor
+					For Local i:=0 Until _results.Length
+						Local jump:=_results[i]
+						If jump.pos>=cursor
+							_resultIndex=i
+							Exit
+						Endif
+					Next
+					If _resultIndex=-1 Then _resultIndex=0 ' take from top of doc
+				Endif
+				
+			Endif
+			
 		Endif
 		
-		Local i:=tvtext.Find( text,cursor )
-		If i=-1
-			i=tvtext.Find( text )
-			If i=-1 Return
+		If _resultIndex>=0
+			
+			Local jump:=_results[_resultIndex]
+			
+			If _storedEntireProject
+				MainWindow.OpenDocument( jump.path )
+				tv=_docs.CurrentTextView
+			Endif
+			
+			If tv Then tv.SelectText( jump.pos,jump.pos+jump.len )
+			
 		Endif
 		
-		tv.SelectText( i,i+text.Length )
+	End
+	
+	Method OnFindPrevious()
+		
+		If _resultIndex>=0
+			
+			Local tv:=_docs.CurrentTextView
+			If Not tv Return
+			
+			_resultIndex-=1
+			If _resultIndex<0 Then _resultIndex=_results.Length-1
+			
+			Local jump:=_results[_resultIndex]
+			
+			If _storedEntireProject
+				MainWindow.OpenDocument( jump.path )
+				tv=_docs.CurrentTextView
+			Endif
+			
+			If tv Then tv.SelectText( jump.pos,jump.pos+jump.len )
+			
+		Endif
+	
 	End
 	
 	Method OnFindAllInFiles()
 	
-		If Not _findInFilesDialog.FindText Return
+		If Not _findInFilesDialog.FindText
+			ShowMessage( "","Please, enter text to find what." )
+			Return
+		Endif
 		
-		If Not _findInFilesDialog.SelectedProject Return
+		If Not _findInFilesDialog.SelectedProject
+			ShowMessage( "","Please, select project in the list." )
+			Return
+		Endif
 		
 		_findInFilesDialog.Hide()
 		MainWindow.ShowFindResults()
@@ -148,119 +275,132 @@ Class FindActions
 			
 			New Fiber( Lambda()
 			
-				FindInFilesInternal()
+				Local what:=_findInFilesDialog.FindText
+				Local proj:=_findInFilesDialog.SelectedProject
+				Local sens:=_findInFilesDialog.CaseSensitive
+				Local filter:=_findInFilesDialog.FilterText
+				
+				Local result:=FindInProject( what,proj,sens,filter )
+				
+				If result Then CreateResultTree( _findConsole.RootNode,result,what,proj )
 			End)
 		End
 		
 	End
 	
-	Method FindInFilesInternal()
-		
-		Local what:=_findInFilesDialog.FindText
-		If Not what Return
-		
-		Local proj:=_findInFilesDialog.SelectedProject
-		If Not proj Return
-		
-		Local filter:=_findInFilesDialog.FilterText
-		If Not filter Then filter="monkey2"
+	Const DEFAULT_FILES_FILTER:="monkey2" ',txt,htm,html,h,cpp,json,xml,ini"
+	
+	Method FindInProject:StringMap<Stack<FileJumpData>>( what:String,projectPath:String,caseSensitive:Bool,filesFilter:String=DEFAULT_FILES_FILTER )
 		
-		Local exts:=filter.Split( "," )
+		If Not filesFilter Then filesFilter=DEFAULT_FILES_FILTER
 		
-		proj+="/"
+		Local exts:=filesFilter.Split( "," )
 		
-		Local sens:=_findInFilesDialog.CaseSensitive
+		projectPath+="/"
 		
-		If Not sens Then what=what.ToLower()
+		If Not caseSensitive Then what=what.ToLower()
 		
 		Local files:=New Stack<String>
-		Utils.GetAllFiles( proj,exts,files )
-		
-		Local root:=_findConsole.RootNode
-		root.RemoveAllChildren()
+		Utils.GetAllFiles( projectPath,exts,files )
 		
-		root.Text="Results for '"+what+"'"
-		
-		Local subRoot:TreeView.Node
-		Local items:=New Stack<FileJumpData>
 		Local len:=what.Length
 		
+		Local result:=New StringMap<Stack<FileJumpData>>
+		
 		Local doc:=New TextDocument 'use it to get line number
 		For Local f:=Eachin files
 		
 			Local text:=LoadString( f )
 		
-			If Not sens Then text=text.ToLower()
-			text=text.Replace( "~r~n","~n" )
-			text=text.Replace( "~r","~n" )
+			If Not caseSensitive Then text=text.ToLower()
 		
-			doc.Text=text
+			doc.Text=text 'any needed replacing is here (\r\n -> \n)
+			text=doc.Text
 		
 			Local i:=0
-			items.Clear()
-		
+			Local items:=New Stack<FileJumpData>
+			
 			Repeat
 				i=text.Find( what,i )
 				If i=-1 Exit
-		
+				
 				Local data:=New FileJumpData
 				data.path=f
 				data.pos=i
 				data.len=len
 				data.line=doc.FindLine( i )+1
-		
+				
 				items.Add( data )
-		
+				
 				i+=len
 			Forever
-		
-			If Not items.Empty
-		
-				subRoot=New TreeView.Node( f.Replace( proj,"" )+" ("+items.Length+")",root )
-		
-				For Local d:=Eachin items
-					Local node:=New NodeWithData<FileJumpData>( " at line "+d.line,subRoot )
-					node.data=d
-				Next
-		
-			Endif
+			
+			If Not items.Empty Then result[f]=items
+			
 		Next
 		
-		If root.NumChildren=0 Then New TreeView.Node( "not found :(",root )
-		
-		root.Expanded=True
+		Return result
 	End
 	
-	Method OnFindPrevious()
+	Method FindInFile:Stack<FileJumpData>( filePath:String,what:String,caseSensitive:Bool,doc:TextDocument=Null )
 	
-		Local tv:=_docs.CurrentTextView
-		If Not tv Return
+		Local len:=what.Length
+		Local text:String
+		
+		If Not doc
+			doc=New TextDocument
+			text=LoadString( filePath )
+			doc.Text=text 'any needed replacing is here (\r\n -> \n)
+		Endif
+		text=doc.Text
+		If Not caseSensitive Then text=text.ToLower()
+		
+		Local i:=0
+		Local result:=New Stack<FileJumpData>
+		
+		Repeat
+			i=text.Find( what,i )
+			If i=-1 Exit
 
-		Local text:=_findDialog.FindText
-		If Not text Return
+			Local data:=New FileJumpData
+			data.path=filePath
+			data.pos=i
+			data.len=len
+			data.line=doc.FindLine( i )+1
 
-		Local tvtext:=tv.Text
-		Local cursor:=Min( tv.Anchor,tv.Cursor )
+			result.Add( data )
+
+			i+=len
+		Forever
+
+		Return result
+	End
+	
+	Method CreateResultTree( root:TreeView.Node,map:StringMap<Stack<FileJumpData>>,what:String,projectPath:String )
 		
-		If Not _findDialog.CaseSensitive
-			tvtext=tvtext.ToLower()
-			text=text.ToLower()
-		Endif
+		root.RemoveAllChildren()
 		
-		Local i:=tvtext.Find( text )
-		If i=-1 Return
+		root.Text="Results for '"+what+"'"
 		
-		If i>=cursor
-			i=tvtext.FindLast( text )
-		Else
-			Repeat
-				Local n:=tvtext.Find( text,i+text.Length )
-				If n>=cursor Exit
-				i=n
-			Forever
-		End
+		Local subRoot:TreeView.Node
+		
+		For Local file:=Eachin map.Keys
+			
+			Local items:=map[file]
+			
+			subRoot=New TreeView.Node( file.Replace( projectPath+"/","" )+" ("+items.Length+")",root )
+	
+			For Local d:=Eachin items
+				Local node:=New NodeWithData<FileJumpData>( " at line "+d.line,subRoot )
+				node.data=d
+			Next
+		
+		Next
+		
+		If root.NumChildren=0 Then New TreeView.Node( "not found :(",root )
+		
+		root.Expanded=True
 		
-		tv.SelectText( i,i+text.Length )
 	End
 	
 	Method OnReplace()

+ 10 - 3
src/ted2go/action/HelpActions.monkey2

@@ -36,9 +36,7 @@ Class HelpActions
 		uploadModules=New Action( "Upload module" )
 		uploadModules.Triggered=Lambda()
 		
-			Alert( "Now taking you to the module manager page at "+MONKEY2_DOMAIN+".~n~nNote: You must have an account at "+MONKEY2_DOMAIN+" and be logged in to upload modules." )
-		
-			OpenUrl( RealPath( MONKEY2_DOMAIN+"/module-manager/" ) )
+			GotoUploadModulesPage()
 		End
 
 		about=New Action( "About monkey2" )
@@ -103,3 +101,12 @@ Class HelpActions
 	End
 	
 End
+
+
+Function GotoUploadModulesPage()
+	
+	Alert( "Now taking you to the module manager page at "+MONKEY2_DOMAIN+".~n~nNote: You must have an account at "+MONKEY2_DOMAIN+" and be logged in to upload modules." )
+	
+	OpenUrl( RealPath( MONKEY2_DOMAIN+"/module-manager/" ) )
+	
+End

+ 9 - 3
src/ted2go/assets/aboutTed2Go.html

@@ -60,8 +60,13 @@ It is based on real parsing of sources, parse all modules and user's code.<br>
 Shows code structure, gives us comfortable code jumping.
 </li>
 <br>
+<li><b>Code templates</b><br>
+You just type short combination (like 'prop'), press TAB and get whole code constuction (for ex. property with setter and getter).<br>
+You can add your own templates. Speed up your coding!
+</li>
+<br>
 <li><b>Goto definition</b><br>
-Press F12 to goto definition of ident under cursor.
+Press F12 (or F2) to goto definition of ident under cursor.
 </li>
 <br>
 <li><b>Parsing on-the-fly</b><br>
@@ -115,12 +120,13 @@ Enjoy coding!</p>
 
 <h3>Third party</h3>
 
-<p>Almost all icons for CodeTree were taken from Netbeans IDE.</p>
+<p>Almost all icons for CodeTree were taken from <a href="https://netbeans.org">Netbeans IDE</a>.<br>
+ToolBar icons were taken from <a href="https://icons8.com/icon/new-icons/win8">icons8.com</a>.</p>
 
 
 <h3>Special Thanks</h3>
 
-<p>Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
+<p>Hezkore, Sal Gunduz, Peter Scheutz, Matthieu Chemin, David Maziarka, Leonardo Teixeira, Jesus Perez, Mark Sibly, Philipp Moeller, Lee Wade.</p>
 
 </body>
 

+ 9 - 0
src/ted2go/assets/gen/newClass.txt

@@ -0,0 +1,9 @@
+
+_NAMESPACE_
+
+
+Class _NAME__SUPERCLASS__INTERFACES_
+	
+	
+	
+End

+ 30 - 0
src/ted2go/assets/liveTemplates.json

@@ -0,0 +1,30 @@
+{
+	".monkey2":{
+		"do":"Repeat\n\t${Cursor}\nForever",
+		"dou":"Repeat\n\t\nUntil _${Cursor}",
+		"each":"For Local ${Cursor}:=Eachin _\n\t\nNext",
+		"fib":"New Fiber( Lambda()\n\t${Cursor}\nEnd )",
+		"fori":"For Local ${Cursor}:=0 Until _\n\t\nNext",
+		"fu":"Function ${Cursor}()\n\t\n\t\nEnd",
+		"fus":"Function ${Cursor}:String()\n\t\n\tReturn \nEnd",
+		"get":"Property ${Cursor}()\n\tReturn \nEnd",
+		"ifb":"If ${Cursor}\n\t\nEndif",
+		"ife":"If ${Cursor}\n\t\nElse\n\t\nEndif",
+		"ifn":"If ${Cursor} = Null\n\t\nEndif",
+		"inn":"If ${Cursor} <> Null\n\t\nEndif",
+		"last":"[_${Cursor}.Lenght-1]",
+		"lo":"Local ${Cursor}:=",
+		"me":"Method ${Cursor}()\n\t\n\t\nEnd",
+		"meb":"Method ${Cursor}:Bool()\n\t\n\t\nEnd",
+		"mes":"Method ${Cursor}:String()\n\t\n\tReturn \nEnd",
+		"prnt":"Print \"${Cursor}\"",
+		"prop":"Property ${Cursor}()\n\tReturn \nSetter( value: )\n\t\n\t=value\nEnd",
+		"sel":"Select ${Cursor}\n\tCase \n\t\t\nEnd",
+		"seld":"Select ${Cursor}\n\tCase \n\t\t\n\tDefault \n\t\t\nEnd",
+		"st":"String",
+		"try":"Try\n\t${Cursor}\nCatch _\n\t\nEnd",
+		"whe":"While ${Cursor} = _\n\t\nWend",
+		"whi":"While ${Cursor}\n\t\nWend",
+		"whn":"While ${Cursor} <> _\n\t\nWend"
+	}
+}

BIN
src/ted2go/assets/themes/cancel.png


BIN
src/ted2go/assets/themes/codeicons/alias.png


BIN
src/ted2go/assets/themes/codeicons/annotation.png


BIN
src/ted2go/assets/themes/codeicons/code_template.png


BIN
src/ted2go/assets/themes/codeicons/const.png


BIN
src/ted2go/assets/themes/codeicons/keyword.png


BIN
src/ted2go/assets/themes/codeicons/operator.png


BIN
src/ted2go/assets/themes/codeicons/other.png


BIN
src/ted2go/assets/themes/codeicons/property.png


BIN
src/ted2go/assets/themes/codeicons/property_private.png


BIN
src/ted2go/assets/themes/codeicons/property_protected.png


BIN
src/ted2go/assets/themes/debug_icons.png


BIN
src/ted2go/assets/themes/docbar/back.png


BIN
src/ted2go/assets/themes/docbar/forward.png


BIN
src/ted2go/assets/themes/docbar/home.png


BIN
src/ted2go/assets/themes/hollow_assets/checkbox_icons.png


BIN
src/ted2go/assets/themes/hollow_assets/dialog_skin.png


BIN
src/ted2go/assets/themes/hollow_assets/progressbar_icons.png


BIN
src/ted2go/assets/themes/hollow_assets/tabclose_icons.png


BIN
src/ted2go/assets/themes/hollow_assets/treeview_icons.png


BIN
src/ted2go/assets/themes/irc/blink.png


BIN
src/ted2go/assets/themes/irc/important.png


BIN
src/ted2go/assets/themes/irc/notice.png


BIN
src/ted2go/assets/themes/outputbar/clean.png


BIN
src/ted2go/assets/themes/outputbar/wrap.png


BIN
src/ted2go/assets/themes/prime_assets/checkbox_icons.png


BIN
src/ted2go/assets/themes/prime_assets/dialog_skin.png


BIN
src/ted2go/assets/themes/prime_assets/progressbar_icons.png


BIN
src/ted2go/assets/themes/prime_assets/tabclose_icons.png


BIN
src/ted2go/assets/themes/prime_assets/treeview_icons.png


BIN
src/ted2go/assets/themes/progressbar_icons.png


BIN
src/ted2go/assets/themes/project/package.png


BIN
src/ted2go/assets/themes/smooth_assets/button_skin.png


BIN
src/ted2go/assets/themes/smooth_assets/checkbox_icons.png


BIN
src/ted2go/assets/themes/smooth_assets/dialog_skin.png


BIN
src/ted2go/assets/themes/smooth_assets/progressbar_icons.png


BIN
src/ted2go/assets/themes/smooth_assets/tabbutton_selected_skin.png


BIN
src/ted2go/assets/themes/smooth_assets/tabbutton_skin.png


BIN
src/ted2go/assets/themes/smooth_assets/tabclose_icons.png


BIN
src/ted2go/assets/themes/smooth_assets/treeview_icons.png


BIN
src/ted2go/assets/themes/sourcebar/filter_inherited.png


BIN
src/ted2go/assets/themes/sourcebar/sort_alpha.png


+ 25 - 3
src/ted2go/assets/themes/ted2-default.json

@@ -10,7 +10,7 @@
 		"statusbar-active": "#CA5100",
 		"menu-shortcut":"text-background",
 		"codemap-background": "transparent",
-		"codemap-selection": "#48000000"
+		"codemap-selection": "#48000000"		
 	},
 
 	"fonts":{
@@ -20,7 +20,8 @@
 	},
 	
 	"styles":{
-	
+				
+
 		"GutterView":{
 			"extends":"TextView",
 			"textColor":"text-disabled",
@@ -51,7 +52,8 @@
 			"margin":[ 0 ],
 			"backgroundColor":"content",
 			"border":[ 0,0,0,1 ],
-			"borderColor":"clear"
+			"borderColor":"clear",
+			"iconColor":"#f00"
 		},
 
 		"MainToolBar":{
@@ -72,6 +74,11 @@
 			"margin":[ 3,0 ]
 		},
 
+		"ColoredToolButton":{
+			"extends":"ToolButton",
+			"iconColor":"#6A92CF"
+		},
+
 		"TabViewArrowPrev":{
 			"extends":"Button",
 			"padding":[ 4,1 ],
@@ -162,6 +169,21 @@
 		"BananasDescription":{
 			"extends":"TextView",
 			"font":"normal"
+		},
+
+		"MenuButton":{
+			"extends":"Label",
+			"states":{
+				"hover":{
+					"backgroundColor":"hover"
+				},
+				"active":{
+					"backgroundColor":"active"
+				},
+				"selected":{
+					"backgroundColor":"active"
+				}
+			}
 		}
 	}
 }

+ 7 - 1
src/ted2go/assets/themes/theme-hollow.json

@@ -173,7 +173,8 @@
 		"StatusBarButton":{
 			"extends":"ToolButton",
 			"padding":[ 0 ],
-			"skinColor":"transparent"
+			"skinColor":"transparent",
+			"backgroundColor":"transparent"
 		},
 		
 		"Label":{
@@ -469,6 +470,11 @@
 		
 		"DialogActions":{
 			"padding":[ 8,4,8,4 ]
+		},
+		
+		"ColoredToolButton":{
+			"extends":"ToolButton",
+			"iconColor":"text-default"
 		}
 	}
 }

+ 7 - 1
src/ted2go/assets/themes/theme-prime-base.json

@@ -183,7 +183,8 @@
 		"StatusBarButton":{
 			"extends":"ToolButton",
 			"padding":[ 0 ],
-			"skinColor":"transparent"
+			"skinColor":"transparent",
+			"backgroundColor":"transparent"
 		},
 		
 		"Label":{
@@ -459,6 +460,11 @@
 		
 		"DialogActions":{
 			"padding":[ 8,4,8,4 ]
+		},
+		
+		"ColoredToolButton":{
+			"extends":"ToolButton",
+			"iconColor":"text-default"
 		}
 	}
 }

BIN
src/ted2go/assets/themes/toolbar/back.png


BIN
src/ted2go/assets/themes/toolbar/build.png


BIN
src/ted2go/assets/themes/toolbar/check.png


BIN
src/ted2go/assets/themes/toolbar/copy.png


BIN
src/ted2go/assets/themes/toolbar/cut.png


BIN
src/ted2go/assets/themes/toolbar/debug.png


BIN
src/ted2go/assets/themes/toolbar/find.png


BIN
src/ted2go/assets/themes/toolbar/forward.png


BIN
src/ted2go/assets/themes/toolbar/navigate_back.png


BIN
src/ted2go/assets/themes/toolbar/navigate_forward.png


BIN
src/ted2go/assets/themes/toolbar/new_file.png


BIN
src/ted2go/assets/themes/toolbar/open_file.png


BIN
src/ted2go/assets/themes/toolbar/open_project.png


BIN
src/ted2go/assets/themes/toolbar/options.png


BIN
src/ted2go/assets/themes/toolbar/paste.png


BIN
src/ted2go/assets/themes/toolbar/paypal.png


BIN
src/ted2go/assets/themes/toolbar/redo.png


BIN
src/ted2go/assets/themes/toolbar/run.png


BIN
src/ted2go/assets/themes/toolbar/save.png


BIN
src/ted2go/assets/themes/toolbar/save_all.png


BIN
src/ted2go/assets/themes/toolbar/save_all_dirty.png


BIN
src/ted2go/assets/themes/toolbar/save_dirty.png


BIN
src/ted2go/assets/themes/toolbar/undo.png


BIN
src/ted2go/assets/themes/toolbar/zoom_in.png


BIN
src/ted2go/assets/themes/toolbar/zoom_out.png


+ 19 - 6
src/ted2go/dialog/FindDialog.monkey2

@@ -17,7 +17,7 @@ Class FindDialog Extends DialogExt
 			
 			Local t:=_findField.Text
 			If t.Length > 1
-				actions.FindByTextChanged()
+				actions.FindByTextChanged( EntireProject )
 			Endif
 		End
 
@@ -28,8 +28,15 @@ Class FindDialog Extends DialogExt
 		_caseSensitive=New CheckButton( "Case sensitive" )
 		_caseSensitive.Layout="float"
 		
-'		_escapedText=New CheckButton( "Escaped text" )
-
+		_entireProject=New CheckButton( "Entire project" )
+		_entireProject.Layout="float"
+		
+		Local entireHint:=New Label( "(use 'Find next' button for entire-project-mode)" )
+		entireHint.Visible=False
+		_entireProject.Clicked+=Lambda()
+			entireHint.Visible=_entireProject.Checked
+		End
+		
 		Local table:=New TableView( 2,2 )
 		table[0,0]=New Label( "Find" )
 		table[1,0]=_findField
@@ -39,10 +46,11 @@ Class FindDialog Extends DialogExt
 		_docker=New DockingView
 		_docker.AddView( table,"top" )
 		_docker.AddView( _caseSensitive,"top" )
-'		_docker.AddView( _escapedText,"top" )
+		_docker.AddView( _entireProject,"top" )
+		_docker.AddView( entireHint,"top" )
 		_docker.AddView( New Label( " " ),"top" )
 		
-		Title="Find/Replace"
+		Title="Find / Replace"
 		
 		MaxSize=New Vec2i( 512,0 )
 		
@@ -77,6 +85,11 @@ Class FindDialog Extends DialogExt
 		Return _caseSensitive.Checked
 	End
 	
+	Property EntireProject:Bool()
+	
+		Return _entireProject.Checked
+	End
+	
 	Method SetInitialText( find:String )
 		
 		_findField.Text=find
@@ -89,7 +102,7 @@ Class FindDialog Extends DialogExt
 	Field _findField:TextField
 	Field _replaceField:TextField
 	Field _caseSensitive:CheckButton
-	Field _escapedText:CheckButton
+	Field _entireProject:CheckButton
 
 	Field _docker:DockingView
 

+ 186 - 0
src/ted2go/dialog/GenerateClassDialog.monkey2

@@ -0,0 +1,186 @@
+
+Namespace ted2go
+
+
+#Import "../assets/gen/@/gen"
+
+Class GenerateClassDialog Extends DialogExt
+	
+	Field Generated:Void( filePath:String,fileContent:String )
+	
+	Method New( rootPath:String )
+		
+		_path=rootPath
+		
+		Title="Generate class"
+		
+		Local dock:=New DockingView
+		
+		_codeView=New Ted2CodeTextView
+		_codeView.FileType=".monkey2"
+		_codeView.MinSize=New Vec2i( 200,200 )
+		dock.AddView( _codeView,"bottom" )
+		
+		_codeTemplate=LoadString( "asset::gen/newClass.txt" )
+		
+		Local table:=New TableView( 2,5 )
+		
+		table[0,0]=New Label( "Class name" )
+		_editClassName=CreateTextField()
+		_editClassName.TextChanged+=Lambda()
+			_editFileName.Text=ClassName+".monkey2"
+		End
+		table[1,0]=_editClassName
+		
+		table[0,1]=New Label( "SuperClass name" )
+		_editSuperClassName=CreateTextField()
+		table[1,1]=_editSuperClassName
+		
+		table[0,2]=New Label( "Interface(s) name" )
+		_editInterfacesName=CreateTextField()
+		table[1,2]=_editInterfacesName
+		
+		table[0,3]=New Label( "Namespace" )
+		_editNamespace=CreateTextField()
+		table[1,3]=_editNamespace
+		
+		table[0,4]=New Label( "File name" )
+		_editFileName=New TextFieldExt
+		table[1,4]=_editFileName
+		
+		dock.AddView( table,"bottom" )
+		
+		ContentView=dock
+		
+		Local cancel:=AddAction( "Cancel"  )
+		cancel.Triggered=lambda()
+			HideWithResult( False )
+		End
+		SetKeyAction( Key.Escape,cancel )
+		
+		Local okay:=AddAction( "Generate" )
+		okay.Triggered=Lambda()
+			OnGenerate()
+		End
+		SetKeyAction( Key.Enter,okay )
+		
+		OnShow+=Lambda()
+			_editClassName.MakeKeyView()
+		End
+		
+		AdjustTabOrder()
+		UpdateCodeView()
+		
+	End
+	
+	Property ClassName:String()
+	
+		Return _editClassName.Text.Trim()
+	End
+	
+	Property SuperClassName:String()
+	
+		Return _editSuperClassName.Text.Trim()
+	End
+	
+	Property InterfacesName:String()
+	
+		Return _editInterfacesName.Text.Trim()
+	End
+	
+	Property NamespaceName:String()
+	
+		Return _editNamespace.Text.Trim()
+	End
+	
+	Property FileName:String()
+	
+		Local s:=_editFileName.Text.Trim()
+		If Not ExtractExt( s ) Then s+=".monkey2"
+		Return s
+	End
+	
+	Property GeneratedContent:String()
+	
+		Local s:=_codeTemplate,n:String
+		s=s.Replace( "_NAME_",ClassName )
+		n=NamespaceName
+		s=s.Replace( "_NAMESPACE_",n ? ("Namespace "+n) Else "" )
+		n=SuperClassName
+		s=s.Replace( "_SUPERCLASS_",n ? (" Extends "+n) Else "" )
+		n=InterfacesName
+		s=s.Replace( "_INTERFACES_",n ? (" Implements "+n) Else "" )
+		Return s
+	End
+	
+	Private
+	
+	Field _path:String
+	Field _codeTemplate:String
+	Field _editNamespace:TextFieldExt
+	Field _editClassName:TextFieldExt
+	Field _editSuperClassName:TextFieldExt
+	Field _editInterfacesName:TextFieldExt
+	Field _editFileName:TextFieldExt
+	Field _codeView:Ted2CodeTextView
+	
+	
+	Method OnGenerate()
+		
+		If Not IsIdentStr( ClassName )
+			Alert( "Class name is invalid or empty!",Title )
+			Return
+		Endif
+		If SuperClassName And Not IsIdentStr( SuperClassName )
+			Alert( "SuperClass name is invalid!",Title )
+			Return
+		Endif
+		If NamespaceName And Not IsIdentStr( NamespaceName )
+			Alert( "Namespace is invalid!",Title )
+			Return
+		Endif
+		If InterfacesName
+			Local arr:=InterfacesName.Split( "," )
+			For Local i:=Eachin arr
+				i=i.Trim()
+				If Not IsIdentStr( i )
+					Alert( "Interface name '"+i+"' is invalid!",Title )
+					Return
+				Endif
+			Next
+		Endif
+		
+		Local path:=_path+"/"+FileName
+		If FileExists( path )
+			Alert( "File with such name already exists!",Title )
+			Return
+		Endif
+		
+		HideWithResult( True )
+		
+		Generated( path,GeneratedContent )
+	End
+	
+	Method UpdateCodeView()
+		
+		_codeView.Text=GeneratedContent
+	End
+	
+	Method CreateTextField:TextFieldExt()
+		
+		Local tf:=New TextFieldExt
+		tf.TextChanged+=UpdateCodeView
+		Return tf
+	End
+	
+	Method AdjustTabOrder()
+		
+		_editClassName.NextView=_editSuperClassName
+		_editSuperClassName.NextView=_editInterfacesName
+		_editInterfacesName.NextView=_editNamespace
+		_editNamespace.NextView=_editFileName
+		'_editFileName.NextView=_codeView
+		
+	End
+	
+End

+ 66 - 0
src/ted2go/dialog/LiveTemplatesDialog.monkey2

@@ -0,0 +1,66 @@
+
+Namespace ted2go
+
+
+Class LiveTemplateDialog
+	
+	Method New()
+	
+		Title="Live templates"
+	
+		Local dock:=New DockingView
+		_tree=New TreeViewExt
+		_tree.NodeClicked=Lambda( node:Node )
+			
+			If node.Parent=_tree.RootNode Return
+			
+			ShowTemplate( node.Parent.Text,node.Text )
+		End
+		FillTree( _tree )
+	
+		dock.AddView( _tree,"left","150",True)
+		
+		_codeView=New Ted2CodeTextView
+		dock.ContentView=_codeView
+		
+		ContentView=dock
+	
+		Local cancel:=AddAction( "Cancel"  )
+		cancel.Triggered=lambda()
+			_result.Set( False )
+		End
+		SetKeyAction( Key.Escape,cancel )
+	
+		Local okay:=AddAction( "Save" )
+		okay.Triggered=Lambda()
+			_result.Set( True )
+		End
+		SetKeyAction( Key.Enter,okay )
+		
+	End
+	
+	
+	Private
+	
+	Field _tree:TreeViewExt
+	Field _codeView:Ted2CodeTextView
+	
+	Method ShowTemplate( lang:String,name:String )
+		
+		If _codeView.FileType<>lang Then _codeView.FileType=lang
+		_codeView.Text=LiveTemplates[lang,name]
+		_codeView.SelectText( 0,0 )
+	End
+	
+	Method FillTree( tree:TreeView )
+		
+		For Local map:=Eachin LiveTemplates.All()
+			Local node:=New TreeView.Node( map.Key,tree.RootNode )
+			For Local i:=Eachin map.Value.All()
+				New TreeView.Node( i.Key,node )
+			Next
+		Next
+	End
+	
+End
+

+ 186 - 1
src/ted2go/dialog/PrefsDialog.monkey2

@@ -1,3 +1,4 @@
+
 Namespace ted2go
 
 
@@ -32,6 +33,10 @@ Class PrefsDialog Extends DialogExt
 		docker=GetChatDock()
 		tabView.AddTab( "IRC chat",docker )
 		
+		' Live Templates
+		'
+		docker=GetLiveTemplatesDock()
+		tabView.AddTab( "CodeTemplates",docker )
 		
 		ContentView=tabView
 		
@@ -41,6 +46,8 @@ Class PrefsDialog Extends DialogExt
 		_acShowAfter.Activated+=_acShowAfter.MakeKeyView
 		
 		Deactivated+=MainWindow.UpdateKeyView
+		
+		MinSize=New Vec2i( 300,500 )
 	End
 	
 	
@@ -55,6 +62,7 @@ Class PrefsDialog Extends DialogExt
 	Field _acNewLineByEnter:CheckButton
 	Field _acKeywordsOnly:CheckButton
 	Field _acShowAfter:TextField
+	Field _acUseLiveTemplates:CheckButton
 	
 	Field _editorToolBarVisible:CheckButton
 	Field _editorGutterVisible:CheckButton
@@ -77,6 +85,9 @@ Class PrefsDialog Extends DialogExt
 	Field _chatRooms:TextField
 	Field _chatAutoConnect:CheckButton
 	
+	Field _codeView:Ted2CodeTextView
+	Field _treeView:TreeViewExt
+	
 	Method OnApply()
 	
 		Prefs.AcEnabled=_acEnabled.Checked
@@ -88,6 +99,7 @@ Class PrefsDialog Extends DialogExt
 		Prefs.AcKeywordsOnly=_acKeywordsOnly.Checked
 		Local count:=Max( 1,Int( _acShowAfter.Text ) )
 		Prefs.AcShowAfter=count
+		Prefs.AcUseLiveTemplates=_acUseLiveTemplates.Checked
 		
 		Prefs.EditorToolBarVisible=_editorToolBarVisible.Checked
 		Prefs.EditorGutterVisible=_editorGutterVisible.Checked
@@ -118,6 +130,8 @@ Class PrefsDialog Extends DialogExt
 		Apply()
 		
 		Prefs.SaveLocalState()
+		
+		LiveTemplates.Save()
 	End
 	
 	Method GetMainDock:DockingView()
@@ -278,6 +292,9 @@ Class PrefsDialog Extends DialogExt
 		_acNewLineByEnter=New CheckButton( "Add new line (by Enter)" )
 		_acNewLineByEnter.Checked=Prefs.AcNewLineByEnter
 		
+		_acUseLiveTemplates=New CheckButton( "Show live templates" )
+		_acUseLiveTemplates.Checked=Prefs.AcUseLiveTemplates
+		
 		Local docker:=New DockingView
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( _acEnabled,"top" )
@@ -288,6 +305,7 @@ Class PrefsDialog Extends DialogExt
 		docker.AddView( _acUseSpace,"top" )
 		docker.AddView( _acUseDot,"top" )
 		docker.AddView( _acKeywordsOnly,"top" )
+		docker.AddView( _acUseLiveTemplates,"top" )
 		docker.AddView( New Label( " " ),"top" )
 		
 		Return docker
@@ -295,7 +313,7 @@ Class PrefsDialog Extends DialogExt
 	
 	Method GetChatDock:DockingView()
 		
-		Local chatTable:=New TableView( 2,5 )
+		Local chatTable:=New TableView( 2,6 )
 		_chatNick=New TextField( Prefs.IrcNickname )
 		_chatServer=New TextField( Prefs.IrcServer )
 		_chatPort=New TextField( ""+Prefs.IrcPort )
@@ -311,6 +329,7 @@ Class PrefsDialog Extends DialogExt
 		chatTable[0,3]=New Label( "Rooms" )
 		chatTable[1,3]=_chatRooms
 		chatTable[0,4]=_chatAutoConnect
+		chatTable[0,5]=New Label( "" ) 'bottom padding hack
 		
 		Local docker:=New DockingView
 		docker.AddView( New Label( " " ),"top" )
@@ -319,4 +338,170 @@ Class PrefsDialog Extends DialogExt
 		Return docker
 	End
 	
+	Method GetLiveTemplatesDock:DockingView()
+	
+		Local treeDock:=New DockingView
+		Local tree:=New TreeViewExt
+		_treeView=tree
+		
+		Local dockButtons:=New DockingView
+		Local st:=dockButtons.Style.Copy()
+		st.Margin=New Recti( 0,-5,0,0 )
+		dockButtons.Style=st
+		
+		Local btn:=New ToolButtonExt( New Action( "Add" ),"Add new template" )
+		btn.Clicked=Lambda()
+			New Fiber( Lambda()
+				Local name:=RequestString( "New template name:","" )
+				name=name.Trim()
+				If name AddTemplate( name )
+			End )
+		End
+		dockButtons.AddView( btn,"right" )
+		
+		btn=New ToolButtonExt( New Action( "Clone" ),"Clone selected" )
+		btn.Clicked=Lambda()
+			New Fiber( Lambda()
+				If Not TemplateSelName
+					Alert( "Please, select an item to clone from!" )
+					Return
+				Endif
+				Local name:=RequestString( "New template name:","" )
+				name=name.Trim()
+				If name CloneTemplate( name )
+			End )
+		End
+		dockButtons.AddView( btn,"right" )
+		
+		btn=New ToolButtonExt( New Action( "Del" ),"Remove selected" )
+		btn.Clicked=Lambda()
+			RemoveTemplate()
+		End
+		dockButtons.AddView( btn,"right" )
+		
+		btn=New ToolButtonExt( New Action( "..." ),"Open containing folder (customTemplates.json)" )
+		btn.Clicked=Lambda()
+			OpenUrl( Prefs.IdeHomeDir )
+		End
+		dockButtons.AddView( btn,"right" )
+		
+		treeDock.ContentView=tree
+		treeDock.AddView( dockButtons,"bottom" )
+		
+		Local docker1:=New DockingView
+		docker1.AddView( treeDock,"left","170",True)
+		
+		_codeView=New Ted2CodeTextView
+		_codeView.ShowWhiteSpaces=True
+		_codeView.Document.TextChanged+=Lambda()
+			
+			Local name:=TemplateSelName
+			If name Then LiveTemplates[TemplateSelLang,name]=_codeView.Text
+		End
+		docker1.ContentView=_codeView
+		
+		Local docker2:=New DockingView
+		docker2.AddView( New Label( "Press 'Tab' in completion list or editor to insert template." ),"top" )
+		docker2.ContentView=docker1
+		
+		PrepareTree( tree )
+		
+		Return docker2
+	End
+	
+	Method ShowTemplate( lang:String,name:String )
+		
+		If _codeView.FileType<>lang Then _codeView.FileType=lang
+		_codeView.Text=LiveTemplates[lang,name]
+		_codeView.SelectText( 0,0 )
+	End
+	
+	Method PrepareTree( tree:TreeViewExt)
+		
+		tree.RootNodeVisible=False
+		tree.RootNode.Expanded=True
+		tree.SelectedChanged+=Lambda( node:TreeView.Node )
+		
+			If Not node Return
+		
+			If node.Parent=tree.RootNode Return
+		
+			ShowTemplate( node.Parent.Text,node.Text )
+		End
+		
+		For Local map:=Eachin LiveTemplates.All()
+			Local node:=New TreeView.Node( map.Key,tree.RootNode )
+			For Local i:=Eachin map.Value.All()
+				New TreeView.Node( i.Key,node )
+			Next
+		Next
+		
+		Local n:=tree.RootNode
+		If n.NumChildren > 0
+			n=n.Children[0]
+			If n.NumChildren > 0
+				_treeView.Selected=n.Children[0]
+			Endif
+		Endif
+	End
+	
+	Method AddTemplate( name:String )
+		
+		Local lang:=TemplateSelLang
+		If LiveTemplates[lang,name]
+			Alert( "Such name already exists!" )
+			Return
+		Endif
+		AddTemplateInternal( lang,name,"" )
+	End
+	
+	Method CloneTemplate( name:String )
+	
+		Local lang:=TemplateSelLang
+		If LiveTemplates[lang,name]
+			Alert( "Such name already exists!" )
+			Return
+		Endif
+		AddTemplateInternal( lang,name,LiveTemplates[lang,TemplateSelName] )
+	End
+	
+	Method RemoveTemplate()
+		
+		If Not TemplateSelName
+			Alert( "Have no selected item to remove!" )
+			Return
+		Endif
+		
+		DebugStop()
+		LiveTemplates[TemplateSelLang].Remove( TemplateSelName )
+		_treeView.RemoveNode( _treeView.Selected )
+		_codeView.Text=""
+	End
+	
+	Method AddTemplateInternal( lang:String,name:String,value:String )
+		
+		LiveTemplates[lang,name]=value
+		Local n:=_treeView.FindSubNode( lang,_treeView.RootNode )
+		Local n2:=New TreeView.Node( name,n )
+		_treeView.Selected=n2
+		
+		_codeView.MakeKeyView()
+	End
+	
+	Property TemplateSelLang:String()
+		
+		Local sel:=_treeView.Selected
+		If Not sel Return Null
+		
+		Return (sel.Parent=_treeView.RootNode) ? sel.Text Else sel.Parent.Text
+	End
+	
+	Property TemplateSelName:String()
+		
+		Local sel:=_treeView.Selected
+		If Not sel Return Null
+		
+		Return (sel.Parent=_treeView.RootNode) ? Null Else sel.Text
+	End
+	
 End

+ 0 - 4
src/ted2go/dialog/UpdateModulesDialog.monkey2

@@ -246,8 +246,4 @@ Class UpdateModulesDialog Extends DialogExt
 	End
 #end
 	
-	Function ShowMessage( title:String,msg:String,okButton:String="  OK  " )
-		
-		Dialog.Run( title,New Label( msg ),New String[](okButton),0,0 )
-	End
 End

+ 54 - 10
src/ted2go/document/CodeDocument.monkey2

@@ -51,13 +51,20 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				
 				Local ident:=result.ident
 				Local text:=result.text
-				Local item:=result.item
-				Local bySpace:=result.bySpace
 				
-				text=_doc.PrepareForInsert( ident,text,Not bySpace,LineTextAtCursor,PosInLineAtCursor,item )
-				
-				SelectText( Cursor,Cursor-AutoComplete.LastIdentPart.Length )
-				ReplaceText( text )
+				If result.isTemplate
+					
+					InsertLiveTemplate( AutoComplete.LastIdentPart,text )
+					
+				Else
+					
+					Local item:=result.item
+					Local bySpace:=result.bySpace
+					
+					text=_doc.PrepareForInsert( ident,text,Not bySpace,LineTextAtCursor,PosInLineAtCursor,item )
+					SelectText( Cursor,Cursor-AutoComplete.LastIdentPart.Length )
+					ReplaceText( text )
+				Endif
 			Endif
 		End
 		
@@ -190,6 +197,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 					Endif
 				
 				Case Key.Backspace
+					
 					If AutoComplete.IsOpened
 						Local ident:=IdentBeforeCursor()
 						ident=ident.Slice( 0,ident.Length-1 )
@@ -198,6 +206,15 @@ Class CodeDocumentView Extends Ted2CodeTextView
 						Else
 							_doc.HideAutocomplete()
 						Endif
+						
+					Else
+						
+						#If __TARGET__="macos"
+						If ctrl
+							DeleteLineAtCursor()
+						Endif
+						#Endif
+						
 					Endif
 				
 				Case Key.F11
@@ -208,9 +225,7 @@ Class CodeDocumentView Extends Ted2CodeTextView
 				#If __TARGET__="windows"
 				Case Key.E 'delete whole line
 					If ctrl
-						Local line:=Document.FindLine( Cursor )
-						SelectText( Document.StartOfLine( line ),Document.EndOfLine( line )+1 )
-						ReplaceText( "" )
+						DeleteLineAtCursor()
 						Return
 					Endif
 				#Endif
@@ -370,6 +385,11 @@ Class CodeDocumentView Extends Ted2CodeTextView
 			
 					If Cursor = Anchor 'has no selection
 			
+						' live templates by tab!
+						Local ident:=IdentBeforeCursor()
+						If InsertLiveTemplate( ident ) Return
+						
+						' usual tab behaviour
 						If Not shift
 							ReplaceText( "~t" )
 						Else
@@ -663,6 +683,30 @@ Class CodeDocumentView Extends Ted2CodeTextView
 		RenderStyle.Font=newFont
 	End
 	
+	Method InsertLiveTemplate:Bool( ident:String,templ:String=Null )
+		
+		If Not templ Then templ=LiveTemplates[FileType,ident]
+		If templ
+			templ=PrepareSmartPaste( templ )
+			Local start:=Cursor-ident.Length
+			Local cursorOffset:=templ.Find( "${Cursor}" )
+			If cursorOffset <> -1 Then templ=templ.Replace( "${Cursor}","" )
+			SelectText( start,Cursor )
+			ReplaceText( templ )
+			If cursorOffset <> -1 Then SelectText( start+cursorOffset,start+cursorOffset )
+			Return True
+		Endif
+		
+		Return False
+	End
+	
+	Method DeleteLineAtCursor()
+		
+		Local line:=Document.FindLine( Cursor )
+		SelectText( Document.StartOfLine( line ),Document.EndOfLine( line )+1 )
+		ReplaceText( "" )
+	End
+	
 End
 
 
@@ -1044,7 +1088,7 @@ Class CodeDocument Extends Ted2Document
 		
 	End
 	
-	Method HideAutocomplete()
+	Function HideAutocomplete()
 		AutoComplete.Hide()
 	End
 	

+ 5 - 1
src/ted2go/product/ModuleManager.monkey2

@@ -72,7 +72,11 @@ Class ModuleManager Extends Dialog
 			
 			UpdateTable()
 		End
-			
+		
+		Local upload:=New Button( "Upload module" )
+		upload.Clicked+=GotoUploadModulesPage
+		buttons.AddView( upload,"right" )
+		
 		_docker.AddView( buttons,"bottom" )
 		
 		ContentView=_docker

+ 10 - 0
src/ted2go/utils/JsonUtils.monkey2

@@ -2,6 +2,16 @@
 Namespace ted2go
 
 
+Function Json_LoadObject:JsonObject( filePath:String )
+	
+	If GetFileType(filePath) <> FileType.File Return Null
+	
+	'Local txt:=LoadString( filePath ).Replace( "\n","~n" ).Replace( "\t","~t" ).Replace( "\r","~r" )
+	
+	'Return JsonObject.Parse( txt )
+	Return JsonObject.Load( filePath )
+End
+
 Function Json_LoadValue:JsonValue( filePath:String,key:String )
 	
 	If GetFileType(filePath) <> FileType.File Return Null

+ 18 - 0
src/ted2go/utils/Utils.monkey2

@@ -188,3 +188,21 @@ Function FormatTime:String( millis:Long,format:String="{min} m {sec} s" )
 	
 	Return s
 End
+
+Function ShowMessage( title:String,msg:String,okButton:String="  OK  " )
+
+	Dialog.Run( title,New Label( msg ),New String[](okButton),0,0 )
+End
+
+Function IsIdentStr:Bool( str:String )
+	
+	If Not str Return False
+	
+	If IsDigit( str[0] ) Return False
+	
+	For Local c:=Eachin str
+		If Not IsIdent( c ) Return False
+	Next
+	
+	Return True
+End

+ 99 - 21
src/ted2go/view/AutocompleteView.monkey2

@@ -85,6 +85,7 @@ Struct AutocompleteResult
 	Field text:String
 	Field item:CodeItem
 	Field bySpace:Bool
+	Field isTemplate:Bool
 	
 End
 
@@ -97,14 +98,17 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 		Super.New()
 		
-		_view=New AutocompleteListView( 20,15 )
+		Local lineHg:=20,linesCount:=15
+		
+		_view=New AutocompleteListView( lineHg,linesCount )
 		_view.MoveCyclic=True
 		
-		_view.MaxSize=New Vec2i( 500,20*15 )
+		_etalonMaxSize=New Vec2i( 500,lineHg*linesCount )
 		
 		ContentView=_view
 		
 		_keywords=New StringMap<List<ListViewItem>>
+		_templates=New StringMap<List<ListViewItem>>
 		_parsers=New StringMap<ICodeParser>
 		
 		_view.OnItemChoosen+=Lambda()
@@ -119,6 +123,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 			_disableUsingsFilter=False
 		End
 		
+		OnThemeChanged()
 	End
 	
 	Property DisableUsingsFilter:Bool()
@@ -288,6 +293,17 @@ Class AutocompleteDialog Extends NoTitleDialog
 		
 		If lastIdent Then CodeItemsSorter.SortByIdent( result,lastIdent )
 		
+		'-----------------------------
+		' live templates
+		'-----------------------------
+		If onlyOne And Prefs.AcUseLiveTemplates
+			For Local i:=Eachin GetTemplates( fileType )
+				If i.Text.StartsWith( lastIdent )
+					result.Insert( 0,i )
+				Endif
+			Next
+		Endif
+		
 		_view.Reset()'reset selIndex
 		_view.SetItems( result )
 		
@@ -297,10 +313,19 @@ Class AutocompleteDialog Extends NoTitleDialog
 	End
 	
 	
+	Protected
+	
+	Method OnThemeChanged() Override
+		
+		_view.MaxSize=_etalonMaxSize*App.Theme.Scale
+	End
+	
 	Private
 	
+	Field _etalonMaxSize:Vec2i
 	Field _view:AutocompleteListView
 	Field _keywords:StringMap<List<ListViewItem>>
+	Field _templates:StringMap<List<ListViewItem>>
 	Field _lastIdentPart:String,_fullIdent:String
 	Field _parsers:StringMap<ICodeParser>
 	Field _listForExtract:=New List<CodeItem>
@@ -317,6 +342,18 @@ Class AutocompleteDialog Extends NoTitleDialog
 		Return _keywords[fileType]
 	End
 	
+	Method GetTemplates:List<ListViewItem>( fileType:String )
+		If _templates[fileType] = Null
+			UpdateTemplates( fileType )
+			LiveTemplates.DataChanged+=Lambda( lang:String )
+				If _templates[lang] 'recreate items only if them were in use
+					UpdateTemplates( lang )
+				Endif
+			End
+		Endif
+		Return _templates[fileType]
+	End
+	
 	Method IsItemInScope:Bool( item:CodeItem,scope:CodeItem )
 		If scope = Null Return False
 		Return item.ScopeStartPos.x >= scope.ScopeStartPos.x And item.ScopeEndPos.x <= scope.ScopeEndPos.x
@@ -330,44 +367,61 @@ Class AutocompleteDialog Extends NoTitleDialog
 			
 			Case EventType.KeyDown,EventType.KeyRepeat
 				
+				Local curItem:=_view.CurrentItem
+				Local templ:=Cast<TemplateListViewItem>( curItem )
+				
 				Select event.Key
 				Case Key.Escape
 					Hide()
 					event.Eat()
+					
 				Case Key.Up
 					_view.SelectPrev()
 					event.Eat()
+					
 				Case Key.Down
 					_view.SelectNext()
 					event.Eat()
+					
 				Case Key.PageUp
 					_view.PageUp()
 					event.Eat()
+					
 				Case Key.PageDown
 					_view.PageDown()
 					event.Eat()
+					
 				Case Key.Enter,Key.KeypadEnter
-					If Prefs.AcUseEnter
-						OnItemChoosen( _view.CurrentItem )
-						If Not Prefs.AcNewLineByEnter Then event.Eat()
-					Else
-						Hide() 'hide by enter
+					If Not templ
+						If Prefs.AcUseEnter
+							OnItemChoosen( curItem )
+							If Not Prefs.AcNewLineByEnter Then event.Eat()
+						Else
+							Hide() 'hide by enter
+						Endif
 					Endif
+					
 				Case Key.Tab
-					If Prefs.AcUseTab
-						OnItemChoosen( _view.CurrentItem )
+					If Prefs.AcUseTab Or templ
+						OnItemChoosen( curItem )
 						event.Eat()
 					Endif
+					
 				Case Key.Space
-					Local ctrl:=event.Modifiers & Modifier.Control
-					If Prefs.AcUseSpace And Not ctrl
-						OnItemChoosen( _view.CurrentItem,True )
-						event.Eat()
+					If Not templ
+						Local ctrl:=event.Modifiers & Modifier.Control
+						If Prefs.AcUseSpace And Not ctrl
+							OnItemChoosen( curItem,True )
+							event.Eat()
+						Endif
 					Endif
+					
 				Case Key.Period
-					If Prefs.AcUseDot
-						OnItemChoosen( _view.CurrentItem )
-						event.Eat()
+					If Not templ
+						If Prefs.AcUseDot
+							OnItemChoosen( curItem )
+							event.Eat()
+						Endif
 					Endif
 				
 				Case Key.Backspace
@@ -390,13 +444,19 @@ Class AutocompleteDialog Extends NoTitleDialog
 	
 	Method OnItemChoosen( item:ListViewItem,bySpace:Bool=False )
 		
-		Local si:=Cast<CodeListViewItem>( item )
+		Local siCode:=Cast<CodeListViewItem>( item )
+		Local siTempl:=Cast<TemplateListViewItem>( item )
 		Local ident:="",text:=""
 		Local code:CodeItem=Null
-		If si <> Null
-			ident=si.CodeItem.Ident
-			text=si.CodeItem.TextForInsert
-			code=si.CodeItem
+		Local templ:=False
+		If siCode
+			ident=siCode.CodeItem.Ident
+			text=siCode.CodeItem.TextForInsert
+			code=siCode.CodeItem
+		Elseif siTempl
+			ident=siTempl.name
+			text=siTempl.value
+			templ=True
 		Else
 			ident=item.Text
 			text=item.Text
@@ -406,6 +466,7 @@ Class AutocompleteDialog Extends NoTitleDialog
 		result.text=text
 		result.item=code
 		result.bySpace=bySpace
+		result.isTemplate=templ
 		OnChoosen( result )
 		Hide()
 	End
@@ -430,6 +491,23 @@ Class AutocompleteDialog Extends NoTitleDialog
 		_keywords[fileType]=list
 	End
 	
+	Method UpdateTemplates( fileType:String )
+	
+		'live templates
+		Local templates:=LiveTemplates.All( fileType )
+		Local list:=New List<ListViewItem>
+		If templates <> Null
+			For Local i:=Eachin templates
+				Local si:=New TemplateListViewItem( i.Key,i.Value )
+				list.AddLast( si )
+			Next
+			list.Sort( Lambda:Int(l:ListViewItem,r:ListViewItem)
+				Return l.Text<=>r.Text
+			End )
+		Endif
+		_templates[fileType]=list
+	End
+	
 	Method UpdateParsers( fileType:String )
 		_parsers[fileType]=ParsersManager.Get( fileType )
 	End

+ 21 - 0
src/ted2go/view/BuildErrorListViewItem.monkey2

@@ -0,0 +1,21 @@
+
+Namespace ted2go
+
+
+Class BuildErrorListViewItem Extends ListViewItem
+	
+	Field error:BuildError
+	
+	Method New( text:String,icon:Image )
+		
+		Super.New( text,icon )
+	End
+	
+	Method New( err:BuildError )
+	
+		Super.New( err.msg )
+		Text="~q"+err.msg.Trim()+"~q at line "+(err.line+1)+" ("+err.path+")"
+		error=err
+	End
+	
+End

+ 24 - 37
src/ted2go/view/CodeMapView.monkey2

@@ -16,18 +16,18 @@ Class CodeMapView Extends View
 		
 		_codeView=sourceView
 	
-		_selColor=App.Theme.GetColor( "codemap-selection" )
-		_padding=PAD*App.Theme.Scale.x
-		App.ThemeChanged+=Lambda()
-			_selColor=App.Theme.GetColor( "codemap-selection" )
-			_padding=PAD*App.Theme.Scale.x
-		End
-		
+		OnThemeChanged()
 	End
 	
 	
 	Protected
 	
+	Method OnThemeChanged() Override
+		
+		_selColor=App.Theme.GetColor( "codemap-selection" )
+		_padding=PAD*App.Theme.Scale.x
+	End
+	
 	Method OnMeasure:Vec2i() Override
 	
 		Local ww:=WIDTH*App.Theme.Scale.x
@@ -119,7 +119,7 @@ Class CodeMapView Extends View
 	
 	Property ScrollKoef:Float()
 	
-		Local hh:=_codeView.ContentView.Frame.Height
+		Local hh:=OwnerContentHeight
 		_maxSelfScroll=Max( Float(0.0),hh*scale-VisibleHeight )
 		_maxOwnerScroll=Max( 0.0,hh-VisibleHeight )
 	
@@ -131,6 +131,11 @@ Class CodeMapView Extends View
 		Return _codeView.ContentView.Frame.Height
 	End
 	
+	Property OwnerContentWidht:Float()
+	
+		Return _codeView.ContentView.Frame.Width
+	End
+	
 	Property BubbleHeight:Float()
 	
 		Return VisibleHeight*scale
@@ -164,37 +169,19 @@ Class CodeMapView Extends View
 	
 		canvas.Translate( _padding,-yy*ScrollKoef+_padding )
 		canvas.Scale( scale,scale )
-	
-		Local times:=Int(OwnerContentHeight/VisibleHeight)+1
-		Local sc:=_codeView.Scroll
-		Local sc2:=New Vec2i
-		Local dy:=VisibleHeight+_codeView.LineHeight
+		
 		Local whiteSpaces:=_codeView.ShowWhiteSpaces
+		
 		_codeView.ShowWhiteSpaces=False
-		Local top:=-yy*ScrollKoef
-		For Local k:=0 Until times
-	
-			' check visibility area
-			If top+VisibleHeight*scale < 0
-				top+=dy*scale
-				sc2.Y=sc2.y+dy
-				Continue
-			Endif
-			If top>VisibleHeight
-				Exit
-			Endif
-			top+=dy*scale
-	
-			_codeView.Scroll=sc2
-			CodeTextViewBridge.ProcessRender( _codeView,canvas )
-			sc2.Y=sc2.y+dy
-			
-		Next
-		_codeView.Scroll=sc
+		Local top:=yy*ScrollKoef/scale
+		
+		Local r:=New Recti( 0,top,OwnerContentWidht,top+VisibleHeight/scale )
+		CodeTextViewBridge.ProcessRender( _codeView,r,canvas )
+		
 		_codeView.ShowWhiteSpaces=whiteSpaces
-	
+		
 		canvas.PopMatrix()
-	
+		
 	End
 	
 End
@@ -206,9 +193,9 @@ Private
 
 Class CodeTextViewBridge Extends CodeTextView Abstract
 
-	Function ProcessRender( item:CodeTextView,canvas:Canvas )
+	Function ProcessRender( item:CodeTextView,rect:Recti,canvas:Canvas )
 		
-		item.OnRenderContent( canvas )
+		item.OnRenderContent( canvas,rect )
 	End
 	
 End

+ 24 - 4
src/ted2go/view/CodeTextView.monkey2

@@ -18,6 +18,7 @@ Class CodeTextView Extends TextView
 		BlockCursor=False
 		
 		CursorMoved += OnCursorMoved
+		Document.TextChanged += TextChanged
 		
 		UpdateThemeColors()
 	End
@@ -202,6 +203,19 @@ Class CodeTextView Extends TextView
 		
 				Scroll-=New Vec2i( 0,RenderStyle.Font.Height*event.Wheel.Y*3 )
 				Return
+			
+			Case EventType.MouseDown 'prevent selection by dragging with right-button
+				
+				If event.Button = MouseButton.Right Return
+				
+				
+			Case EventType.MouseUp
+				
+				If event.Button = MouseButton.Right
+					
+					MainWindow.ShowEditorMenu( Self )
+					Return
+				Endif
 				
 		End
 
@@ -359,7 +373,15 @@ Class CodeTextView Extends TextView
 		Endif
 	End
 	
-	Method SmartPaste()
+	Method SmartPaste( customText:String=Null )
+	
+		Local txt:= customText ? customText Else App.ClipboardText
+	
+		ReplaceText( PrepareSmartPaste( txt ) )
+		
+	End
+	
+	Method PrepareSmartPaste:String( txt:String )
 	
 		' get indent of cursor's line
 		Local cur:=Min( Cursor,Anchor )
@@ -368,7 +390,6 @@ Class CodeTextView Extends TextView
 		Local posInLine:=cur-Document.StartOfLine( line )
 		indent=Min( indent,posInLine )
 	
-		Local txt:=App.ClipboardText
 		txt=txt.Replace( "~r~n","~n" )
 		txt=txt.Replace( "~r","~n" )
 		Local lines:=txt.Split( "~n" )
@@ -388,8 +409,7 @@ Class CodeTextView Extends TextView
 			result+=lines[i]
 		Next
 	
-		ReplaceText( result )
-	
+		Return result
 	End
 	
 	Method DoFormat( all:Bool )

+ 77 - 45
src/ted2go/view/CodeTreeView.monkey2

@@ -7,9 +7,15 @@ Class CodeTreeView Extends TreeViewExt
 	Field SortByType:=True
 	Field ShowInherited:=False
 	
-	Method Fill( fileType:String,path:String )
 	
-		StoreTreeExpands()
+	Method New()
+		
+		_expander=New TreeViewExpander( Self )
+	End
+	
+	Method Fill( fileType:String,path:String,expandIfOnlyOneItem:Bool=True )
+	
+		_expander.Store()
 		
 		Local stack:=New Stack<TreeView.Node>
 		Local parser:=ParsersManager.Get( fileType )
@@ -29,6 +35,9 @@ Class CodeTreeView Extends TreeViewExt
 			AddTreeItem( i,node,parser )
 		Next
 		
+		If expandIfOnlyOneItem And RootNode.NumChildren=1
+			RootNode.Children[0].Expanded=True
+		Endif
 	End
 	
 	Method SelectByScope( scope:CodeItem )
@@ -42,7 +51,7 @@ Class CodeTreeView Extends TreeViewExt
 	
 	Private
 	
-	Field _expands:=New StringMap<Bool>
+	Field _expander:TreeViewExpander
 	
 	
 	Method FindNode:TreeView.Node( treeNode:TreeView.Node,item:CodeItem )
@@ -62,53 +71,12 @@ Class CodeTreeView Extends TreeViewExt
 		Return Null
 	End
 	
-	Method StoreTreeExpands()
-	
-		_expands.Clear()
-		StoreNodeExpand( RootNode )
-		
-	End
-	
-	Method StoreNodeExpand( node:TreeView.Node )
-		
-		If Not node.Expanded Return
-		
-		Local key:=GetNodePath( node )
-		_expands[key]=node.Expanded
-		
-		If node.Children = Null Return
-		
-		For Local i:=Eachin node.Children
-			StoreNodeExpand( i )
-		Next
-		
-	End
-	
-	Method RestoreNodeExpand( node:TreeView.Node )
-	
-		Local key:=GetNodePath( node )
-		node.Expanded=_expands[key]
-		
-	End
-	
-	Method GetNodePath:String( node:TreeView.Node )
-	
-		Local s:=node.Text
-		Local i:=node.Parent
-		While i <> Null
-			s=i.Text+"\"+s
-			i=i.Parent
-		Wend
-		Return s
-		
-	End
-		
 	Method AddTreeItem( item:CodeItem,node:TreeView.Node,parser:ICodeParser )
 	
 		Local n:=New CodeTreeNode( item,node )
 		
 		' restore expand state
-		RestoreNodeExpand( n )
+		_expander.RestoreNode( n )
 		
 		If item.Children = Null And Not ShowInherited Return
 		
@@ -210,3 +178,67 @@ Class CodeTreeNode Extends TreeView.Node
 	Field _code:CodeItem
 	
 End
+
+
+Class TreeViewExpander
+	
+	Method New( tree:TreeView )
+		
+		_tree=tree
+	End
+	
+	Method Store()
+	
+		_expands.Clear()
+		StoreNode( _tree.RootNode )
+	End
+	
+	Method Restore()
+	
+		RestoreNode( _tree.RootNode )
+	End
+	
+	Method RestoreNode( node:TreeView.Node )
+	
+		Local key:=GetNodePath( node )
+		node.Expanded=_expands[key]
+		
+		If node.Children = Null Return
+		
+		For Local i:=Eachin node.Children
+			RestoreNode( i )
+		Next
+	End
+	
+	Private
+	
+	Field _tree:TreeView
+	Field _expands:=New StringMap<Bool>
+	
+	Method GetNodePath:String( node:TreeView.Node )
+	
+		Local s:=node.Text
+		Local i:=node.Parent
+		While i <> Null
+			s=i.Text+"\"+s
+			i=i.Parent
+		Wend
+		Return s
+	End
+	
+	Method StoreNode( node:TreeView.Node )
+	
+		If Not node.Expanded Return
+	
+		Local key:=GetNodePath( node )
+		_expands[key]=node.Expanded
+	
+		If node.Children = Null Return
+	
+		For Local i:=Eachin node.Children
+			StoreNode( i )
+		Next
+	End
+	
+End
+

+ 9 - 0
src/ted2go/view/FileBrowserExt.monkey2

@@ -11,6 +11,7 @@ Class FileBrowserExt Extends TreeView
 	Field FileDoubleClicked:Void( path:String )
 	
 	Method New( rootPath:String="." )
+		
 		Style=GetStyle( "FileBrowser" )
 		
 		GetFileTypeIcons()
@@ -28,6 +29,8 @@ Class FileBrowserExt Extends TreeView
 		
 		RootNode=_rootNode
 		
+		_expander=New TreeViewExpander( Self )
+		
 		Update()
 	End
 	
@@ -49,7 +52,11 @@ Class FileBrowserExt Extends TreeView
 	#end
 	Method Update()
 	
+		_expander.Store()
+		
 		UpdateNode( _rootNode,_rootPath,True )
+		
+		_expander.Restore()
 	End
 	
 	Protected
@@ -83,6 +90,8 @@ Class FileBrowserExt Extends TreeView
 	Field _dirIcon:Image
 	Field _fileIcon:Image
 	
+	Field _expander:TreeViewExpander
+	
 	Method OnNodeClicked( tnode:TreeView.Node )
 	
 		Local node:=Cast<Node>( tnode )

+ 1 - 0
src/ted2go/view/IRCView.monkey2

@@ -929,6 +929,7 @@ Class IRCView Extends DockingView
 		inputField.BlockCursor=False
 		inputField.CursorType=CursorType.Line
 		inputField.CursorBlinkRate=2.5
+		inputField.MaxLength=512
 		inputField.Entered+=Lambda()
 			SendInput(inputField.Text)
 			inputField.Text=Null

+ 36 - 6
src/ted2go/view/ListViewExt.monkey2

@@ -9,7 +9,7 @@ Class ListViewItem
 	Setter( value:String )
 		_text=value
 	End
-	
+
 	Property Icon:Image()
 		Return _icon
 	Setter( value:Image )
@@ -30,7 +30,7 @@ Class ListViewItem
 		canvas.Color=App.Theme.DefaultStyle.TextColor
 		canvas.DrawText( _text,x+dx,y,handleX,handleY )
 	End
-	
+
 	
 	Private
 	
@@ -44,9 +44,13 @@ Class ListViewExt Extends ScrollableView
 
 	Field OnItemChoosen:Void()
 	
+	Method New()
+		Self.New( 20,50 )
+	End
+	
 	Method New( lineHeight:Int,maxLines:Int )
 		
-		_lineH=lineHeight
+		_lineHeightEtalon=lineHeight
 		_maxLines=maxLines
 		
 		_items=New List<ListViewItem>
@@ -56,6 +60,7 @@ Class ListViewExt Extends ScrollableView
 		_selColor=App.Theme.GetColor( "content" )
 		_hoverColor=App.Theme.GetColor( "knob" )
 		
+		OnThemeChanged()
 	End
 	
 	Method AddItems( items:Stack<ListViewItem> )
@@ -67,18 +72,37 @@ Class ListViewExt Extends ScrollableView
 		_visibleCount=Min( _maxLines,_count )
 	End
 	
+	Method AddItem( item:ListViewItem )
+	
+		_items.AddLast( item )
+		_count=_items.Count()
+		_visibleCount=Min( _maxLines,_count )
+	End
+	
 	Method SetItems<T>( items:Stack<T> ) Where T Extends ListViewItem
 		
 		_items.Clear()
 		AddItems( items )
 	End
 	
+	Method SetItems<T>( items:T[] ) Where T Extends ListViewItem
+	
+		_items.Clear()
+		AddItems( items )
+	End
+	
 	Method Reset()
 		
 		_selIndex=0
 		Scroll=New Vec2i
 	End
 	
+	Method Clear()
+	
+		Reset()
+		_items.Clear()
+	End
+	
 	Property LineHeight:Float()
 		Return _lineH
 	End
@@ -155,7 +179,9 @@ Class ListViewExt Extends ScrollableView
 	
 	Protected
 	
-	Method New()
+	Method OnThemeChanged() Override
+	
+		_lineH=_lineHeightEtalon*App.Theme.Scale.y
 	End
 	
 	Method SelectPrevInternal( ensureVis:Bool )
@@ -271,13 +297,17 @@ Class ListViewExt Extends ScrollableView
 		
 			Local index:=(MouseLocation.y+Scroll.y)/_lineH
 			
+			If index < 0 Or index >= _count Return
+			
 			_selIndex=index
 			OnItemChoosen()
 			
 		Case EventType.MouseClick
 		
 			Local index:=(MouseLocation.y+Scroll.y)/_lineH
-		
+			
+			If index < 0 Or index >= _count Return
+			
 			_selIndex=index
 			OnItemChoosen()
 			
@@ -291,7 +321,7 @@ Class ListViewExt Extends ScrollableView
 	Private
 	
 	Field _items:List<ListViewItem>
-	Field _lineH:Int
+	Field _lineH:Int,_lineHeightEtalon:Int
 	Field _count:Int,_visibleCount:Int
 	Field _maxLines:Int
 	Field _selIndex:Int

+ 38 - 11
src/ted2go/view/ProjectView.monkey2

@@ -72,28 +72,36 @@ Class ProjectView Extends ScrollView
 				
 				menu.AddSeparator()
 				
+				menu.AddAction( "New class..." ).Triggered=Lambda()
+				
+					Local d:=New GenerateClassDialog( path )
+					d.Generated+=Lambda( filePath:String,fileContent:String )
+						
+						If CreateFileInternal( filePath,fileContent )
+						
+							MainWindow.OpenDocument( filePath )
+							browser.Refresh()
+						Endif
+					End
+					d.ShowModal()
+					Return
+				End
+				
+				menu.AddSeparator()
+				
 				menu.AddAction( "New file" ).Triggered=Lambda()
 				
 					Local file:=RequestString( "New file name:" )
 					If Not file Return
 					
-					If ExtractExt(file)="" Then file+=".monkey2"
-					
 					Local tpath:=path+"/"+file
 					
-					If GetFileType( tpath )<>FileType.None
-						Alert( "A file or directory already exists at '"+tpath+"'" )
-						Return
-					End
-					
-					If Not CreateFile( tpath )
-						Alert( "Failed to create file '"+file+"'" )
-					Endif
+					CreateFileInternal( tpath )
 					
 					browser.Refresh()
 					Return
 				End
-		
+				
 				menu.AddAction( "New folder" ).Triggered=Lambda()
 				
 					Local dir:=RequestString( "New folder name:" )
@@ -360,4 +368,23 @@ Class ProjectView Extends ScrollView
 		Return succ>0
 	End
 	
+	Method CreateFileInternal:Bool( path:String,content:String=Null )
+		
+		If ExtractExt(path)="" Then path+=".monkey2"
+		
+		If GetFileType( path )<>FileType.None
+			Alert( "A file or directory already exists at '"+path+"'" )
+			Return False
+		End
+		
+		If Not CreateFile( path )
+			Alert( "Failed to create file '"+StripDir( path )+"'" )
+			Return False
+		Endif
+		
+		If content Then SaveString( content,path )
+		
+		Return True
+	End
+	
 End

+ 49 - 0
src/ted2go/view/Ted2CodeTextView.monkey2

@@ -0,0 +1,49 @@
+
+Namespace ted2go
+
+
+Class Ted2CodeTextView Extends CodeTextView
+
+	Property FileType:String() 'where else we can store this type?
+		return _type
+	Setter( value:String )
+		_type=value
+		Keywords = KeywordsManager.Get(_type)
+		Highlighter = HighlightersManager.Get(_type)
+		Formatter = FormattersManager.Get(_type)
+		Document.TextHighlighter = Highlighter.Painter
+	End
+	
+	Property FilePath:String()
+		return _path
+	Setter(value:String)
+		_path = value
+	End
+	
+	Method LoadCode( path:String,type:String=".monkey2" )
+		
+		If Not type Then type=ExtractExt( path )
+		FileType=type
+		FilePath=path
+		Text=LoadString( path )
+	End
+	
+	
+	Protected
+	
+	Method OnKeyEvent( event:KeyEvent ) Override
+	
+		TextViewKeyEventFilter.FilterKeyEvent( event,Self,FileType )
+		
+		If Not event.Eaten
+			Super.OnKeyEvent( event )
+		Endif
+		
+	End
+
+	Private
+	
+	Field _type:String
+	Field _path:String
+	
+End

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov