<commit_before>const _ = require('underscore-plus')
const {CompositeDisposable} = require('atom')
const {
  saveEditorState,
  saveVmpPaneMaximizedState,
  isActiveEditor,
  paneForItem,
  getNextAdjacentPaneForPane,
  getPreviousAdjacentPaneForPane,
  splitPane,
  isNarrowEditor,
  getCurrentWord
} = require('../utils')
const Ui = require('../ui')
const settings = require('../settings')
const SearchOptions = require('../search-options')
const ScopedConfig = require('../scoped-config')

const Config = {
  needRestoreEditorState: true,
  boundToSingleFile: false,

  showProjectHeader: false,
  showFileHeader: false,
  showColumnOnLineHeader: false,
  itemHaveRange: false,

  supportDirectEdit: false,
  supportCacheItems: false,
  supportReopen: true,
  supportFilePathOnlyItemsUpdate: false,

  refreshOnDidStopChanging: false,
  refreshOnDidSave: false,

  // used by scan, search, atom-scan,
  showSearchOption: false,

  queryWordBoundaryOnByCurrentWordInvocation: false,
  useFirstQueryAsSearchTerm: false
}

class Provider {
  static initClass () {
    this.destroyedProviderStates = []
    this.providerByName = new Map()
    this.reopenableMax = 10
    this.service = {}
  }

  // Keep service by name
  // service must be object like `{inlineGitDiff: service}`
  static setService (service) {
    Object.assign(this.service, service)
  }

  static reopen () {
    const stateAtDestroyed = this.destroyedProviderStates.shift()
    if (stateAtDestroyed) {
      const {name, options, state} = stateAtDestroyed
      return this.start(name, options, state)
    }
  }

  static create (options = {}) {
    const editor = atom.workspace.getActiveTextEditor()
    return new Provider(editor, options)
  }

  static async start (name, options = {}, state) {
    if (!this.providerByName.has(name)) {
      this.providerByName.set(name, require(`./${name}`))
    }
    const Klass = this.providerByName.get(name)
    if (Klass) {
      return new Klass(state).start(options)
    } else {
      throw new Error(`Provier ${name} not available`)
    }
  }

  static registerProvider (name, provider) {
    if (typeof provider === 'function') {
      this.providerByName.set(name, provider)
    } else {
      throw new Error('provider must be or function')
    }
  }

  static saveState (state) {
    this.destroyedProviderStates.unshift(state)
    this.destroyedProviderStates.splice(this.reopenableMax)
  }

  getConfig (name) {
    return this.scopedConfig.get(name)
  }

  setConfig (name, value) {
    return this.scopedConfig.set(name, value)
  }

  getOnStartConditionValueFor (name) {
    const value = this.getConfig(name)
    if (value === 'never') return false
    if (value === 'always') return true
    if (value === 'on-input') return this.query
    if (value === 'no-input') return !this.query
  }

  needRevealOnStart () {
    return this.getOnStartConditionValueFor('revealOnStartCondition')
  }

  needFocusOnStart () {
    return this.getOnStartConditionValueFor('focusOnStartCondition')
  }

  buildSearchOptionsProps ({queryCurrentWord}) {
    const editor = atom.workspace.getActiveTextEditor()
    return {
      searchWholeWord:
        (queryCurrentWord && editor.getSelectedBufferRange().isEmpty()) || this.getConfig('searchWholeWord'),
      searchUseRegex: this.getConfig('searchUseRegex')
    }
  }

  bindEditor (editor) {
    if (editor === this.editor) return

    if (this.editorSubscriptions) this.editorSubscriptions.dispose()
    this.editorSubscriptions = new CompositeDisposable()
    const oldEditor = this.editor
    this.editor = editor
    this.callHook('didBindEditor', {
      newEditor: editor,
      oldEditor: oldEditor
    })
  }

  getPane () {
    // If editor was pending item, it will be destroyed on next pending-item opened
    const pane = paneForItem(this.editor)
    if (pane && pane.isAlive()) {
      this.lastPane = pane
    }

    if (this.lastPane && this.lastPane.isAlive()) {
      return this.lastPane
    }
  }

  isActive () {
    return isActiveEditor(this.editor)
  }

  getState () {
    let providerState = {}
    if (this.searchOptions) {
      Object.assign(providerState, {
        searchOptionState: this.searchOptions.getState()
      })
    }
    Object.assign(providerState, this.callHook('willSaveState'))

    return {
      name: this.dashName,
      options: {query: this.ui.lastQuery},
      state: {
        provider: providerState,
        ui: this.ui.getState()
      }
    }
  }

