Default Log
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Aktives Programm + Cursor — Single Source of Truth (doc/draft_filehandeling.md §9).
|
||||
* Aktives Programm + Cursor — Single Source of Truth.
|
||||
*
|
||||
* Der Cursor lebt zur Laufzeit als In-Memory-Index (schnelles Stepping ohne
|
||||
* Datei-Neuschreiben). Beim Laden wird er aus dem '!'-Kommentar gelesen, beim
|
||||
* Speichern/Entladen als '!' in die Cursor-Zeile zurückgeschrieben.
|
||||
* Datei-Neuschreiben). Beim Speichern wird er ins .json-Sidecar geschrieben;
|
||||
* das .gcode bleibt reiner G-Code ohne '!'-Marker.
|
||||
*
|
||||
* Inhaltliche Änderungen (FPoint, Editieren) werden direkt persistiert (durables
|
||||
* Teaching); reine Cursor-Bewegungen NICHT.
|
||||
@@ -65,15 +65,10 @@ class ActiveState {
|
||||
}
|
||||
|
||||
const prog = await store.read(id);
|
||||
let cursor = 0;
|
||||
const lines = prog.lines.map((line, i) => {
|
||||
if (units.hasCursorMarker(line)) cursor = i;
|
||||
return units.removeCursorMarker(line);
|
||||
});
|
||||
this.programId = id;
|
||||
this.name = prog.name;
|
||||
this.lines = lines;
|
||||
this.cursor = Math.min(cursor, Math.max(0, lines.length - 1));
|
||||
this.lines = prog.lines; // bereits sauber (kein '!'-Marker)
|
||||
this.cursor = Math.min(prog.cursor ?? 0, Math.max(0, prog.lines.length - 1));
|
||||
this.playing = false;
|
||||
this._touch();
|
||||
return this.getState();
|
||||
@@ -199,18 +194,13 @@ class ActiveState {
|
||||
this._requireActive();
|
||||
const id = store.slugify(name);
|
||||
if (!id) throw new ApiError(400, 'INVALID_NAME', `invalid name: ${name}`);
|
||||
const meta = await store.write(id, { name, lines: this._linesWithCursor() });
|
||||
const meta = await store.write(id, { name, lines: this.lines, cursor: this.cursor });
|
||||
return { id: meta.id, lineCount: meta.lineCount };
|
||||
}
|
||||
|
||||
/** In-Memory-Zeilen mit '!' an der Cursor-Position (für die Persistenz). */
|
||||
_linesWithCursor() {
|
||||
return this.lines.map((line, i) => (i === this.cursor ? units.addCursorMarker(line) : line));
|
||||
}
|
||||
|
||||
async _persist() {
|
||||
if (!this.programId) return;
|
||||
await store.write(this.programId, { name: this.name, lines: this._linesWithCursor() });
|
||||
await store.write(this.programId, { name: this.name, lines: this.lines, cursor: this.cursor });
|
||||
}
|
||||
|
||||
async _persistIfActive() {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
const fsp = require('fs/promises');
|
||||
const path = require('path');
|
||||
const cfg = require('../config');
|
||||
const units = require('../gcode/units');
|
||||
const { ApiError } = require('../errors');
|
||||
|
||||
const ID_RE = /^[a-z0-9_]+$/;
|
||||
@@ -55,25 +56,35 @@ function splitLines(text) {
|
||||
.filter((l) => l.trim().length > 0);
|
||||
}
|
||||
|
||||
/** Liest ein Programm: { id, name, lines (Grad, mit Kommentaren), meta }. */
|
||||
/** Liest ein Programm: { id, name, cursor, lines (Grad, sauber ohne '!'), meta }. */
|
||||
async function read(id) {
|
||||
assertValidId(id);
|
||||
if (!(await exists(id))) {
|
||||
throw new ApiError(404, 'PROGRAM_NOT_FOUND', `no program '${id}'`);
|
||||
}
|
||||
const text = await fsp.readFile(gcodePath(id), 'utf8');
|
||||
const lines = splitLines(text);
|
||||
let meta = {};
|
||||
try {
|
||||
meta = JSON.parse(await fsp.readFile(jsonPath(id), 'utf8'));
|
||||
} catch {
|
||||
/* Sidecar ist optional */
|
||||
}
|
||||
return { id, name: meta.name || id, lines, meta };
|
||||
// Migration: alter '!'-Cursor-Marker in .gcode → Cursor liegt jetzt im .json.
|
||||
let legacyCursor = null;
|
||||
const lines = splitLines(text).map((line, i) => {
|
||||
if (units.hasCursorMarker(line)) { legacyCursor = i; return units.removeCursorMarker(line); }
|
||||
return line;
|
||||
});
|
||||
const cursor = meta.cursor ?? legacyCursor ?? 0;
|
||||
return { id, name: meta.name || id, cursor, lines, meta };
|
||||
}
|
||||
|
||||
/** Schreibt .gcode + .json. lines = gespeicherte Zeilen (Grad, inkl. Kommentar/Cursor). */
|
||||
async function write(id, { name, lines }) {
|
||||
/**
|
||||
* Schreibt .gcode + .json.
|
||||
* lines = saubere G-Code-Zeilen (Grad, ohne '!'-Cursor-Marker).
|
||||
* cursor = Cursor-Index (landet im .json, nicht in .gcode).
|
||||
*/
|
||||
async function write(id, { name, lines, cursor = 0 }) {
|
||||
assertValidId(id);
|
||||
await ensureDir();
|
||||
const now = new Date().toISOString();
|
||||
@@ -88,6 +99,7 @@ async function write(id, { name, lines }) {
|
||||
id,
|
||||
name: name || id,
|
||||
lineCount: lines.length,
|
||||
cursor,
|
||||
angleUnit: cfg.storeAngleUnit,
|
||||
createdAt,
|
||||
updatedAt: now,
|
||||
|
||||
Reference in New Issue
Block a user