Merge pull request #444 from github/process-task

Add ProcessTask
This commit is contained in:
Cheng Zhao
2013-03-26 23:00:03 -07:00
14 changed files with 47 additions and 77 deletions

View File

@@ -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"

View File

@@ -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<CefV8Value> 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<CefV8Value> 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();
}

View File

@@ -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"
},

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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()

View File

@@ -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)

View File

@@ -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]])

View File

@@ -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

View File

@@ -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'