  constructor (editor, options = {}) {
    this.clientEditor = editor
    Object.assign(this, Config, options.config)

    this.name = options.name
    this.dashName = _.dasherize(this.name)
    this.subscriptions = new CompositeDisposable()<commit_msg>should not restore editor state if some cursor position change happened on client-editor<commit_after>const _ = require('underscore-plus')
const {CompositeDisposable} = require('atom')
const {
  saveEditorState,
  saveVmpPaneMaximizedState,
  isActiveEditor,
  paneForItem,
  getNextAdjacentPaneForPane,
  getPreviousAdjacentPaneForPane,
  splitPane,
  isNarrowEditor,
  getCurrentWord
} = require('../utils')
const Ui = require('../ui')
const settings = require('../settings')
const SearchOptions = require('../search-options')
const ScopedConfig = require('../scoped-config')

const Config = {
  needRestoreEditorState: true,
  boundToSingleFile: false,

  showProjectHeader: false,
  showFileHeader: false,
  showColumnOnLineHeader: false,
  itemHaveRange: false,

  supportDirectEdit: false,
  supportCacheItems: false,
  supportReopen: true,
  supportFilePathOnlyItemsUpdate: false,

  refreshOnDidStopChanging: false,
  refreshOnDidSave: false,

  // used by scan, search, atom-scan,
  showSearchOption: false,

  queryWordBoundaryOnByCurrentWordInvocation: false,
  useFirstQueryAsSearchTerm: false
}

class Provider {
  static initClass () {
    this.destroyedProviderStates = []
    this.providerByName = new Map()
    this.reopenableMax = 10
    this.service = {}
  }

  // Keep service by name
  // service must be object like `{inlineGitDiff: service}`
  static setService (service) {
    Object.assign(this.service, service)
  }

  static reopen () {
    const stateAtDestroyed = this.destroyedProviderStates.shift()
    if (stateAtDestroyed) {
      const {name, options, state} = stateAtDestroyed
      return this.start(name, options, state)
    }
  }

  static create (options = {}) {
    const editor = atom.workspace.getActiveTextEditor()
    return new Provider(editor, options)
  }

  static async start (name, options = {}, state) {
    if (!this.providerByName.has(name)) {
      this.providerByName.set(name, require(`./${name}`))
    }
    const Klass = this.providerByName.get(name)
    if (Klass) {
      return new Klass(state).start(options)
    } else {
      throw new Error(`Provier ${name} not available`)
    }
  }

  static registerProvider (name, provider) {
    if (typeof provider === 'function') {
      this.providerByName.set(name, provider)
    } else {
      throw new Error('provider must be or function')
    }
  }

  static saveState (state) {
    this.destroyedProviderStates.unshift(state)
    this.destroyedProviderStates.splice(this.reopenableMax)
  }

  getConfig (name) {
    return this.scopedConfig.get(name)
  }

  setConfig (name, value) {
    return this.scopedConfig.set(name, value)
  }

  getOnStartConditionValueFor (name) {
    const value = this.getConfig(name)
    if (value === 'never') return false
    if (value === 'always') return true
    if (value === 'on-input') return this.query
    if (value === 'no-input') return !this.query
  }

  needRevealOnStart () {
    return this.getOnStartConditionValueFor('revealOnStartCondition')
  }

  needFocusOnStart () {
    return this.getOnStartConditionValueFor('focusOnStartCondition')
  }

  buildSearchOptionsProps ({queryCurrentWord}) {
    const editor = atom.workspace.getActiveTextEditor()
    return {
      searchWholeWord:
        (queryCurrentWord && editor.getSelectedBufferRange().isEmpty()) || this.getConfig('searchWholeWord'),
      searchUseRegex: this.getConfig('searchUseRegex')
    }
  }

  bindEditor (editor) {
    if (editor === this.editor) return

    if (this.editorSubscriptions) this.editorSubscriptions.dispose()
    this.editorSubscriptions = new CompositeDisposable()
    const oldEditor = this.editor
    this.editor = editor
    this.callHook('didBindEditor', {
      newEditor: editor,
      oldEditor: oldEditor
    })
  }

  getPane () {
    // If editor was pending item, it will be destroyed on next pending-item opened
    const pane = paneForItem(this.editor)
    if (pane && pane.isAlive()) {
      this.lastPane = pane
    }

    if (this.lastPane && this.lastPane.isAlive()) {
      return this.lastPane
    }
  }

  isActive () {
    return isActiveEditor(this.editor)
  }

  getState () {
    let providerState = {}
    if (this.searchOptions) {
      Object.assign(providerState, {
        searchOptionState: this.searchOptions.getState()
      })
    }
    Object.assign(providerState, this.callHook('willSaveState'))

    return {
      name: this.dashName,
      options: {query: this.ui.lastQuery},
      state: {
        provider: providerState,
        ui: this.ui.getState()
      }
    }
  }

  constructor (editor, options = {}) {
    this.clientEditor = editor

    // When ui was not focused on start(e.g. focusOnStartCondition was set to `never`).
    // We should not restore editor state when if at least some cursor movement happened in client-editor.
    const clientEditorDisposable = this.clientEditor.onDidChangeCursorPosition(() => {
      clientEditorDisposable.dispose()
      this.needRestoreEditorState = false
    })

    Object.assign(this, Config, options.config)

    this.name = options.name
    this.dashName = _.dasherize(this.name)
    this.subscriptions = new CompositeDisposable()
{'fraction_non_alphanumeric': 0.11395090413173048, 'fraction_numerical': 0.0004040812203252854, 'mean_word_length': 3.419642857142857, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, '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': '2816487', 'n_tokens_mistral': 3044, 'n_tokens_neox': 2973, 'n_words': 659}