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

Escape CSON correctly #1109

Merged
merged 8 commits into from Mar 6, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 10 additions & 10 deletions lib/keybindings-panel.js
Expand Up @@ -150,18 +150,18 @@ export default class KeybindingsPanel {
copyIcon.onclick = () => {
let content
const keymapExtension = path.extname(atom.keymaps.getUserKeymapPath())
const escapedKeystrokes = keystrokes.replace(/\\/g, '\\\\') // Escape backslashes

const escapeCSON = (input) => {
return JSON.stringify(input)
.slice(1, -1) // Remove wrapping double quotes
.replace(/\\"/g, '"') // Unescape double quotes
.replace(/'/g, '\\\'') // Escape single quotes
}

if (keymapExtension === '.cson') {
content = `\
'${selector}':
'${escapedKeystrokes}': '${command}'\
`
content = `'${escapeCSON(selector)}':\n '${escapeCSON(keystrokes)}': '${escapeCSON(command)}'`
} else {
content = `\
"${selector}": {
"${escapedKeystrokes}": "${command}"
}\
`
content = `${JSON.stringify(selector)}: {\n ${JSON.stringify(keystrokes)}: ${JSON.stringify(command)}\n}`
}
return atom.clipboard.write(content)
}
Expand Down
31 changes: 23 additions & 8 deletions spec/keybindings-panel-spec.coffee
Expand Up @@ -6,37 +6,44 @@ describe "KeybindingsPanel", ->

beforeEach ->
expect(atom.keymaps).toBeDefined()
keySource = "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps"
keyBindings = [
{
source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps"
source: keySource
keystrokes: 'ctrl-a'
command: 'core:select-all'
selector: '.editor, .platform-test'
}
{
source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps"
source: keySource
keystrokes: 'ctrl-u'
command: 'core:undo'
selector: ".platform-test"
}
{
source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps"
source: keySource
keystrokes: 'ctrl-u'
command: 'core:undo'
selector: ".platform-a, .platform-b"
}
{
source: "#{atom.getLoadSettings().resourcePath}#{path.sep}keymaps"
source: keySource
keystrokes: 'shift-\\ \\'
command: 'core:undo'
selector: '.editor'
}
{
source: keySource
keystrokes: 'ctrl-z\''
command: 'core:toggle'
selector: 'atom-text-editor[data-grammar~=\'css\']'
}
]
spyOn(atom.keymaps, 'getKeyBindings').andReturn(keyBindings)
panel = new KeybindingsPanel

it "loads and displays core key bindings", ->
expect(panel.refs.keybindingRows.children.length).toBe 2
expect(panel.refs.keybindingRows.children.length).toBe 3

row = panel.refs.keybindingRows.children[0]
expect(row.querySelector('.keystroke').textContent).toBe 'ctrl-a'
Expand Down Expand Up @@ -64,23 +71,31 @@ describe "KeybindingsPanel", ->
}
"""

describe "when the keybinding contains backslashes", ->
describe "when the keybinding contains special characters", ->
it "escapes the backslashes before copying", ->
spyOn(atom.keymaps, 'getUserKeymapPath').andReturn 'keymap.cson'
panel.element.querySelectorAll('.copy-icon')[1].click()
panel.element.querySelectorAll('.copy-icon')[2].click()
expect(atom.clipboard.read()).toBe """
'.editor':
'shift-\\\\ \\\\': 'core:undo'
"""

it "escapes the single quotes before copying", ->
spyOn(atom.keymaps, 'getUserKeymapPath').andReturn 'keymap.cson'
panel.element.querySelectorAll('.copy-icon')[1].click()
expect(atom.clipboard.read()).toBe """
'atom-text-editor[data-grammar~=\\'css\\']':
'ctrl-z\\'': 'core:toggle'
"""

describe "when the key bindings change", ->
it "reloads the key bindings", ->
keyBindings.push
source: atom.keymaps.getUserKeymapPath(), keystrokes: 'ctrl-b', command: 'core:undo', selector: '.editor'
atom.keymaps.emitter.emit 'did-reload-keymap'

waitsFor "the new keybinding to show up in the keybinding panel", ->
panel.refs.keybindingRows.children.length is 3
panel.refs.keybindingRows.children.length is 4

runs ->
row = panel.refs.keybindingRows.children[1]
Expand Down