From 3a1644b734f4c801800bf0d478062789a5680f15 Mon Sep 17 00:00:00 2001 From: Rasmus Andersson Date: Tue, 1 Feb 2011 14:13:21 +0100 Subject: [PATCH] added an "edit" event in node.js-land emitted from documents (with version, location and change delta values) --- resources/main.js | 21 +++++++++++++++++++++ src/KDocument.mm | 32 +++++++++++++++++++++++++++++++- src/node-module/KObjectProxy.mm | 2 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/resources/main.js b/resources/main.js index 17e4e3c..f2f356c 100644 --- a/resources/main.js +++ b/resources/main.js @@ -64,6 +64,27 @@ kod.on('openDocument', function(document) { //console.log('openDocument: '+ util.inspect(document, 0, 4)); console.log('openDocument: #'+document.identifier+' '+document.type+ ' '+(document.url || '*new*')); + + // example of registering for the "edit" event, emitted after each edit to + // a document. + /*document.on('edit', function(version, location, changeDelta) { + console.log(this+':edit -> %j', { + version:version, location:location, changeDelta:changeDelta}); + // if we are to manipulate the text, we need to compare versions since + // these things happen concurrently. Here, we wrap a "p" character in < & >: + if (document.version == version && changeDelta == 1) { + var text = document.text; + var changedChar = text.substr(location, 1); + if (changedChar == "p") { + document.text = text.substr(0,location)+'<'+changedChar+'>'+ + text.substr(location+1); + if (document.version != version+1) { + console.log("another edit happened while we where running. "+ + "The effect is undefined from our perspective."); + } + } + } + })*/ }); // example event listener for the "activateDocument" event, emitted when a diff --git a/src/KDocument.mm b/src/KDocument.mm index 5f60029..3c02e80 100644 --- a/src/KDocument.mm +++ b/src/KDocument.mm @@ -1358,7 +1358,7 @@ - (void)textStorageDidProcessEditing:(NSNotification *)notification { // Increment our version [self willChangeValueForKey:@"version"]; - h_atomic_inc(&version_); + uint64_t version = h_atomic_inc(&version_); [self didChangeValueForKey:@"version"]; // range that was affected by the edit @@ -1382,6 +1382,36 @@ - (void)textStorageDidProcessEditing:(NSNotification *)notification { }); } + // emit event in node-land + KNodePerformInNode(^(KNodeReturnBlock returnCallback){ + v8::HandleScope scope; + v8::Local doc = [self v8Value]->ToObject(); + // TODO: refactor this to be reusable for emitting events on any object + v8::Local emitV = doc->Get(v8::String::New("emit")); + if (!emitV.IsEmpty() && emitV->IsFunction()) { + v8::Local argv[] = { + v8::String::New("edit"), + v8::Number::New((double)version), + v8::Number::New((double)editedRange.location), + v8::Integer::New(changeInLength) + }; + static const int argc = sizeof(argv) / sizeof(argv[0]); + v8::TryCatch tryCatch; + v8::Local returnValue = + v8::Local::Cast(emitV)->Call(doc, argc, argv); + NSError *error = nil; + if (tryCatch.HasCaught()) { + v8::String::Utf8Value trace(tryCatch.StackTrace()); + NSAutoreleasePool *pool1 = [NSAutoreleasePool new]; + WLOG("Error while emitting event '%s' on %@: %s", "edit", self, + *trace ? *trace : "(no trace)"); + [pool1 drain]; + } + } + // must be called since this takes care of releasing some resources + returnCallback(nil, nil, nil); + }); + // we do not process edits when we are loading if (isLoading_) return; diff --git a/src/node-module/KObjectProxy.mm b/src/node-module/KObjectProxy.mm index c22a17c..548b4f7 100644 --- a/src/node-module/KObjectProxy.mm +++ b/src/node-module/KObjectProxy.mm @@ -32,6 +32,8 @@ @interface _KObjectProxyShelf : NSObject {} @end @implementation _KObjectProxyShelf - (void)_KObjectProxy_dealloc_associations { //DLOG("_KObjectProxy_dealloc_associations for %p", self); + // TODO: assert that we are running in the nodejs thread, or we need to + // defer this to that thread since v8 will crash and burn unless so. // clear wrapper NSValue *v = objc_getAssociatedObject(self, &kPersistentWrapperKey);