diff --git a/Rakefile b/Rakefile index e75cd8834..873693031 100644 --- a/Rakefile +++ b/Rakefile @@ -28,7 +28,7 @@ end desc "Download node binary" task "update-node" do - `script/update-node` + `script/update-node v0.10.1` end desc "Download debug symbols for CEF" diff --git a/native/v8_extensions/native.mm b/native/v8_extensions/native.mm index 8211c7958..03c92eda0 100644 --- a/native/v8_extensions/native.mm +++ b/native/v8_extensions/native.mm @@ -24,8 +24,7 @@ namespace v8_extensions { const char* methodNames[] = { "writeToPasteboard", "readFromPasteboard", "quit", "watchPath", "unwatchPath", "getWatchedPaths", "unwatchAllPaths", "moveToTrash", - "reload", "setWindowState", "getWindowState", "isMisspelled", - "getCorrectionsForMisspelling", "beep" + "reload", "setWindowState", "getWindowState", "beep" }; CefRefPtr nativeObject = CefV8Value::CreateObject(NULL); @@ -163,34 +162,6 @@ namespace v8_extensions { return true; } - else if (name == "isMisspelled") { - NSString *word = stringFromCefV8Value(arguments[0]); - NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; - @synchronized(spellChecker) { - NSRange range = [spellChecker checkSpellingOfString:word startingAt:0]; - retval = CefV8Value::CreateBool(range.length > 0); - } - return true; - } - - else if (name == "getCorrectionsForMisspelling") { - NSString *misspelling = stringFromCefV8Value(arguments[0]); - NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; - @synchronized(spellChecker) { - NSString *language = [spellChecker language]; - NSRange range; - range.location = 0; - range.length = [misspelling length]; - NSArray *guesses = [spellChecker guessesForWordRange:range inString:misspelling language:language inSpellDocumentWithTag:0]; - CefRefPtr v8Guesses = CefV8Value::CreateArray([guesses count]); - for (int i = 0; i < [guesses count]; i++) { - v8Guesses->SetValue(i, CefV8Value::CreateString([[guesses objectAtIndex:i] UTF8String])); - } - retval = v8Guesses; - } - return true; - } - else if (name == "beep") { NSBeep(); } diff --git a/package.json b/package.json index 8f1d8129a..761afa2f7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", + "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git" }, diff --git a/script/bootstrap b/script/bootstrap index a3ffd75bf..4db2c1279 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -21,8 +21,8 @@ exit_unless_npm_exists npm install npm --silent NODE_DIR="$HOME/.cefode-gyp" -NODE_VERSION="0.8.21" -NODE_URL="https://gh-contractor-zcbenz.s3.amazonaws.com/cefode/dist" +NODE_VERSION="0.10.1" +NODE_URL="https://gh-contractor-zcbenz.s3.amazonaws.com/cefode2/dist" if [ ! -d "node_modules/node-gyp" ]; then ./node_modules/.bin/npm install node-gyp --silent HOME="$NODE_DIR" ./node_modules/.bin/node-gyp install --target="$NODE_VERSION" --dist-url="$NODE_URL" --arch=ia32 diff --git a/script/update-cefode b/script/update-cefode index 7f582be19..a715242c6 100755 --- a/script/update-cefode +++ b/script/update-cefode @@ -13,7 +13,7 @@ else TARGET=$1 fi -DISTURL="https://gh-contractor-zcbenz.s3.amazonaws.com/cefode/prebuilt-cef" +DISTURL="https://gh-contractor-zcbenz.s3.amazonaws.com/cefode2/prebuilt-cef" CEF_BASENAME="cef_binary_3.1423.1133_macosx" CEF_SYMBOLS_BASENAME="${CEF_BASENAME}_symbols" @@ -29,7 +29,7 @@ fi CURRENT_VERSION=`cat cef/version 2>&1` if [[ $LATEST_VERSION != $CURRENT_VERSION ]]; then - echo "Downloading/extracting cefode u${LATEST_VERSION}..." + echo "Downloading/extracting cefode2 u${LATEST_VERSION}..." curl --progress-bar "${DISTURL}/cef_binary_latest.zip" > "${TEMP_DIR}/cef.zip" unzip -q "${TEMP_DIR}/cef.zip" -d "${TEMP_DIR}" [ -e "${TARGET}" ] && rm -rf "${TARGET}" @@ -41,7 +41,7 @@ if [[ "${SYMBOLS}" != "1" ]]; then exit 0 fi -echo "Downloading/extracting symbols for cefode u${LATEST_VERSION}..." +echo "Downloading/extracting symbols for cefode2 u${LATEST_VERSION}..." curl --progress-bar "${DISTURL}/cef_binary_latest_symbols.zip" > "${TEMP_DIR}/symbols.zip" unzip -q "${TEMP_DIR}/symbols.zip" -d "${TEMP_DIR}" mv "${TEMP_DIR}/${CEF_SYMBOLS_BASENAME}"/* "${TARGET}/Release" diff --git a/script/update-node b/script/update-node index e3a249707..bbbb6d9e3 100755 --- a/script/update-node +++ b/script/update-node @@ -4,35 +4,24 @@ set -e cd "$(dirname $0)/.." +NODE_VERSION=v0.10.1 +[ -z $1 ] || NODE_VERSION=$1 + # Test whether we need update. -if [ -f "node/node" ]; then +if [ -f "node/node" ] && [[ `node/node --version` == $NODE_VERSION ]] ; then exit 0 fi -if ! DOWNLOAD_PAGE=$(curl -fsSkL http://nodejs.org/download/); then - exit 1; -fi - -NODE_VERSION=$(echo "$DOWNLOAD_PAGE" \ - | awk '/Current version:/ { print }' \ - | awk -F"[<>]" '{ print $5 }') - case $OSTYPE in darwin*) NODE_PLATFORM=darwin ;; linux*) NODE_PLATFORM=linux ;; *) echo "Unsupported platform $OSTYPE" && exit 1 ;; esac -if uname -a | grep 'x86_64' > /dev/null ; then - NODE_ARCH=x64 -else - NODE_ARCH=x86 -fi - -NODE_DIST_NAME="node-$NODE_VERSION-$NODE_PLATFORM-$NODE_ARCH" +NODE_DIST_NAME="node-$NODE_VERSION-$NODE_PLATFORM-x86" # Download node and untar -NODE_TARBALL_URL="http://nodejs.org/dist/$NODE_VERSION/$NODE_DIST_NAME.tar.gz" +NODE_TARBALL_URL="https://gh-contractor-zcbenz.s3.amazonaws.com/node/dist/$NODE_DIST_NAME.tar.gz" TARGET_DIR='node' [ -d "$TARGET_DIR" ] || mkdir "$TARGET_DIR" cd "$TARGET_DIR" diff --git a/spec/stdlib/task-shell-spec.coffee b/spec/stdlib/task-shell-spec.coffee index d1ccb8fc0..f1a539036 100644 --- a/spec/stdlib/task-shell-spec.coffee +++ b/spec/stdlib/task-shell-spec.coffee @@ -2,7 +2,7 @@ Task = require 'task' describe "Task shell", -> describe "populating the window with fake properties", -> - describe "when jQuery is loaded in a web worker", -> + describe "when jQuery is loaded in a child process", -> it "doesn't log to the console", -> spyOn(console, 'log') spyOn(console, 'error') @@ -14,7 +14,7 @@ describe "Task shell", -> task = new JQueryTask() task.start() - waitsFor "web worker to start and jquery to be required", 5000, -> + waitsFor "child process to start and jquery to be required", 5000, -> task.jqueryLoaded runs -> expect(task.jqueryLoaded).toBeTruthy() diff --git a/src/app/point.coffee b/src/app/point.coffee index e471ad6c6..6dd3eca27 100644 --- a/src/app/point.coffee +++ b/src/app/point.coffee @@ -1,10 +1,12 @@ +_ = require 'underscore' + module.exports = class Point @fromObject: (object) -> if object instanceof Point object else - if object instanceof Array + if _.isArray(object) [row, column] = object else { row, column } = object diff --git a/src/app/range.coffee b/src/app/range.coffee index a3870ea66..d72ef6514 100644 --- a/src/app/range.coffee +++ b/src/app/range.coffee @@ -31,7 +31,7 @@ class Range new Range(@start.copy(), @end.copy()) isEqual: (other) -> - if other instanceof Array and other.length == 2 + if _.isArray(other) and other.length == 2 other = new Range(other...) other.start.isEqual(@start) and other.end.isEqual(@end) diff --git a/src/app/window.coffee b/src/app/window.coffee index 8ef579f0e..f6c513c2d 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -80,7 +80,7 @@ window.installAtomCommand = (commandPath) -> bundledCommandPath = fs.resolve(window.resourcePath, 'atom.sh') if bundledCommandPath? fs.write(commandPath, fs.read(bundledCommandPath)) - spawn("chmod u+x '#{commandPath}'") + spawn('chmod', ['u+x', commandPath]) window.handleWindowEvents = -> $(window).command 'window:toggle-full-screen', => atom.toggleFullScreen() diff --git a/src/packages/spell-check/lib/misspelling-view.coffee b/src/packages/spell-check/lib/misspelling-view.coffee index ba57e4164..0940ce0f7 100644 --- a/src/packages/spell-check/lib/misspelling-view.coffee +++ b/src/packages/spell-check/lib/misspelling-view.coffee @@ -1,6 +1,7 @@ {View} = require 'space-pen' Range = require 'range' CorrectionsView = require './corrections-view' +SpellChecker = require 'spellchecker' module.exports = class MisspellingView extends View @@ -30,7 +31,7 @@ class MisspellingView extends View screenRange = @getScreenRange() misspelling = @editor.getTextInRange(@editor.bufferRangeForScreenRange(screenRange)) - corrections = $native.getCorrectionsForMisspelling(misspelling) + corrections = SpellChecker.getCorrectionsForMisspelling(misspelling) @correctionsView?.remove() @correctionsView = new CorrectionsView(@editor, corrections, screenRange) diff --git a/src/packages/spell-check/lib/spell-check-handler.coffee b/src/packages/spell-check/lib/spell-check-handler.coffee index 8040f4991..0b21f73ab 100644 --- a/src/packages/spell-check/lib/spell-check-handler.coffee +++ b/src/packages/spell-check/lib/spell-check-handler.coffee @@ -1,3 +1,5 @@ +SpellChecker = require 'spellchecker' + module.exports = findMisspellings: (text) -> wordRegex = /(?:^|[\s\[\]])([a-zA-Z']+)(?=[\s\.\[\]]|$)/g @@ -6,7 +8,7 @@ module.exports = for line in text.split('\n') while matches = wordRegex.exec(line) word = matches[1] - continue unless $native.isMisspelled(word) + continue unless SpellChecker.isMisspelled(word) startColumn = matches.index + matches[0].length - word.length endColumn = startColumn + word.length misspellings.push([[row, startColumn], [row, endColumn]]) diff --git a/src/stdlib/task-shell.coffee b/src/stdlib/task-shell.coffee index bab99dc7c..6ac2d5f6e 100644 --- a/src/stdlib/task-shell.coffee +++ b/src/stdlib/task-shell.coffee @@ -1,17 +1,17 @@ -# This file is loaded within Task's worker thread. It will attempt to invoke +# This file is loaded within Task's worker process. It will attempt to invoke # any message with a 'method' and 'args' key on the global `handler` object. The # initial `handler` object contains the `start` method, which is called by the # task itself to relay information from the window thread and bootstrap the # worker's environment. The `start` method then replaces the handler with an # object required from the given `handlerPath`. -self.window = {} -self.attachEvent = -> +global.window = {} +global.attachEvent = -> console = warn: -> callTaskMethod 'warn', arguments... log: -> callTaskMethod 'log', arguments... error: -> callTaskMethod 'error', arguments... -self.__defineGetter__ 'console', -> console +global.__defineGetter__ 'console', -> console window.document = createElement: -> @@ -24,21 +24,21 @@ window.document = getElementById: -> {} createComment: -> {} createDocumentFragment: -> {} -self.document = window.document +global.document = window.document # `callTaskMethod` can be used to invoke method's on the parent `Task` object # back in the window thread. -self.callTaskMethod = (method, args...) -> - postMessage(method: method, args: args) +global.callTaskMethod = (method, args...) -> + process.send(method: method, args: args) -# The worker's initial handler replaces itself when `start` is invoked -self.handler = +# The worker's initial handler replaces itglobal when `start` is invoked +global.handler = start: ({globals, handlerPath}) -> for key, value of globals - self[key] = value + global[key] = value window[key] = value - self.handler = require(handlerPath) + global.handler = require(handlerPath) callTaskMethod 'started' -self.addEventListener 'message', ({data}) -> +process.on 'message', (data) -> handler[data.method]?(data.args...) if data.method diff --git a/src/stdlib/task.coffee b/src/stdlib/task.coffee index 636be9e6f..8216a4f15 100644 --- a/src/stdlib/task.coffee +++ b/src/stdlib/task.coffee @@ -1,4 +1,5 @@ _ = require 'underscore' +child_process = require 'child_process' EventEmitter = require 'event-emitter' fs = require 'fs-utils' @@ -11,9 +12,11 @@ class Task start: -> throw new Error("Task already started") if @worker? - blob = new Blob(["require('coffee-script'); require('task-shell');"], type: 'text/javascript') - @worker = new Worker(URL.createObjectURL(blob)) - @worker.onmessage = ({data}) => + # Equivalent with node --eval "...". + blob = "require('coffee-script'); require('task-shell');" + @worker = child_process.fork '--eval', [ blob ], cwd: __dirname + + @worker.on 'message', (data) => if @aborted @done() return @@ -22,6 +25,7 @@ class Task this[data.method](data.args...) else @onMessage(data) + @startWorker() log: -> console.log(arguments...) @@ -43,14 +47,14 @@ class Task @postMessage({method, args}) postMessage: (data) -> - @worker.postMessage(data) + @worker.send(data) abort: -> @aborted = true done: -> @abort() - @worker?.terminate() + @worker?.kill() @worker = null @trigger 'task-completed'