Bladeren bron

Display line number next to properties on domkit inspector (#1194)

Leonardo 1 jaar geleden
bovenliggende
commit
18fa2917bd
1 gewijzigde bestanden met toevoegingen van 165 en 14 verwijderingen
  1. 165 14
      h2d/domkit/Style.hx

+ 165 - 14
h2d/domkit/Style.hx

@@ -1,5 +1,11 @@
 package h2d.domkit;
 
+typedef SourceFile = {
+	name: String,
+	txt: String,
+	#if (format >= version("3.8.0")) sourceMap: format.map.Data, #end
+}
+
 class Style extends domkit.CssStyle {
 
 	var currentObjects : Array<h2d.Object> = [];
@@ -28,7 +34,7 @@ class Style extends domkit.CssStyle {
 		});
 		resources.push(r);
 		var variables = cssParser.variables.copy();
-		add(cssParser.parseSheet(r.entry.getText()));
+		add(cssParser.parseSheet(r.entry.getText(), r.name));
 		cssParser.variables = variables;
 		for( o in currentObjects )
 			o.dom.applyStyle(this);
@@ -77,31 +83,110 @@ class Style extends domkit.CssStyle {
 				ee = ee.parent;
 			}
 			if( msg == null ) msg = "Invalid property value '"+(domkit.CssParser.valueStr(s.value))+"'";
-			errors.push(msg+" for " + path);
+			var posStr = "";
+			var f = find(sourceFiles, f -> f.name == s.pos.file);
+			if (s.pos != null && f != null) {
+				var pos = getPos(f, s.pos.pmin);
+				posStr = pos.file+":"+pos.line+": ";
+			}
+			errors.push(posStr+msg+" for " + path);
 		}
 	}
 
