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

Add suggestion type icons and left label #334

Merged
merged 20 commits into from
Apr 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 45 additions & 21 deletions lib/suggestion-list-element.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
{CompositeDisposable} = require 'atom'
_ = require 'underscore-plus'

ItemTemplate = """
<span class="icon-container"></span>
<span class="left-label"></span>
<span class="word-container">
<span class="word"></span>
<span class="right-label"></span>
</span>
"""

IconTemplate = '<i class="icon"></i>'

DefaultSuggestionTypeIconHTML =
'snippet': '<i class="icon-move-right"></i>'

class SuggestionListElement extends HTMLElement
maxItems: 200
snippetRegex: /\$\{[0-9]+:([^}]+)\}/g
Expand Down Expand Up @@ -106,7 +120,8 @@ class SuggestionListElement extends HTMLElement
li.textContent = 'test'
@ol.appendChild(li)
itemHeight = li.offsetHeight
@ol.style['max-height'] = "#{maxVisibleItems * itemHeight}px"
paddingHeight = parseInt(getComputedStyle(this)['padding-top']) + parseInt(getComputedStyle(this)['padding-bottom']) ? 0
@style['max-height'] = "#{maxVisibleItems * itemHeight + paddingHeight}px"
li.remove()

renderItems: ->
Expand All @@ -115,40 +130,49 @@ class SuggestionListElement extends HTMLElement
li.remove() while li = @ol.childNodes[items.length]
@selectedLi?.scrollIntoView(false)

renderItem: ({snippet, text, rightLabel, rightLabelHTML, className, replacementPrefix}, index) ->
renderItem: ({iconHTML, type, snippet, text, className, replacementPrefix, leftLabel, leftLabelHTML, rightLabel, rightLabelHTML}, index) ->
li = @ol.childNodes[index]
unless li
li = document.createElement('li')
@ol.appendChild(li)
li.innerHTML = ItemTemplate
li.dataset.index = index
@ol.appendChild(li)

li.className = ''
li.classList.add(className) if className
li.classList.add('selected') if index is @selectedIndex
@selectedLi = li if index is @selectedIndex

wordSpan = li.childNodes[0]
unless wordSpan
wordSpan = document.createElement('span')
li.appendChild(wordSpan)
wordSpan.className = 'word'
typeIconContainer = li.querySelector('.icon-container')
typeIconContainer.innerHTML = ''

sanitizedType = if _.isString(type) then type else ''
sanitizedIconHTML = if _.isString(iconHTML) then iconHTML else undefined
defaultIconHTML = DefaultSuggestionTypeIconHTML[sanitizedType] ? sanitizedType[0]
if (sanitizedIconHTML or defaultIconHTML) and iconHTML isnt false
typeIconContainer.innerHTML = IconTemplate
typeIcon = typeIconContainer.childNodes[0]
typeIcon.innerHTML = sanitizedIconHTML ? defaultIconHTML
typeIcon.classList.add(type) if type

wordSpan = li.querySelector('.word')
wordSpan.innerHTML = @getHighlightedHTML(text, snippet, replacementPrefix)

labelSpan = li.childNodes[1]
hasRightLabel = rightLabel or rightLabelHTML
if hasRightLabel
unless labelSpan
labelSpan = document.createElement('span')
li.appendChild(labelSpan) if hasRightLabel
labelSpan.className = 'completion-label text-smaller text-subtle'

if rightLabelHTML?
labelSpan.innerHTML = rightLabelHTML
else
labelSpan.textContent = rightLabel
leftLabelSpan = li.querySelector('.left-label')
if leftLabelHTML?
leftLabelSpan.innerHTML = leftLabelHTML
else if leftLabel?
leftLabelSpan.textContent = leftLabel
else
leftLabelSpan.textContent = ''

rightLabelSpan = li.querySelector('.right-label')
if rightLabelHTML?
rightLabelSpan.innerHTML = rightLabelHTML
else if rightLabel?
rightLabelSpan.textContent = rightLabel
else
labelSpan?.remove()
rightLabelSpan.textContent = ''

getHighlightedHTML: (text, snippet, replacementPrefix) ->
# 1. Pull the snippets out, replacing with placeholder
Expand Down
3 changes: 1 addition & 2 deletions lib/symbol-provider.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SymbolProvider
config: null
defaultConfig:
class:
selector: '.class.name, .inherited-class'
selector: '.class.name, .inherited-class, .instance.type'
priority: 4
function:
selector: '.function.name'
Expand Down Expand Up @@ -122,7 +122,6 @@ class SymbolProvider

