function handleFileClose(commandData) {
        var file,
            promptOnly,
            _forceClose,
            _spawnedRequest,
            paneId = MainViewManager.ACTIVE_PANE;

        if (commandData) {
            file        = commandData.file;
            promptOnly  = commandData.promptOnly;
            _forceClose = commandData._forceClose;
            paneId      = commandData.paneId || paneId;
            _spawnedRequest = commandData.spawnedRequest || false;
        }

        // utility function for handleFileClose: closes document & removes from workingset
        function doClose(file) {
            if (!promptOnly) {
                MainViewManager._close(paneId, file);
                HealthLogger.fileClosed(file);
            }
        }

        var result = new $.Deferred(), promise = result.promise();

        // Default to current document if doc is null
        if (!file) {
            file = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
        }

        // No-op if called when nothing is open; TODO: (issue #273) should command be grayed out instead?
        if (!file) {
            result.resolve();
            return promise;
        }

        var doc = DocumentManager.getOpenDocumentForPath(file.fullPath);

        if (doc && doc.isDirty && !_forceClose && (MainViewManager.isExclusiveToPane(doc.file, paneId) || _spawnedRequest)) {
            // Document is dirty: prompt to save changes before closing if only the document is exclusively
            // listed in the requested pane or this is part of a list close request
            var filename = FileUtils.getBaseName(doc.file.fullPath);

            Dialogs.showModalDialog(
                DefaultDialogs.DIALOG_ID_SAVE_CLOSE,
                Strings.SAVE_CLOSE_TITLE,
                StringUtils.format(
                    Strings.SAVE_CLOSE_MESSAGE,
                    StringUtils.breakableUrl(filename)
                ),
                [
                    {
                        className : Dialogs.DIALOG_BTN_CLASS_LEFT,
                        id        : Dialogs.DIALOG_BTN_DONTSAVE,
                        text      : Strings.DONT_SAVE
                    },
                    {
                        className : Dialogs.DIALOG_BTN_CLASS_NORMAL,
                        id        : Dialogs.DIALOG_BTN_CANCEL,
                        text      : Strings.CANCEL
                    },
                    {
                        className : Dialogs.DIALOG_BTN_CLASS_PRIMARY,
                        id        : Dialogs.DIALOG_BTN_OK,
                        text      : Strings.SAVE
                    }
                ]
            )
                .done(function (id) {
                    if (id === Dialogs.DIALOG_BTN_CANCEL) {
                        dispatchAppQuitCancelledEvent();
                        result.reject();
                    } else if (id === Dialogs.DIALOG_BTN_OK) {
                        // "Save" case: wait until we confirm save has succeeded before closing
                        handleFileSave({doc: doc})
                            .done(function (newFile) {
                                doClose(newFile);
                                result.resolve();
                            })
                            .fail(function () {
                                result.reject();
                            });
                    } else {
                        // "Don't Save" case: even though we're closing the main editor, other views of
                        // the Document may remain in the UI. So we need to revert the Document to a clean
                        // copy of whatever's on disk.
                        doClose(file);

                        // Only reload from disk if we've executed the Close for real.
                        if (promptOnly) {
                            result.resolve();
                        } else {
                            // Even if there are no listeners attached to the document at this point, we want
                            // to do the revert anyway, because clients who are listening to the global documentChange
                            // event from the Document module (rather than attaching to the document directly),
                            // such as the Find in Files panel, should get a change event. However, in that case,
                            // we want to ignore errors during the revert, since we don't want a failed revert
                            // to throw a dialog if the document isn't actually open in the UI.
                            var suppressError = !DocumentManager.getOpenDocumentForPath(file.fullPath);
                            _doRevert(doc, suppressError)
                                .then(result.resolve, result.reject);
                        }
                    }
                });
            result.always(function () {
                MainViewManager.focusActivePane();
            });
        } else {
            // File is not open, or IS open but Document not dirty: close immediately
            doClose(file);
            MainViewManager.focusActivePane();
            result.resolve();
        }
        return promise;
    }
Closes the specified file: removes it from the workingset, and closes the main editor if one
is open. Prompts user about saving changes first, if document is dirty.

@param {?{file: File, promptOnly:boolean}} commandData  Optional bag of arguments:
     file - File to close; assumes the current document if not specified.
     promptOnly - If true, only displays the relevant confirmation UI and does NOT actually
         close the document. This is useful when chaining file-close together with other user
         prompts that may be cancelable.
     _forceClose - If true, closes the document without prompting even if there are unsaved
         changes. Only for use in unit tests.
@return {$.Promise} a promise that is resolved when the file is closed, or if no file is open.
     FUTURE: should we reject the promise if no file is open?