➡️ Migrate core package 'grammar-selector' into ./packages

This commit is contained in:
Max Brunsfeld 2018-10-17 14:30:51 -07:00
parent 09a03a384a
commit 2a318c1316
15 changed files with 566 additions and 6 deletions

3
package-lock.json generated
View File

@ -2557,8 +2557,7 @@
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"grammar-selector": {
"version": "https://www.atom.io/api/packages/grammar-selector/versions/0.50.1/tarball",
"integrity": "sha512-tXoxzu+RtJffRc6no/KsIyI9YX1qfpuQjmMI3RJ42qPHtGk54RsEpAuFku8oOW4sIrSy5c7suM7iKmh4aUnsZg==",
"version": "file:packages/grammar-selector",
"requires": {
"atom-select-list": "^0.7.0"
}

View File

@ -70,7 +70,7 @@
"github": "https://www.atom.io/api/packages/github/versions/0.20.1/tarball",
"glob": "^7.1.1",
"go-to-line": "file:packages/go-to-line",
"grammar-selector": "https://www.atom.io/api/packages/grammar-selector/versions/0.50.1/tarball",
"grammar-selector": "file:packages/grammar-selector",
"grim": "1.5.0",
"image-view": "https://www.atom.io/api/packages/image-view/versions/0.63.1/tarball",
"incompatible-packages": "file:packages/incompatible-packages",
@ -205,7 +205,7 @@
"github": "0.20.1",
"git-diff": "file:./packages/git-diff",
"go-to-line": "file:./packages/go-to-line",
"grammar-selector": "0.50.1",
"grammar-selector": "file:./packages/grammar-selector",
"image-view": "0.63.1",
"incompatible-packages": "file:./packages/incompatible-packages",
"keybinding-resolver": "0.38.4",

View File

@ -36,7 +36,7 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
| **github** | [`atom/github`][github] | |
| **git-diff** | [`./git-diff`](./git-diff) | [#17843](https://github.com/atom/atom/issues/17843) |
| **go-to-line** | [`./go-to-line`](./go-to-line) | [#17844](https://github.com/atom/atom/issues/17844) |
| **grammar-selector** | [`atom/grammar-selector`][grammar-selector] | [#17845](https://github.com/atom/atom/issues/17845) |
| **grammar-selector** | [`./packages/grammar-selector`](./grammar-selector) | [#17845](https://github.com/atom/atom/issues/17845) |
| **image-view** | [`atom/image-view`][image-view] | |
| **incompatible-packages** | [`./incompatible-packages`](./incompatible-packages) | [#17846](https://github.com/atom/atom/issues/17846) |
| **keybinding-resolver** | [`atom/keybinding-resolver`][keybinding-resolver] | |
@ -115,7 +115,6 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
[find-and-replace]: https://github.com/atom/find-and-replace
[fuzzy-finder]: https://github.com/atom/fuzzy-finder
[github]: https://github.com/atom/github
[grammar-selector]: https://github.com/atom/grammar-selector
[image-view]: https://github.com/atom/image-view
[keybinding-resolver]: https://github.com/atom/keybinding-resolver
[language-c]: https://github.com/atom/language-c

View File

@ -0,0 +1,5 @@
# Grammar Selector package
Pick the grammar used for syntax highlighting using <kbd>ctrl-shift-L</kbd> or by clicking the current grammar name in the status bar.
![](https://f.cloud.github.com/assets/671378/2241618/b7661f08-9cd9-11e3-8276-fe1c02955901.png)

View File

@ -0,0 +1,8 @@
'.platform-darwin atom-text-editor':
'ctrl-L': 'grammar-selector:show'
'.platform-win32 atom-text-editor':
'ctrl-L': 'grammar-selector:show'
'.platform-linux atom-text-editor':
'ctrl-L': 'grammar-selector:show'

View File

@ -0,0 +1,104 @@
const SelectListView = require('atom-select-list')
module.exports =
class GrammarListView {
constructor () {
this.autoDetect = {name: 'Auto Detect'}
this.selectListView = new SelectListView({
itemsClassList: ['mark-active'],
items: [],
filterKeyForItem: (grammar) => grammar.name,
elementForItem: (grammar) => {
const grammarName = grammar.name || grammar.scopeName
const element = document.createElement('li')
if (grammar === this.currentGrammar) {
element.classList.add('active')
}
element.textContent = grammarName
element.dataset.grammar = grammarName
const div = document.createElement('div')
div.classList.add('pull-right')
if (grammar.scopeName) {
const scopeName = document.createElement('scopeName')
scopeName.classList.add('key-binding') // It will be styled the same as the keybindings in the command palette
scopeName.textContent = grammar.scopeName
div.appendChild(scopeName)
element.appendChild(div)
}
return element
},
didConfirmSelection: (grammar) => {
this.cancel()
if (grammar === this.autoDetect) {
atom.textEditors.clearGrammarOverride(this.editor)
} else {
atom.textEditors.setGrammarOverride(this.editor, grammar.scopeName)
}
},
didCancelSelection: () => {
this.cancel()
}
})
this.selectListView.element.classList.add('grammar-selector')
}
destroy () {
this.cancel()
return this.selectListView.destroy()
}
cancel () {
if (this.panel != null) {
this.panel.destroy()
}
this.panel = null
this.currentGrammar = null
if (this.previouslyFocusedElement) {
this.previouslyFocusedElement.focus()
this.previouslyFocusedElement = null
}
}
attach () {
this.previouslyFocusedElement = document.activeElement
if (this.panel == null) {
this.panel = atom.workspace.addModalPanel({item: this.selectListView})
}
this.selectListView.focus()
this.selectListView.reset()
}
async toggle () {
if (this.panel != null) {
this.cancel()
} else if (atom.workspace.getActiveTextEditor()) {
this.editor = atom.workspace.getActiveTextEditor()
this.currentGrammar = this.editor.getGrammar()
if (this.currentGrammar === atom.grammars.nullGrammar) {
this.currentGrammar = this.autoDetect
}
const grammars = atom.grammars.getGrammars().filter((grammar) => {
return grammar !== atom.grammars.nullGrammar && grammar.name
})
grammars.sort((a, b) => {
if (a.scopeName === 'text.plain') {
return -1
} else if (b.scopeName === 'text.plain') {
return 1
} else if (a.name) {
return a.name.localeCompare(b.name)
} else if (a.scopeName) {
return a.scopeName.localeCompare(b.scopeName)
} else {
return 1
}
})
grammars.unshift(this.autoDetect)
await this.selectListView.update({items: grammars})
this.attach()
}
}
}

View File

@ -0,0 +1,101 @@
const {Disposable} = require('atom')
module.exports =
class GrammarStatusView {
constructor (statusBar) {
this.statusBar = statusBar
this.element = document.createElement('grammar-selector-status')
this.element.classList.add('grammar-status', 'inline-block')
this.grammarLink = document.createElement('a')
this.grammarLink.classList.add('inline-block')
this.element.appendChild(this.grammarLink)
this.activeItemSubscription = atom.workspace.observeActiveTextEditor(this.subscribeToActiveTextEditor.bind(this))
this.configSubscription = atom.config.observe('grammar-selector.showOnRightSideOfStatusBar', this.attach.bind(this))
const clickHandler = (event) => {
event.preventDefault()
atom.commands.dispatch(atom.views.getView(atom.workspace.getActiveTextEditor()), 'grammar-selector:show')
}
this.element.addEventListener('click', clickHandler)
this.clickSubscription = new Disposable(() => { this.element.removeEventListener('click', clickHandler) })
}
attach () {
if (this.tile) {
this.tile.destroy()
}
this.tile = atom.config.get('grammar-selector.showOnRightSideOfStatusBar')
? this.statusBar.addRightTile({item: this.element, priority: 10})
: this.statusBar.addLeftTile({item: this.element, priority: 10})
}
destroy () {
if (this.activeItemSubscription) {
this.activeItemSubscription.dispose()
}
if (this.grammarSubscription) {
this.grammarSubscription.dispose()
}
if (this.clickSubscription) {
this.clickSubscription.dispose()
}
if (this.configSubscription) {
this.configSubscription.dispose()
}
if (this.tile) {
this.tile.destroy()
}
if (this.tooltip) {
this.tooltip.dispose()
}
}
subscribeToActiveTextEditor () {
if (this.grammarSubscription) {
this.grammarSubscription.dispose()
this.grammarSubscription = null
}
const editor = atom.workspace.getActiveTextEditor()
if (editor) {
this.grammarSubscription = editor.onDidChangeGrammar(this.updateGrammarText.bind(this))
}
this.updateGrammarText()
}
updateGrammarText () {
atom.views.updateDocument(() => {
const editor = atom.workspace.getActiveTextEditor()
const grammar = editor ? editor.getGrammar() : null
if (this.tooltip) {
this.tooltip.dispose()
this.tooltip = null
}
if (grammar) {
let grammarName = null
if (grammar === atom.grammars.nullGrammar) {
grammarName = 'Plain Text'
} else {
grammarName = grammar.name || grammar.scopeName
}
this.grammarLink.textContent = grammarName
this.grammarLink.dataset.grammar = grammarName
this.element.style.display = ''
this.tooltip = atom.tooltips.add(this.element, {title: `File uses the ${grammarName} grammar`})
} else {
this.element.style.display = 'none'
}
})
}
}

View File

@ -0,0 +1,31 @@
const GrammarListView = require('./grammar-list-view')
const GrammarStatusView = require('./grammar-status-view')
let commandDisposable = null
let grammarListView = null
let grammarStatusView = null
module.exports = {
activate () {
commandDisposable = atom.commands.add('atom-text-editor', 'grammar-selector:show', () => {
if (!grammarListView) grammarListView = new GrammarListView()
grammarListView.toggle()
})
},
deactivate () {
if (commandDisposable) commandDisposable.dispose()
commandDisposable = null
if (grammarStatusView) grammarStatusView.destroy()
grammarStatusView = null
if (grammarListView) grammarListView.destroy()
grammarListView = null
},
consumeStatusBar (statusBar) {
grammarStatusView = new GrammarStatusView(statusBar)
grammarStatusView.attach()
}
}

View File

@ -0,0 +1,13 @@
'menu': [
'label': 'Edit'
'submenu': [
'label': 'Select Grammar'
'command': 'grammar-selector:show'
]
]
'context-menu':
'.overlayer': [
'label': 'Change Grammar'
'command': 'grammar-selector:show'
]

View File

@ -0,0 +1,42 @@
{
"name": "grammar-selector",
"version": "0.50.1",
"main": "./lib/main",
"description": "Select the grammar to use for the current editor with `ctrl-shift-L`.",
"license": "MIT",
"repository": "https://github.com/atom/atom",
"engines": {
"atom": "*"
},
"dependencies": {
"atom-select-list": "^0.7.0"
},
"consumedServices": {
"status-bar": {
"versions": {
"^1.0.0": "consumeStatusBar"
}
}
},
"devDependencies": {
"standard": "^10.0.3"
},
"standard": {
"globals": [
"atom",
"beforeEach",
"describe",
"expect",
"it",
"jasmine",
"spyOn"
]
},
"configSchema": {
"showOnRightSideOfStatusBar": {
"type": "boolean",
"default": true,
"description": "Show the active pane item's language on the right side of Atom's status bar, instead of the left."
}
}
}

View File

@ -0,0 +1,42 @@
exports.beforeEach = function beforeEach (fn) {
global.beforeEach(function () {
const result = fn()
if (result instanceof Promise) {
waitsForPromise('beforeEach promise', result)
}
})
}
exports.afterEach = function afterEach (fn) {
global.afterEach(function () {
const result = fn()
if (result instanceof Promise) {
waitsForPromise('afterEach promise', result)
}
})
}
;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) {
exports[name] = function (description, fn) {
if (fn === undefined) {
global[name](description)
return
}
global[name](description, function () {
const result = fn()
if (result instanceof Promise) {
waitsForPromise('test promise', result)
}
})
}
})
function waitsForPromise (message, promise) {
global.waitsFor(message, (done) => {
promise.then(done, (error) => {
jasmine.getEnv().currentSpec.fail(error)
done()
})
})
}

View File

@ -0,0 +1,8 @@
{
"scopeName": "source.a",
"fileTypes": [
".a",
".aa",
"a"
]
}

View File

@ -0,0 +1,4 @@
{
"name": "language-test",
"version": "1.0.0"
}

View File

@ -0,0 +1,198 @@
const path = require('path')
const SelectListView = require('atom-select-list')
const {it, fit, ffit, beforeEach, afterEach} = require('./async-spec-helpers') // eslint-disable-line
describe('GrammarSelector', () => {
let [editor, textGrammar, jsGrammar] = []
beforeEach(async () => {
jasmine.attachToDOM(atom.views.getView(atom.workspace))
atom.config.set('grammar-selector.showOnRightSideOfStatusBar', false)
await atom.packages.activatePackage('status-bar')
await atom.packages.activatePackage('grammar-selector')
await atom.packages.activatePackage('language-text')
await atom.packages.activatePackage('language-javascript')
await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'language-with-no-name'))
editor = await atom.workspace.open('sample.js')
textGrammar = atom.grammars.grammarForScopeName('text.plain')
expect(textGrammar).toBeTruthy()
jsGrammar = atom.grammars.grammarForScopeName('source.js')
expect(jsGrammar).toBeTruthy()
expect(editor.getGrammar()).toBe(jsGrammar)
})
describe('when grammar-selector:show is triggered', () =>
it('displays a list of all the available grammars', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
const grammarView = atom.workspace.getModalPanels()[0].getItem().element
// TODO: Remove once Atom 1.23 reaches stable
if (parseFloat(atom.getVersion()) >= 1.23) {
// Do not take into account the two JS regex grammars or language-with-no-name
expect(grammarView.querySelectorAll('li').length).toBe(atom.grammars.grammars.length - 3)
} else {
expect(grammarView.querySelectorAll('li').length).toBe(atom.grammars.grammars.length - 1)
}
expect(grammarView.querySelectorAll('li')[0].textContent).toBe('Auto Detect')
expect(grammarView.textContent.includes('source.a')).toBe(false)
grammarView.querySelectorAll('li').forEach(li => expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name))
})
)
describe('when a grammar is selected', () =>
it('sets the new grammar on the editor', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
const grammarView = atom.workspace.getModalPanels()[0].getItem()
grammarView.props.didConfirmSelection(textGrammar)
expect(editor.getGrammar()).toBe(textGrammar)
})
)
describe('when auto-detect is selected', () =>
it('restores the auto-detected grammar on the editor', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
let grammarView = atom.workspace.getModalPanels()[0].getItem()
grammarView.props.didConfirmSelection(textGrammar)
expect(editor.getGrammar()).toBe(textGrammar)
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
grammarView = atom.workspace.getModalPanels()[0].getItem()
grammarView.props.didConfirmSelection(grammarView.items[0])
expect(editor.getGrammar()).toBe(jsGrammar)
})
)
describe("when the editor's current grammar is the null grammar", () =>
it('displays Auto Detect as the selected grammar', async () => {
editor.setGrammar(atom.grammars.nullGrammar)
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
const grammarView = atom.workspace.getModalPanels()[0].getItem().element
expect(grammarView.querySelector('li.active').textContent).toBe('Auto Detect')
})
)
describe('when editor is untitled', () =>
it('sets the new grammar on the editor', async () => {
editor = await atom.workspace.open()
expect(editor.getGrammar()).not.toBe(jsGrammar)
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show')
await SelectListView.getScheduler().getNextUpdatePromise()
const grammarView = atom.workspace.getModalPanels()[0].getItem()
grammarView.props.didConfirmSelection(jsGrammar)
expect(editor.getGrammar()).toBe(jsGrammar)
})
)
describe('Status bar grammar label', () => {
let [grammarStatus, grammarTile, statusBar] = []
beforeEach(async () => {
statusBar = document.querySelector('status-bar')
;[grammarTile] = statusBar.getLeftTiles().slice(-1)
grammarStatus = grammarTile.getItem()
// Wait for status bar service hook to fire
while (!grammarStatus || !grammarStatus.textContent) {
await atom.views.getNextUpdatePromise()
grammarStatus = document.querySelector('.grammar-status')
}
})
it('displays the name of the current grammar', () => {
expect(grammarStatus.querySelector('a').textContent).toBe('JavaScript')
expect(getTooltipText(grammarStatus)).toBe('File uses the JavaScript grammar')
})
it('displays Plain Text when the current grammar is the null grammar', async () => {
editor.setGrammar(atom.grammars.nullGrammar)
await atom.views.getNextUpdatePromise()
expect(grammarStatus.querySelector('a').textContent).toBe('Plain Text')
expect(grammarStatus).toBeVisible()
expect(getTooltipText(grammarStatus)).toBe('File uses the Plain Text grammar')
editor.setGrammar(atom.grammars.grammarForScopeName('source.js'))
await atom.views.getNextUpdatePromise()
expect(grammarStatus.querySelector('a').textContent).toBe('JavaScript')
expect(grammarStatus).toBeVisible()
})
it('hides the label when the current grammar is null', async () => {
jasmine.attachToDOM(editor.getElement())
spyOn(editor, 'getGrammar').andReturn(null)
editor.setGrammar(atom.grammars.nullGrammar)
await atom.views.getNextUpdatePromise()
expect(grammarStatus.offsetHeight).toBe(0)
})
describe('when the grammar-selector.showOnRightSideOfStatusBar setting changes', () =>
it('moves the item to the preferred side of the status bar', () => {
expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain(grammarStatus)
expect(statusBar.getRightTiles().map(tile => tile.getItem())).not.toContain(grammarStatus)
atom.config.set('grammar-selector.showOnRightSideOfStatusBar', true)
expect(statusBar.getLeftTiles().map(tile => tile.getItem())).not.toContain(grammarStatus)
expect(statusBar.getRightTiles().map(tile => tile.getItem())).toContain(grammarStatus)
atom.config.set('grammar-selector.showOnRightSideOfStatusBar', false)
expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain(grammarStatus)
expect(statusBar.getRightTiles().map(tile => tile.getItem())).not.toContain(grammarStatus)
})
)
describe("when the editor's grammar changes", () =>
it('displays the new grammar of the editor', async () => {
editor.setGrammar(atom.grammars.grammarForScopeName('text.plain'))
await atom.views.getNextUpdatePromise()
expect(grammarStatus.querySelector('a').textContent).toBe('Plain Text')
expect(getTooltipText(grammarStatus)).toBe('File uses the Plain Text grammar')
editor.setGrammar(atom.grammars.grammarForScopeName('source.a'))
await atom.views.getNextUpdatePromise()
expect(grammarStatus.querySelector('a').textContent).toBe('source.a')
expect(getTooltipText(grammarStatus)).toBe('File uses the source.a grammar')
})
)
describe('when clicked', () =>
it('shows the grammar selector modal', () => {
const eventHandler = jasmine.createSpy('eventHandler')
atom.commands.add(editor.getElement(), 'grammar-selector:show', eventHandler)
grammarStatus.click()
expect(eventHandler).toHaveBeenCalled()
})
)
describe('when the package is deactivated', () =>
it('removes the view', () => {
spyOn(grammarTile, 'destroy')
atom.packages.deactivatePackage('grammar-selector')
expect(grammarTile.destroy).toHaveBeenCalled()
})
)
})
})
function getTooltipText (element) {
const [tooltip] = atom.tooltips.findTooltips(element)
return tooltip.getTitle()
}

View File

@ -0,0 +1,6 @@
@import "ui-variables";
.grammar-status a,
.grammar-status a:hover {
color: @text-color;
}