for word in words
word.replacementPrefix = options.prefix
word.rightLabel = word.type

return words

Expand Down
2 changes: 1 addition & 1 deletion spec/autocomplete-manager-async-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe 'Async providers', ->

runs ->
suggestionListView = atom.views.getView(autocompleteManager.suggestionList)
expect(suggestionListView.querySelector('li .completion-label')).toHaveText('asyncProvided')
expect(suggestionListView.querySelector('li .right-label')).toHaveText('asyncProvided')

describe 'when a provider takes a long time to provide suggestions', ->
beforeEach ->
Expand Down
151 changes: 145 additions & 6 deletions spec/autocomplete-manager-integration-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe 'Autocomplete Manager', ->
expect(triggerPosition).toEqual [0, 1]
expect(suggestion.text).toBe 'ab'

fdescribe "suppression for editorView classes", ->
describe "suppression for editorView classes", ->
beforeEach ->
atom.config.set('autocomplete-plus.suppressActivationForEditorClasses', ['vim-mode.command-mode', 'vim-mode . visual-mode', ' vim-mode.operator-pending-mode ', ' '])

Expand Down Expand Up @@ -201,7 +201,7 @@ describe 'Autocomplete Manager', ->
runs ->
expect(editorView.querySelector('.autocomplete-plus')).toExist()
expect(editorView.querySelectorAll('.autocomplete-plus li')).toHaveLength 4
expect(editorView.querySelector('.autocomplete-plus .list-group').style['max-height']).toBe("#{2 * 25}px")
expect(editorView.querySelector('.autocomplete-plus autocomplete-suggestion-list').style['max-height']).toBe("#{2 * 25}px")

describe "when match.snippet is used", ->
beforeEach ->
Expand Down Expand Up @@ -615,9 +615,9 @@ describe 'Autocomplete Manager', ->

items = editorView.querySelectorAll('.autocomplete-plus li')
expect(items).toHaveLength 3
expect(items[0].textContent).toBe 'abcOk'
expect(items[1].textContent).toBe '[self abcOk]'
expect(items[2].textContent).toBe '[self aabcOk]'
expect(items[0].textContent).toContain 'abcOk'
expect(items[1].textContent).toContain '[self abcOk]'
expect(items[2].textContent).toContain '[self aabcOk]'

it 'resets the strict match on subsequent opens', ->
editor.insertText 'yeah ab'
Expand Down Expand Up @@ -788,6 +788,145 @@ describe 'Autocomplete Manager', ->
atom.commands.dispatch(suggestionListView, 'autocomplete-plus:select-next')
expect(items[0]).toHaveClass('selected')

describe "label rendering", ->
describe "when no labels are specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok']

it "displays the text in the suggestion", ->
triggerAutocompletion(editor)
runs ->
iconContainer = editorView.querySelector('.autocomplete-plus li .icon-container')
leftLabel = editorView.querySelector('.autocomplete-plus li .right-label')
rightLabel = editorView.querySelector('.autocomplete-plus li .right-label')

expect(iconContainer.childNodes).toHaveLength 0
expect(leftLabel.childNodes).toHaveLength 0
expect(rightLabel.childNodes).toHaveLength 0

describe "when `type` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', type: 'omg']

it "displays an icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
icon = editorView.querySelector('.autocomplete-plus li .icon-container .icon')
expect(icon.innerHTML).toBe('o')

describe "when the `type` specified has a default icon", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', type: 'snippet']

it "displays the default icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
icon = editorView.querySelector('.autocomplete-plus li .icon-container .icon i')
console.log editorView.querySelector('.autocomplete-plus li .icon-container .icon').innerHTML
expect(icon).toHaveClass('icon-move-right')

describe "when `type` is an empty string", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', type: '']

it "does not display an icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
iconContainer = editorView.querySelector('.autocomplete-plus li .icon-container')
expect(iconContainer.childNodes).toHaveLength 0

describe "when `iconHTML` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', iconHTML: '<i class="omg"></i>']

it "displays an icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
icon = editorView.querySelector('.autocomplete-plus li .icon-container .icon .omg')
expect(icon).toExist()

