mirror of
https://github.com/atom/atom.git
synced 2026-01-24 22:38:20 -05:00
Merge branch 'dirty-buffer'
This commit is contained in:
@@ -85,7 +85,19 @@
|
||||
|
||||
- (bool)keyEventOfType:(cef_handler_keyevent_type_t)type code:(int)code modifiers:(int)modifiers isSystemKey:(bool)isSystemKey isAfterJavaScript:(bool)isAfterJavaScript {
|
||||
if (isAfterJavaScript && type == KEYEVENT_RAWKEYDOWN && modifiers == KEY_META && code == 'R') {
|
||||
_clientHandler->GetBrowser()->ReloadIgnoreCache();
|
||||
|
||||
CefRefPtr<CefV8Context> context = _clientHandler->GetBrowser()->GetMainFrame()->GetV8Context();
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
|
||||
context->Enter();
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
CefV8ValueList arguments;
|
||||
global->GetValue("reload")->ExecuteFunction(global, arguments, retval, exception, true);
|
||||
if (exception) _clientHandler->GetBrowser()->ReloadIgnoreCache();
|
||||
context->Exit();
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ NSString *stringFromCefV8Value(const CefRefPtr<CefV8Value>& value) {
|
||||
NativeHandler::NativeHandler() : CefV8Handler() {
|
||||
std::string extensionCode = "var $native = {}; (function() {";
|
||||
|
||||
const char *functionNames[] = {"exists", "alert", "read", "write", "absolute", "list", "isFile", "isDirectory", "remove", "asyncList", "open", "openDialog", "quit", "writeToPasteboard", "readFromPasteboard", "showDevTools", "newWindow", "saveDialog", "exit", "watchPath", "unwatchPath", "makeDirectory", "move", "moveToTrash"};
|
||||
const char *functionNames[] = {"exists", "alert", "read", "write", "absolute", "list", "isFile", "isDirectory", "remove", "asyncList", "open", "openDialog", "quit", "writeToPasteboard", "readFromPasteboard", "showDevTools", "newWindow", "saveDialog", "exit", "watchPath", "unwatchPath", "makeDirectory", "move", "moveToTrash", "reload"};
|
||||
NSUInteger arrayLength = sizeof(functionNames) / sizeof(const char *);
|
||||
for (NSUInteger i = 0; i < arrayLength; i++) {
|
||||
std::string functionName = std::string(functionNames[i]);
|
||||
@@ -375,5 +375,8 @@ bool NativeHandler::Execute(const CefString& name,
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "reload") {
|
||||
CefV8Context::GetCurrentContext()->GetBrowser()->ReloadIgnoreCache();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -31,6 +31,43 @@ describe 'Buffer', ->
|
||||
buffer = new Buffer
|
||||
expect(buffer.getText()).toBe ""
|
||||
|
||||
describe "path-change event", ->
|
||||
it "emits path-change event when path is changed", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
buffer.on 'path-change', eventHandler
|
||||
buffer.setPath("moo.text")
|
||||
expect(eventHandler).toHaveBeenCalledWith(buffer)
|
||||
|
||||
describe ".isModified()", ->
|
||||
describe "when deserialized", ->
|
||||
it "returns false", ->
|
||||
buffer = Buffer.deserialize(buffer.serialize(), new Project)
|
||||
expect(buffer.isModified()).toBe false
|
||||
|
||||
buffer = Buffer.deserialize((new Buffer).serialize(), new Project)
|
||||
expect(buffer.isModified()).toBe false
|
||||
|
||||
it "returns is true if buffer no path and had changes", ->
|
||||
buffer = new Buffer
|
||||
buffer.insert([0,0], "oh hi")
|
||||
expect(buffer.isModified()).toBe true
|
||||
|
||||
it "returns true when user changes buffer", ->
|
||||
expect(buffer.isModified()).toBeFalsy()
|
||||
buffer.insert([0,0], "hi")
|
||||
expect(buffer.isModified()).toBe true
|
||||
|
||||
it "returns false after modified buffer is saved", ->
|
||||
filePath = "/tmp/atom-tmp-file"
|
||||
buffer = new Buffer(filePath)
|
||||
expect(buffer.isModified()).toBe false
|
||||
|
||||
buffer.insert([0,0], "hi")
|
||||
expect(buffer.isModified()).toBe true
|
||||
|
||||
buffer.save()
|
||||
expect(buffer.isModified()).toBe false
|
||||
|
||||
describe '.deserialize(state, project)', ->
|
||||
project = null
|
||||
|
||||
@@ -365,7 +402,7 @@ describe 'Buffer', ->
|
||||
|
||||
expect(ranges.length).toBe 2
|
||||
|
||||
describe "backwardsScanInRange(range, regex, fn)", ->
|
||||
describe ".backwardsScanInRange(range, regex, fn)", ->
|
||||
describe "when given a regex with no global flag", ->
|
||||
it "calls the iterator with the last match for the given regex in the given range", ->
|
||||
matches = []
|
||||
@@ -446,11 +483,3 @@ describe 'Buffer', ->
|
||||
expect(buffer.positionForCharacterIndex(30)).toEqual [1, 0]
|
||||
expect(buffer.positionForCharacterIndex(61)).toEqual [2, 0]
|
||||
expect(buffer.positionForCharacterIndex(408)).toEqual [12, 2]
|
||||
|
||||
describe "path-change event", ->
|
||||
it "emits path-change event when path is changed", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
buffer.on 'path-change', eventHandler
|
||||
buffer.setPath("moo.text")
|
||||
expect(eventHandler).toHaveBeenCalledWith(buffer)
|
||||
|
||||
|
||||
@@ -1549,6 +1549,7 @@ describe "Editor", ->
|
||||
expect(editor.buffer).toBe buffer
|
||||
|
||||
it "calls remove on the editor if there is one edit session and mini is false", ->
|
||||
originalBuffer = editor.buffer
|
||||
expect(editor.mini).toBeFalsy()
|
||||
expect(editor.editSessions.length).toBe 1
|
||||
spyOn(editor, 'remove')
|
||||
@@ -1560,3 +1561,12 @@ describe "Editor", ->
|
||||
spyOn(editor, 'remove')
|
||||
editor.trigger 'close'
|
||||
expect(editor.remove).not.toHaveBeenCalled()
|
||||
|
||||
describe "when buffer is modified", ->
|
||||
it "triggers alert and does not close session", ->
|
||||
spyOn(editor, 'remove')
|
||||
spyOn($native, 'alert')
|
||||
editor.insertText("I AM CHANGED!")
|
||||
editor.trigger "close"
|
||||
expect(editor.remove).not.toHaveBeenCalled()
|
||||
expect($native.alert).toHaveBeenCalled()
|
||||
|
||||
@@ -17,6 +17,20 @@ describe "Window", ->
|
||||
$(window).trigger 'close'
|
||||
expect(window.close).toHaveBeenCalled()
|
||||
|
||||
describe ".reload()", ->
|
||||
it "returns false when no buffers are modified", ->
|
||||
spyOn($native, "reload")
|
||||
window.reload()
|
||||
expect($native.reload).toHaveBeenCalled()
|
||||
|
||||
it "shows alert when a modifed buffer exists", ->
|
||||
rootView.activeEditor().insertText("hi")
|
||||
spyOn($native, "alert")
|
||||
spyOn($native, "reload")
|
||||
window.reload()
|
||||
expect($native.reload).not.toHaveBeenCalled()
|
||||
expect($native.alert).toHaveBeenCalled()
|
||||
|
||||
describe "requireStylesheet(path)", ->
|
||||
it "synchronously loads the stylesheet at the given path and installs a style tag for it in the head", ->
|
||||
$('head style[path*="atom.css"]').remove()
|
||||
|
||||
@@ -8,16 +8,19 @@ UndoManager = require 'undo-manager'
|
||||
module.exports =
|
||||
class Buffer
|
||||
@idCounter = 1
|
||||
modified: null
|
||||
lines: null
|
||||
path: null
|
||||
|
||||
@deserialize: (state, project) ->
|
||||
if state.path
|
||||
project.open(state.path)
|
||||
buffer = project.open(state.path)
|
||||
else
|
||||
buffer = project.bufferWithId(state.id) ? project.open()
|
||||
buffer.setText(state.text)
|
||||
buffer
|
||||
buffer.modified = state.modified
|
||||
|
||||
buffer
|
||||
|
||||
constructor: (path) ->
|
||||
@id = @constructor.idCounter++
|
||||
@@ -28,12 +31,13 @@ class Buffer
|
||||
else
|
||||
@setText('')
|
||||
@undoManager = new UndoManager(this)
|
||||
@modified = false
|
||||
|
||||
serialize: ->
|
||||
if @getPath()
|
||||
{ path: @path }
|
||||
else
|
||||
{ text: @getText(), id: @id }
|
||||
{ text: @getText(), id: @id , modified: @modified}
|
||||
|
||||
getPath: ->
|
||||
@path
|
||||
@@ -139,6 +143,8 @@ class Buffer
|
||||
newTextLines[lastLineIndex] += suffix
|
||||
|
||||
@lines[oldRange.start.row..oldRange.end.row] = newTextLines
|
||||
@modified = true
|
||||
|
||||
@trigger 'change', { oldRange, newRange, oldText, newText }
|
||||
newRange
|
||||
|
||||
@@ -155,15 +161,19 @@ class Buffer
|
||||
@undoManager.redo()
|
||||
|
||||
save: ->
|
||||
if not @getPath() then throw new Error("Tried to save buffer with no file path")
|
||||
if not @getPath() then throw new Error("Can't save buffer with no file path")
|
||||
@trigger 'before-save'
|
||||
fs.write @getPath(), @getText()
|
||||
@modified = false
|
||||
@trigger 'after-save'
|
||||
|
||||
saveAs: (path) ->
|
||||
@setPath(path)
|
||||
@save()
|
||||
|
||||
isModified: ->
|
||||
@modified
|
||||
|
||||
getMode: ->
|
||||
return @mode if @mode
|
||||
extension = if @getPath() then @getPath().split('/').pop().split('.').pop() else null
|
||||
|
||||
@@ -7,6 +7,8 @@ Range = require 'range'
|
||||
EditSession = require 'edit-session'
|
||||
CursorView = require 'cursor-view'
|
||||
SelectionView = require 'selection-view'
|
||||
Native = require 'native'
|
||||
fs = require 'fs'
|
||||
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
@@ -604,12 +606,14 @@ class Editor extends View
|
||||
|
||||
save: ->
|
||||
if not @buffer.getPath()
|
||||
path = $native.saveDialog()
|
||||
return if not path
|
||||
path = Native.saveDialog()
|
||||
return false if not path
|
||||
@buffer.saveAs(path)
|
||||
else
|
||||
@buffer.save()
|
||||
|
||||
true
|
||||
|
||||
clipScreenPosition: (screenPosition, options={}) ->
|
||||
@renderer.clipScreenPosition(screenPosition, options)
|
||||
|
||||
@@ -778,7 +782,19 @@ class Editor extends View
|
||||
|
||||
close: ->
|
||||
return if @mini
|
||||
@removeActiveEditSession()
|
||||
if @buffer.isModified()
|
||||
filename = if @buffer.getPath() then fs.base(@buffer.getPath()) else "untitled buffer"
|
||||
message = "'#{filename}' has changes, do you want to save them?"
|
||||
detailedMessage = "Your changes will be lost if you don't save them"
|
||||
buttons = [
|
||||
["Save", => @save() and @removeActiveEditSession()]
|
||||
["Cancel", =>]
|
||||
["Don't save", => @removeActiveEditSession()]
|
||||
]
|
||||
|
||||
Native.alert message, detailedMessage, buttons
|
||||
else
|
||||
@removeActiveEditSession()
|
||||
|
||||
unsubscribeFromBuffer: ->
|
||||
@buffer.off ".editor#{@id}"
|
||||
|
||||
@@ -123,6 +123,14 @@ class RootView extends View
|
||||
editors: ->
|
||||
@panes.find('.editor').map -> $(this).view()
|
||||
|
||||
modifiedBuffers: ->
|
||||
modifiedBuffers = []
|
||||
for editor in @editors()
|
||||
for session in editor.editSessions
|
||||
modifiedBuffers.push session.buffer if session.buffer.isModified()
|
||||
|
||||
modifiedBuffers
|
||||
|
||||
activeEditor: ->
|
||||
if (editor = @panes.find('.editor.active')).length
|
||||
editor.view()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# This a weirdo file. We don't create a Window class, we just add stuff to
|
||||
# the DOM window.
|
||||
|
||||
Native = require 'native'
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
@@ -60,6 +61,19 @@ windowAdditions =
|
||||
return if $("head style[path='#{fullPath}']").length
|
||||
$('head').append "<style path='#{fullPath}'>#{content}</style>"
|
||||
|
||||
reload: ->
|
||||
if rootView.modifiedBuffers().length > 0
|
||||
message = "There are unsaved buffers, reload anyway?"
|
||||
detailedMessage = "You will lose all unsaved changes if you reload"
|
||||
buttons = [
|
||||
["Reload", -> Native.reload()]
|
||||
["Cancel", ->]
|
||||
]
|
||||
|
||||
Native.alert(message, detailedMessage, buttons)
|
||||
else
|
||||
Native.reload()
|
||||
|
||||
showConsole: ->
|
||||
$native.showDevTools()
|
||||
|
||||
|
||||
@@ -2,4 +2,8 @@ module.exports =
|
||||
class Native
|
||||
@alert: (args...) -> $native.alert(args...)
|
||||
|
||||
@saveDialog: (args...) -> $native.saveDialog(args...)
|
||||
|
||||
@reload: -> $native.reload()
|
||||
|
||||
@moveToTrash: (args...) -> $native.moveToTrash(args...)
|
||||
|
||||
Reference in New Issue
Block a user