mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2026-10-24 08:02:27 +00:00
display asset line numbers, headers, and errors
- For each detected asset, display its line number and header snippet for reference. - When asset data cannot be found or the number of values detected is incorrect, and inline error message is displayed instead of a (broken) asset editor.
This commit is contained in:
1 parent
cf60055c77
commit
c08c216a48
3 files changed
+87
-6
No files matched your search
+26
@@ -495,6 +495,32 @@ div.asset_file_header {
|
||||
border-radius: 8px;
|
||||
padding-left: 1em;
|
||||
}
|
||||
div.asset_block {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.asset_snip {
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-weight: bold;
|
||||
color: #c1c1b0;
|
||||
background-color: #555;
|
||||
border-radius: 8px;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.asset_lineno {
|
||||
color: #99cc99;
|
||||
display: inline-block;
|
||||
min-width: 4rem;
|
||||
text-align: right;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.asset_error_msg {
|
||||
color: #ff6666;
|
||||
background-color: #330000;
|
||||
padding: 4px 8px;
|
||||
margin: 2px 0;
|
||||
border-left: 3px solid #ff0000;
|
||||
font-family: monospace;
|
||||
}
|
||||
div.asset_grid {
|
||||
line-height:0;
|
||||
margin: 1em;
|
||||
|
||||
@@ -192,6 +192,30 @@ export function convertWordsToImages(words: UintArray, fmt: PixelEditorImageForm
|
||||
return images;
|
||||
}
|
||||
|
||||
export function validateAssetData(datastr: string, fmt): string | null {
|
||||
var words = parseHexWords(convertToHexStatements(datastr));
|
||||
if (fmt.w > 0 && fmt.h > 0) {
|
||||
// same variables as convertWordsToImages
|
||||
var count = fmt.count || 1;
|
||||
var bpp = fmt.bpp || 1;
|
||||
var nplanes = fmt.np || 1;
|
||||
var bitsperword = fmt.bpw || 8;
|
||||
var wordsperline = fmt.sl || Math.ceil(fmt.w * bpp / bitsperword);
|
||||
var pofs = fmt.pofs || wordsperline * fmt.h * count;
|
||||
var skip = fmt.skip || 0;
|
||||
var wpimg = fmt.wpimg || wordsperline * fmt.h;
|
||||
var required = wpimg * count + (nplanes > 1 ? (nplanes - 1) * pofs : 0) + skip;
|
||||
if (words.length != required) {
|
||||
return `Expected ${required} value(s), found ${words.length}`;
|
||||
}
|
||||
} else if (fmt.pal) {
|
||||
if (words.length < 1) {
|
||||
return `Palette requires at least 1 value, found ${words.length}`;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function convertImagesToWords(images: Uint8Array[], fmt: PixelEditorImageFormat): number[] {
|
||||
if (fmt.destfmt) fmt = fmt.destfmt;
|
||||
var width = fmt.w;
|
||||
|
||||
@@ -6,6 +6,15 @@ import { hex, safeident, rgb2bgr } from "../../common/util";
|
||||
import * as pixed from "../pixeleditor";
|
||||
import Mousetrap = require('mousetrap');
|
||||
|
||||
function getLineNumber(data: string, offset: number): number {
|
||||
let line = 1;
|
||||
for (let i = 0; i < offset && i < data.length; i++) {
|
||||
if (data[i] === '\n') line++;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
||||
maindiv: JQuery;
|
||||
cureditordiv: JQuery;
|
||||
@@ -146,14 +155,21 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
||||
end = data.indexOf(';', start); // C
|
||||
}
|
||||
//console.log(id, start, end, m[1], data.substring(start,end));
|
||||
if (end > start) {
|
||||
var line = getLineNumber(data, m.index);
|
||||
var header = m[0];
|
||||
if (end < 0) {
|
||||
var closingDelim = platform_id.includes('verilog') ? '"end"' : m[0].startsWith(';;') ? '";;"' : '";"';
|
||||
result.push({ fileid: id, header: header, line: line, error: `No closing ${closingDelim} found after asset header` });
|
||||
} else if (end <= start) {
|
||||
result.push({ fileid: id, header: header, line: line, error: `Empty data block after asset header` });
|
||||
} else {
|
||||
try {
|
||||
var jsontxt = m[1].replace(/([A-Za-z]+):/g, '"$1":'); // fix lenient JSON
|
||||
var json = JSON.parse(jsontxt);
|
||||
// TODO: name?
|
||||
result.push({ fileid: id, fmt: json, start: start, end: end });
|
||||
result.push({ fileid: id, header: header, line: line, fmt: json, start: start, end: end });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
result.push({ fileid: id, header: header, line: line, error: `Invalid asset format: ${e.message}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,7 +320,22 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
||||
} else if (typeof data === 'string') {
|
||||
let textfrags = this.scanFileTextForAssets(fileid, data);
|
||||
for (let frag of textfrags) {
|
||||
const block = $('<div class="asset_block"/>').appendTo(this.ensureFileDiv(fileid));
|
||||
var snip = $('<div class="asset_snip"/>').appendTo(block);
|
||||
$('<span class="asset_lineno"/>').text(frag.line).appendTo(snip);
|
||||
snip.append(' ' + frag.header);
|
||||
if (frag.error) {
|
||||
$('<div class="asset_error_msg"/>').text(frag.error).appendTo(block);
|
||||
continue;
|
||||
}
|
||||
if (frag.fmt) {
|
||||
// validate data block size before creating editors
|
||||
const assetError = pixed.validateAssetData(data.substring(frag.start, frag.end), frag.fmt);
|
||||
if (assetError) {
|
||||
$('<div class="asset_error_msg"/>').text(assetError).appendTo(block);
|
||||
continue;
|
||||
}
|
||||
|
||||
let label = fileid; // TODO: label
|
||||
let node: pixed.PixNode = new pixed.TextDataNode(projectWindows, fileid, label, frag.start, frag.end);
|
||||
let first = node;
|
||||
@@ -317,19 +348,19 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
||||
node = node.addRight(new pixed.NESNametableConverter(this));
|
||||
node = node.addRight(new pixed.Palettizer(this, { w: 8, h: 8, bpp: 4 }));
|
||||
const fmt = { w: 8 * (frag.fmt.w || 32), h: 8 * (frag.fmt.h || 30), count: 1 }; // TODO: can't do custom sizes
|
||||
node = node.addRight(new pixed.MapEditor(this, newDiv(this.ensureFileDiv(fileid)), fmt));
|
||||
node = node.addRight(new pixed.MapEditor(this, newDiv(block), fmt));
|
||||
this.registerAsset("nametable", first, 2);
|
||||
nassets++;
|
||||
}
|
||||
// is this a bitmap?
|
||||
else if (frag.fmt.w > 0 && frag.fmt.h > 0) {
|
||||
this.addPixelEditor(this.ensureFileDiv(fileid), node, frag.fmt);
|
||||
this.addPixelEditor(block, node, frag.fmt);
|
||||
this.registerAsset("charmap", first, 1);
|
||||
nassets++;
|
||||
}
|
||||
// is this a palette?
|
||||
else if (frag.fmt.pal) {
|
||||
this.addPaletteEditor(this.ensureFileDiv(fileid), node, frag.fmt);
|
||||
this.addPaletteEditor(block, node, frag.fmt);
|
||||
this.registerAsset("palette", first, 0);
|
||||
nassets++;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user