diff --git a/lib/command-palette-view.js b/lib/command-palette-view.js index 403c4a4..ad2306f 100644 --- a/lib/command-palette-view.js +++ b/lib/command-palette-view.js @@ -81,12 +81,60 @@ export default class CommandPaletteView { } }) this.selectListView.element.classList.add('command-palette') + this.registerCommands() } async destroy () { await this.selectListView.destroy() } + copyItemText (propertyName, event) { + const item = event + ? this.itemForElement(event.target.closest("li")) // by contextMenu + : this.selectListView.getSelectedItem() // by keyborad shortcut + + if (item) { + const paramName = propertyName === "name" ? "surroundByBacktickWhenCopyCommandName" : "surroundByBacktickWhenCopyDisplayName" + let textToClip = item[propertyName] + if (atom.config.get(`command-palette.${paramName}`)) { + textToClip = "`" + textToClip + "`" + } + atom.clipboard.write(textToClip) + } + } + + itemForElement (element) { + if (element && this.selectListView.refs.items) { + const index = Array.from(this.selectListView.refs.items.children).indexOf(element) + if (index >= 0) { + return this.selectListView.items[index] + } + } + } + + registerCommands () { + atom.commands.add(this.selectListView.element, { + "command-palette:copy-display-name": () => this.copyItemText("displayName"), + "command-palette:copy-display-name-from-context-menu": event => this.copyItemText("displayName", event), + "command-palette:copy-command-name": () => this.copyItemText("name"), + "command-palette:copy-command-name-from-context-menu": event => this.copyItemText("name", event) + }) + const queryEditor = this.selectListView.refs.queryEditor + atom.commands.add(queryEditor.element, { + "core:copy": event => { + const propertyToCopy = atom.config.get('command-palette.allowCoreCopyWithEmptySelectionCopySelectedItemText') + if (propertyToCopy !== "none" && queryEditor.getSelectedBufferRange().isEmpty()) { + event.stopImmediatePropagation() + if (propertyToCopy === "display-name") { + this.copyItemText("displayName") + } else if (propertyToCopy === "command-name") { + this.copyItemText("name") + } + } + } + }) + } + toggle () { if (this.panel && this.panel.isVisible()) { this.hide() diff --git a/menus/command-palette.cson b/menus/command-palette.cson index 8df08e4..745adc5 100644 --- a/menus/command-palette.cson +++ b/menus/command-palette.cson @@ -23,3 +23,9 @@ ] } ] + +'context-menu': + '.command-palette .list-group': [ + {label: 'Copy Display Name', command: 'command-palette:copy-display-name-from-context-menu'} + {label: 'Copy Command Name', command: 'command-palette:copy-command-name-from-context-menu'} + ] diff --git a/package.json b/package.json index 0606389..5f979b4 100644 --- a/package.json +++ b/package.json @@ -29,14 +29,35 @@ }, "configSchema": { "useAlternateScoring": { + "order": 0, "type": "boolean", "default": true, "description": "Use an alternative scoring approach which prefers run of consecutive characters, acronyms and start of words." }, "preserveLastSearch": { + "order": 1, "type": "boolean", "default": false, "description": "Preserve the last search when reopening the command palette." + }, + "allowCoreCopyWithEmptySelectionCopySelectedItemText": { + "order": 2, + "type": "string", + "default": "none", + "enum": ["none", "command-name", "display-name"], + "description": "Copy selected item's command name or display name by `core:copy`." + }, + "surroundByBacktickWhenCopyCommandName": { + "order": 3, + "type": "boolean", + "default": false, + "description": "Automatically surround by backtick when copying command name." + }, + "surroundByBacktickWhenCopyDisplayName": { + "order": 4, + "type": "boolean", + "default": false, + "description": "Automatically surround by backtick when copying display name." } } } diff --git a/test/command-palette-view.test.js b/test/command-palette-view.test.js index 93e3247..af92cb8 100644 --- a/test/command-palette-view.test.js +++ b/test/command-palette-view.test.js @@ -285,4 +285,115 @@ describe('CommandPaletteView', () => { }) }) }) + + describe('`command-palette:copy-display-name` and `command-palette:copy-command-name`', () => { + let spy, commandPalette, selectListView + + beforeEach(async () => { + atom.commands.add('*', { + 'test-xxxxx-command:command-one': () => {}, + 'test-xxxxx-command:command-two': () => {}, + 'test-xxxxx-command:command-three': () => {}, + 'test-xxxxx-command:command-four': () => {}, + 'test-xxxxx-command:command-five': () => {}, + }) + + spy = sandbox.spy(atom.clipboard, 'write') + commandPalette = new CommandPaletteView() + selectListView = commandPalette.selectListView + await commandPalette.toggle() + atom.config.set("command-palette.surroundByBacktickWhenCopyCommandName", false) + atom.config.set("command-palette.surroundByBacktickWhenCopyDisplayName", false) + }) + + describe('surroundByBacktickWhenCopyCommandName', () => { + it('auto-surround by backtick when copy-command-name', async () => { + selectListView.selectItem(selectListView.items.find(item => item.name === "test-xxxxx-command:command-one")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-command-name') + assert(spy.calledWith("test-xxxxx-command:command-one")) + spy.reset() + atom.config.set("command-palette.surroundByBacktickWhenCopyCommandName", true) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-command-name') + assert(spy.calledWith("`test-xxxxx-command:command-one`")) + }) + }) + describe('surroundByBacktickWhenCopyDisCommandName', () => { + it('auto-surround by backtick when copy-display-name', async () => { + selectListView.selectItem(selectListView.items.find(item => item.name === "test-xxxxx-command:command-one")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-display-name') + assert(spy.calledWith("Test Xxxxx Command: Command One")) + spy.reset() + atom.config.set("command-palette.surroundByBacktickWhenCopyDisplayName", true) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-display-name') + assert(spy.calledWith("`Test Xxxxx Command: Command One`")) + }) + }) + + describe('copy by keyboard shortcut', () => { + it('copy name for selected item', async () => { + selectListView.selectItem(selectListView.items.find(item => item.name === "test-xxxxx-command:command-one")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-display-name') + assert(spy.calledWith("Test Xxxxx Command: Command One")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-command-name') + assert(spy.calledWith("test-xxxxx-command:command-one")) + + spy.reset() + selectListView.selectItem(selectListView.items.find(item => item.name === "test-xxxxx-command:command-two")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-display-name') + assert(spy.calledWith("Test Xxxxx Command: Command Two")) + atom.commands.dispatch(selectListView.element, 'command-palette:copy-command-name') + assert(spy.calledWith("test-xxxxx-command:command-two")) + }) + }) + + describe('copy from context menu', () => { + it('copy name or displayName of targeted item', async () => { + selectListView.refs.queryEditor.setText('xxxxx') + await selectListView.update() + const elements = Array.from(selectListView.refs.items.children) + assert.equal(elements.length, 5) + + const elementOne = selectListView.element.querySelector("[data-event-name='test-xxxxx-command:command-one']") + atom.commands.dispatch(elementOne, 'command-palette:copy-display-name-from-context-menu') + assert(spy.calledWith("Test Xxxxx Command: Command One")) + atom.commands.dispatch(elementOne, 'command-palette:copy-command-name-from-context-menu') + assert(spy.calledWith("test-xxxxx-command:command-one")) + + spy.reset() + const elementTwo = selectListView.element.querySelector("[data-event-name='test-xxxxx-command:command-two']") + atom.commands.dispatch(elementTwo, 'command-palette:copy-display-name-from-context-menu') + assert(spy.calledWith("Test Xxxxx Command: Command Two")) + atom.commands.dispatch(elementTwo, 'command-palette:copy-command-name-from-context-menu') + assert(spy.calledWith("test-xxxxx-command:command-two")) + }) + }) + + describe('core:copy behavior with command-palette.allowCoreCopyWithEmptySelectionCopySelectedItemText setting', () => { + beforeEach(async () => { + selectListView.refs.queryEditor.setText('xxxxx') + await selectListView.update() + assert.equal(selectListView.getSelectedItem().name, 'test-xxxxx-command:command-one') + const elements = Array.from(selectListView.refs.items.children) + assert.equal(elements.length, 5) + }) + + it('[value = "none"]: copy line text', async () => { + atom.config.set("command-palette.allowCoreCopyWithEmptySelectionCopySelectedItemText", "none") + atom.commands.dispatch(selectListView.refs.queryEditor.element, 'core:copy') + assert(spy.calledWith("xxxxx")) // default behavoir of atom-text-editor + }) + + it('[value = "display-name"]: copy displayName of selected item', async () => { + atom.config.set("command-palette.allowCoreCopyWithEmptySelectionCopySelectedItemText", "display-name") + atom.commands.dispatch(selectListView.refs.queryEditor.element, 'core:copy') + assert(spy.calledWith("Test Xxxxx Command: Command One")) + }) + + it('[value = "command-name]": copy command name of selected item', async () => { + atom.config.set("command-palette.allowCoreCopyWithEmptySelectionCopySelectedItemText", "command-name") + atom.commands.dispatch(selectListView.refs.queryEditor.element, 'core:copy') + assert(spy.calledWith("test-xxxxx-command:command-one")) + }) + }) + }) })