<commit_before>#= require trix/observers/mutation_observer
#= require trix/operations/file_verification_operation
#= require trix/controllers/input/composition_input

{handleEvent, makeElement, innerElementIsActive, objectsAreEqual, tagName} = Trix

class Trix.InputController extends Trix.BasicObject
  pastedFileCount = 0

  @keyNames:
    "8":  "backspace"
    "9":  "tab"
    "13": "return"
    "37": "left"
    "39": "right"
    "46": "delete"
    "68": "d"
    "72": "h"
    "79": "o"

  constructor: (@element) ->
    @resetInputSummary()

    @mutationObserver = new Trix.MutationObserver @element
    @mutationObserver.delegate = this

    for eventName of @events
      handleEvent eventName, onElement: @element, withCallback: @handlerFor(eventName), inPhase: "capturing"

  handlerFor: (eventName) ->
    (event) =>
      @handleInput ->
        unless innerElementIsActive(@element)
          @eventName = eventName
          @events[eventName].call(this, event)

  setInputSummary: (summary = {}) ->
    @inputSummary.eventName = @eventName
    @inputSummary[key] = value for key, value of summary
    @inputSummary

  resetInputSummary: ->
    @inputSummary = {}

  reset: ->
    @resetInputSummary()
    Trix.selectionChangeObserver.reset()

  # Render cycle

  editorWillSyncDocumentView: ->
    @mutationObserver.stop()

  editorDidSyncDocumentView: ->
    @mutationObserver.start()

  requestRender: ->
    @delegate?.inputControllerDidRequestRender?()

  requestReparse: ->
    @delegate?.inputControllerDidRequestReparse?()
    @requestRender()

  # Mutation observer delegate

  elementDidMutate: (mutationSummary) ->
    if @isComposing()
      @delegate?.inputControllerDidAllowUnhandledInput?()
    else
      @handleInput ->
        if @mutationIsSignificant(mutationSummary)
          if @mutationIsExpected(mutationSummary)
            @requestRender()
          else
            @requestReparse()
        @reset()

  mutationIsExpected: ({textAdded, textDeleted}) ->
    return true if @inputSummary.preferDocument

    mutationAdditionMatchesSummary =
      if textAdded?
        textAdded is @inputSummary.textAdded
      else
        not @inputSummary.textAdded
    mutationDeletionMatchesSummary =
      if textDeleted?
        @inputSummary.didDelete
      else
        not @inputSummary.didDelete

    unexpectedNewlineAddition =
      textAdded in ["\n", " \n"] and not mutationAdditionMatchesSummary
    unexpectedNewlineDeletion =
      textDeleted is "\n" and not mutationDeletionMatchesSummary
    singleUnexpectedNewline =
      (unexpectedNewlineAddition and not unexpectedNewlineDeletion) or
      (unexpectedNewlineDeletion and not unexpectedNewlineAddition)

    if singleUnexpectedNewline
      if range = @getSelectedRange()
        offset =
          if unexpectedNewlineAddition
            textAdded.replace(/\n$/, "").length or -1
          else
            1
        if @responder?.positionIsBlockBreak(range[1] + offset)
          return true

    mutationAdditionMatchesSummary and mutationDeletionMatchesSummary

  mutationIsSignificant: (mutationSummary) ->
    textChanged = Object.keys(mutationSummary).length > 0
    composedEmptyString = @compositionInput?.getEndData() is ""
    textChanged or not composedEmptyString

  # File verification

  attachFiles: (files) ->
    operations = (new Trix.FileVerificationOperation(file) for file in files)
    Promise.all(operations).then (files) =>
      @handleInput -><commit_msg>Consider length of added text when allowing newline deletion mutations<commit_after>#= require trix/observers/mutation_observer
#= require trix/operations/file_verification_operation
#= require trix/controllers/input/composition_input

{handleEvent, makeElement, innerElementIsActive, objectsAreEqual, tagName} = Trix

class Trix.InputController extends Trix.BasicObject
  pastedFileCount = 0

  @keyNames:
    "8":  "backspace"
    "9":  "tab"
    "13": "return"
    "37": "left"
    "39": "right"
    "46": "delete"
    "68": "d"
    "72": "h"
    "79": "o"

  constructor: (@element) ->
    @resetInputSummary()

    @mutationObserver = new Trix.MutationObserver @element
    @mutationObserver.delegate = this

    for eventName of @events
      handleEvent eventName, onElement: @element, withCallback: @handlerFor(eventName), inPhase: "capturing"

  handlerFor: (eventName) ->
    (event) =>
      @handleInput ->
        unless innerElementIsActive(@element)
          @eventName = eventName
          @events[eventName].call(this, event)

  setInputSummary: (summary = {}) ->
    @inputSummary.eventName = @eventName
    @inputSummary[key] = value for key, value of summary
    @inputSummary

  resetInputSummary: ->
    @inputSummary = {}

  reset: ->
    @resetInputSummary()
    Trix.selectionChangeObserver.reset()

  # Render cycle

  editorWillSyncDocumentView: ->
    @mutationObserver.stop()

  editorDidSyncDocumentView: ->
    @mutationObserver.start()

  requestRender: ->
    @delegate?.inputControllerDidRequestRender?()

  requestReparse: ->
    @delegate?.inputControllerDidRequestReparse?()
    @requestRender()

  # Mutation observer delegate

  elementDidMutate: (mutationSummary) ->
    if @isComposing()
      @delegate?.inputControllerDidAllowUnhandledInput?()
    else
      @handleInput ->
        if @mutationIsSignificant(mutationSummary)
          if @mutationIsExpected(mutationSummary)
            @requestRender()
          else
            @requestReparse()
        @reset()

  mutationIsExpected: ({textAdded, textDeleted}) ->
    return true if @inputSummary.preferDocument

    mutationAdditionMatchesSummary =
      if textAdded?
        textAdded is @inputSummary.textAdded
      else
        not @inputSummary.textAdded
    mutationDeletionMatchesSummary =
      if textDeleted?
        @inputSummary.didDelete
      else
        not @inputSummary.didDelete

    unexpectedNewlineAddition =
      textAdded in ["\n", " \n"] and not mutationAdditionMatchesSummary
    unexpectedNewlineDeletion =
      textDeleted is "\n" and not mutationDeletionMatchesSummary
    singleUnexpectedNewline =
      (unexpectedNewlineAddition and not unexpectedNewlineDeletion) or
      (unexpectedNewlineDeletion and not unexpectedNewlineAddition)

    if singleUnexpectedNewline
      if range = @getSelectedRange()
        offset =
          if unexpectedNewlineAddition
            textAdded.replace(/\n$/, "").length or -1
          else
            textAdded?.length or 1
        if @responder?.positionIsBlockBreak(range[1] + offset)
          return true

    mutationAdditionMatchesSummary and mutationDeletionMatchesSummary

  mutationIsSignificant: (mutationSummary) ->
    textChanged = Object.keys(mutationSummary).length > 0
    composedEmptyString = @compositionInput?.getEndData() is ""
    textChanged or not composedEmptyString

  # File verification

  attachFiles: (files) ->
    operations = (new Trix.FileVerificationOperation(file) for file in files)
    Promise.all(operations).then (files) =>
      @handleInput ->
{'fraction_non_alphanumeric': 0.09622480840193018, 'fraction_numerical': 0.005960828839057622, 'mean_word_length': 3.304825901038485, 'pattern_counts': {'":': 18, '<': 3, '<?xml version=': 0, '>': 41, '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': '2757152', 'n_tokens_mistral': 2062, 'n_tokens_neox': 1967, 'n_words': 433}