describe "when `iconHTML` is false", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', type: 'something', iconHTML: false]

it "does not display an icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
iconContainer = editorView.querySelector('.autocomplete-plus li .icon-container')
expect(iconContainer.childNodes).toHaveLength 0

describe "when `iconHTML` is not a string and a `type` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', type: 'something', iconHTML: true]

it "displays the default icon in the icon-container", ->
triggerAutocompletion(editor)
runs ->
icon = editorView.querySelector('.autocomplete-plus li .icon-container .icon')
expect(icon.innerHTML).toBe('s')

describe "when `iconHTML` is not a string and no type is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', iconHTML: true]

it "it does not display an icon", ->
triggerAutocompletion(editor)
runs ->
iconContainer = editorView.querySelector('.autocomplete-plus li .icon-container')
expect(iconContainer.childNodes).toHaveLength 0

describe "when `rightLabel` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', rightLabel: '<i class="something">sometext</i>']

it "displays the text in the suggestion", ->
triggerAutocompletion(editor)
runs ->
label = editorView.querySelector('.autocomplete-plus li .right-label')
expect(label).toHaveText('<i class="something">sometext</i>')

describe "when `rightLabelHTML` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', rightLabelHTML: '<i class="something">sometext</i>']

it "displays the text in the suggestion", ->
triggerAutocompletion(editor)
runs ->
label = editorView.querySelector('.autocomplete-plus li .right-label .something')
expect(label).toHaveText('sometext')

describe "when `leftLabel` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', leftLabel: '<i class="something">sometext</i>']

it "displays the text in the suggestion", ->
triggerAutocompletion(editor)
runs ->
label = editorView.querySelector('.autocomplete-plus li .left-label')
expect(label).toHaveText('<i class="something">sometext</i>')

describe "when `leftLabelHTML` is specified", ->
beforeEach ->
spyOn(provider, 'getSuggestions').andCallFake (options) ->
[text: 'ok', leftLabelHTML: '<i class="something">sometext</i>']

it "displays the text in the suggestion", ->
triggerAutocompletion(editor)
runs ->
label = editorView.querySelector('.autocomplete-plus li .left-label .something')
expect(label).toHaveText('sometext')

describe 'when opening a file without a path', ->
beforeEach ->
waitsForPromise ->
Expand Down Expand Up @@ -1038,7 +1177,7 @@ describe 'Autocomplete Manager', ->
item.dispatchEvent(mouse)

expect(editorView.querySelector('.autocomplete-plus')).not.toExist()
expect(editor.getBuffer().getLastLine()).toEqual(item.innerText)
expect(editor.getBuffer().getLastLine()).toEqual(item.textContent.trim())

describe '.cancel()', ->
it 'unbinds autocomplete event handlers for move-up and move-down', ->
Expand Down
4 changes: 1 addition & 3 deletions spec/issues/64-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ describe 'Autocomplete', ->
waitForAutocomplete()

runs ->

expect(editorView.querySelector('.autocomplete-plus')).toExist()

suggestionListView = atom.views.getView(autocompleteManager.suggestionList)
expect(suggestionListView.querySelector('li')).toHaveText('bla-foo--bar')
expect(suggestionListView.querySelector('li').textContent).toContain 'bla-foo--bar'
2 changes: 1 addition & 1 deletion spec/provider-api-legacy-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ describe 'Provider API Legacy', ->
runs ->
suggestionListView = atom.views.getView(autocompleteManager.suggestionList)

expect(suggestionListView.querySelector('li .completion-label')).toHaveHtml('<span style="color: red">ohai</span>')
expect(suggestionListView.querySelector('li .right-label')).toHaveHtml('<span style="color: red">ohai</span>')
expect(suggestionListView.querySelector('li')).toHaveClass('ohai')

it 'should dispose a provider registration correctly', ->
Expand Down
2 changes: 1 addition & 1 deletion spec/provider-api-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,5 @@ describe 'Provider API', ->

runs ->
suggestionListView = atom.views.getView(autocompleteManager.suggestionList)
expect(suggestionListView.querySelector('li .completion-label')).toHaveHtml('<span style="color: red">ohai</span>')
expect(suggestionListView.querySelector('li .right-label')).toHaveHtml('<span style="color: red">ohai</span>')
expect(suggestionListView.querySelector('span.word')).toHaveText('ohai')
Loading