<commit_before>import {fromDOM, toDOM, Pos, Node, inline} from "../model"

import * as keys from "./keys"
import {mac, addClass, rmClass} from "./dom"
import {execCommand} from "./commands"
import {applyDOMChange} from "./domchange"
import text from "./text"
import {Range} from "./selection"

let stopSeq = null
const handlers = {}

export class Input {
  constructor(pm) {
    this.pm = pm

    this.keySeq = null
    this.composing = null
    this.composeActive = 0

    this.draggingFrom = false

    this.keymaps = []
    this.commandExtensions = Object.create(null)

    this.storedStyles = null

    for (let event in handlers) {
      let handler = handlers[event]
      pm.content.addEventListener(event, (e) => handler(pm, e))
    }

    pm.on("selectionChange", () => this.storedStyles = null)
  }

  extendCommand(name, priority, f) {
    let obj = this.commandExtensions[name] ||
        (this.commandExtensions[name] = {low: [], normal: [], high: []})
    obj[priority].push(f)
  }

  unextendCommand(name, priority, f) {
    let obj = this.commandExtensions[name]
    let arr = obj && obj[priority]
    if (arr) for (let i = 0; i < arr.length; i++)
      if (arr[i] == f) { arr.splice(i, 1); break }
  }
}

function dispatchKey(pm, name, e) {
  let seq = pm.input.keySeq
  if (seq) {
    if (keys.isModifierKey(name)) return true
    clearTimeout(stopSeq)
    stopSeq = setTimeout(function() {
      if (pm.input.keySeq == seq)
        pm.input.keySeq = null
    }, 50)
    name = seq + " " + name
  }

  let handle = function(bound) {
    let result = typeof bound == "string" ? execCommand(pm, bound) : bound(pm)
    return result !== false
  }

  let result
  for (let i = 0; !result && i < pm.input.keymaps.length; i++)
    result = keys.lookupKey(name, pm.input.keymaps[i], handle, pm)
  if (!result)
    result = keys.lookupKey(name, pm.options.extraKeymap, handle, pm) ||
      keys.lookupKey(name, pm.options.keymap, handle, pm)

  if (result == "multi")
    pm.input.keySeq = name

  if (result == "handled" || result == "multi")
    e.preventDefault()

  if (seq && !result && /\'$/.test(name)) {
    e.preventDefault()
    return true
  }
  return !!result
}

handlers.keydown = (pm, e) => {
  let name = keys.keyName(e)
  if (name) dispatchKey(pm, name, e)
}<commit_msg>Always preventDefault key events for which a handler exists<commit_after>import {fromDOM, toDOM, Pos, Node, inline} from "../model"

import * as keys from "./keys"
import {mac, addClass, rmClass} from "./dom"
import {execCommand} from "./commands"
import {applyDOMChange} from "./domchange"
import text from "./text"
import {Range} from "./selection"

let stopSeq = null
const handlers = {}

export class Input {
  constructor(pm) {
    this.pm = pm

    this.keySeq = null
    this.composing = null
    this.composeActive = 0

    this.draggingFrom = false

    this.keymaps = []
    this.commandExtensions = Object.create(null)

    this.storedStyles = null

    for (let event in handlers) {
      let handler = handlers[event]
      pm.content.addEventListener(event, (e) => handler(pm, e))
    }

    pm.on("selectionChange", () => this.storedStyles = null)
  }

  extendCommand(name, priority, f) {
    let obj = this.commandExtensions[name] ||
        (this.commandExtensions[name] = {low: [], normal: [], high: []})
    obj[priority].push(f)
  }

  unextendCommand(name, priority, f) {
    let obj = this.commandExtensions[name]
    let arr = obj && obj[priority]
    if (arr) for (let i = 0; i < arr.length; i++)
      if (arr[i] == f) { arr.splice(i, 1); break }
  }
}

function dispatchKey(pm, name, e) {
  let seq = pm.input.keySeq
  if (seq) {
    if (keys.isModifierKey(name)) return true
    clearTimeout(stopSeq)
    stopSeq = setTimeout(function() {
      if (pm.input.keySeq == seq)
        pm.input.keySeq = null
    }, 50)
    name = seq + " " + name
  }

  let sawHandler = false
  let handle = function(bound) {
    sawHandler = true
    let result = typeof bound == "string" ? execCommand(pm, bound) : bound(pm)
    return result !== false
  }

  let result
  for (let i = 0; !result && i < pm.input.keymaps.length; i++)
    result = keys.lookupKey(name, pm.input.keymaps[i], handle, pm)
  if (!result)
    result = keys.lookupKey(name, pm.options.extraKeymap, handle, pm) ||
      keys.lookupKey(name, pm.options.keymap, handle, pm)

  if (result == "multi")
    pm.input.keySeq = name

  if (result == "handled" || result == "multi" || sawHandler)
    e.preventDefault()

  if (seq && !result && /\'$/.test(name)) {
    e.preventDefault()
    return true
  }
  return !!result
}

handlers.keydown = (pm, e) => {
  let name = keys.keyName(e)
  if (name) dispatchKey(pm, name, e)
}
{'fraction_non_alphanumeric': 0.1540097851520953, 'fraction_numerical': 0.0025526483726866626, 'mean_word_length': 3.0051107325383306, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, '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': '2082792', 'n_tokens_mistral': 1618, 'n_tokens_neox': 1581, 'n_words': 426}