<commit_before>{find, compact, extend, last} = require 'underscore-plus'
{CompositeDisposable, Emitter} = require 'event-kit'
Model = require './model'
PaneAxis = require './pane-axis'
TextEditor = require './text-editor'

# Extended: A container for presenting content in the center of the workspace.
# Panes can contain multiple items, one of which is *active* at a given time.
# The view corresponding to the active item is displayed in the interface. In
# the default configuration, tabs are also displayed for each item.
#
# Each pane may also contain one *pending* item. When a pending item is added
# to a pane, it will replace the currently pending item, if any, instead of
# simply being added. In the default configuration, the text in the tab for
# pending items is shown in italics.
module.exports =
class Pane extends Model
  container: undefined
  activeItem: undefined
  focused: false

  @deserialize: (state, {deserializers, applicationDelegate, config, notifications}) ->
    {items, itemStackIndices, activeItemURI, activeItemUri} = state
    activeItemURI ?= activeItemUri
    state.items = compact(items.map (itemState) -> deserializers.deserialize(itemState))
    state.activeItem = find state.items, (item) ->
      if typeof item.getURI is 'function'
        itemURI = item.getURI()
      itemURI is activeItemURI
    new Pane(extend(state, {
      deserializerManager: deserializers,
      notificationManager: notifications,
      config, applicationDelegate
    }))

  constructor: (params) ->
    super

    {
      @activeItem, @focused, @applicationDelegate, @notificationManager, @config,
      @deserializerManager
    } = params

    @emitter = new Emitter
    @subscriptionsPerItem = new WeakMap
    @items = []
    @itemStack = []

    @addItems(compact(params?.items ? []))
    @setActiveItem(@items[0]) unless @getActiveItem()?
    @addItemsToStack(params?.itemStackIndices ? [])
    @setFlexScale(params?.flexScale ? 1)

  serialize: ->
    if typeof @activeItem?.getURI is 'function'
      activeItemURI = @activeItem.getURI()
    itemsToBeSerialized = compact(@items.map((item) -> item if typeof item.serialize is 'function'))
    itemStackIndices = []
    for item in @itemStack
      itemStackIndices.push(itemsToBeSerialized.indexOf(item)) if typeof item.serialize is 'function'

    deserializer: 'Pane'
    id: @id
    items: itemsToBeSerialized.map((item) -> item.serialize())
    itemStackIndices: itemStackIndices
    activeItemURI: activeItemURI
    focused: @focused
    flexScale: @flexScale

  getParent: -> @parent

  setParent: (@parent) -> @parent

  getContainer: -> @container

  setContainer: (container) ->
    if container and container isnt @container
      @container = container
      container.didAddPane({pane: this})

  setFlexScale: (@flexScale) ->
    @emitter.emit 'did-change-flex-scale', @flexScale
    @flexScale

  getFlexScale: -> @flexScale

  increaseSize: -> @setFlexScale(@getFlexScale() * 1.1)

  decreaseSize: -> @setFlexScale(@getFlexScale() / 1.1)

  ###
  Section: Event Subscription
  ###

  # Public: Invoke the given callback when the pane resizes
  #
  # The callback will be invoked when pane's flexScale property changes.
  # Use {::getFlexScale} to get the current value.
  #
  # * `callback` {Function} to be called when the pane is resized
  #   * `flexScale` {Number} representing the panes `flex-grow`; ability for a
  #     flex item to grow if necessary.
  #
  # Returns a {Disposable} on which '.dispose()' can be called to unsubscribe.
  onDidChangeFlexScale: (callback) ->
    @emitter.on 'did-change-flex-scale', callback

  # Public: Invoke the given callback with the current and future values of
  # {::getFlexScale}.
  #
  # * `callback` {Function} to be called with the current and future values of
  #   the {::getFlexScale} property.
  #   * `flexScale` {Number} representing the panes `flex-grow`; ability for a
  #     flex item to grow if necessary.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeFlexScale: (callback) ->
    callback(@flexScale)
    @onDidChangeFlexScale(callback)

  # Public: Invoke the given callback when the pane is activated.
  #
  # The given callback will be invoked whenever {::activate} is called on the
  # pane, even if it is already active at the time.
  #
  # * `callback` {Function} to be called when the pane is activated.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidActivate: (callback) ->
    @emitter.on 'did-activate', callback

  # Public: Invoke the given callback before the pane is destroyed.
  #
  # * `callback` {Function} to be called before the pane is destroyed.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onWillDestroy: (callback) ->
    @emitter.on 'will-destroy', callback

  # Public: Invoke the given callback when the pane is destroyed.
  #
  # * `callback` {Function} to be called when the pane is destroyed.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidDestroy: (callback) ->
    @emitter.on 'did-destroy', callback

  # Public: Invoke the given callback when the value of the {::isActive}
  # property changes.
  #
  # * `callback` {Function} to be called when the value of the {::isActive}
  #   property changes.
  #   * `active` {Boolean} indicating whether the pane is active.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeActive: (callback) ->
    @container.onDidChangeActivePane (activePane) =>
      callback(this is activePane)

  # Public: Invoke the given callback with the current and future values of the
  # {::isActive} property.
  #
  # * `callback` {Function} to be called with the current and future values of
  #   the {::isActive} property.
  #   * `active` {Boolean} indicating whether the pane is active.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeActive: (callback) ->
    callback(@isActive())
    @onDidChangeActive(callback)

  # Public: Invoke the given callback when an item is added to the pane.
  #
  # * `callback` {Function} to be called with when items are added.
  #   * `event` {Object} with the following keys:
  #     * `item` The added pane item.
  #     * `index` {Number} indicating where the item is located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidAddItem: (callback) ->
    @emitter.on 'did-add-item', callback

  # Public: Invoke the given callback when an item is removed from the pane.
  #
  # * `callback` {Function} to be called with when items are removed.
  #   * `event` {Object} with the following keys:
  #     * `item` The removed pane item.
  #     * `index` {Number} indicating where the item was located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidRemoveItem: (callback) ->
    @emitter.on 'did-remove-item', callback

  # Public: Invoke the given callback before an item is removed from the pane.
  #
  # * `callback` {Function} to be called with when items are removed.
  #   * `event` {Object} with the following keys:
  #     * `item` The pane item to be removed.
  #     * `index` {Number} indicating where the item is located.
  onWillRemoveItem: (callback) ->
    @emitter.on 'will-remove-item', callback

  # Public: Invoke the given callback when an item is moved within the pane.
  #
  # * `callback` {Function} to be called with when items are moved.
  #   * `event` {Object} with the following keys:
  #     * `item` The removed pane item.
  #     * `oldIndex` {Number} indicating where the item was located.
  #     * `newIndex` {Number} indicating where the item is now located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidMoveItem: (callback) ->
    @emitter.on 'did-move-item', callback

  # Public: Invoke the given callback with all current and future items.
  #
  # * `callback` {Function} to be called with current and future items.
  #   * `item` An item that is present in {::getItems} at the time of
  #     subscription or that is added at some later time.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeItems: (callback) ->
    callback(item) for item in @getItems()
    @onDidAddItem ({item}) -> callback(item)

  # Public: Invoke the given callback when the value of {::getActiveItem}
  # changes.
  #
  # * `callback` {Function} to be called with when the active item changes.
  #   * `activeItem` The current active item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeActiveItem: (callback) ->
    @emitter.on 'did-change-active-item', callback

  # Public: Invoke the given callback with the current and future values of
  # {::getActiveItem}.
  #
  # * `callback` {Function} to be called with the current and future active
  #   items.
  #   * `activeItem` The current active item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeActiveItem: (callback) ->
    callback(@getActiveItem())
    @onDidChangeActiveItem(callback)

  # Public: Invoke the given callback before items are destroyed.
  #
  # * `callback` {Function} to be called before items are destroyed.
  #   * `event` {Object} with the following keys:
  #     * `item` The item that will be destroyed.
  #     * `index` The location of the item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to
  # unsubscribe.
  onWillDestroyItem: (callback) ->
    @emitter.on 'will-destroy-item', callback

  # Called by the view layer to indicate that the pane has gained focus.
  focus: ->
    @focused = true
    @activate() unless @isActive()

  # Called by the view layer to indicate that the pane has lost focus.
  blur: ->
    @focused = false
    true # if this is called from an event handler, don't cancel it

  isFocused: -> @focused

  getPanes: -> [this]

  unsubscribeFromItem: (item) ->
    @subscriptionsPerItem.get(item)?.dispose()
    @subscriptionsPerItem.delete(item)

  ###
  Section: Items
  ###

  # Public: Get the items in this pane.
  #
  # Returns an {Array} of items.
  getItems: ->
    @items.slice()

  # Public: Get the active pane item in this pane.
  #
  # Returns a pane item.
  getActiveItem: -> @activeItem

  setActiveItem: (activeItem, options) ->
    {modifyStack} = options if options?
    unless activeItem is @activeItem
      @addItemToStack(activeItem) unless modifyStack is false
      @activeItem = activeItem
      @emitter.emit 'did-change-active-item', @activeItem
    @activeItem

  # Build the itemStack after deserializing
  addItemsToStack: (itemStackIndices) ->
    if @items.length > 0
      if itemStackIndices.length is 0 or itemStackIndices.length isnt @items.length or itemStackIndices.indexOf(-1) >= 0
        itemStackIndices = (i for i in [0..@items.length-1])
      for itemIndex in itemStackIndices
        @addItemToStack(@items[itemIndex])

  # Add item (or move item) to the end of the itemStack
  addItemToStack: (newItem) ->
    index = @itemStack.indexOf(newItem)
    @itemStack.splice(index, 1) unless index is -1
    @itemStack.push(newItem)

  # Return an {TextEditor} if the pane item is an {TextEditor}, or null otherwise.
  getActiveEditor: ->
    @activeItem if @activeItem instanceof TextEditor

  # Public: Return the item at the given index.
  #
  # * `index` {Number}
  #
  # Returns an item or `null` if no item exists at the given index.
  itemAtIndex: (index) ->
    @items[index]

  # Makes the next item in the itemStack active.
  activateNextRecentlyUsedItem: ->
    if @items.length > 1
      @itemStackIndex = @itemStack.length - 1 unless @itemStackIndex?
      @itemStackIndex = @itemStackIndex - 1
      nextRecentlyUsedItem = @itemStack[@itemStackIndex]
      @setActiveItem(nextRecentlyUsedItem, modifyStack: false)<commit_msg>:art: Change the structure of a few pieces relating to serialization.<commit_after>{find, compact, extend, last} = require 'underscore-plus'
{CompositeDisposable, Emitter} = require 'event-kit'
Model = require './model'
PaneAxis = require './pane-axis'
TextEditor = require './text-editor'

