瀏覽代碼

added filewatcher, refresh fileview/filetree on file change

ncannasse 7 年之前
父節點
當前提交
e5a8eec3b7
共有 5 個文件被更改,包括 116 次插入7 次删除
  1. 62 0
      hide/tools/FileWatcher.hx
  2. 7 0
      hide/ui/Ide.hx
  3. 25 6
      hide/ui/View.hx
  4. 4 0
      hide/view/FileTree.hx
  5. 18 1
      hide/view/FileView.hx

+ 62 - 0
hide/tools/FileWatcher.hx

@@ -0,0 +1,62 @@
+package hide.tools;
+
+class FileWatcher {
+
+	var ide : hide.ui.Ide;
+	var watches : Map<String,{ events : Array<{path:String,fun:Void->Void,checkDel:Bool}>, w : js.node.fs.FSWatcher, changed : Bool }> = new Map();
+
+	public function new() {
+		ide = hide.ui.Ide.inst;
+	}
+
+	public function register( path : String, updateFun, ?checkDelete : Bool ) {
+		var w = getWatches(path);
+		w.events.push({ path : path, fun : updateFun, checkDel : checkDelete });
+	}
+
+	public function unregister( path : String, updateFun ) {
+		var w = getWatches(path);
+		for( e in w.events )
+			if( Reflect.compareMethods(e.fun, updateFun) ) {
+				w.events.remove(e);
+				break;
+			}
+		if( w.events.length == 0 ) {
+			watches.remove(path);
+			if( w.w != null ) w.w.close();
+		}
+	}
+
+	function getWatches( path : String ) {
+		var w = watches.get(path);
+		if( w == null ) {
+			w = {
+				events : [],
+				w : null,
+				changed : false,
+			};
+			w.w = try js.node.Fs.watch(ide.getPath(path), function(k:String, file:String) {
+				w.changed = true;
+				haxe.Timer.delay(function() {
+					if( !w.changed ) return;
+					w.changed = false;
+					for( e in w.events.copy() )
+						if( k == "change" || e.checkDel )
+							e.fun();
+				}, 100);
+			}) catch( e : Dynamic ) {
+				// file does not exists, trigger a delayed event
+				haxe.Timer.delay(function() {
+					for( e in w.events )
+						if( e.checkDel )
+							e.fun();
+				}, 0);
+				return w;
+			}
+			watches.set(path, w);
+		}
+		return w;
+	}
+
+
+}

+ 7 - 0
hide/ui/Ide.hx

@@ -14,6 +14,7 @@ class Ide {
 
 	public var database : cdb.Database;
 	public var shaderLoader : hide.tools.ShaderLoader;
+	public var fileWatcher : hide.tools.FileWatcher;
 
 	var databaseFile : String;
 
@@ -49,6 +50,8 @@ class Ide {
 		}
 		window.show(true);
 
+		fileWatcher = new hide.tools.FileWatcher();
+
 		setProject(ideProps.currentProject);
 		window.window.document.addEventListener("mousemove", function(e) {
 			mouseX = e.x;
@@ -511,6 +514,10 @@ class Ide {
 			target.addChild(config, index);
 	}
 
+	public function confirm( text : String ) {
+		return js.Browser.window.confirm(text);
+	}
+
 	public function ask( text : String, ?defaultValue = "" ) {
 		return js.Browser.window.prompt(text, defaultValue);
 	}

+ 25 - 6
hide/ui/View.hx

@@ -17,6 +17,7 @@ class View<T> extends hide.comp.Component {
 	var keys(get,null) : Keys;
 	var props(get,null) : Props;
 	var undo = new hide.ui.UndoHistory();
+	var watches : Array<{ keep : Bool, path : String, callb : Void -> Void }> = [];
 	public var viewClass(get, never) : String;
 	public var defaultOptions(get,never) : ViewOptions;
 
@@ -29,6 +30,12 @@ class View<T> extends hide.comp.Component {
 		ide = Ide.inst;
 	}
 
+	function watch( filePath : String, onChange : Void -> Void, ?opts : { ?checkDelete : Bool, ?keepOnRebuild : Bool } ) {
+		if( opts == null ) opts = {};
+		ide.fileWatcher.register(filePath, onChange, opts.checkDelete);
+		watches.push({ keep : opts.keepOnRebuild, path : filePath, callb : onChange });
+	}
+
 	function get_props() {
 		if( props == null )
 			props = ide.currentProps;
@@ -85,12 +92,7 @@ class View<T> extends hide.comp.Component {
 				e.preventDefault();
 				return;
 			}
-			@:privateAccess ide.views.remove(this);
-			for( c in container.getElement().find("canvas") ) {
-				var s : hide.comp.Scene = Reflect.field(c, "__scene");
-				if( s != null )
-					s.dispose();
-			}
+			destroy();
 		});
 		container.getElement().keydown(function(e) {
 			keys.processEvent(e);
@@ -109,6 +111,11 @@ class View<T> extends hide.comp.Component {
 
 	public function rebuild() {
 		if( container == null ) return;
+		for( w in watches.copy() )
+			if( !w.keep ) {
+				ide.fileWatcher.unregister(w.path, w.path);
+				watches.remove(w);
+			}
 		syncTitle();
 		root.html('');
 		onDisplay();
@@ -130,6 +137,18 @@ class View<T> extends hide.comp.Component {
 			container.close();
 	}
 
+	function destroy() {
+		for( w in watches.copy() )
+			ide.fileWatcher.unregister(w.path, w.path);
+		watches = [];
+		@:privateAccess ide.views.remove(this);
+		for( c in container.getElement().find("canvas") ) {
+			var s : hide.comp.Scene = Reflect.field(c, "__scene");
+			if( s != null )
+				s.dispose();
+		}
+	}
+
 	function buildTabMenu() : Array<hide.comp.ContextMenu.ContextMenuItem> {
 		return [
 			{ label : "Close", click : close },

+ 4 - 0
hide/view/FileTree.hx

@@ -80,6 +80,10 @@ class FileTree extends FileView {
 					children : isDir,
 				});
 			}
+			ide.fileWatcher.register(basePath, function() {
+				trace(basePath);
+				rebuild();
+			});
 			content.sort(function(a,b) { if( a.children != b.children ) return a.children?-1:1; return Reflect.compare(a.text,b.text); });
 			return content;
 		};

+ 18 - 1
hide/view/FileView.hx

@@ -3,7 +3,24 @@ package hide.view;
 class FileView extends hide.ui.View<{ path : String }> {
 
 	var extension(get,never) : String;
-	var modified(default,set) : Bool;
+	var modified(default, set) : Bool;
+
+	public function new(state) {
+		super(state);
+		watch(state.path, function() onFileChanged(!sys.FileSystem.exists(ide.getPath(state.path))), { checkDelete : true, keepOnRebuild : true });
+	}
+
+	function onFileChanged( wasDeleted : Bool ) {
+		if( wasDeleted ) {
+			if( modified ) return;
+			root.html('${state.path} no longer exists');
+			return;
+		}
+		if( modified && !ide.confirm('${state.path} has been modified, reload and ignore local changes?') )
+			return;
+		modified = false;
+		rebuild();
+	}
 
 	function get_extension() {
 		if( state.path == null )