<commit_before>
/*
 * code_block_input.ts
 *
 * Copyright (C) 2019-20 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

import { EditorState, Transaction } from "prosemirror-state";
import { Schema, ResolvedPos, Fragment } from "prosemirror-model";
import { InputRule } from "prosemirror-inputrules";
import { setTextSelection } from "prosemirror-utils";

import { PandocExtensions } from "../api/pandoc";
import { PandocCapabilities } from "../api/pandoc_capabilities";
import { EditorUI } from "../api/ui";
import { EditorFormat } from "../api/format";
import { Extension } from "../api/extension";
import { precedingListItemInsertPos, precedingListItemInsert } from "../api/list";
import { pandocAttrFrom } from "../api/pandoc_attr";
import { BaseKey } from "../api/basekeys";
import { fancyQuotesToSimple } from "../api/quote";
import { markIsActive } from "../api/mark";

const extension = (
  pandocExtensions: PandocExtensions,
  _caps: PandocCapabilities,
  _ui: EditorUI,
  format: EditorFormat
): Extension | null => {

  const fencedAttributes = pandocExtensions.fenced_code_attributes || !!format.rmdExtensions.codeChunks;

  return {
    baseKeys: () => {
      return [
        { key: BaseKey.Enter, command: codeBlockInputRuleEnter(fencedAttributes, format)},
      ];
    },

    inputRules: () => {
      if (fencedAttributes) {
        return [
          new InputRule(/^```{$/, (state: EditorState, match: string[], start: number, end: number) => {
            if (!canApplyCodeBlockInputRule(state)) {
              return null;
            }
            const tr = state.tr;
            tr.insertText('{}');
            setTextSelection(start + match[0].length)(tr);
            return tr;
          }),
        ];
      } else {
        return [];
      }
    }
  };


};

function codeBlockInputRuleEnter(fencedAttributes: boolean, format: EditorFormat) {
  return (state: EditorState, dispatch?: (tr: Transaction) => void) => {

    // see if the parent consist of a pending code block input rule
    const schema = state.schema;
    const { $head } = state.selection;

    // selection must be empty
    if (!state.selection.empty) {
      return false;
    }

    // full text of parent must meet the pattern
    const match = $head.parent.textContent.match(/^```(?:(\w+)|\{(\.?[^\}]+)\})$/);
    if (!match) {
      return false;
    }

    // no inline code marks
    if (markIsActive(state, schema.marks.code)) {
      return false;
    }

    // must be able to perform the replacement
    if (!canApplyCodeBlockInputRule(state)) {
      return false;
    }

    // execute
    if (dispatch) {

      // determine nature of insert
      const fenced = fencedAttributes && !!match[2];
      const langAttrib = fenced ? match[2] : (match[1] || '');<commit_msg>match plain code blocks<commit_after>
/*
 * code_block_input.ts
 *
 * Copyright (C) 2019-20 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

import { EditorState, Transaction } from "prosemirror-state";
import { Schema, ResolvedPos, Fragment } from "prosemirror-model";
import { InputRule } from "prosemirror-inputrules";
import { setTextSelection } from "prosemirror-utils";

import { PandocExtensions } from "../api/pandoc";
import { PandocCapabilities } from "../api/pandoc_capabilities";
import { EditorUI } from "../api/ui";
import { EditorFormat } from "../api/format";
import { Extension } from "../api/extension";
import { precedingListItemInsertPos, precedingListItemInsert } from "../api/list";
import { pandocAttrFrom } from "../api/pandoc_attr";
import { BaseKey } from "../api/basekeys";
import { fancyQuotesToSimple } from "../api/quote";
import { markIsActive } from "../api/mark";

const extension = (
  pandocExtensions: PandocExtensions,
  _caps: PandocCapabilities,
  _ui: EditorUI,
  format: EditorFormat
): Extension | null => {

  const fencedAttributes = pandocExtensions.fenced_code_attributes || !!format.rmdExtensions.codeChunks;

  return {
    baseKeys: () => {
      return [
        { key: BaseKey.Enter, command: codeBlockInputRuleEnter(fencedAttributes, format)},
      ];
    },

    inputRules: () => {
      if (fencedAttributes) {
        return [
          new InputRule(/^```{$/, (state: EditorState, match: string[], start: number, end: number) => {
            if (!canApplyCodeBlockInputRule(state)) {
              return null;
            }
            const tr = state.tr;
            tr.insertText('{}');
            setTextSelection(start + match[0].length)(tr);
            return tr;
          }),
        ];
      } else {
        return [];
      }
    }
  };


};

function codeBlockInputRuleEnter(fencedAttributes: boolean, format: EditorFormat) {
  return (state: EditorState, dispatch?: (tr: Transaction) => void) => {

    // see if the parent consist of a pending code block input rule
    const schema = state.schema;
    const { $head } = state.selection;

    // selection must be empty
    if (!state.selection.empty) {
      return false;
    }

    // full text of parent must meet the pattern
    const match = $head.parent.textContent.match(/^```(?:(\w+)|\{(\.?[^\}]+)\})?$/);
    if (!match) {
      return false;
    }

    // no inline code marks
    if (markIsActive(state, schema.marks.code)) {
      return false;
    }

    // must be able to perform the replacement
    if (!canApplyCodeBlockInputRule(state)) {
      return false;
    }

    // execute
    if (dispatch) {

      // determine nature of insert
      const fenced = fencedAttributes && !!match[2];
      const langAttrib = fenced ? match[2] : (match[1] || '');
{'fraction_non_alphanumeric': 0.12994350282485875, 'fraction_numerical': 0.003970071766681936, 'mean_word_length': 2.9268585131894485, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '980249', 'n_tokens_mistral': 1916, 'n_tokens_neox': 1852, 'n_words': 561}