@abaplint/core
Version:
abaplint - Core API
252 lines • 9.65 kB
JavaScript
"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