diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 93fdc36a7..58643bb91 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1828,3 +1828,55 @@ describe "Editor", -> editor.pageUp() expect(editor.getCursor().getScreenPosition().row).toBe(0) expect(editor.getFirstVisibleScreenRow()).toBe(0) + + describe ".replaceSelectedText()", -> + it "doesn't call the replace function when the selection is empty", -> + replaced = false + edited = false + replacer = (text) -> + replaced = true + 'new' + + editor.moveCursorToTop() + edited = editor.replaceSelectedText(replacer) + expect(replaced).toBe false + expect(edited).toBe false + + it "returns true when transformed text is non-empty", -> + replaced = false + edited = false + replacer = (text) -> + replaced = true + 'new' + + editor.moveCursorToTop() + editor.selectToEndOfLine() + edited = editor.replaceSelectedText(replacer) + expect(replaced).toBe true + expect(edited).toBe true + + it "returns false when transformed text is null", -> + replaced = false + edited = false + replacer = (text) -> + replaced = true + null + + editor.moveCursorToTop() + editor.selectToEndOfLine() + edited = editor.replaceSelectedText(replacer) + expect(replaced).toBe true + expect(edited).toBe false + + it "returns false when transformed text is undefined", -> + replaced = false + edited = false + replacer = (text) -> + replaced = true + undefined + + editor.moveCursorToTop() + editor.selectToEndOfLine() + edited = editor.replaceSelectedText(replacer) + expect(replaced).toBe true + expect(edited).toBe false diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index 8e1c2ca81..3b56766a5 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -690,3 +690,31 @@ describe "RootView", -> expect(fs.read(buffer1.getPath())).toBe("edited1") expect(buffer2.isModified()).toBe(false) expect(fs.read(buffer2.getPath())).toBe("edited2") + + fdescribe ".eachEditor(callback)", -> + beforeEach -> + rootView.attachToDom() + + it "invokes the callback for existing editor", -> + count = 0 + callbackEditor = null + callback = (editor) -> + callbackEditor = editor + count++ + rootView.eachEditor(callback) + expect(count).toBe 1 + expect(callbackEditor).toBe rootView.getActiveEditor() + + it "invokes the callback for new editor", -> + count = 0 + callbackEditor = null + callback = (editor) -> + callbackEditor = editor + count++ + + rootView.eachEditor(callback) + count = 0 + callbackEditor = null + rootView.getActiveEditor().splitRight() + expect(count).toBe 1 + expect(callbackEditor).toBe rootView.getActiveEditor() diff --git a/spec/extensions/editor-command-spec.coffee b/spec/extensions/editor-command-spec.coffee deleted file mode 100644 index 96b2f08ac..000000000 --- a/spec/extensions/editor-command-spec.coffee +++ /dev/null @@ -1,140 +0,0 @@ -EditorCommand = require 'editor-command' -LowerCaseCommand = require 'lowercase-command' -UpperCaseCommand = require 'uppercase-command' -RootView = require 'root-view' -fs = require 'fs' - -describe "EditorCommand", -> - [rootView, editor, path] = [] - - beforeEach -> - rootView = new RootView - rootView.open(require.resolve 'fixtures/sample.js') - - rootView.focus() - editor = rootView.getActiveEditor() - - afterEach -> - rootView.remove() - - describe "@replaceSelectedText()", -> - it "returns true when transformed text is non-empty", -> - transformed = false - edited = false - class CustomCommand extends EditorCommand - - @onEditor: (editor) -> - @register editor, 'meta-V', 'custom', => - edited = @replaceSelectedText editor, (text) -> - transformed = true - 'new' - - CustomCommand.activate(rootView) - editor.moveCursorToTop() - editor.selectToEndOfLine() - editor.trigger 'custom' - expect(transformed).toBe true - expect(edited).toBe true - - it "returns false when transformed text is null", -> - transformed = false - edited = false - class CustomCommand extends EditorCommand - - @onEditor: (editor) -> - @register editor, 'meta-V', 'custom', => - edited = @replaceSelectedText editor, (text) -> - transformed = true - null - - CustomCommand.activate(rootView) - editor.moveCursorToTop() - editor.selectToEndOfLine() - editor.trigger 'custom' - expect(transformed).toBe true - expect(edited).toBe false - - it "returns false when transformed text is undefined", -> - transformed = false - edited = false - class CustomCommand extends EditorCommand - - @onEditor: (editor) -> - @register editor, 'meta-V', 'custom', => - edited = @replaceSelectedText editor, (text) -> - transformed = true - undefined - - CustomCommand.activate(rootView) - editor.moveCursorToTop() - editor.selectToEndOfLine() - editor.trigger 'custom' - expect(transformed).toBe true - expect(edited).toBe false - - describe "custom sub-class", -> - it "removes vowels from selected text", -> - class VowelRemover extends EditorCommand - - @onEditor: (editor) -> - @register editor, 'meta-V', 'devowel', => - @replaceSelectedText editor, (text) -> - text.replace(/[aeiouy]/gi, '') - - VowelRemover.activate(rootView) - editor.moveCursorToTop() - editor.selectToEndOfLine() - editor.trigger 'devowel' - expect(editor.lineForBufferRow(0)).toBe 'vr qcksrt = fnctn () {' - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'vr qcksrt = fnctn () {' - expect(editor.getCursorBufferPosition()).toBe(editor.getSelection().getBufferRange().end) - - it "maintains reversed selections", -> - class VowelRemover extends EditorCommand - @onEditor: (editor) -> - @register editor, 'meta-V', 'devowel', => - @replaceSelectedText editor, (text) -> - text.replace(/[aeiouy]/gi, '') - - VowelRemover.activate(rootView) - editor.moveCursorToTop() - editor.moveCursorToEndOfLine() - editor.selectToBeginningOfLine() - editor.trigger 'devowel' - expect(editor.lineForBufferRow(0)).toBe 'vr qcksrt = fnctn () {' - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'vr qcksrt = fnctn () {' - expect(editor.getCursorBufferPosition()).toBe(editor.getSelection().getBufferRange().start) - - it "doesn't transform empty selections", -> - callbackCount = 0 - class CustomCommand extends EditorCommand - @onEditor: (editor) -> - @register editor, 'meta-V', 'custom', => - @replaceSelectedText editor, (text) -> - callbackCount++ - text - - CustomCommand.activate(rootView) - editor.moveCursorToTop() - editor.selectToEndOfLine() - editor.trigger 'custom' - expect(callbackCount).toBe 1 - editor.clearSelections() - editor.trigger 'custom' - expect(callbackCount).toBe 1 - - describe "LowerCaseCommand", -> - it "replaces the selected text with all lower case characters", -> - LowerCaseCommand.activate(rootView) - editor.setSelectedBufferRange([[11,14], [11,19]]) - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'Array' - editor.trigger 'lowercase' - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'array' - - describe "UpperCaseCommand", -> - it "replaces the selected text with all upper case characters", -> - UpperCaseCommand.activate(rootView) - editor.setSelectedBufferRange([[0,0], [0,3]]) - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'var' - editor.trigger 'uppercase' - expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'VAR' diff --git a/spec/extensions/lowercase-command-spec.coffee b/spec/extensions/lowercase-command-spec.coffee new file mode 100644 index 000000000..120120f2d --- /dev/null +++ b/spec/extensions/lowercase-command-spec.coffee @@ -0,0 +1,23 @@ +LowerCaseCommand = require 'lowercase-command' +RootView = require 'root-view' +fs = require 'fs' + +describe "LowerCaseCommand", -> + [rootView, editor, path] = [] + + beforeEach -> + rootView = new RootView + rootView.open(require.resolve 'fixtures/sample.js') + + rootView.focus() + editor = rootView.getActiveEditor() + + afterEach -> + rootView.remove() + + it "replaces the selected text with all lower case characters", -> + LowerCaseCommand.activate(rootView) + editor.setSelectedBufferRange([[11,14], [11,19]]) + expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'Array' + editor.trigger 'lowercase' + expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'array' diff --git a/spec/extensions/uppercase-command-spec.coffee b/spec/extensions/uppercase-command-spec.coffee new file mode 100644 index 000000000..5ad77077e --- /dev/null +++ b/spec/extensions/uppercase-command-spec.coffee @@ -0,0 +1,23 @@ +UpperCaseCommand = require 'uppercase-command' +RootView = require 'root-view' +fs = require 'fs' + +describe "UpperCaseCommand", -> + [rootView, editor, path] = [] + + beforeEach -> + rootView = new RootView + rootView.open(require.resolve 'fixtures/sample.js') + + rootView.focus() + editor = rootView.getActiveEditor() + + afterEach -> + rootView.remove() + + it "replaces the selected text with all upper case characters", -> + UpperCaseCommand.activate(rootView) + editor.setSelectedBufferRange([[0,0], [0,3]]) + expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'var' + editor.trigger 'uppercase' + expect(editor.getTextInRange(editor.getSelection().getBufferRange())).toBe 'VAR' diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 41c69752d..35b752ad3 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -965,3 +965,20 @@ class Editor extends View @find('pre.line.cursor-line').removeClass('cursor-line') if @getSelection().isSingleScreenLine() @find("pre.line:eq(#{screenRow})").addClass('cursor-line') + + bindToKeyedEvent: (key, event, callback) -> + binding = {} + binding[key] = event + window.keymap.bindKeys '.editor', binding + @on event, => + callback(this, event) + + replaceSelectedText: (replaceFn) -> + selection = @getSelection() + return false if selection.isEmpty() + + text = replaceFn(@getTextInRange(selection.getBufferRange())) + return false if text is null or text is undefined + + @insertText(text, select: true) + true diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index 38cb4f1e9..4b9479329 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -232,3 +232,10 @@ class RootView extends View saveAll: -> editor.save() for editor in @getEditors() + + eachEditor: (callback) -> + for editor in @getEditors() + callback(editor) + + @on 'editor-open', (e, editor) -> + callback(editor) diff --git a/src/extensions/editor-command.coffee b/src/extensions/editor-command.coffee deleted file mode 100644 index e4a649d07..000000000 --- a/src/extensions/editor-command.coffee +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = -class EditorCommand - - @activate: (rootView) -> - for editor in rootView.getEditors() - @onEditor(editor) - - rootView.on 'editor-open', (e, editor) => - @onEditor(editor) - - @register: (editor, key, event, callback) -> - binding = {} - binding[key] = event - window.keymap.bindKeys '.editor', binding - editor.on event, => - callback(editor, event) - - @replaceSelectedText: (editor, replace) -> - selection = editor.getSelection() - return false if selection.isEmpty() - - text = replace(editor.getTextInRange(selection.getBufferRange())) - return false if text is null or text is undefined - - editor.insertText(text, select: true) - true diff --git a/src/extensions/lowercase-command.coffee b/src/extensions/lowercase-command.coffee index 7254fb72d..e9fa2c3f4 100644 --- a/src/extensions/lowercase-command.coffee +++ b/src/extensions/lowercase-command.coffee @@ -1,9 +1,10 @@ -EditorCommand = require 'editor-command' - module.exports = -class LowerCaseCommand extends EditorCommand +class LowerCaseCommand + + @activate: (rootView) -> + rootView.eachEditor(@onEditor) @onEditor: (editor) -> - @register editor, 'meta-Y', 'lowercase', => - @replaceSelectedText editor, (text) -> + editor.bindToKeyedEvent 'meta-Y', 'lowercase', => + editor.replaceSelectedText (text) -> text.toLowerCase() diff --git a/src/extensions/uppercase-command.coffee b/src/extensions/uppercase-command.coffee index 2096a91c9..840ee848b 100644 --- a/src/extensions/uppercase-command.coffee +++ b/src/extensions/uppercase-command.coffee @@ -1,9 +1,10 @@ -EditorCommand = require 'editor-command' - module.exports = -class UpperCaseCommand extends EditorCommand +class UpperCaseCommand + + @activate: (rootView) -> + rootView.eachEditor(@onEditor) @onEditor: (editor) -> - @register editor, 'meta-X', 'uppercase', => - @replaceSelectedText editor, (text) -> + editor.bindToKeyedEvent 'meta-X', 'uppercase', => + editor.replaceSelectedText (text) -> text.toUpperCase()