<commit_before>package texteditor.signalsAndEventsFromEventsOnly

import java.awt.Dimension
import java.awt.Graphics2D
import java.awt.Point
import java.awt.Rectangle
import java.awt.SystemColor
import java.awt.Toolkit
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection

import scala.math.max
import scala.math.min
import scala.swing.Component
import scala.swing.event.Key
import scala.swing.event.KeyPressed
import scala.swing.event.KeyTyped
import scala.swing.event.MouseDragged
import scala.swing.event.MouseEvent

import macro.SignalMacro.{SignalM => Signal}
import react.SignalSynt
import react.Var
import react.Signal
import react.events.ImperativeEvent
import reswing.ImperativeSignal
import reswing.ReComponent
import texteditor.JScrollableComponent
import texteditor.LineIterator
import texteditor.LineOffset
import texteditor.Position

class TextArea extends ReComponent {
  override protected lazy val peer = new Component with ComponentMixin {
    override lazy val peer: JScrollableComponent = new JScrollableComponent with SuperMixin
  }
  
  protected def stringWidth = peer.peer.metrics.stringWidth _
  protected def lineHeight = peer.peer.unitHeight
  
  protected val padding = 5
  protected val clipboard = Toolkit.getDefaultToolkit.getSystemClipboard
  
  protected lazy val buffer = new GapBuffer
  
  def this(text: String) {
    this
    buffer.insert(text)
  }
  
  override lazy val preferredSize: ImperativeSignal[Dimension] = Signal{ //#SIG
    def it = LineIterator(buffer.iterable())
    new Dimension(2 * padding + it.map(stringWidth(_)).max, (it.size + 1) * lineHeight)
  }
  
  val charCount = Signal{ buffer.length() } //#SIG
  
  val lineCount = Signal{ LineIterator(buffer.iterable()).size } //#SIG
  
  val wordCount = Signal{ buffer.iterable().iterator.foldLeft((0, false)){(c, ch) => //#SIG
    val alphanum = Character.isLetterOrDigit(ch)
    (if (alphanum && !c._2) c._1 + 1 else c._1, alphanum)}._1
  }
  
  val selected = Signal{  //#SIG
    val (it, dot, mark) = (buffer.iterable(), caret.dot(), caret.mark())
    val (start, end) = (min(dot, mark), max(dot, mark))
    new Iterable[Char] { def iterator = it.iterator.slice(start, end) } : Iterable[Char]
  }
  
  protected val selectedAll = new ImperativeEvent[Unit]  //#EVT
  protected val pasted = new ImperativeEvent[Unit]  //#EVT
  protected val copied = new ImperativeEvent[Unit]   //#EVT
  <commit_msg>markers<commit_after>package texteditor.signalsAndEventsFromEventsOnly

import java.awt.Dimension
import java.awt.Graphics2D
import java.awt.Point
import java.awt.Rectangle
import java.awt.SystemColor
import java.awt.Toolkit
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection

import scala.math.max
import scala.math.min
import scala.swing.Component
import scala.swing.event.Key
import scala.swing.event.KeyPressed
import scala.swing.event.KeyTyped
import scala.swing.event.MouseDragged
import scala.swing.event.MouseEvent

import macro.SignalMacro.{SignalM => Signal}
import react.SignalSynt
import react.Var
import react.Signal
import react.events.ImperativeEvent
import reswing.ImperativeSignal
import reswing.ReComponent
import texteditor.JScrollableComponent
import texteditor.LineIterator
import texteditor.LineOffset
import texteditor.Position

class TextArea extends ReComponent {
  override protected lazy val peer = new Component with ComponentMixin {
    override lazy val peer: JScrollableComponent = new JScrollableComponent with SuperMixin
  }
  
  protected def stringWidth = peer.peer.metrics.stringWidth _
  protected def lineHeight = peer.peer.unitHeight
  
  protected val padding = 5
  protected val clipboard = Toolkit.getDefaultToolkit.getSystemClipboard  
  protected lazy val buffer = new GapBuffer
  
  def this(text: String) {
    this
    buffer.insert(text)
  }
  
  override lazy val preferredSize: ImperativeSignal[Dimension] = Signal{ //#SIG
    def it = LineIterator(buffer.iterable())
    new Dimension(2 * padding + it.map(stringWidth(_)).max, (it.size + 1) * lineHeight)
  }
  
  val charCount = Signal{ buffer.length() } //#SIG
  
  val lineCount = Signal{ LineIterator(buffer.iterable()).size } //#SIG
  
  val wordCount = Signal{ buffer.iterable().iterator.foldLeft((0, false)){(c, ch) => //#SIG
    val alphanum = Character.isLetterOrDigit(ch)
    (if (alphanum && !c._2) c._1 + 1 else c._1, alphanum)}._1
  }
  
  val selected = Signal{  //#SIG
    val (it, dot, mark) = (buffer.iterable(), caret.dot(), caret.mark())
    val (start, end) = (min(dot, mark), max(dot, mark))
    new Iterable[Char] { def iterator = it.iterator.slice(start, end) } : Iterable[Char]
  }
  
  protected val selectedAll = new ImperativeEvent[Unit]  //#EVT
  protected val pasted = new ImperativeEvent[Unit]  //#EVT
  protected val copied = new ImperativeEvent[Unit]   //#EVT
  
{'fraction_non_alphanumeric': 0.10113052415210688, 'fraction_numerical': 0.0041109969167523125, 'mean_word_length': 4.359030837004405, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '3870426', 'n_tokens_mistral': 1529, 'n_tokens_neox': 1518, 'n_words': 388}