/**
   * Sets a styler to use for the given source range. The range must be subrange of actual string of
   * this {@link StyledString}. Stylers previously set for that range will be overwritten.
   *
   * @param offset the start offset of the range
   * @param length the length of the range
   * @param styler the styler to set
   * @throws StringIndexOutOfBoundsException if <code>start</code> is less than zero, or if offset
   *     plus length is greater than the length of this object.
   */
  public void setStyle(int offset, int length, Styler styler)
      throws StringIndexOutOfBoundsException {
    if (offset < 0 || offset + length > fBuffer.length()) {
      throw new StringIndexOutOfBoundsException(
          "Invalid offset ("
              + offset
              + ") or length ("
              + length
              + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
    }
    if (length == 0) {
      return;
    }
    final StyleRun lastRun = getLastRun();
    if (lastRun == null || lastRun.offset <= offset) {
      Styler lastStyler = lastRun == null ? null : lastRun.style;
      appendStyleRun(styler, offset);
      if (offset + length != fBuffer.length()) {
        appendStyleRun(lastStyler, offset + length);
      }
      return;
    }

    int endRun = findRun(offset + length);
    if (endRun >= 0) {
      // run with the same end index, nothing to change
    } else {
      endRun = -(endRun + 1);
      if (offset + length < fBuffer.length()) {
        Styler prevStyle = endRun > 0 ? fStyleRuns.getRun(endRun - 1).style : null;
        fStyleRuns.add(endRun, new StyleRun(offset + length, prevStyle));
      }
    }

    int startRun = findRun(offset);
    if (startRun >= 0) {
      // run with the same start index
      StyleRun styleRun = fStyleRuns.getRun(startRun);
      styleRun.style = styler;
    } else {
      startRun = -(startRun + 1);

      Styler prevStyle = startRun > 0 ? fStyleRuns.getRun(startRun - 1).style : null;
      if (isDifferentStyle(prevStyle, styler) || (startRun == 0 && styler != null)) {
        fStyleRuns.add(startRun, new StyleRun(offset, styler));
        endRun++; // endrun is moved one back
      } else {
        startRun--; // we use the previous
      }
    }
    if (startRun + 1 < endRun) {
      fStyleRuns.removeRange(startRun + 1, endRun);
    }
  }
  private void appendStyleRun(Styler style, int offset) {
    StyleRun lastRun = getLastRun();
    if (lastRun != null && lastRun.offset == offset) {
      lastRun.style = style;
      return;
    }

    if (lastRun == null && style != null
        || lastRun != null && isDifferentStyle(style, lastRun.style)) {
      getStyleRuns().add(new StyleRun(offset, style));
    }
  }