diff --git a/spec/extensions/snippets-spec.coffee b/spec/extensions/snippets-spec.coffee index 499d88b95..83aed2ac6 100644 --- a/spec/extensions/snippets-spec.coffee +++ b/spec/extensions/snippets-spec.coffee @@ -85,3 +85,19 @@ describe "Snippets extension", -> expect(snippet.prefix).toBe 't2' expect(snippet.description).toBe "Test snippet 2" expect(snippet.body).toBe "this is a test 2" + + it "can parse snippets with tabstops", -> + snippets = Snippets.snippetsParser.parse """ + # this line intentially left blank. + snippet t1 "Test snippet 1" + then go back to here: ($2) + first go here: ($1) + endsnippet + """ + + snippet = snippets['t1'] + expect(snippet.body).toBe """ + then go back to here: () + first go here: () + """ + expect(snippet.tabStops).toEqual [[1, 16], [0, 23]] diff --git a/src/extensions/snippets/snippet.coffee b/src/extensions/snippets/snippet.coffee new file mode 100644 index 000000000..9e938dfd3 --- /dev/null +++ b/src/extensions/snippets/snippet.coffee @@ -0,0 +1,21 @@ +_ = require 'underscore' + +module.exports = +class Snippet + constructor: ({@bodyPosition, @prefix, @description, body}) -> + @body = @extractTabStops(body) + + extractTabStops: (body) -> + tabStopsByIndex = {} + bodyText = [] + for element in body + if element.index + tabStopsByIndex[element.index] = element.position.subtract(@bodyPosition) + else + bodyText.push(element) + + @tabStops = [] + for index in _.keys(tabStopsByIndex).sort() + @tabStops.push tabStopsByIndex[index] + + bodyText.join('') diff --git a/src/extensions/snippets/snippets.coffee b/src/extensions/snippets/snippets.coffee index d69a8c00d..c39e2b7be 100644 --- a/src/extensions/snippets/snippets.coffee +++ b/src/extensions/snippets/snippets.coffee @@ -5,7 +5,7 @@ _ = require 'underscore' module.exports = name: 'Snippets' snippetsByExtension: {} - snippetsParser: PEG.buildParser(fs.read(require.resolve 'extensions/snippets/snippets.pegjs')) + snippetsParser: PEG.buildParser(fs.read(require.resolve 'extensions/snippets/snippets.pegjs'), trackLineAndColumn: true) activate: (@rootView) -> @loadSnippets() diff --git a/src/extensions/snippets/snippets.pegjs b/src/extensions/snippets/snippets.pegjs index f53683544..f615c134c 100644 --- a/src/extensions/snippets/snippets.pegjs +++ b/src/extensions/snippets/snippets.pegjs @@ -1,3 +1,8 @@ +{ + var Snippet = require('extensions/snippets/snippet'); + var Point = require('point'); +} + snippets = snippets:snippet+ ws? { var snippetsByPrefix = {}; snippets.forEach(function(snippet) { @@ -6,17 +11,21 @@ snippets = snippets:snippet+ ws? { return snippetsByPrefix; } -snippet = ws? start ws prefix:prefix ws description:string separator body:body end { - return { prefix: prefix, description: description, body: body }; +snippet = ws? start ws prefix:prefix ws description:string bodyPosition:beforeBody body:body end { + return new Snippet({ bodyPosition: bodyPosition, prefix: prefix, description: description, body: body }); } -separator = [ ]* '\n' start = 'snippet' prefix = prefix:[A-Za-z0-9_]+ { return prefix.join(''); } -body = body:bodyCharacter* { return body.join(''); } -bodyCharacter = !end char:. { return char; } +string = ['] body:[^']* ['] { return body.join(''); } + / ["] body:[^"]* ["] { return body.join(''); } +beforeBody = [ ]* '\n' { return new Point(line, 0); } // return start position of body: body begins on next line, so don't subtract 1 from line + +body = (tabStop / bodyText)* +bodyText = body:bodyCharacter+ { return body.join(''); } +bodyCharacter = !(end / tabStop) char:. { return char; } +tabStop = '$' index:[0-9]+ { return { index: index, position: new Point(line - 1, column - 1) }; } + end = '\nendsnippet' -string - = ['] body:[^']* ['] { return body.join(''); } - / ["] body:[^"]* ["] { return body.join(''); } -ws = [ \n]+ +ws = ([ \n] / comment)+ +comment = '#' [^\n]*