# Extended: A container for presenting content in the center of the workspace.
# Panes can contain multiple items, one of which is *active* at a given time.
# The view corresponding to the active item is displayed in the interface. In
# the default configuration, tabs are also displayed for each item.
#
# Each pane may also contain one *pending* item. When a pending item is added
# to a pane, it will replace the currently pending item, if any, instead of
# simply being added. In the default configuration, the text in the tab for
# pending items is shown in italics.
module.exports =
class Pane extends Model
  container: undefined
  activeItem: undefined
  focused: false

  @deserialize: (state, {deserializers, applicationDelegate, config, notifications}) ->
    {items, itemStackIndices, activeItemURI, activeItemUri} = state
    activeItemURI ?= activeItemUri
    state.items = compact(items.map (itemState) -> deserializers.deserialize(itemState))
    state.activeItem = find state.items, (item) ->
      if typeof item.getURI is 'function'
        itemURI = item.getURI()
      itemURI is activeItemURI
    new Pane(extend(state, {
      deserializerManager: deserializers,
      notificationManager: notifications,
      config, applicationDelegate
    }))

  constructor: (params) ->
    super

    {
      @activeItem, @focused, @applicationDelegate, @notificationManager, @config,
      @deserializerManager
    } = params

    @emitter = new Emitter
    @subscriptionsPerItem = new WeakMap
    @items = []
    @itemStack = []

    @addItems(compact(params?.items ? []))
    @setActiveItem(@items[0]) unless @getActiveItem()?
    @addItemsToStack(params?.itemStackIndices ? [])
    @setFlexScale(params?.flexScale ? 1)

  serialize: ->
    if typeof @activeItem?.getURI is 'function'
      activeItemURI = @activeItem.getURI()
    itemsToBeSerialized = compact(@items.map((item) -> item if typeof item.serialize is 'function'))
    itemStackIndices = (itemsToBeSerialized.indexOf(item) for item in @itemStack when typeof item.serialize is 'function')

    deserializer: 'Pane'
    id: @id
    items: itemsToBeSerialized.map((item) -> item.serialize())
    itemStackIndices: itemStackIndices
    activeItemURI: activeItemURI
    focused: @focused
    flexScale: @flexScale

  getParent: -> @parent

  setParent: (@parent) -> @parent

  getContainer: -> @container

  setContainer: (container) ->
    if container and container isnt @container
      @container = container
      container.didAddPane({pane: this})

  setFlexScale: (@flexScale) ->
    @emitter.emit 'did-change-flex-scale', @flexScale
    @flexScale

  getFlexScale: -> @flexScale

  increaseSize: -> @setFlexScale(@getFlexScale() * 1.1)

  decreaseSize: -> @setFlexScale(@getFlexScale() / 1.1)

  ###
  Section: Event Subscription
  ###

  # Public: Invoke the given callback when the pane resizes
  #
  # The callback will be invoked when pane's flexScale property changes.
  # Use {::getFlexScale} to get the current value.
  #
  # * `callback` {Function} to be called when the pane is resized
  #   * `flexScale` {Number} representing the panes `flex-grow`; ability for a
  #     flex item to grow if necessary.
  #
  # Returns a {Disposable} on which '.dispose()' can be called to unsubscribe.
  onDidChangeFlexScale: (callback) ->
    @emitter.on 'did-change-flex-scale', callback

  # Public: Invoke the given callback with the current and future values of
  # {::getFlexScale}.
  #
  # * `callback` {Function} to be called with the current and future values of
  #   the {::getFlexScale} property.
  #   * `flexScale` {Number} representing the panes `flex-grow`; ability for a
  #     flex item to grow if necessary.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeFlexScale: (callback) ->
    callback(@flexScale)
    @onDidChangeFlexScale(callback)

  # Public: Invoke the given callback when the pane is activated.
  #
  # The given callback will be invoked whenever {::activate} is called on the
  # pane, even if it is already active at the time.
  #
  # * `callback` {Function} to be called when the pane is activated.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidActivate: (callback) ->
    @emitter.on 'did-activate', callback

  # Public: Invoke the given callback before the pane is destroyed.
  #
  # * `callback` {Function} to be called before the pane is destroyed.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onWillDestroy: (callback) ->
    @emitter.on 'will-destroy', callback

  # Public: Invoke the given callback when the pane is destroyed.
  #
  # * `callback` {Function} to be called when the pane is destroyed.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidDestroy: (callback) ->
    @emitter.on 'did-destroy', callback

  # Public: Invoke the given callback when the value of the {::isActive}
  # property changes.
  #
  # * `callback` {Function} to be called when the value of the {::isActive}
  #   property changes.
  #   * `active` {Boolean} indicating whether the pane is active.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeActive: (callback) ->
    @container.onDidChangeActivePane (activePane) =>
      callback(this is activePane)

  # Public: Invoke the given callback with the current and future values of the
  # {::isActive} property.
  #
  # * `callback` {Function} to be called with the current and future values of
  #   the {::isActive} property.
  #   * `active` {Boolean} indicating whether the pane is active.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeActive: (callback) ->
    callback(@isActive())
    @onDidChangeActive(callback)

  # Public: Invoke the given callback when an item is added to the pane.
  #
  # * `callback` {Function} to be called with when items are added.
  #   * `event` {Object} with the following keys:
  #     * `item` The added pane item.
  #     * `index` {Number} indicating where the item is located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidAddItem: (callback) ->
    @emitter.on 'did-add-item', callback

  # Public: Invoke the given callback when an item is removed from the pane.
  #
  # * `callback` {Function} to be called with when items are removed.
  #   * `event` {Object} with the following keys:
  #     * `item` The removed pane item.
  #     * `index` {Number} indicating where the item was located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidRemoveItem: (callback) ->
    @emitter.on 'did-remove-item', callback

  # Public: Invoke the given callback before an item is removed from the pane.
  #
  # * `callback` {Function} to be called with when items are removed.
  #   * `event` {Object} with the following keys:
  #     * `item` The pane item to be removed.
  #     * `index` {Number} indicating where the item is located.
  onWillRemoveItem: (callback) ->
    @emitter.on 'will-remove-item', callback

  # Public: Invoke the given callback when an item is moved within the pane.
  #
  # * `callback` {Function} to be called with when items are moved.
  #   * `event` {Object} with the following keys:
  #     * `item` The removed pane item.
  #     * `oldIndex` {Number} indicating where the item was located.
  #     * `newIndex` {Number} indicating where the item is now located.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidMoveItem: (callback) ->
    @emitter.on 'did-move-item', callback

  # Public: Invoke the given callback with all current and future items.
  #
  # * `callback` {Function} to be called with current and future items.
  #   * `item` An item that is present in {::getItems} at the time of
  #     subscription or that is added at some later time.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeItems: (callback) ->
    callback(item) for item in @getItems()
    @onDidAddItem ({item}) -> callback(item)

  # Public: Invoke the given callback when the value of {::getActiveItem}
  # changes.
  #
  # * `callback` {Function} to be called with when the active item changes.
  #   * `activeItem` The current active item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeActiveItem: (callback) ->
    @emitter.on 'did-change-active-item', callback

  # Public: Invoke the given callback with the current and future values of
  # {::getActiveItem}.
  #
  # * `callback` {Function} to be called with the current and future active
  #   items.
  #   * `activeItem` The current active item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  observeActiveItem: (callback) ->
    callback(@getActiveItem())
    @onDidChangeActiveItem(callback)

  # Public: Invoke the given callback before items are destroyed.
  #
  # * `callback` {Function} to be called before items are destroyed.
  #   * `event` {Object} with the following keys:
  #     * `item` The item that will be destroyed.
  #     * `index` The location of the item.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to
  # unsubscribe.
  onWillDestroyItem: (callback) ->
    @emitter.on 'will-destroy-item', callback

  # Called by the view layer to indicate that the pane has gained focus.
  focus: ->
    @focused = true
    @activate() unless @isActive()

  # Called by the view layer to indicate that the pane has lost focus.
  blur: ->
    @focused = false
    true # if this is called from an event handler, don't cancel it

  isFocused: -> @focused

  getPanes: -> [this]

  unsubscribeFromItem: (item) ->
    @subscriptionsPerItem.get(item)?.dispose()
    @subscriptionsPerItem.delete(item)

  ###
  Section: Items
  ###

  # Public: Get the items in this pane.
  #
  # Returns an {Array} of items.
  getItems: ->
    @items.slice()

  # Public: Get the active pane item in this pane.
  #
  # Returns a pane item.
  getActiveItem: -> @activeItem

  setActiveItem: (activeItem, options) ->
    {modifyStack} = options if options?
    unless activeItem is @activeItem
      @addItemToStack(activeItem) unless modifyStack is false
      @activeItem = activeItem
      @emitter.emit 'did-change-active-item', @activeItem
    @activeItem

  # Build the itemStack after deserializing
  addItemsToStack: (itemStackIndices) ->
    if @items.length > 0
      if itemStackIndices.length is 0 or itemStackIndices.length isnt @items.length or itemStackIndices.indexOf(-1) >= 0
        itemStackIndices = (i for i in [0..@items.length-1])
      for itemIndex in itemStackIndices
        @addItemToStack(@items[itemIndex])
      return

  # Add item (or move item) to the end of the itemStack
  addItemToStack: (newItem) ->
    index = @itemStack.indexOf(newItem)
    @itemStack.splice(index, 1) unless index is -1
    @itemStack.push(newItem)

  # Return an {TextEditor} if the pane item is an {TextEditor}, or null otherwise.
  getActiveEditor: ->
    @activeItem if @activeItem instanceof TextEditor

  # Public: Return the item at the given index.
  #
  # * `index` {Number}
  #
  # Returns an item or `null` if no item exists at the given index.
  itemAtIndex: (index) ->
    @items[index]

  # Makes the next item in the itemStack active.
  activateNextRecentlyUsedItem: ->
    if @items.length > 1
      @itemStackIndex = @itemStack.length - 1 unless @itemStackIndex?
      @itemStackIndex = @itemStackIndex - 1
      nextRecentlyUsedItem = @itemStack[@itemStackIndex]
      @setActiveItem(nextRecentlyUsedItem, modifyStack: false)
{'fraction_non_alphanumeric': 0.10572723869733394, 'fraction_numerical': 0.0014141330116873934, 'mean_word_length': 3.415794306703398, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, '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': '1626437', 'n_tokens_mistral': 7322, 'n_tokens_neox': 7033, 'n_words': 2602}