mirror of
https://github.com/atom/atom.git
synced 2026-02-13 08:04:56 -05:00
Give Task an RPC-style interaction with its Worker
This commit makes all interactions between Task and Worker look like method calls. The worker now has a global `callTaskMethod` function that it can use to call methods on the Task object. And the Task can use `callWorkerMethod` to call methods on a global `handler` object in the worker. The worker's initial `handler` actually contains the `start` method, which the Task initially calls to kick things off. Then the global `handler` gets replaced with whatever `handlerPath` is specified by the Task. The worker then calls `workerStarted` on its parent Task object. This commit also gets rid of the `onProgress` method with the reply semantics, favoring a more explicit interaction. When `snippetsLoaded` finishes adding the snippet data, we call `loadNextPackageSnippets` explicitly rather than returning a reply message.
This commit is contained in:
committed by
Kevin Sawicki
parent
c628a88409
commit
0726987896
@@ -4,7 +4,7 @@ PEG = require 'pegjs'
|
||||
_ = require 'underscore'
|
||||
SnippetExpansion = require './src/snippet-expansion'
|
||||
Snippet = require './src/snippet'
|
||||
SnippetsTask = require './src/snippets-task'
|
||||
SnippetsTask = require './src/load-snippets-task'
|
||||
|
||||
module.exports =
|
||||
class Snippets extends AtomPackage
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Snippets = require 'snippets'
|
||||
Snippet = require 'snippets/src/snippet'
|
||||
SnippetsTask = require 'snippets/src/snippets-task'
|
||||
LoadSnippetsTask = require 'snippets/src/load-snippets-task'
|
||||
RootView = require 'root-view'
|
||||
Buffer = require 'buffer'
|
||||
Editor = require 'editor'
|
||||
@@ -11,7 +11,7 @@ describe "Snippets extension", ->
|
||||
[buffer, editor] = []
|
||||
beforeEach ->
|
||||
rootView = new RootView(require.resolve('fixtures/sample.js'))
|
||||
spyOn(SnippetsTask.prototype, 'start')
|
||||
spyOn(LoadSnippetsTask.prototype, 'start')
|
||||
atom.loadPackage("snippets")
|
||||
editor = rootView.getActiveEditor()
|
||||
buffer = editor.getBuffer()
|
||||
@@ -214,7 +214,7 @@ describe "Snippets extension", ->
|
||||
describe "snippet loading", ->
|
||||
it "loads non-hidden snippet files from all atom packages with snippets directories, logging a warning if a file can't be parsed", ->
|
||||
spyOn(console, 'warn').andCallThrough()
|
||||
jasmine.unspy(SnippetsTask.prototype, 'start')
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'start')
|
||||
snippets.loaded = false
|
||||
snippets.loadAll()
|
||||
|
||||
@@ -228,7 +228,7 @@ describe "Snippets extension", ->
|
||||
expect(console.warn.calls.length).toBeGreaterThan 0
|
||||
|
||||
it "loads snippets from all TextMate packages with snippets", ->
|
||||
jasmine.unspy(SnippetsTask.prototype, 'start')
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'start')
|
||||
snippets.loaded = false
|
||||
snippets.loadAll()
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports =
|
||||
loadTextmateSnippets: ({path}) ->
|
||||
fs = require 'fs'
|
||||
loadTextmateSnippets: (path) ->
|
||||
snippetsDirPath = fs.join(path, 'Snippets')
|
||||
snippets = fs.list(snippetsDirPath).map (snippetPath) ->
|
||||
fs.readPlist(snippetPath)
|
||||
self.postMessage
|
||||
type: 'loadSnippets'
|
||||
snippets: snippets
|
||||
@snippetsLoaded(snippets)
|
||||
|
||||
loadAtomSnippets: ({path}) ->
|
||||
fs = require 'fs'
|
||||
loadAtomSnippets: (path) ->
|
||||
snippetsDirPath = fs.join(path, 'snippets')
|
||||
snippets = []
|
||||
for snippetsPath in fs.list(snippetsDirPath)
|
||||
@@ -18,6 +16,6 @@ module.exports =
|
||||
snippets.push(fs.readObject(snippetsPath))
|
||||
catch e
|
||||
console.warn "Error reading snippets file '#{snippetsPath}'"
|
||||
self.postMessage
|
||||
type: 'loadSnippets'
|
||||
snippets: snippets
|
||||
@snippetsLoaded(snippets)
|
||||
|
||||
snippetsLoaded: (snippets) -> callTaskMethod('snippetsLoaded', snippets)
|
||||
42
src/packages/snippets/src/load-snippets-task.coffee
Normal file
42
src/packages/snippets/src/load-snippets-task.coffee
Normal file
@@ -0,0 +1,42 @@
|
||||
Task = require 'Task'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
module.exports =
|
||||
class LoadSnippetsTask extends Task
|
||||
constructor: (@snippets) ->
|
||||
super('snippets/src/load-snippets-handler')
|
||||
@packages = atom.getPackages()
|
||||
@packages.push(path: config.configDirPath)
|
||||
|
||||
started: ->
|
||||
@loadNextPackageSnippets()
|
||||
|
||||
loadNextPackageSnippets: ->
|
||||
unless @packages.length
|
||||
@snippets.loaded = true
|
||||
return
|
||||
|
||||
@packageBeingLoaded = @packages.shift()
|
||||
if @packageBeingLoaded instanceof TextMatePackage
|
||||
method = 'loadTextmateSnippets'
|
||||
else
|
||||
method = 'loadAtomSnippets'
|
||||
@callWorkerMethod(method, @packageBeingLoaded.path)
|
||||
|
||||
snippetsLoaded: (snippets) ->
|
||||
if @packageBeingLoaded instanceof TextMatePackage
|
||||
snippets = @translateTextmateSnippets(snippets)
|
||||
@snippets.add(snippet) for snippet in snippets
|
||||
@loadNextPackageSnippets()
|
||||
|
||||
translateTextmateSnippets: (tmSnippets) ->
|
||||
atomSnippets = {}
|
||||
for { scope, name, content, tabTrigger } in tmSnippets
|
||||
if scope
|
||||
scope = TextMatePackage.cssSelectorFromScopeSelector(scope)
|
||||
else
|
||||
scope = '*'
|
||||
|
||||
snippetsForScope = (atomSnippets[scope] ?= {})
|
||||
snippetsForScope[name] = { prefix: tabTrigger, body: content }
|
||||
[atomSnippets]
|
||||
@@ -1,42 +0,0 @@
|
||||
Task = require 'task'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
module.exports =
|
||||
class SnippetsTask extends Task
|
||||
|
||||
constructor: (@snippets) ->
|
||||
super('snippets/src/snippets-reader')
|
||||
|
||||
@packages = atom.getPackages()
|
||||
@packages.push(path: config.configDirPath)
|
||||
|
||||
onProgress: (event) =>
|
||||
if event.data.type is 'loadSnippets'
|
||||
rawSnippets = event.data.snippets
|
||||
if @package instanceof TextMatePackage
|
||||
@snippets.add(@translateTextmateSnippets(rawSnippets))
|
||||
else
|
||||
@snippets.add(snippet) for snippet in rawSnippets
|
||||
|
||||
@package = @packages.shift()
|
||||
if not @package?
|
||||
@snippets.loaded = true
|
||||
return
|
||||
|
||||
if @package instanceof TextMatePackage
|
||||
eventType = 'loadTextmateSnippets'
|
||||
else
|
||||
eventType = 'loadAtomSnippets'
|
||||
{ type: eventType, path: @package.path }
|
||||
|
||||
translateTextmateSnippets: (tmSnippets) ->
|
||||
atomSnippets = {}
|
||||
for { scope, name, content, tabTrigger } in tmSnippets
|
||||
if scope
|
||||
scope = TextMatePackage.cssSelectorFromScopeSelector(scope)
|
||||
else
|
||||
scope = '*'
|
||||
|
||||
snippetsForScope = (atomSnippets[scope] ?= {})
|
||||
snippetsForScope[name] = { prefix: tabTrigger, body: content }
|
||||
atomSnippets
|
||||
@@ -1,21 +1,29 @@
|
||||
# This file is loaded within Task's worker thread. 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 = ->
|
||||
self.console =
|
||||
warn: ->
|
||||
self.postMessage
|
||||
type: 'warn'
|
||||
details: arguments
|
||||
log: ->
|
||||
self.postMessage
|
||||
type: 'log'
|
||||
details: arguments
|
||||
warn: -> callTaskMethod 'warn', arguments...
|
||||
log: -> callTaskMethod 'log', arguments...
|
||||
error: -> callTaskMethod 'error', arguments...
|
||||
|
||||
self.addEventListener 'message', (event) ->
|
||||
switch event.data.type
|
||||
when 'start'
|
||||
window.resourcePath = event.data.resourcePath
|
||||
importScripts(event.data.requirePath)
|
||||
self.task = require(event.data.taskPath)
|
||||
self.postMessage(type:'started')
|
||||
else
|
||||
self.task[event.data.type](event.data)
|
||||
# `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)
|
||||
|
||||
# The worker's initial handler replaces itself when `start` is invoked
|
||||
self.handler =
|
||||
start: ({resourcePath, requirePath, handlerPath}) ->
|
||||
window.resourcePath = resourcePath
|
||||
importScripts(requirePath)
|
||||
self.handler = require(handlerPath)
|
||||
callTaskMethod 'started'
|
||||
|
||||
self.addEventListener 'message', ({data}) ->
|
||||
handler[data.method]?(data.args...) if data.method
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
module.exports =
|
||||
class Task
|
||||
|
||||
constructor: (@path) ->
|
||||
|
||||
onProgress: (event) ->
|
||||
|
||||
start: ->
|
||||
worker = new Worker(require.getPath('task-shell'))
|
||||
worker.onmessage = (event) =>
|
||||
switch event.data.type
|
||||
when 'warn'
|
||||
console.warn(event.data.details...)
|
||||
return
|
||||
when 'log'
|
||||
console.log(event.data.details...)
|
||||
return
|
||||
@worker = new Worker(require.getPath('task-shell'))
|
||||
@worker.onmessage = ({data}) =>
|
||||
if data.method and this[data.method]
|
||||
this[data.method](data.args...)
|
||||
else
|
||||
@onMessage(data)
|
||||
@startWorker()
|
||||
|
||||
reply = @onProgress(event)
|
||||
worker.postMessage(reply) if reply
|
||||
log: -> console.log(arguments...)
|
||||
warn: -> console.warn(arguments...)
|
||||
error: -> console.error(arguments...)
|
||||
|
||||
worker.postMessage
|
||||
type: 'start'
|
||||
startWorker: ->
|
||||
@callWorkerMethod 'start'
|
||||
resourcePath: window.resourcePath
|
||||
requirePath: require.getPath('require')
|
||||
taskPath: @path
|
||||
handlerPath: @path
|
||||
|
||||
started: ->
|
||||
|
||||
onMessage: (message) ->
|
||||
|
||||
callWorkerMethod: (method, args...) ->
|
||||
@postMessage({method, args})
|
||||
|
||||
postMessage: (data) ->
|
||||
@worker.postMessage(data)
|
||||
|
||||
Reference in New Issue
Block a user