replaceInLine method

void replaceInLine(
  1. AFCommandContext context,
  2. int lineIdx,
  3. String code,
  4. List<String> createValue(
    1. AFCommandContext context,
    2. List<String> options
    ),
)

Replaces all instances of code in the line with the lines returned by createValue

Implementation

void replaceInLine(AFCommandContext context, int lineIdx, String code, List<String> Function(AFCommandContext context, List<String> options) createValue) {
  modified = true;
  final lineStart = lines[lineIdx];
  final codeStart = "$startCode$code";
  var curStart = lineStart.lastIndexOf(codeStart);
  while(curStart >= 0) {
    final lineCur = lines[lineIdx];
    final charNext = lineCur[curStart+codeStart.length];
    if(charNext != "]" && charNext != "(") {
      if(curStart > 0) {
        curStart = lineCur.lastIndexOf(codeStart, curStart-1);
      } else {
        curStart = -1;
      }
      continue;
    }
    var curEnd = lineCur.indexOf(endCode, curStart);
    if(curEnd < 0) {
      throw AFCommandError(error: "Found $codeStart but failed to find matching $endCode");
    }
    final idxOpenOptions = lineCur.lastIndexOf("(", curEnd);
    final idxCloseOptions = lineCur.lastIndexOf(")", curEnd);
    if(idxOpenOptions > curStart && idxCloseOptions < idxOpenOptions) {
      throw AFCommandError(error: "Found open paren after $codeStart, but did not find close paren.");
    }
    final options = <String>[];
    if(idxOpenOptions > curStart) {
      final optionsStr = lineCur.substring(idxOpenOptions+1, idxCloseOptions);
      final optionsList = optionsStr.split(",");
      options.addAll(optionsList);
    }

    // new algorithm.
    // a: Find the indent always.
    final indentBuf = StringBuffer();
    var idxIndent = 0;
    while(idxIndent < lineStart.length) {
      final val = lineStart[idxIndent++];
      if(val.trim().isEmpty) {
        indentBuf.write(val);
      } else {
        break;
      }
    }

    final indent = indentBuf.toString();
    final textBefore = lineCur.substring(idxIndent-1, curStart);
    final textAfter = lineCur.substring(curEnd+1);
    final isSingleLineInsert = textBefore.isNotEmpty && textAfter.isNotEmpty;
    var internalIndent = "";
    if(isSingleLineInsert) {
      internalIndent = "  ";
    }

    // b, this no longer does the indentation
    final value = createValue(context, options);
    final insertLines = <String>[];
    if(value.isEmpty) {
      insertLines.add("$indent$textBefore$textAfter");
    }
    for(var i = 0; i < value.length; i++) {
      final lineInsert = value[i];
      if(i == 0) {
        var suffix = "";
        if(value.length == 1) {
          suffix = textAfter;
        }
        insertLines.add("$indent$textBefore$lineInsert$suffix");
      } else if(i == (value.length - 1)) {
        insertLines.add("$indent$lineInsert$textAfter");
      } else {
        insertLines.add("$indent$internalIndent$lineInsert");
      }
    }

    lines.removeAt(lineIdx);
    lines.insertAll(lineIdx, insertLines);

    curStart = lineIdx < lines.length ? lines[lineIdx].lastIndexOf(codeStart) : -1;
  }
}