Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

Commit

Permalink
Update To autocomplete+ API v2, Emit Snippets
Browse files Browse the repository at this point in the history
- Partially based on #114
- Need to fix tests
- Switched approach for matching to regex, will allow for us emitting function results also
  • Loading branch information
joefitzgerald committed Mar 10, 2015
1 parent a486f65 commit 106746a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 30 deletions.
2 changes: 1 addition & 1 deletion lib/go-plus.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ module.exports =
return @provider

provide: ->
return {providers: [@getProvider()]}
return @getProvider()
66 changes: 50 additions & 16 deletions lib/gocodeprovider.coffee
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
{Range} = require('atom')
_ = require('underscore-plus')
path = require('path')

module.exports =
class GocodeProvider
id: 'go-plus-gocodeprovider'
selector: '.source.go'
inclusionPriority: 1
excludeLowerPriority: true

constructor: ->
@blacklist = atom.config.get('go-plus.autocompleteBlacklist')
if atom.config.get('go-plus.suppressBuiltinAutocompleteProvider')
@providerblacklist =
'autocomplete-plus-fuzzyprovider': '.source.go'
@disableForSelector = atom.config.get('go-plus.autocompleteBlacklist')

setDispatch: (dispatch) ->
@dispatch = dispatch
@funcRegex = /^(?:func[(]{1})([^\)]*)(?:[)]{1})(?:$|(?:\s)([^\(]*$)|(?: [(]{1})([^\)]*)(?:[)]{1}))/i

