<commit_before>import { Node as ProsemirrorNode } from 'prosemirror-model';
import { EditorView } from 'prosemirror-view';
import { NodeWithPos, findChildrenByType } from 'prosemirror-utils';
import { EditorState } from 'prosemirror-state';

import { bodyElement } from './dom';
import {
  EditorOutlineItemType,
  kYamlMetadataOutlineItenItem,
  kHeadingOutlineItemType,
  kRmdchunkOutlineItemType,
} from './outline';
import { findTopLevelBodyNodes } from './node';
import { restoreSelection } from './selection';
import { scrollToPos } from './scroll';

export interface EditingLocation {
  pos: number;
  scrollTop: number;
}

export interface EditingOutlineLocationItem {
  type: EditorOutlineItemType;
  level: number;
  title: string;
  active: boolean;
}

export interface EditingOutlineLocation {
  items: EditingOutlineLocationItem[];
}

export function getEditingLocation(view: EditorView): EditingLocation {
  const pos = view.state.selection.from;
  const bodyEl = bodyElement(view);
  const scrollTop = bodyEl.scrollTop;
  return { pos, scrollTop };
}

export function setEditingLocation(
  view: EditorView,
  outlineLocation?: EditingOutlineLocation,
  previousLocation?: EditingLocation,
) {
  // get the current document outline
  const documentOutline = getDocumentOutline(view.state);

  // if all of the types and levels match up to the active outline item,
  // then we have a candidate match
  let docOutlineLocationNode: NodeWithPos | undefined;

  if (outlineLocation) {
    for (let i = 0; i < outlineLocation.items.length && i < documentOutline.length; i++) {
      // get the item and it's peer
      const item = outlineLocation.items[i];
      const docOutlineNode = documentOutline[i];

      // if they don't match then bail (can't resolve different interpretations of the outline)
      if (!outlineItemSimillarToNode(item, docOutlineNode.node)) {
        break;
      }

      // if this is the active item
      if (item.active) {
        // see if the previous location is actually a better target (because it's between this location and
        // the next outline node). in that case we don't set the target node and we leave the restorePos
        // at the previous location
        if (!locationIsBetweenDocOutlineNodes(docOutlineNode, documentOutline[i + 1], previousLocation)) {
          // set the target
          docOutlineLocationNode = docOutlineNode;

          // if this is an rmd chunk then advance to the second line
          if (docOutlineNode.node.type === view.state.schema.nodes.rmd_chunk) {
            const chunkText = docOutlineNode.node.textContent;
            const newlineIdx = chunkText.indexOf('\n');
            if (newlineIdx !== -1) {
              docOutlineLocationNode.pos += newlineIdx + 2;
            }
          }
        }

        break;
      }
    }
  }

  // do the restore
  if (docOutlineLocationNode) {<commit_msg>improve location restoration logic<commit_after>import { Node as ProsemirrorNode } from 'prosemirror-model';
import { EditorView } from 'prosemirror-view';
import { NodeWithPos, findChildrenByType } from 'prosemirror-utils';
import { EditorState } from 'prosemirror-state';

import { bodyElement } from './dom';
import {
  EditorOutlineItemType,
  kYamlMetadataOutlineItenItem,
  kHeadingOutlineItemType,
  kRmdchunkOutlineItemType,
} from './outline';
import { findTopLevelBodyNodes } from './node';
import { restoreSelection } from './selection';
import { scrollToPos } from './scroll';

export interface EditingLocation {
  pos: number;
  scrollTop: number;
}

export interface EditingOutlineLocationItem {
  type: EditorOutlineItemType;
  level: number;
  title: string;
  active: boolean;
}

export interface EditingOutlineLocation {
  items: EditingOutlineLocationItem[];
}

export function getEditingLocation(view: EditorView): EditingLocation {
  const pos = view.state.selection.from;
  const bodyEl = bodyElement(view);
  const scrollTop = bodyEl.scrollTop;
  return { pos, scrollTop };
}

export function setEditingLocation(
  view: EditorView,
  outlineLocation?: EditingOutlineLocation,
  previousLocation?: EditingLocation,
) {
  // get the current document outline
  const documentOutline = getDocumentOutline(view.state);

  // if all of the types and levels match up to the active outline item,
  // then we have a candidate match
  let docOutlineLocationNode: NodeWithPos | undefined;

  if (outlineLocation) {
    for (let i = 0; i < outlineLocation.items.length && i < documentOutline.length; i++) {
      // get the item and it's peer
      const item = outlineLocation.items[i];
      const docOutlineNode = documentOutline[i];

      // if they don't match then bail (can't resolve different interpretations of the outline)
      if (!outlineItemSimillarToNode(item, docOutlineNode.node)) {
        break;
      }

      // if this is the active item then we are done
      if (item.active) {

        docOutlineLocationNode = docOutlineNode;

        // if this is an rmd chunk then advance to the second line
        if (docOutlineNode.node.type === view.state.schema.nodes.rmd_chunk) {
          const chunkText = docOutlineNode.node.textContent;
          const newlineIdx = chunkText.indexOf('\n');
          if (newlineIdx !== -1) {
            docOutlineLocationNode.pos += newlineIdx + 2;
          }
        }

        break;

      }
    }
  }

  // do the restore
  if (docOutlineLocationNode) {
{'fraction_non_alphanumeric': 0.09300184162062615, 'fraction_numerical': 0.001289134438305709, 'mean_word_length': 3.337859424920128, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, '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': '2487841', 'n_tokens_mistral': 1578, 'n_tokens_neox': 1547, 'n_words': 465}