Преглед на файлове

Squashed 'src/ted2go/' changes from 0f6470b6..188a508b

188a508b Merge branch 'dev'
84f73667 Fixed bug with Project -- New file.
15f0adfb Merge branch 'dev'
5b976819 Updated about.html.
51645b91 Code map - now drawing by one pass.
54840df5 Improve - completion list now resized accordingly to theme scale. Updated themes images.
610fd362 Added 'Save' icon into main toolbar.
67bb690e Fix in themes.
da3daaf9 Show 'dirty' state on SaveAll toolbar icon.
4999c545 Fixed - click outside console errors list items crash.
1da79f43 Updated themes.
6a036aeb Replace icons with white-color ones. Compress all themes' icons by pngoptimizer.
cff1bac0 Macos - added shortcut Cmd+Backspace - delete line at caret.
de89a83a Done with live templates. Added option to on/off showing templates in completion list.
53dcc5d5 Added Templates into Preferences dialog.
74ba7c08 (wip) Live templates feature.
5dd9bfc0 Cleanup.
49185096 Added "Generate class" dialog.
375bf8ca Fixed project tree expanding state (when create or delete files).
7c495c5f (wip) Show clickable errors list in build console.
98c775f4 Fixed "Find text" bug (have no results for non case sensitive mode).
b795b45c Now closing related docs when close project.
9a6c71d1 Added word-wrap mode for output console.
4b3daa82 Added right-click menu for code editor.
4bafc33f Changed toolbar icons. Added cut/copy/paste button into main toolbar.
0c8eeb9c Merge branch 'dev'
1d181eac Added link to "upload module" to module manager.
52650e42 Merge branch 'redesign_find_dialog' into dev
847ef534 Done with Find entire project logic.
1ec8ca62 Merge pull request #43 from Hezkore/dev
ec96c368 IRC char limit increased to 512 (was 60)
e387e303 Merge pull request #42 from Hezkore/dev
8316318b Merge branch 'dev'
5935adcc Better chat nick notifications
da1cc5de wip Find dialog - added 'entire solution' checkbox

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

+ 158 - 0
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
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
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
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
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
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
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
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
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
assets/gen/newClass.txt

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

+ 30 - 0
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
assets/themes/cancel.png


BIN
assets/themes/codeicons/alias.png


BIN
assets/themes/codeicons/annotation.png


BIN
assets/themes/codeicons/code_template.png


BIN
assets/themes/codeicons/const.png


BIN
assets/themes/codeicons/keyword.png


BIN
assets/themes/codeicons/operator.png


BIN
assets/themes/codeicons/other.png


BIN
assets/themes/codeicons/property.png


BIN
assets/themes/codeicons/property_private.png


BIN
assets/themes/codeicons/property_protected.png


BIN
assets/themes/debug_icons.png


BIN
assets/themes/docbar/back.png


BIN
assets/themes/docbar/forward.png


BIN
assets/themes/docbar/home.png


BIN
assets/themes/hollow_assets/checkbox_icons.png


BIN
assets/themes/hollow_assets/dialog_skin.png


BIN
assets/themes/hollow_assets/progressbar_icons.png


BIN
assets/themes/hollow_assets/tabclose_icons.png


BIN
assets/themes/hollow_assets/treeview_icons.png


BIN
assets/themes/irc/blink.png


BIN
assets/themes/irc/important.png


BIN
assets/themes/irc/notice.png


BIN
assets/themes/outputbar/clean.png


BIN
assets/themes/outputbar/wrap.png


BIN
assets/themes/prime_assets/checkbox_icons.png


BIN
assets/themes/prime_assets/dialog_skin.png


BIN
assets/themes/prime_assets/progressbar_icons.png


BIN
assets/themes/prime_assets/tabclose_icons.png


BIN
assets/themes/prime_assets/treeview_icons.png


BIN
assets/themes/progressbar_icons.png


BIN
assets/themes/project/package.png


BIN
assets/themes/smooth_assets/button_skin.png


BIN
assets/themes/smooth_assets/checkbox_icons.png


BIN
assets/themes/smooth_assets/dialog_skin.png


BIN
assets/themes/smooth_assets/progressbar_icons.png


BIN
assets/themes/smooth_assets/tabbutton_selected_skin.png


BIN
assets/themes/smooth_assets/tabbutton_skin.png


BIN
assets/themes/smooth_assets/tabclose_icons.png


BIN
assets/themes/smooth_assets/treeview_icons.png


BIN
assets/themes/sourcebar/filter_inherited.png


BIN
assets/themes/sourcebar/sort_alpha.png


+ 25 - 3
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
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
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
assets/themes/toolbar/back.png


BIN
assets/themes/toolbar/build.png


BIN
assets/themes/toolbar/check.png


BIN
assets/themes/toolbar/copy.png


BIN
assets/themes/toolbar/cut.png


BIN
assets/themes/toolbar/debug.png


BIN
assets/themes/toolbar/find.png


BIN
assets/themes/toolbar/forward.png


BIN
assets/themes/toolbar/navigate_back.png


BIN
assets/themes/toolbar/navigate_forward.png


BIN
assets/themes/toolbar/new_file.png


BIN
assets/themes/toolbar/open_file.png


BIN
assets/themes/toolbar/open_project.png


BIN
assets/themes/toolbar/options.png


BIN
assets/themes/toolbar/paste.png


BIN
assets/themes/toolbar/paypal.png


BIN
assets/themes/toolbar/redo.png


BIN
assets/themes/toolbar/run.png


BIN
assets/themes/toolbar/save.png


BIN
assets/themes/toolbar/save_all.png


BIN
assets/themes/toolbar/save_all_dirty.png


BIN
assets/themes/toolbar/save_dirty.png


BIN
assets/themes/toolbar/undo.png


BIN
assets/themes/toolbar/zoom_in.png


BIN
assets/themes/toolbar/zoom_out.png


+ 19 - 6
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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

Някои файлове не бяха показани, защото твърде много файлове са промени