final void doWhenStreamsSynchronized(@NotNull String text, @NotNull ProcessOutputType outputType, @NotNull Runnable flushRunnable) {
    long nowNano = getNanoTime();
    synchronized (myLock) {
      ProcessOutputType baseOutputType = outputType.getBaseOutputType();
      if (ProcessOutputType.SYSTEM.equals(baseOutputType)) {
        handleSystemOutput(flushRunnable, nowNano);
        return;
      }
      Boolean textEndsWithNewline = text.isEmpty() ? null : StringUtil.endsWithChar(text, '\n');
      if ((myLastFlushedChunkBaseOutputType == null || baseOutputType.equals(myLastFlushedChunkBaseOutputType))) {
        boolean newlineAdded = !myFlushedChunksEndWithNewline && Boolean.TRUE.equals(textEndsWithNewline);
        if (textEndsWithNewline != null) {
          myFlushedChunksEndWithNewline = textEndsWithNewline;
        }
        myLastFlushedChunkBaseOutputType = baseOutputType;
        myLastFlushedChunkCreatedNanoTime = nowNano;
        flushRunnable.run();
        if (newlineAdded && myPendingChunks.size() > 0
            && myPendingChunks.get(0).getNanoTimePassedSinceLastFlushedChunk(nowNano) >= AWAIT_SAME_STREAM_TEXT_NANO) {
          processPendingChunks(nowNano);
        }
        return;
      }
      Chunk chunk = new Chunk(textEndsWithNewline, baseOutputType, nowNano, myLastFlushedChunkCreatedNanoTime, flushRunnable);
      myPendingChunks.add(chunk);
      if (!isProcessingScheduled()) {
        long delayNano = AWAIT_SAME_STREAM_TEXT_NANO - chunk.getNanoTimePassedSinceLastFlushedChunk(nowNano);
        if (delayNano <= 0) {
          processPendingChunks(nowNano);
        }
        else {
          myReschedules++;
          scheduleProcessPendingChunks(delayNano);
        }
      }
    }
  }
final void doWhenStreamsSynchronized(@NotNull String text, @NotNull ProcessOutputType outputType, @NotNull Runnable flushRunnable)