Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit 8f022fc

Browse files
committed
Add variable support
1 parent bd5700b commit 8f022fc

File tree

5 files changed

+93
-24
lines changed

5 files changed

+93
-24
lines changed

lib/snippet-expansion.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,27 @@ module.exports = class SnippetExpansion {
1414
this.selections = [this.cursor.selection]
1515

1616
const startPosition = this.cursor.selection.getBufferRange().start
17-
let {body, tabStopList} = this.snippet
18-
let tabStops = tabStopList.toArray()
17+
let {body, tabStopList} = this.snippet.toString()
18+
19+
this.tabStopList = tabStopList
20+
21+
let tabStops = this.tabStopList.toArray()
1922

2023
let indent = this.editor.lineTextForBufferRow(startPosition.row).match(/^\s*/)[0]
2124
if (this.snippet.lineCount > 1 && indent) {
2225
// Add proper leading indentation to the snippet
2326
body = body.replace(/\n/g, `\n${indent}`)
2427

28+
// TODO: Remove concept of "body"; build on the fly each time to resolve variables and their transformations
29+
2530
tabStops = tabStops.map(tabStop => tabStop.copyWithIndent(indent))
2631
}
2732

2833
this.editor.transact(() => {
2934
this.ignoringBufferChanges(() => {
3035
this.editor.transact(() => {
3136
const newRange = this.cursor.selection.insertText(body, {autoIndent: false})
32-
if (this.snippet.tabStopList.length > 0) {
37+
if (this.tabStopList.length > 0) {
3338
this.subscriptions.add(this.cursor.onDidChangePosition(event => this.cursorMoved(event)))
3439
this.subscriptions.add(this.cursor.onDidDestroy(() => this.cursorDestroyed()))
3540
this.placeTabStopMarkers(startPosition, tabStops)
@@ -152,7 +157,7 @@ module.exports = class SnippetExpansion {
152157
} else {
153158
// The user has tabbed past the last tab stop. If the last tab stop is a
154159
// $0, we shouldn't move the cursor any further.
155-
if (this.snippet.tabStopList.hasEndStop) {
160+
if (this.tabStopList.hasEndStop) { foo
156161
this.destroy()
157162
return false
158163
} else {

lib/snippet.js

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,81 @@
11
const {Range} = require('atom')
22
const TabStopList = require('./tab-stop-list')
33

4+
5+
/*
6+
7+
1. Snippet stores the parsed snippet template
8+
9+
2. Template variables are resolved on demand
10+
11+
3. Followed by insertion
12+
13+
*/
14+
415
module.exports = class Snippet {
5-
constructor({name, prefix, bodyText, description, descriptionMoreURL, rightLabelHTML, leftLabel, leftLabelHTML, bodyTree}) {
16+
constructor({name, prefix, description, descriptionMoreURL, rightLabelHTML, leftLabel, leftLabelHTML, bodyTree, variableResolver}) {
617
this.name = name
718
this.prefix = prefix
8-
this.bodyText = bodyText
919
this.description = description
1020
this.descriptionMoreURL = descriptionMoreURL
1121
this.rightLabelHTML = rightLabelHTML
1222
this.leftLabel = leftLabel
1323
this.leftLabelHTML = leftLabelHTML
14-
this.tabStopList = new TabStopList(this)
15-
this.body = this.extractTabStops(bodyTree)
24+
this.bodyTree = bodyTree
25+
this.variableResolver = variableResolver
1626
}
1727

18-
extractTabStops (bodyTree) {
28+
toString () {
29+
const tabStopList = new TabStopList(this)
1930
const bodyText = []
2031
let row = 0
2132
let column = 0
2233

2334
// recursive helper function; mutates vars above
2435
let extractTabStops = bodyTree => {
25-
for (const segment of bodyTree) {
36+
for (let segment of bodyTree) {
2637
if (segment.index != null) {
2738
let {index, content, substitution} = segment
2839
if (index === 0) { index = Infinity; }
2940
const start = [row, column]
3041
extractTabStops(content)
3142
const range = new Range(start, [row, column])
32-
const tabStop = this.tabStopList.findOrCreate({
43+
const tabStop = tabStopList.findOrCreate({
3344
index,
3445
snippet: this
3546
})
3647
tabStop.addInsertion({ range, substitution })
37-
} else if (typeof segment === 'string') {
38-
bodyText.push(segment)
39-
var segmentLines = segment.split('\n')
40-
column += segmentLines.shift().length
41-
let nextLine
42-
while ((nextLine = segmentLines.shift()) != null) {
43-
row += 1
44-
column = nextLine.length
48+
} else {
49+
if (segment.variable != undefined) {
50+
debugger
51+
const value = this.variableResolver.resolve({ name: segment.variable })
52+
if (value === undefined) {
53+
if (segment.content) {
54+
extractTabStops(segment.content)
55+
}
56+
} else {
57+
segment = value
58+
}
59+
}
60+
61+
if (typeof segment === 'string') {
62+
bodyText.push(segment)
63+
var segmentLines = segment.split('\n')
64+
column += segmentLines.shift().length
65+
let nextLine
66+
while ((nextLine = segmentLines.shift()) != null) {
67+
row += 1
68+
column = nextLine.length
69+
}
4570
}
4671
}
4772
}
4873
}
4974

50-
extractTabStops(bodyTree)
75+
extractTabStops(this.bodyTree)
5176
this.lineCount = row + 1
52-
this.insertions = this.tabStopList.getInsertions()
77+
this.insertions = tabStopList.getInsertions()
5378

54-
return bodyText.join('')
79+
return { body: bodyText.join(''), tabStopList }
5580
}
5681
}

lib/snippets.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const ScopedPropertyStore = require('scoped-property-store')
99
const Snippet = require('./snippet')
1010
const SnippetExpansion = require('./snippet-expansion')
1111
const EditorStore = require('./editor-store')
12+
const VariableResolver = require('./variable-resolver')
1213
const {getPackageRoot} = require('./helpers')
1314

1415
module.exports = {
@@ -19,6 +20,7 @@ module.exports = {
1920
this.snippetsByPackage = new Map
2021
this.parsedSnippetsById = new Map
2122
this.editorMarkerLayers = new WeakMap
23+
this.variableResolver = new VariableResolver
2224

2325
this.scopedPropertyStore = new ScopedPropertyStore
2426
// The above ScopedPropertyStore will store the main registry of snippets.
@@ -418,7 +420,7 @@ module.exports = {
418420
if (snippet == null) {
419421
let {id, prefix, name, body, bodyTree, description, descriptionMoreURL, rightLabelHTML, leftLabel, leftLabelHTML} = attributes
420422
if (bodyTree == null) { bodyTree = this.getBodyParser().parse(body) }
421-
snippet = new Snippet({id, name, prefix, bodyTree, description, descriptionMoreURL, rightLabelHTML, leftLabel, leftLabelHTML, bodyText: body})
423+
snippet = new Snippet({id, name, prefix, bodyTree, description, descriptionMoreURL, rightLabelHTML, leftLabel, leftLabelHTML, bodyText: body, variableResolver: this.variableResolver})
422424
this.parsedSnippetsById.set(attributes.id, snippet)
423425
}
424426
return snippet
@@ -624,7 +626,7 @@ module.exports = {
624626
if (cursor == null) { cursor = editor.getLastCursor() }
625627
if (typeof snippet === 'string') {
626628
const bodyTree = this.getBodyParser().parse(snippet)
627-
snippet = new Snippet({name: '__anonymous', prefix: '', bodyTree, bodyText: snippet})
629+
snippet = new Snippet({name: '__anonymous', prefix: '', bodyTree, bodyText: snippet, variableResolver: this.variableResolver})
628630
}
629631
return new SnippetExpansion(snippet, editor, cursor, this)
630632
},
@@ -662,5 +664,9 @@ module.exports = {
662664
onUndoOrRedo (editor, isUndo) {
663665
const activeExpansions = this.getExpansions(editor)
664666
activeExpansions.forEach(expansion => expansion.onUndoOrRedo(isUndo))
667+
},
668+
669+
provideVariableResolver (resolver) {
670+
this.variableResolver.add(resolver)
665671
}
666672
}

lib/variable-resolver.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module.exports = class VariableResolver {
2+
constructor (resolvers = new Map) {
3+
this.resolvers = new Map([
4+
["CLIPBOARD", resolveClipboard],
5+
...resolvers
6+
])
7+
}
8+
9+
add (variable, resolver) {
10+
this.resolvers.set(variable, resolver)
11+
}
12+
13+
resolve (params) {
14+
15+
const resolver = this.resolvers.get(params.name)
16+
17+
if (resolver) {
18+
return resolver(params)
19+
}
20+
21+
return undefined
22+
}
23+
}
24+
25+
function resolveClipboard () {
26+
return atom.clipboard.read()
27+
}

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
"versions": {
2626
"0.1.0": "provideSnippets"
2727
}
28+
},
29+
"snippetsVariableResolver": {
30+
"description": "Provide custom functions to resolve snippet variables.",
31+
"versions": {
32+
"0.0.0": "provideVariableResolver"
33+
}
2834
}
2935
},
3036
"devDependencies": {

0 commit comments

Comments
 (0)