requestHandler: (options) ->
getSuggestions: (options) ->
return new Promise((resolve) =>
return resolve() unless options?
return resolve() unless @dispatch?.isValidEditor(options.editor)
return resolve() unless options.buffer?
buffer = options.editor.getBuffer()
return resolve() unless buffer?

go = @dispatch.goexecutable.current()
return resolve() unless go?
gopath = go.buildgopath()
return resolve() if not gopath? or gopath is ''

return resolve() unless options.position
index = options.buffer.characterIndexForPosition(options.position)
return resolve() unless options.bufferPosition
index = buffer.characterIndexForPosition(options.bufferPosition)
offset = 'c' + index.toString()
text = options.editor.getText()
return resolve() if text[index - 1] is ')' or text[index - 1] is ';'
quotedRange = options.editor.displayBuffer.bufferRangeForScopeAtPosition('.string.quoted', options.position)
quotedRange = options.editor.displayBuffer.bufferRangeForScopeAtPosition('.string.quoted', options.bufferPosition)
return resolve() if quotedRange

env = @dispatch.env()
env['GOPATH'] = gopath
cwd = path.dirname(options.buffer.getPath())
args = ['-f=json', 'autocomplete', options.buffer.getPath(), offset]
cwd = path.dirname(buffer.getPath())
args = ['-f=json', 'autocomplete', buffer.getPath(), offset]
configArgs = @dispatch.splicersplitter.splitAndSquashToArray(' ', atom.config.get('go-plus.gocodeArgs'))
args = _.union(configArgs, args) if configArgs? and _.size(configArgs) > 0
cmd = go.gocode()
Expand Down Expand Up @@ -72,13 +73,46 @@ class GocodeProvider
suggestions = []
for c in candidates
suggestion =
prefix: c.name.substring(0, numPrefix)
word: c.name
label: c.type or c.class
suggestion.word += '(' if c.class is 'func' and text[index] isnt '('
replacementPrefix: c.name.substring(0, numPrefix)
rightLabel: c.type or c.class
type: c.class
if c.class is 'func'
suggestion.snippet = c.name + @generateSignature(c.type)
suggestion.rightLabel = c.class
else
suggestion.text = c.name
suggestions.push(suggestion)

return suggestions

generateSignature: (type) ->
signature = ""
skipBlank = false
parenCounter = 0
paramCount = 1
scanned = false
match = @funcRegex.exec(type)
return '()' unless match? and match[0]? # Not a function
return '()' unless match[1]? and match[1] isnt '' # Has no arguments, shouldn't be a snippet, for now
args = match[1].split(/, /)
args = _.map args, (a) ->
return a unless a?.length > 2
if a.substring(a.length - 2, a.length) is '{}'
return a.substring(0, a.length - 2)
return a

return '(${0:' + args[0] + '})' if args.length is 1
i = 0
for arg in args
if i is 0
signature = '(${' + i + ':' + args[i] + '}'
else
signature = signature + ', ${' + i + ':' + args[i] + '}'
i = i + 1

signature = signature + ')'
return signature
# TODO: Emit function's result(s) in snippet, when appropriate

dispose: ->
@dispatch = null
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"providedServices": {
"autocomplete.provider": {
"versions": {
"1.1.0": "provide"
"2.0.0": "provide"
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions spec/gocode-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe 'gocode', ->
spyOn(goplusMain, 'setDispatch').andCallThrough()
pack = atom.packages.loadPackage('autocomplete-plus')
autocompleteMain = pack.mainModule
spyOn(autocompleteMain, 'consumeProviders').andCallThrough()
spyOn(autocompleteMain, 'consumeProvider').andCallThrough()
jasmine.unspy(window, 'setTimeout')

waitsForPromise -> atom.workspace.open('gocode.go').then (e) ->
Expand All @@ -41,7 +41,7 @@ describe 'gocode', ->
autocompleteMain.autocompleteManager?.ready

runs ->
autocompleteManager = autocompleteMain.autocompleteManager
autocompleteManager = autocompleteMain.getAutocompleteManager()
spyOn(autocompleteManager, 'displaySuggestions').andCallThrough()
spyOn(autocompleteManager, 'showSuggestionList').andCallThrough()
spyOn(autocompleteManager, 'hideSuggestionList').andCallThrough()
Expand All @@ -60,7 +60,7 @@ describe 'gocode', ->
goplusMain.provide.calls.length is 1

waitsFor ->
autocompleteMain.consumeProviders.calls.length is 1
autocompleteMain.consumeProvider.calls.length is 1

waitsFor ->
goplusMain.dispatch?.ready
Expand All @@ -72,9 +72,9 @@ describe 'gocode', ->
expect(goplusMain.provide).toHaveBeenCalled()
expect(goplusMain.provider).toBeDefined()
provider = goplusMain.provider
spyOn(provider, 'requestHandler').andCallThrough()
expect(_.size(autocompleteManager.providerManager.providersForScopeChain('.source.go'))).toEqual(2)
expect(autocompleteManager.providerManager.providersForScopeChain('.source.go')[0]).toEqual(provider)
spyOn(provider, 'getSuggestions').andCallThrough()
expect(_.size(autocompleteManager.providerManager.providersForScopeDescriptor('.source.go'))).toEqual(1)
expect(autocompleteManager.providerManager.providersForScopeDescriptor('.source.go')[0]).toEqual(provider)
buffer = editor.getBuffer()
dispatch = atom.packages.getLoadedPackage('go-plus').mainModule.dispatch
dispatch.goexecutable.detect()
Expand All @@ -83,17 +83,17 @@ describe 'gocode', ->
jasmine.unspy(goplusMain, 'provide')
jasmine.unspy(goplusMain, 'setDispatch')
jasmine.unspy(autocompleteManager, 'displaySuggestions')
jasmine.unspy(autocompleteMain, 'consumeProviders')
jasmine.unspy(autocompleteMain, 'consumeProvider')
jasmine.unspy(autocompleteManager, 'hideSuggestionList')
jasmine.unspy(autocompleteManager, 'showSuggestionList')
jasmine.unspy(provider, 'requestHandler')
jasmine.unspy(provider, 'getSuggestions')

describe 'when the gocode autocomplete-plus provider is enabled', ->

it 'displays suggestions from gocode', ->
fit 'displays suggestions from gocode', ->
runs ->
expect(provider).toBeDefined()
expect(provider.requestHandler).not.toHaveBeenCalled()
expect(provider.getSuggestions).not.toHaveBeenCalled()
expect(autocompleteManager.displaySuggestions).not.toHaveBeenCalled()
expect(editorView.querySelector('.autocomplete-plus')).not.toExist()

Expand All @@ -111,8 +111,8 @@ describe 'gocode', ->
autocompleteManager.displaySuggestions.calls.length is 1

runs ->
expect(provider.requestHandler).toHaveBeenCalled()
expect(provider.requestHandler.calls.length).toBe(1)
expect(provider.getSuggestions).toHaveBeenCalled()
expect(provider.getSuggestions.calls.length).toBe(1)
expect(editorView.querySelector('.autocomplete-plus')).toExist()
expect(editorView.querySelector('.autocomplete-plus span.word')).toHaveText('Print(')
expect(editorView.querySelector('.autocomplete-plus span.completion-label')).toHaveText('func(a ...interface{}) (n int, err error)')
Expand Down

0 comments on commit 106746a

Please sign in to comment.