UNPKG

@abaplint/core

Version:
252 lines • 9.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EditHelper = exports.EditDraft = void 0; exports.applyEditSingle = applyEditSingle; exports.applyEditList = applyEditList; const position_1 = require("./position"); const memory_file_1 = require("./files/memory_file"); class EditDraft { constructor(file) { this.start = undefined; this.end = undefined; this.rows = file.getRawRows(); this.file = file; } /** replace existing text, insert text wont work */ replace(pos, value) { if (this.start === undefined || pos.isBefore(this.start)) { this.start = pos; } const end = new position_1.Position(pos.getRow(), pos.getCol() + value.length); if (this.end === undefined || end.isAfter(this.end)) { this.end = end; } const str = this.rows[pos.getRow() - 1]; this.rows[pos.getRow() - 1] = str.substr(0, pos.getCol() - 1) + value + str.substr(pos.getCol() + value.length - 1); } toEdit() { if (this.start === undefined) { throw "EditDraft, start undefined"; } else if (this.end === undefined) { throw "EditDraft, end undefined"; } let value = ""; for (let row = this.start.getRow(); row <= this.end.getRow(); row++) { if (row === this.start.getRow() && row === this.end.getRow()) { // first and last row value = this.rows[row - 1].substring(this.start.getCol() - 1, this.end.getCol() - 1); } else if (row === this.start.getRow()) { // first row value = this.rows[row - 1].substring(this.start.getCol() - 1); } else if (row === this.end.getRow()) { // last row value += "\n" + this.rows[row - 1].substring(0, this.end.getCol() - 1); } else { // middle row value += "\n" + this.rows[row - 1]; } } return EditHelper.replaceRange(this.file, this.start, this.end, value); } } exports.EditDraft = EditDraft; class EditHelper { static mergeList(fixes) { const results = {}; for (const f of fixes) { for (const filename in f) { if (results[filename] === undefined) { results[filename] = []; } results[filename] = results[filename].concat(f[filename]); } } return results; } static merge(fix1, fix2) { const ret = {}; for (const k of Object.keys(fix1)) { if (ret[k] === undefined) { ret[k] = []; } ret[k] = ret[k].concat(fix1[k]); } for (const k of Object.keys(fix2)) { if (ret[k] === undefined) { ret[k] = []; } ret[k] = ret[k].concat(fix2[k]); } return ret; } static findStatement(token, file) { if (file === undefined) { return undefined; } for (const s of file.getStatements()) { if (s.includesToken(token)) { return s; } } return undefined; } static deleteStatement(file, statement) { const scolon = statement.getColon(); if (scolon === undefined) { return EditHelper.deleteRange(file, statement.getFirstToken().getStart(), statement.getLastToken().getEnd()); } let setPrevious = true; let setNext = true; /** previous statement in the chain */ let previousStatement = undefined; /** next statement in the chain */ let nextStatement = undefined; for (const s of file.getStatements()) { const colon = s.getColon(); if (colon === undefined) { continue; } else if (s === statement) { setPrevious = false; setNext = true; continue; } else if (setPrevious === true) { if (scolon.getStart().equals(colon.getStart())) { previousStatement = s; } } else if (setNext === true) { if (scolon.getStart().equals(colon.getStart())) { nextStatement = s; } break; } } if (previousStatement === undefined && nextStatement === undefined) { // the statement to be deleted is the only one in the chain return EditHelper.deleteRange(file, statement.getFirstToken().getStart(), statement.getLastToken().getEnd()); } // the start of deletion should happen for tokens after the colon let startDelete = statement.getFirstToken().getStart(); for (const t of statement.getTokens()) { if (t.getStart().isAfter(scolon.getEnd())) { startDelete = t.getStart(); break; } } const colon = statement.getColon(); if (statement.getLastToken().getStr() === "." && previousStatement) { // last statement in chain const edit1 = EditHelper.replaceToken(file, previousStatement.getLastToken(), "."); const edit2 = EditHelper.deleteRange(file, previousStatement.getLastToken().getEnd(), statement.getLastToken().getEnd()); return EditHelper.merge(edit1, edit2); } else if (previousStatement === undefined && colon && nextStatement) { // first statement in chain return EditHelper.deleteRange(file, this.firstAfterColon(statement), this.firstAfterColon(nextStatement)); } else { // middle statement return EditHelper.deleteRange(file, startDelete, this.firstAfterColon(nextStatement)); } } static firstAfterColon(statement) { const colon = statement.getColon().getStart(); for (const t of statement.getTokens()) { if (t.getStart().isAfter(colon)) { return t.getStart(); } } throw new Error("firstAfterColon, emtpy statement?"); } static deleteToken(file, token) { const filename = file.getFilename(); const range = { start: token.getStart(), end: token.getEnd() }; return { [filename]: [{ range, newText: "" }] }; } static deleteRange(file, start, end) { const filename = file.getFilename(); const range = { start, end }; return { [filename]: [{ range, newText: "" }] }; } static insertAt(file, pos, text) { const filename = file.getFilename(); const range = { start: pos, end: pos }; return { [filename]: [{ range, newText: text }] }; } static replaceToken(file, token, text) { return this.replaceRange(file, token.getStart(), token.getEnd(), text); } static replaceRange(file, start, end, text) { const filename = file.getFilename(); const range = { start, end }; return { [filename]: [{ range, newText: text }] }; } } exports.EditHelper = EditHelper; function applyEditSingle(reg, edit) { var _a; for (const filename in edit) { let rows = (_a = reg.getFileByName(filename)) === null || _a === void 0 ? void 0 : _a.getRawRows(); if (rows === undefined) { throw new Error("applyEdit, file not found"); } for (const e of edit[filename]) { if (e.range.start.getRow() === e.range.end.getRow()) { const line = rows[e.range.start.getRow() - 1]; rows[e.range.start.getRow() - 1] = line.substr(0, e.range.start.getCol() - 1) + e.newText + line.substr(e.range.end.getCol() - 1); } else { const first = rows[e.range.start.getRow() - 1]; let res = first.substr(0, e.range.start.getCol() - 1) + e.newText; const last = rows[e.range.end.getRow() - 1]; res = res + last.substr(e.range.end.getCol() - 1); // delete middle lines rows.splice(e.range.start.getRow(), e.range.end.getRow() - e.range.start.getRow()); // clean up rows[e.range.start.getRow() - 1] = res; rows = rows.join("\n").split("\n"); // if the edit contained newlines and multiple edits } } const result = new memory_file_1.MemoryFile(filename, rows.join("\n")); reg.updateFile(result); } } /** returns list of filenames which were changed */ function applyEditList(reg, edits) { const ret = []; let length = 0; const merged = {}; for (const e of edits) { for (const f in e) { if (merged[f] === undefined) { merged[f] = []; length = length + 1; } merged[f] = merged[f].concat(e[f]); } } for (const f in merged) { const singleFile = {}; // sort, start with the last position first singleFile[f] = merged[f].sort((a, b) => { let val = b.range.start.getRow() - a.range.start.getRow(); if (val === 0) { val = b.range.start.getCol() - a.range.start.getCol(); } return val; }); applyEditSingle(reg, singleFile); ret.push(f); } return ret; } //# sourceMappingURL=edit_helper.js.map