Browse Source

script type checking

ncannasse 7 years ago
parent
commit
21a7928f11

+ 8 - 0
bin/cdb.css

@@ -280,5 +280,13 @@
   background: rgba(255, 0, 0, 0.1);
 }
 .cdb .cdb-sheet div.cdb-script .scriptErrorContent {
+  text-decoration: underline dashed red;
+}
+.cdb .cdb-sheet div.cdb-script .scriptErrorMessage {
   background: rgba(255, 5, 5, 0.4);
+  color: red;
+  position: absolute;
+  margin-top: -20px;
+  padding: 2px;
+  border: 1px solid red;
 }

+ 8 - 0
bin/cdb.less

@@ -309,7 +309,15 @@
 				background : rgba(255,0,0,0.1);
 			}
 			.scriptErrorContent {
+				text-decoration: underline dashed red;
+			}
+			.scriptErrorMessage {
 				background : rgba(255, 5, 5, 0.4);
+				color : red;
+				position: absolute;
+				margin-top : -20px;
+				padding: 2px;
+				border: 1px solid red;
 			}
 		}
 

+ 12 - 0
bin/defaultProps.json

@@ -54,6 +54,18 @@
 
 	"cdb.databaseFile" : "data.cdb",
 
+	// script support
+
+	"script.api.files" : [],
+	"script.api.cdbModule" : "Data",
+	"script.api" : {
+		"TableName.fieldName" : {
+			"globals" : { "this" : "ThisClass" },
+			"context" : "ContextClass",
+			"cdbEnums" : false
+		}
+	},
+
 	// paths to look files/shaders into - relative to project root
 	"haxe.classPath" : ["src"],
 

+ 3 - 1
hide/comp/cdb/Editor.hx

@@ -15,12 +15,14 @@ class Editor extends Component {
 		data : {},
 		schema : Array<cdb.Data.Column>,
 	};
+	public var props : hide.ui.Props;
 	public var cursor : Cursor;
 	public var keys : hide.ui.Keys;
 	public var undo : hide.ui.UndoHistory;
 
