<commit_before>package com.jediterm.terminal.display;

import com.google.common.collect.Maps;
import com.jediterm.terminal.*;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Buffer for storing styled text data.
 * Stores only text that fit into one screen XxY, but has scrollBuffer to save history lines and textBuffer to restore
 * screen after resize. ScrollBuffer stores all lines before the first line currently shown on the screen. TextBuffer
 * stores lines that are shown currently on the screen and they have there(in TextBuffer) their initial length (even if
 * it doesn't fit to screen width).
 * <p/>
 * Also handles screen damage (TODO: write about it).
 */
public class BackBuffer implements StyledTextConsumer {
  private static final Logger LOG = Logger.getLogger(BackBuffer.class);

  private static final char EMPTY_CHAR = ' '; // (char) 0x0;

  private char[] myBuf;
  private TextStyle[] myStyleBuf;
  private BitSet myDamage;

  @NotNull
  private final StyleState myStyleState;

  private LinesBuffer myScrollBuffer = new LinesBuffer();

  private LinesBuffer myTextBuffer = new LinesBuffer();

  private int myWidth;
  private int myHeight;

  private final Lock myLock = new ReentrantLock();

  private LinesBuffer myTextBufferBackup; // to store textBuffer after switching to alternate buffer
  private LinesBuffer myScrollBufferBackup;
  private boolean myAlternateBuffer = false;

  private boolean myUsingAlternateBuffer = false;

  public BackBuffer(final int width, final int height, @NotNull StyleState styleState) {
    myStyleState = styleState;
    myWidth = width;
    myHeight = height;

    allocateBuffers();
  }

  private void allocateBuffers() {
    myBuf = new char[myWidth * myHeight];
    Arrays.fill(myBuf, EMPTY_CHAR);

    myStyleBuf = new TextStyle[myWidth * myHeight];
    Arrays.fill(myStyleBuf, TextStyle.EMPTY);

    myDamage = new BitSet(myWidth * myHeight);
  }

  public Dimension resize(@NotNull final Dimension pendingResize,
                          @NotNull final RequestOrigin origin,
                          final int cursorY,
                          @NotNull JediTerminal.ResizeHandler resizeHandler) {
    final char[] oldBuf = myBuf;
    final TextStyle[] oldStyleBuf = myStyleBuf;
    final int oldHeight = myHeight;
    final int oldWidth = myWidth;

    final int newWidth = pendingResize.width;
    final int newHeight = pendingResize.height;
    final int scrollLinesCountOld = myScrollBuffer.getLineCount();
    final int textLinesCountOld = myTextBuffer.getLineCount();

    boolean textBufferUpdated = false;

    if (newHeight < cursorY) {
      //we need to move lines from text buffer to the scroll buffer
      int count = cursorY - newHeight;
      if (!myAlternateBuffer) {
        myTextBuffer.moveTopLinesTo(count, myScrollBuffer);
      }
    }
    else if (newHeight > cursorY && myScrollBuffer.getLineCount() > 0) {
      //we need to move lines from scroll buffer to the text buffer
      if (!myAlternateBuffer) {
        myScrollBuffer.moveBottomLinesTo(newHeight - cursorY, myTextBuffer);
        textBufferUpdated = true;
      }
    }

    myWidth = newWidth;
    myHeight = newHeight;

    allocateBuffers();

    Arrays.fill(myBuf, EMPTY_CHAR);

    final int copyWidth = Math.min(oldWidth, myWidth);
    final int copyHeight = Math.min(oldHeight, myHeight);

    final int oldStart;
    final int start;


    if (myHeight > oldHeight) {
      oldStart = 0;

      start = Math.min(myHeight - copyHeight, scrollLinesCountOld);
    }
    else {
      oldStart = Math.max(0, cursorY - myHeight);
      start = 0;
    }

    // copying lines...
    for (int i = 0; i < copyHeight; i++) {
      System.arraycopy(oldBuf, (oldStart + i) * oldWidth, myBuf, (start + i) * myWidth, copyWidth);
      System.arraycopy(oldStyleBuf, (oldStart + i) * oldWidth, myStyleBuf, (start + i) * myWidth, copyWidth);
    }

    if (!myAlternateBuffer && (myWidth > oldWidth || textBufferUpdated)) {
      //we need to fill new space with data from the text buffer
      resetFromTextBuffer();
    }

    if (myTextBuffer.getLineCount() >= myHeight) {
      myTextBuffer.moveTopLinesTo(myTextBuffer.getLineCount() - myHeight, myScrollBuffer);
    }

    int myCursorY = cursorY + (myTextBuffer.getLineCount() - textLinesCountOld);

    myDamage.set(0, myWidth * myHeight - 1, true);

    resizeHandler.sizeUpdated(myWidth, myHeight, myCursorY);

    return pendingResize;
  }

  private void resetFromTextBuffer() {
    clearArea();
    myTextBuffer.processLines(0, getTextBufferLinesCount(), this, 0);
  }

  private void clearArea() {
    clearArea(0, 0, myWidth, myHeight);
  }

  private void clearArea(final int leftX, final int topY, final int rightX, final int bottomY) {
    if (topY > bottomY) {
      LOG.error("Attempt to clear upside down area: top:" + topY + " > bottom:" + bottomY);
      return;
    }
    for (int y = topY; y < bottomY; y++) {
      if (y > myHeight - 1 || y < 0) {
        LOG.error("attempt to clear line " + y + "\n" +
                  "args were x1:" + leftX + " y1:" + topY + " x2:"
                  + rightX + " y2:" + bottomY);
      }
      else if (leftX > rightX) {
        LOG.error("Attempt to clear backwards area: left:" + leftX + " > right:" + rightX);
      }
      else {
        Arrays.fill(myBuf,
                    y * myWidth + leftX,
                    y * myWidth + rightX,
                    EMPTY_CHAR);
        Arrays.fill(myStyleBuf,
                    y * myWidth + leftX,
                    y * myWidth + rightX,
                    TextStyle.EMPTY
        );
        myDamage.set(y * myWidth + leftX,<commit_msg>Clear area with current background color.<commit_after>package com.jediterm.terminal.display;

import com.google.common.collect.Maps;
import com.jediterm.terminal.*;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Buffer for storing styled text data.
 * Stores only text that fit into one screen XxY, but has scrollBuffer to save history lines and textBuffer to restore
 * screen after resize. ScrollBuffer stores all lines before the first line currently shown on the screen. TextBuffer
 * stores lines that are shown currently on the screen and they have there(in TextBuffer) their initial length (even if
 * it doesn't fit to screen width).
 * <p/>
 * Also handles screen damage (TODO: write about it).
 */
public class BackBuffer implements StyledTextConsumer {
  private static final Logger LOG = Logger.getLogger(BackBuffer.class);

  private static final char EMPTY_CHAR = ' '; // (char) 0x0;

  private char[] myBuf;
  private TextStyle[] myStyleBuf;
  private BitSet myDamage;

  @NotNull
  private final StyleState myStyleState;

  private LinesBuffer myScrollBuffer = new LinesBuffer();

  private LinesBuffer myTextBuffer = new LinesBuffer();

  private int myWidth;
  private int myHeight;

  private final Lock myLock = new ReentrantLock();

  private LinesBuffer myTextBufferBackup; // to store textBuffer after switching to alternate buffer
  private LinesBuffer myScrollBufferBackup;
  private boolean myAlternateBuffer = false;

  private boolean myUsingAlternateBuffer = false;

  public BackBuffer(final int width, final int height, @NotNull StyleState styleState) {
    myStyleState = styleState;
    myWidth = width;
    myHeight = height;

    allocateBuffers();
  }

  private void allocateBuffers() {
    myBuf = new char[myWidth * myHeight];
    Arrays.fill(myBuf, EMPTY_CHAR);

    myStyleBuf = new TextStyle[myWidth * myHeight];
    Arrays.fill(myStyleBuf, TextStyle.EMPTY);

    myDamage = new BitSet(myWidth * myHeight);
  }

  public Dimension resize(@NotNull final Dimension pendingResize,
                          @NotNull final RequestOrigin origin,
                          final int cursorY,
                          @NotNull JediTerminal.ResizeHandler resizeHandler) {
    final char[] oldBuf = myBuf;
    final TextStyle[] oldStyleBuf = myStyleBuf;
    final int oldHeight = myHeight;
    final int oldWidth = myWidth;

    final int newWidth = pendingResize.width;
    final int newHeight = pendingResize.height;
    final int scrollLinesCountOld = myScrollBuffer.getLineCount();
    final int textLinesCountOld = myTextBuffer.getLineCount();

    boolean textBufferUpdated = false;

    if (newHeight < cursorY) {
      //we need to move lines from text buffer to the scroll buffer
      int count = cursorY - newHeight;
      if (!myAlternateBuffer) {
        myTextBuffer.moveTopLinesTo(count, myScrollBuffer);
      }
    }
    else if (newHeight > cursorY && myScrollBuffer.getLineCount() > 0) {
      //we need to move lines from scroll buffer to the text buffer
      if (!myAlternateBuffer) {
        myScrollBuffer.moveBottomLinesTo(newHeight - cursorY, myTextBuffer);
        textBufferUpdated = true;
      }
    }

    myWidth = newWidth;
    myHeight = newHeight;

    allocateBuffers();

    Arrays.fill(myBuf, EMPTY_CHAR);

    final int copyWidth = Math.min(oldWidth, myWidth);
    final int copyHeight = Math.min(oldHeight, myHeight);

    final int oldStart;
    final int start;


    if (myHeight > oldHeight) {
      oldStart = 0;

      start = Math.min(myHeight - copyHeight, scrollLinesCountOld);
    }
    else {
      oldStart = Math.max(0, cursorY - myHeight);
      start = 0;
    }

    // copying lines...
    for (int i = 0; i < copyHeight; i++) {
      System.arraycopy(oldBuf, (oldStart + i) * oldWidth, myBuf, (start + i) * myWidth, copyWidth);
      System.arraycopy(oldStyleBuf, (oldStart + i) * oldWidth, myStyleBuf, (start + i) * myWidth, copyWidth);
    }

    if (!myAlternateBuffer && (myWidth > oldWidth || textBufferUpdated)) {
      //we need to fill new space with data from the text buffer
      resetFromTextBuffer();
    }

    if (myTextBuffer.getLineCount() >= myHeight) {
      myTextBuffer.moveTopLinesTo(myTextBuffer.getLineCount() - myHeight, myScrollBuffer);
    }

    int myCursorY = cursorY + (myTextBuffer.getLineCount() - textLinesCountOld);

    myDamage.set(0, myWidth * myHeight - 1, true);

    resizeHandler.sizeUpdated(myWidth, myHeight, myCursorY);

    return pendingResize;
  }

  private void resetFromTextBuffer() {
    clearArea();
    myTextBuffer.processLines(0, getTextBufferLinesCount(), this, 0);
  }

  private void clearArea() {
    clearArea(0, 0, myWidth, myHeight);
  }

  private void clearArea(final int leftX, final int topY, final int rightX, final int bottomY) {
    if (topY > bottomY) {
      LOG.error("Attempt to clear upside down area: top:" + topY + " > bottom:" + bottomY);
      return;
    }
    for (int y = topY; y < bottomY; y++) {
      if (y > myHeight - 1 || y < 0) {
        LOG.error("attempt to clear line " + y + "\n" +
                  "args were x1:" + leftX + " y1:" + topY + " x2:"
                  + rightX + " y2:" + bottomY);
      }
      else if (leftX > rightX) {
        LOG.error("Attempt to clear backwards area: left:" + leftX + " > right:" + rightX);
      }
      else {
        Arrays.fill(myBuf,
                    y * myWidth + leftX,
                    y * myWidth + rightX,
                    EMPTY_CHAR);

        TextStyle style = new TextStyle(myStyleState.getCurrent().getForeground(), myStyleState.getCurrent().getBackground());
        
        Arrays.fill(myStyleBuf,
                    y * myWidth + leftX,
                    y * myWidth + rightX,
                    style
        );
        myDamage.set(y * myWidth + leftX,
{'fraction_non_alphanumeric': 0.096427070197562, 'fraction_numerical': 0.003362757461118117, 'mean_word_length': 2.8573281452658885, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3519814', 'n_tokens_mistral': 3581, 'n_tokens_neox': 3428, 'n_words': 1049}