<commit_before>AtomWindow = require './atom-window'
ApplicationMenu = require './application-menu'
AtomProtocolHandler = require './atom-protocol-handler'
BrowserWindow = require 'browser-window'
Menu = require 'menu'
autoUpdater = require 'auto-updater'
app = require 'app'
dialog = require 'dialog'
fs = require 'fs'
ipc = require 'ipc'
path = require 'path'
os = require 'os'
net = require 'net'
shell = require 'shell'
url = require 'url'
{EventEmitter} = require 'events'
_ = require 'underscore-plus'

socketPath =
  if process.platform is 'win32'
    '\\\\.\\pipe\\atom-sock'
  else
    path.join(os.tmpdir(), 'atom.sock')

# The application's singleton class.
#
# It's the entry point into the Atom application and maintains the global state
# of the application.
#
module.exports =
class AtomApplication
  _.extend @prototype, EventEmitter.prototype
  updateVersion: null

  # Public: The entry point into the Atom application.
  @open: (options) ->
    createAtomApplication = -> new AtomApplication(options)

    # FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
    # take a few seconds to trigger 'error' event, it could be a bug of node
    # or atom-shell, before it's fixed we check the existence of socketPath to
    # speedup startup.
    if (process.platform isnt 'win32' and not fs.existsSync socketPath) or options.test
      createAtomApplication()
      return

    client = net.connect {path: socketPath}, ->
      client.write JSON.stringify(options), ->
        client.end()
        app.terminate()

    client.on 'error', createAtomApplication

  windows: null
  applicationMenu: null
  atomProtocolHandler: null
  resourcePath: null
  version: null

  exit: (status) -> app.exit(status)

  constructor: (options) ->
    {@resourcePath, @version, @devMode} = options
    global.atomApplication = this

    @pidsToOpenWindows = {}
    @pathsToOpen ?= []
    @windows = []

    @applicationMenu = new ApplicationMenu(@version)
    @atomProtocolHandler = new AtomProtocolHandler(@resourcePath)

    @listenForArgumentsFromNewProcess()
    @setupJavaScriptArguments()
    @handleEvents()
    @setupAutoUpdater()

    @openWithOptions(options)

  # Opens a new window based on the options provided.
  openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}) ->
    if test
      @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile})
    else if pathsToOpen.length > 0
      @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode})
    else if urlsToOpen.length > 0
      @openUrl({urlToOpen, devMode}) for urlToOpen in urlsToOpen
    else
      @openPath({pidToKillWhenClosed, newWindow, devMode}) # Always open a editor window if this is the first instance of Atom.

  # Public: Removes the {AtomWindow} from the global window list.
  removeWindow: (window) ->
    @windows.splice @windows.indexOf(window), 1
    @applicationMenu?.enableWindowSpecificItems(false) if @windows.length == 0

  # Public: Adds the {AtomWindow} to the global window list.
  addWindow: (window) ->
    @windows.push window
    @applicationMenu?.enableWindowSpecificItems(true)

  # Creates server to listen for additional atom application launches.
  #
  # You can run the atom command multiple times, but after the first launch
  # the other launches will just pass their information to this server and then
  # close immediately.
  listenForArgumentsFromNewProcess: ->
    @deleteSocketFile()
    server = net.createServer (connection) =>
      connection.on 'data', (data) =>
        @openWithOptions(JSON.parse(data))

    server.listen socketPath
    server.on 'error', (error) -> console.error 'Application server failed', error

  deleteSocketFile: ->
    return if process.platform is 'win32'

    if fs.existsSync(socketPath)
      try
        fs.unlinkSync(socketPath)
      catch error
        # Ignore ENOENT errors in case the file was deleted between the exists
        # check and the call to unlink sync. This occurred occasionally on CI
        # which is why this check is here.
        throw error unless error.code is 'ENOENT'

  # Configures required javascript environment flags.
  setupJavaScriptArguments: ->
    app.commandLine.appendSwitch 'js-flags', '--harmony_collections --harmony-proxies'

  # Enable updates unless running from a local build of Atom.
  setupAutoUpdater: ->
    autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"

    autoUpdater.on 'checking-for-update', =>
      @applicationMenu.showDownloadingUpdateItem(false)
      @applicationMenu.showInstallUpdateItem(false)
      @applicationMenu.showCheckForUpdateItem(false)

    autoUpdater.on 'update-not-available', =>
      @applicationMenu.showCheckForUpdateItem(true)

    autoUpdater.on 'update-available', =>
      @applicationMenu.showDownloadingUpdateItem(true)

    autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseName, releaseDate, releaseURL) =>
      atomWindow.sendCommand('window:update-available', [releaseName, releaseNotes]) for atomWindow in @windows
      @applicationMenu.showInstallUpdateItem(true)
      @updateVersion = releaseName

    autoUpdater.on 'error', (event, message) =>
      @applicationMenu.showCheckForUpdateItem(true)

    # Check for update after Atom has fully started and the menus are created
    setTimeout((-> autoUpdater.checkForUpdates()), 5000)

  checkForUpdate: ->
    @onUpdateNotAvailable ?= =>
      autoUpdater.removeListener 'error', @onUpdateError
      dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."

    @onUpdateError ?= (event, message) =>
      autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
      dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message

    autoUpdater.on 'update-not-available', @onUpdateNotAvailable
    autoUpdater.on 'error', @onUpdateError
    @applicationMenu.showCheckForUpdateItem(false)<commit_msg>Rely on events to hide the "Check for update" menu item<commit_after>AtomWindow = require './atom-window'
