module otya.smilebasic.program; import otya.smilebasic.error; import std.range; import std.container; import std.algorithm; import std.algorithm; unittest { Slot slot; slot.init(); slot.currentLine = 1; assert(slot.get() == "\n"); slot.currentLine = 1; slot.set("1"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "1\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 2; slot.set("2"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "1\n"); assert(slot.get() == "2\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; slot.set("A"); assert(slot.get() == "2\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "A\n"); assert(slot.get() == "2\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 2; slot.set("I\nJ"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); //PRGINS slot.currentLine = 1; slot.insert("3", false); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "3\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; slot.insert("4", true); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "3\n"); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 2; slot.insert("5", false); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "3\n"); assert(slot.get() == "5\n"); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 2; slot.insert("6", true); assert(slot.get() == "6\n"); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); slot.currentLine = 1; assert(slot.get() == "3\n"); assert(slot.get() == "5\n"); assert(slot.get() == "6\n"); assert(slot.get() == "4\n"); assert(slot.get() == "A\n"); assert(slot.get() == "I\n"); assert(slot.get() == "J\n"); assert(slot.get() == "\n"); assert(slot.get() == ""); } struct Slot { DList!wstring program; DList!wstring.Range range; void init() { program = make!(DList!wstring)(["\n"w]); range = program[]; } void load(wstring data) { program.clear(); foreach(l; splitter(data, "\n")) { program.insertBack(l ~ '\n'); } if (program.back == "\n") { program.removeBack(); } range = program[]; } wchar[] text() { import std.algorithm.iteration, std.outbuffer; auto buffer = new OutBuffer(); buffer.reserve(program.opSlice.map!"(a.length + 1) * 2".sum); foreach(line; program) { buffer.write(line); } ubyte[] progbuff = buffer.toBytes; wchar[] progbuff2 = (cast(wchar*)progbuff.ptr)[0..progbuff.length / 2]; return progbuff2; } import otya.smilebasic.token; wstring getLine(SourceLocation loc) { import std.string; int i; foreach (line; program) { i++; if (i == loc.line) return line; } return ""; } void currentLine(int line) { if (line == -1) { //range = DList!wstring.Range(program._last); range = program[]; while (!range.empty) { auto old = range.save; range.popFront(); if (range.empty) { range = old; break; } } return; } range = program[]; range.popFrontN(line - 1); } wstring get() { if (range.empty) { return ""; } auto a = range.front; range.popFront(); return a; } void set(wstring v) { int i; foreach(l; splitter(v, "\n")) { if (!range.empty && i == 0) { auto b = range.save; b.popFront(); if (b.empty) { program.insertBefore(range, l ~ "\n"); } else { range.put(l ~ "\n"); } } else { if (range.empty) { program.insertAfter(range, l ~ "\n"); } else { program.insertBefore(range, l ~ "\n"); } } i++; } } void insert(wstring line, bool isBack) { typeof(range) backup; if (isBack) { backup = range.save; range.popFront(); } foreach(l; splitter(line, "\n")) { if (isBack) { //backup = range.save; program.insertBefore(range, l ~ "\n"); } else { program.insertBefore(range, l ~ "\n"); } } if (isBack) { range = backup; range.popFront(); } } } class Program { Slot[] slot; bool PRGEDITused; int currentSlot; int slotSize = 4; this() { slot = new Slot[5]; foreach(ref s; slot) { s.init(); } } void edit(int slot, int line) { PRGEDITused = true; this.currentSlot = slot; this.slot[slot].currentLine = line; } wstring get() { if (!PRGEDITused) throw new UsePRGEDITBeforeAnyPRGFunction("PRGGET$"); return this.slot[currentSlot].get; } void set(wstring v) { if (!PRGEDITused) throw new UsePRGEDITBeforeAnyPRGFunction("PRGSET"); this.slot[currentSlot].set = v; } void insert(wstring line, bool isBack) { if (!PRGEDITused) throw new UsePRGEDITBeforeAnyPRGFunction("PRGINS"); this.slot[currentSlot].insert(line, isBack); } }