-	public function new(sheet,?parent) {
+	public function new(sheet,props,?parent) {
 		super(parent,null);
+		this.props = props;
 		this.undo = new hide.ui.UndoHistory();
 		this.sheet = sheet;
 		element.attr("tabindex", 0);

+ 2 - 2
hide/comp/cdb/ObjEditor.hx

@@ -4,12 +4,12 @@ class ObjEditor extends Editor {
 
     public dynamic function onChange(propName : String) {}
 
-    public function new( sheet : cdb.Sheet, obj : {}, ?parent : Element ) {
+    public function new( sheet : cdb.Sheet, props, obj : {}, ?parent : Element ) {
         var sheetData = Reflect.copy(@:privateAccess sheet.sheet);
         sheetData.lines = [for( i in 0...sheet.columns.length ) obj];
         var pseudoSheet = new cdb.Sheet(sheet.base, sheetData);
         this.displayMode = AllProperties;
-        super(pseudoSheet, parent);
+        super(pseudoSheet, props, parent);
     }
 
     override function addChanges( changes : cdb.Database.Changes ) {

+ 74 - 18
hide/comp/cdb/ScriptTable.hx

@@ -1,8 +1,55 @@
 package hide.comp.cdb;
 
+typedef GlobalsDef = haxe.DynamicAccess<{
+	var globals : haxe.DynamicAccess<String>;
+	var context : String;
+	var cdbEnums : Bool;
+}>;
+
 class ScriptTable extends SubTable {
 
 	var edit : monaco.Editor;
+	var check : hscript.Checker;
+	var errorMessage : Element;
+	var currrentDecos : Array<String> = [];
+
+	public function new(editor:Editor,cell) {
+		super(editor,cell);
+		var files : Array<String> = editor.props.get("script.api.files");
+		if( files.length >= 0 ) {
+			check = new hscript.Checker();
+			check.allowAsync = true;
+			for( f in files ) {
+				var content = try sys.io.File.getContent(ide.getPath(f)) catch( e : Dynamic ) { ide.error(e); continue; };
+				check.addXmlApi(Xml.parse(content).firstElement());
+			}
+			var key = cell.table.sheet.name+"."+cell.column.name;
+			var api = (editor.props.get("script.api") : GlobalsDef).get(key);
+			if( api != null ) {
+				for( f in api.globals.keys() )	{
+					var tname = api.globals.get(f);
+					var t = check.resolveType(tname);
+					if( t == null ) ide.error('Global type $tname not found in $files ($f)');
+					check.setGlobal(f, t);
+				}
+				if( api.context != null ) {
+					var t = check.resolveType(api.context);
+					if( t == null ) ide.error("Missing context type "+api.context);
+					while( t != null )
+						switch (t) {
+						case TInst(c, args):
+							for( fname in c.fields.keys() ) {
+								var f = c.fields.get(fname);
+								check.setGlobal(f.name, f.t);
+							}
+							t = c.superClass;
+						default:
+							ide.error(api.context+" context is not a class");
+						}
+				}
+			}
+		}
+	}
 
 	override function makeSubSheet():cdb.Sheet {
 		var sheet = cell.table.sheet;
@@ -19,6 +66,27 @@ class ScriptTable extends SubTable {
 		}, key, { sheet : sheet, column : cell.columnIndex, line : index });
 	}
 
+	function checkScript() {
+		var cur = edit.getValue({preserveBOM:true});
+		try {
+			var expr = new hscript.Parser().parseString(cur, "");
+			if( check != null ) check.check(expr);
+			if( currrentDecos.length != 0 ) currrentDecos = edit.deltaDecorations(currrentDecos,[]);
+			errorMessage.hide();
+		} catch( e : hscript.Expr.Error ) {
+			var linePos = cur.substr(0,e.pmin).lastIndexOf("\n");
+			//trace(e, e.pmin, e.pmax, cur.substr(e.pmin, e.pmax - e.pmin + 1), linePos);
+			if( linePos < 0 ) linePos = 0 else linePos++;
+			var range = new monaco.Range(e.line,e.pmin + 1 - linePos,e.line,e.pmax + 2 - linePos);
+			currrentDecos = edit.deltaDecorations(currrentDecos,[
+				{ range : range, options : { inlineClassName: "scriptErrorContentLine", isWholeLine : true } },
+				{ range : range, options : { linesDecorationsClassName: "scriptErrorLine", inlineClassName: "scriptErrorContent" } }
+			]);
+			errorMessage.text(hscript.Printer.errorToString(e));
+			errorMessage.show();
+		}
+	}
+
 	override function refresh() {
 		var first = edit == null;
 		element.html("<div class='cdb-script'></div>");
@@ -32,29 +100,17 @@ class ScriptTable extends SubTable {
 			wordWrap : true,
 			theme : "vs-dark",
 		});
-		var deco = [];
+		errorMessage = new Element('<div class="scriptErrorMessage"></div>').appendTo(lineElement).hide();
 		edit.addCommand(monaco.KeyCode.KEY_S | monaco.KeyMod.CtrlCmd, function() {
 			var cur = edit.getValue({preserveBOM:true});
 			@:privateAccess cell.setValue(cur);
 		});
-		edit.onDidChangeModelContent(function() {
-			var cur = edit.getValue({preserveBOM:true});
-			try {
-				new hscript.Parser().parseString(cur);
-				if( deco.length != 0 ) deco = edit.deltaDecorations(deco,[]);
-			} catch( e : hscript.Expr.Error ) {
-				var linePos = cur.substr(0,e.pmin).lastIndexOf("\n");
-				//trace(e, e.pmin, e.pmax, cur.substr(e.pmin, e.pmax - e.pmin + 1), linePos);
-				if( linePos < 0 ) linePos = 0 else linePos++;
-				var range = new monaco.Range(e.line,e.pmin + 1 - linePos,e.line,e.pmax + 2 - linePos);
-				deco = edit.deltaDecorations(deco,[
-					{ range : range, options : { inlineClassName: "scriptErrorContentLine", isWholeLine : true } },
-					{ range : range, options : { linesDecorationsClassName: "scriptErrorLine", inlineClassName: "scriptErrorContent" } }
-				]);
-			}
-		});
+		edit.onDidChangeModelContent(function() checkScript());
 		lines = [new Line(this,[],0,lineElement)];
-		if( first ) haxe.Timer.delay(function() edit.focus(),0);
+		if( first ) haxe.Timer.delay(function() {
+			edit.focus();
+			checkScript();
+		},0);
 	}
 
 }

+ 1 - 1
hide/view/CdbTable.hx

@@ -20,7 +20,7 @@ class CdbTable extends hide.ui.View<{ path : String }> {
 			return;
 		}
 		element.addClass("hide-scroll");
-		editor = new hide.comp.cdb.Editor(sheet,element);
+		editor = new hide.comp.cdb.Editor(sheet,props,element);
 		editor.undo = undo;
 		undo.onChange = function() {
 			editor.save();

+ 2 - 2
hide/view/l3d/Level3D.hx

@@ -266,7 +266,7 @@ private class Level3DSceneEditor extends hide.comp.SceneEditor {
 
 		if(sheet != null) {
 			var props = new hide.Element('<div></div>').appendTo(group.find(".content"));
-			var editor = new hide.comp.cdb.ObjEditor(sheet, e.props, props);
+			var editor = new hide.comp.cdb.ObjEditor(sheet, parent.props, e.props, props);
 			editor.undo = properties.undo;
 			editor.onChange = function(pname) {
 				edit.onChange(e, 'props.$pname');
@@ -595,7 +595,7 @@ class Level3D extends FileView {
 	}
 
 	function onPrefabChange(p: PrefabElement, ?pname: String) {
-		
+
 	}
 
 	function applySceneStyle(p: PrefabElement) {