ApplicationMenu = require './application-menu'
AtomProtocolHandler = require './atom-protocol-handler'
BrowserWindow = require 'browser-window'
Menu = require 'menu'
autoUpdater = require 'auto-updater'
app = require 'app'
dialog = require 'dialog'
fs = require 'fs'
ipc = require 'ipc'
path = require 'path'
os = require 'os'
net = require 'net'
shell = require 'shell'
url = require 'url'
{EventEmitter} = require 'events'
_ = require 'underscore-plus'

socketPath =
  if process.platform is 'win32'
    '\\\\.\\pipe\\atom-sock'
  else
    path.join(os.tmpdir(), 'atom.sock')

# The application's singleton class.
#
# It's the entry point into the Atom application and maintains the global state
# of the application.
#
module.exports =
class AtomApplication
  _.extend @prototype, EventEmitter.prototype
  updateVersion: null

  # Public: The entry point into the Atom application.
  @open: (options) ->
    createAtomApplication = -> new AtomApplication(options)

    # FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
    # take a few seconds to trigger 'error' event, it could be a bug of node
    # or atom-shell, before it's fixed we check the existence of socketPath to
    # speedup startup.
    if (process.platform isnt 'win32' and not fs.existsSync socketPath) or options.test
      createAtomApplication()
      return

    client = net.connect {path: socketPath}, ->
      client.write JSON.stringify(options), ->
        client.end()
        app.terminate()

    client.on 'error', createAtomApplication

  windows: null
  applicationMenu: null
  atomProtocolHandler: null
  resourcePath: null
  version: null

  exit: (status) -> app.exit(status)

  constructor: (options) ->
    {@resourcePath, @version, @devMode} = options
    global.atomApplication = this

    @pidsToOpenWindows = {}
    @pathsToOpen ?= []
    @windows = []

    @applicationMenu = new ApplicationMenu(@version)
    @atomProtocolHandler = new AtomProtocolHandler(@resourcePath)

    @listenForArgumentsFromNewProcess()
    @setupJavaScriptArguments()
    @handleEvents()
    @setupAutoUpdater()

    @openWithOptions(options)

  # Opens a new window based on the options provided.
  openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}) ->
    if test
      @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile})
    else if pathsToOpen.length > 0
      @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode})
    else if urlsToOpen.length > 0
      @openUrl({urlToOpen, devMode}) for urlToOpen in urlsToOpen
    else
      @openPath({pidToKillWhenClosed, newWindow, devMode}) # Always open a editor window if this is the first instance of Atom.

  # Public: Removes the {AtomWindow} from the global window list.
  removeWindow: (window) ->
    @windows.splice @windows.indexOf(window), 1
    @applicationMenu?.enableWindowSpecificItems(false) if @windows.length == 0

  # Public: Adds the {AtomWindow} to the global window list.
  addWindow: (window) ->
    @windows.push window
    @applicationMenu?.enableWindowSpecificItems(true)

  # Creates server to listen for additional atom application launches.
  #
  # You can run the atom command multiple times, but after the first launch
  # the other launches will just pass their information to this server and then
  # close immediately.
  listenForArgumentsFromNewProcess: ->
    @deleteSocketFile()
    server = net.createServer (connection) =>
      connection.on 'data', (data) =>
        @openWithOptions(JSON.parse(data))

    server.listen socketPath
    server.on 'error', (error) -> console.error 'Application server failed', error

  deleteSocketFile: ->
    return if process.platform is 'win32'

    if fs.existsSync(socketPath)
      try
        fs.unlinkSync(socketPath)
      catch error
        # Ignore ENOENT errors in case the file was deleted between the exists
        # check and the call to unlink sync. This occurred occasionally on CI
        # which is why this check is here.
        throw error unless error.code is 'ENOENT'

  # Configures required javascript environment flags.
  setupJavaScriptArguments: ->
    app.commandLine.appendSwitch 'js-flags', '--harmony_collections --harmony-proxies'

  # Enable updates unless running from a local build of Atom.
  setupAutoUpdater: ->
    autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"

    autoUpdater.on 'checking-for-update', =>
      @applicationMenu.showDownloadingUpdateItem(false)
      @applicationMenu.showInstallUpdateItem(false)
      @applicationMenu.showCheckForUpdateItem(false)

    autoUpdater.on 'update-not-available', =>
      @applicationMenu.showCheckForUpdateItem(true)

    autoUpdater.on 'update-available', =>
      @applicationMenu.showDownloadingUpdateItem(true)

    autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseName, releaseDate, releaseURL) =>
      atomWindow.sendCommand('window:update-available', [releaseName, releaseNotes]) for atomWindow in @windows
      @applicationMenu.showInstallUpdateItem(true)
      @updateVersion = releaseName

    autoUpdater.on 'error', (event, message) =>
      @applicationMenu.showCheckForUpdateItem(true)

    # Check for update after Atom has fully started and the menus are created
    setTimeout((-> autoUpdater.checkForUpdates()), 5000)

  checkForUpdate: ->
    @onUpdateNotAvailable ?= =>
      autoUpdater.removeListener 'error', @onUpdateError
      dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."

    @onUpdateError ?= (event, message) =>
      autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
      dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message

    autoUpdater.on 'update-not-available', @onUpdateNotAvailable
    autoUpdater.on 'error', @onUpdateError
{'fraction_non_alphanumeric': 0.10187229171776634, 'fraction_numerical': 0.002289264982421715, 'mean_word_length': 3.938231731933791, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 57, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5432132', 'n_tokens_mistral': 3516, 'n_tokens_neox': 3418, 'n_words': 1036}