mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-12 22:50:54 +03:00
Load snippets from CSON/JSON. Use syntax
properties for scoping.
This commit eliminates the custom `snippets` format and instead just uses CSON/JSON.
This commit is contained in:
parent
2d4c4b3930
commit
361bf83345
34
.atom/snippets/coffee.cson
Normal file
34
.atom/snippets/coffee.cson
Normal file
@ -0,0 +1,34 @@
|
||||
".source.coffee":
|
||||
"Describe block":
|
||||
prefix: "de"
|
||||
body: """
|
||||
describe "${1:description}", ->
|
||||
${2:body}
|
||||
"""
|
||||
"It block":
|
||||
prefix: "i"
|
||||
body: """
|
||||
it "$1", ->
|
||||
$2
|
||||
"""
|
||||
"Before each":
|
||||
prefix: "be"
|
||||
body: """
|
||||
beforeEach ->
|
||||
$1
|
||||
"""
|
||||
"Expectation":
|
||||
prefix: "be"
|
||||
body: "expect($1).to$2"
|
||||
"Console log":
|
||||
prefix: "log"
|
||||
body: "console.log $1"
|
||||
"Range array":
|
||||
prefix: "ra"
|
||||
body: "[[$1, $2], [$3, $4]]"
|
||||
"Point array":
|
||||
prefix: "pt"
|
||||
body: "[$1, $2]"
|
||||
"Create Jasmine spy":
|
||||
prefix: "pt"
|
||||
body: 'jasmine.createSpy("${1:description}")$2'
|
@ -1,34 +0,0 @@
|
||||
snippet de "Describe block"
|
||||
describe "${1:description}", ->
|
||||
${2:body}
|
||||
endsnippet
|
||||
|
||||
snippet i "It block"
|
||||
it "$1", ->
|
||||
$2
|
||||
endsnippet
|
||||
|
||||
snippet be "Before each"
|
||||
beforeEach ->
|
||||
$1
|
||||
endsnippet
|
||||
|
||||
snippet ex "Expectation"
|
||||
expect($1).to$2
|
||||
endsnippet
|
||||
|
||||
snippet log "Console log"
|
||||
console.log $1
|
||||
endsnippet
|
||||
|
||||
snippet ra "Range array"
|
||||
[[$1, $2], [$3, $4]]
|
||||
endsnippet
|
||||
|
||||
snippet pt "Point array"
|
||||
[$1, $2]
|
||||
endsnippet
|
||||
|
||||
snippet spy "Jasmine spy"
|
||||
jasmine.createSpy("${1:description}")$2
|
||||
endsnippet
|
@ -1,31 +1,10 @@
|
||||
{
|
||||
var Snippet = require('snippets/src/snippet');
|
||||
var Point = require('point');
|
||||
body = leadingLines:bodyLineWithNewline* lastLine:bodyLine? {
|
||||
return lastLine ? leadingLines.concat([lastLine]) : leadingLines;
|
||||
}
|
||||
|
||||
snippets = snippets:snippet+ ws? {
|
||||
var snippetsByPrefix = {};
|
||||
snippets.forEach(function(snippet) {
|
||||
snippetsByPrefix[snippet.prefix] = snippet
|
||||
});
|
||||
return snippetsByPrefix;
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
start = 'snippet'
|
||||
prefix = prefix:[A-Za-z0-9_]+ { return prefix.join(''); }
|
||||
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 = bodyLine+
|
||||
bodyLine = content:(tabStop / bodyText)* '\n' { return content; }
|
||||
bodyLineWithNewline = bodyLine:bodyLine '\n' { return bodyLine; }
|
||||
bodyLine = content:(tabStop / bodyText)* { return content; }
|
||||
bodyText = text:bodyChar+ { return text.join(''); }
|
||||
bodyChar = !(end / tabStop) char:[^\n] { return char; }
|
||||
bodyChar = !(tabStop) char:[^\n] { return char; }
|
||||
tabStop = simpleTabStop / tabStopWithPlaceholder
|
||||
simpleTabStop = '$' index:[0-9]+ {
|
||||
return { index: parseInt(index), placeholderText: '' };
|
||||
@ -33,7 +12,3 @@ simpleTabStop = '$' index:[0-9]+ {
|
||||
tabStopWithPlaceholder = '${' index:[0-9]+ ':' placeholderText:[^}]* '}' {
|
||||
return { index: parseInt(index), placeholderText: placeholderText.join('') };
|
||||
}
|
||||
|
||||
end = 'endsnippet'
|
||||
ws = ([ \n] / comment)+
|
||||
comment = '#' [^\n]*
|
||||
|
@ -17,36 +17,45 @@ describe "Snippets extension", ->
|
||||
|
||||
afterEach ->
|
||||
rootView.remove()
|
||||
delete window.snippets
|
||||
|
||||
describe "when 'tab' is triggered on the editor", ->
|
||||
beforeEach ->
|
||||
Snippets.evalSnippets 'js', """
|
||||
snippet t1 "Snippet without tab stops"
|
||||
this is a test
|
||||
endsnippet
|
||||
snippets.add
|
||||
".source.js":
|
||||
"without tab stops":
|
||||
prefix: "t1"
|
||||
body: "this is a test"
|
||||
|
||||
snippet t2 "With tab stops"
|
||||
go here next:($2) and finally go here:($3)
|
||||
go here first:($1)
|
||||
"tab stops":
|
||||
prefix: "t2"
|
||||
body: """
|
||||
go here next:($2) and finally go here:($3)
|
||||
go here first:($1)
|
||||
|
||||
endsnippet
|
||||
"""
|
||||
|
||||
snippet t3 "With indented second line"
|
||||
line 1
|
||||
line 2$1
|
||||
"indented second line":
|
||||
prefix: "t3"
|
||||
body: """
|
||||
line 1
|
||||
line 2$1
|
||||
|
||||
endsnippet
|
||||
"""
|
||||
|
||||
snippet t4 "With tab stop placeholders"
|
||||
go here ${1:first} and then here ${2:second}
|
||||
"tab stop placeholders":
|
||||
prefix: "t4"
|
||||
body: """
|
||||
go here ${1:first} and then here ${2:second}
|
||||
|
||||
endsnippet
|
||||
"""
|
||||
|
||||
snippet t5 "Caused problems with undo"
|
||||
first line$1
|
||||
${2:placeholder ending second line}
|
||||
endsnippet
|
||||
"""
|
||||
"caused problems with undo":
|
||||
prefix: "t5"
|
||||
body: """
|
||||
first line$1
|
||||
${2:placeholder ending second line}
|
||||
"""
|
||||
|
||||
describe "when the letters preceding the cursor trigger a snippet", ->
|
||||
describe "when the snippet contains no tab stops", ->
|
||||
@ -188,56 +197,20 @@ describe "Snippets extension", ->
|
||||
anotherEditor.trigger keydownEvent('tab', target: anotherEditor[0])
|
||||
expect(anotherEditor.getSelectedBufferRange()).toEqual [[1, 6], [1, 36]]
|
||||
|
||||
describe ".loadSnippetsFile(path)", ->
|
||||
it "loads the snippets in the given file", ->
|
||||
spyOn(fs, 'read').andReturn """
|
||||
snippet t1 "Test snippet 1"
|
||||
this is a test 1
|
||||
endsnippet
|
||||
"""
|
||||
|
||||
Snippets.loadSnippetsFile('/tmp/foo/js.snippets')
|
||||
expect(fs.read).toHaveBeenCalledWith('/tmp/foo/js.snippets')
|
||||
|
||||
editor.insertText("t1")
|
||||
editor.trigger 'snippets:expand'
|
||||
expect(buffer.lineForRow(0)).toBe "this is a test 1var quicksort = function () {"
|
||||
|
||||
describe "Snippets parser", ->
|
||||
it "can parse multiple snippets", ->
|
||||
snippets = Snippets.snippetsParser.parse """
|
||||
snippet t1 "Test snippet 1"
|
||||
this is a test 1
|
||||
endsnippet
|
||||
|
||||
snippet t2 "Test snippet 2"
|
||||
this is a test 2
|
||||
endsnippet
|
||||
"""
|
||||
expect(_.keys(snippets).length).toBe 2
|
||||
snippet = snippets['t1']
|
||||
expect(snippet.prefix).toBe 't1'
|
||||
expect(snippet.description).toBe "Test snippet 1"
|
||||
expect(snippet.body).toBe "this is a test 1"
|
||||
|
||||
snippet = snippets['t2']
|
||||
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 "Snippet with tab stops"
|
||||
go here next:($2) and finally go here:($3)
|
||||
it "breaks a snippet body into lines, with each line containing tab stops at the appropriate position", ->
|
||||
bodyTree = Snippets.parser.parse """
|
||||
go here next:($2) and finally go here:(${3:here!})
|
||||
go here first:($1)
|
||||
endsnippet
|
||||
"""
|
||||
|
||||
snippet = snippets['t1']
|
||||
expect(snippet.body).toBe """
|
||||
go here next:() and finally go here:()
|
||||
go here first:()
|
||||
"""
|
||||
|
||||
expect(snippet.tabStops).toEqual [[[1, 15], [1, 15]], [[0, 14], [0, 14]], [[0, 37], [0, 37]]]
|
||||
expect(bodyTree).toEqual [
|
||||
[
|
||||
"go here next:(",
|
||||
{ index: 2, placeholderText: "" },
|
||||
") and finally go here:(",
|
||||
{ index: 3, placeholderText: "here!" },
|
||||
")",
|
||||
],
|
||||
[ "go here first:(", { index: 1, placeholderText: "" }, ")"]
|
||||
]
|
||||
|
@ -3,19 +3,21 @@ Range = require 'range'
|
||||
|
||||
module.exports =
|
||||
class Snippet
|
||||
name: null
|
||||
prefix: null
|
||||
body: null
|
||||
lineCount: null
|
||||
tabStops: null
|
||||
|
||||
constructor: ({@bodyPosition, @prefix, @description, body}) ->
|
||||
@body = @extractTabStops(body)
|
||||
constructor: ({@name, @prefix, bodyTree}) ->
|
||||
@body = @extractTabStops(bodyTree)
|
||||
|
||||
extractTabStops: (bodyLines) ->
|
||||
extractTabStops: (bodyTree) ->
|
||||
tabStopsByIndex = {}
|
||||
bodyText = []
|
||||
|
||||
[row, column] = [0, 0]
|
||||
for bodyLine, i in bodyLines
|
||||
for bodyLine, i in bodyTree
|
||||
lineText = []
|
||||
for segment in bodyLine
|
||||
if segment.index
|
||||
|
@ -2,32 +2,41 @@ fs = require 'fs'
|
||||
PEG = require 'pegjs'
|
||||
_ = require 'underscore'
|
||||
SnippetExpansion = require 'snippets/src/snippet-expansion'
|
||||
Snippet = require './snippet'
|
||||
|
||||
module.exports =
|
||||
name: 'Snippets'
|
||||
snippetsByExtension: {}
|
||||
snippetsParser: PEG.buildParser(fs.read(require.resolve 'snippets/snippets.pegjs'), trackLineAndColumn: true)
|
||||
parser: PEG.buildParser(fs.read(require.resolve 'snippets/snippets.pegjs'), trackLineAndColumn: true)
|
||||
userSnippetsDir: fs.join(config.configDirPath, 'snippets')
|
||||
|
||||
activate: (@rootView) ->
|
||||
@loadSnippets()
|
||||
window.snippets = this
|
||||
@loadAll()
|
||||
@rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)
|
||||
|
||||
loadSnippets: ->
|
||||
snippetsDir = fs.join(config.configDirPath, 'snippets')
|
||||
if fs.exists(snippetsDir)
|
||||
@loadSnippetsFile(path) for path in fs.list(snippetsDir) when fs.extension(path) == '.snippets'
|
||||
loadAll: ->
|
||||
for snippetsPath in fs.list(@userSnippetsDir)
|
||||
@load(snippetsPath)
|
||||
|
||||
loadSnippetsFile: (path) ->
|
||||
@evalSnippets(fs.base(path, '.snippets'), fs.read(path))
|
||||
load: (snippetsPath) ->
|
||||
@add(fs.readObject(snippetsPath))
|
||||
|
||||
add: (snippetsBySelector) ->
|
||||
for selector, snippetsByName of snippetsBySelector
|
||||
snippetsByPrefix = {}
|
||||
for name, attributes of snippetsByName
|
||||
{ prefix, body } = attributes
|
||||
bodyTree = @parser.parse(body)
|
||||
snippet = new Snippet({name, prefix, bodyTree})
|
||||
snippetsByPrefix[snippet.prefix] = snippet
|
||||
syntax.addProperties(selector, snippets: snippetsByPrefix)
|
||||
|
||||
evalSnippets: (extension, text) ->
|
||||
@snippetsByExtension[extension] = @snippetsParser.parse(text)
|
||||
|
||||
enableSnippetsInEditor: (editor) ->
|
||||
editor.command 'snippets:expand', (e) =>
|
||||
editSession = editor.activeEditSession
|
||||
prefix = editSession.getLastCursor().getCurrentWordPrefix()
|
||||
if snippet = @snippetsByExtension[editSession.getFileExtension()]?[prefix]
|
||||
if snippet = syntax.getProperty(editSession.getCursorScopes(), "snippets.#{prefix}")
|
||||
editSession.transact ->
|
||||
snippetExpansion = new SnippetExpansion(snippet, editSession)
|
||||
editSession.snippetExpansion = snippetExpansion
|
||||
|
Loading…
Reference in New Issue
Block a user