+	inline function find<T>( it : Array<T>, f : T -> Bool ) : Null<T> {
+		var ret = null;
+		for( v in it ) {
+			if(f(v)) {
+				ret = v;
+				break;
+			}
+		}
+		return ret;
+	}
+	inline function countLines(str: String, until = -1, code = "\n".code) {
+		var ret = {
+			line: 1,
+			col: 0,
+		}
+		if (until < 0)
+			until = str.length;
+		var lastFound = 0;
+		for( i in 0...until ) {
+			if( StringTools.fastCodeAt(str, i) == code ) {
+				ret.line++;
+				lastFound = i;
+			}
+		}
+		ret.col = until - lastFound;
+		return ret;
+	}
+	inline function getPos(f: SourceFile, pmin) {
+		var count = countLines(f.txt, pmin);
+		var line = count.line;
+		var col = count.col;
+		var file = f.name;
+		#if (format >= version("3.8.0"))
+		if (f.sourceMap != null) {
+			var pos = f.sourceMap.originalPositionFor(count.line, count.col);
+			if (pos != null) {
+				file = pos.source;
+				line = pos.originalLine;
+				col = pos.originalColumn;
+			}
+		}
+		#end
+		return {
+			line: line,
+			count: count,
+			file: file,
+		};
+	}
+
+	#if (format >= version("3.8.0"))
+	function getSourceMapFor(r: hxd.res.Resource) {
+		var mapFile = r.entry.path + ".map";
+		if( hxd.res.Loader.currentInstance.exists(mapFile) ) {
+			var mapContent = hxd.res.Loader.currentInstance.load(mapFile).toText();
+			try {
+				return new format.map.Reader().parse(mapContent);
+			} catch(e) {}
+		}
+		return null;
+	}
+	#end
+	var sourceFiles: Array<SourceFile> = [];
+
 	function onChange( ntry : Int = 0 ) {
 		if( ntry >= 10 ) return;
 		ntry++;
 		var oldRules = data.rules;
 		errors = [];
 		data.rules = [];
+		sourceFiles = [];
 		for( r in resources ) {
 			var txt = try r.entry.getText() catch( e : Dynamic ) { haxe.Timer.delay(onChange.bind(ntry),100); data.rules = oldRules; return; }
+			var curFile = {
+				name: r.entry.name,
+				txt: txt,
+				#if (format >= version("3.8.0"))
+				sourceMap: getSourceMapFor(r),
+				#end
+			};
+			sourceFiles.push(curFile);
 			try {
-				data.add(cssParser.parseSheet(txt));
+				data.add(cssParser.parseSheet(txt, r.name));
 			} catch( e : domkit.Error ) {
 				cssParser.warnings.push({ msg : e.message, pmin : e.pmin, pmax : e.pmax });
 			}
 			for( w in cssParser.warnings ) {
-				var line = txt.substr(0,w.pmin).split("\n").length;
-				errors.push(r.entry.path+":"+line+": " + w.msg);
+				var pos = getPos(curFile, w.pmin);
+				errors.push(pos.file+":"+pos.line+": " + w.msg);
 		 	}
 		}
 		for( o in currentObjects )
 			o.dom.applyStyle(this);
 		refreshErrors();
+		sourceFiles = [];
 	}
 
 	function refreshErrors( ?scene ) {
@@ -160,7 +245,10 @@ class Style extends domkit.CssStyle {
 				if( s == null || scenes.indexOf(s) >= 0 ) continue;
 				scenes.push(s);
 				function scanRec(o:h2d.Object) {
-					if( o.dom != null ) @:privateAccess o.dom.currentValues = null;
+					if( o.dom != null ) {
+						@:privateAccess o.dom.currentValues = null;
+						@:privateAccess o.dom.currentRuleStyles = null;
+					}
 					for( o in o ) scanRec(o);
 				}
 				scanRec(s);
@@ -173,9 +261,11 @@ class Style extends domkit.CssStyle {
 		return allowInspect = b;
 	}
 
+	var lastFrame = -1;
 	function onWindowEvent( e : hxd.Event ) {
 		switch( e.kind ) {
 		case EPush if( inspectKeyCode == 0 || hxd.Key.isDown(inspectKeyCode) ):
+			lastFrame = -1;
 			if( e.button == hxd.Key.MOUSE_MIDDLE ) {
 				if(hxd.Key.isDown(inspectDetailsKeyCode)) {
 					inspectModeActive = true;
@@ -199,8 +289,20 @@ class Style extends domkit.CssStyle {
 				}
 			}
 		case EMove:
-			if( inspectModeActive && !inspectModeDetails) updatePreview(e);
+			if( inspectModeActive && !inspectModeDetails ) {
+				var anyScene = null;
+				for( o in currentObjects ) {
+					anyScene = o.getScene();
+					if( anyScene != null ) break;
+				}
+				if( anyScene == null || lastFrame < anyScene.renderer.frame ) {
+					if( anyScene != null )
+						lastFrame = anyScene.renderer.frame;
+					updatePreview(e);
+				}
+			}
 		case EWheel if( inspectKeyCode == 0 || hxd.Key.isDown(inspectKeyCode) ):
+			lastFrame = -1;
 			if( inspectPreviewObjects != null ) {
 				if( e.wheelDelta > 0 ) {
 					var p = inspectPreviewObjects[0].parent;
@@ -389,25 +491,74 @@ class Style extends domkit.CssStyle {
 		prevFlow.backgroundTile = h2d.Tile.fromColor(0,0.8);
 		prevFlow.padding = 7;
 		prevFlow.paddingTop = 4;
+		prevFlow.layout = Vertical;
+		prevFlow.verticalSpacing = 16;
+
+		var previewTitle = new h2d.HtmlText(hxd.res.DefaultFont.get(), prevFlow);
 
-		var previewText = new h2d.HtmlText(hxd.res.DefaultFont.get(), prevFlow);
-		var lines = [];
-		lines.push(getDisplayInfo(obj));
-		lines.push("");
+		var propsFlow = new h2d.Flow(prevFlow);
+		var propsLineText = new h2d.HtmlText(hxd.res.DefaultFont.get(), propsFlow);
+		var propsValueText = new h2d.HtmlText(hxd.res.DefaultFont.get(), propsFlow);
+
+		previewTitle.text = getDisplayInfo(obj);
 		var dom = obj.dom;
+
 		if(dom != null) {
+			var posLines = [];
+			var valueLines = [];
+			var files: Array<SourceFile> = [];
+			var lineDigits = 0;
+			for( i in 0...dom.currentSet.length ) {
+				if( dom.currentRuleStyles == null || dom.currentRuleStyles[i] == null )
+					continue;
+				var vs = dom.currentRuleStyles[i];
+				if (find(files, f -> f.name == vs.pos.file) != null)
+					continue;
+				var r = find(resources, r -> r.name == vs.pos.file);
+				if (r != null) {
+					var txt = r.entry.getText();
+					files.push({
+						name: vs.pos.file,
+						txt: txt,
+						#if (format >= version("3.8.0"))
+						sourceMap: getSourceMapFor(r),
+						#end
+					});
+					lineDigits = hxd.Math.imax(lineDigits, Std.int(Math.log(countLines(txt).line) / Math.log(10)));
+				}
+			}
+
 			for( s in dom.style ) {
 				if( s.p.name == "text" || Std.isOfType(s.value,h2d.Tile) ) continue;
-				lines.push(' <font color="#D0D0D0"> ${s.p.name}</font> <font color="#808080">${s.value}</font><font color="#606060"> (style)</font>');
+				valueLines.push(' <font color="#D0D0D0"> ${s.p.name}</font> <font color="#808080">${s.value}</font><font color="#606060"> (style)</font>');
 			}
+			var emptyDigits = "";
+			for (i in 0...lineDigits)
+				emptyDigits += " ";
 			for( i in 0...dom.currentSet.length ) {
 				var p = dom.currentSet[i];
 				if( p.name == "text" ) continue;
 				var v = dom.currentValues == null ? null : dom.currentValues[i];
+				var vs = dom.currentRuleStyles == null ? null : dom.currentRuleStyles[i];
+				var lStr = emptyDigits;
+				if (vs != null) {
+					v = vs.value;
+					var f = find(files, f -> f.name == vs.pos.file);
+					if (f != null) {
+						var pos = getPos(f, vs.pos.pmin);
+						var s = "" + pos.line;
+						if (pos.file == null)
+							lStr = '<font color="#707070">$s</font>';
+						else
+							lStr = '<font color="#707070">${pos.file}:$s</font>';
+					}
+				}
 				var vstr = v == null ? "???" : StringTools.htmlEscape(domkit.CssParser.valueStr(v));
-				lines.push(' <font color="#D0D0D0"> ${p.name}</font> <font color="#808080">$vstr</font>');
+				posLines.push(lStr);
+				valueLines.push('<font color="#D0D0D0"> ${p.name}</font> <font color="#808080">$vstr</font>');
 			}
-			previewText.text = lines.join("<br/>");
+			propsLineText.text = posLines.join("<br/>");
+			propsValueText.text = valueLines.join("<br/>");
 		}
 
 		var size = prevFlow.getBounds();