diff --git a/src/packages/snippets/index.coffee b/src/packages/snippets/index.coffee index e7e01c99a..20502b22f 100644 --- a/src/packages/snippets/index.coffee +++ b/src/packages/snippets/index.coffee @@ -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 diff --git a/src/packages/snippets/spec/snippets-spec.coffee b/src/packages/snippets/spec/snippets-spec.coffee index f5686d669..57dea1a42 100644 --- a/src/packages/snippets/spec/snippets-spec.coffee +++ b/src/packages/snippets/spec/snippets-spec.coffee @@ -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() diff --git a/src/packages/snippets/src/snippets-reader.coffee b/src/packages/snippets/src/load-snippets-handler.coffee similarity index 64% rename from src/packages/snippets/src/snippets-reader.coffee rename to src/packages/snippets/src/load-snippets-handler.coffee index 83ee59aa3..94bbdec92 100644 --- a/src/packages/snippets/src/snippets-reader.coffee +++ b/src/packages/snippets/src/load-snippets-handler.coffee @@ -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) diff --git a/src/packages/snippets/src/load-snippets-task.coffee b/src/packages/snippets/src/load-snippets-task.coffee new file mode 100644 index 000000000..459acc40f --- /dev/null +++ b/src/packages/snippets/src/load-snippets-task.coffee @@ -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] diff --git a/src/packages/snippets/src/snippets-task.coffee b/src/packages/snippets/src/snippets-task.coffee deleted file mode 100644 index 0b1ae00e3..000000000 --- a/src/packages/snippets/src/snippets-task.coffee +++ /dev/null @@ -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 diff --git a/src/stdlib/task-shell.coffee b/src/stdlib/task-shell.coffee index 5aa610d67..ea7f84ecf 100644 --- a/src/stdlib/task-shell.coffee +++ b/src/stdlib/task-shell.coffee @@ -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 diff --git a/src/stdlib/task.coffee b/src/stdlib/task.coffee index c393fb1b2..3a2f981f4 100644 --- a/src/stdlib/task.coffee +++ b/src/stdlib/task.coffee @@ -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)