<commit_before>import { cloneDeep } from 'lodash'

import { trackEvent } from '../app/event_tracking'
import { t } from '../app/locale'
import { showStatusMessage, hideStatusMessage } from '../app/status_message'
import { infoBubble } from '../info_bubble/info_bubble'
import {
  trimStreetData,
  getStreet,
  setStreet,
  setUpdateTimeToNow,
  updateEverything,
  getLastStreet,
  setStreetDataInRedux
} from './data_model'
import { getRemixOnFirstEdit } from './remix'

import store from '../store'
import {
  createNewUndo,
  unifyStack,
  replaceUndoStack,
  replaceUndoPosition,
  undoAction,
  redoAction
} from '../store/actions/undo'

export function getCurrentUndo () {
  const state = store.getState().undo
  return state.stack[state.position]
}

export function getUndoStack () {
  return cloneDeep(store.getState().undo.stack)
}

export function setUndoStack (value) {
  store.dispatch(replaceUndoStack(value))
}

export function getUndoPosition () {
  return store.getState().undo.position
}

export function setUndoPosition (value) {
  replaceUndoPosition(value)
}

function finishUndoOrRedo () {
  // set current street to the thing we just updated
  const state = store.getState().undo
  setStreet(cloneDeep(state.stack[state.position]))

  setUpdateTimeToNow()

  infoBubble.hide()
  infoBubble.hideSegment()
  infoBubble.dontConsiderShowing()

  updateEverything(true)
  hideStatusMessage()

  trackEvent('INTERACTION', 'UNDO', null, null, true)
}

export function undo () {
  if (!isUndoAvailable()) {
    showStatusMessage(t('toast.no-undo'))
    return
  }

  // sends current street to update current position before undoing
  store.dispatch(undoAction(trimStreetData(getStreet())))

  finishUndoOrRedo()
}

export function redo () {
  if (!isRedoAvailable()) {
    showStatusMessage(t('toast.no-undo'))
    return
  }

  store.dispatch(redoAction())

  finishUndoOrRedo()
}

export function createNewUndoIfNecessary (lastStreet, currentStreet) {
  if (lastStreet.name !== currentStreet.name) {
    return
  }

  store.dispatch(createNewUndo(cloneDeep(getLastStreet())))
}

export function isUndoAvailable () {
  const undoPosition = getUndoPosition()
  // Don’t allow undo/redo unless you own the street
  return (undoPosition > 0) && !getRemixOnFirstEdit()
}

export function isRedoAvailable () {
  const undoStack = getUndoStack()
  const undoPosition = getUndoPosition()
  // Don’t allow undo/redo unless you own the street
  return (undoPosition >= 0 && undoPosition < undoStack.length - 1) && !getRemixOnFirstEdit()
}
<commit_msg>undo stack: stop calling getStreet()<commit_after>import { cloneDeep } from 'lodash'

import { trackEvent } from '../app/event_tracking'
import { t } from '../app/locale'
import { showStatusMessage, hideStatusMessage } from '../app/status_message'
import { infoBubble } from '../info_bubble/info_bubble'
import {
  trimStreetData,
  getStreet,
  setStreet,
  setUpdateTimeToNow,
  updateEverything
} from './data_model'
import { getRemixOnFirstEdit } from './remix'

import store from '../store'
import {
  createNewUndo,
  unifyStack,
  replaceUndoStack,
  replaceUndoPosition,
  undoAction,
  redoAction
} from '../store/actions/undo'

export function getCurrentUndo () {
  const state = store.getState().undo
  return state.stack[state.position]
}

export function getUndoStack () {
  return cloneDeep(store.getState().undo.stack)
}

export function setUndoStack (value) {
  store.dispatch(replaceUndoStack(value))
}

export function getUndoPosition () {
  return store.getState().undo.position
}

export function setUndoPosition (value) {
  replaceUndoPosition(value)
}

function finishUndoOrRedo () {
  // set current street to the thing we just updated
  const state = store.getState().undo
  setStreet(cloneDeep(state.stack[state.position]))

  setUpdateTimeToNow()

  infoBubble.hide()
  infoBubble.hideSegment()
  infoBubble.dontConsiderShowing()

  updateEverything(true)
  hideStatusMessage()

  trackEvent('INTERACTION', 'UNDO', null, null, true)
}

export function undo () {
  if (!isUndoAvailable()) {
    showStatusMessage(t('toast.no-undo'))
    return
  }

  // sends current street to update current position before undoing
  store.dispatch(undoAction(trimStreetData(getStreet())))

  finishUndoOrRedo()
}

export function redo () {
  if (!isRedoAvailable()) {
    showStatusMessage(t('toast.no-undo'))
    return
  }

  store.dispatch(redoAction())

  finishUndoOrRedo()
}

export function createNewUndoIfNecessary (lastStreet, currentStreet) {
  if (lastStreet.name !== currentStreet.name) {
    return
  }

  store.dispatch(createNewUndo(cloneDeep(lastStreet)))
}

export function isUndoAvailable () {
  const undoPosition = getUndoPosition()
  // Don’t allow undo/redo unless you own the street
  return (undoPosition > 0) && !getRemixOnFirstEdit()
}

export function isRedoAvailable () {
  const undoStack = getUndoStack()
  const undoPosition = getUndoPosition()
  // Don’t allow undo/redo unless you own the street
  return (undoPosition >= 0 && undoPosition < undoStack.length - 1) && !getRemixOnFirstEdit()
}

{'fraction_non_alphanumeric': 0.11638861629048086, 'fraction_numerical': 0.0011776251226692837, 'mean_word_length': 4.606160616061606, 'pattern_counts': {'":': 0, '<': 5, '<?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': '5508368', 'n_tokens_mistral': 1697, 'n_tokens_neox': 1590, 'n_words': 364}